From bcac748a7611fcdff0be8d0c76e3249760987a0e Mon Sep 17 00:00:00 2001 From: bradymiller Date: Wed, 26 Jun 2013 00:10:15 -0700 Subject: [PATCH] Upgraded phpmyadmin to 4.0.4 (All Languages) - No modifications yet --- phpmyadmin/ChangeLog | 222 + phpmyadmin/LICENSE | 340 + phpmyadmin/README | 84 + phpmyadmin/RELEASE-DATE-4.0.4 | 1 + phpmyadmin/browse_foreigners.php | 340 + phpmyadmin/changelog.php | 152 + phpmyadmin/chk_rel.php | 15 + phpmyadmin/composer.json | 24 + phpmyadmin/config.sample.inc.php | 141 + phpmyadmin/db_create.php | 148 + phpmyadmin/db_datadict.php | 291 + phpmyadmin/db_events.php | 26 + phpmyadmin/db_export.php | 90 + phpmyadmin/db_import.php | 28 + phpmyadmin/db_operations.php | 293 + phpmyadmin/db_printview.php | 252 + phpmyadmin/db_qbe.php | 68 + phpmyadmin/db_routines.php | 27 + phpmyadmin/db_search.php | 57 + phpmyadmin/db_sql.php | 65 + phpmyadmin/db_structure.php | 335 + phpmyadmin/db_tracking.php | 243 + phpmyadmin/db_triggers.php | 25 + phpmyadmin/doc/Makefile | 153 + phpmyadmin/doc/_ext/configext.py | 189 + phpmyadmin/doc/conf.py | 286 + phpmyadmin/doc/config.rst | 2776 ++ phpmyadmin/doc/copyright.rst | 30 + phpmyadmin/doc/credits.rst | 597 + phpmyadmin/doc/developers.rst | 12 + phpmyadmin/doc/doctrees/config.doctree | Bin 0 -> 935625 bytes phpmyadmin/doc/doctrees/copyright.doctree | Bin 0 -> 6876 bytes phpmyadmin/doc/doctrees/credits.doctree | Bin 0 -> 135005 bytes phpmyadmin/doc/doctrees/developers.doctree | Bin 0 -> 4726 bytes phpmyadmin/doc/doctrees/environment.pickle | Bin 0 -> 243711 bytes phpmyadmin/doc/doctrees/faq.doctree | Bin 0 -> 595349 bytes phpmyadmin/doc/doctrees/glossary.doctree | Bin 0 -> 120004 bytes phpmyadmin/doc/doctrees/index.doctree | Bin 0 -> 6400 bytes phpmyadmin/doc/doctrees/intro.doctree | Bin 0 -> 29111 bytes phpmyadmin/doc/doctrees/other.doctree | Bin 0 -> 5433 bytes phpmyadmin/doc/doctrees/privileges.doctree | Bin 0 -> 11974 bytes phpmyadmin/doc/doctrees/require.doctree | Bin 0 -> 16868 bytes phpmyadmin/doc/doctrees/setup.doctree | Bin 0 -> 132201 bytes phpmyadmin/doc/doctrees/transformations.doctree | Bin 0 -> 33416 bytes phpmyadmin/doc/doctrees/user.doctree | Bin 0 -> 2928 bytes phpmyadmin/doc/doctrees/vendors.doctree | Bin 0 -> 8707 bytes phpmyadmin/doc/faq.rst | 2001 ++ phpmyadmin/doc/glossary.rst | 406 + phpmyadmin/doc/html/.buildinfo | 4 + phpmyadmin/doc/html/_sources/config.txt | 2776 ++ phpmyadmin/doc/html/_sources/copyright.txt | 30 + phpmyadmin/doc/html/_sources/credits.txt | 597 + phpmyadmin/doc/html/_sources/developers.txt | 12 + phpmyadmin/doc/html/_sources/faq.txt | 2001 ++ 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 | 55 + phpmyadmin/doc/html/_sources/setup.txt | 424 + phpmyadmin/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 + phpmyadmin/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 | 154 + 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 | 23 + 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 | 4896 +++ phpmyadmin/doc/html/copyright.html | 134 + phpmyadmin/doc/html/credits.html | 658 + phpmyadmin/doc/html/developers.html | 118 + phpmyadmin/doc/html/faq.html | 1780 ++ phpmyadmin/doc/html/genindex.html | 3699 +++ phpmyadmin/doc/html/glossary.html | 627 + phpmyadmin/doc/html/index.html | 206 + phpmyadmin/doc/html/intro.html | 182 + phpmyadmin/doc/html/objects.inv | Bin 0 -> 9513 bytes phpmyadmin/doc/html/other.html | 135 + phpmyadmin/doc/html/privileges.html | 169 + phpmyadmin/doc/html/require.html | 170 + phpmyadmin/doc/html/search.html | 100 + phpmyadmin/doc/html/searchindex.js | 1 + phpmyadmin/doc/html/setup.html | 481 + 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 | 55 + phpmyadmin/doc/setup.rst | 424 + phpmyadmin/doc/transformations.rst | 138 + phpmyadmin/doc/user.rst | 9 + phpmyadmin/doc/vendors.rst | 34 + phpmyadmin/examples/config.manyhosts.inc.php | 46 + phpmyadmin/examples/create_tables.sql | 241 + phpmyadmin/examples/create_tables_drizzle.sql | 228 + phpmyadmin/examples/openid.php | 158 + phpmyadmin/examples/signon-script.php | 29 + phpmyadmin/examples/signon.php | 65 + phpmyadmin/examples/swekey.sample.conf | 44 + .../examples/upgrade_tables_mysql_4_1_2+.sql | 144 + phpmyadmin/export.php | 979 + phpmyadmin/favicon.ico | Bin 0 -> 18902 bytes phpmyadmin/file_echo.php | 71 + phpmyadmin/gis_data_editor.php | 416 + phpmyadmin/import.php | 601 + phpmyadmin/import_status.php | 105 + phpmyadmin/index.php | 616 + phpmyadmin/js/OpenStreetMap.js | 1 + phpmyadmin/js/ajax.js | 1 + phpmyadmin/js/canvg/MIT-LICENSE.txt | 22 + phpmyadmin/js/canvg/canvg.js | 1 + phpmyadmin/js/canvg/flashcanvas.js | 1 + phpmyadmin/js/canvg/flashcanvas.swf | Bin 0 -> 21235 bytes phpmyadmin/js/chart.js | 1 + phpmyadmin/js/codemirror/LICENSE | 19 + phpmyadmin/js/codemirror/lib/codemirror.js | 1 + phpmyadmin/js/codemirror/mode/mysql/mysql.js | 1 + phpmyadmin/js/common.js | 1 + phpmyadmin/js/config.js | 1 + phpmyadmin/js/date.js | 1 + phpmyadmin/js/db_operations.js | 1 + phpmyadmin/js/db_search.js | 1 + phpmyadmin/js/db_structure.js | 1 + phpmyadmin/js/export.js | 1 + phpmyadmin/js/functions.js | 1 + phpmyadmin/js/get_image.js.php | 138 + phpmyadmin/js/get_scripts.js.php | 38 + phpmyadmin/js/gis_data_editor.js | 1 + phpmyadmin/js/import.js | 1 + phpmyadmin/js/indexes.js | 1 + phpmyadmin/js/jqplot/excanvas.js | 1 + phpmyadmin/js/jqplot/jquery.jqplot.js | 1 + phpmyadmin/js/jqplot/plugins/jqplot.barRenderer.js | 1 + .../js/jqplot/plugins/jqplot.byteFormatter.js | 1 + .../plugins/jqplot.canvasAxisLabelRenderer.js | 1 + .../js/jqplot/plugins/jqplot.canvasTextRenderer.js | 1 + .../jqplot/plugins/jqplot.categoryAxisRenderer.js | 1 + phpmyadmin/js/jqplot/plugins/jqplot.cursor.js | 1 + .../js/jqplot/plugins/jqplot.dateAxisRenderer.js | 1 + phpmyadmin/js/jqplot/plugins/jqplot.highlighter.js | 1 + phpmyadmin/js/jqplot/plugins/jqplot.pieRenderer.js | 1 + phpmyadmin/js/jqplot/plugins/jqplot.pointLabels.js | 1 + phpmyadmin/js/jquery/jquery-1.8.3.js | 21 + phpmyadmin/js/jquery/jquery-ui-1.9.2.custom.js | 16 + phpmyadmin/js/jquery/jquery-ui-timepicker-addon.js | 1 + phpmyadmin/js/jquery/jquery.ba-hashchange-1.3.js | 9 + phpmyadmin/js/jquery/jquery.cookie.js | 1 + phpmyadmin/js/jquery/jquery.debounce-1.0.5.js | 1 + phpmyadmin/js/jquery/jquery.event.drag-2.2.js | 6 + phpmyadmin/js/jquery/jquery.fullscreen.js | 1 + phpmyadmin/js/jquery/jquery.json-2.4.js | 1 + phpmyadmin/js/jquery/jquery.menuResizer-1.0.js | 1 + phpmyadmin/js/jquery/jquery.mousewheel.js | 12 + phpmyadmin/js/jquery/jquery.sortableTable.js | 1 + phpmyadmin/js/jquery/jquery.sprintf.js | 1 + phpmyadmin/js/jquery/jquery.svg.js | 1 + phpmyadmin/js/jquery/jquery.tablesorter.js | 1 + phpmyadmin/js/keyhandler.js | 1 + phpmyadmin/js/makegrid.js | 1 + phpmyadmin/js/messages.php | 530 + phpmyadmin/js/navigation.js | 1 + phpmyadmin/js/openlayers/OpenLayers.js | 1 + phpmyadmin/js/openlayers/img/blank.gif | Bin 0 -> 42 bytes .../js/openlayers/img/cloud-popup-relative.png | Bin 0 -> 3177 bytes .../js/openlayers/img/drag-rectangle-off.png | Bin 0 -> 1202 bytes phpmyadmin/js/openlayers/img/drag-rectangle-on.png | Bin 0 -> 1218 bytes phpmyadmin/js/openlayers/img/east-mini.png | Bin 0 -> 451 bytes .../js/openlayers/img/layer-switcher-maximize.png | Bin 0 -> 451 bytes .../js/openlayers/img/layer-switcher-minimize.png | Bin 0 -> 249 bytes phpmyadmin/js/openlayers/img/marker-blue.png | Bin 0 -> 992 bytes phpmyadmin/js/openlayers/img/marker-gold.png | Bin 0 -> 831 bytes phpmyadmin/js/openlayers/img/marker-green.png | Bin 0 -> 967 bytes phpmyadmin/js/openlayers/img/marker.png | Bin 0 -> 606 bytes .../js/openlayers/img/measuring-stick-off.png | Bin 0 -> 3343 bytes .../js/openlayers/img/measuring-stick-on.png | Bin 0 -> 3816 bytes phpmyadmin/js/openlayers/img/north-mini.png | Bin 0 -> 484 bytes phpmyadmin/js/openlayers/img/panning-hand-off.png | Bin 0 -> 3875 bytes phpmyadmin/js/openlayers/img/panning-hand-on.png | Bin 0 -> 3977 bytes phpmyadmin/js/openlayers/img/slider.png | Bin 0 -> 285 bytes phpmyadmin/js/openlayers/img/south-mini.png | Bin 0 -> 481 bytes phpmyadmin/js/openlayers/img/west-mini.png | Bin 0 -> 453 bytes phpmyadmin/js/openlayers/img/zoom-minus-mini.png | Bin 0 -> 359 bytes phpmyadmin/js/openlayers/img/zoom-plus-mini.png | Bin 0 -> 489 bytes phpmyadmin/js/openlayers/img/zoom-world-mini.png | Bin 0 -> 1072 bytes phpmyadmin/js/openlayers/img/zoombar.png | Bin 0 -> 463 bytes .../js/openlayers/theme/default/framedCloud.css | 0 phpmyadmin/js/openlayers/theme/default/google.css | 10 + .../js/openlayers/theme/default/ie6-style.css | 7 + .../openlayers/theme/default/img/add_point_off.png | Bin 0 -> 1616 bytes .../openlayers/theme/default/img/add_point_on.png | Bin 0 -> 1464 bytes .../js/openlayers/theme/default/img/blank.gif | Bin 0 -> 42 bytes .../js/openlayers/theme/default/img/close.gif | Bin 0 -> 1078 bytes .../theme/default/img/drag-rectangle-off.png | Bin 0 -> 1202 bytes .../theme/default/img/drag-rectangle-on.png | Bin 0 -> 1218 bytes .../openlayers/theme/default/img/draw_line_off.png | Bin 0 -> 1567 bytes .../openlayers/theme/default/img/draw_line_on.png | Bin 0 -> 1399 bytes .../theme/default/img/draw_point_off.png | Bin 0 -> 1612 bytes .../openlayers/theme/default/img/draw_point_on.png | Bin 0 -> 1460 bytes .../theme/default/img/draw_polygon_off.png | Bin 0 -> 1546 bytes .../theme/default/img/draw_polygon_on.png | Bin 0 -> 1407 bytes .../theme/default/img/editing_tool_bar.png | Bin 0 -> 3901 bytes .../theme/default/img/move_feature_off.png | Bin 0 -> 1543 bytes .../theme/default/img/move_feature_on.png | Bin 0 -> 1379 bytes .../theme/default/img/navigation_history.png | Bin 0 -> 7021 bytes .../theme/default/img/overview_replacement.gif | Bin 0 -> 79 bytes .../theme/default/img/pan-panel-NOALPHA.png | Bin 0 -> 566 bytes .../js/openlayers/theme/default/img/pan-panel.png | Bin 0 -> 1287 bytes .../js/openlayers/theme/default/img/pan_off.png | Bin 0 -> 1696 bytes .../js/openlayers/theme/default/img/pan_on.png | Bin 0 -> 1568 bytes .../theme/default/img/panning-hand-off.png | Bin 0 -> 3875 bytes .../theme/default/img/panning-hand-on.png | Bin 0 -> 3977 bytes .../theme/default/img/remove_point_off.png | Bin 0 -> 1612 bytes .../theme/default/img/remove_point_on.png | Bin 0 -> 1464 bytes .../js/openlayers/theme/default/img/ruler.png | Bin 0 -> 1211 bytes .../theme/default/img/save_features_off.png | Bin 0 -> 357 bytes .../theme/default/img/save_features_on.png | Bin 0 -> 364 bytes .../openlayers/theme/default/img/view_next_off.png | Bin 0 -> 1644 bytes .../openlayers/theme/default/img/view_next_on.png | Bin 0 -> 1686 bytes .../theme/default/img/view_previous_off.png | Bin 0 -> 1553 bytes .../theme/default/img/view_previous_on.png | Bin 0 -> 1592 bytes .../theme/default/img/zoom-panel-NOALPHA.png | Bin 0 -> 1173 bytes .../js/openlayers/theme/default/img/zoom-panel.png | Bin 0 -> 1624 bytes phpmyadmin/js/openlayers/theme/default/style.css | 397 + phpmyadmin/js/pmd/ajax.js | 1 + phpmyadmin/js/pmd/history.js | 1 + phpmyadmin/js/pmd/iecanvas.js | 1 + phpmyadmin/js/pmd/init.js | 1 + phpmyadmin/js/pmd/move.js | 1 + phpmyadmin/js/querywindow.js | 1 + phpmyadmin/js/replication.js | 1 + phpmyadmin/js/rte.js | 1 + phpmyadmin/js/server_databases.js | 1 + phpmyadmin/js/server_plugins.js | 1 + phpmyadmin/js/server_privileges.js | 1 + phpmyadmin/js/server_status.js | 1 + phpmyadmin/js/server_status_advisor.js | 1 + phpmyadmin/js/server_status_monitor.js | 1 + phpmyadmin/js/server_status_queries.js | 1 + phpmyadmin/js/server_status_sorter.js | 1 + phpmyadmin/js/server_status_variables.js | 1 + phpmyadmin/js/server_variables.js | 1 + phpmyadmin/js/sql.js | 1 + phpmyadmin/js/tbl_change.js | 1 + phpmyadmin/js/tbl_chart.js | 1 + phpmyadmin/js/tbl_gis_visualization.js | 1 + phpmyadmin/js/tbl_relation.js | 1 + phpmyadmin/js/tbl_select.js | 1 + phpmyadmin/js/tbl_structure.js | 1 + phpmyadmin/js/tbl_zoom_plot_jqplot.js | 1 + phpmyadmin/libraries/.htaccess | 3 + phpmyadmin/libraries/Advisor.class.php | 509 + phpmyadmin/libraries/Config.class.php | 1829 ++ phpmyadmin/libraries/DBQbe.class.php | 1343 + phpmyadmin/libraries/DbSearch.class.php | 489 + phpmyadmin/libraries/DisplayResults.class.php | 5967 ++++ phpmyadmin/libraries/Error.class.php | 409 + phpmyadmin/libraries/Error_Handler.class.php | 446 + phpmyadmin/libraries/File.class.php | 863 + phpmyadmin/libraries/Footer.class.php | 283 + phpmyadmin/libraries/Header.class.php | 660 + phpmyadmin/libraries/Index.class.php | 863 + phpmyadmin/libraries/List.class.php | 121 + phpmyadmin/libraries/List_Database.class.php | 318 + phpmyadmin/libraries/Menu.class.php | 525 + phpmyadmin/libraries/Message.class.php | 749 + phpmyadmin/libraries/OutputBuffering.class.php | 148 + phpmyadmin/libraries/PDF.class.php | 143 + phpmyadmin/libraries/PMA.php | 106 + phpmyadmin/libraries/Partition.class.php | 79 + phpmyadmin/libraries/RecentTable.class.php | 210 + phpmyadmin/libraries/Response.class.php | 377 + phpmyadmin/libraries/Scripts.class.php | 243 + phpmyadmin/libraries/ServerStatusData.class.php | 380 + phpmyadmin/libraries/StorageEngine.class.php | 434 + phpmyadmin/libraries/Table.class.php | 1664 ++ phpmyadmin/libraries/TableSearch.class.php | 1229 + phpmyadmin/libraries/Theme.class.php | 601 + phpmyadmin/libraries/Theme_Manager.class.php | 453 + phpmyadmin/libraries/Tracker.class.php | 1079 + phpmyadmin/libraries/Types.class.php | 984 + phpmyadmin/libraries/Util.class.php | 4098 +++ phpmyadmin/libraries/advisory_rules.txt | 470 + .../libraries/bfShapeFiles/ShapeFile.lib.php | 666 + phpmyadmin/libraries/bookmark.lib.php | 208 + phpmyadmin/libraries/build_html_for_db.lib.php | 180 + phpmyadmin/libraries/charset_conversion.lib.php | 97 + phpmyadmin/libraries/check_user_privileges.lib.php | 165 + phpmyadmin/libraries/cleanup.lib.php | 50 + phpmyadmin/libraries/common.inc.php | 1142 + phpmyadmin/libraries/config.default.php | 2824 ++ phpmyadmin/libraries/config.values.php | 239 + phpmyadmin/libraries/config/ConfigFile.class.php | 549 + phpmyadmin/libraries/config/Form.class.php | 210 + phpmyadmin/libraries/config/FormDisplay.class.php | 831 + phpmyadmin/libraries/config/FormDisplay.tpl.php | 489 + .../libraries/config/config_functions.lib.php | 55 + phpmyadmin/libraries/config/messages.inc.php | 523 + phpmyadmin/libraries/config/setup.forms.php | 367 + .../libraries/config/user_preferences.forms.php | 271 + phpmyadmin/libraries/config/validate.lib.php | 584 + phpmyadmin/libraries/core.lib.php | 802 + .../libraries/data_dictionary_relations.lib.php | 166 + phpmyadmin/libraries/database_interface.lib.php | 2134 ++ phpmyadmin/libraries/db_common.inc.php | 100 + phpmyadmin/libraries/db_info.inc.php | 224 + phpmyadmin/libraries/db_table_exists.lib.php | 103 + phpmyadmin/libraries/dbi/drizzle-wrappers.lib.php | 437 + phpmyadmin/libraries/dbi/drizzle.dbi.lib.php | 667 + phpmyadmin/libraries/dbi/dummy.lib.php | 511 + phpmyadmin/libraries/dbi/mysql.dbi.lib.php | 552 + phpmyadmin/libraries/dbi/mysqli.dbi.lib.php | 748 + .../libraries/display_change_password.lib.php | 98 + .../libraries/display_create_database.lib.php | 49 + phpmyadmin/libraries/display_create_table.lib.php | 63 + phpmyadmin/libraries/display_export.lib.php | 443 + phpmyadmin/libraries/display_git_revision.lib.php | 83 + phpmyadmin/libraries/display_import.lib.php | 338 + phpmyadmin/libraries/display_import_ajax.lib.php | 132 + phpmyadmin/libraries/display_select_lang.lib.php | 98 + phpmyadmin/libraries/engines/bdb.lib.php | 84 + phpmyadmin/libraries/engines/berkeleydb.lib.php | 24 + phpmyadmin/libraries/engines/binlog.lib.php | 28 + phpmyadmin/libraries/engines/innobase.lib.php | 23 + phpmyadmin/libraries/engines/innodb.lib.php | 411 + phpmyadmin/libraries/engines/memory.lib.php | 34 + phpmyadmin/libraries/engines/merge.lib.php | 21 + phpmyadmin/libraries/engines/mrg_myisam.lib.php | 33 + phpmyadmin/libraries/engines/myisam.lib.php | 69 + phpmyadmin/libraries/engines/ndbcluster.lib.php | 55 + phpmyadmin/libraries/engines/pbxt.lib.php | 142 + .../libraries/engines/performance_schema.lib.php | 28 + phpmyadmin/libraries/error.inc.php | 59 + phpmyadmin/libraries/file_listing.lib.php | 103 + phpmyadmin/libraries/gis/pma_gis_factory.php | 61 + phpmyadmin/libraries/gis/pma_gis_geometry.php | 361 + .../libraries/gis/pma_gis_geometrycollection.php | 336 + phpmyadmin/libraries/gis/pma_gis_linestring.php | 298 + .../libraries/gis/pma_gis_multilinestring.php | 370 + phpmyadmin/libraries/gis/pma_gis_multipoint.php | 343 + phpmyadmin/libraries/gis/pma_gis_multipolygon.php | 527 + phpmyadmin/libraries/gis/pma_gis_point.php | 294 + phpmyadmin/libraries/gis/pma_gis_polygon.php | 549 + phpmyadmin/libraries/gis/pma_gis_visualization.php | 503 + phpmyadmin/libraries/gis_visualization.lib.php | 182 + phpmyadmin/libraries/iconv_wrapper.lib.php | 105 + phpmyadmin/libraries/import.lib.php | 1248 + phpmyadmin/libraries/index.lib.php | 44 + .../libraries/information_schema_relations.lib.php | 138 + phpmyadmin/libraries/insert_edit.lib.php | 2366 ++ phpmyadmin/libraries/ip_allow_deny.lib.php | 327 + phpmyadmin/libraries/js_escape.lib.php | 133 + phpmyadmin/libraries/kanji-encoding.lib.php | 161 + phpmyadmin/libraries/language_stats.inc.php | 76 + phpmyadmin/libraries/logging.lib.php | 30 + phpmyadmin/libraries/mime.lib.php | 34 + phpmyadmin/libraries/mult_submits.inc.php | 578 + phpmyadmin/libraries/mysql_charsets.lib.php | 455 + .../libraries/navigation/Navigation.class.php | 77 + .../navigation/NavigationHeader.class.php | 298 + .../libraries/navigation/NavigationTree.class.php | 1148 + .../libraries/navigation/NodeFactory.class.php | 97 + .../libraries/navigation/Nodes/Node.class.php | 455 + .../navigation/Nodes/Node_Column.class.php | 71 + .../Nodes/Node_Column_Container.class.php | 56 + .../navigation/Nodes/Node_Database.class.php | 447 + .../navigation/Nodes/Node_Event.class.php | 66 + .../Nodes/Node_Event_Container.class.php | 52 + .../navigation/Nodes/Node_Function.class.php | 67 + .../Nodes/Node_Function_Container.class.php | 52 + .../navigation/Nodes/Node_Index.class.php | 45 + .../Nodes/Node_Index_Container.class.php | 54 + .../navigation/Nodes/Node_Procedure.class.php | 67 + .../Nodes/Node_Procedure_Container.class.php | 52 + .../navigation/Nodes/Node_Table.class.php | 229 + .../Nodes/Node_Table_Container.class.php | 54 + .../navigation/Nodes/Node_Trigger.class.php | 45 + .../Nodes/Node_Trigger_Container.class.php | 53 + .../libraries/navigation/Nodes/Node_View.class.php | 44 + .../navigation/Nodes/Node_View_Container.class.php | 50 + phpmyadmin/libraries/opendocument.lib.php | 170 + phpmyadmin/libraries/operations.lib.php | 1609 + phpmyadmin/libraries/parse_analyze.lib.php | 61 + phpmyadmin/libraries/php-gettext/gettext.inc | 536 + phpmyadmin/libraries/php-gettext/gettext.php | 432 + phpmyadmin/libraries/php-gettext/streams.php | 167 + phpmyadmin/libraries/phpseclib/Crypt/AES.php | 612 + phpmyadmin/libraries/phpseclib/Crypt/Rijndael.php | 1479 + phpmyadmin/libraries/plugin_interface.lib.php | 508 + .../plugins/AuthenticationPlugin.class.php | 51 + .../libraries/plugins/ExportPlugin.class.php | 205 + .../libraries/plugins/ImportPlugin.class.php | 59 + .../libraries/plugins/PluginManager.class.php | 132 + .../libraries/plugins/PluginObserver.class.php | 90 + .../plugins/TransformationsInterface.int.php | 49 + .../plugins/TransformationsPlugin.class.php | 49 + .../libraries/plugins/UploadInterface.int.php | 36 + .../plugins/auth/AuthenticationConfig.class.php | 172 + .../plugins/auth/AuthenticationCookie.class.php | 696 + .../plugins/auth/AuthenticationHttp.class.php | 249 + .../plugins/auth/AuthenticationSignon.class.php | 284 + .../plugins/auth/swekey/authentication.inc.php | 172 + .../libraries/plugins/auth/swekey/musbe-ca.crt | 25 + .../plugins/auth/swekey/swekey.auth.lib.php | 293 + .../libraries/plugins/auth/swekey/swekey.php | 522 + .../plugins/export/ExportCodegen.class.php | 423 + .../libraries/plugins/export/ExportCsv.class.php | 345 + .../libraries/plugins/export/ExportExcel.class.php | 105 + .../plugins/export/ExportHtmlword.class.php | 645 + .../libraries/plugins/export/ExportJson.class.php | 221 + .../libraries/plugins/export/ExportLatex.class.php | 655 + .../plugins/export/ExportMediawiki.class.php | 364 + .../libraries/plugins/export/ExportOds.class.php | 334 + .../libraries/plugins/export/ExportOdt.class.php | 734 + .../libraries/plugins/export/ExportPdf.class.php | 268 + .../plugins/export/ExportPhparray.class.php | 227 + .../libraries/plugins/export/ExportSql.class.php | 1876 ++ .../plugins/export/ExportTexytext.class.php | 574 + .../libraries/plugins/export/ExportXml.class.php | 536 + .../libraries/plugins/export/ExportYaml.class.php | 214 + .../plugins/export/PMA_ExportPdf.class.php | 408 + phpmyadmin/libraries/plugins/export/README | 276 + .../plugins/export/TableProperty.class.php | 288 + .../plugins/import/AbstractImportCsv.class.php | 91 + .../libraries/plugins/import/ImportCsv.class.php | 588 + .../libraries/plugins/import/ImportLdi.class.php | 172 + .../plugins/import/ImportMediawiki.class.php | 573 + .../libraries/plugins/import/ImportOds.class.php | 415 + .../libraries/plugins/import/ImportShp.class.php | 342 + .../libraries/plugins/import/ImportSql.class.php | 440 + .../libraries/plugins/import/ImportXml.class.php | 379 + phpmyadmin/libraries/plugins/import/README | 173 + .../libraries/plugins/import/ShapeFile.class.php | 102 + .../libraries/plugins/import/ShapeRecord.class.php | 161 + .../plugins/import/upload/UploadApc.class.php | 84 + .../plugins/import/upload/UploadNoplugin.class.php | 64 + .../plugins/import/upload/UploadProgress.class.php | 94 + .../plugins/import/upload/UploadSession.class.php | 96 + .../Application_Octetstream_Download.class.php | 64 + .../Application_Octetstream_Hex.class.php | 65 + .../transformations/Image_JPEG_Inline.class.php | 65 + .../transformations/Image_JPEG_Link.class.php | 65 + .../transformations/Image_PNG_Inline.class.php | 65 + .../libraries/plugins/transformations/README | 4 + .../libraries/plugins/transformations/TEMPLATE | 68 + .../plugins/transformations/TEMPLATE_ABSTRACT | 89 + .../transformations/Text_Plain_Append.class.php | 66 + .../Text_Plain_Dateformat.class.php | 65 + .../transformations/Text_Plain_External.class.php | 65 + .../transformations/Text_Plain_Formatted.class.php | 65 + .../transformations/Text_Plain_Imagelink.class.php | 65 + .../transformations/Text_Plain_Link.class.php | 65 + .../Text_Plain_Longtoipv4.class.php | 65 + .../transformations/Text_Plain_Sql.class.php | 65 + .../transformations/Text_Plain_Substring.class.php | 65 + .../abstract/AppendTransformationsPlugin.class.php | 86 + .../DateFormatTransformationsPlugin.class.php | 178 + .../DownloadTransformationsPlugin.class.php | 110 + .../ExternalTransformationsPlugin.class.php | 182 + .../FormattedTransformationsPlugin.class.php | 80 + .../abstract/HexTransformationsPlugin.class.php | 91 + .../ImageLinkTransformationsPlugin.class.php | 89 + .../abstract/InlineTransformationsPlugin.class.php | 103 + .../LongToIPv4TransformationsPlugin.class.php | 83 + .../abstract/SQLTransformationsPlugin.class.php | 81 + .../SubstringTransformationsPlugin.class.php | 116 + .../TextImageLinkTransformationsPlugin.class.php | 96 + .../TextLinkTransformationsPlugin.class.php | 98 + .../transformations/generator_main_class.sh | 16 + .../plugins/transformations/generator_plugin.sh | 64 + phpmyadmin/libraries/pmd_common.php | 262 + .../libraries/properties/PropertyItem.class.php | 49 + .../options/OptionsPropertyGroup.class.php | 104 + .../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 + .../options/items/HiddenPropertyItem.class.php | 35 + .../items/MessageOnlyPropertyItem.class.php | 35 + .../options/items/RadioPropertyItem.class.php | 35 + .../options/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 | 1396 + phpmyadmin/libraries/relation_cleanup.lib.php | 165 + phpmyadmin/libraries/replication.inc.php | 307 + phpmyadmin/libraries/replication_gui.lib.php | 401 + phpmyadmin/libraries/rte/rte_events.lib.php | 637 + phpmyadmin/libraries/rte/rte_export.lib.php | 122 + phpmyadmin/libraries/rte/rte_footer.lib.php | 127 + phpmyadmin/libraries/rte/rte_list.lib.php | 366 + phpmyadmin/libraries/rte/rte_main.inc.php | 92 + phpmyadmin/libraries/rte/rte_routines.lib.php | 1676 ++ phpmyadmin/libraries/rte/rte_triggers.lib.php | 486 + phpmyadmin/libraries/rte/rte_words.lib.php | 64 + phpmyadmin/libraries/sanitizing.lib.php | 190 + .../libraries/schema/Dia_Relation_Schema.class.php | 835 + .../libraries/schema/Eps_Relation_Schema.class.php | 957 + .../schema/Export_Relation_Schema.class.php | 244 + .../libraries/schema/Pdf_Relation_Schema.class.php | 1443 + .../libraries/schema/Svg_Relation_Schema.class.php | 950 + phpmyadmin/libraries/schema/User_Schema.class.php | 933 + phpmyadmin/libraries/select_lang.lib.php | 556 + phpmyadmin/libraries/select_server.lib.php | 108 + phpmyadmin/libraries/server_common.inc.php | 56 + phpmyadmin/libraries/server_privileges.lib.php | 3355 +++ phpmyadmin/libraries/server_variables_doc.php | 1403 + phpmyadmin/libraries/session.inc.php | 120 + phpmyadmin/libraries/special_schema_links.lib.php | 323 + phpmyadmin/libraries/sql_query_form.lib.php | 496 + phpmyadmin/libraries/sqlparser.data.php | 2016 ++ phpmyadmin/libraries/sqlparser.lib.php | 2906 ++ phpmyadmin/libraries/sqlvalidator.class.php | 457 + phpmyadmin/libraries/sqlvalidator.lib.php | 106 + phpmyadmin/libraries/string.lib.php | 101 + phpmyadmin/libraries/string_mb.lib.php | 71 + phpmyadmin/libraries/string_native.lib.php | 71 + phpmyadmin/libraries/string_type_ctype.lib.php | 104 + phpmyadmin/libraries/string_type_native.lib.php | 133 + phpmyadmin/libraries/structure.lib.php | 2513 ++ phpmyadmin/libraries/sysinfo.lib.php | 363 + .../libraries/tbl_columns_definition_form.inc.php | 906 + phpmyadmin/libraries/tbl_common.inc.php | 63 + phpmyadmin/libraries/tbl_info.inc.php | 105 + phpmyadmin/libraries/tbl_views.lib.php | 157 + phpmyadmin/libraries/tcpdf/LICENSE.TXT | 858 + phpmyadmin/libraries/tcpdf/README.TXT | 97 + phpmyadmin/libraries/tcpdf/config/tcpdf_config.php | 258 + phpmyadmin/libraries/tcpdf/encodings_maps.php | 846 + .../tcpdf/fonts/dejavu-fonts-ttf-2.33/LICENSE | 99 + phpmyadmin/libraries/tcpdf/fonts/dejavusans.ctg.z | Bin 0 -> 10120 bytes phpmyadmin/libraries/tcpdf/fonts/dejavusans.php | 15 + phpmyadmin/libraries/tcpdf/fonts/dejavusans.z | Bin 0 -> 361229 bytes phpmyadmin/libraries/tcpdf/fonts/dejavusansb.ctg.z | Bin 0 -> 9854 bytes phpmyadmin/libraries/tcpdf/fonts/dejavusansb.php | 15 + phpmyadmin/libraries/tcpdf/fonts/dejavusansb.z | Bin 0 -> 333391 bytes phpmyadmin/libraries/tcpdf/fonts/helvetica.php | 13 + phpmyadmin/libraries/tcpdf/htmlcolors.php | 199 + phpmyadmin/libraries/tcpdf/tcpdf.php | 29927 +++++++++++++++++++ phpmyadmin/libraries/tcpdf/unicode_data.php | 18371 ++++++++++++ phpmyadmin/libraries/transformations.lib.php | 412 + phpmyadmin/libraries/url_generating.lib.php | 302 + phpmyadmin/libraries/user_preferences.inc.php | 71 + phpmyadmin/libraries/user_preferences.lib.php | 288 + phpmyadmin/libraries/vendor_config.php | 76 + phpmyadmin/libraries/zip.lib.php | 216 + phpmyadmin/libraries/zip_extension.lib.php | 188 + phpmyadmin/license.php | 31 + phpmyadmin/locale/ar/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 115250 bytes phpmyadmin/locale/bg/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 224973 bytes phpmyadmin/locale/ca/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 299247 bytes phpmyadmin/locale/cs/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 294865 bytes phpmyadmin/locale/da/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 289850 bytes phpmyadmin/locale/de/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 302646 bytes phpmyadmin/locale/el/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 407201 bytes phpmyadmin/locale/en_GB/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 280613 bytes phpmyadmin/locale/es/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 307246 bytes phpmyadmin/locale/et/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 285386 bytes phpmyadmin/locale/fi/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 177545 bytes phpmyadmin/locale/fr/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 305497 bytes phpmyadmin/locale/gl/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 299946 bytes phpmyadmin/locale/hi/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 169310 bytes phpmyadmin/locale/hr/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 101079 bytes phpmyadmin/locale/hu/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 204717 bytes phpmyadmin/locale/id/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 163565 bytes phpmyadmin/locale/it/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 275439 bytes phpmyadmin/locale/ja/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 313785 bytes phpmyadmin/locale/ko/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 166964 bytes phpmyadmin/locale/lt/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 154043 bytes phpmyadmin/locale/nb/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 181573 bytes phpmyadmin/locale/nl/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 298120 bytes phpmyadmin/locale/pl/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 296050 bytes phpmyadmin/locale/pt/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 120011 bytes phpmyadmin/locale/pt_BR/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 300910 bytes phpmyadmin/locale/ro/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 149400 bytes phpmyadmin/locale/ru/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 394178 bytes phpmyadmin/locale/si/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 297064 bytes phpmyadmin/locale/sk/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 221664 bytes phpmyadmin/locale/sl/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 292337 bytes .../locale/sr@latin/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 159377 bytes phpmyadmin/locale/sv/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 289017 bytes phpmyadmin/locale/th/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 136908 bytes phpmyadmin/locale/tr/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 300954 bytes phpmyadmin/locale/uk/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 344070 bytes phpmyadmin/locale/uz/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 178426 bytes .../locale/uz@latin/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 137336 bytes phpmyadmin/locale/zh_CN/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 263011 bytes phpmyadmin/locale/zh_TW/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 201513 bytes phpmyadmin/navigation.php | 27 + phpmyadmin/phpinfo.php | 21 + phpmyadmin/phpmyadmin.css.php | 31 + phpmyadmin/phpunit.xml.nocoverage | 47 + phpmyadmin/pmd_display_field.php | 61 + phpmyadmin/pmd_general.php | 879 + phpmyadmin/pmd_pdf.php | 156 + phpmyadmin/pmd_relation_new.php | 119 + phpmyadmin/pmd_relation_upd.php | 75 + phpmyadmin/pmd_save_pos.php | 84 + phpmyadmin/prefs_forms.php | 91 + phpmyadmin/prefs_manage.php | 331 + phpmyadmin/print.css | 92 + phpmyadmin/querywindow.php | 207 + phpmyadmin/robots.txt | 2 + phpmyadmin/schema_edit.php | 126 + phpmyadmin/schema_export.php | 66 + phpmyadmin/server_binlog.php | 219 + phpmyadmin/server_collations.php | 84 + phpmyadmin/server_databases.php | 349 + phpmyadmin/server_engines.php | 129 + phpmyadmin/server_export.php | 73 + phpmyadmin/server_import.php | 27 + phpmyadmin/server_plugins.php | 184 + phpmyadmin/server_privileges.php | 490 + phpmyadmin/server_replication.php | 349 + phpmyadmin/server_sql.php | 30 + phpmyadmin/server_status.php | 496 + phpmyadmin/server_status_advisor.php | 74 + phpmyadmin/server_status_monitor.php | 756 + phpmyadmin/server_status_queries.php | 162 + phpmyadmin/server_status_variables.php | 767 + phpmyadmin/server_variables.php | 247 + phpmyadmin/setup/ajax.js | 11 + phpmyadmin/setup/config.php | 78 + phpmyadmin/setup/frames/.htaccess | 3 + phpmyadmin/setup/frames/config.inc.php | 48 + phpmyadmin/setup/frames/form.inc.php | 36 + phpmyadmin/setup/frames/index.inc.php | 276 + phpmyadmin/setup/frames/menu.inc.php | 23 + phpmyadmin/setup/frames/servers.inc.php | 49 + phpmyadmin/setup/index.php | 60 + phpmyadmin/setup/lib/.htaccess | 3 + phpmyadmin/setup/lib/ConfigGenerator.class.php | 154 + phpmyadmin/setup/lib/common.inc.php | 56 + phpmyadmin/setup/lib/form_processing.lib.php | 62 + phpmyadmin/setup/lib/index.lib.php | 605 + phpmyadmin/setup/scripts.js | 204 + phpmyadmin/setup/styles.css | 631 + phpmyadmin/setup/validate.php | 30 + phpmyadmin/show_config_errors.php | 40 + phpmyadmin/sql.php | 1740 ++ phpmyadmin/tbl_addfield.php | 250 + phpmyadmin/tbl_change.php | 437 + phpmyadmin/tbl_chart.php | 266 + phpmyadmin/tbl_create.php | 450 + phpmyadmin/tbl_export.php | 85 + phpmyadmin/tbl_get_field.php | 67 + phpmyadmin/tbl_gis_visualization.php | 220 + phpmyadmin/tbl_import.php | 30 + phpmyadmin/tbl_indexes.php | 365 + phpmyadmin/tbl_move_copy.php | 103 + phpmyadmin/tbl_operations.php | 378 + phpmyadmin/tbl_printview.php | 463 + phpmyadmin/tbl_relation.php | 689 + phpmyadmin/tbl_replace.php | 398 + phpmyadmin/tbl_row_action.php | 143 + phpmyadmin/tbl_select.php | 69 + phpmyadmin/tbl_sql.php | 46 + phpmyadmin/tbl_structure.php | 466 + phpmyadmin/tbl_tracking.php | 889 + phpmyadmin/tbl_triggers.php | 10 + phpmyadmin/tbl_zoom_select.php | 171 + phpmyadmin/themes.php | 31 + phpmyadmin/themes/dot.gif | Bin 0 -> 43 bytes phpmyadmin/themes/original/css/common.css.php | 2521 ++ phpmyadmin/themes/original/css/navigation.css.php | 252 + .../themes/original/img/ajax_clock_small.gif | Bin 0 -> 1810 bytes phpmyadmin/themes/original/img/arrow_ltr.png | Bin 0 -> 139 bytes phpmyadmin/themes/original/img/arrow_rtl.png | Bin 0 -> 136 bytes phpmyadmin/themes/original/img/b_bookmark.png | Bin 0 -> 252 bytes phpmyadmin/themes/original/img/b_browse.png | Bin 0 -> 157 bytes phpmyadmin/themes/original/img/b_calendar.png | Bin 0 -> 203 bytes phpmyadmin/themes/original/img/b_chart.png | Bin 0 -> 402 bytes phpmyadmin/themes/original/img/b_close.png | Bin 0 -> 180 bytes phpmyadmin/themes/original/img/b_column_add.png | Bin 0 -> 534 bytes phpmyadmin/themes/original/img/b_comment.png | Bin 0 -> 363 bytes phpmyadmin/themes/original/img/b_dbstatistics.png | Bin 0 -> 157 bytes phpmyadmin/themes/original/img/b_deltbl.png | Bin 0 -> 239 bytes phpmyadmin/themes/original/img/b_docs.png | Bin 0 -> 184 bytes phpmyadmin/themes/original/img/b_drop.png | Bin 0 -> 184 bytes phpmyadmin/themes/original/img/b_edit.png | Bin 0 -> 305 bytes phpmyadmin/themes/original/img/b_empty.png | Bin 0 -> 186 bytes phpmyadmin/themes/original/img/b_engine.png | Bin 0 -> 232 bytes phpmyadmin/themes/original/img/b_event_add.png | Bin 0 -> 863 bytes phpmyadmin/themes/original/img/b_events.png | Bin 0 -> 783 bytes phpmyadmin/themes/original/img/b_export.png | Bin 0 -> 199 bytes phpmyadmin/themes/original/img/b_ftext.png | Bin 0 -> 175 bytes phpmyadmin/themes/original/img/b_globe.gif | Bin 0 -> 1045 bytes phpmyadmin/themes/original/img/b_group.png | Bin 0 -> 796 bytes phpmyadmin/themes/original/img/b_help.png | Bin 0 -> 145 bytes phpmyadmin/themes/original/img/b_home.png | Bin 0 -> 238 bytes phpmyadmin/themes/original/img/b_import.png | Bin 0 -> 202 bytes phpmyadmin/themes/original/img/b_index.png | Bin 0 -> 207 bytes phpmyadmin/themes/original/img/b_index_add.png | Bin 0 -> 429 bytes phpmyadmin/themes/original/img/b_info.png | Bin 0 -> 147 bytes phpmyadmin/themes/original/img/b_inline_edit.png | Bin 0 -> 302 bytes phpmyadmin/themes/original/img/b_insrow.png | Bin 0 -> 183 bytes phpmyadmin/themes/original/img/b_minus.png | Bin 0 -> 110 bytes phpmyadmin/themes/original/img/b_more.png | Bin 0 -> 132 bytes phpmyadmin/themes/original/img/b_move.png | Bin 0 -> 168 bytes phpmyadmin/themes/original/img/b_newdb.png | Bin 0 -> 260 bytes phpmyadmin/themes/original/img/b_newtbl.png | Bin 0 -> 264 bytes phpmyadmin/themes/original/img/b_nextpage.png | Bin 0 -> 373 bytes phpmyadmin/themes/original/img/b_plus.png | Bin 0 -> 115 bytes phpmyadmin/themes/original/img/b_primary.png | Bin 0 -> 278 bytes phpmyadmin/themes/original/img/b_print.png | Bin 0 -> 396 bytes phpmyadmin/themes/original/img/b_props.png | Bin 0 -> 188 bytes phpmyadmin/themes/original/img/b_relations.png | Bin 0 -> 172 bytes phpmyadmin/themes/original/img/b_routine_add.png | Bin 0 -> 409 bytes phpmyadmin/themes/original/img/b_routines.png | Bin 0 -> 310 bytes phpmyadmin/themes/original/img/b_save.png | Bin 0 -> 844 bytes phpmyadmin/themes/original/img/b_sbrowse.png | Bin 0 -> 122 bytes phpmyadmin/themes/original/img/b_search.png | Bin 0 -> 442 bytes phpmyadmin/themes/original/img/b_selboard.png | Bin 0 -> 175 bytes phpmyadmin/themes/original/img/b_select.png | Bin 0 -> 387 bytes phpmyadmin/themes/original/img/b_snewtbl.png | Bin 0 -> 168 bytes phpmyadmin/themes/original/img/b_spatial.png | Bin 0 -> 379 bytes phpmyadmin/themes/original/img/b_sql.png | Bin 0 -> 208 bytes phpmyadmin/themes/original/img/b_sqlhelp.png | Bin 0 -> 173 bytes phpmyadmin/themes/original/img/b_table_add.png | Bin 0 -> 368 bytes phpmyadmin/themes/original/img/b_tblanalyse.png | Bin 0 -> 188 bytes phpmyadmin/themes/original/img/b_tblexport.png | Bin 0 -> 176 bytes phpmyadmin/themes/original/img/b_tblimport.png | Bin 0 -> 174 bytes phpmyadmin/themes/original/img/b_tblops.png | Bin 0 -> 220 bytes phpmyadmin/themes/original/img/b_tbloptimize.png | Bin 0 -> 198 bytes phpmyadmin/themes/original/img/b_tipp.png | Bin 0 -> 201 bytes phpmyadmin/themes/original/img/b_trigger_add.png | Bin 0 -> 615 bytes phpmyadmin/themes/original/img/b_triggers.png | Bin 0 -> 494 bytes phpmyadmin/themes/original/img/b_unique.png | Bin 0 -> 175 bytes phpmyadmin/themes/original/img/b_usradd.png | Bin 0 -> 352 bytes phpmyadmin/themes/original/img/b_usrcheck.png | Bin 0 -> 259 bytes phpmyadmin/themes/original/img/b_usrdrop.png | Bin 0 -> 289 bytes phpmyadmin/themes/original/img/b_usredit.png | Bin 0 -> 339 bytes phpmyadmin/themes/original/img/b_usrlist.png | Bin 0 -> 262 bytes phpmyadmin/themes/original/img/b_view.png | Bin 0 -> 646 bytes phpmyadmin/themes/original/img/b_view_add.png | Bin 0 -> 726 bytes phpmyadmin/themes/original/img/b_views.png | Bin 0 -> 326 bytes phpmyadmin/themes/original/img/bd_browse.png | Bin 0 -> 157 bytes phpmyadmin/themes/original/img/bd_deltbl.png | Bin 0 -> 278 bytes phpmyadmin/themes/original/img/bd_drop.png | Bin 0 -> 205 bytes phpmyadmin/themes/original/img/bd_edit.png | Bin 0 -> 226 bytes phpmyadmin/themes/original/img/bd_empty.png | Bin 0 -> 186 bytes phpmyadmin/themes/original/img/bd_export.png | Bin 0 -> 183 bytes phpmyadmin/themes/original/img/bd_ftext.png | Bin 0 -> 175 bytes phpmyadmin/themes/original/img/bd_index.png | Bin 0 -> 207 bytes phpmyadmin/themes/original/img/bd_insrow.png | Bin 0 -> 224 bytes phpmyadmin/themes/original/img/bd_nextpage.png | Bin 0 -> 110 bytes phpmyadmin/themes/original/img/bd_primary.png | Bin 0 -> 257 bytes phpmyadmin/themes/original/img/bd_sbrowse.png | Bin 0 -> 122 bytes phpmyadmin/themes/original/img/bd_select.png | Bin 0 -> 375 bytes phpmyadmin/themes/original/img/bd_spatial.png | Bin 0 -> 344 bytes phpmyadmin/themes/original/img/bd_unique.png | Bin 0 -> 175 bytes phpmyadmin/themes/original/img/cleardot.gif | Bin 0 -> 43 bytes phpmyadmin/themes/original/img/col_drop.png | Bin 0 -> 132 bytes phpmyadmin/themes/original/img/col_pointer.png | Bin 0 -> 101 bytes phpmyadmin/themes/original/img/col_pointer_ver.png | Bin 0 -> 111 bytes phpmyadmin/themes/original/img/east-mini.png | Bin 0 -> 322 bytes phpmyadmin/themes/original/img/error.ico | Bin 0 -> 1150 bytes phpmyadmin/themes/original/img/eye.png | Bin 0 -> 721 bytes phpmyadmin/themes/original/img/eye_grey.png | Bin 0 -> 330 bytes phpmyadmin/themes/original/img/logo_left.png | Bin 0 -> 6796 bytes phpmyadmin/themes/original/img/logo_right.png | Bin 0 -> 4548 bytes phpmyadmin/themes/original/img/more.png | Bin 0 -> 117 bytes phpmyadmin/themes/original/img/new_data.png | Bin 0 -> 264 bytes .../themes/original/img/new_data_hovered.png | Bin 0 -> 264 bytes .../themes/original/img/new_data_selected.png | Bin 0 -> 179 bytes .../original/img/new_data_selected_hovered.png | Bin 0 -> 181 bytes phpmyadmin/themes/original/img/new_struct.png | Bin 0 -> 301 bytes .../themes/original/img/new_struct_hovered.png | Bin 0 -> 301 bytes .../themes/original/img/new_struct_selected.png | Bin 0 -> 189 bytes .../original/img/new_struct_selected_hovered.png | Bin 0 -> 196 bytes phpmyadmin/themes/original/img/north-mini.png | Bin 0 -> 327 bytes phpmyadmin/themes/original/img/pause.png | Bin 0 -> 271 bytes phpmyadmin/themes/original/img/play.png | Bin 0 -> 373 bytes phpmyadmin/themes/original/img/s_asc.png | Bin 0 -> 128 bytes phpmyadmin/themes/original/img/s_asci.png | Bin 0 -> 136 bytes phpmyadmin/themes/original/img/s_cancel.png | Bin 0 -> 310 bytes phpmyadmin/themes/original/img/s_cog.png | Bin 0 -> 222 bytes phpmyadmin/themes/original/img/s_db.png | Bin 0 -> 180 bytes phpmyadmin/themes/original/img/s_desc.png | Bin 0 -> 137 bytes phpmyadmin/themes/original/img/s_error.png | Bin 0 -> 173 bytes phpmyadmin/themes/original/img/s_error2.png | Bin 0 -> 152 bytes phpmyadmin/themes/original/img/s_fulltext.png | Bin 0 -> 193 bytes phpmyadmin/themes/original/img/s_host.png | Bin 0 -> 209 bytes phpmyadmin/themes/original/img/s_lang.png | Bin 0 -> 281 bytes phpmyadmin/themes/original/img/s_loggoff.png | Bin 0 -> 163 bytes phpmyadmin/themes/original/img/s_notice.png | Bin 0 -> 151 bytes phpmyadmin/themes/original/img/s_partialtext.png | Bin 0 -> 196 bytes phpmyadmin/themes/original/img/s_passwd.png | Bin 0 -> 353 bytes phpmyadmin/themes/original/img/s_really.png | Bin 0 -> 145 bytes phpmyadmin/themes/original/img/s_reload.png | Bin 0 -> 285 bytes phpmyadmin/themes/original/img/s_replication.png | Bin 0 -> 424 bytes phpmyadmin/themes/original/img/s_rights.png | Bin 0 -> 355 bytes phpmyadmin/themes/original/img/s_sortable.png | Bin 0 -> 132 bytes phpmyadmin/themes/original/img/s_status.png | Bin 0 -> 198 bytes phpmyadmin/themes/original/img/s_success.png | Bin 0 -> 589 bytes phpmyadmin/themes/original/img/s_sync.png | Bin 0 -> 498 bytes phpmyadmin/themes/original/img/s_tbl.png | Bin 0 -> 142 bytes phpmyadmin/themes/original/img/s_theme.png | Bin 0 -> 546 bytes phpmyadmin/themes/original/img/s_top.png | Bin 0 -> 443 bytes phpmyadmin/themes/original/img/s_vars.png | Bin 0 -> 190 bytes phpmyadmin/themes/original/img/s_views.png | Bin 0 -> 235 bytes phpmyadmin/themes/original/img/south-mini.png | Bin 0 -> 335 bytes phpmyadmin/themes/original/img/spacer.png | Bin 0 -> 84 bytes phpmyadmin/themes/original/img/sprites.png | Bin 0 -> 18431 bytes phpmyadmin/themes/original/img/toggle-ltr.png | Bin 0 -> 177 bytes phpmyadmin/themes/original/img/toggle-rtl.png | Bin 0 -> 177 bytes phpmyadmin/themes/original/img/vertical_line.png | Bin 0 -> 68 bytes phpmyadmin/themes/original/img/west-mini.png | Bin 0 -> 328 bytes phpmyadmin/themes/original/img/window-new.png | Bin 0 -> 484 bytes phpmyadmin/themes/original/img/zoom-minus-mini.png | Bin 0 -> 247 bytes phpmyadmin/themes/original/img/zoom-plus-mini.png | Bin 0 -> 329 bytes phpmyadmin/themes/original/img/zoom-world-mini.png | Bin 0 -> 808 bytes phpmyadmin/themes/original/info.inc.php | 15 + .../jquery/images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 0 -> 180 bytes .../jquery/images/ui-bg_flat_75_ffffff_40x100.png | Bin 0 -> 178 bytes .../jquery/images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 0 -> 120 bytes .../jquery/images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 105 bytes .../jquery/images/ui-bg_glass_75_dadada_1x400.png | Bin 0 -> 159 bytes .../jquery/images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 0 -> 110 bytes .../jquery/images/ui-bg_glass_95_fef1ec_1x400.png | Bin 0 -> 119 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 0 -> 101 bytes .../jquery/images/ui-icons_222222_256x240.png | Bin 0 -> 4369 bytes .../jquery/images/ui-icons_2e83ff_256x240.png | Bin 0 -> 4369 bytes .../jquery/images/ui-icons_454545_256x240.png | Bin 0 -> 4369 bytes .../jquery/images/ui-icons_888888_256x240.png | Bin 0 -> 4369 bytes .../jquery/images/ui-icons_cd0a0a_256x240.png | Bin 0 -> 4369 bytes .../original/jquery/jquery-ui-1.9.2.custom.css | 462 + phpmyadmin/themes/original/layout.inc.php | 138 + phpmyadmin/themes/original/screen.png | Bin 0 -> 53043 bytes phpmyadmin/themes/original/sprites.lib.php | 625 + phpmyadmin/themes/pmahomme/css/codemirror.css.php | 162 + phpmyadmin/themes/pmahomme/css/common.css.php | 2756 ++ phpmyadmin/themes/pmahomme/css/enum_editor.css.php | 80 + phpmyadmin/themes/pmahomme/css/gis.css.php | 65 + phpmyadmin/themes/pmahomme/css/jqplot.css.php | 277 + phpmyadmin/themes/pmahomme/css/navigation.css.php | 242 + phpmyadmin/themes/pmahomme/css/pmd.css.php | 529 + .../themes/pmahomme/css/resizable-menu.css.php | 57 + phpmyadmin/themes/pmahomme/css/rte.css.php | 43 + .../themes/pmahomme/img/ajax_clock_small.gif | Bin 0 -> 1810 bytes phpmyadmin/themes/pmahomme/img/arrow_ltr.png | Bin 0 -> 139 bytes phpmyadmin/themes/pmahomme/img/arrow_rtl.png | Bin 0 -> 136 bytes phpmyadmin/themes/pmahomme/img/asc_order.png | Bin 0 -> 182 bytes phpmyadmin/themes/pmahomme/img/b_bookmark.png | Bin 0 -> 677 bytes phpmyadmin/themes/pmahomme/img/b_browse.png | Bin 0 -> 536 bytes phpmyadmin/themes/pmahomme/img/b_calendar.png | Bin 0 -> 638 bytes phpmyadmin/themes/pmahomme/img/b_chart.png | Bin 0 -> 504 bytes phpmyadmin/themes/pmahomme/img/b_close.png | Bin 0 -> 180 bytes phpmyadmin/themes/pmahomme/img/b_column_add.png | Bin 0 -> 534 bytes phpmyadmin/themes/pmahomme/img/b_comment.png | Bin 0 -> 454 bytes phpmyadmin/themes/pmahomme/img/b_dbstatistics.png | Bin 0 -> 504 bytes phpmyadmin/themes/pmahomme/img/b_deltbl.png | Bin 0 -> 623 bytes phpmyadmin/themes/pmahomme/img/b_docs.png | Bin 0 -> 756 bytes phpmyadmin/themes/pmahomme/img/b_docsql.png | Bin 0 -> 188 bytes phpmyadmin/themes/pmahomme/img/b_drop.png | Bin 0 -> 687 bytes phpmyadmin/themes/pmahomme/img/b_edit.png | Bin 0 -> 407 bytes phpmyadmin/themes/pmahomme/img/b_empty.png | Bin 0 -> 615 bytes phpmyadmin/themes/pmahomme/img/b_engine.png | Bin 0 -> 431 bytes phpmyadmin/themes/pmahomme/img/b_event_add.png | Bin 0 -> 863 bytes phpmyadmin/themes/pmahomme/img/b_events.png | Bin 0 -> 783 bytes phpmyadmin/themes/pmahomme/img/b_export.png | Bin 0 -> 606 bytes phpmyadmin/themes/pmahomme/img/b_firstpage.png | Bin 0 -> 754 bytes phpmyadmin/themes/pmahomme/img/b_ftext.png | Bin 0 -> 576 bytes phpmyadmin/themes/pmahomme/img/b_globe.gif | Bin 0 -> 1045 bytes phpmyadmin/themes/pmahomme/img/b_group.png | Bin 0 -> 796 bytes phpmyadmin/themes/pmahomme/img/b_help.png | Bin 0 -> 740 bytes phpmyadmin/themes/pmahomme/img/b_home.png | Bin 0 -> 801 bytes phpmyadmin/themes/pmahomme/img/b_import.png | Bin 0 -> 592 bytes phpmyadmin/themes/pmahomme/img/b_index.png | Bin 0 -> 708 bytes phpmyadmin/themes/pmahomme/img/b_index_add.png | Bin 0 -> 839 bytes phpmyadmin/themes/pmahomme/img/b_info.png | Bin 0 -> 147 bytes phpmyadmin/themes/pmahomme/img/b_inline_edit.png | Bin 0 -> 621 bytes phpmyadmin/themes/pmahomme/img/b_insrow.png | Bin 0 -> 183 bytes phpmyadmin/themes/pmahomme/img/b_lastpage.png | Bin 0 -> 746 bytes phpmyadmin/themes/pmahomme/img/b_minus.png | Bin 0 -> 224 bytes phpmyadmin/themes/pmahomme/img/b_more.png | Bin 0 -> 132 bytes phpmyadmin/themes/pmahomme/img/b_move.png | Bin 0 -> 520 bytes phpmyadmin/themes/pmahomme/img/b_newdb.png | Bin 0 -> 650 bytes phpmyadmin/themes/pmahomme/img/b_newtbl.png | Bin 0 -> 264 bytes phpmyadmin/themes/pmahomme/img/b_nextpage.png | Bin 0 -> 373 bytes phpmyadmin/themes/pmahomme/img/b_pdfdoc.png | Bin 0 -> 595 bytes phpmyadmin/themes/pmahomme/img/b_plus.png | Bin 0 -> 237 bytes phpmyadmin/themes/pmahomme/img/b_prevpage.png | Bin 0 -> 369 bytes phpmyadmin/themes/pmahomme/img/b_primary.png | Bin 0 -> 619 bytes phpmyadmin/themes/pmahomme/img/b_print.png | Bin 0 -> 702 bytes phpmyadmin/themes/pmahomme/img/b_props.png | Bin 0 -> 655 bytes phpmyadmin/themes/pmahomme/img/b_relations.png | Bin 0 -> 172 bytes phpmyadmin/themes/pmahomme/img/b_routine_add.png | Bin 0 -> 409 bytes phpmyadmin/themes/pmahomme/img/b_routines.png | Bin 0 -> 310 bytes phpmyadmin/themes/pmahomme/img/b_save.png | Bin 0 -> 585 bytes phpmyadmin/themes/pmahomme/img/b_sbrowse.png | Bin 0 -> 536 bytes phpmyadmin/themes/pmahomme/img/b_sdb.png | Bin 0 -> 148 bytes phpmyadmin/themes/pmahomme/img/b_search.png | Bin 0 -> 578 bytes phpmyadmin/themes/pmahomme/img/b_selboard.png | Bin 0 -> 676 bytes phpmyadmin/themes/pmahomme/img/b_select.png | Bin 0 -> 645 bytes phpmyadmin/themes/pmahomme/img/b_snewtbl.png | Bin 0 -> 717 bytes phpmyadmin/themes/pmahomme/img/b_spatial.png | Bin 0 -> 379 bytes phpmyadmin/themes/pmahomme/img/b_sql.png | Bin 0 -> 723 bytes phpmyadmin/themes/pmahomme/img/b_sqldoc.png | Bin 0 -> 194 bytes phpmyadmin/themes/pmahomme/img/b_sqlhelp.png | Bin 0 -> 590 bytes phpmyadmin/themes/pmahomme/img/b_table_add.png | Bin 0 -> 676 bytes phpmyadmin/themes/pmahomme/img/b_tblanalyse.png | Bin 0 -> 188 bytes phpmyadmin/themes/pmahomme/img/b_tblexport.png | Bin 0 -> 606 bytes phpmyadmin/themes/pmahomme/img/b_tblimport.png | Bin 0 -> 592 bytes phpmyadmin/themes/pmahomme/img/b_tblops.png | Bin 0 -> 618 bytes phpmyadmin/themes/pmahomme/img/b_tbloptimize.png | Bin 0 -> 198 bytes phpmyadmin/themes/pmahomme/img/b_tipp.png | Bin 0 -> 764 bytes phpmyadmin/themes/pmahomme/img/b_trigger_add.png | Bin 0 -> 615 bytes phpmyadmin/themes/pmahomme/img/b_triggers.png | Bin 0 -> 494 bytes phpmyadmin/themes/pmahomme/img/b_unique.png | Bin 0 -> 615 bytes phpmyadmin/themes/pmahomme/img/b_usradd.png | Bin 0 -> 750 bytes phpmyadmin/themes/pmahomme/img/b_usrcheck.png | Bin 0 -> 773 bytes phpmyadmin/themes/pmahomme/img/b_usrdrop.png | Bin 0 -> 756 bytes phpmyadmin/themes/pmahomme/img/b_usredit.png | Bin 0 -> 845 bytes phpmyadmin/themes/pmahomme/img/b_usrlist.png | Bin 0 -> 774 bytes phpmyadmin/themes/pmahomme/img/b_view.png | Bin 0 -> 646 bytes phpmyadmin/themes/pmahomme/img/b_view_add.png | Bin 0 -> 766 bytes phpmyadmin/themes/pmahomme/img/b_views.png | Bin 0 -> 630 bytes phpmyadmin/themes/pmahomme/img/bd_browse.png | Bin 0 -> 431 bytes phpmyadmin/themes/pmahomme/img/bd_deltbl.png | Bin 0 -> 510 bytes phpmyadmin/themes/pmahomme/img/bd_drop.png | Bin 0 -> 560 bytes phpmyadmin/themes/pmahomme/img/bd_edit.png | Bin 0 -> 271 bytes phpmyadmin/themes/pmahomme/img/bd_empty.png | Bin 0 -> 511 bytes phpmyadmin/themes/pmahomme/img/bd_export.png | Bin 0 -> 326 bytes phpmyadmin/themes/pmahomme/img/bd_firstpage.png | Bin 0 -> 613 bytes phpmyadmin/themes/pmahomme/img/bd_ftext.png | Bin 0 -> 473 bytes phpmyadmin/themes/pmahomme/img/bd_index.png | Bin 0 -> 560 bytes phpmyadmin/themes/pmahomme/img/bd_insrow.png | Bin 0 -> 224 bytes phpmyadmin/themes/pmahomme/img/bd_lastpage.png | Bin 0 -> 603 bytes phpmyadmin/themes/pmahomme/img/bd_nextpage.png | Bin 0 -> 302 bytes phpmyadmin/themes/pmahomme/img/bd_prevpage.png | Bin 0 -> 303 bytes phpmyadmin/themes/pmahomme/img/bd_primary.png | Bin 0 -> 476 bytes phpmyadmin/themes/pmahomme/img/bd_sbrowse.png | Bin 0 -> 431 bytes phpmyadmin/themes/pmahomme/img/bd_select.png | Bin 0 -> 536 bytes phpmyadmin/themes/pmahomme/img/bd_spatial.png | Bin 0 -> 375 bytes phpmyadmin/themes/pmahomme/img/bd_unique.png | Bin 0 -> 508 bytes phpmyadmin/themes/pmahomme/img/col_drop.png | Bin 0 -> 132 bytes phpmyadmin/themes/pmahomme/img/col_pointer.png | Bin 0 -> 113 bytes phpmyadmin/themes/pmahomme/img/col_pointer_ver.png | Bin 0 -> 117 bytes phpmyadmin/themes/pmahomme/img/database.png | Bin 0 -> 353 bytes phpmyadmin/themes/pmahomme/img/east-mini.png | Bin 0 -> 322 bytes phpmyadmin/themes/pmahomme/img/error.ico | Bin 0 -> 5430 bytes phpmyadmin/themes/pmahomme/img/eye.png | Bin 0 -> 721 bytes phpmyadmin/themes/pmahomme/img/eye_grey.png | Bin 0 -> 330 bytes phpmyadmin/themes/pmahomme/img/item.png | Bin 0 -> 134 bytes phpmyadmin/themes/pmahomme/img/left_nav_bg.png | Bin 0 -> 297 bytes phpmyadmin/themes/pmahomme/img/logo_left.png | Bin 0 -> 2327 bytes phpmyadmin/themes/pmahomme/img/logo_right.png | Bin 0 -> 4548 bytes phpmyadmin/themes/pmahomme/img/more.png | Bin 0 -> 117 bytes phpmyadmin/themes/pmahomme/img/new_data.png | Bin 0 -> 264 bytes .../themes/pmahomme/img/new_data_hovered.png | Bin 0 -> 264 bytes .../themes/pmahomme/img/new_data_selected.png | Bin 0 -> 179 bytes .../pmahomme/img/new_data_selected_hovered.png | Bin 0 -> 181 bytes phpmyadmin/themes/pmahomme/img/new_struct.png | Bin 0 -> 301 bytes .../themes/pmahomme/img/new_struct_hovered.png | Bin 0 -> 301 bytes .../themes/pmahomme/img/new_struct_selected.png | Bin 0 -> 189 bytes .../pmahomme/img/new_struct_selected_hovered.png | Bin 0 -> 196 bytes phpmyadmin/themes/pmahomme/img/north-mini.png | Bin 0 -> 327 bytes phpmyadmin/themes/pmahomme/img/pause.png | Bin 0 -> 271 bytes phpmyadmin/themes/pmahomme/img/php_sym.png | Bin 0 -> 156 bytes phpmyadmin/themes/pmahomme/img/play.png | Bin 0 -> 373 bytes phpmyadmin/themes/pmahomme/img/pma_logo2.png | Bin 0 -> 1424 bytes phpmyadmin/themes/pmahomme/img/pmd/1.png | Bin 0 -> 101 bytes phpmyadmin/themes/pmahomme/img/pmd/2.png | Bin 0 -> 169 bytes phpmyadmin/themes/pmahomme/img/pmd/2leftarrow.png | Bin 0 -> 702 bytes .../themes/pmahomme/img/pmd/2leftarrow_m.png | Bin 0 -> 666 bytes phpmyadmin/themes/pmahomme/img/pmd/2rightarrow.png | Bin 0 -> 737 bytes .../themes/pmahomme/img/pmd/2rightarrow_m.png | Bin 0 -> 699 bytes phpmyadmin/themes/pmahomme/img/pmd/3.png | Bin 0 -> 175 bytes phpmyadmin/themes/pmahomme/img/pmd/4.png | Bin 0 -> 181 bytes phpmyadmin/themes/pmahomme/img/pmd/5.png | Bin 0 -> 90 bytes phpmyadmin/themes/pmahomme/img/pmd/6.png | Bin 0 -> 98 bytes phpmyadmin/themes/pmahomme/img/pmd/7.png | Bin 0 -> 105 bytes phpmyadmin/themes/pmahomme/img/pmd/8.png | Bin 0 -> 88 bytes .../themes/pmahomme/img/pmd/FieldKey_small.png | Bin 0 -> 229 bytes phpmyadmin/themes/pmahomme/img/pmd/Field_small.png | Bin 0 -> 275 bytes .../themes/pmahomme/img/pmd/Field_small_char.png | Bin 0 -> 154 bytes .../themes/pmahomme/img/pmd/Field_small_date.png | Bin 0 -> 156 bytes .../themes/pmahomme/img/pmd/Field_small_int.png | Bin 0 -> 145 bytes phpmyadmin/themes/pmahomme/img/pmd/Header.png | Bin 0 -> 125 bytes .../themes/pmahomme/img/pmd/Header_Linked.png | Bin 0 -> 108 bytes phpmyadmin/themes/pmahomme/img/pmd/and_icon.png | Bin 0 -> 792 bytes phpmyadmin/themes/pmahomme/img/pmd/ang_direct.png | Bin 0 -> 679 bytes phpmyadmin/themes/pmahomme/img/pmd/bord.png | Bin 0 -> 87 bytes phpmyadmin/themes/pmahomme/img/pmd/bottom.png | Bin 0 -> 734 bytes phpmyadmin/themes/pmahomme/img/pmd/def.png | Bin 0 -> 670 bytes .../themes/pmahomme/img/pmd/display_field.png | Bin 0 -> 685 bytes phpmyadmin/themes/pmahomme/img/pmd/downarrow1.png | Bin 0 -> 758 bytes phpmyadmin/themes/pmahomme/img/pmd/downarrow2.png | Bin 0 -> 772 bytes .../themes/pmahomme/img/pmd/downarrow2_m.png | Bin 0 -> 711 bytes phpmyadmin/themes/pmahomme/img/pmd/exec.png | Bin 0 -> 796 bytes phpmyadmin/themes/pmahomme/img/pmd/exec_small.png | Bin 0 -> 161 bytes .../themes/pmahomme/img/pmd/exitFullscreen.png | Bin 0 -> 444 bytes phpmyadmin/themes/pmahomme/img/pmd/favicon.ico | Bin 0 -> 1150 bytes phpmyadmin/themes/pmahomme/img/pmd/grid.png | Bin 0 -> 688 bytes phpmyadmin/themes/pmahomme/img/pmd/help.png | Bin 0 -> 714 bytes .../themes/pmahomme/img/pmd/help_relation.png | Bin 0 -> 920 bytes .../themes/pmahomme/img/pmd/left_panel_butt.png | Bin 0 -> 129 bytes .../themes/pmahomme/img/pmd/left_panel_tab.png | Bin 0 -> 133 bytes phpmyadmin/themes/pmahomme/img/pmd/minus.png | Bin 0 -> 1004 bytes phpmyadmin/themes/pmahomme/img/pmd/or_icon.png | Bin 0 -> 611 bytes phpmyadmin/themes/pmahomme/img/pmd/pdf.png | Bin 0 -> 905 bytes phpmyadmin/themes/pmahomme/img/pmd/plus.png | Bin 0 -> 969 bytes .../themes/pmahomme/img/pmd/query_builder.png | Bin 0 -> 685 bytes phpmyadmin/themes/pmahomme/img/pmd/relation.png | Bin 0 -> 295 bytes phpmyadmin/themes/pmahomme/img/pmd/reload.png | Bin 0 -> 874 bytes phpmyadmin/themes/pmahomme/img/pmd/resize.png | Bin 0 -> 121 bytes phpmyadmin/themes/pmahomme/img/pmd/rightarrow1.png | Bin 0 -> 746 bytes phpmyadmin/themes/pmahomme/img/pmd/rightarrow2.png | Bin 0 -> 757 bytes phpmyadmin/themes/pmahomme/img/pmd/save.png | Bin 0 -> 409 bytes phpmyadmin/themes/pmahomme/img/pmd/small_tab.png | Bin 0 -> 180 bytes phpmyadmin/themes/pmahomme/img/pmd/table.png | Bin 0 -> 163 bytes .../themes/pmahomme/img/pmd/toggle_lines.png | Bin 0 -> 630 bytes phpmyadmin/themes/pmahomme/img/pmd/top_panel.png | Bin 0 -> 173 bytes phpmyadmin/themes/pmahomme/img/pmd/uparrow2_m.png | Bin 0 -> 729 bytes .../themes/pmahomme/img/pmd/viewInFullscreen.png | Bin 0 -> 472 bytes phpmyadmin/themes/pmahomme/img/s_asc.png | Bin 0 -> 169 bytes phpmyadmin/themes/pmahomme/img/s_asci.png | Bin 0 -> 184 bytes phpmyadmin/themes/pmahomme/img/s_attention.png | Bin 0 -> 629 bytes phpmyadmin/themes/pmahomme/img/s_cancel.png | Bin 0 -> 575 bytes phpmyadmin/themes/pmahomme/img/s_cancel2.png | Bin 0 -> 305 bytes phpmyadmin/themes/pmahomme/img/s_cog.png | Bin 0 -> 475 bytes phpmyadmin/themes/pmahomme/img/s_db.png | Bin 0 -> 353 bytes phpmyadmin/themes/pmahomme/img/s_desc.png | Bin 0 -> 182 bytes phpmyadmin/themes/pmahomme/img/s_error.png | Bin 0 -> 664 bytes phpmyadmin/themes/pmahomme/img/s_error2.png | Bin 0 -> 152 bytes phpmyadmin/themes/pmahomme/img/s_fulltext.png | Bin 0 -> 193 bytes phpmyadmin/themes/pmahomme/img/s_host.png | Bin 0 -> 655 bytes phpmyadmin/themes/pmahomme/img/s_info.png | Bin 0 -> 740 bytes phpmyadmin/themes/pmahomme/img/s_lang.png | Bin 0 -> 755 bytes phpmyadmin/themes/pmahomme/img/s_loggoff.png | Bin 0 -> 651 bytes phpmyadmin/themes/pmahomme/img/s_notice.png | Bin 0 -> 629 bytes phpmyadmin/themes/pmahomme/img/s_okay.png | Bin 0 -> 772 bytes phpmyadmin/themes/pmahomme/img/s_partialtext.png | Bin 0 -> 196 bytes phpmyadmin/themes/pmahomme/img/s_passwd.png | Bin 0 -> 353 bytes phpmyadmin/themes/pmahomme/img/s_process.png | Bin 0 -> 475 bytes phpmyadmin/themes/pmahomme/img/s_really.png | Bin 0 -> 145 bytes phpmyadmin/themes/pmahomme/img/s_reload.png | Bin 0 -> 582 bytes phpmyadmin/themes/pmahomme/img/s_replication.png | Bin 0 -> 424 bytes phpmyadmin/themes/pmahomme/img/s_rights.png | Bin 0 -> 503 bytes phpmyadmin/themes/pmahomme/img/s_sortable.png | Bin 0 -> 234 bytes phpmyadmin/themes/pmahomme/img/s_status.png | Bin 0 -> 637 bytes phpmyadmin/themes/pmahomme/img/s_success.png | Bin 0 -> 552 bytes phpmyadmin/themes/pmahomme/img/s_sync.png | Bin 0 -> 498 bytes phpmyadmin/themes/pmahomme/img/s_tbl.png | Bin 0 -> 684 bytes phpmyadmin/themes/pmahomme/img/s_theme.png | Bin 0 -> 828 bytes phpmyadmin/themes/pmahomme/img/s_top.png | Bin 0 -> 443 bytes phpmyadmin/themes/pmahomme/img/s_vars.png | Bin 0 -> 614 bytes phpmyadmin/themes/pmahomme/img/s_views.png | Bin 0 -> 630 bytes phpmyadmin/themes/pmahomme/img/south-mini.png | Bin 0 -> 335 bytes phpmyadmin/themes/pmahomme/img/spacer.png | Bin 0 -> 84 bytes phpmyadmin/themes/pmahomme/img/sprites.png | Bin 0 -> 61899 bytes phpmyadmin/themes/pmahomme/img/toggle-ltr.png | Bin 0 -> 414 bytes phpmyadmin/themes/pmahomme/img/toggle-rtl.png | Bin 0 -> 414 bytes phpmyadmin/themes/pmahomme/img/vertical_line.png | Bin 0 -> 68 bytes phpmyadmin/themes/pmahomme/img/west-mini.png | Bin 0 -> 328 bytes phpmyadmin/themes/pmahomme/img/window-new.png | Bin 0 -> 484 bytes phpmyadmin/themes/pmahomme/img/zoom-minus-mini.png | Bin 0 -> 247 bytes phpmyadmin/themes/pmahomme/img/zoom-plus-mini.png | Bin 0 -> 329 bytes phpmyadmin/themes/pmahomme/img/zoom-world-mini.png | Bin 0 -> 808 bytes phpmyadmin/themes/pmahomme/info.inc.php | 16 + .../jquery/images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 0 -> 180 bytes .../jquery/images/ui-bg_flat_75_ffffff_40x100.png | Bin 0 -> 178 bytes .../jquery/images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 0 -> 120 bytes .../jquery/images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 105 bytes .../jquery/images/ui-bg_glass_75_dadada_1x400.png | Bin 0 -> 159 bytes .../jquery/images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 0 -> 110 bytes .../jquery/images/ui-bg_glass_95_fef1ec_1x400.png | Bin 0 -> 119 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 0 -> 101 bytes .../jquery/images/ui-icons_222222_256x240.png | Bin 0 -> 4369 bytes .../jquery/images/ui-icons_2e83ff_256x240.png | Bin 0 -> 4369 bytes .../jquery/images/ui-icons_454545_256x240.png | Bin 0 -> 4369 bytes .../jquery/images/ui-icons_888888_256x240.png | Bin 0 -> 4369 bytes .../jquery/images/ui-icons_cd0a0a_256x240.png | Bin 0 -> 4369 bytes .../pmahomme/jquery/jquery-ui-1.9.2.custom.css | 462 + phpmyadmin/themes/pmahomme/layout.inc.php | 140 + phpmyadmin/themes/pmahomme/screen.png | Bin 0 -> 63100 bytes phpmyadmin/themes/pmahomme/sprites.lib.php | 720 + phpmyadmin/themes/sprites.css.php | 82 + phpmyadmin/themes/svg_gradient.php | 30 + phpmyadmin/transformation_overview.php | 58 + phpmyadmin/transformation_wrapper.php | 149 + phpmyadmin/url.php | 22 + phpmyadmin/user_password.php | 242 + phpmyadmin/version_check.php | 47 + phpmyadmin/view_create.php | 235 + phpmyadmin/view_operations.php | 102 + phpmyadmin/webapp.php | 55 + 1113 files changed, 231323 insertions(+) create mode 100644 phpmyadmin/ChangeLog create mode 100644 phpmyadmin/LICENSE create mode 100644 phpmyadmin/README create mode 100644 phpmyadmin/RELEASE-DATE-4.0.4 create mode 100644 phpmyadmin/browse_foreigners.php create mode 100644 phpmyadmin/changelog.php create mode 100644 phpmyadmin/chk_rel.php create mode 100644 phpmyadmin/composer.json create mode 100644 phpmyadmin/config.sample.inc.php create mode 100644 phpmyadmin/db_create.php create mode 100644 phpmyadmin/db_datadict.php create mode 100644 phpmyadmin/db_events.php create mode 100644 phpmyadmin/db_export.php create mode 100644 phpmyadmin/db_import.php create mode 100644 phpmyadmin/db_operations.php create mode 100644 phpmyadmin/db_printview.php create mode 100644 phpmyadmin/db_qbe.php create mode 100644 phpmyadmin/db_routines.php create mode 100644 phpmyadmin/db_search.php create mode 100644 phpmyadmin/db_sql.php create mode 100644 phpmyadmin/db_structure.php create mode 100644 phpmyadmin/db_tracking.php create mode 100644 phpmyadmin/db_triggers.php create mode 100644 phpmyadmin/doc/Makefile create mode 100644 phpmyadmin/doc/_ext/configext.py 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/examples/config.manyhosts.inc.php create mode 100644 phpmyadmin/examples/create_tables.sql create mode 100644 phpmyadmin/examples/create_tables_drizzle.sql create mode 100644 phpmyadmin/examples/openid.php create mode 100644 phpmyadmin/examples/signon-script.php create mode 100644 phpmyadmin/examples/signon.php create mode 100644 phpmyadmin/examples/swekey.sample.conf create mode 100644 phpmyadmin/examples/upgrade_tables_mysql_4_1_2+.sql create mode 100644 phpmyadmin/export.php create mode 100644 phpmyadmin/favicon.ico create mode 100644 phpmyadmin/file_echo.php create mode 100644 phpmyadmin/gis_data_editor.php create mode 100644 phpmyadmin/import.php create mode 100644 phpmyadmin/import_status.php create mode 100644 phpmyadmin/index.php create mode 100644 phpmyadmin/js/OpenStreetMap.js create mode 100644 phpmyadmin/js/ajax.js create mode 100644 phpmyadmin/js/canvg/MIT-LICENSE.txt create mode 100644 phpmyadmin/js/canvg/canvg.js create mode 100644 phpmyadmin/js/canvg/flashcanvas.js create mode 100644 phpmyadmin/js/canvg/flashcanvas.swf create mode 100644 phpmyadmin/js/chart.js create mode 100644 phpmyadmin/js/codemirror/LICENSE create mode 100644 phpmyadmin/js/codemirror/lib/codemirror.js create mode 100644 phpmyadmin/js/codemirror/mode/mysql/mysql.js create mode 100644 phpmyadmin/js/common.js create mode 100644 phpmyadmin/js/config.js create mode 100644 phpmyadmin/js/date.js create mode 100644 phpmyadmin/js/db_operations.js create mode 100644 phpmyadmin/js/db_search.js create mode 100644 phpmyadmin/js/db_structure.js create mode 100644 phpmyadmin/js/export.js create mode 100644 phpmyadmin/js/functions.js create mode 100644 phpmyadmin/js/get_image.js.php create mode 100644 phpmyadmin/js/get_scripts.js.php create mode 100644 phpmyadmin/js/gis_data_editor.js create mode 100644 phpmyadmin/js/import.js create mode 100644 phpmyadmin/js/indexes.js create mode 100644 phpmyadmin/js/jqplot/excanvas.js create mode 100644 phpmyadmin/js/jqplot/jquery.jqplot.js create mode 100644 phpmyadmin/js/jqplot/plugins/jqplot.barRenderer.js create mode 100644 phpmyadmin/js/jqplot/plugins/jqplot.byteFormatter.js create mode 100644 phpmyadmin/js/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js create mode 100644 phpmyadmin/js/jqplot/plugins/jqplot.canvasTextRenderer.js create mode 100644 phpmyadmin/js/jqplot/plugins/jqplot.categoryAxisRenderer.js create mode 100644 phpmyadmin/js/jqplot/plugins/jqplot.cursor.js create mode 100644 phpmyadmin/js/jqplot/plugins/jqplot.dateAxisRenderer.js create mode 100644 phpmyadmin/js/jqplot/plugins/jqplot.highlighter.js create mode 100644 phpmyadmin/js/jqplot/plugins/jqplot.pieRenderer.js create mode 100644 phpmyadmin/js/jqplot/plugins/jqplot.pointLabels.js create mode 100644 phpmyadmin/js/jquery/jquery-1.8.3.js create mode 100644 phpmyadmin/js/jquery/jquery-ui-1.9.2.custom.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.cookie.js create mode 100644 phpmyadmin/js/jquery/jquery.debounce-1.0.5.js create mode 100644 phpmyadmin/js/jquery/jquery.event.drag-2.2.js create mode 100644 phpmyadmin/js/jquery/jquery.fullscreen.js create mode 100644 phpmyadmin/js/jquery/jquery.json-2.4.js create mode 100644 phpmyadmin/js/jquery/jquery.menuResizer-1.0.js create mode 100644 phpmyadmin/js/jquery/jquery.mousewheel.js create mode 100644 phpmyadmin/js/jquery/jquery.sortableTable.js create mode 100644 phpmyadmin/js/jquery/jquery.sprintf.js create mode 100644 phpmyadmin/js/jquery/jquery.svg.js create mode 100644 phpmyadmin/js/jquery/jquery.tablesorter.js create mode 100644 phpmyadmin/js/keyhandler.js create mode 100644 phpmyadmin/js/makegrid.js create mode 100644 phpmyadmin/js/messages.php create mode 100644 phpmyadmin/js/navigation.js create mode 100644 phpmyadmin/js/openlayers/OpenLayers.js create mode 100644 phpmyadmin/js/openlayers/img/blank.gif create mode 100644 phpmyadmin/js/openlayers/img/cloud-popup-relative.png create mode 100644 phpmyadmin/js/openlayers/img/drag-rectangle-off.png create mode 100644 phpmyadmin/js/openlayers/img/drag-rectangle-on.png create mode 100644 phpmyadmin/js/openlayers/img/east-mini.png create mode 100644 phpmyadmin/js/openlayers/img/layer-switcher-maximize.png create mode 100644 phpmyadmin/js/openlayers/img/layer-switcher-minimize.png create mode 100644 phpmyadmin/js/openlayers/img/marker-blue.png create mode 100644 phpmyadmin/js/openlayers/img/marker-gold.png create mode 100644 phpmyadmin/js/openlayers/img/marker-green.png create mode 100644 phpmyadmin/js/openlayers/img/marker.png create mode 100644 phpmyadmin/js/openlayers/img/measuring-stick-off.png create mode 100644 phpmyadmin/js/openlayers/img/measuring-stick-on.png create mode 100644 phpmyadmin/js/openlayers/img/north-mini.png create mode 100644 phpmyadmin/js/openlayers/img/panning-hand-off.png create mode 100644 phpmyadmin/js/openlayers/img/panning-hand-on.png create mode 100644 phpmyadmin/js/openlayers/img/slider.png create mode 100644 phpmyadmin/js/openlayers/img/south-mini.png create mode 100644 phpmyadmin/js/openlayers/img/west-mini.png create mode 100644 phpmyadmin/js/openlayers/img/zoom-minus-mini.png create mode 100644 phpmyadmin/js/openlayers/img/zoom-plus-mini.png create mode 100644 phpmyadmin/js/openlayers/img/zoom-world-mini.png create mode 100644 phpmyadmin/js/openlayers/img/zoombar.png create mode 100644 phpmyadmin/js/openlayers/theme/default/framedCloud.css create mode 100644 phpmyadmin/js/openlayers/theme/default/google.css create mode 100644 phpmyadmin/js/openlayers/theme/default/ie6-style.css create mode 100644 phpmyadmin/js/openlayers/theme/default/img/add_point_off.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/add_point_on.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/blank.gif create mode 100644 phpmyadmin/js/openlayers/theme/default/img/close.gif create mode 100644 phpmyadmin/js/openlayers/theme/default/img/drag-rectangle-off.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/drag-rectangle-on.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/draw_line_off.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/draw_line_on.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/draw_point_off.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/draw_point_on.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/draw_polygon_off.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/draw_polygon_on.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/editing_tool_bar.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/move_feature_off.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/move_feature_on.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/navigation_history.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/overview_replacement.gif create mode 100644 phpmyadmin/js/openlayers/theme/default/img/pan-panel-NOALPHA.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/pan-panel.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/pan_off.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/pan_on.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/panning-hand-off.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/panning-hand-on.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/remove_point_off.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/remove_point_on.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/ruler.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/save_features_off.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/save_features_on.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/view_next_off.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/view_next_on.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/view_previous_off.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/view_previous_on.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/zoom-panel-NOALPHA.png create mode 100644 phpmyadmin/js/openlayers/theme/default/img/zoom-panel.png create mode 100644 phpmyadmin/js/openlayers/theme/default/style.css create mode 100644 phpmyadmin/js/pmd/ajax.js create mode 100644 phpmyadmin/js/pmd/history.js create mode 100644 phpmyadmin/js/pmd/iecanvas.js create mode 100644 phpmyadmin/js/pmd/init.js create mode 100644 phpmyadmin/js/pmd/move.js create mode 100644 phpmyadmin/js/querywindow.js create mode 100644 phpmyadmin/js/replication.js create mode 100644 phpmyadmin/js/rte.js create mode 100644 phpmyadmin/js/server_databases.js create mode 100644 phpmyadmin/js/server_plugins.js create mode 100644 phpmyadmin/js/server_privileges.js create mode 100644 phpmyadmin/js/server_status.js create mode 100644 phpmyadmin/js/server_status_advisor.js create mode 100644 phpmyadmin/js/server_status_monitor.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 create mode 100644 phpmyadmin/js/server_variables.js create mode 100644 phpmyadmin/js/sql.js create mode 100644 phpmyadmin/js/tbl_change.js create mode 100644 phpmyadmin/js/tbl_chart.js create mode 100644 phpmyadmin/js/tbl_gis_visualization.js create mode 100644 phpmyadmin/js/tbl_relation.js create mode 100644 phpmyadmin/js/tbl_select.js create mode 100644 phpmyadmin/js/tbl_structure.js create mode 100644 phpmyadmin/js/tbl_zoom_plot_jqplot.js create mode 100644 phpmyadmin/libraries/.htaccess create mode 100644 phpmyadmin/libraries/Advisor.class.php create mode 100644 phpmyadmin/libraries/Config.class.php create mode 100644 phpmyadmin/libraries/DBQbe.class.php create mode 100644 phpmyadmin/libraries/DbSearch.class.php create mode 100644 phpmyadmin/libraries/DisplayResults.class.php create mode 100644 phpmyadmin/libraries/Error.class.php create mode 100644 phpmyadmin/libraries/Error_Handler.class.php create mode 100644 phpmyadmin/libraries/File.class.php create mode 100644 phpmyadmin/libraries/Footer.class.php create mode 100644 phpmyadmin/libraries/Header.class.php create mode 100644 phpmyadmin/libraries/Index.class.php create mode 100644 phpmyadmin/libraries/List.class.php create mode 100644 phpmyadmin/libraries/List_Database.class.php create mode 100644 phpmyadmin/libraries/Menu.class.php create mode 100644 phpmyadmin/libraries/Message.class.php create mode 100644 phpmyadmin/libraries/OutputBuffering.class.php create mode 100644 phpmyadmin/libraries/PDF.class.php create mode 100644 phpmyadmin/libraries/PMA.php create mode 100644 phpmyadmin/libraries/Partition.class.php create mode 100644 phpmyadmin/libraries/RecentTable.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/StorageEngine.class.php create mode 100644 phpmyadmin/libraries/Table.class.php create mode 100644 phpmyadmin/libraries/TableSearch.class.php create mode 100644 phpmyadmin/libraries/Theme.class.php create mode 100644 phpmyadmin/libraries/Theme_Manager.class.php create mode 100644 phpmyadmin/libraries/Tracker.class.php create mode 100644 phpmyadmin/libraries/Types.class.php create mode 100644 phpmyadmin/libraries/Util.class.php create mode 100644 phpmyadmin/libraries/advisory_rules.txt create mode 100644 phpmyadmin/libraries/bfShapeFiles/ShapeFile.lib.php create mode 100644 phpmyadmin/libraries/bookmark.lib.php create mode 100644 phpmyadmin/libraries/build_html_for_db.lib.php create mode 100644 phpmyadmin/libraries/charset_conversion.lib.php create mode 100644 phpmyadmin/libraries/check_user_privileges.lib.php create mode 100644 phpmyadmin/libraries/cleanup.lib.php create mode 100644 phpmyadmin/libraries/common.inc.php create mode 100644 phpmyadmin/libraries/config.default.php create mode 100644 phpmyadmin/libraries/config.values.php create mode 100644 phpmyadmin/libraries/config/ConfigFile.class.php create mode 100644 phpmyadmin/libraries/config/Form.class.php create mode 100644 phpmyadmin/libraries/config/FormDisplay.class.php create mode 100644 phpmyadmin/libraries/config/FormDisplay.tpl.php create mode 100644 phpmyadmin/libraries/config/config_functions.lib.php create mode 100644 phpmyadmin/libraries/config/messages.inc.php create mode 100644 phpmyadmin/libraries/config/setup.forms.php create mode 100644 phpmyadmin/libraries/config/user_preferences.forms.php create mode 100644 phpmyadmin/libraries/config/validate.lib.php create mode 100644 phpmyadmin/libraries/core.lib.php create mode 100644 phpmyadmin/libraries/data_dictionary_relations.lib.php create mode 100644 phpmyadmin/libraries/database_interface.lib.php create mode 100644 phpmyadmin/libraries/db_common.inc.php create mode 100644 phpmyadmin/libraries/db_info.inc.php create mode 100644 phpmyadmin/libraries/db_table_exists.lib.php create mode 100644 phpmyadmin/libraries/dbi/drizzle-wrappers.lib.php create mode 100644 phpmyadmin/libraries/dbi/drizzle.dbi.lib.php create mode 100644 phpmyadmin/libraries/dbi/dummy.lib.php create mode 100644 phpmyadmin/libraries/dbi/mysql.dbi.lib.php create mode 100644 phpmyadmin/libraries/dbi/mysqli.dbi.lib.php create mode 100644 phpmyadmin/libraries/display_change_password.lib.php create mode 100644 phpmyadmin/libraries/display_create_database.lib.php create mode 100644 phpmyadmin/libraries/display_create_table.lib.php create mode 100644 phpmyadmin/libraries/display_export.lib.php create mode 100644 phpmyadmin/libraries/display_git_revision.lib.php create mode 100644 phpmyadmin/libraries/display_import.lib.php create mode 100644 phpmyadmin/libraries/display_import_ajax.lib.php create mode 100644 phpmyadmin/libraries/display_select_lang.lib.php create mode 100644 phpmyadmin/libraries/engines/bdb.lib.php create mode 100644 phpmyadmin/libraries/engines/berkeleydb.lib.php create mode 100644 phpmyadmin/libraries/engines/binlog.lib.php create mode 100644 phpmyadmin/libraries/engines/innobase.lib.php create mode 100644 phpmyadmin/libraries/engines/innodb.lib.php create mode 100644 phpmyadmin/libraries/engines/memory.lib.php create mode 100644 phpmyadmin/libraries/engines/merge.lib.php create mode 100644 phpmyadmin/libraries/engines/mrg_myisam.lib.php create mode 100644 phpmyadmin/libraries/engines/myisam.lib.php create mode 100644 phpmyadmin/libraries/engines/ndbcluster.lib.php create mode 100644 phpmyadmin/libraries/engines/pbxt.lib.php create mode 100644 phpmyadmin/libraries/engines/performance_schema.lib.php create mode 100644 phpmyadmin/libraries/error.inc.php create mode 100644 phpmyadmin/libraries/file_listing.lib.php create mode 100644 phpmyadmin/libraries/gis/pma_gis_factory.php create mode 100644 phpmyadmin/libraries/gis/pma_gis_geometry.php create mode 100644 phpmyadmin/libraries/gis/pma_gis_geometrycollection.php create mode 100644 phpmyadmin/libraries/gis/pma_gis_linestring.php create mode 100644 phpmyadmin/libraries/gis/pma_gis_multilinestring.php create mode 100644 phpmyadmin/libraries/gis/pma_gis_multipoint.php create mode 100644 phpmyadmin/libraries/gis/pma_gis_multipolygon.php create mode 100644 phpmyadmin/libraries/gis/pma_gis_point.php create mode 100644 phpmyadmin/libraries/gis/pma_gis_polygon.php create mode 100644 phpmyadmin/libraries/gis/pma_gis_visualization.php create mode 100644 phpmyadmin/libraries/gis_visualization.lib.php create mode 100644 phpmyadmin/libraries/iconv_wrapper.lib.php create mode 100644 phpmyadmin/libraries/import.lib.php create mode 100644 phpmyadmin/libraries/index.lib.php create mode 100644 phpmyadmin/libraries/information_schema_relations.lib.php create mode 100644 phpmyadmin/libraries/insert_edit.lib.php create mode 100644 phpmyadmin/libraries/ip_allow_deny.lib.php create mode 100644 phpmyadmin/libraries/js_escape.lib.php create mode 100644 phpmyadmin/libraries/kanji-encoding.lib.php create mode 100644 phpmyadmin/libraries/language_stats.inc.php create mode 100644 phpmyadmin/libraries/logging.lib.php create mode 100644 phpmyadmin/libraries/mime.lib.php create mode 100644 phpmyadmin/libraries/mult_submits.inc.php create mode 100644 phpmyadmin/libraries/mysql_charsets.lib.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_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 create mode 100644 phpmyadmin/libraries/opendocument.lib.php create mode 100644 phpmyadmin/libraries/operations.lib.php create mode 100644 phpmyadmin/libraries/parse_analyze.lib.php create mode 100644 phpmyadmin/libraries/php-gettext/gettext.inc create mode 100644 phpmyadmin/libraries/php-gettext/gettext.php create mode 100644 phpmyadmin/libraries/php-gettext/streams.php create mode 100644 phpmyadmin/libraries/phpseclib/Crypt/AES.php create mode 100644 phpmyadmin/libraries/phpseclib/Crypt/Rijndael.php create mode 100644 phpmyadmin/libraries/plugin_interface.lib.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/swekey/authentication.inc.php create mode 100644 phpmyadmin/libraries/plugins/auth/swekey/musbe-ca.crt create mode 100644 phpmyadmin/libraries/plugins/auth/swekey/swekey.auth.lib.php create mode 100644 phpmyadmin/libraries/plugins/auth/swekey/swekey.php 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/pmd_common.php 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/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 create mode 100644 phpmyadmin/libraries/relation.lib.php create mode 100644 phpmyadmin/libraries/relation_cleanup.lib.php create mode 100644 phpmyadmin/libraries/replication.inc.php create mode 100644 phpmyadmin/libraries/replication_gui.lib.php create mode 100644 phpmyadmin/libraries/rte/rte_events.lib.php create mode 100644 phpmyadmin/libraries/rte/rte_export.lib.php create mode 100644 phpmyadmin/libraries/rte/rte_footer.lib.php create mode 100644 phpmyadmin/libraries/rte/rte_list.lib.php create mode 100644 phpmyadmin/libraries/rte/rte_main.inc.php create mode 100644 phpmyadmin/libraries/rte/rte_routines.lib.php create mode 100644 phpmyadmin/libraries/rte/rte_triggers.lib.php create mode 100644 phpmyadmin/libraries/rte/rte_words.lib.php create mode 100644 phpmyadmin/libraries/sanitizing.lib.php create mode 100644 phpmyadmin/libraries/schema/Dia_Relation_Schema.class.php create mode 100644 phpmyadmin/libraries/schema/Eps_Relation_Schema.class.php create mode 100644 phpmyadmin/libraries/schema/Export_Relation_Schema.class.php create mode 100644 phpmyadmin/libraries/schema/Pdf_Relation_Schema.class.php create mode 100644 phpmyadmin/libraries/schema/Svg_Relation_Schema.class.php create mode 100644 phpmyadmin/libraries/schema/User_Schema.class.php create mode 100644 phpmyadmin/libraries/select_lang.lib.php create mode 100644 phpmyadmin/libraries/select_server.lib.php create mode 100644 phpmyadmin/libraries/server_common.inc.php create mode 100644 phpmyadmin/libraries/server_privileges.lib.php create mode 100644 phpmyadmin/libraries/server_variables_doc.php create mode 100644 phpmyadmin/libraries/session.inc.php create mode 100644 phpmyadmin/libraries/special_schema_links.lib.php create mode 100644 phpmyadmin/libraries/sql_query_form.lib.php create mode 100644 phpmyadmin/libraries/sqlparser.data.php create mode 100644 phpmyadmin/libraries/sqlparser.lib.php create mode 100644 phpmyadmin/libraries/sqlvalidator.class.php create mode 100644 phpmyadmin/libraries/sqlvalidator.lib.php create mode 100644 phpmyadmin/libraries/string.lib.php create mode 100644 phpmyadmin/libraries/string_mb.lib.php create mode 100644 phpmyadmin/libraries/string_native.lib.php create mode 100644 phpmyadmin/libraries/string_type_ctype.lib.php create mode 100644 phpmyadmin/libraries/string_type_native.lib.php create mode 100644 phpmyadmin/libraries/structure.lib.php create mode 100644 phpmyadmin/libraries/sysinfo.lib.php create mode 100644 phpmyadmin/libraries/tbl_columns_definition_form.inc.php create mode 100644 phpmyadmin/libraries/tbl_common.inc.php create mode 100644 phpmyadmin/libraries/tbl_info.inc.php create mode 100644 phpmyadmin/libraries/tbl_views.lib.php create mode 100644 phpmyadmin/libraries/tcpdf/LICENSE.TXT create mode 100644 phpmyadmin/libraries/tcpdf/README.TXT create mode 100644 phpmyadmin/libraries/tcpdf/config/tcpdf_config.php create mode 100644 phpmyadmin/libraries/tcpdf/encodings_maps.php create mode 100644 phpmyadmin/libraries/tcpdf/fonts/dejavu-fonts-ttf-2.33/LICENSE create mode 100644 phpmyadmin/libraries/tcpdf/fonts/dejavusans.ctg.z create mode 100644 phpmyadmin/libraries/tcpdf/fonts/dejavusans.php create mode 100644 phpmyadmin/libraries/tcpdf/fonts/dejavusans.z create mode 100644 phpmyadmin/libraries/tcpdf/fonts/dejavusansb.ctg.z create mode 100644 phpmyadmin/libraries/tcpdf/fonts/dejavusansb.php create mode 100644 phpmyadmin/libraries/tcpdf/fonts/dejavusansb.z create mode 100644 phpmyadmin/libraries/tcpdf/fonts/helvetica.php create mode 100644 phpmyadmin/libraries/tcpdf/htmlcolors.php create mode 100644 phpmyadmin/libraries/tcpdf/tcpdf.php create mode 100644 phpmyadmin/libraries/tcpdf/unicode_data.php create mode 100644 phpmyadmin/libraries/transformations.lib.php create mode 100644 phpmyadmin/libraries/url_generating.lib.php create mode 100644 phpmyadmin/libraries/user_preferences.inc.php create mode 100644 phpmyadmin/libraries/user_preferences.lib.php create mode 100644 phpmyadmin/libraries/vendor_config.php create mode 100644 phpmyadmin/libraries/zip.lib.php create mode 100644 phpmyadmin/libraries/zip_extension.lib.php create mode 100644 phpmyadmin/license.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/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/hr/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpmyadmin/locale/hu/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/navigation.php create mode 100644 phpmyadmin/phpinfo.php create mode 100644 phpmyadmin/phpmyadmin.css.php create mode 100644 phpmyadmin/phpunit.xml.nocoverage create mode 100644 phpmyadmin/pmd_display_field.php create mode 100644 phpmyadmin/pmd_general.php create mode 100644 phpmyadmin/pmd_pdf.php create mode 100644 phpmyadmin/pmd_relation_new.php create mode 100644 phpmyadmin/pmd_relation_upd.php create mode 100644 phpmyadmin/pmd_save_pos.php create mode 100644 phpmyadmin/prefs_forms.php create mode 100644 phpmyadmin/prefs_manage.php create mode 100644 phpmyadmin/print.css create mode 100644 phpmyadmin/querywindow.php create mode 100644 phpmyadmin/robots.txt create mode 100644 phpmyadmin/schema_edit.php create mode 100644 phpmyadmin/schema_export.php create mode 100644 phpmyadmin/server_binlog.php create mode 100644 phpmyadmin/server_collations.php create mode 100644 phpmyadmin/server_databases.php create mode 100644 phpmyadmin/server_engines.php create mode 100644 phpmyadmin/server_export.php create mode 100644 phpmyadmin/server_import.php create mode 100644 phpmyadmin/server_plugins.php create mode 100644 phpmyadmin/server_privileges.php create mode 100644 phpmyadmin/server_replication.php create mode 100644 phpmyadmin/server_sql.php create mode 100644 phpmyadmin/server_status.php 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_variables.php create mode 100644 phpmyadmin/setup/ajax.js create mode 100644 phpmyadmin/setup/config.php create mode 100644 phpmyadmin/setup/frames/.htaccess create mode 100644 phpmyadmin/setup/frames/config.inc.php create mode 100644 phpmyadmin/setup/frames/form.inc.php create mode 100644 phpmyadmin/setup/frames/index.inc.php create mode 100644 phpmyadmin/setup/frames/menu.inc.php create mode 100644 phpmyadmin/setup/frames/servers.inc.php create mode 100644 phpmyadmin/setup/index.php create mode 100644 phpmyadmin/setup/lib/.htaccess create mode 100644 phpmyadmin/setup/lib/ConfigGenerator.class.php create mode 100644 phpmyadmin/setup/lib/common.inc.php create mode 100644 phpmyadmin/setup/lib/form_processing.lib.php create mode 100644 phpmyadmin/setup/lib/index.lib.php create mode 100644 phpmyadmin/setup/scripts.js create mode 100644 phpmyadmin/setup/styles.css create mode 100644 phpmyadmin/setup/validate.php create mode 100644 phpmyadmin/show_config_errors.php create mode 100644 phpmyadmin/sql.php create mode 100644 phpmyadmin/tbl_addfield.php create mode 100644 phpmyadmin/tbl_change.php create mode 100644 phpmyadmin/tbl_chart.php create mode 100644 phpmyadmin/tbl_create.php create mode 100644 phpmyadmin/tbl_export.php create mode 100644 phpmyadmin/tbl_get_field.php create mode 100644 phpmyadmin/tbl_gis_visualization.php create mode 100644 phpmyadmin/tbl_import.php create mode 100644 phpmyadmin/tbl_indexes.php create mode 100644 phpmyadmin/tbl_move_copy.php create mode 100644 phpmyadmin/tbl_operations.php create mode 100644 phpmyadmin/tbl_printview.php create mode 100644 phpmyadmin/tbl_relation.php create mode 100644 phpmyadmin/tbl_replace.php create mode 100644 phpmyadmin/tbl_row_action.php create mode 100644 phpmyadmin/tbl_select.php create mode 100644 phpmyadmin/tbl_sql.php create mode 100644 phpmyadmin/tbl_structure.php create mode 100644 phpmyadmin/tbl_tracking.php create mode 100644 phpmyadmin/tbl_triggers.php create mode 100644 phpmyadmin/tbl_zoom_select.php create mode 100644 phpmyadmin/themes.php create mode 100644 phpmyadmin/themes/dot.gif create mode 100644 phpmyadmin/themes/original/css/common.css.php create mode 100644 phpmyadmin/themes/original/css/navigation.css.php create mode 100644 phpmyadmin/themes/original/img/ajax_clock_small.gif create mode 100644 phpmyadmin/themes/original/img/arrow_ltr.png create mode 100644 phpmyadmin/themes/original/img/arrow_rtl.png create mode 100644 phpmyadmin/themes/original/img/b_bookmark.png create mode 100644 phpmyadmin/themes/original/img/b_browse.png create mode 100644 phpmyadmin/themes/original/img/b_calendar.png create mode 100644 phpmyadmin/themes/original/img/b_chart.png create mode 100644 phpmyadmin/themes/original/img/b_close.png create mode 100644 phpmyadmin/themes/original/img/b_column_add.png create mode 100644 phpmyadmin/themes/original/img/b_comment.png create mode 100644 phpmyadmin/themes/original/img/b_dbstatistics.png create mode 100644 phpmyadmin/themes/original/img/b_deltbl.png create mode 100644 phpmyadmin/themes/original/img/b_docs.png create mode 100644 phpmyadmin/themes/original/img/b_drop.png create mode 100644 phpmyadmin/themes/original/img/b_edit.png create mode 100644 phpmyadmin/themes/original/img/b_empty.png create mode 100644 phpmyadmin/themes/original/img/b_engine.png create mode 100644 phpmyadmin/themes/original/img/b_event_add.png create mode 100644 phpmyadmin/themes/original/img/b_events.png create mode 100644 phpmyadmin/themes/original/img/b_export.png create mode 100644 phpmyadmin/themes/original/img/b_ftext.png create mode 100644 phpmyadmin/themes/original/img/b_globe.gif create mode 100644 phpmyadmin/themes/original/img/b_group.png create mode 100644 phpmyadmin/themes/original/img/b_help.png create mode 100644 phpmyadmin/themes/original/img/b_home.png create mode 100644 phpmyadmin/themes/original/img/b_import.png create mode 100644 phpmyadmin/themes/original/img/b_index.png create mode 100644 phpmyadmin/themes/original/img/b_index_add.png create mode 100644 phpmyadmin/themes/original/img/b_info.png create mode 100644 phpmyadmin/themes/original/img/b_inline_edit.png create mode 100644 phpmyadmin/themes/original/img/b_insrow.png create mode 100644 phpmyadmin/themes/original/img/b_minus.png create mode 100644 phpmyadmin/themes/original/img/b_more.png create mode 100644 phpmyadmin/themes/original/img/b_move.png create mode 100644 phpmyadmin/themes/original/img/b_newdb.png create mode 100644 phpmyadmin/themes/original/img/b_newtbl.png create mode 100644 phpmyadmin/themes/original/img/b_nextpage.png create mode 100644 phpmyadmin/themes/original/img/b_plus.png create mode 100644 phpmyadmin/themes/original/img/b_primary.png create mode 100644 phpmyadmin/themes/original/img/b_print.png create mode 100644 phpmyadmin/themes/original/img/b_props.png create mode 100644 phpmyadmin/themes/original/img/b_relations.png create mode 100644 phpmyadmin/themes/original/img/b_routine_add.png create mode 100644 phpmyadmin/themes/original/img/b_routines.png create mode 100644 phpmyadmin/themes/original/img/b_save.png create mode 100644 phpmyadmin/themes/original/img/b_sbrowse.png create mode 100644 phpmyadmin/themes/original/img/b_search.png create mode 100644 phpmyadmin/themes/original/img/b_selboard.png create mode 100644 phpmyadmin/themes/original/img/b_select.png create mode 100644 phpmyadmin/themes/original/img/b_snewtbl.png create mode 100644 phpmyadmin/themes/original/img/b_spatial.png create mode 100644 phpmyadmin/themes/original/img/b_sql.png create mode 100644 phpmyadmin/themes/original/img/b_sqlhelp.png create mode 100644 phpmyadmin/themes/original/img/b_table_add.png create mode 100644 phpmyadmin/themes/original/img/b_tblanalyse.png create mode 100644 phpmyadmin/themes/original/img/b_tblexport.png create mode 100644 phpmyadmin/themes/original/img/b_tblimport.png create mode 100644 phpmyadmin/themes/original/img/b_tblops.png create mode 100644 phpmyadmin/themes/original/img/b_tbloptimize.png create mode 100644 phpmyadmin/themes/original/img/b_tipp.png create mode 100644 phpmyadmin/themes/original/img/b_trigger_add.png create mode 100644 phpmyadmin/themes/original/img/b_triggers.png create mode 100644 phpmyadmin/themes/original/img/b_unique.png create mode 100644 phpmyadmin/themes/original/img/b_usradd.png create mode 100644 phpmyadmin/themes/original/img/b_usrcheck.png create mode 100644 phpmyadmin/themes/original/img/b_usrdrop.png create mode 100644 phpmyadmin/themes/original/img/b_usredit.png create mode 100644 phpmyadmin/themes/original/img/b_usrlist.png create mode 100644 phpmyadmin/themes/original/img/b_view.png create mode 100644 phpmyadmin/themes/original/img/b_view_add.png create mode 100644 phpmyadmin/themes/original/img/b_views.png create mode 100644 phpmyadmin/themes/original/img/bd_browse.png create mode 100644 phpmyadmin/themes/original/img/bd_deltbl.png create mode 100644 phpmyadmin/themes/original/img/bd_drop.png create mode 100644 phpmyadmin/themes/original/img/bd_edit.png create mode 100644 phpmyadmin/themes/original/img/bd_empty.png create mode 100644 phpmyadmin/themes/original/img/bd_export.png create mode 100644 phpmyadmin/themes/original/img/bd_ftext.png create mode 100644 phpmyadmin/themes/original/img/bd_index.png create mode 100644 phpmyadmin/themes/original/img/bd_insrow.png create mode 100644 phpmyadmin/themes/original/img/bd_nextpage.png create mode 100644 phpmyadmin/themes/original/img/bd_primary.png create mode 100644 phpmyadmin/themes/original/img/bd_sbrowse.png create mode 100644 phpmyadmin/themes/original/img/bd_select.png create mode 100644 phpmyadmin/themes/original/img/bd_spatial.png create mode 100644 phpmyadmin/themes/original/img/bd_unique.png create mode 100644 phpmyadmin/themes/original/img/cleardot.gif create mode 100644 phpmyadmin/themes/original/img/col_drop.png create mode 100644 phpmyadmin/themes/original/img/col_pointer.png create mode 100644 phpmyadmin/themes/original/img/col_pointer_ver.png create mode 100644 phpmyadmin/themes/original/img/east-mini.png create mode 100644 phpmyadmin/themes/original/img/error.ico create mode 100644 phpmyadmin/themes/original/img/eye.png create mode 100644 phpmyadmin/themes/original/img/eye_grey.png create mode 100644 phpmyadmin/themes/original/img/logo_left.png create mode 100644 phpmyadmin/themes/original/img/logo_right.png create mode 100644 phpmyadmin/themes/original/img/more.png create mode 100644 phpmyadmin/themes/original/img/new_data.png create mode 100644 phpmyadmin/themes/original/img/new_data_hovered.png create mode 100644 phpmyadmin/themes/original/img/new_data_selected.png create mode 100644 phpmyadmin/themes/original/img/new_data_selected_hovered.png create mode 100644 phpmyadmin/themes/original/img/new_struct.png create mode 100644 phpmyadmin/themes/original/img/new_struct_hovered.png create mode 100644 phpmyadmin/themes/original/img/new_struct_selected.png create mode 100644 phpmyadmin/themes/original/img/new_struct_selected_hovered.png create mode 100644 phpmyadmin/themes/original/img/north-mini.png create mode 100644 phpmyadmin/themes/original/img/pause.png create mode 100644 phpmyadmin/themes/original/img/play.png create mode 100644 phpmyadmin/themes/original/img/s_asc.png create mode 100644 phpmyadmin/themes/original/img/s_asci.png create mode 100644 phpmyadmin/themes/original/img/s_cancel.png create mode 100644 phpmyadmin/themes/original/img/s_cog.png create mode 100644 phpmyadmin/themes/original/img/s_db.png create mode 100644 phpmyadmin/themes/original/img/s_desc.png create mode 100644 phpmyadmin/themes/original/img/s_error.png create mode 100644 phpmyadmin/themes/original/img/s_error2.png create mode 100644 phpmyadmin/themes/original/img/s_fulltext.png create mode 100644 phpmyadmin/themes/original/img/s_host.png create mode 100644 phpmyadmin/themes/original/img/s_lang.png create mode 100644 phpmyadmin/themes/original/img/s_loggoff.png create mode 100644 phpmyadmin/themes/original/img/s_notice.png create mode 100644 phpmyadmin/themes/original/img/s_partialtext.png create mode 100644 phpmyadmin/themes/original/img/s_passwd.png create mode 100644 phpmyadmin/themes/original/img/s_really.png create mode 100644 phpmyadmin/themes/original/img/s_reload.png create mode 100644 phpmyadmin/themes/original/img/s_replication.png create mode 100644 phpmyadmin/themes/original/img/s_rights.png create mode 100644 phpmyadmin/themes/original/img/s_sortable.png create mode 100644 phpmyadmin/themes/original/img/s_status.png create mode 100644 phpmyadmin/themes/original/img/s_success.png create mode 100644 phpmyadmin/themes/original/img/s_sync.png create mode 100644 phpmyadmin/themes/original/img/s_tbl.png create mode 100644 phpmyadmin/themes/original/img/s_theme.png create mode 100644 phpmyadmin/themes/original/img/s_top.png create mode 100644 phpmyadmin/themes/original/img/s_vars.png create mode 100644 phpmyadmin/themes/original/img/s_views.png create mode 100644 phpmyadmin/themes/original/img/south-mini.png create mode 100644 phpmyadmin/themes/original/img/spacer.png create mode 100644 phpmyadmin/themes/original/img/sprites.png create mode 100644 phpmyadmin/themes/original/img/toggle-ltr.png create mode 100644 phpmyadmin/themes/original/img/toggle-rtl.png create mode 100644 phpmyadmin/themes/original/img/vertical_line.png create mode 100644 phpmyadmin/themes/original/img/west-mini.png create mode 100644 phpmyadmin/themes/original/img/window-new.png create mode 100644 phpmyadmin/themes/original/img/zoom-minus-mini.png create mode 100644 phpmyadmin/themes/original/img/zoom-plus-mini.png create mode 100644 phpmyadmin/themes/original/img/zoom-world-mini.png create mode 100644 phpmyadmin/themes/original/info.inc.php create mode 100644 phpmyadmin/themes/original/jquery/images/ui-bg_flat_0_aaaaaa_40x100.png create mode 100644 phpmyadmin/themes/original/jquery/images/ui-bg_flat_75_ffffff_40x100.png create mode 100644 phpmyadmin/themes/original/jquery/images/ui-bg_glass_55_fbf9ee_1x400.png create mode 100644 phpmyadmin/themes/original/jquery/images/ui-bg_glass_65_ffffff_1x400.png create mode 100644 phpmyadmin/themes/original/jquery/images/ui-bg_glass_75_dadada_1x400.png create mode 100644 phpmyadmin/themes/original/jquery/images/ui-bg_glass_75_e6e6e6_1x400.png create mode 100644 phpmyadmin/themes/original/jquery/images/ui-bg_glass_95_fef1ec_1x400.png create mode 100644 phpmyadmin/themes/original/jquery/images/ui-bg_highlight-soft_75_cccccc_1x100.png create mode 100644 phpmyadmin/themes/original/jquery/images/ui-icons_222222_256x240.png create mode 100644 phpmyadmin/themes/original/jquery/images/ui-icons_2e83ff_256x240.png create mode 100644 phpmyadmin/themes/original/jquery/images/ui-icons_454545_256x240.png create mode 100644 phpmyadmin/themes/original/jquery/images/ui-icons_888888_256x240.png create mode 100644 phpmyadmin/themes/original/jquery/images/ui-icons_cd0a0a_256x240.png create mode 100644 phpmyadmin/themes/original/jquery/jquery-ui-1.9.2.custom.css create mode 100644 phpmyadmin/themes/original/layout.inc.php create mode 100644 phpmyadmin/themes/original/screen.png create mode 100644 phpmyadmin/themes/original/sprites.lib.php 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 create mode 100644 phpmyadmin/themes/pmahomme/img/ajax_clock_small.gif create mode 100644 phpmyadmin/themes/pmahomme/img/arrow_ltr.png create mode 100644 phpmyadmin/themes/pmahomme/img/arrow_rtl.png create mode 100644 phpmyadmin/themes/pmahomme/img/asc_order.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_bookmark.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_browse.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_calendar.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_chart.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_close.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_column_add.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_comment.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_dbstatistics.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_deltbl.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_docs.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_docsql.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_drop.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_edit.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_empty.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_engine.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_event_add.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_events.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_export.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_firstpage.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_ftext.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_globe.gif create mode 100644 phpmyadmin/themes/pmahomme/img/b_group.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_help.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_home.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_import.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_index.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_index_add.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_info.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_inline_edit.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_insrow.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_lastpage.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_minus.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_more.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_move.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_newdb.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_newtbl.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_nextpage.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_pdfdoc.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_plus.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_prevpage.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_primary.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_print.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_props.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_relations.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_routine_add.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_routines.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_save.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_sbrowse.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_sdb.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_search.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_selboard.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_select.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_snewtbl.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_spatial.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_sql.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_sqldoc.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_sqlhelp.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_table_add.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_tblanalyse.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_tblexport.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_tblimport.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_tblops.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_tbloptimize.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_tipp.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_trigger_add.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_triggers.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_unique.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_usradd.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_usrcheck.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_usrdrop.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_usredit.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_usrlist.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_view.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_view_add.png create mode 100644 phpmyadmin/themes/pmahomme/img/b_views.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_browse.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_deltbl.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_drop.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_edit.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_empty.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_export.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_firstpage.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_ftext.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_index.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_insrow.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_lastpage.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_nextpage.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_prevpage.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_primary.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_sbrowse.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_select.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_spatial.png create mode 100644 phpmyadmin/themes/pmahomme/img/bd_unique.png create mode 100644 phpmyadmin/themes/pmahomme/img/col_drop.png create mode 100644 phpmyadmin/themes/pmahomme/img/col_pointer.png create mode 100644 phpmyadmin/themes/pmahomme/img/col_pointer_ver.png create mode 100644 phpmyadmin/themes/pmahomme/img/database.png create mode 100644 phpmyadmin/themes/pmahomme/img/east-mini.png create mode 100644 phpmyadmin/themes/pmahomme/img/error.ico create mode 100644 phpmyadmin/themes/pmahomme/img/eye.png create mode 100644 phpmyadmin/themes/pmahomme/img/eye_grey.png create mode 100644 phpmyadmin/themes/pmahomme/img/item.png create mode 100644 phpmyadmin/themes/pmahomme/img/left_nav_bg.png create mode 100644 phpmyadmin/themes/pmahomme/img/logo_left.png create mode 100644 phpmyadmin/themes/pmahomme/img/logo_right.png create mode 100644 phpmyadmin/themes/pmahomme/img/more.png create mode 100644 phpmyadmin/themes/pmahomme/img/new_data.png create mode 100644 phpmyadmin/themes/pmahomme/img/new_data_hovered.png create mode 100644 phpmyadmin/themes/pmahomme/img/new_data_selected.png create mode 100644 phpmyadmin/themes/pmahomme/img/new_data_selected_hovered.png create mode 100644 phpmyadmin/themes/pmahomme/img/new_struct.png create mode 100644 phpmyadmin/themes/pmahomme/img/new_struct_hovered.png create mode 100644 phpmyadmin/themes/pmahomme/img/new_struct_selected.png create mode 100644 phpmyadmin/themes/pmahomme/img/new_struct_selected_hovered.png create mode 100644 phpmyadmin/themes/pmahomme/img/north-mini.png create mode 100644 phpmyadmin/themes/pmahomme/img/pause.png create mode 100644 phpmyadmin/themes/pmahomme/img/php_sym.png create mode 100644 phpmyadmin/themes/pmahomme/img/play.png create mode 100644 phpmyadmin/themes/pmahomme/img/pma_logo2.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/1.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/2.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/2leftarrow.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/2leftarrow_m.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/2rightarrow.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/2rightarrow_m.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/3.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/4.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/5.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/6.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/7.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/8.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/FieldKey_small.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/Field_small.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/Field_small_char.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/Field_small_date.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/Field_small_int.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/Header.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/Header_Linked.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/and_icon.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/ang_direct.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/bord.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/bottom.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/def.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/display_field.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/downarrow1.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/downarrow2.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/downarrow2_m.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/exec.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/exec_small.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/exitFullscreen.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/favicon.ico create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/grid.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/help.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/help_relation.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/left_panel_butt.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/left_panel_tab.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/minus.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/or_icon.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/pdf.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/plus.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/query_builder.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/relation.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/reload.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/resize.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/rightarrow1.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/rightarrow2.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/save.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/small_tab.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/table.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/toggle_lines.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/top_panel.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/uparrow2_m.png create mode 100644 phpmyadmin/themes/pmahomme/img/pmd/viewInFullscreen.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_asc.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_asci.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_attention.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_cancel.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_cancel2.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_cog.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_db.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_desc.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_error.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_error2.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_fulltext.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_host.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_info.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_lang.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_loggoff.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_notice.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_okay.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_partialtext.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_passwd.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_process.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_really.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_reload.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_replication.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_rights.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_sortable.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_status.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_success.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_sync.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_tbl.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_theme.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_top.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_vars.png create mode 100644 phpmyadmin/themes/pmahomme/img/s_views.png create mode 100644 phpmyadmin/themes/pmahomme/img/south-mini.png create mode 100644 phpmyadmin/themes/pmahomme/img/spacer.png create mode 100644 phpmyadmin/themes/pmahomme/img/sprites.png create mode 100644 phpmyadmin/themes/pmahomme/img/toggle-ltr.png create mode 100644 phpmyadmin/themes/pmahomme/img/toggle-rtl.png create mode 100644 phpmyadmin/themes/pmahomme/img/vertical_line.png create mode 100644 phpmyadmin/themes/pmahomme/img/west-mini.png create mode 100644 phpmyadmin/themes/pmahomme/img/window-new.png create mode 100644 phpmyadmin/themes/pmahomme/img/zoom-minus-mini.png create mode 100644 phpmyadmin/themes/pmahomme/img/zoom-plus-mini.png create mode 100644 phpmyadmin/themes/pmahomme/img/zoom-world-mini.png create mode 100644 phpmyadmin/themes/pmahomme/info.inc.php create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-bg_flat_0_aaaaaa_40x100.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-bg_flat_75_ffffff_40x100.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-bg_glass_55_fbf9ee_1x400.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-bg_glass_65_ffffff_1x400.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-bg_glass_75_dadada_1x400.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-bg_glass_75_e6e6e6_1x400.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-bg_glass_95_fef1ec_1x400.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-bg_highlight-soft_75_cccccc_1x100.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-icons_222222_256x240.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-icons_2e83ff_256x240.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-icons_454545_256x240.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-icons_888888_256x240.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/images/ui-icons_cd0a0a_256x240.png create mode 100644 phpmyadmin/themes/pmahomme/jquery/jquery-ui-1.9.2.custom.css create mode 100644 phpmyadmin/themes/pmahomme/layout.inc.php create mode 100644 phpmyadmin/themes/pmahomme/screen.png create mode 100644 phpmyadmin/themes/pmahomme/sprites.lib.php create mode 100644 phpmyadmin/themes/sprites.css.php create mode 100644 phpmyadmin/themes/svg_gradient.php create mode 100644 phpmyadmin/transformation_overview.php create mode 100644 phpmyadmin/transformation_wrapper.php create mode 100644 phpmyadmin/url.php create mode 100644 phpmyadmin/user_password.php create mode 100644 phpmyadmin/version_check.php create mode 100644 phpmyadmin/view_create.php create mode 100644 phpmyadmin/view_operations.php create mode 100644 phpmyadmin/webapp.php diff --git a/phpmyadmin/ChangeLog b/phpmyadmin/ChangeLog new file mode 100644 index 000000000..8b29aabbd --- /dev/null +++ b/phpmyadmin/ChangeLog @@ -0,0 +1,222 @@ +phpMyAdmin - ChangeLog +====================== + +4.0.4.0 (2013-06-17) +- bug #3959 Using DefaultTabDatabase in NavigationTree for Database Click +- bug #3961 Avoid Suhosin warning when in simulation mode +- bug #3897 Row Statistics and Space usage bugs +- bug #3966 Only display "table has no unique column" message when applicable +- bug #3960 NavigationBarIconic config not honored +- bug #3965 Default language wrong with zh-TW +- bug #3921 Call to undefined function PMA_isSuperuser() if default server is +not set +- bug #3971 Ctrl/shift + click opens links in same window +- bug #3964 Import using https does not work +- bug Missing removeCRLF option in ExportCsv and ExportExcel plugins +- bug #3631 Drop not working Visio schema export. +- bug #3645 Better handling of invalid ODS documents +- bug #3976 Number of pages +- bug #3922 User privileges, database name unescaped + +4.0.3.0 (2013-06-05) +- bug #3941 Recent tables list always empty +- bug #3933 Do not translate "Open Document" in export settings +- bug #3927 List of tables is missing after expanding in the navigation frame +- bug #3942 Warnings about reserved word for many non reserved words +- bug #3912 Exporting row selection, resulted by ORDER BY query +- bug #3957 Cookies must be enabled past this point +- bug #3956 "Browse foreign values" search filter / page selector not working +- bug #3579 NOW() function incorrectly selected (partial regression) +- [security] Javascript execution vulnerability in Create view, + reported by Maxim Rupp (see PMASA-2013-6) + +4.0.2.0 (2013-05-24) +- bug #3902 Cannot browse when table name contains keyword "call" ++ center loading indicator for navigation refresh, related to bug #3920 +- bug #3925 Table sorting in navigation panel is case-sensitive +- bug #3915 Import of CSV file (Replace table data with file) with duplicate values +- bug #3907 undefined variables, function parameter problems +- bug #3898 Structure not refreshed after column drop +- bug #3926 View is not updatable +- bug #3919 PropertiesIconic not honored +- bug #3930 Databases to choose for specific privileges show up escaped +- bug #3910 Export database with empty table as a php array, does not produce valid PHP +- bug #3936 Query profiler chart not loading from SQL Query page +- bug #3946 Missing CSV import option "Do not abort on INSERT error" +- bug #3943 Missing Operations>Table options>AUTO_INCREMENT +- bug Missing CREATE DATABASE statement when exporting at database level +- bug #3924 Show warning when CSV file does not contain data for all columns +- bug #3947 Missing Sql Query after modify structure +- bug #3948 Server export problems +- bug #3917 CountTables directive is deprecated + +4.0.1.0 (2013-05-14) +- bug #3879 Import broken for CSV using LOAD DATA +- bug #3889 When login fails and error display is active, login data is displayed +- bug #3890 [import] Web server upload directory import fails +- bug #3891 [import] Server upload folder import file name missing in success message ++ rfe #1421 [auth] Add retry button on connection failure with config auth +- bug #3894 [interface] Provide feedback if no columns selected for multi-submit +- bug #3799 [interface] Incorrect select field change on ctrl key navigation in Firefox +- bug #3885 [browse] display_binary_as_hex option causes unexpected behavior +- bug #3899 Git commit links to Github missing +- bug #3900 CSP WARN in Firefox console +- bug #3901 Setup script warning for config auth (stored login data) shows link BBcode +- bug #3895 [browse] Fixed getting BLOB data +- bug #3905 [export] Custom Exporting exports all databases +- bug #3909 [import] Import of CSV FIle to selected table doesn't work +- bug #3904 Browsing an empty table should not display its Structure +- bug #3908 Calendar widget improperly redirects to home +- bug #3918 Greyed out tabs when there are no rows fixed +- bug #3916 [interface] Missing scrollbar (original theme) ++ [vendor] add tcpdf path to vendor_config.php +- bug fix compat with tcpdf >= 6.0 (tested with 6.0.012) + +4.0.0.0 (2013-05-03) ++ Patch #3481047 for rfe #3480477 Insert as new row enhancement ++ Patch #3480999 Activate codemirror in the query window +- Patch #3495284 XML Import - fix message and redirect ++ rfe #3484063 Null checkbox behavior ++ Patch #3497179 Contest-5: Add user: Allow create DB w/same name + grant u_% ++ Patch #3498201 Contest-6: Export all privileges ++ Patch #3502814 for rfe #3187077 Change password buttons should match ++ rfe #3488640 Expand table-group in non-light navigation frame if only one ++ Patch #3509360 Contest-3: Option "Truncate table" before "insert" ++ Patch #3506552 Contest-2: Show index information in the data dictionary ++ Patch #3510656 Contest-1: Ignoring foreign keys while dropping tables +- Bug #3509686 Reverting sort on joined column does not work ++ New transformation: append string ++ rfe #3507804 Session upload progress (PHP 5.4) ++ rfe #3488185 draggable columns vs copy column name ++ Patch #3507001 Contest-4: Textarea for large character columns ++ Removed the PHP version of the ENUM editor ++ Patch #3507111 Display distinct results, linked to corresponding data rows +- bug #3507917 [export] JSON has unescaped values for allegedly numeric columns ++ rfe #3516187 show tables creation, last update, last check timestamps in db_structure +- bug #3059806 Supporting running from CIFS/Samba shares +- bug #3516341 [export] Open Document Text, Word and Texy! Text show table structure twice +- bug [export] Texy! Text: Columns containing Pipe Character don't export properly ++ [export] Show triggers in Open Document Text, Word and Texy! Text +- Patch #3415061 [auth] Login screen appears under the page ++ rfe #3517354 [interface] Allow disabling CodeMirror with $cfg['CodemirrorEnable'] = false ++ rfe #3475567 [interface] New directive $cfg['HideStructureActions'] +- bug #3468272 [import] Fixed import of ODS with more paragraphs in a cell +- bug #3510196 [core] Improved redirecting with ForceSSL option ++ rfe #3518852 [edit] edit blob but not other binary, new option $cfg['ProtectBinary'] = 'noblob' ++ Hide language select box if there are no locales installed ++ Removed some directives: verbose_check, SuggestDBName, LightTabs, +VerboseMultiSubmit, ReplaceHelpImg +- Patch #3500882 Fixing checkbox behaviour while editing identical rows ++ rfe #3441722 [interface] Display description of datatypes ++ rfe #3517835 [structure] Move columns easily ++ Ajaxified "Create View" functionality ++ [import] New plugin: import mediawiki ++ New navigation system ++ Discontinued the use of a frame-based layout ++ rfe #3528994 [interface] Allow wrapping possibly long values in replication-status table ++ [interface] Autoselect username input on cookie login page +- bug #3563799 [interface] Grid editing destroying huge amount of data ++ [import] Remove support for the unactive docSQL import format +- bug #3577443 [edit] "Browse foreign values" does not show on ajax edit ++ rfe #3522109 [browse] Grid editing: action to trigger it (or disable) +- bug #3526598 [interface] SQL query not shown when creating table ++ Dropped configuration directive: AllowThirdPartyFraming ++ Dropped configuration directive: LeftFrameLight ++ Dropped configuration directive: DisplayDatabasesList ++ Dropped configuration directives: ShowTooltipAliasDB and ShowTooltipAliasTB ++ Dropped configuration directive: NaviDatabaseNameColor ++ Added configuration directive: MaxNavigationItems ++ Renamed configuration directive: LeftFrameDBTree => NavigationTreeEnableGrouping ++ Renamed configuration directive: LeftFrameDBSeparator => NavigationTreeDbSeparator ++ Renamed configuration directive: LeftFrameTableSeparator => NavigationTreeTableSeparator ++ Renamed configuration directive: LeftFrameTableLevel => NavigationTreeTableLevel ++ Renamed configuration directive: LeftPointerEnable => NavigationTreePointerEnable ++ Renamed configuration directive: LeftDefaultTabTable => NavigationTreeDefaultTabTable ++ Renamed configuration directive: LeftDisplayTableFilterMinimum => NavigationTreeDisplayTableFilterMinimum ++ Renamed configuration directive: LeftDisplayLogo => NavigationDisplayLogo ++ Renamed configuration directive: LeftLogoLink => NavigationLogoLink ++ Renamed configuration directive: LeftLogoLinkWindow => NavigationLogoLinkWindow ++ Renamed configuration directive: LeftDisplayServers => NavigationDisplayServers ++ Renamed configuration directive: LeftRecentTable => NumRecentTables ++ Renamed configuration directive: LeftDisplayDatabaseFilterMinimum => NavigationTreeDisplayDbFilterMinimum ++ Removed the "Mark row on click" feature; must now click the checkbox to mark ++ Removed the "Synchronize" feature ++ Improved layout of server variables page ++ rfe #1052091 [config] Double-underscores in PMA table names ++ Improved the "More" dropdown on the table structure page ++ [interface] Added "scroll to top" link in menubar ++ [designer] Fullscreen mode for the designer ++ Upgraded jquery to v1.8.3 and jquery-ui to v1.9.2 ++ Patch #3597529 [status] Add raw value as title on server status page ++ Support MySQL 5.6 partitioning ++ Removed the AjaxEnable directive ++ rfe #3542567 Accept IPv6 ranges and IPv6 CIDR notations in $cfg['Servers'][$i]['AllowDeny']['rules'] +- Bug #3576788 Grid editing shows the value before silent truncation +- Upgraded jqPlot to 1.0.4 r1121 +- Upgraded to jquery-ui-timepicker-addon 1.1.1 ++ rfe #3599046 [interface] Added comments for indexes +- Replaced qtip with jQuery UI tooltip +- Upgraded CodeMirror to 2.37 +- bug #2951 [export] Correctly export decimal fields. +- bug #3762 [core] Make Advisor work on Windows withou COM extension. +- bug #3519 [export] Prevent infinite recursion in PDF export. +- bug #3827 Table specific privileges not displayed for db name containing +underscore +- rfe #1386 Add IF NOT EXISTS clause when copying database +- No longer package .travis.yml configuration file when creating a release. +- bug #3830 Can't export custom query because it lowercases table names +- bug #3829 Enabling query profiling crashes javascript based navigation ++ rfe #879 Reserved word warning ++ Remove the database ordering sub-feature of the only_db directive +- bug #3840 When exporting to gzip format, the data is compressed 2 times ++ rfe #1319 Permit to create index when creating foreign key +- bug #3703 Incorrect updating of the list of users +- bug #3853 Blowfish implementation might be broken (replace with phpseclib) +- bug #3865 Using like operator on each backslash needs 4 backslash protection +- bug #3860 Displayed git revision info is not set +- bug #3871 Check referential integrity broken across databases +- bug #3874 [export] No preselected option when exporting table +- bug #3873 Can't copy table to target database if table exists there +- bug #3683 Incorrect listing of records from to count +- bug #3876 [import] PHP 5.2 - unexpected T_PAAMAYIM_NEKUDOTAYIM +- [security] Local file inclusion vulnerability, reported by Janek Vind + (see PMASA-2013-4) +- [security] Global variables overwrite in export.php, reported by Janek Vind + (see PMASA-2013-5) +- bug #3892 [export] SQL Export files are empty + +3.5.8.1 (2013-04-24) +- [security] Remote code execution (preg_replace), reported by Janek Vind + (see PMASA-2013-2) +- [security] Locally Saved SQL Dump File Multiple File Extension Remote Code + Execution, reported by Janek Vind (see PMASA-2013-3) + +3.5.8.0 (2013-04-08) +- bug #3828 MariaDB reported as MySQL +- bug #3854 Incorrect header for Safari 6.0 +- bug #3705 Attempt to open trigger for edit gives NULL +- Use HTML5 DOCTYPE +- [security] Self-XSS on GIS visualisation page, reported by Janek Vind +- bug #3800 Incorrect keyhandler behaviour #2 + +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 + + --- Older ChangeLogs can be found on our project website --- + http://www.phpmyadmin.net/old-stuff/ChangeLogs/ + +# vim: et ts=4 sw=4 sts=4 +# vim: ft=changelog fenc=utf-8 +# vim: fde=getline(v\:lnum-1)=~'^\\s*$'&&getline(v\:lnum)=~'\\S'?'>1'\:1&&v\:lnum>4&&getline(v\:lnum)!~'^#' +# vim: fdn=1 fdm=expr diff --git a/phpmyadmin/LICENSE b/phpmyadmin/LICENSE new file mode 100644 index 000000000..3912109b5 --- /dev/null +++ b/phpmyadmin/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/phpmyadmin/README b/phpmyadmin/README new file mode 100644 index 000000000..94543f288 --- /dev/null +++ b/phpmyadmin/README @@ -0,0 +1,84 @@ +phpMyAdmin - Readme +=================== + +Version 4.0.4 + +A set of PHP-scripts to manage MySQL over the web. + +http://www.phpmyadmin.net/ + +Copyright +--------- + +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 documentation for more details] + +License +------- + +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 . + +Requirements +------------ + +* PHP 5.2 or later +* MySQL 5.0 or later +* a web-browser (doh!) + +Summary +------- + +phpMyAdmin is intended to handle the administration of MySQL over the web. +For a summary of features, please see the documentation in the doc folder. + +Download +-------- + +You can get the newest version at http://www.phpmyadmin.net/. + +More Information +---------------- + +Please see the documentation in the doc folder. + +Support +------- + +See reference about support forums under http://www.phpmyadmin.net/ + + +Enjoy! +------ + +The phpMyAdmin Devel team + + +PS: + +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 (especially the FAQ part). + diff --git a/phpmyadmin/RELEASE-DATE-4.0.4 b/phpmyadmin/RELEASE-DATE-4.0.4 new file mode 100644 index 000000000..6eb670b97 --- /dev/null +++ b/phpmyadmin/RELEASE-DATE-4.0.4 @@ -0,0 +1 @@ +Mon Jun 17 16:28:34 UTC 2013 diff --git a/phpmyadmin/browse_foreigners.php b/phpmyadmin/browse_foreigners.php new file mode 100644 index 000000000..9a9fdf904 --- /dev/null +++ b/phpmyadmin/browse_foreigners.php @@ -0,0 +1,340 @@ +getFooter()->setMinimal(); +$header = $response->getHeader(); +$header->disableMenu(); +$header->setBodyId('body_browse_foreigners'); + +/** + * Displays the frame + */ + +$cfgRelation = PMA_getRelationsParam(); +$foreigners = ($cfgRelation['relwork'] ? PMA_getForeigners($db, $table) : false); + +$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, $field, $override_total, + isset($foreign_filter) ? $foreign_filter : '', $foreign_limit +); + +if (isset($rownumber)) { + $rownumber_param = '&rownumber=' . urlencode($rownumber); +} else { + $rownumber_param = ''; +} + +$gotopage = ''; +$showall = ''; + +if (is_array($foreignData['disp_row'])) { + + if ($cfg['ShowAll'] + && ($foreignData['the_total'] > $GLOBALS['cfg']['MaxRows']) + ) { + $showall = ''; + } + + $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_Util::pageselector( + 'pos', + $session_max_rows, + $pageNow, + $nbTotalPage, + 200, + 5, + 5, + 20, + 10, + __('Page number:') + ); + } +} + + + +if (isset($rownumber)) { + $element_name = " var element_name = field + '[multi_edit][" + . htmlspecialchars($rownumber) . "][' + fieldmd5 + ']';\n" + . " var null_name = field_null + '[multi_edit][" + . htmlspecialchars($rownumber) . "][' + fieldmd5 + ']';\n"; +} else { + $element_name = "var element_name = field + '[]'"; +} +$error = PMA_jsFormat( + __( + 'The target browser window could not be updated. ' + . 'Maybe you have closed the parent window, or ' + . 'your browser\'s security settings are ' + . 'configured to block cross-window updates.' + ) +); + + +if (! isset($fieldkey) || ! is_numeric($fieldkey)) { + $fieldkey = 0; +} + +$code = <<getScripts()->addCode($code); + +// HTML output +$output = '
' + . '
' + . PMA_generate_common_hidden_inputs($db, $table) + . '' + . ''; + +if (isset($rownumber)) { + $output .= ''; +} +$output .= '' + . '' + . '' + . '' + . '' + . '' . $gotopage . '' + . '' . $showall . '' + . '
' + . '
'; + +$output .= ''; + +if (is_array($foreignData['disp_row'])) { + $header = ' + + + + + + '; + + $output .= '' . $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) { + $hcount++; + + if ($cfg['RepeatCells'] > 0 && $hcount > $cfg['RepeatCells']) { + $output .= $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; + } + + $output .= ''; + $odd_row = ! $odd_row; + + $output .= ''; + + $output .= ''; + + $output .= ''; + + $output .= ''; + + $output .= ''; + $output .= ''; + } // end while +} + +$output .= '' + . '
' . __('Keyname') . '' . __('Description') . '' . __('Description') . '' . __('Keyname') . '
' + . ($key_ordered_current_equals_data ? '' : '') + . '' + . htmlspecialchars($key_ordered_current_key) + . '' . ($key_ordered_current_equals_data ? '' : '') + . '' + . ($key_ordered_current_equals_data ? '' : '') + . '' + . $key_ordered_current_val . '' + . ($key_ordered_current_equals_data ? '' : '') + . '' + . '' + . ($val_ordered_current_equals_data ? '' : '') + . '' + . $val_ordered_current_val . '' + . ($val_ordered_current_equals_data ? '' : '') + . '' + . ($val_ordered_current_equals_data ? '' : '') + . '' + . htmlspecialchars($val_ordered_current_key) + . '' . ($val_ordered_current_equals_data ? '' : '') + . '
'; + +$response->addHtml($output); +?> diff --git a/phpmyadmin/changelog.php b/phpmyadmin/changelog.php new file mode 100644 index 000000000..c216c7fe3 --- /dev/null +++ b/phpmyadmin/changelog.php @@ -0,0 +1,152 @@ +disable(); + +$filename = CHANGELOG_FILE; + +/** + * Read changelog. + */ +// Check if the file is available, some distributions remove these. +if (is_readable($filename)) { + + // Test if the if is in a compressed format + if (substr($filename, -3) == '.gz') { + ob_start(); + readgzfile($filename); + $changelog = ob_get_contents(); + ob_end_clean(); + } else { + $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 + ); + exit; +} + +/** + * Whole changelog in variable. + */ +$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/'; + +$replaces = array( + '@(http://[./a-zA-Z0-9.-_-]*[/a-zA-Z0-9_])@' + => '\\1', + + // sourceforge users + '/([0-9]{4}-[0-9]{2}-[0-9]{2}) (.+[^ ]) +<(.*)@users.sourceforge.net>/i' + => '\\1 \\2', + '/thanks to ([^\(\r\n]+) \(([-\w]+)\)/i' + => 'thanks to \\1', + '/thanks to ([^\(\r\n]+) -\s+([-\w]+)/i' + => 'thanks to \\1', + + // mail address + '/([0-9]{4}-[0-9]{2}-[0-9]{2}) (.+[^ ]) +<(.*@.*)>/i' + => '\\1 \\2', + + // linking patches + '/patch\s*#?([0-9]{6,})/i' + => 'patch #\\1', + + // linking RFE + '/(?:rfe|feature)\s*#?([0-9]{6,})/i' + => 'RFE #\\1', + + // linking files + '/(\s+)([\\/a-z_0-9\.]+\.(?:php3?|html|pl|js|sh))/i' + => '\\1\\2', + + // FAQ entries + '/FAQ ([0-9]+)\.([0-9a-z]+)/i' + => 'FAQ \\1.\\2', + + // linking bugs + '/bug\s*#?([0-9]{6,})/i' + => 'bug #\\1', + + // all other 6+ digit numbers are treated as bugs + '/(? '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]+)/' + => '\\1', + + // PMASAentries + '/(PMASA-[0-9]+-[0-9]+)/' + => '\\1', + + // Highlight releases (with links) + '/([0-9]+)\.([0-9]+)\.([0-9]+)\.0 (\([0-9-]+\))/' + => '' + . '' + . '\\1.\\2.\\3.0 \\4', + '/([0-9]+)\.([0-9]+)\.([0-9]+)\.([1-9][0-9]*) (\([0-9-]+\))/' + => '' + . '' + . '\\1.\\2.\\3.\\4 \\5', + + // Highlight releases (not linkable) + '/( ### )(.*)/' + => '\\1\\2', + +); + +header('Content-type: text/html; charset=utf-8'); +?> + + + + + + phpMyAdmin - ChangeLog + + + +

phpMyAdmin - ChangeLog

+'; +echo preg_replace(array_keys($replaces), $replaces, $changelog); +echo ''; +?> + + + diff --git a/phpmyadmin/chk_rel.php b/phpmyadmin/chk_rel.php new file mode 100644 index 000000000..915e8b24b --- /dev/null +++ b/phpmyadmin/chk_rel.php @@ -0,0 +1,15 @@ +addHTML( + PMA_getRelationsParamDiagnostic(PMA_getRelationsParam()) +); + +?> diff --git a/phpmyadmin/composer.json b/phpmyadmin/composer.json new file mode 100644 index 000000000..ba03706ef --- /dev/null +++ b/phpmyadmin/composer.json @@ -0,0 +1,24 @@ +{ + "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.2.0" + } +} diff --git a/phpmyadmin/config.sample.inc.php b/phpmyadmin/config.sample.inc.php new file mode 100644 index 000000000..10db2b508 --- /dev/null +++ b/phpmyadmin/config.sample.inc.php @@ -0,0 +1,141 @@ +. + * + * @package PhpMyAdmin + */ + +/* + * This is needed for cookie based authentication to encrypt password in + * cookie + */ +$cfg['blowfish_secret'] = 'a8b7c6d'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */ + +/* + * Servers configuration + */ +$i = 0; + +/* + * First server + */ +$i++; +/* Authentication type */ +$cfg['Servers'][$i]['auth_type'] = 'cookie'; +/* Server parameters */ +$cfg['Servers'][$i]['host'] = 'localhost'; +$cfg['Servers'][$i]['connect_type'] = 'tcp'; +$cfg['Servers'][$i]['compress'] = false; +/* Select mysql if your server does not have mysqli */ +$cfg['Servers'][$i]['extension'] = 'mysqli'; +$cfg['Servers'][$i]['AllowNoPassword'] = false; + +/* + * phpMyAdmin configuration storage settings. + */ + +/* User used to manipulate with storage */ +// $cfg['Servers'][$i]['controlhost'] = ''; +// $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'; +/* Contrib / Swekey authentication */ +// $cfg['Servers'][$i]['auth_swekey_config'] = '/etc/swekey-pma.conf'; + +/* + * End of servers configuration + */ + +/* + * Directories for saving/loading files from server + */ +$cfg['UploadDir'] = ''; +$cfg['SaveDir'] = ''; + +/** + * Defines whether a user should be displayed a "show all (records)" + * button in browse mode or not. + * default = false + */ +//$cfg['ShowAll'] = true; + +/** + * Number of rows displayed when browsing a result set. If the result + * set contains more rows, "Previous" and "Next". + * default = 30 + */ +//$cfg['MaxRows'] = 50; + +/** + * disallow editing of binary fields + * valid values are: + * 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'; + +/** + * Default language to use, if not browser-defined or user-defined + * (you find all languages in the locale folder) + * uncomment the desired line: + * default = 'en' + */ +//$cfg['DefaultLang'] = 'en'; +//$cfg['DefaultLang'] = 'de'; + +/** + * default display direction (horizontal|vertical|horizontalflipped) + */ +//$cfg['DefaultDisplay'] = 'vertical'; + + +/** + * How many columns should be used for table display of a database? + * (a value larger than 1 results in some information being hidden) + * default = 1 + */ +//$cfg['PropertiesNumColumns'] = 2; + +/** + * Set to true if you want DB-based query history.If false, this utilizes + * JS-routines to display query history (lost by window close) + * + * This requires configuration storage enabled, see above. + * default = false + */ +//$cfg['QueryHistoryDB'] = true; + +/** + * When using DB-based query history, how many entries should be kept? + * + * default = 25 + */ +//$cfg['QueryHistoryMax'] = 100; + +/* + * 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 new file mode 100644 index 000000000..48ce08468 --- /dev/null +++ b/phpmyadmin/db_create.php @@ -0,0 +1,148 @@ +isSuccess(false); + $response->addJSON('message', $message); + } else { + include_once 'index.php'; + } +} else { + $message = PMA_Message::success(__('Database %1$s has been created.')); + $message->addParam($new_db); + $GLOBALS['db'] = $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 + + /** + * Build the array to be passed to {@link PMA_generate_common_url} + * to generate the links + * + * @global array $GLOBALS['db_url_params'] + * @name $db_url_params + */ + $db_url_params['db'] = $new_db; + + $is_superuser = PMA_isSuperuser(); + $column_order = PMA_getColumnOrder(); + $url_query = PMA_generate_common_url($new_db); + + /** + * String that will contain the output HTML + * @name $new_db_string + */ + $new_db_string = ''; + + if (empty($db_collation_for_ajax)) { + $db_collation_for_ajax = PMA_getServerCollation(); + } + + // $dbstats comes from the create table dialog + if (! empty($dbstats)) { + $current = array( + 'SCHEMA_NAME' => $new_db, + 'DEFAULT_COLLATION_NAME' => $db_collation_for_ajax, + 'SCHEMA_TABLES' => '0', + 'SCHEMA_TABLE_ROWS' => '0', + 'SCHEMA_DATA_LENGTH' => '0', + 'SCHEMA_MAX_DATA_LENGTH' => '0', + 'SCHEMA_INDEX_LENGTH' => '0', + 'SCHEMA_LENGTH' => '0', + 'SCHEMA_DATA_FREE' => '0' + ); + } else { + $current = array( + 'SCHEMA_NAME' => $new_db + ); + } + + 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 .= ''; + + $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']; + } +} +?> diff --git a/phpmyadmin/db_datadict.php b/phpmyadmin/db_datadict.php new file mode 100644 index 000000000..8744aa4a0 --- /dev/null +++ b/phpmyadmin/db_datadict.php @@ -0,0 +1,291 @@ +getHeader(); +$header->enablePrintView(); + +/** + * Gets the relations settings + */ +$cfgRelation = PMA_getRelationsParam(); + +require_once 'libraries/transformations.lib.php'; +require_once 'libraries/Index.class.php'; + +/** + * Check parameters + */ +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); +} else { + $err_url = 'db_sql.php?' . PMA_generate_common_url($db); +} + +if ($cfgRelation['commwork']) { + $comment = PMA_getDbComment($db); + + /** + * Displays DB comment + */ + if ($comment) { + echo '

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

'; + } // end if +} + +/** + * Selects the database and gets tables names + */ +PMA_DBI_select_db($db); +$tables = PMA_DBI_get_tables($db); + +$count = 0; +foreach ($tables as $table) { + $comments = PMA_getComments($db, $table); + + echo '
' . "\n"; + + echo '

' . htmlspecialchars($table) . '

' . "\n"; + + /** + * Gets table informations + */ + $show_comment = PMA_Table::sGetStatusInfo($db, $table, 'TABLE_COMMENT'); + + /** + * Gets table keys and retains them + */ + + PMA_DBI_select_db($db); + $indexes = PMA_DBI_get_table_indexes($db, $table); + $primary = ''; + $indexes = array(); + $lastIndex = ''; + $indexes_info = array(); + $indexes_data = array(); + $pk_array = array(); // will be use to emphasis prim. keys in the table + // view + foreach ($indexes as $row) { + // Backups the list of primary keys + if ($row['Key_name'] == 'PRIMARY') { + $primary .= $row['Column_name'] . ', '; + $pk_array[$row['Column_name']] = 1; + } + // Retains keys informations + if ($row['Key_name'] != $lastIndex) { + $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']; + 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_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']; + } + + } // end while + + /** + * Gets columns properties + */ + $columns = PMA_DBI_get_columns($db, $table); + $fields_cnt = count($columns); + + if (PMA_MYSQL_INT_VERSION < 50025) { + // We need this to correctly learn if a TIMESTAMP is NOT NULL, since + // SHOW FULL COLUMNS or INFORMATION_SCHEMA incorrectly says NULL + // and SHOW CREATE TABLE says NOT NULL + // http://bugs.mysql.com/20910. + + $show_create_table_query = 'SHOW CREATE TABLE ' + . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table); + $show_create_table = PMA_DBI_fetch_value( + $show_create_table_query, 0, 1 + ); + $analyzed_sql = PMA_SQP_analyze(PMA_SQP_parse($show_create_table)); + } + + // Check if we can use Relations + if (!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 (count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + + /** + * Displays the comments of the table if MySQL >= 3.23 + */ + if (!empty($show_comment)) { + echo __('Table comments') . ': ' . htmlspecialchars($show_comment) . '

'; + } + + /** + * Displays the table structure + */ + ?> + + + + +*/ ?> + + +*/ ?> + ' . __('Links to') . '' . "\n"; + } + echo ' ' . "\n"; + if ($cfgRelation['mimework']) { + echo ' ' . "\n"; + } + ?> + + NULL'; + } + } else { + $row['Default'] = htmlspecialchars($row['Default']); + } + $field_name = $row['Field']; + + 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. + /** + * @todo merge this logic with the one in tbl_structure.php + * or move it in a function similar to PMA_DBI_get_columns_full() + * but based on SHOW CREATE TABLE because information_schema + * cannot be trusted in this case (MySQL bug) + */ + $row['Null'] = 'NO'; + } + ?> + + + lang="en" dir="ltr"> +>*/ ?> + + +>*/ ?> + '; + if (isset($res_rel[$field_name])) { + echo htmlspecialchars($res_rel[$field_name]['foreign_table'] . ' -> ' . $res_rel[$field_name]['foreign_field']); + } + echo '' . "\n"; + } + echo ' ' . "\n"; + if ($cfgRelation['mimework']) { + $mime_map = PMA_getMIME($db, $table, true); + + echo ' ' . "\n"; + } + ?> + + +
' . __('Comments') . 'MIME
+ ' . htmlspecialchars($field_name) . ''; + } else { + echo htmlspecialchars($field_name); + } + ?> + '; + if (isset($comments[$field_name])) { + echo htmlspecialchars($comments[$field_name]); + } + echo ''; + if (isset($mime_map[$field_name])) { + echo htmlspecialchars(str_replace('_', '/', $mime_map[$field_name]['mimetype'])); + } + echo '
+ 0) { + echo PMA_Index::getView($table, $db, true); + } +?> +
+ diff --git a/phpmyadmin/db_events.php b/phpmyadmin/db_events.php new file mode 100644 index 000000000..917778bc3 --- /dev/null +++ b/phpmyadmin/db_events.php @@ -0,0 +1,26 @@ + diff --git a/phpmyadmin/db_export.php b/phpmyadmin/db_export.php new file mode 100644 index 000000000..2b2fde41d --- /dev/null +++ b/phpmyadmin/db_export.php @@ -0,0 +1,90 @@ +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'; +$url_query .= '&goto=db_export.php'; +require_once 'libraries/db_info.inc.php'; + +/** + * Displays the form + */ +$export_page_title = __('View dump (schema) of database'); + +// exit if no tables in db found +if ($num_tables < 1) { + PMA_Message::error(__('No tables found in database.'))->display(); + exit; +} // end if + +$multi_values = '
'; +$multi_values .= ''; +$multi_values .= __('Select All'); +$multi_values .= ''; +$multi_values .= ' / '; +$multi_values .= ''; +$multi_values .= __('Unselect All'); +$multi_values .= '
'; + +$multi_values .= '
'; + +$export_type = 'database'; +require_once 'libraries/display_export.lib.php'; + +?> diff --git a/phpmyadmin/db_import.php b/phpmyadmin/db_import.php new file mode 100644 index 000000000..f8ea8097a --- /dev/null +++ b/phpmyadmin/db_import.php @@ -0,0 +1,28 @@ +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'; + +$import_type = 'database'; +require 'libraries/display_import.lib.php'; + +?> + diff --git a/phpmyadmin/db_operations.php b/phpmyadmin/db_operations.php new file mode 100644 index 000000000..338d38574 --- /dev/null +++ b/phpmyadmin/db_operations.php @@ -0,0 +1,293 @@ +getHeader(); +$scripts = $header->getScripts(); +$scripts->addFile('db_operations.js'); + +/** + * Rename/move or copy database + */ +if (strlen($db) + && (! empty($_REQUEST['db_rename']) || ! empty($_REQUEST['db_copy'])) +) { + if (! empty($_REQUEST['db_rename'])) { + $move = true; + } else { + $move = false; + } + + 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($_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 + // language; I have to send each statement 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 + PMA_runProcedureAndFunctionDefinitions($db); + + // go back to current db, just in case + PMA_DBI_select_db($db); + + $tables_full = PMA_DBI_get_tables_full($db); + + include_once "libraries/plugin_interface.lib.php"; + // remove all foreign key constraints, otherwise we can get errors + $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 + ); + + $views = PMA_getViewsAndCreateSqlViewStandIn( + $tables_full, $export_sql_plugin, $db + ); + + list($sql_query, $_error) = PMA_getSqlQueryForCopyTable( + $tables_full, $sql_query, $move, $db + ); + + // handle the views + if (! $_error) { + $_error = PMA_handleTheViews($views, $move, $db); + } + unset($views); + + // now that all tables exist, create all the accumulated constraints + if (! $_error && count($GLOBALS['sql_constraints_query_full_db']) > 0) { + PMA_createAllAccumulatedConstraints(); + } + + 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 + + PMA_runEventDefinitionsForDb($db); + } + + // go back to current db, just in case + PMA_DBI_select_db($db); + + // Duplicate the bookmarks for this db (done once for each db) + PMA_duplicateBookmarks($_error, $db); + + if (! $_error && $move) { + /** + * cleanup pmadb stuff for this db + */ + include_once 'libraries/relation_cleanup.lib.php'; + PMA_relationsCleanupDatabase($db); + + // if someday the RENAME DATABASE reappears, do not DROP + $local_query = 'DROP DATABASE ' . PMA_Util::backquote($db) . ';'; + $sql_query .= "\n" . $local_query; + PMA_DBI_query($local_query); + + $message = PMA_Message::success(__('Database %1$s has been renamed to %2$s')); + $message->addParam($db); + $message->addParam($_REQUEST['newname']); + } elseif (! $_error) { + $message = PMA_Message::success(__('Database %1$s has been copied to %2$s')); + $message->addParam($db); + $message->addParam($_REQUEST['newname']); + } + $reload = true; + + /* Change database to be used */ + if (! $_error && $move) { + $db = $_REQUEST['newname']; + } elseif (! $_error) { + if (isset($_REQUEST['switch_to_new']) + && $_REQUEST['switch_to_new'] == 'true' + ) { + $GLOBALS['PMA_Config']->setCookie('pma_switch_to_new', 'true'); + $db = $_REQUEST['newname']; + } else { + $GLOBALS['PMA_Config']->setCookie('pma_switch_to_new', ''); + } + } + + if ($_error && ! isset($message)) { + $message = PMA_Message::error(); + } + } + + /** + * Database has been successfully renamed/moved. If in an Ajax request, + * generate the output with {@link PMA_Response} and exit + */ + 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) + ); + exit; + } +} + +/** + * Settings for relations stuff + */ + +$cfgRelation = PMA_getRelationsParam(); + +/** + * Check if comments were updated + * (must be done before displaying the menu tabs) + */ +if (isset($_REQUEST['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)) { + echo PMA_Util::getMessage($message, $sql_query); + unset($message); + } +} + +$_REQUEST['db_collation'] = PMA_getDbCollation($db); +$is_information_schema = PMA_is_system_schema($db); + +if (!$is_information_schema) { + if ($cfgRelation['commwork']) { + /** + * database comment + */ + $response->addHTML(PMA_getHtmlForDatabaseComment($db)); + } + + $response->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') { + $response->addHTML(PMA_getHtmlForRenameDatabase($db)); + } + + // Drop link if allowed + // Don't even try to drop information_schema. + // You won't be able to. Believe me. You won't. + // Don't allow to easily drop mysql database, RFE #1327514. + if (($is_superuser || $GLOBALS['cfg']['AllowUserDropDatabase']) + && ! $db_is_information_schema + && (PMA_DRIZZLE || $db != 'mysql') + ) { + $response->addHTML(PMA_getHtmlForDropDatabaseLink($db)); + } + /** + * Copy database + */ + $response->addHTML(PMA_getHtmlForCopyDatabase($db)); + + /** + * Change database charset + */ + $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 + ); + $message->addParam('', false); + /* Show error if user has configured something, notice elsewhere */ + if (!empty($cfg['Servers'][$server]['pmadb'])) { + $message->isError(true); + } + $response->addHTML('
'); + $response->addHTML($message->getDisplay()); + $response->addHTML('
'); + } // end if +} // end if (!$is_information_schema) + + +// not sure about displaying the PDF dialog in case db is information_schema +if ($cfgRelation['pdfwork'] && $num_tables > 0) { + // We only show this if we find something in the new pdf_pages table + $test_query = ' + SELECT * + 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_DBI_QUERY_STORE); + + /* + * Export Relational Schema View + */ + $response->addHTML(PMA_getHtmlForExportRelationalSchemaView($url_query)); +} // end if + +?> diff --git a/phpmyadmin/db_printview.php b/phpmyadmin/db_printview.php new file mode 100644 index 000000000..e0c2f1423 --- /dev/null +++ b/phpmyadmin/db_printview.php @@ -0,0 +1,252 @@ +getHeader(); +$header->enablePrintView(); + +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); + +/** + * 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_Util::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_Util::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_Util::backquote($db) . ' LIKE \'' . 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_Util::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); +$num_tables = count($tables); + +echo '
'; + +// 1. No table +if ($num_tables == 0) { + echo __('No tables found in database.'); +} else { +// 2. Shows table information + ?> + + + + + + + ' . __('Size') . ''; + } + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + ' . PMA_Util::formatNumber($sts_data['TABLE_ROWS'], 0) . '' . "\n"; + } else { + echo PMA_Util::formatNumber($sts_data['TABLE_ROWS'], 0) . "\n"; + } + ?> + + + + + + + + '; + } else { + $needs_break = ''; + } + + if (! empty($sts_data['Create_time']) + || ! empty($sts_data['Update_time']) + || ! empty($sts_data['Check_time']) + ) { + echo $needs_break; + ?> + + + + + + + + + + + + + + + + + +
+ +
+ + + + + -- + + +
+ \n"; +?> diff --git a/phpmyadmin/db_qbe.php b/phpmyadmin/db_qbe.php new file mode 100644 index 000000000..940758ccc --- /dev/null +++ b/phpmyadmin/db_qbe.php @@ -0,0 +1,68 @@ + (maybe) execute it + */ +$message_to_display = false; +if (isset($_REQUEST['submit_sql']) && ! empty($sql_query)) { + if (! preg_match('@^SELECT@i', $sql_query)) { + $message_to_display = true; + } else { + $goto = 'db_sql.php'; + include 'sql.php'; + exit; + } +} + +$sub_part = '_qbe'; +require 'libraries/db_common.inc.php'; +$url_query .= '&goto=db_qbe.php'; +$url_params['goto'] = 'db_qbe.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); + +// create new qbe search instance +$db_qbe = new PMA_DBQbe($GLOBALS['db']); + +/** + * Displays the Query by example form + */ +if ($cfgRelation['designerwork']) { + $url = 'pmd_general.php' . PMA_generate_common_url( + array_merge( + $url_params, + array('query' => 1) + ) + ); + $response->addHTML( + PMA_Message::notice( + sprintf( + __('Switch to %svisual builder%s'), + '', + '' + ) + ) + ); +} +$response->addHTML($db_qbe->getSelectionForm($cfgRelation)); +?> diff --git a/phpmyadmin/db_routines.php b/phpmyadmin/db_routines.php new file mode 100644 index 000000000..690da852f --- /dev/null +++ b/phpmyadmin/db_routines.php @@ -0,0 +1,27 @@ + diff --git a/phpmyadmin/db_search.php b/phpmyadmin/db_search.php new file mode 100644 index 000000000..acfec8e55 --- /dev/null +++ b/phpmyadmin/db_search.php @@ -0,0 +1,57 @@ +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'); + +require 'libraries/db_common.inc.php'; + +// If config variable $GLOBALS['cfg']['Usedbsearch'] is on false : exit. +if (! $GLOBALS['cfg']['UseDbSearch']) { + PMA_Util::mysqlDie( + __('Access denied'), '', false, $err_url + ); +} // end if +$url_query .= '&goto=db_search.php'; +$url_params['goto'] = 'db_search.php'; + +// 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'; +} +$response->addHTML('
'); + +// Main search form has been submitted, get results +if (isset($_REQUEST['submit_search'])) { + $response->addHTML($db_search->getSearchResults()); +} + +// 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; +} + +// Display the search form +$response->addHTML($db_search->getSelectionForm($url_params)); +?> diff --git a/phpmyadmin/db_sql.php b/phpmyadmin/db_sql.php new file mode 100644 index 000000000..baced4407 --- /dev/null +++ b/phpmyadmin/db_sql.php @@ -0,0 +1,65 @@ +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'; + +// After a syntax error, we return to this script +// with the typed query in the textarea. +$goto = 'db_sql.php'; +$back = 'db_sql.php'; + +/** + * Sets globals from $_GET + */ + +$get_params = array( + 'db_query_force' +); + +foreach ($get_params as $one_get_param) { + if (isset($_GET[$one_get_param])) { + $GLOBALS[$one_get_param] = $_GET[$one_get_param]; + } +} + +/** + * 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']) : ';' +); + +?> diff --git a/phpmyadmin/db_structure.php b/phpmyadmin/db_structure.php new file mode 100644 index 000000000..ed5a48151 --- /dev/null +++ b/phpmyadmin/db_structure.php @@ -0,0 +1,335 @@ +getHeader(); +$scripts = $header->getScripts(); +$scripts->addFile('db_structure.js'); +$scripts->addFile('tbl_change.js'); +$scripts->addFile('jquery/jquery-ui-timepicker-addon.js'); + +$post_params = array( + 'error', + 'is_info', + 'message', + 'mult_btn', + 'selected_tbl', + 'submit_mult' +); +foreach ($post_params as $one_post_param) { + if (isset($_POST[$one_post_param])) { + $GLOBALS[$one_post_param] = $_POST[$one_post_param]; + } +} +/** + * 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($_POST['is_info'])) { + // 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_generate_common_url($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'; + } + if (empty($_POST['message'])) { + $_POST['message'] = PMA_Message::success(); + } + } + include 'libraries/db_common.inc.php'; + $url_query .= '&goto=db_structure.php'; + + // Gets the database structure + $sub_part = '_structure'; + include 'libraries/db_info.inc.php'; + + if (!PMA_DRIZZLE) { + include_once 'libraries/replication.inc.php'; + } else { + $server_slave_status = false; + } +} + +require_once 'libraries/bookmark.lib.php'; + +require_once 'libraries/mysql_charsets.lib.php'; +$db_collation = PMA_getDbCollation($db); + +$titles = PMA_Util::buildActionTitles(); + +// 1. No tables + +if ($num_tables == 0) { + $response->addHTML( + '

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

' . "\n" + ); + if (empty($db_is_information_schema)) { + 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) + exit; +} + +// else +// 2. Shows table informations + +/** + * Displays the tables list + */ +$response->addHTML('
'); +$_url_params = array( + 'pos' => $pos, + 'db' => $db); + +// Add the sort options if they exists +if (isset($_REQUEST['sort'])) { + $_url_params['sort'] = $_REQUEST['sort']; +} + +if (isset($_REQUEST['sort_order'])) { + $_url_params['sort_order'] = $_REQUEST['sort_order']; +} + +$response->addHTML( + PMA_Util::getListNavigator( + $total_num_tables, $pos, $_url_params, 'db_structure.php', + 'frame_content', $GLOBALS['cfg']['MaxTableList'] + ) +); + +// tables form +$response->addHTML( + '
' +); + +$response->addHTML(PMA_generate_common_hidden_inputs($db)); + +$response->addHTML( + PMA_TableHeader($db_is_information_schema, $server_slave_status) +); + +$i = $sum_entries = 0; +$overhead_check = ''; +$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 = ''; + +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($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 + + 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 + ); + + if (! PMA_Table::isMerge($db, $current_table['TABLE_NAME'])) { + $sum_entries += $current_table['TABLE_ROWS']; + } + + if (isset($current_table['Collation'])) { + $collation = '' + . $current_table['Collation'] . ''; + } else { + $collation = '---'; + } + + if ($is_show_stats) { + if ($formatted_overhead != '') { + $overhead = '' + . '' . $formatted_overhead . '' + . '' . $overhead_unit . '' + . '' . "\n"; + $overhead_check .= + "markAllRows('row_tbl_" . ($i + 1) . "');"; + } else { + $overhead = '-'; + } + } // end if + + 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[] = ''; + } + + /* + * Always activate links for Browse, Search and Empty, even if + * the icons are greyed, because + * 1. for views, we don't know the number of rows at this point + * 2. for tables, another source could have populated them since the + * page was generated + * + * I could have used the PHP ternary conditional operator but I find + * the code easier to read without this operator. + */ + 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 + ); + + if (! $db_is_information_schema) { + list($drop_query, $drop_message) + = PMA_getTableDropQueryAndMessage($table_is_view, $current_table); + } + + if ($num_columns > 0 + && $num_tables > $num_columns + && ($row_count % $num_columns) == 0 + ) { + $row_count = 1; + $odd_row = true; + + $response->addHTML( + '' + ); + + $response->addHTML(PMA_TableHeader(false, $server_slave_status)); + } + + list($do, $ignored) = PMA_getServerSlaveStatus( + $server_slave_status, $truename + ); + + list($html_output, $odd_row) = PMA_getHtmlForStructureTableRow( + $i, $odd_row, $table_is_view, $current_table, + $browse_table_label, $tracking_icon, $server_slave_status, + $browse_table, $tbl_url_query, $search_table, $db_is_information_schema, + $titles, $empty_table, $drop_query, $drop_message, $collation, + $formatted_size, $unit, $overhead, + (isset ($create_time) ? $create_time : ''), + (isset ($update_time) ? $update_time : ''), + (isset ($check_time) ? $check_time : ''), + $is_show_stats, $ignored, $do, $colspan_for_structure + ); + $response->addHTML($html_output); + +} // end foreach + +// Show Summary +$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 + +// display again the table list navigator +$response->addHTML( + PMA_Util::getListNavigator( + $total_num_tables, $pos, $_url_params, 'db_structure.php', + 'frame_content', $GLOBALS['cfg']['MaxTableList'] + ) +); + +$response->addHTML('

'); + +/** + * Work on the database + */ +/* DATABASE WORK */ +/* Printable view of a table */ +$response->addHTML( + PMA_getHtmlForTablePrintViewLink($url_query) + . PMA_getHtmlForDataDictionaryLink($url_query) +); + +if (empty($db_is_information_schema)) { + ob_start(); + include 'libraries/display_create_table.lib.php'; + $content = ob_get_contents(); + ob_end_clean(); + $response->addHTML($content); +} // end if (Create Table dialog) + +?> diff --git a/phpmyadmin/db_tracking.php b/phpmyadmin/db_tracking.php new file mode 100644 index 000000000..e95a7e0a5 --- /dev/null +++ b/phpmyadmin/db_tracking.php @@ -0,0 +1,243 @@ +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. + */ +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'; + +// Work to do? +// (here, do not use $_REQUEST['db] as it can be crafted) +if (isset($_REQUEST['delete_tracking']) && isset($_REQUEST['table'])) { + PMA_Tracker::deleteTracking($GLOBALS['db'], $_REQUEST['table']); + + /** + * If in an Ajax request, generate the success message and use + * {@link PMA_Response()} to send the output + */ + if ($GLOBALS['is_ajax_request'] == true) { + $response = PMA_Response::getInstance(); + $response->addJSON('message', PMA_Message::success()); + exit; + } +} + +// Get tracked data about the database +$data = PMA_Tracker::getTrackedData($_REQUEST['db'], '', '1'); + +// No tables present and no log exist +if ($num_tables == 0 && count($data['ddlog']) == 0) { + echo '

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

' . "\n"; + + if (empty($db_is_information_schema)) { + include 'libraries/display_create_table.lib.php'; + } + exit; +} + +// --------------------------------------------------------------------------- + +// Prepare statement to get HEAD version +$all_tables_query = ' SELECT table_name, MAX(version) as version FROM ' . + 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_queryAsControlUser($all_tables_query); + +// If a HEAD version exists +if (PMA_DBI_num_rows($all_tables_result) > 0) { +?> +
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ | + |
+
+ $value) { + // If $value is a table group. + if (array_key_exists(('is' . $sep . 'group'), $value) + && $value['is' . $sep . 'group'] + ) { + foreach ($value as $temp_table) { + // If $temp_table is a table with the value for 'Name' is set, + // rather than a propery of the table group. + if (is_array($temp_table) + && array_key_exists('Name', $temp_table) + ) { + $tracking_version = PMA_Tracker::getVersion( + $GLOBALS['db'], + $temp_table['Name'] + ); + if ($tracking_version == -1) { + $my_tables[] = $temp_table['Name']; + } + } + } + } else { // If $value is a table. + if (PMA_Tracker::getVersion($GLOBALS['db'], $value['Name']) == -1) { + $my_tables[] = $value['Name']; + } + } +} + +// If untracked tables exist +if (isset($my_tables)) { +?> +

+ + + + + + + + + + $tablename) { + if (PMA_Tracker::getVersion($GLOBALS['db'], $tablename) == -1) { + $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"; + } + echo PMA_Util::getMessage(__('Database Log'), $log); +} + +?> diff --git a/phpmyadmin/db_triggers.php b/phpmyadmin/db_triggers.php new file mode 100644 index 000000000..d1a2a8c6b --- /dev/null +++ b/phpmyadmin/db_triggers.php @@ -0,0 +1,25 @@ + diff --git a/phpmyadmin/doc/Makefile b/phpmyadmin/doc/Makefile new file mode 100644 index 000000000..1ee62c86a --- /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 000000000..fdf33149c --- /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/conf.py b/phpmyadmin/doc/conf.py new file mode 100644 index 000000000..372d84539 --- /dev/null +++ b/phpmyadmin/doc/conf.py @@ -0,0 +1,286 @@ +# -*- coding: utf-8 -*- +# +# phpMyAdmin documentation build configuration file, created by +# sphinx-quickstart on Wed Sep 26 14:04:48 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "_ext"))) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['configext'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'phpMyAdmin' +copyright = u'2012 - 2013, The phpMyAdmin devel team' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '4.0.4' +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build', 'html', 'doctrees'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " 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 diff --git a/phpmyadmin/doc/config.rst b/phpmyadmin/doc/config.rst new file mode 100644 index 000000000..2b9ced27b --- /dev/null +++ b/phpmyadmin/doc/config.rst @@ -0,0 +1,2776 @@ +.. 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`. + +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 some 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 not longer be displayed + +.. config:option:: $cfg['TranslationWarningThreshold'] + + :type: integer + :default: 80 + + Show warning about incomplete translations on certain threshold. + +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 + +.. 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 connection to 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. + +.. _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``) + + +.. _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]['DisableIS'] + + :type: boolean + :default: true + + Disable using ``INFORMATION_SCHEMA`` to retrieve information (use + ``SHOW`` commands instead), because of speed issues when many + databases are present. Currently used in some parts of the code, more + to come. + +.. config:option:: $cfg['Servers'][$i]['ShowDatabasesCommand'] + + :type: string + :default: ``'SHOW DATABASES'`` + + On a server with a huge number of databases, the default ``SHOW DATABASES`` + command used to fetch the name of available databases will probably be too + slow, so it can be replaced by faster commands. You can use ``#user#`` + string will be replaced by current user. + + When using ``false``, it will disable fetching databases from the server, + only databases in :config:option:`$cfg['Servers'][$i]['only_db']` will be + displayed. + + Examples: + + * ``'SHOW DATABASES'`` + * ``"SHOW DATABASES LIKE '#user#\_%'"`` + * ``'SELECT DISTINCT TABLE_SCHEMA FROM information_schema.SCHEMA_PRIVILEGES'`` + * ``'SELECT SCHEMA_NAME FROM information_schema.SCHEMATA'`` + * ``false`` + +.. 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']`. + + Takes effect only if :config:option:`$cfg['Servers'][$i]['DisableIS']` is + ``true``. + +.. 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['MaxDbList'] + + :type: integer + :default: 100 + + The maximum number of database names to be displayed in the main panel's + database list. + +.. config:option:: $cfg['MaxNavigationItems'] + + :type: integer + :default: 25 + + The number of items that can be displayed on each page of the + navigation tree. + +.. 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. + +.. 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: ``'0'`` + + Set the number of bytes a script is allowed to allocate. If set to + zero, 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. + +Navigation panel setup +---------------------- + +.. 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['ShowTooltip'] + + :type: boolean + :default: true + + Defines whether to display item comments as tooltips in navigation + panel or not. + +.. 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['NavigationBarIconic'] + + :type: string + :default: true + + Defines whether navigation bar buttons contain text or symbols only. A + value of true displays icons, false displays text and 'both' displays + both icons and text. + +.. 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 5 × :config:option:`$cfg['MaxRows']` rows) to avoid + performance issues while getting too many rows. + +.. config:option:: $cfg['MaxRows'] + + :type: integer + :default: 30 + + 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. + +.. 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['PropertiesIconic'] + + :type: string + :default: ``'both'`` + + If set to ``true``, will display icons instead of text for db and table + properties links (like :guilabel:`Browse`, :guilabel:`Select`, + :guilabel:`Insert`, ...) and for the menu tabs. Can be set to ``'both'`` + if you want icons AND text. When set to ``false``, 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`` + +Documentation +------------- + +.. config:option:: $cfg['MySQLManualBase'] + + :type: string + :default: ``'http://dev.mysql.com/doc/refman'`` + + If set to an :term:`URL` which points to + the MySQL documentation (type depends on + :config:option:`$cfg['MySQLManualType']`), appropriate help links are + generated. + + See `MySQL Documentation page `_ for more + information about MySQL manuals and their types. + +.. config:option:: $cfg['MySQLManualType'] + + :type: string + :default: ``'viewable'`` + + Type of MySQL documentation: + + * viewable - "viewable online", current one used on MySQL website + * searchable - "Searchable, with user comments" + * chapters - "HTML, one page per chapter" + * big - "HTML, all on one page" + * none - do not show documentation links + +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 + * 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 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. + +.. 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 navi frame. 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 parser settings +------------------- + +.. config:option:: $cfg['SQP']['fmtType'] + + :type: string + :default: ``'html'`` + + The main use of the new :term:`SQL` Parser + is to pretty-print :term:`SQL` queries. By + default we use HTML to format the query, but you can disable this by + setting this variable to ``'none'``. + + Available options: + + * ``'html'`` + * ``'none'`` + +.. _cfg_SQP: +.. config:option:: $cfg['SQP']['fmtInd'] + + :type: float + :default: ``'1'`` + +.. config:option:: $cfg['SQP']['fmtIndUnit'] + + :type: string + :default: ``'em'`` + + For the pretty-printing of :term:`SQL` queries, + under some cases the part of a query inside a bracket is indented. By + changing :config:option:`$cfg['SQP']['fmtInd']` you can change the amount + of this indent. + + Related in purpose is :config:option:`$cfg['SQP']['fmtIndUnit']` which + specifies the units of the indent amount that you specified. This is used + via stylesheets. + + You can use any HTML unit, for example: + + * ``'em'`` + * ``'ex'`` + * ``'pt'`` + * ``'px'`` + +.. config:option:: $cfg['SQP']['fmtColor'] + + :type: array of string tuples + :default: + + This array is used to define the colours for each type of element of + the pretty-printed :term:`SQL` queries. + The tuple format is *class* => [*HTML colour code* | *empty string*] + + + If you specify an empty string for the color of a class, it is ignored + in creating the stylesheet. You should not alter the class names, only + the colour strings. + + **Class name key:** + + comment + Applies to all comment sub-classes + comment\_mysql + Comments as ``"#...\n"`` + comment\_ansi + Comments as ``"-- ...\n"`` + comment\_c + Comments as ``"/*...*/"`` + digit + Applies to all digit sub-classes + digit\_hex + Hexadecimal numbers + digit\_integer + Integer numbers + digit\_float + Floating point numbers + punct + Applies to all punctuation sub-classes + punct\_bracket\_open\_round + Opening brackets ``"("`` + punct\_bracket\_close\_round + Closing brackets ``")"`` + punct\_listsep + List item Separator ``","`` + punct\_qualifier + Table/Column Qualifier ``"."`` + punct\_queryend + End of query marker ``";"`` + alpha + Applies to all alphabetic classes + alpha\_columnType + Identifiers matching a column type + alpha\_columnAttrib + Identifiers matching a database/table/column attribute + alpha\_functionName + Identifiers matching a MySQL function name + alpha\_reservedWord + Identifiers matching any other reserved word + alpha\_variable + Identifiers matching a :term:`SQL` variable ``"@foo"`` + alpha\_identifier + All other identifiers + quote + Applies to all quotation mark classes + quote\_double + Double quotes ``"`` + quote\_single + Single quotes ``'`` + quote\_backtick + Backtick quotes ````` + +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['Error_Handler']['display'] + + :type: boolean + :default: false + + Whether to display errors from PHP or not. + +.. config:option:: $cfg['Error_Handler']['gather'] + + :type: boolean + :default: false + + Whether to gather errors from PHP or not. + diff --git a/phpmyadmin/doc/copyright.rst b/phpmyadmin/doc/copyright.rst new file mode 100644 index 000000000..cfcb86394 --- /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 000000000..21f5e1892 --- /dev/null +++ b/phpmyadmin/doc/credits.rst @@ -0,0 +1,597 @@ +.. _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 + +* 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 + +* 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 + +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 000000000..557452769 --- /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..98b1ab1a6a97b25ed0733f3b2e401d62a5572dbd GIT binary patch literal 935625 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 WTV!z+L_9qY0^8w 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

{6n_;%DO2VSJoflo1d~J`afs8udI@o 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

    IYcD8MFrNJvO^i^f( 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 z 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

    {Tb=O>X~|w8sN-2-TNtq%4yhBpPp*SCxc!R1ohX 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

    0q<7)8ioF>+Xf9F`)7Wobbc90$|Xf`fk2 zAwOhGEI1A^<43~ir5u=;1nyXHe4K`YexkzX1;=3^eF~({fb@BqzTh})om0O^vlkp+ zvh`Pi)`x6swcz+V4HM@Zm>fYqzD0h%gXvKTRI@vl##5)Fl7FAZ6XQ68{E%kXiO`(O zjUTzy39XfuCbiu7NwJ;;>nX7Q4Ax)3db%9zuW9yj<2UyDUGw@e&E;5b{GqJ=gw+{X zorTq3usW9(SpUDNqdE)y!%nVr?Ff2NI)pDy7vU=DB78}@2vs0gsbVoAxgM9glj;!CWLE2xHg3UfpDF4SHNX$qJt0MpC?)0}=!C!ZE9+EN$2Qi-}D+6tnrA=(C_Z6QivB-&0Q)Rq(N zCB_bH(oszG_d8LKWN!-<@r9Nfomr@hPTN({b^~oFXuE^92WWey2Nt?lx>o4kEZj#I z?yH3RLAXDJuY&LZ2oHpCXQW|}q@nzBW3Xgn2zw2+ypp}WRs4>M595}@b*d4HY9y#e zfoe3U#(-+9gKAtlDn6b?C+MPAE76G%odnUz5S;?isSq6o(P`=Sa$`E{&JbPxCh7Am zH_ERtW|E}IGE1?{2Fo0<%mvFlu*?U`c(5!;=d^b`-wMOIs92cJ69FBk^5TGYrUsbF~r&YyD>Rg!z(#WP%hM)F8 z8vWNsBvp_8F&!96e;`eufZ8R>P6+bU6t^v}uK)Mb{*Qe`Ci?6No=caUfX>kKvZw|ChvaQw9;>L8$n44g7GxBi@ z@^dRpw@9Fx-PUxTGZj|-wsf8!+nD6`bh}c-=3HBB=T>)Ut+YI;wZ#qvdnaJ;0_@#@ zy$7)OmV>>Ix~j#+{cQGtX13inQ>%-e%IrayJp{9dVfF~j9!(D%0=w7>C!NRGD%r9! zg&$YKPeAxd2tNhkry=}Ix*VhkmxP~9*G@XmvGDV{@C!=#MF_tH;g=!28^W(Z_%R6Y zNp}UTE?!ON%Du)GuWM-{(_rVCH@M}SI?P@L^A=#<2FyEvc^5G6IbhzWS31}1W6}M( z=m$#l07O$DnhMc0h^9mI4Txq)gxcyMQ)0|wlWZ~3-_M~Q$=-b`;tQ=Va#<)(r}Zn^ ze9#tvwh**Mpe;@hEObe_R_Ia|F4Kh%D&Y?yd;Fe$NR9`8ouR-+7`2P<7Kj8l-{LjGu82rzs zbE=y=R}{`w#9!&0`E!i;ceR=(1pZ1{Uz}TgqpW;C zY=;E-w1<0nm=WrpFW)-Le?BQ+BDErHb-$&(`Y#JLF3NBP9wg;+J{M;oH&rquH2eraQ;wVtW}3P*)tr8hFVt$m;kJ};y&N0u=~SKF zkZeW2kT29CpnxybYMp^E)M^9Nw(xJ4ArpjBO1|wgT{Y6q`mdAcPXSt`#*n_t1CC|W{U@Ylq*!l+8wd>K&E>loL=-gmp{tYn|{2U zKgxB)8rgkVfIiCAm!0|ni=L!8E7B7~&;N`KTj??A4#1m6P34N(=?$i3I5r~FIX!A4GK14IGiZ9OjmRu|yMm3#>

    q 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 literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/copyright.doctree b/phpmyadmin/doc/doctrees/copyright.doctree new file mode 100644 index 0000000000000000000000000000000000000000..26a63963bd3b222e04269de141a3f0e035430946 GIT binary patch literal 6876 zcwX&UXLKCZ6}D{EwI$0k#u(f2!?ZP6yOM3dMHu8RWXVR-U^!$n%+9>sH)z@`BWaUN zVv>-UgoN~jbW$LlgmgkGkluSGJt2_Zdvfoa-BqFZ2j_534)O8X-Fb80z2Cj}yZ03x zTWC9>9V^$9xgd0?%;2L>1C`+o8?NFD6TT>Gv;~$=RVAX5HzvF(JHBSYf(1;eXnQ_C zH8qth2XQVG<-F(GG>}y0dGqn{HjuHys3P1lQ@rJPY%G&;Q7Tt~xiBytT9Ujq;cZ4o zWC=-4pGs+!!A7RQ7te*I{=)preqikoARZ`0;3s}0es$h9}Uz- zyBWR=rgkNKd6uDkM$i(488&tJNrMfnlPxrwtNK>V*CA*m;=r}xA;V7|-vut_!${>L z-|8;A@XaE>VmZDWe_XWU;{3Uu ztEjL%v*?BPM1~&*)R!iF1X179FiRcD?%qIpw{6?ny{V_Chm3_q*OFw!QWBHlQ9=5Y z9y2Wn+01ax4*i{(xoSW|FR1C=Ool9BlReaPrAJAh4^KGV4N4*Y&f$-p83O+fdG4eO zMuu*`Ej1SUC>i>JD|0qWg+>5CKrRVcAj5$4iLh9-)FzaRB^5H4R%!{l56uNsrIY$S zI&B3G>duj|SkMUoLU9s|39A^(oI_L5A=hS>NA9@RW!9b7gP49sQ5#08uA<<6OH2Zi z1Fk*c2IZPQ8Anu<;niG))FXq`MynGO@O=WfqqJy2U$g=;L;1kw*7A(jhl>D-5j8@MI$}#j;eq_86 zh!=!VtK&x7wC`<~kp&&`sL>h;3Wz2te>8IWa%A;mkmLm<`D2mVCQ`e(M(r!u!T;0l zkwrTT+Eg*&wq9X@f|uTJn}UVfDhn%O8SX%fq6sfyi@F7fH^y8^A`!xCpTN(Opp?k4 zq^4kT-$5#2Ol-i70AzLLBCaA3{JaL^xTQ)424bBJ#V7&l`;vqu{jh)7Ap2>6)j$r% zMcB5GgXz|VOoG?2CJF@!#$oKCWI5;qNlt8rh4U7%%9UUe64vmn0a=3qF zY+$!>uz!RcHbxE~8r_?NI-#|&WgZ}G^GhJd;~6?I&4EeHfhpv`G;*MV9C#dZ;PJ?T zl{F4L0XXo8ic|v3d1At!gv`OH$r+45ivfN(?LG@4bnL#XL48Y};m?NDUzhOb zAhMl+?4jj^KNr*RysXiv&pppS@!|CaMl+y^h09-fV&NBIK3|NPeF-M|dQ9|7F}*KC zG9Sa#z8o@pLOrj5bi6X*ud1z?*FhQJQc{l#e>GGEp7U-<_-imU>p6!Kz z(D5{k!|Sqj=U&e=_8W~=sG}P+bc2R&(9m7ez;Ck9vp1k;Z$!`Dgr2>bHN%+-9D55O zIyl~d=S@KW)`Y(eap~tY$yEQZu8JLV&+z&>mEMl&YR74JfKMC2hdnX0McY!<25Cc+O;5}OiL{-pub)EK=lGovfR88q z6Sef+rqjomZf2IzVaEcmCCsWjpM(zSP&*WQ`Q)D(HoB}>g{3f5P$|@uU`g>$!!fx9 zjp1qhGYS7}mNm1RSPRSR@P97L*0L_DuQ3)YXx$RJt4{_0{IJnpSEbMHUr6{DjaK-X zp3uLP@Gl#kvf>v*&#XyG{*?m%s!bFPn#Vd--vI~f2xo43zFXkmV|bNwSHizvPtp%`l73j@#E()={224~lR6=OniAq? zn7f}>32`^XD<#A)*sVH5_h<^-oA6)Owf{;rY4zKiv9v?!BaRB1v=!SQwwI`WL6VfhGI=ddlg@L`6aqgj_nyX z*1$P06ehR=d+?xarjHCZ=5W#!%MnK>Iv`;p1N$BXL!6}jaA+|uixt{pC-sXInNjg5 zY`>`zC&TzP##-36MX`Dy{VP#XGeWbKI7LSUZ_t9+H>a`g#Huu@OP$z{%z8OWacUY~ z;0zvwCoB@Tgmlw@=fUK;0kbhEgEfwcim_9Y;nY+@NpTP zb``Q*#j+a3b!ilv?Jy|0WkF_g4xFBJrK>_APD>5hUT962)Q8QYX*rIdI^yd!dDg-V ze@;V6X=Lil3URs)+9DcEiZisb)bU8t*a0tnPn=l|_jD8jk6kDf5m=rSXX)`Sj2>)9 z^?hD7Drak*i_<2Ay=_8dQ}|d8vxvMQwKy+h;vAjqSe3fBigWRIrm6~yXk)6$4dzVg z*7Vg=x+R1whtEq*I1pGx54o;`nAdaLprJ%~^ExehPz)>1DwR+GK#xLzJQqhZ}JxD=x&JYvyKSUdinQkt=nnbzt*0XTpCG4lZ;Zaj||2 zp_omhehqtd+D0IJy3Lumb*?v+UE16BYJPRGNwFIS3t|tdJXx2Y3)?iI*9RIP9UQT@ zLD%hKVNKP?_N8O(I-s>>LhMHianV>Ye`VK8k~n~q7U(|(h=B%NE-r!3ENnn-V0k#? z>|k9n)X40=>FC{s7}UZC;S(0UURZO*ke-+=h+!N&qaY69_gMvTxIwq9lx3IVAg=0S r1b=NTh*9{CjkfxlD8{t^hMuMWz#zqC+S(DEkuM0`eX_L{pvwIhKi)uF literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/credits.doctree b/phpmyadmin/doc/doctrees/credits.doctree new file mode 100644 index 0000000000000000000000000000000000000000..9cb3aa4e79a774846c0947ea2201f8a8847b038b GIT binary patch literal 135005 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 z z+=0HH54!<}(J8QfM%9fd!A;aeNgBPSQQe%~_@$YKgVZhhuMPLGZ*6hc+Yrj_22h}>ysZf9E|m2ml=bfHlqO!qNwj;9WOgr`zc1VL_D+H8IULI!Y`4zne%|c?WJI49 z-Ao+nLDKCquY*D9>+46^JjB@;%Ma_H0>;@k3Zo;nHdMDYl-n9gh>z$$c*ygk@cbA& zKMv1N&^FV zcQ?PvRNiuL)L$td3puiQZ1Hg09i^zpA1n=fVz`L5-ZyxTJS9)h&u3%6ya4|%W=mgq z2?@T8JYLC8o}ORLHq-NK?CW*-8omR*)Ef*IpoFZW`Aq}&7U13n+&h4K7jW+h+`Q+A z?EUPNhV^C>AT6vnKggE%SFxe(J7ef0G4xutb@u<5+x;ZlGW&m;ZJYf+gTv3WrCWXh z=U>9PV-j+n^FNscf# z2NC8mK|Tojwvj*;KasBISSA~APm^lpe5 zMC7N1)o6DUNGMq=KJI%&trXa%skeQ@%jU=Q!{vKfOze0OTWkf3(&ou!B=0gR$1=H$&aq7{V}LZ4wi`l{6peV+Rw}eN9jOr}nN%i2Y9Am>K`K)rJq^+$Aw8Y8 zRFxSlJrmNqwR) zYyc?apoN=HOZk{(Fi3B?S>`SEL}PwW$i2WDD%Yo-iDh-AVSTcRRkyY}NPIKMX^p$4`iIWm$sH|<>Im=!{lTaN*r7TV2p7Zs;twfF{;buC0TLc9)H zZ-VFn5Dh@|K-yAwsAtWCpxL=uO?9y3L5$XFA7ThLgWymQ90r2JL2yKlRQoNGKQf1_ z-GbavIb6@98Sfau3xI)`8?6?OLqkSW^Z-VyC(7pxQw<6g0Ncc7h zwke(4CD%I`=uYGc@oP=4JS}YHUGB=UObd7C*rtVhKyxo`HRXMvydP8#;^ z+ER@k;>I7&Nz4k(6=WM7qO~6}NjwUT$DsWtd?qI`D>SXC zo|QO=(OQe=48ijtcmV`2g5V_(yqqJo_<-bJ$w@J@LNju&=5R?~W4zY|F8~H&Zs9ck z1|Rb#EYWL7OFaQy>}WLZ*8kFrI;G2BG%Fmg40_$m;?>n&{!;E~;c{MD@5wh{r_NtA zH5yZ1`hN9Fb6dT|7YyHGx};I^wn^t5r1LJ)c@OElk90oBNggF1=9p2ko!xu{H^X

    A-uF!l3nhyGBE^ult(KvDw1#T~mO3UR4f3p=hJr`^lxx$v2D{RhO zVav)DHdn3`_+tXg&TS}gyFqetxxl$>DNif~Ku11X7`6F)OaWr3PciS5UaU6NmDUBL zRsNRx))4*w5ySZv8~u+F11;ZERZbs36R&a02a?hsXdURTY4~t=UX)K){!N>7+YK)X z7BY3xXzpn8+y!}dLY})K&(6qmx7_5>+$GnH=C16r8(dD@Ntdd-L`&HvJp^DtcL!)s zfbIcMH$Z!#@ShT8Zz=pvL-mnP(3h?DLni=f*Ier;@6Wpo$hC~}qFmc39|-h8wAGdd z!_p8~7@8~NiZh_=cy54t)G%&+cy8j<)^v|hBj`}AJ<`NB3L2xKJqEFjh2}VD_J`)4 zw59TnXUPeW+_gDLwU?wpgx0!EGyr=8U=jc(17IHjOv#nHeNO6Ab5qP?>`kjp%jJSh zXSf*x7XShgH(FuO2Cc9g4H-2Xq0KSObHO|h%=5v#0L%+*p)E3@EoQYPP%CIc zO)VAJnYO%^8SUlJE`j#G&|U%UmB{N$5?&>FH7T@OqS}v<)*vdVFK#NTwY=y47WhUp z$vPyp-q3nLTMF7T(3XSNYfGxaBvr{`K8WQv7E^vfU26*}V5F-c9fWi>q(hJnBdD)Q zw?=|$N+%*YDF%unCx}iX3`a}7j$tFmqFw+y$kdDHOAP458dOSdjV~!fETjvMbPcmqOQ7FVj)&*y|x&NOF(fcC@urV<)FACSL*dWAzYc8 zVxC)QLGr3xF3;7Bd5vHOz(MRStedXoW3Gd>Sz2dG(7RDStzv0BRu!&o`TQ+oYPs^r z_bgO?d=jce8K0hNmrcfv36gXAmj9-q=(*pQYXDirvKYJlcN& zx-TN8m!S7D^d5%ZE3~B&zRG&9L9b(zdg^tFf!M4?dc&x{3H7(2{x;O#f%?0-Qly_r z`n}u~^Lk?wQt#(-89rdF4+Sd#ePV54^lay2K7ti`ENivLr#$Y39z}I z;gElmycA)+P_jsQt9hh1x@`QIsgl3m)+F*N68Q{?e2zrEKq6n}CXcDFa?P0fnq7PY z7e(!Gp}v)vw%f||oq_ruP(J|bM?n1qsGm`$Uy0}!DO0-uewE_=k1hO$;(_YxTo*D{9w%(ac7zkvBSZ8iQs!2cJxDS6VT*)Ls%>z}zJq~=lMjy#Ew?g_NNxM|cF zU3cdpyo@|i&&(4lXP$(Yl_xYV(EJXXZ2CPFG>2(&^AeL}dudc&9!E&NtcA@tYz1H| z1Y1Y2?EDj{7kD?e)I}@>Ku11X7@b}Dm~M!Ho=#sLuHLrg z(Jk&}DpciZb$l-M(%bKZvtc>jou!k8U=I_@?g*tPLfHeMxDiUPyyPL+JI@TkK8)HI zsDs*ts`^P9U2V1MZ?Facs|Z*Ffi(zNgHfwLh-rw_s+|Z!rAozYV;HIgu0DCzVK|(3 z8Iflhh9mQA!*CQpN7Ggt7y|=i0X!~GIzBt53uxL>#m95w6A&Z47~f~8x<)N1D&W;$4 z0fR5H$0uUo3wmSW#CPRY@E2-CU1}*KC5@wHCXeOFqXc>Ei#%2!kCl1J<7ic$8Aq$x z!hWzYxP2DX8i{GKtxjtV*Z$yI2d?$t@_?%pb^3>(%A`*1Whj^WdD%z>>IbmZdDf9s z$-DUSEF;OEXB$ZYkXF%FI|#x-HHbrb(y`gHh7Qw~`a%si9Pd0fvU*vFCLBLFZm*TQ%_ijO%O-VfEf^TW#Tp6~UxIuc9h&Q$Zy zkjz+EvS8S<8Oz zUcn7ePq~s?zY6iuhbpwx0o2vhfF`)c#B?o`t^>jKi0K9>-w5Rkp?ni7gdIdp2{fVZ6dX@Kl4ea!pDQ%rZUPpd! z7!z;8#9J`&HcY$&6Ytvcd(Y(eJ~Mm(hW>44P#=o1S8cIwH$)$S=wlFl0-{er^ciAx za;%?AtnJYMLel<{`M*NifO_ASw(S=9*L=)3@H{((-qRG)tBb|)P`M}QuWI$|FlFwP zmHvu4x(&iN6Ah+Ieaiqzv-@`@k?)bn4@l%kB=Qpy`8h9ncK;>M%i-~ps ztKTG)uWgn3-EjQ@u0O%`7r6cg*FUI~i!1f7RI0rYDfwKk4*BFHHDAgFvR_TPc&2yo zE@}CenLa(=Hq&S13u-29wFPIsSjfs3WLLg)clJzI_VjxyeGWICD~+%0s@rS6mU(m# zU9;ySr~;@ILcL?Y1horPJ3*Bk@MSw~seYYVbvLMXX+c$W$>&Ij(^{;qhM^l6x`Uwy z7R#Y4 ztMYE}KXQUU9&L3zP4nr)^m(-(t0s+}{>JzK7%zhHfiOM@#s}vokDej$Z*q-cbJSqmjq50OaG=X>7 zE8jAfCg$75(%vARL|g4-GMwxK@+tY!tJykTyVI7cKaCroj$AW!d!~*vXcxLbH|fkm zo3o)c2kFd(#yn_DfW~~QTz?)yv^%(C=;j={9<>$Gv#! zf@SW-vlr{r9ewm7T_iR6#E;93+n#F}DrwNHH7V?m6xJby^+>^k6iV}x2TfVN88qc= z!V43*b`z>XqF8OqztSlCpzMco0LoQR4kG`KoPV|C-&iIjWe77(4axxR@_cJokMJ%k z-_q5i`L?be15BK@8gc_5YXP+}U%DZ?qN`}yQb{*);|Cy(IVsIOo7KJwO8pKb5xS~2 z(H#V;gF$-;qT3A0LqQn<+%LskBmdse(A=4tih zwXZ)K_XOP${*G<>67F((MEEpTP8yY`o3PG6SZ5-vvk=zV2Jy52n5{1czJ@4c@lo6@*<|(7grwlTu+@xd19fK zZu`j7p^Iv~p;>d5C0O0Kzj>C>CQ!YTZ*y+9PdcE-eo`UpQD2fE3<9Q{TXek^q+I%Um#Dqx6`PQU(&u>^eYq5 z*J%73h<=NRzJu8J5PKhDKhTzn_alq_1hM?aV(MoJfT*n1`Nc^83hDnr`Zq}b4(UJg zr8>KFb^gpxG52=tLVx9R{C_jiKSC6MI$^djTK?r@QVPVyo-|`tS9_Ful_%$RbV-( zv=LBcGf?1PTmCr)Di=_BfXW9{0iX&6YQY|yf5(E9hLcKL33e&q!gOK}yNZVZu*g_q zTy*ALb}O)qi!KGWanTi=-Ds=%yMw<6cy}+5uKF*!YESw-6?qSC+>H!#bbCpK>qYx% z!QLjAK4`cv1p6VF{ty}fA%Z5MBHB{12C~o~2xTV=slj5LXsq=ZVq}LxwivR*AUhng zBMPJ*y|^AD3%DM3kx>O4`Di8?BP0PR6J85rVJsgr4)pxAobpHAGxdqd6N-gf9Su`e zxHjq?O5gWoyCuIT>n9D3@y7K8xZVq{C&KmKa6PFYd1y>7FhgS>=A8oGLG9vIQzeqI zwqi^(Skr+u16VVGH49j?QH(xZj5$(_b~4PBTFql0^HD2+?NeYK9t(Jvg$0)3v8cc{ zJQjm=32n85rEste#LEk$*Ro~JTtZu_`@Y=x3gk$)-I}i?omEJEmC0!}RQ7}V8sxMV zs{2EA0aVw~ma4a&RXtGc(t@fgl}L!wTB|a{P!0w!7%IR}2?k$*)T$rX%3qLTZo4(B z7%1S%R54>v7z4l{@D@ft-kHPKpp>C3_F0<9? zX2W$0xNZg4ZQ!~cTz8;OgSk$3N}bvZu~n*g7dyEdRRq}$1=itn5ASksfo1sIS6~}H z_XG6-+G-0A!oov9ez-vTG<(+2+h|KY;t_8AQ6xEBx7Y3xKSph7sK-ryPeA-hKs|;0 zo(9Y_fVl@S&(fC4`W(YNUyzs`+Xt34`S>JPb>#XK#&5`yzsJQl9@ z#OQq;UX2>6bg6e)H)#;QXA*fIiF|-WK13qhk;q2{$%F9Y0y79dVa`v%Ij}vP>N82= zZCjl_H&kDM>Pt|41*)$>^$qGYjO+BR)Tw<4-${kOXBR)9Lg4zOz&Zeb1x*z2Z`xbS{$uj_7tN;> zifo5M$tSf?(tn{yRs~XiC9pYZD{FQoW%h;c>!94pmC*}##r~Jf}CltkF zeDRuc?K3LRuvUjRc!H!}p*+>p5Pil($g{y;i6u%WHk>p*cQs*mM%cR{>@EnqE5hzp zm^?na7nbjWMZ?1;;q>?TJ*!gKGk~27+rZ+EU#oGS=R}8ox7GYLcW% zPOYV%Y#{dm`h9PA`>D0bG{f~__%A;5$IQv;X?U=)HK&%s6|*tSW>B;Ghv zZ$P}@3E1MbJ(E|<$83bt8Cq_--y74D;*@gb_jp6msQ!;%Znb~d7=3z3JXYpwx_j5L zdeXUOlS$$LByk{;s7De9A&G+vlg~AW6q<9*W~Mz9w7WD-s}2+AwYEweZuF0U{*ll> z3i?Mw{}@zaFRsL~Qi*@#AOQW{lEokK^_tpbz8d1(H8$XN7g7(#gQiZ*_3fB~J6`EAKwvbD3 z9Wz}oOaaIfXrtNX2Hx{V(9@gLTjgx72vl4{C0rfVGHd}6WUgmy$iBk zTas0G3;qqZ^zJbb_X6TRK->?A2LSOP(wofbJtXP1Ecvj+xQ!_vL5$$oYKze}i#*E5 zJO*bAQshnL?ghG1Exm0>R>ceTWL6W5SNcP80@i2j8n24^z0rn`M0lJjl4g@9OcGBb ziKmdn(@5eOB=Kxv@@(>4p_xsdXX+O~J)rH>>P1QAQCoFhGE6Un=@l@&3Z~b<^g60D zg{$+1RHr=vZ%VD+Vh3-dR-k&`)QV@FcX*d~3oWzGdxf@H=Y3#)KwFLfA@H{Y_oG7T z(d?Hl&S^_^|AZU=v@mg+ZbLCYqoe66+@$pdo*FMN_g8t`Q%b#c$`kYHU$r*imU=5ZWqJ+F*Zlvm ze$vqT*JP2>QL^aJQL;$wC|NiDiCIudVYN8uf}Rs|F~)HmB{4H4wrmHLmZqiY(STetV_6O}Gcz+Yqr=S1%*^=e-g`>Z)0Sn)*?n*S z@4w%-o08<7I=_2P-JY&NPptjuINCiMpDaw=AA$qm(zryk@ne)PiSdSQ0@x;kZ4%ffgKY|un88U*l_b^%WSXQkohzDwv_Q8_ zj<-Q(@*%TwJPk5C$JZcpfIF8)UB*0=F(265=g7L{x@lWXBPG9pCtsMeng*$%<7ne+ z{8@~Nmq2hw__Gs)c81VQ2<<{6MYk&p?UvJigVajlMB|NRcOz>4jLrPw`l@BeKFFckR7x232_E}v}u@L5!|Kzh_Gx% ze?(2OF%%m|vCSxUDT-A&nf;N-G5wKb%oH#KUB*<)#Eq~ohZcjj9B8dTTLH8^fVL-c zn8P{jB{{4G$KDdvK3vbfhzfAY9B+5*$A|2n%4xql zPL{%n#+%A1M)p+5o(9>|A$ta7&&-ij=5Z=#xTTxk3_#GU0X59p~|F z&IdicaGqWpmkim~e0_~aKeX7%4qt#ha&^y^UBCdDpDu37z6fPsjIu95*_Wd1%W^XN zi>OR>0~i@#Z{VDpwo4Yk+qx@U8>i^}xFUscg@w+$gE6CCg0`-pyRs zEeH>QSLAs6mpedwCylz2yHLs9AipO^mNA#E+3%&17Q%fz`Tg)U zC#&7(&sNgWTJ`~B)PtD*A;>-qqaK0Wqma85a*xqSF+R?6Pe5+t_TPU(f5tkpk%_F@i)@DfwKEL36W6KV$?^a|hRRa8P3-ZR~( zwb*Uc8>J+@wWK-JoN($RZk_)tD!6gl{xw^@#(J3_G;V5r1GT=1THivgZ==?Caxxp{ z-5k>}?=j!|;2Y8vKJ|e(@QN>i4-M5vp!yh8pMdI9P<@63YB+(8@wCUcIllJz4xr!Ds0;W31^fu$pK@fqa>W|?XBsKxUwHCg;bL|c zf0vU9?l(G0%l&SA`2*Ab3Aw-E%ioa6$`zTfA+wJDox@r;mt@w<6`5XM8MS^c7yXMb zjBdFQ?Vc;5J#s~~XRe6$$`#Sj#7PiLzAOC zxy^@^BeTQS&B~e>SGF}F;_7>>RHe0pTW_mi+}f_vTCmKCRZUTDlQn@pOf%ucD)n(r zB0*mf5Vs~IlD2Y_c4hYbm6y@82ovq5cr4gjX-%YVPUs=&L_+aOYhJ`%=F$PFL_&|1 z)?CMpSd(p~EvvNV&<7Pwi8UsYDju!0X4oF^~Bk;Q+09rHQp2>9ePW&OD`-_I)!>S=2lwMTt#1s zKG$~jzq5`tm%a}@R_Cb3%4}V!a`cSz?Nr2}QXCc2epqt?)_gY-p-BzWblcXc4OpNr zm80=wd_bkOV``Zl$zEXVn^ao#MVq?I^s#!vh?{JsZ?+BCDfV!=o3IwdQxQEi{l3gr z`qy~W(Wbj8ec2Gxrt&j0I)nO3%Y0elLVCJCo@mlwJJ|Kw68)EGB5VhBVYA};N<`nH zM#VMO?9|Gu64s(XWj1>dj#-NX7JXX^eJbi~$05~54Y9~}V|FUhM5Ro&W3Coir0cX} zDQB53Vv+vW*2?S|jWN64jq9UVEKNBpswUJaty^hL3OSCo*w*SZ?WRa<)5D@u{ddW$+#S<>x94d?-E-;h>l~*hu2Q7D>&6s08AVP(kyBCRG!!`< zMMm0+oFPU2E8u2|F|)Yp*)RsgU$Wu5<@f zx&W0eL}jtI%4&EDeuECnE%xLvLD_X~JwIkp7fk8C3+cYBT3|at*Q&Phr@)Be^4)&g zlVH3hq0gocolLgPR!gL+IZWNQQQFbOuoK{R2J|k7VOPNJmYcazs?9YUrQI3T25R>< zR8=R6i_$*Hdw7gw5Rwig8z9*T$xzxKE$HTQ>Yn+-x$=%3){lsO7@`D~4ll}w#Bx1b zoOrG;t!7Xx&6Tti=n|kw=E~lK%h5b38Y!w}Jb4T1--7toDxl>wp(blJ{;UAO9w6Hj z{_F*!y+ITO(LOX%BKtDYejpmXmPBfQv6AZZ=68VMI}m&af$w1O9Rj{Xb0xoK&hN0? zEc0kj$29a^m#eTGp37Mu!Id5PPb)i0DkGmdc!c6;7CXixHZc`x)E6>#jM`9NU9{>G z3*C`cr+*ejeV^q(cK`r2SoSgN=!+4 zHBTl{5Z)@+7W4@B{pB~&$ab+ zt==e9FJBguA6Jd*5mEE?(WAzy$6(dtu<8j|^(3r%DmSx_p3XIW^b7+&3&0*}K=qtR zKIDt%d87FPG+%_~OVE57ny(<9WgO3|5|3BlHA&!gCU`>#!ccuC*V{vH@*!{KdV1*X zTwf2p1B`cR)Oha!?|tBWkSpt#>(M|T(nt|~#FKvv2k0%$UC8AVnnmM$YFzmYvY!Lz z3%K$nFunrDo51**MhfB^#`qQ(L%M>Yz7x}^5^q%B8>k-u^&_Bu0@Tld`XyJQTFz1Z znww=_d9_*uUo-ud%TfN$HTr~h%75FtDRO_Cl6k&n#J@bgI zSDvtSGi)kb1po4-)7vQaf#L>G>Q4t`DY1D8ffGY(|S)Q!lzp#GG>F<k~qG2E! zo+lCQ$q|jn%QAOG?dwzbc+^Mcae||mestIAw-9=&zJt~o!_#kx>37!C(*qd^?wxqE z6O(6Atm^d7A{0)BpjntFYn;oW-7!zVyJMbxF$|zZ z)|vDaefSn{dW|1DL2+l0>;gY_1;K70m;-`Z8hOvl05%+0A`TFh*Y-LiQxBOSWE{ve zK&CNIY~Pn{59P7#16ErVwN6`2ZXQPxW}v37Iua3bD#zP4Y;u&RjOC>-3c9fN6D0q;72T6F4@>#viSlz-H%k$EAsGY`8tx{gp7t9I+wFjW~1k_%D+8a>&Aej9) zn0+OfK^-Gxq_dx-vp?5xz*^OCpw!Ufi^%sv`-52FU?@DV6{a~VD%aRiRp-QlZlgYV z;wOUWaOggbZLn>C^WL0PUifa{qJx2Q4Zzws%N1R6>&La`$QF)nX)T8sv8TA;p@7TQb8CC34$BE)Wz7=%5kvsvCCqnWhNS+MI zQ?P;#;1zVLtRT<)r^y02o%PQU{V+t2F_H5b^-MnGtUS*d_3S*~8TA}coJ*soI}dc{ zgXV%fX)-QH^IVu`&Zrmh>=(lT`of4#tr~R+&7@H-HHKUU$;*Lq1q`_o2v-5&OdwoM zBSmlx6I=@mE)fd|%j^4fM&^3R+yI#yA#)RCZq5_m4`SbM$z$I)X}2tD*vz7C&ErsR zW1`!;?8zO%P6e%UQoWPsybE)V&~tXV>(t%w{2pV*y)ffGm~lVMSP3&8@Ol2A@%$mC zc^IDGE!=ndJb%Q&*I>=-z69Pd3B1V+Zy|vfh4y)0 z0&g3ccOdgFWZr|!`;hqn2^_)+d?*PFTy0@|4elxHBk}!XX8L3;eEC%P-)ztA&v@3) zF{?#suHha*eF2-lH1&Ul`oBi~-=O|)QU7;7o4+?U|G?ru!sago^E02#KN*>yA@d7l zeud0$kog@pAIdiWAvX8(RYd0c>iJXr{flA#?urvx`Aqynd&aJlPt&cNpPp`w_oM6O zi?QqHqvCG)QgQcuskleJRNOOPD(;n^X>4{rjP1?heIQ=3W^uKFltR>A^ZOc<4S})| zP&Nii4p4IQ#r(tA{JeZNzkC&8KC63V^YhvJ0_H930&kJ7@eA_6mK1il?mVX8O6dSp-|{P&|&u0!l^Dcac+O{3(Y&{oqdp z{ITFq|NP90oB@18%4!p4+!T!645Jz-g2lc>HZzKYpg0(cL!dYmikl;mBRG*tNhCde zl{g<@^31ArxmWeb{5|fx^GFSp#W>HhbKB~zZ z*;GR|4P?_nHUnfcK{hL2B0GvBo1M>*Rj!ePn#w~lC!dp@%hk+V`)cM(HRMVM58iCg zGCM$q-b*|s))=8z=nSrjx%6EBEH~B|j7R0IC-FK*C9NGCJE*U-t!l-;*DCp45JK^! z=W*->LgDMXg~rkvSh@(7E{3H`VCjzenSHlYzUjN28GILj7j*!xb`^&0eYx&tAZh`z zJ0NU8)B&O%xgNv01|`=H6&=a2ff*ZxF$|2I^S#{};zQhgPj`m%ecjmvt_Y2qHwxYu z_~QA}5nP}qY^IUIUCNUyctqEFT@NrplWD4?aVrJ&WuR(-TgySy3YrjTR?tX^?ZGsA zf@b(y(5St{LaNJ~(Vzk4Lx?_8@Mw5=3_Ls*9v+vU*^=uyS3bNZkc00)K$d}Mg;?VBQ&oXz19dp!X zJ_C4HJ|}xOS98zWS97maL#}ktX!o(q{rTxL=2Ydx@I0Wc>aEF+KI2DNP1TEt8*7Nu zZvpy2N4QdyeEs!+vF$WF^K=N5gJ_pI?k<=;j-XuxNGyjW{!Aq?Fvgn5)`gp##yI$c#Ud{J(*K7H{?s^>* zZ_ude-UQuSpm{rARy3ERdETLs!g-e`e-HKZGl89q4x%;B#j90t}mVnn8Ujc2N!9jJ`5NUxVly5Pb`x??Ci@zGQS7XY@mUR@*ay ztLRe)`P6^R=LCOZ`k%W_|BKL5^&NE2uRQ&4n0|?#e!3eAy3{Z3y`nL{xEL-2{-?On}5U2tO9X!or26J zTerY8*?I+3!}Q=ylzxwj)UI4`&1)|uqKoolwh+;MrdyC?nGdRCK1zBc4 zC)00GzybAT^$kTm3{65xx7bE}$i@Yp7RxE{wOB47@@Uj>`G6|`Oksg6?_aUJi+BRw za`WsZD4!nN?L=~_l;)-Vv~i;xg8cwe0XHlF^alVH!~1C(c{|Peo5FxnF@T`FrVlhS zn?Ys}WClZK2xNv9i0Nms>6;g@>HXU+ikik-Qe^=LQpG%hF8VP{xT%;`9$6aBGmgNF z^t4sySN%x%Jjxg_8U}0u1IECBEn&b|pU+zvpT{x9)}R>N1qxLy#SQm`vW;Qd7EIfL zX*`%FfN3H^Ih#Y7B%y590fFy|V6r4Lg)5l4HWf^h3dZ^3@jd!9odsq zsx~^RF+OU?Rap=N{UUy?u{p9XqJJd1vJY+(+Zju1rpEs9M2vF9FNtm zwy$yaEa24kV(PuSM!k(>jMU;}Kx&k!Dm!isZh&WR5bLM?>=%XdVmA zXJ^=o}g;rE_`m^WZ>LRy&{B++j55(?pu+0%OdDP`(I67sHrKKyoQaP65ef zG*T9qGszVosq7+&x>Bs8dc1*MWw@>e*EQg}7F^eX>-qu->|ze=h5`<3Xh#&(QJD-k z7I3CFaV0meZ6&uzCFDm3?R6`Q+y;>?w8%`m*^W60{<_^AQ*M38r5D4t;wLD@n}=^1 zhzDbVm=g#$>i};THD7PtVQjk-w%rBW?uKpmz_xn}GJEU30@GXfGvG=9_VfU%2SoE$ zUsewq(T5=VFhn1L=%WyQ3|U>uSv@XUWhgu$Nj%96PYFX9viBEwyX$E_#pa(@jQ*1?*;I^2%eV;WKDBHn&@R3DWq3;@>k&jUEg&+nAd0$P4l{OOjr1F{{SLP53^w(L zsD9%M=uad27i9m2Y*wMju2U$o>lR8tS8_n>6>>m6jr9vTgl>hz(Y;Wb3Btb>c$=vQ zAJVhX(@ebzea)0zC?vgU)P#Ksg>VB9^(~ZT%q3~24e9Tc(MCM^#xglyt8^lj9J;l} z$Ss5+d63HoMga^dgnSX?sT7hgrjcSOVfj+X_wS6nDl24@h}@e_xq;~im8^T0G8OxuBJdm4FL%S;QvG-j=t)Izb7YRuRJ8^T2(Tnxe` zAlwmzI~7Wt*UKKbkmDTPX&zr^?oue*Wv*_we_ma!R7Y-g(5}0)oDI217Cw!fze-@$ zkJi_hr>Tfz$C9F!(ic<-{|8{vL$uTRCAR!g7CX4HCVeygU-Ou;n{3dx2*e_KRn!Tj zubt~n0zo9;Ab|!X(1-*=g_-T_7MgYrb6riStDC7yMMQ9SU*=Jx7=vOQip@}53Ppv? zZ{*Aql6iXiq=cAa^<|bcd_c|svacOpZc^sjL4WT}wK zUgZJaQ&{Fy$k2srr+el!1ai7@>I^t_CY(A8PMr;>&hZ6ut_kEkhBzM(gE|kPE|Ahr z@r8GxLAnS?7X#@MAYBTi%Mjiz9Ny&;-oVuX)bevx9{DRIt1FrRs;bjajqeE8O^l`&-qKxC+(=ZH2>In)x_&oxu4{iq{)&Z-BQq!rPnR?alD^mcq=F z;;n_|q<9mS)vh&lz)`hx`k`dJ*Ql1e}+F^AK=ep^@Tvm1$ms9nXp#gy_xSbtCfz zWZs0#TabAhGVc^h26u1c52Yq5bd@vUM?C+> znBP3j+==%11Oa?%ocRpSd=6*6fHPmhnXh~Sd~E{wh7rC6!obcVsPCk#k9<*mZ-9OP z(2oH62|zys=odtFCr9Jjaf8&e9cjo(xXa5_sZ^50c zlBvcN9!8uQx8n=vOm=O3S4f}vL?7%dGGYBMLH+kY)SUMy*#Q zMy+2YMs+I^qq-Mmp2~U@nNwNMA_DAHB!Jl&fGS&5|MKP2+sO8T>;{nS3)u}JyOGGw zxtsIZxG2j!_TkaUDdHG%nIlg)!Vo67^eHW$4=E_}oYD%5e5bS`kQCFX2}?j&3Zk+i zS;Bu|376B~DX4xtc|}qBF0ixFSTu!Z>2F*a0L@LnvMF2{2!_qTK=lyAAQ~x)!OSqE zDBa1OV^BlIE~>$s)8>Y#5=2!X3V>)Bh=vzQPWN(7BZ{)j%U#;jrxwakA6di+j$-=J zU8mnd=&AY+HdteL`YkcNow10l!4s9e!j16Drd!-dl0HJM8b7SEg&t}-QGJ~mkBzQV z^gbZ-^QwF8u|np5`@6Aq9BkbhwpPQ|ZD8xRMVVc0d7kMYGi z$>>jp{uJm>h5j_?Pe-ixbF4EY*42s4loV$%*=!*TgJ67-w-4v=A#;m7eK@bk*N5|g zv^|X)bqAm>0NTPL=>e`y!_^d-ON&K3`(jvQ=?T{qsG^sL6UC0kn4O@uGbna}F}p&2 zH>l5ndM%BV%kC_0qxvOMJrQ~RuQM|BkO@M@flLEr8jHmL2iX5mQI>g=mA@k2BN%QG zM-gV2rmi><5n?K1mFt8kPZujnpW!;&266b?YzkkB!W9ZnpztILPx<^^X8dhohUG=+ zb42GDRI3yg^+mD55bXh?Jwdb=i1r52K8WH$j$&VlV$;>?`vTcd0@|isip?2ntllApH|K35Rvh}x7>Ji7(6;09vuOXj)X@? z6=j~TjxI8%t7Dk#SdjJfkg4ND^B`X^#~aZTAbKK1PlD*l5IqIKJj}tID#2tZoF?X< z&J1S=Lm0Bh7)Ry(<$TClMV=GW*+sq+(>dTcmqyKZ9{A1&&jm%Ybh#i+bRmtD&P6== z#qfZh9O*#-+xN%OH0-Fs^_dS3>?O$e#)Mt7)VNu3`CWA>Y3<^6EMvec=GLMt^W?}X(!PGVt%xJLotf|G67!wHOyzcPF>n{p zd^cvM%jzBI)0U-E7P<88DAuBQq$$44st(z)6dqq{4mDRrTW$K_)PPFqeC`o7U&q{Q z47v{n-4BCS!k`CW(1S&p9rI9;>6nKZ@DTv^NCT=zMe;6RD32M<$D#QIG@pd#Q_y@G zp*+r^JR_la1)df2pJRgOg&+*ohl{-Z@&X_7Vv(m`UMlkS%gexcg+`6{D)3$d&g(_8 zV7VR*^ahO-(VIN^TX2A0=h1~+-lkbJ&O64HcOm;8aNdV29{}S+V7vf~k7%SIK4y$h zfH9;i80u3ojVkd*^_hYC98g~X>PtX<1*or!B&sJls&9%oszIwkpce82d|Sj(e#bR@ zzg9K;AT^K;9rV+Wtnd>Q=-b5?xUrBOvE{88!B9%s)=azAR(4X}{lR|<)Q49+=lv{- zzMlHUnD#47`wgc34%7aCX@3@F_S9cRrlp zqS>ujG`kmzW{+YC>S+$DXK_~BJDwoWtC)kxE+&HBLJ)@P-$mY@>cfX@Q0(cczQw+t z+7K8U(Wvn@23`(ua*Jg#|A@t$M}Mc7@_F(CI3VxK=~6a@G?PXuGR_o3x&%n2aHb3> zl*G9p$(Qs{x;>_k6Q*4@ROQstOy6$asYAaE! z@&z@{NNx?uYDjJa$!#II9fEqEgBmYEdFG!W8BApTNunQy=$6Ia)|$+ROeyxX*3@EO zYfS^ibQ(3?4A9L4&8%Ws&s>h?nN1_5GlwUii~0xi8t7yu^JoqYGv8RUJw$f^%mP@l z5D+zhm<)(TG*SqQ8Da?_26Y}n?I?y(72cF~GDtfEX%`^v3Z&hDR9h@5y~ru;UYuo~ zM`{;<+9*TbF6I#Hn7@84_=Cbv26WIu4$t3!`8UTRa?BQKay&}U=?ClTM~xc2>dCJW z9%c4U$XMjUqA)CKf<+Nn6fMr|omjEyoj7AP1FM%8ODz>q#}|w;stKqjp_+o~GN`s7 zn3p-2E%1*VITJ*kQ+MCY`n)MauJC7cYy7uU}p<=DZ4XUV}NW!<;u@ z&YQ)V{qk0^>6f<|>>Yr0Ghpgn5q!}X$9qQceJFka#SfwQ5fnd09B*?RpGX|(=|2_A zKV$XJMLi77w~M{K@&zCAWwEDMzAEuC9*dy;k{`Wx%&wB-^CsF z$_6}lU(8JpKrD13sm2sF%QDBIkJhV}an*bI4MoA%CmR`KHij`dFeVqqfQ#Wibav2y;+nP$x=v`L9!f@{UBL^EZ*lVEXl$%e}6H20PAle`eBF? zRJv0(xk&HQf-<4F%2SC9+Vt9L-ZnBkw19@&M|mhh^6k#W1=l zZ5NFbBcL@B45Q%0XlQQ%?M))u+*2x(&S<^O^`<3Bl6@8sGXjq>tq^@Gy`o2jU6r|!$4_*9T6Zz zfv^h@Vl?u8kP(`JFtD=-YN?n-6=duc4Nw9=NdTn)vk43939PGtbv3ZADUrCol-*?s$2FuQh*f&( zx)Rxcave9UWgRz49b`raoplpy++31A?bW!Ap_Jke&j>j&*Q(}01n|j~F&)<}GQF>n zZZ$652A6J!OLxGfJK@q@C7F$McZq4Fdzk265Or@OQum4CO}=36HFxe&A~h(!Fc9>R9t_I^&c1gFhuVu@wU+ue8`g}o;G@_#MeeogW?$)HQlqIdk!?u zm&oenax~8iH1YZ;=0s8x@SJPh$kgsvRF}{5Z-@b!y-@~^b;MQ@o{(wEk6M)h~7{sGlLq52n8|3+Hhb6Q!YS?1y7w8T24oX)zXM6q6}v=4NDF7dX{ z`g};YQcwGIFZH!gk5U2YNuvhrRVsklr2^EuR8}!pq>=jY1ib0w+548Jmq!QbsSRm9 z+E|vtiH#wY1AyF8aUu`G`4FZecw!diPbDX?U@bDS=EWWXd2@4w-(X zV)&12ctvTJX^)Izs6X0Du}V3B{>(9;ll5;RoCNP}4|Z}>o@pRvqKCS=w$e9)w}VX4 zgHiMl6g?D0Z;qlXeco0XZv#v+3?!9ZBvHeq$W47=j4)gy!8Hn8qrtTWxW*uipE!&y zC5)kKpz!S}$4WX|aV6u{wvw%-l7KHR-zx&ES!5fC&^uylRFEHand5}&;_-N$H7i7q z??n06y1G*m9e8|F5&-tmQ z)OUVb1ct>lYPKa{+Yu}~mC91)Vl>UpG*ULZ@Z`IerWZh$GTDvh(LlAvl-(h01E>zB z)B_|4kOcs7XrvGt7^D#(n|BRFg~T|j#+#LEu)@G<0#*cAQDDVNC9B^!t9WUaxk~N; z!q-vFr5xx|u0yS59SNy}%;@0qAjujjXpGOISNKGmBW{E11g%LS*L=E9LJPKP%{p7} z%Tl_T7r4rfx+_wv2Dwaxea+Qk{96wHTH)Uc__qiA+p{#Yx%MhG&9yhP?gQ4Gc3IWF zqMr1{x1W*UAMyu4{y@kd1o?vz-ya;`Arjwev<{V=4r8vvg)0nzy-U4~cLX1DWT~g| zjw(q0SZ4s1k2#=NYK;0d)bOE(Fv?fV#L;Qu~Wj zyQDPBys&V!2)>rPw3MT~jBB`jt!lVJY9JdrXt*m`;VLNb13t#Pf_D%daNl9#_Lm2CziBny;UWZ9ZN)P`U*1jx&C*XO!$Is(Ay>- zx~*%PP{y;JGbu3fkkx0D7jWt@$PP{qdSRs156}@*+ zxpgV}){$hqO^k%&4OVlgc~0vDdcn1o;qN&0=PCy9g8a)E@HY&|DiZ_NDH8+MEfWLQ zD-#2Hv>C8|85{7gN9|U|rgbkPM|zZrY2g38)O*J1$%phRYg>ul`eIaHcA4)4)Eo8n zp;6bpL7CLu7j-jUih=a|~Fvgdtk}XgJ=SXCW2^EnMBl^Bbr>s5q0{j!l#sRf>W7(TG#2P3q4ie!L`>6o_;2#ADi_L zzR+!!2>M!RwsC6?+?orw=E1G`aBKUr%of_A%(Tz~W?Wd7ZXx-`wHgte;mc={QCtkg zB~aWEiaSAZXXLX1>+K@>q^I9i0@#h!YehW_%>`xN7TTQ;vCBLyR9EI}p?W|BY1D8I z;2HqaSSHJttI;?i8Yv-{Cl90gwfRD~CYnk!MT{{~Xve@5hcV4ySqhfj!J=rSBofS$ z1j|}{1zJk%qnf;tEi+^-AX^TyR*3QG?w%j~js?VVfH)oyCm`328R109wL`^|B*T-L@f2YU1LKG?Z+D)` zhn!aC>CV&3eBF5lxXz?e^PUCXv%z;xnREmfs0q)dk-|NXCqEw^t=$*8T|kp*stb)< z7eW1EP+bDIE(OhHpg9#Zm(xgzUBNV0f@ZD0{_HBTkm~X#d9`7?25i@Y?K-es54Ic1 zB*|P(^2RbwaxK2l?WQu$_hzo>mVZ*wtx^$r(?OTs#zMD4XzMKR_e@P%d09}o_12`g zvRACIt?GJ*e%I6U@1ohF&mBR1W@u14(mO=c*OPY|6YqkFcf-VcVB)ALN z$u!j)#+x^x{uZd-hBxnk=3US{1Df|}q%_`Vnh(m-tFx;#>O--R>hk9HkzxB7Y@dMb zQ?Pvow$IBXw?fYCi?S@!Z)+f-hVycKS;qN(#T9-1Pb&IGDk5(>=(lfK=sO5)m$jNt z&R=LZ*&#a-a@X_`FU!JEQ&q)QnHK z|5G%-^`-Zh5&avYS>+mCL5PoHyO&(sz*kz0BKp zJ^7Gc<(|IFF8B3aZ*cUXk#^bT!q*o(8yQ73_K&(ibs`~vyD_+#va_zRe;U{U4PIG z0Np0#l3uCo!OJ=0JWfu;#&>`M}v8IOBn{1C6{FXPkxQ z>HFU<tokHny$JdmE@(V-;9&ziY=nm)c<7dAHe9&e zG+YxiM!>kbPlAhzyzR>{X7uCGZ-)L-=qu%b2W1$ig6KD)+YH zaz3QB+|!CH%6+Z42axupQKRk!)V+bWPr0mpu1&-3OCxXOdGh_?488Gc%`qK7H>T~l zG3Fqs9Sn*?V9cRVKMd;2p?)}xyc=irBcX0}LR}pt77=&GuH3L31D0dKavWHW2g?cN z64EBJD=+7e`n986oB7P~N#(LPXW~=3LVT(aQ>`7e(P=#K>6o~yZ}C4vG<=s+U0ZQm9@A)ytuJ1)>

    z{qanbHPY&W6WEm$^L zQsgs3afxLLE2pV490O7l02?4=9SvDV$hsv;Gcp8NmH?YyQfPn;D!|H%V1pd`#>>>&Qh>?&hv{(LYLI*8C2DTvM?3Y~FEMZIa49V!?+3@JUF7%Wiq z2*u^zqk#vt{1Z7lQgm<>c5t-6gPfwri~{4aSob)py9%n+s2&14zCXxClaP7 z5$GqEC`CJkpggr8l&2{uSKuU!LI7JRSUw%eKBFX8^^P4AJ)d{O&J<0Zg-xBEgPyQ*9p=r*zQ38@P-q%I_+E+V8ZCZsMQq%JLp)MW~(Qr;c!j9o5RxdO?# zG7pt=M?=NXhT5p^-BqITtFiHGh}T7`d~FVLT2kjaZ18$&&=*=awzC^l-9mn)7Fyp} zLPP#0!t`c%6rlf&K);3Hy%ip{(7KV`R-z`lmHeLO?TUOEUEhJ^-`(EyNyEa=xR0 zoVC#NaSf;^2&g9ssHX_1r%BGwkW^RoOZ8bOwD6A*|6B=*3$9+^WvA2wWRCh%3XjKw85zlXm%@o6&@HyLVH7R7w>9FpKtD@o2iy>Qc}y{BVcsj6m|i6@ zy+&esoy7D8iRn!e)9QXPy`{wT-vQOzLMh%sLBC5%K@h&^DMenu;#wAWviPL)UI}W; z-?5SRRU=)wLg-XW)mV{zP@*L9p(crsND?3O$F60#Wk{!R(;v4XRuJocQbOw%pOTP1 zBO!gRgw*Mm(HA9}ZTJ$2{)$u_HWbW(T|m&w*F@nr8ioHL3cn>?`Hsl=p2+y2M9qu< zkfh;9r6<1reiGvN8HxIZ#PPKf$CoAA3<(y8M(eLw>o*;LL3&XskzQP?NG~Z>q?eW| z(#uK}>E)$`NUwkbGCZv;h4!mT6?zc=wDXXty+@>-dsua;NBXax9%zG63qJ$U3Wc9F zrP6JH0BbR51VYY{IK-KB47-6XUg{4y$9eVKOq4A_d@V`bE>)TvZ!TR*@#Zpw(6WTZ za_|UoW?Ty~Yb7Mhm*$6IHJvx%ieV_0gy z@i?7$+?aUWgm~PPM6?+RWP)EHn?s?6qf)j-DJty@WMigcBTf`=Q0h4}QX#j*va^U~ zpF%dbv#rMDR#V8WOGzO+iN$T;QD88eFxZy3-3}f#g=}VXi2q4`{^yqFC}bCszr7-V zOoiNm7mJ-52bS{{GOP(}M*!oxJqRmdwi~pA$)MUm8stugINcJI zyCm@&b-p(k>9>R0`Q9L%?}by?sdOf&&i4k*pm)BPPy88JI)nWaL3zHH?Fu9UeBQX& z4G4|>96Qw;6m|YV(d|``s0f&QO0_{@BE-FIM!t{jINwi?WwIj7E;`MU?4=f?B{ z&YNs8^A8+wo-udsZ2tjg7EwCeRX}I85gOHmZjsRYNa+0}^cd-^O&VI~*U&f=TKL}q z)4WnN7YP(_QVBRt@PX`o@lOiNrb!u|lTJNee9m3%esP8j?x;tWCd>O&Lz$t>_+GAI%V}Y+>gYcJM8ENSPHh@ zDH6PGF@|g~pspNX17j+Y7Be}T5;0ODmy{?&N|Yrfnomj;@+;9GwuoA^>hIvohJ+A@ zQ7{WgFuz-Icg0@{r5u-D*&f)^p41X}us$)ey-F4Hduz<^L(K0>%ef;WCsa04@Tlf6mg!t-=kCu0)!VP+JTenf128{Lj)CvA{B=bM1O8C zhv!O0Zdp76yFHS+h2uYea44{&NR~%K%W}`+G5i@%5fp5m9SgN?1R7v*a#8wX$B`Z! zPug(;Jjy&Ysn1EIC?^+Glv9+Vj85aJLRhCEY76sJ<_KM7{96@I$0}zK&~SQd5g}z~ z0%`iTL?k=cTRID|_O>OS4MjA7&f$+;%kp-Ey#1hHD=4@+x0J&C^9a223A_skybJkb z>=?B@@uE^17;B-*E`lArSipD*Vsa^Avd9fwR_a%0EgZTW8@+-W^?9Ey?d(cbw~!Im z@Vu&&yw9skm3m!62wh7ET}KFA509Gn*}`rpRc5)#Z-lw?ZQDv6R6mH9cOC`8C zA$Gq~nVSlzjOP43pke+XVg3+d{xD(w2&v4Yq#&(+1$hh#E&TVh_;@J}$tMulCl#=9 zV*TFI9LMb`Ec-MGVP8(+T$pZb*kL8^N|7fLsXG|V?Qm&xd(X@{(`V1b?MN9o)^EdA z8+gbx4VV7IG1-9JpD$j&<7PZhWAyj`gxE7<3QKdcp4Ei)90}`r64nbOtQSdGFOjgO z`i1p!sdBQ`UQ{gDD+2jf5zW^K%|&nFb;a>hC?hX%_y#ulCN+tPLmhkemapmY1pjz6llnQSAS#XoZ# z{Vd4&1$g(B25a+qQ5p1KTvm8KZ*6BKWkq9*cWpi|Eu;CotW4=!IXnuf zSClEKSC%OWR>7k-pSQB=GNoke`7J=8EN4EiLGl+X%avxq`FwF+EOv4nSk9l%$CZ(K zEt&&-*eS7- zz3F;G|8%{aS3%M(v-M@#biD$Cup-IOdqKfWd5wv@yGNVRX74a(lou4Rm6X5%+%ab3 zl{LgxA;eZC#8xB3Rwse4LE_!eFJ1!*E&RhAj4#8XRg18!sbGl{XDgKDOtx!b*|iD6 zkG<(ZT(kpsY(OZ;dllC=Z*C{-fq}F!$4;hG+$pft?apvNp~>*WL^Bh>01@|5XT-~) zU_iqw4B)QhK6_|VI}d{JWhi)sR#Mz)5`&$?n{Kno+#P3c*3%P+T9Je)wtBe6#6|e{qEL6iDKlKLc) z`ec&&x+L{FlKMt|sRzr{w7%E>IO;4UlxGSmL_I0QUx2g*C8M=af4z-SjYw+~(F!(P zQy{7$uP75AHrCKPa>&}gvj zL?3gokGa$bmFOA;%!OBS}&M=jwGIxw08){li_RM_W$wY4)_bzI0Y zYYtdk19KjMnIJHe1ZIlRO2eb(fVHuKGG(hb^V@1ikuM!EhUB|tnrKINz%sm8?D06T zobP~T%g8d#Cqf5_lOcE%{0&3luFYfVL3zdu-#n9ML3m$P&t>`1s*{R^xVTo^NPQcn-=-R|k>UEpnhhA#sU{`X~55iyO3DIeb|0%ie@pjhIq zhtM8(J~Mb}{lu=6Jv3zp@s^spz#MoV>elcw1P%gcSKKDbLO0A7UFG!a% zJFQHiuuwzcbVA__Lg7q8;VeSo>@qdCK>refbJT!<`v2*rO5`kAlc0SmjcxvLqtnS8{e4VRE^K$rXgjm4wMvgvr%}$u$Kr zxmIBU*Hh@dvg-s-*CT;96oCUWsegiPiT-lNsv56kUUM0JVTH?TM&}x z6eIzHg!jpw7yP_{#J!k@$fKhn!XJzH#PE`+{xVj7g?N)cznX)E=9|8TRbHnmKHqd| zJ9|UbEi~t7zUiA~5_%zjq0#_ux_UO{cQIm#JB38~-fyz9L`xrXL{r zALap8&^P^v7mFPg2bS}F(~rwY(4P>YpAsjZl_^1g4u!jR#N;5jn&O&9?ux<)4@H4#|3>V>r@H79p7s9h|mHK>8Kz%e1_B### z?+O1O2>%}m|DQ;GekNtv&aW)LK%s^IDMo)S!y)(^f?QOtoLU0lo3b3IwzwS1mZ-8} zxX5}(I6xt;lC+|dG?#ZQca*`LBhO6K%2x(OZB|bzj(kzyyQ;Y(TpGmm}R^OS!wxLTBSL{W#yz*<>gAND$12sRhBEQsw!7nRb8&MYHrT@M7eT=;Tr2dM_jC? z9JOaL)QH7NBmTrL#wpA|?`T3?0{dK2^{Fy9OO=yBUzz}01|9{X%Mzl?@kh$sEMHEU zn-!qY@&xUQDc2Ht4F+8em(H z2F-xlT@~V2Hj{tCB<^IXGh31-&4NdvYFm-2ZB0tmS*~V_o&2-KHqc4_wH|J!+lB$b zW($6{MSiv;5pB#VQ5RRc7TgF5Z)C?q^ziNoe3gg5x*aY#N+!9_(%zGt2X8w7{e_E< zd)OQWFCdnSOtm6}%_UsA%4uY6PwehMctDipW%LPzofHT;2N`#UGScPQ1sUB{F&ZZd zx6P+epUHRA$m%AtdWbBO$m%7sBD!n@LD6zGg-`ltaAsCH4yZn4qMxMo&$SX$ECU+( z3eVLv4Wq>tx)I0T=234e72(}Fqli2~l1yrlr3kV#f9$H14X}Z7+Pdlxf{YM!%azFl zf+dI0K+Q+e2NmhwFpZa!@$9M){Ia2PX#l`Omg8a=8(2WR!xlbxk1V|N zh})x>JpjfBjF<0_`2-hVbQ8k!!}M{Fj(xM+gl&60tgpu=*F9J6eITKdNC|4!&cs{bQ;93BJKMHnPW& z!W^$*cLHH|B0TCN@FYU;WJ2(iay0^hJPG2d@Q4_~v68V!VW$bS79uyND{j2;cucwG z%oG}jXJExM35FIA<^cw;FVtRU;8#5E9~iCm^%^K=DWrdAjGe7Pb`C*yZn;vo^9Zc- z39JjsM;T)mLK!*6E<%PbRt&|7tTPIbrHz71G_o!wvMwXCE+?|CAhNDhWX;-D5_DC$ z8U-tkfhW6KNbee?`C1afn3b+m3|&;NYxMQl$_>=YYB?I6FR~j+C^u=`-%Q;94IXtp zzJ)Njl`y!iTW7v`;$h6$1NJjjPv)tJjIEH;Ah@iL1BDl{x}BlCihp5&2pv zFP_#&VDAWK-$l~jQ>1%Z`BM2Pp*4U3y2bu38h9TY_`r`A7Wi-!v_8TbAM0HTAU?sb z1fQQ0_n*O|fai09=Zo?pEo1X#Ic03Vf!W;-{6qH#Z0AR62Uf7)ZEo-yVHumUpHzFlGb(>BCq?;%koc9L`mJ0kN>POZptxd` zQCR|I}9;H7Npi~>E6%|BjWrd=&szOm(U7;uq5T!MW(plY- z#>Fa%G)Fy$pv5atT;q`TB^2#(A{5vXw`cg)jh4h3OA)ueb)#wRY-!a(p%ksQZnR7V zDebbv-*WIM09c*?Sb2t76v-u-8~I#%?euKSqpxP?H4=RTj7cNS9sQjW}vDhL~yna zwkTJ4CLmW6Nhsn%ifK77Y*dl~6vkMRnXIw4F0ocetObd+5J_eV$sy{OLp>B)I4Wfg z6{wAk$VQW5BTf`gsF2#|>0vXLZ6THy)Ag{SzMZv>$*!h|Z55=5Q;ElE@F+lNClJ;n zcGrhTRK!Ygp?p2tfDq{OBd}pbjwW^>0~;v@#?-{=yjbj&I53^Bi5qL;+Jq?Glvvq} z#I-pT?m7;RCC1G8u=vQM@GQLaR^E8$y&e-+Gv$dy?Er*K1j0cGGbplo-pzU14e@aB zQNEu&=)Ip^E{7)NrFuLx^WVJ3wg4&tL2qQt09s=w#$NG8hV362GrbBD7=iSb723#{ zg(z=DYH}*-Uqd~f`4b2j9s=@eI`x83naRXA1k(WpFBK|ZlMD#R;4%c4-g$2kw_RhV z_lo+>yjRrY0;Bi(-u&n^#I{yS+fhJiwK3YM34I$9`fL*Vwj}iJNNMMghT47&oePB) z{uf}>Re{!Gdlc;sO0;ppZdQe7E#w>>#BzhQ%T^#f^RcNxY6>o(m}6x&OU<9zXLNxX zp56~T(P~4Jx1KX|v(V&PBbA1`8O;PF4_r49%%&m<%S;8`ST++)52o0Vl0^ai?ONPN z2^%K(7XTS>mv_oarCqjr1zf*gl`vENS+n0_d+^V=peHOo+p_|eA%>EPc9(x)vAy7P z6>K5IF}^p6Y9A8dzVIj{ydOz;f0E?^6>4mx{A1%lCC@(tq=SSK9E<`O$y0*)6*<=D z5G;5oNoq4r#7yr+?|d9U`>;|Vj+?7j(e_%IL5o}4!ZvcwoUKCau(9N&+nd8HXnY(& z=p9M$9z~!ZO_&}-m@+@6$0|(!Ja&!~$R3Y?ouB}V6Pt%9aHS)7B9=Xg!1X(V4ejjY zF)`8{!BZ;85j>TEIgRvgAt84W*LoJCk6`_+dM%BF7Ot8yPq!PmKyXg6Be4 z8^dSdJKq;PPZRU`MC=8`&4nc9i=c4VEVV@qUY#D4uTBqYuTBr*Vy@;InqsRP9JxY2 z4&R9!>`f1`i=lO3-t*xuL4tzCl5EeD8}xf}mwMGCTLP-fDl|{-a)jv$lJndm`R@0b zzIVUx@`qpkex=fvvkT~p=7U|OfqgZBeGP$qErER<>C5$`9D{!4xB&{`n3_|VyFbj_ zjTK^JGopF(e*n$DDKsyy$gzvJAQ86`5i9XObL>>a@~$2>8bght<~rYNh{Wz^*YLI` zpzrCUHK5VzhT!~)1=kY8hU%0Bx4WgimqTZ)ByY^*w9=w27$ffncFV9c0n;7jbwYD_ z?M-bqVb`9JF*oMnA@^zlVTpv;8a`iKDaWijJWOZy!FfE*CrFYm2TzUA>ne?&(A zJ`u6|gl6B5O7#FK)d_!y;D4i1u?LkvZ^5Avm#;*62w8Yov7qw2k5teE^(aa6F?bZ> zew@Vp1PS&@coc6!dJ3A5uQGz1YK|terz?uoE07x4Gf)w}%CKj#Z>+a=(b%s*Qmw_c z`p;F+JCJ}~saelgcna))`OyoA!HfAAyre1j%f#&~1jnnS+^@kS5aGT2==BQa?rTK6 zp@$g?2Lx@$@ax_Z>;`O_JjG@Q605kYfK(f#%^y zr1+-_O|P&W;3Q{7LfsLwIe3(RiiKxC3o3p=Dt=W|{Fz<+R#D`)DpHw?DxuHfO4TQ1 z?zJh0l~gXG-j-JS^tOzDq#KROD~o(L8u1{w$aNB|qSCLum6b(wpHWq%5_5H>Qr$ph zuIkoQlIkv2sdQ@bN~Id(D#uXWCE!PyU04#~SW3YWNA?ASOIMQWE<@ccTd7nR2=?D+ zv|J@=?efIV3Pjq9l}c+t7LulwDm|?QFt{Mt%9UdCGZMIJWv-?I;W;@5rK!vCCJMO@ ztBEF8$0pZMO^#aLsPyZQwg5C9+o+{B{P9*}J6ls#F65_Z@zz?EG@Y$YVqXUy1^5#P z{D}nQBzV;0twuJvQVDx6zw5GYWlp?RhYSSsa4i^bg`lfV;4|=@A8$>mBu%L&VjGB? zM$&~QDBM+VL+0HICem&Oa^}flK0Jafoz4UYOxGPuvuMs6R-2&-;Lr=ITA-oWWF*Xs zsP^?oRIOeeNw@%`4at=e)l>vx8cDKE!~l&v2Ea3iKq0)l6JPUT0ELD}VcvT@+m+A( z-!X!w^)$rRC&V@N?vI!Ndnk%ag4OL#gITKGp9*timh$R-HNrV5leF*da_Cw|!s z%Wh5p4j17eXW1VgR9Q0t=i(FG;JHRDJqTW64`jK-wJ)@B$5j`aMy>fFREZEDm+-Rn zDfnrMm70PTGZ27l6+^L1GO=M#cZh8iOH|wfYfNl>x%DZ}Z z;LmsuZozIDY={td^{!u3RP;w^U^|kKb|TU343BbMfn>WYNpZJIH4OoJQi9!;-XI#C z_8uWL6H)F}D0>EUPNg<6-CeAE^AW5PCBZ-%_794HSwQmrppC^EJGqlgAIiqN+qWNz zXu!qzW7l%n3udx(cI`^q*A^#K=Mkz2LNy7GUHnnq@0${;snY*&eM}m07$6+*2VIr5 znbyI=j0*c_+NO5qRu+vh;x!O5l{C|4E0wOyC$0vGt0CfQ7#{VRwuvpMR7T(+zY*A7 zF(7B!J&=Jt^Ax4vOuH9!wJ8!`S!kx+yONC7K1A%k#La#r*8Q56GcPNP83zk~T9Qrg3;U zad-rAcqDOn6bb2QlE@)`i5vrk7LHEZv6VQWk3&X|SB%7oxd|73VM&68N|3*yvHL|6h-7+S>nnvDQNg8<@F?l;Y z%5*BBa3}G57d+}3*~0E72#)qca8G59M&64I+@}~AQzP$(t~Q6yz<0hzKA?&0K_d1c z;^tuz*&|T6t4;DhTe4%N~X5z@4YMk3l1`Gmt1xb&vC_ z?&Dq^NwfgsiAqg%pF|LzA}KZt{b=!gd9{p)soBZGUjXtZ8-hLq=?k%^m9+0IAZ<;% zpV6RtmY{l$pn9I5dV!?+Xl>y>$F4BD-lBhrsWQ=ec{pAwe^ihh=ZkVWCz=UDv^v3 z>2$-(kr2H~A+6SeyRS6qeofN-hNSxslJ2)8-R~-u zR-fS4>hCL+RvU|e82dp;>qmt9CxUyCD*vqb{2b-yWtxA%)_$edAo=DAhy7Nm_%Es= z{)?*=|0Pw5|I#YOe_55{zr0Fm_vfVD6;+;gLxK}}W0h6NUR4$JR$Y~=*T3j`UHB5C zfM}rxTUboBpp{s>sxS)Uu*wotWdfqGNLtC3tWqE?rGd0GfwT;Pv@C(N9D%faL6BBZ zAg#&CSp;I(iUNU^ke!wDFa$P#2g6lF3#(!as};g<^-(Zf1FINRWiiB%Mk^anK-FqM ztw}(wML?}hK&?YSO(+P|LI?*4oY*RpmlvPjlUxs>pR~Ch4@mqYz&!iLZ?WH5DFp*R7RJ zt5TNm6u%{GugY=V)C#__f4U5+jrdbfKriS~cJg7NShtnLiJ*DwUhWpE-Td!`)^|=Y{|1y2D9GY=eR*; zXEOW)AGU!E-qWdEPx*>)U@{%y103G>?Y#rss^g6JGc#%l(?EMF0`mB^|6SsEDBGN8 z8D@08naaSM*5pNrDQnOp(7Pct#I_$()|%I|gC^@R$$CeU^-d(~ok`ZakgU(}%X(KO z>;I+L?k3c(8&#=?)Q&Kpo2zyvmhC0At1J=edinZzcwvLs0UEO+^Nfjbf0{c_P#=S} z7|!>6J8CgiW)j{4%V`YEHxpS4FOX5^Ka=KAHx46vfz{Jf$A1u`sXJjO?TqlV1AOM@ zEn`_x&f9*Tdlj00#|r!yGNvaI5+m2*qG1-kp)-SQU?!tfpHhHKhUQ8}M-!A}m8-tMAakT>fG@OTfS zp%ePN9DxY}7{QO9aj8><$L)jk@l{WMl%G*)dItLON~YP?ECDBBkO8#I#56JsTT z`ky5I|M&EkQb?Lry62k4?gyy*6^gXe(tbT)PL%?jX@I)~c!mJa65#U*@WCqO!~!7_ z>>*_sVfR3R&e^a)YXOqGyCTb2 zz(y}$x9l{*)j}lk^gLXS84Z`JB5_b269#99M$W`W<d2h0Y!YopZ3(xq8 zoH(C2zW^QuG#3&y7gZH$C+aV*q7(I(K%t8Xqe}~7beY1avWQO0UoIHC0!h4*7}LvK zrT98$G_Z~>!W`LOZ0=)M3+}E#?ye>7{-WewH;MvXkM!SA^*h7s#wsjdE&1tEM> zK{(np|CV6-Z6x=dJS1Nj4N2G~^*`sPzALDH52^k;f&4#9)%!WR068Xk=j8`T>4$mv z7V@&SYc4;+3VGLCeoWf%2|NmQ`IOYZzRT| zY9+?vY9+>!Y9+?fYHd6U0hU!mQ);Hu#l_02(b82^L!Xt^O0IbYtExT1e?sHqokOa| zngLZ)dB-)?@GN&LJ%YO~~^^;4|eZ6I;5vNS#D#WXnKR z_$tGe#onuC=gSHJwEQmL-_WS9`+ppG8^$aab`Qhn1>HkSi0%s}Lls zk|0-uM)5r&gk`jpPVIl7vl#N43)_ zU%jVQ!MTVH^)0fMuk0_Xn#=N;8Wep@Vu|3(PK zbbOVE>fGTztD1)URx}Q`rs33CJ;rd~27Z*Ao@OH?+bT%n2!LR5yJ{NlbEuoS)oQo{ z!I(>d6I{S~S2Ydv?TMQmh%$I>s2u1Z4oT9E)!snYu-d5_6?kVPahK}c(G8@Jd4{Wi zd$Fr%ayM+UTQxaq`JQUOCiyQ|G_jdpYUY_D*xw=!^TXvcc4pX^=w>4^c%Mkm#&-Xv z+2nxQvOhRD7)tXPFg-sMwWjd+2i82{WvUzYbWei8;c|KFW24vV1N~Q52H%IhB*MrBi{I1XY^(>0Z5vggYcL04GA09yQhj%9I;%vU(V(* zL=+6a<6K8Im9a==`l^*S_mft{NGt5>QJm{Il#$N$JcK*(zaQ?Tf*Uk!3@13H!JQ_! z2MBJ5;ARB3tKgn>r35-tt(@SM#)6e)#Sog0!WblBj9qI;u`~~dt#{gJ7@Ju@%>*G& z^UsKm?Ov_$*aO;;XNdN!mbOVY#`c18H$opqkvcUrYRhbILT(?zb6JJD~#s!w{9RPZ-=G{`GnRcA8>aO-r45Q_{j}vXQ5gQl3$* z#`Kw_+Gmlfo?Si4lynX@DCeYe5!>?!+vEP4*s}8#R-g`J%qbUWcwI<%T|{_YOn6;F zcwMUSnsu$WCI`PR{41k!xftSCpcJoEQj8N?=T>`;rMxomDlB_7NqkxGe+%d*yJk$t zwTu6*#m4Zyzc}9V2Wvy9`|LWX2{-%2wfp?8Ct2J8k3v{ClCW+fvD{2zxlxMcZ%Qnq zl75T8aEehY3zeFVCi0iS{I{H>^uR?|Rw zjEH@lxOt*liS$V*+*LOivm@TIA#YQE5Z(l@Umq-|6802S2kyL$r%yv8vAIZ;xAF9L z|Hjj2ygHI-0mQRNs@!<`9D?vXNfBNP(-3NCGj;&#a*iB`_tfWK1J%J^P_hPC$Jk@~ zq6XAU1k}p})GGwkt0e2!NU*p21^YS_TKETOf1?`p|4oGAEd@oKczUkdvkP)2cpJ;U zL$Hl2_3q5ldT0vOhlc8mbSmN9sL;Z{X~5m~DQgf`&Ec9~L5CF$8JnkBAf13Uu-u~_ z`mI@DGQsA_&5VtqA)}X>sYomo&^iZW$z$sjx1Uf6Q#Ybjk=>Ek1<#%_dxC335~l0g z5u*o71gxQqmBJm8o|g&xCsI~MoHOT+IQaR4VAlD+KuZrd-3)Ks$!%dGeqm24+>{M% z;f{gavlr2UdNd*#A~&p6oj zkl`voNRX`zB9Z(1b_+xAZ zl`p6XP`&^*L*-66Y_R~MvpBLkj#w>Nc!@w^{aO-hFGaQCmYF{?o3W(>3bJJaq;kvh z=kR#mxW8>9ziqZ$z*EBIMo~hWEgw+OuMkjLxFTV^5@EbDVZ2J9kQS~Q@U$?Wzyi#( z)dcdZBX(;9a`ke_z^Hm@V3qL%_ll$HrM)4m4J?Xct{Ko3b1kT&p|duB>{`R)DVU?7 zK?&zN0aDZn1mZ*jaT0+znLoxRDMej3K#H2?fBwHe^B?tRSe?+uAgWe~RO|oC;y*8o zDS;d_D_3LdQ8*1G9GLEMJWBfPY1{ z&8rD3vQx=uObaNJ+8)SVkzFr9E3)g8f!Kfy#D?&gyCQq1G#4H4qg;{Q2w|D7V2L9H zg2{~o|2rDEI=!=n-e!%5M?t0%Kn2$BuO*jQJoY}Xl)t5fi(+> z+)5GYnRy_7v^CihNCp{fYtcd{wy=$A!TWi3ps3)aye*dBj>;S8^o<>+usMX?+yG6y zT^>rZKHDD3;qUOt@arPHR>mEO*{PwB8I6kf%E)H$ zXur+dWljJ^!jKL(Pl^Qs->xNc8ey4$5=0gSQ7KEX`2lI2nnEpXkR&n`P&zqGB3M8o z*qubM2S~3B&E%fY9NYjS+ZX$)qinB$vQdxu#2h2w zJ{B=KE|9Bo2LwDjEX~F7Snvb_Z)M$FsW+4G{IstPAe~dA+Fg9lf$c~JYgP!sk>?{G&*~t4j#Cw6F=laK+)(nK!@)_Y(;=|Q9!B9#e~i!gwCae&Smh3Yadl|?Zaf3 z2b3y3>4)nI#e!V?xDr{oDv+x_1s6ZAhQ1o%GjN{2_;F2uJe6yS+Utm&>q#SSfWlo@ zm_cI>B3VvS{^#y~AEVoCX&Tp9IAP0^Eg{bcn{;jlcll>n*?B z1Z>2vKv=xxmuLLTFE@L2By4g)4#ASkFSno=ZY52+u}Caom~>BumP?};!Ikd@oS88M zK8C~x%OF06#HY@v-9$tSxB{Z@Pw*pTcnBE^Ay{S=U9D$$5E%+0Uo29~Zc{pcrGHH2 zt^wVy>B}9YFL#o@+(r6wH|hL6q~Fi@_4{5ZwD7+j!21GdweClyct9ydoPfP0kh2i= zAeMcI6sVf}3$Rws<2RAC6$|aMC)`A0rZA8z6i8x3?72BA{45x9%HyGUD4+Ml=k{TF z=LT%qoj56w&SnO(8IEwu=(kdEFs#n7GhU1>0_xw1Sxq;9jmpGv5VCo&SCjuHy7Wbm zJ#vGyj7VYovFtc8EP_=Ohe$vB^4vxUmy{0jF7wlL?)IcB;sbR&^Eh?se| z88$2rta*8IKv`~!hI4X27|7HI=*OP=}|IC zkC91woJ`UaWRjjFlk}Y5Bs~>SzVk;#|Ch!jds>*WXV5e~OQz}n7!1!T-Fq;gr^22` zTwWkt#^t8Mdf1D;x?^O*UJ4ZHnXs1wS|;ojsH$bcDk-SD?fZ0m0)30UDbhQa2yr z*O&+cf_;gwj{}ql`-HgplqmZwpmH@J5J}SK@TfvA53DZ&sL)>`jbAAmJ)aq9A1x1d zdy#le(SPr>#J(2Xe}mlrLvjDVfwgY~IYU$?9KJ(dzb9U&K*Hglo1fVaq`^N1D7)|z z=qfBx<~GNEh6uGxvKx2uKNBoWhGXrQdPpM7Uk?(&t2`S22%9Q1Cp5=Fb8V%d_xV? z(EwSDf9_gRw5Y8^FJ425hjBFus3i!fB?+jd;Bk7fmbF~EhO!MYNFn@(d@r_)fPY!U zayi2CKT5>%H94b1o_1aVsajE23L&DEYAC0%a*fi^RS5W13Ha3r_|@T2oOWIVnviFf zjUw+j=;&T2GeGe2@N*Lz4=ur08CHwLU_+1{9_#S)=*`Eq2G^{iv(VZ=TC2uWR{vS( zwGpLt@==;lL(|$s!ebHvHn~RW^}6r~M0jVR>uL&(=Aa_Ne-=7~L`)$CYA71*Ec6(j zJ*)R=!WeEzLygZZY2+XEqtQ*!j&?K}g{OHV&0cwVIIx9)XeD^sYH}TtsWs$~Oe09! zYm|zu2alsUBnWMO8Frg_*fur}IB>5Xtw|6>6h+fwvD3;W+n_5bHI zzI9De!8yAVd)tP3+p#5?%_dMbof6&!aTQ*2w;UpFIpO~21&Qdj=ZWl^dX#A&ZXoeji&2We%Ml89+ zQU)IN6BAQewno{(xBVH6`87F<27}1JP@ZBGTr?Plu4ck#;5&cOU_lKT(cOvIJ&2n< zNuqlRenGCKcC?x8T|=4pec-p)O4yf|iGRz?UylJr#QfPsaN#-OoVKS5MnGn)acXy}m?(Xj1TX%PNeS58a&i?kC5z@l#zxTfT zd+*tYgE){PU;f{naZqwyK^vNm_^DU0Xy7?6@6O^}>X>kG zjs85A)#~MFBMN8bL9ZkE=q zzk9NXTaH|3}U zm7RO3=S-Y6X-cDh2kf#33fq}~X`#dPX|~1{o<35Ag)LwAXx$&b^93TgYIn0UOQOY& z>w7II-xhKAW18yFS<0C7cAseO2)5`gB(iu@XE?$aa>t$BoqlmcR^pB6`5O)5Zvyc* zgZNuO{H-AVHW2@5GV!-_i_H8Q4us+k#mAkD@m;`J7r0x?dtGny_39q3aW87{Su-Xh z;=ZJ+Szev)r&jRl^g!<%ex{pd{SKEseat08G)0F;W)8EpOw-8|2K=JzKOIQh2l z7kcB>=|!mX5=48sx6XQr4@ag~=#gnAte6b(YH#NGH5T!8EutGdNc2qexowo!{%xa6 zyrCq0lO=siOZs<<@pf;I-8=7G@336&LN2~tsb?-hya$7LpIUHUs6OcJI9+=>my?)>?T;Q`gSZMzT(x#$nw&jYDpp#-TSo>g85yBUoOZ_JCg|2bcUj zPo7%9Dir2-PDU%;I*wWjs=j$f zGP)kav_6=g%SlZv?zI2HqC%?gyLc5BvBg**-R*Ld*Z%3J%EQQMf6Cx|s&G4T`Uq=SeRIa@j#3 z;8gjaIWcnymAeB)efS>AJ<|r!xcr6gK##RJ1zI|z&73ahHU}cK$E3eUh5pXhLwtH@ zmsxg`&4=VTN7wUK9dkPhpCi&CeMZn1jt(Ab#bhDT6_!AR6OJ4Sb#k}_%?{=UyJb`f zlLXzg*elMLuvyMG%Rp14+r1ez9vea*B!@_2U$991DHw?iN!r?~S1vFkOq7;giYJ38 z3FfyN;=HkkFFMM_$5HwYxkP;ubw0$X6SU&7mIR;u(-CN1Ot%oZfJxOzeaCRvsWE&oqrxWNma{lX$L{zK6 zRKo*gI0nf754w-gRyL3whMVJ$WH3enjNBZ3iLM+@Vv9U&f1?fi8w2~Rh5c;_``Zfk zH#ScvXVkZ2ds}P&N$&`5hhm)KXd4!5ycWw1wj=XW@_M`g(%2UhR09*afl1Iy7nqy@ zi78xTDr(TjbgwHB+X9a|1CQ;1$M(Qu8t|A7JZ7ZDW2VM~FSQ7DpjR9hk&I6DQD zDVabyosz77wDYT1n$2O&8i4&jU-BJ2W@IG0b6J~t&?Ya(n3Aojt`$4!%ISQ*k?Zc9 zhg^3)3~K>BD$834%i9Guwul~$DcPE8(U_;hz;DT6AfOd+Qr#w2pgG0R(x$pWSuE7Q zjg(H!bL~8gkrqhW3ROaRdW?jraKoIiFVIetu~AyVPpNKmYuG(p$ro$kRJJq93;m)oXu^tDt? z2q-;xIh9{@Xwzv*V>(94yQ=}c0Q7M{p8)ioFr6jZP7FMh=3P{3`QM@C(meJH-Hh&T z8r?Q%AIM(s)xhrmgLXY4^C596b~;_vRTf?LG$Oe$c8eey*vJo?8k$kUx;A?`qQ= ziTO=NO3YJ%{Vf(*j<=Zis%XD>KwHF3X)MBsUk@69J_JA?2B41s&_`hrkAeQRJ@h|L zrIxR1jh@Kk!Sp1f_LN4g4VvDU=ZRHMbJ=Hra5KGv(tD!(|Lt^XY9zeaj&$pfli@UR zjMs!VHqxILDOsd<%9Zbx^5u_CLkTH4oKM(X@0QxTi z{g;6Lx*qgj&eK6{;}xqbUQw{V%22%qsCrWOb*<*pd8UtlgByEOH>QK(TX}FlZ$rm- z=uv_2Emv@{+>j@LI8^uAFXIn%_S1VW(^7Yh>5S*LJ#YzJ@+GUxVD69?dX0 zT;%2Jk(%cjsrmVyFj>GF6y|%ePXFyg77Gn%BdybX_{fKq6hqV!=u(=mt)z?!H+0b& z8uxuredLfKGT`e9M~Bz=+5^q<#oYGU@_&7aa62uzX%==MAz%D_QM=2RpcA7wys9U9 zUu=#=I@_Z@nkI|;E8QB7 z_RjZ_d?UE7$55^hW7t!LqT#%%#C?-evxu}u&6-PUT8^52YqET>NKXnxtfwqPcikt{ z6+JSBsV92VQhM@qV4PRtI(n*!6i3f~Vgqe{M0B>#C*aew`9Ll^2z=5SMvhORKu3oijVCQIQtGH9(dk1` zV@~ZEhK7tSkL;)j8`n z-9r!)ypcWJ-a#9?=x6tp9pcEYhH+O@rpUf(t?fGFiCjAvPPoZNdp9Q^jn2hUbOIR; zTr-w=b8#tSFxKUs03Q?GOhq85=I>f!bcq$oK&Q#O>l9i=th2+K&%->puvQGtYMSQP z5yLb$hiMLlY5HKAewbzzOtX*2G>7Hugk^BfpCDCKD>JHL(-;oZ_;am{(5es2HzV^% zZgv!!U5_JkCPNZiHR)PT}jJON#>1_b@#*c=V*cMpT8CY!xthNVM z(}2}qLQiz=az4WWvRk)&CYRAnKKbb6CO#!1eb@uww=W z=dwuiAkx~3LGoH+Cs4SvLE(H*xBwI`1ckeR!bNE*Y}6FeoSW=S1QbF|EKYL@hjTM= zSWF0}cvlfr&Dq>s3$)8nyfp(lA+8@r{oEWik)>R>Xahit4S*s5s2u=B0ZbRo(fXEbSmJcrXBr%g$!lOA|w_c)(e( z!#oph!j2~b&K)*b2M}(y;nvi7L%C|<4wYLHh;-VPzK~FRGWBhPO6=Nci*9j9Rx*ry z=Fof$&BFld;XwU}e9gs?fchvvy}k$Pqczn3SK1$=XgikKI8L+C22>8x%sHliJeNHI z%=x73_1n&zYwb9GcHQ_1(hrnrIYdLs19lUJh;pGg?%b(ZnOoixKjMCZp-hptuhSQmgIEM?K3pkVKB1Y7T z^Rl94%tf5fjVL5801_7hiHm^5#X#Z`dNk)EMuNU{i+I-FRbzGPPrR{4Y#r64^7r23c+la*8*qs{K)H5}3 zBQ-_U9buGqH*rm8YT#zp>=tmNHi^}YNZurNt0w63Gz1xM>$e&D-46ZkfPQyEzq>%t z-C$!=4;%MTspXkvyEmWB@jlk%eyvFxWWG7yW04PV*$1I@vPF)p6%S=q*s#cl^I?&X zK+8wzQNi#SV0at~KS7VCMUE6t0)v4b44%sOSme{J!82NetQPsKEEd|RjkHd+$ma~k z{smE=hb}LGu@|Xu!(K_tB?27*>6Lv%iLX5t^tJ95?(kLnhWlzp`KkjnZ`P$U72nbh zXXQkz47u(B;6A$l(-(;I`id5rs|0m4j{CYoc2t(9ZE^u0&B7_4{t`(Hy6fIhmO?ZOd8q=!YPMUtANXQ!d#T(inpH5?t#t3}V z;PWl;`8N1`2YkK@gM1IxH^gIo?^7urfd};jlD`R&5Au23f5^0b^be)&V@=y@`JVjn z6Bhha2)?rve7uzicc@zkw~NJXYl;*k7O%BBIuo*Cbr(Q_giX%z6J0UR^W${#3hfIC z`f26;Q2tQG8B(qIEUN_>Y2fFE1$_Yv`VtoO6)fm$SkO1HprIZM`c_-ezgfxelu>-o z*#4lgZG-ZkXdaww??*2C6L?r4MchOi@}h9UZeJ9RHb**xPRhD~&LA3)o2g7YO%V4t zE^Dn?>SJ+f8JT}bfAMoxCXD3pmwZohNH4j{--=(Usy93Q4IKSWkBY=UKw?gTrmI(h zrmMqW-Ttbwk|lYn;?m+w*X^KNRM%{BWLgr zaz^-IIu{H#P=uuU(b~*hS~#Y*D3;BSDSNHN%li7Ec45L2RwA&W`M{z_TW zGDw=7{f(*>QvTuPNd+UMg^}*@}^k`;(qr`?FdbEe=jS4*3-^Q$g zl`>k=W`F%;u~5G@(mFN!>u;FlCJ=Q1blDVUxfvC1*gNcN>x?IS&Z1^JXx=*-rmK(hIIRC)sa3wOyzy*oId(KO8Fl;5d%pi!plwn z29aQ)T|)ib^lwW~`Zw6E;lQA99a3PVf15L=Ltzz89x+OWb<)?;`kEIL$p7EoZMphd zq%RqHU0ppd5mzY$g)wJq){L0N3M=QS74EMR2%Jnvi3Gaw3!k<~;yz3I=Qjwg0-?h| zXf+6}fkh67`EBVjzY$bw`9BVlkp=8`Mlo+&Xx`cY)#e4B;4zxZjseHK4aZs76RtBBp4;3F(My1)}|r!XEquqn+R}+F1pjaJvI*Fk5SoHQd(AVj-)Iv`!7TbBrO@08w{@ zE^{%&=!EA%4f9mYwA(up-M$XGxWbtf=?X;o1fV5hyUQ2qlt1vVcB?Pg10nNo$pq1G*pl+C@>=FLWXM> z5Zl zSm24Vi&>-yMEb>be_b-SZ`P+f2dqX)>zg`T^?`r#Ij)cQt*IWi#Tb3fcdS|ZHP#__ z>dtkuEOivStliRL3rY}V`*xJX3;L}(KIPq_dpV@kEwqDmP*Zn?D+y*!m?~dJ1}|NnVgx^}4Y>976c&YkAORCXTk;D9=J*!z7@i%Ii zWejH70khl{W+`BnahT;)k69+TNw&+fOf-m2WlKw#xGoTvxyDkh(qg9HJ=mq2o7fFa zY$luN8O>t%0u976YQQ_0r7qS zbAJX?>*nBiK!H2FO;HY1z#YU|AFQ?3UxXQ(v?sb8!c`6hP;|<5Hh{!oB*6o{aHS@ft* zr#_pSa1NE0k2%Q>NSwp;sI#a?h;ykP{V5^N(){|&3=~6`ZIz*n0YmNnNU-fYL ziWzWjMx^O`Stbw_-&3cAi2J(u1Isy(P}#tJU7YE8UHs9l^wTToIL=o(NkLttYD{Y9%#hAfnGjoCAQ4Yf&uv&Nk@=XIh$p8 zU0E)_YIb(;jU?)TvVaIQC+IxMKqMhOPHQO3))l%#$k`iL?YHK{$p5geLy`I=FBBX~ zhc8KZ=_1F77Alt@HN?`Jb(B#2E43Hq@6&-+nGX1^@ewIzG(fFJx`)#Iny?4bT%T0k zM}h>F1i}$+ls{4t3al;zbkAAC{WZh=BS%?Pxg(^TtgiO82HM*Lez9(0HoG+59CHg{ zm%R(MUFH>PyUd4O7QikGVV662?6QcPWW#LB`8zoleUw=iv#FK9)c$5MN;UXo^vEd6 zSgvx&wSuiM6@{9nN`t1pplLnOv_5Fs05ok_sFMnk#r-O%Jx7+UFdHi{Ef%_;7TOI? zWrZ2ii03%5`Y#+){S_daFdzfK;(x8en|kcnNV+y-5C#H-iwknTXe0f0=S0T`?UChFiMjUz|<9Y6?FPb-sF23P!1y z`c>@)4tA;~GImgmp^gXzH_@tP+14c_)^`)F`JO~;OSh7vp8{;FLL<={%V2E{x)-X9 zV~k7>cy3s4X;rpMR~fS+yeNxA9qLRgO9!kz-m)pn#KX~qx4A+SzZj?OhnUKeS#4v$ zKOXQ;0Q?gH|0LMYWEjhQkFiXlQp^7yJ*O73SJ{>kuG0v&LI1IZo>Xc(F1tP0SR|#a zOYjkjv3NX8k|p?rNS^Gm-L*3El}ar{w7LS_YC?=&vCM@tx#6hvB^@#|BqzZW`Ob04 z)3WkmWE9g4K4yTAnc!m<_}Bq_%myC|J$%$_KK>3(=O{)R808(o2oTuL%g9_VI}eQ1 zbH-s~K@w&jc`>52nHK4#qX~5v6)7MsfoedV|gM|fP zVIf%91uQHA3ymHY8Z`_5F6{ye`6foQ8OTHHxf*$A31*PX+CZMZ8`Rs0nLM*QB}}1_ zPb`&xtBWT6Nwj1I(^yQ|%FU-=Oc|o8-o=z*z}!ZUiigGEAp*qPfq1hA@u)`pPiPfW zAa*b?yJ}$E_!jiquHb@kAV~Y@ByA$mQ(NmaY;6g2>;ec&VQbycd^czw_GrGl*4&k5 znNn*HmUd6r2BZ{T+t`cC?hVao3VeJpIH$Wqy72T1OW6~MeR^sc`)09>{nA;+{s83w zSjK@s?I7TDFz{LI!RHW-PmgsvQ~`JxgK~I^UF_wxizB$;kwEW{96q~`gBc~GU35)# z*HD>=+U_yK#;B$*f8l6uV`G(_Xs%*es>l&kVfl4q<51}{!p`v*d~7f`l(A|cNGFiV zh}$V0brpT)QqAy9-E^Eeum29(L3aCL=XI^I(ZPrMi^tUZGrd&2Q>`d#35$5bRYNTm zr&Tk_YeQ?rQ9T_KM;l|}7_fUR=syl);&^a=0yvL(I6sk_WYVku3KilcWdSEMv8RC8 zzt-BR8j2$d&9~gsxcTL1ej|R%&1MGT^g<2X83u4?0=TmP+}Qx`8~}H2p?=dPc^u5n z)8mBRwKK~g&R5u6z`|dcGCEEx%<#6mVGbQmmBot1MXKeCx#dd$%Zh7WngQXFuOPTTU6?tzKSNc$!Tnh<`y4$wUjsq?^C0m|j;%M8vdDW>p5p&Q_xIhAiPVD#vIP@Vd6dDvb%RPp|%5O4(9{b;KLME)6U_1B#VXW+DPlvIh>CRF;qW+ zsGmZY&k8lopHtz6%~N(H1eSzb)rqLIP=*)1Mq7RIr86YHpxUIGJ2CSmcQ}L8t8*u2 z_Vi55eC1YhgjOhg%{85gnQs_@Z^0p5gInz%J}h;yJjA1Pu-2Ncosb&J)CvTA}W)7TRxX90Jq7$t-4keX2sa>ZAC@! zZG8Z2F+D2eOMrYSFfOA<)3;TNa=^Zy2lk30k8i7F4f<*gvii35WUo2DZNRN;mQWE!kdD!O_VRFwkFZnXJea?BaB)fGEQu!nIz1zc&>p45Q6~3U;r@$ zKx_^shk~{PJ+%3#)bc+gt-pwkxr((NrnPN@76Xbrj;fl=)&Ln=PqY(FRSwUpy5T5B z7^;ti>Z73g7EpaOR38J?5B8{Dt5w(HY^ikHisc;(-5_SQSGTRX>^SH)Pc~K`jy6+n zuI?Kf?jI&!MI+tLdY~GfQjgkQw(wh1WN1)(Todyn)on=j} zn4T3k!&%NKg0q|nux8PtLURY8IUBgu)1&DuYs4Htd4vbbh9Zx%+>teyt2M~#Eb08k z(9|~4I@MY3WDvhIM4b;^7J&GLRJdU?x{y2UqpP;*ZI^Fwk?%XsM4Z||6As74E>w}U za=qpvsvepYn(BJZqdi`;(XHVKtF#Xk8D6uAHE#xYLzN$@u_gxSgB6|Ex$T@ev#eyP z)c4=Iy83YJiaEzWjlaX#Bp4fo8~mzLHdeB6EF$+I!coQyp6>iW~2Po>WZ}yGGiG-6E)7g z%XRhRXVo>*2SMApM8^H0uD(%@>T18(H7nMJ{}Be(abTSQ)}6q539#-0*2j9VUdl}} z*b`Tc-lAJ^up8sLJ8)f9?Jv`C#h6QXiT57d;hyM_)*~meAofbCnq@)v-qZ>fbnjD? zW88kdFV*$jejSbnI>KVVqU43$`%^voRzbI49{_F+1Y-vkc~^BGT!dBKhk)fn!RKN0 z=v~!)th=iFaQfA`5bg-ZBb7IYs6eU680 zClu*vDk8+4rKU%=G6IX)5GNI>iDwq^6fL6brAc%>N#(iznnIB|q{OMJt<$)z<+`oZ zf~OayH=Z-N=9#G3+b|wEQpH(G6|q!UOcE*m#i2tkofnLRNUF zh`UzgJPe>8p}(&~{jz~R%5?%F&=hVKj}>XNIKdMs9%p@Kt*Pc(S;Z#-94+Rra}JXA z-15RJDBLT{np?wu(b8Nqs(RF-kR1rp8p*NNu*OF5lm`5+RGix8tf^snx(Md?Op!Lf zXMxCbMcTmr1-+lwy3I(|>;)?0WCJgvf3r zMiS&oqBo0lR9?pbR=icjX8Se^`3}%eD)g?Fn3TasiubtI`?{9iy7B@4NeT8L#Qms9 z+ttU==aZrwW9!PNMcBIX85Q~zihW+B2Q&%dsP+Xt>JJuMTa>bueas3?nu9Mk_e=gGY@JkWw;aA}I z8vy>jNZZ37fGwv_I@o&kabc^FB4iLitk#G1UA+$putp!R1Nt!)H(R+!XIQVv71z=g z=WWo74Xd$nuH9tShZD9nOCJ?s`L?#ENDQkc=>wzP(<11n@zGecyFJz!&mG^~Y{zL$ zeJ~uL>k^w{ONUxGc(<`p7qtRzQT|yL(&0x!PZ1R2cxlZ z=Jt(^ezA6+oSu2Db^5>@*6pLsA-9h!W!io6q9biw)jNz*{MJD+6!k;H^UQHvL4`tylKZZhdv-u|;1sV%K8=*9U>_?;B`2 ziDP)C4Y|Tbs4#^+)2g6bY}`j{ZyDP6gZBNQ{U*?U0JPtth+)9I z+Q7U9m=6c$BY^oxU_L4>=38jYrGLut_AEv#ZO5>nwJ8YtGa)#J(D7!M{U7)(qA6O+KiWH2!WOiWG7#I~9VvVwHIi#mnN zb}aDrDQt|(#D;v#8Ja7msp`|Y`V8pn{5&%QKC`&|4k*7Vl3Pce*E7j+-DhpDOo0SPUTD+lxhghhZ*oB)|1T>5yjTsOO zaGfU9QP-8Y(MU7{rl0|n4VYR0Q!8K!0j6+TnA$W46WmNZ8D$lmMFMDb8fYy6T3tYEDbVT$TDzr1Yj=$njfk1s zi)BiuJy@7MQ;-swkdptGH#xuFhs*Da^06EzPn*~oPsG|S-e()< zC8>P2nhGy;{SYmSYHS=ata{68ncgHq!r8z|e;L`>$XmqJ5p60rt5^HZCaDXhWR<4Q zL?RaT=ZgI_B`Zi-_cy>l0N@`8@DBp`2Lt>=`eaC152Z3r%6b?>aX6re{_RkRBQz33 zOqL|@NCSzZfW*;2;us)tERZ-(BQgCnHwiqxPf8Maf-=Js8IqF#iTnG>TF%4zn1kpP zu5czdat0JR6N;P#Mb7S{#}kR*sB#WHvL-aup46>4SLt*f zi+H{k(H&Z+^vN)^%5&5$=c$y73sjRAa+4Q9>nv3+&Vbw{+{UG7V_inhu_Xr<6+{)E%ONWOXQQ~&safgA&oxtNR;BhzbxCeOLn--7zQt%il?pK;Tz#=`Eg2%0y z@F~wE~ne&1Ce-4yxj+fjJ*R4 z-vx&6^~n%@-sirYFXSJvtRE(;T5sDH_wo^_{MeB26G-?esQe6Kd=4?b0F|$S$}csQ zN&S7L@c){H`bG=Y_K}AC1CvMk{EiRU-*T<*OxTs^-y5R;0MUPh=s!X9pCS4$X+{5) zTXRk|`;GhjJ+;q2_)n_IoMPQkFM3pxtX8ZgS-n{IxduI|Q_a>arY87wG72lRr%c?^ zlK-)2w$nY%Y@}GLn0if!wdMZ?9BIFWwChlN3|8`CWa}1_l)1$zg7+>4Sa}dJA378i zYp@FGktA>rBP%M_kQqYs(Ly+fkvYd27PAl~sX~;}pY(BiWu)Rj=M29@EEb9T!*-&@ z9}}%rp+tM6%9#T8(?3Kx#H)bNl>ojkv|6v&$u49IVtqr84XDd?coS?i5D^>7e;$&m z*GAM*Sf#WZvo4m_g$>)KOZ20XO1J(7z?(pn0g!c5Xs}tawv2&*mT+@K7(|bHAnE=F z7xO?G!a{9s0?ZANuzD0NUDNo-Jxq{|%rEI+gQ47>4@xGlg&JNf{3K7Zw@beks;U?R zWEga>22V8rXERPB;gU2l)>Q>NYEO^|S3zML9!D&Am0F%z zw&}%evNKqdnOc)J$UKqBG?wPg;<7tH>tu5rQ7dL=RoF1c`eK;l9BA1@aNi3&Fi zQ%m#I45&|SVvKat(bw*QD|F_DI(&l;GmeX9YJ&80Z8t~_g@U2!uI*mrv0dA(;fSqp zXel;qx0NvnfyGhEK1MjJ-IRQmD<36&`uw4oaL$@w`NoN`=6ik`z6}F!GvHbbxFUe7 z9dJd#cMRlSj#}RJq@#`HL81_ocOA?DpXE`fcpI&4Nv19Sw5r%~<}i z{9pMjTJ6MGb*GG4o!i)`sx>xp|Lzs(&X$O1XM2+^a=Sv|<`5mjMqh9f>Q3F5pp{CF z{7&(XfC#jTKu3sI7N$K^+HcKaKLdkq9%mq;&#$FpyK^(D?$R{Biq%^< zze=^Z(1cIn8nx{pGaKV`<@Bi=YEzCx!ntiL*V)t8L04w;s^%5~$vK+CJ*imjy;ZyE zD9@quy1VQq2L^xc6y7D+9+14nJB2;e;!`~Iy*4$!&dab8szj#{meSW_U9 z>k)7#SBJ*NnG90gk-5IReOfrWm_BN%Z;RvUuQR0>A{?}H=`&Sbv?V5gc6%j-aCveU z9k`Tqk4fCP--Mc!V&`(#e1(y)y99j=lUO#{IB$3k?WG|FdDofxa!Gox-XXRk0h=_yb-_4bS zhZN^v<=~;f^e`ZOI8{knIe0`dRt_Esc8&rMN7JKs<=`dmoaQm~tFv19u z0-m7-baM|9Jk!cS`Z}S)g*a2Sau&C8wr<5Na!#?wRGjy|bGgoWs6zqsuf-p6K2W`Y z8q{x%7Z$Hv!xsVLi;K0*TtbhExJyCYWgy{lkdOcgS7;JeLZT}b;#V)KcjGZmL+`-IHf82FRkT+nW!9|!{=N4*(6asucUZ^rFaoi{MGhe@)F{B$CtT- zSI|LqHkXkpMHR0W>v8p3vFR9JFaFDIzEP})-*N4U4q5QJRzv&L?oA*LXe59&>%+)^u+Ro3Pdf9Q(oX@!Y=P2(@bG}Hbm?h2m zvN$Qt`Ks7VbH1j!Y0{i;ij&ivZ;OpI=R45zJ?QzN*qi43Sd291CouLi82g1DGp0Ge z(yvaM^Bd#wyT+r9^>-%0i{a06N_0QHN_3h-5+|oQtCb+lS-nK-vqp)QZOsyGO+b1%YKH+91p6QCUR= ztfCSO_XWd-zgSN*Y{;>`0(b*fcf%Bt2?nnda3&8o;wl>hAvyyqGc>}Y?jPudi-K4* z?>u6^64TZ8r#c1*o5;t8wVXq829)3v-ll+LGe9yBkPMQKps~rIvM}n78X-#zt zZK|{;BYpp3w1RRB3tgLHx_;Ai&HRP;X7Mt-EmaF!aSLOiHcD)r0jY6ZWg9P2nWlEc zcpx>wKx!h8ngpaK1F0!MYHC`fwoO7RegC3P>A4*Xy?qK&<1!&dXSA%6S*ewrloHdF z0@GQ689@DjRVCocPMe9DUPE!xomnjM4iLEy(j82)iP=fjvm`zBB}qxooDwtXX`oh& zq=y#Y=uX6rCCRDJ+!7=8nFpKO36{8Xi8u9`UxL(U0jzf+>~t4;%$WKtqFt+1(-s#HV7H5ut9 z(v9N>6HH3_;|Dvb5%2MXOG>m`=%Pnw4jyB(8{=%Z5daBqy(E;p_*)*&l{;01W3q7|ucT zXf6jBDGr7$-R(W6y2SN2&T@c5S%bq;R86}a;BZ+i)X_#-r!EILq6G2hNQinAbUC_2 z4~=7}aD%T0C-tZS=4);Zi({!iDd(;QIF4Egy%_3n*8<$oAfp7v#>Z}Dg zkpVaf6b{efPw69ja`KJyb~|xu-8gZwW|}a~vJl`D1E^C0)M)@}Ie%N5>NFostG!>mZw3dqfSFrMym|C(CCH<12b*_*w>#<4n@2z3 z=FxZ2uTCC)H{)@S#-ok(R~p`HSj~Ot=l&9%N0Y?KdGrG%$fF;GJ`X{*hf8!GO=LJS zJwlIq3Q;m49xY+Jc#H*nTnp&BWfDA722H1EuVCmrp;~{ETYpNo-jk|Nmn55(k+VL- z%{`0e>T)vYDIAUcLoA;)fAZMblc&#|GkH-%{p8uTo9<4Is&>3I@0bYh#@4;Z&}j?B zbGqkrPbNRNv2mq7ZBcsGe z0PaZ-a35<+a*)?_9dBGgM2}#(zdZ@{^+G+bb z#gITWpyovR^L1F=xEin`vDjiuO%n@eCYd(Vvb1#G0M7@shg(Alt2MlYZW?QjblQHg zR%tezjU;64QsBH!sm6KTQjK$Nsm8f?sm3|4RO9@d2j_f^^WUa!f#Rl+@h$>4fPtt; z@C>z8`G z(FUx+hFXKH-e@CPEHtf+v`+O#8yiMoLDYWGr9X^d6Dr(bhkc?mYM%Kl--sj`aXEN= zu@;}c)63T`0~~#+>LznBL|Ybdn8gcjZV)pR#P~prAH-C_vWCHo zUiO$#HI-Waf1!0vDG$=&jQ$9XejCsjRO)e{Bf0D-F!hC$S*;lnTEu4QN5b($vZw(e zMNQbv{25Ih6xz(EJ;v3Cgd(wU;LBD4%7omM>AKap~crJi(h# z_YcRVbK4@TwHUs9v|%k{U@f(ouk7igIEw%^4Z+Uki zm3qR;bk<;o)*x$GnJJ5fCbW^(sbOW7VUIgN)Y;Ib9`-ng3O8(pDYxX%5^z&ons_7D zeDTguOuiEO!f~JTaZfZ*bEK;qEp}uHDoEc6Zoqig6ENnwl^iV;Eb~f@fUy%pvNK4X zpj_u@V;U>jeFoemhuX;MmAGV$j=1B*d~FKT)0l!02NoDeE(DUh0Leu_vJs{b0PpX5 zcyFRo%U7W?&80k8f{c}|v1)^oJC%CedkdFs1+Mq1=_S7YgVt>Z)n4}GH9*#qfK2-0 z9*DRBg@S=v zfhL22k~*Bor8k*qEJ1HGEu9e=X97!NVY&}45ce!jSR9r$B&^0Yn`-#*A_ev8BLdO5 zjGIx?Ft2^T4nKw=qjX32%UtE4JH*8m0*xv~oqj}{2E@?SK82|-8Z(TuFH zm&lmxx2D=r$rg(niR3mmI?mJYwCEo~$LZkD9WnJcXM>abXZf;Be>HF8B{+EfQq-pF zmS`c9Oaz+wzIg+V&Um0H90@17)v6^~D>o473UqVW4U(RmSm-ysxZ`Ld;r4JsCKo|v zhgML;Iyy*SnFP2~%Y1d5yCWwU4zxyN&MI;DCL(^h4Dy1H_CSJi*w$R{AW&`jMQ2Zk z?h<3@c46o)#nA1>(A^C~cXtfkk3BR2TH;7m{V1+}G&FU7J|+V)$8!1OP`)?` z8P^Sp;{nSF1}rB6mXiR>$$;e)z;bF@SWeTh6d16me#LU7)afkb87Y_?n+X%Fc05zH za2B_4Hq=Ckb21=vE>}4ZRr(|$<3s{+K7hHv0Ompfa}j{K7{FWtU@lDy%w-ywd;=Kn zR$Q*Mx`IW#G6k1&GvV^8Z0Wx`c3q`_xtf8w2HgGED}JrVifv?q*D)B^1B?^Zq_ob4 zo&1+l*mgPYtn~3D<}6w63P&PpmLeR@hgyIA}Eu9 zppWi$^GEGOl~b=Od9MH+1hq+;Cb>mAOCcVLbw+}@O*92Yi=k=0ZIIpSw`zus7(G}# zrUAY?4Q|HKppP4t`2=8j61Y7D%X}JOJ)^<$9M1MEm2t-MbBxr#{?SN1uaSBr4N}G! ze!)QMMIiMOka`(Ny#l0OO)@J5(ret7v(xEyM(GWp6#M&85^t7jMc*PxoLy6I%V$1i zJ5ycp4pqF7#GaX>_faK@wi1$wcLC{p0Q&t>J(NEH6CVQek4klpLN@5G51>bOnOQaZ zq?Dc3r%cOdnikg)5nUN}WPQ$6z5tW;ImV8xRmYe3k~A^5a!(sAaT^l^D;R@6E5v_c z_XObDuK9KNmATCBP^Acj6;T%e0DRW$?`9WzNJv+KQrrYO!0Mw(@Q{ zx#>#4*cafgSEhZ$`apjJ;Jjg(_Q_;%4$>RZBRh)Bx@=s=?!jUn`e`0qhfMrraLE0+ z$|j(0)+%wx$sCCRq=V^=SwF8g-n7j0#+y+Q1IdB%v7yZM#?%2^@t`ue;=zD<2w>hE zFb|cFq4TvX_LZe|#Tkd2UtwLvzzqX%J*itwQfL6YuDFJq9F8V0&6wr{ga~vmSj1Z@ z7A%U`(bhyLJ!^`z+#a!JhEeW8b>Orwhgz=IFD2BB95q;s(CV$gTaPS*CmIEkwkXqs zWi*H%1L|taGI;APsf^>Tw_+H_{^!EDwT6)_B8x*GXTZ1(U>pw^CjiEYfN_$Bar*DB zL!Vq`IP@tD;Z#6)#6Jx}v2B@#p{@*0e>?d+Z?g=^YidhkduoQGz`~V}0xRfi8pxOq zie{8)e>D>v&H`IIl6T!+B3w79l6R}SVSOW zoLGfC3yOJ3frAn729BM|%)qfT6)~`$FCQB=OP9uTk3MzGwu8`uGDMPvU}hIEvk1&I z%EwSlN0LApA_*<IFOFQgS)K?Dhx!S%I)oW*5&Tt#33?Vv1LmLY<~sEiXqIvBuR{}TZe8bGpwEU_bQ z0GI%Pod9qN0PF&QOErMgd%4(kml?5RHwJHafOpV82RyN?Oarh-8KTCX@|lm%=|MAM zFKUBB#?C7rGO~5FHwf4VwCr1^z0!W*ZGSLyK$(sgWXKLj2hti$l4}VK9MRRuC*!o?CG^>1Rd?*4-N^jwmxD#gSCRK=~;7*x+`DSBx}a z;^;DjiDN*>u^{9)5OTbH3|+3n#0h18DomWHXgG;6JsFtxpz0|kg9gJJCQjuRPeY3r zW=!%Du|yz3BW2YMR5SAH=6mAiMpuui87!7-)m9KFPA`L>I|KBbS*8cnSulXJLE1TG z83M(*RK^Ju=P`um|7SvYfrgMQAxo&Z(17qFKzK1AyaW(l3J5RL5KdpiMep)5BUD_$ z@LdV`4*mzhC$1{f2wYu;SaFSfo;M&v&h2eSTuY5`u$aH{!6Iu<*MWoU!ORV1+Bw|_ z>TUu_H<#&XLDuZhbPGMQhw8DWx0bP=x{W!#U32P&3*tIMxVVF>+zB&Sv`WH7R({1@ zq@fuvSbJ~0xVy}Z7xz#R1Lu3?W5a-SZx*^gH(=aXhJbNDIC%h^JP1x6l8>QnbijDH zEO~}%MFaa0#l)iw>tlemCv_huDKsA5knsdJ`6QY=JAH2VXGg1SAh)N%Kh03hJng2G zdP*y`f?)A<89d!Hpyt^!J)WKe`~L!A&zEHg7B5g4Cs@45;Jx&p2HwjWJYqjfn0Uni z?^S^J8o+xU;JpFx-qhetU)#m)tuiA_yv@M91K{@kM*t_@Ez`QcSB3!bzI>k7FI|$I z;xj*>7C1W0TlwgaxtkAx`$u5o<1+1rJ^@{yf|$?BbZ8*kb*TBA9@!W5Ovf+E*c*Mx zBz~nybmIb%n;|ZI%~ieu?+aEO7gmZ>@h$0Q1_jpJ8x+1PGlRnSRK!5|2l?30FXbg7 zB_jM-hKTSJsQ4LF`~oU|rN_!%eE*xG;kUA$ezs7<_;*FaAB<^Ec~VeVQQcm$IPmZW zh1JTb$<@*1N#^jR1&;0N<6oq61tas%d|`6hRn7J!>8&1CGh(nyxCgi znv=E5_4rw*Tywr|xn?T2JVPkxO=X-=kjIea|7So}pdllsvjl)b1F|AO)(4Ok1F{l8 zR;nSJp6jAjR&E4 zK+rokqn}@C{=^{C$aL|nt=Gj5E;n8L5GrEey19I8*uZu1bcRVge~Fg;xZZteIlQ|M z*!zKf6|f&BA47AsYp*WvX}+%pXpKUCIKwysF!rSGNRmS1;C1bzxXCThi|-oo zHwD6xSZ89vqF8jnBDHRMrHM1zmCdSF$xrF+C{1+UXIverJIL4vI9QC<>a4)Mk12<* zss$-qmg^C-75E+tszj_wTmYUb!ga;9#dR=+J5Jjv!j{ETw)W0N6JH`(|Jtq{ot8 zMgnh_!^_hrnVyW(7DYfSqZtC4J*^)mDKsQrZ{NnvE=IFwn`1B%YxOS}^4B?&^;^Ty z)Dvs;4adJH9vogA_juT$;XD?uGf|wiQ~)Rq)z~- zCj!)y0P4x~xMeTHNuN>~+xRddPM|xgJ(Th9lFB^vE_qXhOD39NNIW0>6B#YX3HF|90Je&nn+ho@`z!${RaK@8o9hLbJ4x#n}*R1tRg7n?LaO z)vkbu(q30Su9p8&tA=i^+96rnIH0+ub^gG5HS8v-s&iGXfeRb`;%+U_3U-0sV~~0; zNWHII8{GY%?E%pCV7WG=velAf^h4YvBft5d(^5RFNO*+NdK75=*>)b&>fgzHv<*?i z{c&#i3DbHM3{Uc(l$K9H_owO6`8Wk|o&^lg(c|#d=<#3F#Gtm3G`=^K@@Az-JTFT( ztgTkKj1n(UGxVo~c#$RHR)*)eH!(Uc+u0zyrIoeqHlwwdK;cmIa=B{?Tdrot zomUv2S5xtM%`lVKfy5ht>P?u*Tl7dm1RRv!F4tq+5aJyz1VtP8g*2l~q6DBdSe~`w({AjH>CdKX%J2@x&)U;ZtDqS-IC| ze_jrs{RQy+vRqr%SM=!h*=6n+`DI@%mQd)yB#@A5IM3zDGYllxv?&5_9gN zH1Ii!|5y&k{S%b>83O(SQr`usztSU*{S}Xa-^zKk|IYINQEnI=w@P|>&S20kUH)H= zU)Ig3pt`*(w5{+D=Fqoc-K%lo)loS4T)i>1VvUNNEN;_Ciq@=vzgVk66TLP)Dzw+B z&}gq)p+U=~NAq00F`{>crnkc5N%JaP4V-iJ@>zp|3NKV?&($lG#X=L?NbA&d^@=KB z7=0jWF?1=Z(5#nI;fCG2LN*<&mk`~)M9e4cC2BV(d`rRszS<%#f1;E3WDZEju{OyU zcRI!2*WT?G4afMTJz=Y3BxLg16lh*dZBcz69aO_D@QDvTIz!RdWQPJv!t&L>jHDr` z+++F5Nv6=Zp^5I9eCuiO)R}x0ZVd+k1!*Pg?VQQim*HFw20?e5Rr`mJvF6eZUv-vL zmCr9z@>^0>i&Y&ef1_AL=Lv_SL*3KSqE>si1!d`|A1G^)veX*2;FmoF65NJ5--1t! zbhRBP*4KtelxI2BZv%tJ4Z-6^;BjN{Xu%Ns!RprYSY3ZAwfr9i$0il(O9%6{sphK< zF!il){ezQnZN_B>f?L{cGC|#&nBm&Q#>V>kY0kZZjqbT+^@-r*=#m`+g8mea=JIhR z&b1=RuUcYIR?>{5Yp_Au5RkSxNE-^$d?3va(l+prR#l;su8mfxs2Ha3tY(aAfKd;s z4%bR<#*n*FXau)45^d38M9GMXQ5713Eer@o1A;MtpcW8p2?(~T&{2o_ceEd?O_uIK zN1tMArRX>oZW}F}>o-SKq=Xpn@kirT3lq47iBJzECS^cmGFO?Bf{0;IVk!{X)e1ArE`=70vuIHxbR3ur|3aU1E zFr=9Go`P{lZfx7tJfjNr> zKzSih-lf7FdY&1{MHNOsX=GUgP@P_e>usA~T0|4bZZ;$gLP8s4w?K?mh!FzWJA&-6 zCOfIWHpRzc7Am5JYHQM9H=1lyRDu6&=UPz{b|reu5WNGU?+VccM2|!CL|V~1E41H| z|Ch6sly?dD+yxN%2UWA31$JjLmvYH&l-w#u&lS@Dn0F0V1!K+esv7^Ws`glr{%=t{ z9&x^H$oF{1U+e~ocBf|byw|ddRnhz&KxR+iwHG}qK=%fq`vAIq0bM(w+fTE;(sJ#u zEad>k^FWhx?sTbXCeBQyrfh3j@gS~va580Eo0QoIf=M~~AzbrN)J)3BM+~bKhgIZw zM|}F6{BUkWp?d_-Jrd|11$2)Fy2sF?k&}-YCXTJpfwrF~&>mOe$;ppr4Ngb_Ep1MI zqAV7g*G5{W=Hw?;U}T*PQBQ#`r&ehDIgJW8%;KC}T}>)qs>}ngDKD4Fv~#%}9rq~c zL~IdT+U?$zAoDd@kWSe5MPtrw3CpPq(%((APp6JTKZWMGiS__bqJ4&2!%<7&bY_L& z7tdmh&IZeKIkOxwOl6i@e)Hrw$}VL-=)?<0ev9QF>fR8*3h)&HeDbEcBj6luFvq7c z7$bK+*TDNc;C(*uz5sY%2!pu@)-k|i9T!un<^OICFR9?+dMTrNnMSn@niJqj>G0)T z_6jgS8$agomrM6*HOjlqn-?6p+UZO+I?7pPgyDot2>GL@b9q)S&A7$wgkw}z$PNUh zB7SSKbC`3Bh_&;yoYP>9zeXz5+}UnN6CD0)#g$npGcxC^49czsW!HeRYeCs{pzL~3 zwwZ^r8#HDAC`fKp9N)ye-3*Qa)#aLF=aRBpxa_Uq_+_ckEHbBAbgN!fdzikWSGB}q zRhAPj=q1dK2K~;#+y3TQdsVKkGTSl9zg%-7>pzL-%B(astd7p6NVwVjQ-(HX1tk1c zNs@@$vRaLCYufD$N%~vU?x3pPThs1@J>5l*%HZyX!QBJXx)-K3*kfAvY18^IXX1Wk ztPijOKBx`Q4TZOOz0pHl@L^c$(-NNU}cZP44;5o zdlI(y6l|~BV|!0m=)`(J55X1BC>oz-cAf(}J#OG%TH%K(%tZZpZt(@QxPg(ersGn) zSfRmrslrUeU#{p$^;ZDbs{rvejOEvX@*BYO%?h1plL8KuZ&kR%c!mAGtq^>N^?kR( zI}o0)$dE`MokL$4SJr-4vH8BIlzE?(`2ge{vr2?r)r0LrkL?+^cYeegd<+d9{!8xI z%l2P)&k~juwPiZn)Z%7O;uEd;3gY0W6`AAUXH?Z22S3Ny`2u6-ON^bbFm}GK(7tG- z#}|F02he{P@ZYKd@*SJk_bH?OqY5|dIa66baKRr_3ToO?r?P&kKxFtCxc^d-X)5d2 z3QT4FR-u{v9Yp=1iSkTk!IZE70>C^=s6vJXXIHO zu|AmDpwbMS8&PTD z`kJgLW%*o=7jrl4cH=;oG1Jo*jIt-vz z1JoLNH0P_T#qdh)d$;!Z-Vv3a`Kpnu!Kf6_(#}_HA&Z6fX(O#u=c`6nV)%@KsI|~# z%SvrFTT$VL`OY`wC1JbE7w`oGi9k~zZu7mKfjEB)CQlYl#C;tiyd)g4TW$KVoOEk( zpovz6%YSx8`HCr@x)eo>rQQe%cj{_u>N6A%?c+{ejrUAljdN=_8Y;-PsWklHc!p~N z2yapoJJs$-QBuVUSgtDS&Ve|8+LWru#3gP)m7(72f>{^(r=yE=!HZu^)MiA4WtqjA zWUw$9EKC6lQ^CTvFrzxy%y^H@Y)7S*|BcFSU&-Tn8e=_OW8DT2##ee?A!l&enc!vj z9ChWu^zQl{rs<1+A&$CAEY3HRQKs41K~hUi?4kUblNR&KzvR+Arp}VP_I9aXZDV_P zeAmdL&W=_Q2-=O7^LM)FLe29~Pku2gD`CdV-VO#~vq4xr2%7`K8bH{NAZ((Cu(_2w z^h{gDFo=1Io1GZ%oq_i%?`XaTa0Zjz7FL@i7I4oC(X)KY$;6J>rBVaE$N;(#KnLit zV@;$>_y_r0q&~XwaIeq`pOqLaLSJ4QY8@2fLush)PS>L{yStA}5no zg;kqv+~#6nkgZO{1EdkY+PR%5+DQ&yHMJt9E2lGKBYbsKB7E&yscl!#qryB6%oD)1 zlOE0RRU?*EYRjJDvFt9bffK%#vIgBL=%x){yUAjqz1v9Z)bO=?CCp{+P| zV=pS)P!o!E@e-x5&$&R$Ct^)88LenWH|=*Au{SkB8oE(wA8IP}acFNhD%E+S(!OpD zM{wtJU!@V1_Gc6h0FR@Uqpq>Gjdk%lnmYH2FH1?N=A6@ghZrXg)SNF(!?_V_4l*D+ z7?2$T$PNW$hk^6ML2#Xi;3KHi@|9NM$Vwh3M=>r(Yh2o(8bOv6L5|_F#{$E;H|$Q)D&(MW%62}kH2WAzuSiMRX4=;9;#W2=-twK=FWD~Qmvb6=FJPP;sNI_n_Rwb&Vd04@QR9XG@b}VBF;*R8fLCxXk9z~#x{@)U5ny@$(FD|Hy!a79>((-dRNnT6BA!isC2p;bJFIdvBf zpUF*~g{J7fu@uh4*-6#2tPMVgTEg1kbLBs=rQ0KmzNhKBuUkZjU0~eRmqj!<;_AVV)(67$Mjw>0Pt28!kjDphhYQqw) zK|j~>pLvlmNu0c~>in zJ*z?!LaS^o^H)t)KEWp_M-7qC(oF(hqcR~w!o6WvgS?^ zS=J@rS_b=vXem}y)jwoVB;3^1)#a0JB7!!Sb#x~}vFNgBcyS`OtZQ*t{vT74lC~;oAOl?MO3?0QEJ&{dI_6 z{=fdZ&@^7Q+~4wbg%^h{UrS7Mwmbh5w|soWAgz+p<<$&vTz~U$*2ebl33=m#@d>en zZz_wvEF4&*S*vf3#UwDx#>W@?x3lFijxU=K2nRdk9bsZ~@>2QsoLDwxeEl5%WGRS{ zFIsWi?=ZxF_szAN+G;Ule)c^P=*>P!_ z9m}T37qb>SK_3N@OHczLTlVU!o8y}v5Q`H&w>w!@2CVSXW#OiFnrL6p9ItA2eyf}4 zmI_N%MQqvh?W${(FbV1Cgv4W6dps)t;+tW2#V61$kj@|6zqgav%VtdVDFa;=>1?*6 zwlQ0{Y(}RPc;b%r%VxGm!;@tMjR{*UqNb%glE&xj#Chb^nO z?Zwnjy&a8*<9-RCMzntNOn;oa!=EIc0sn&e^po?q1q-R5Dz~gY8tCZgChYyv1tf$W z4aNx#{!3zU#2=P@bovsp#oaM~pxNKnQMIRwQhj$c79)9`Kk!KNCw$>(OKclCaO}mg zc4Bf)r=ThSC>322>m~q~%^mKqmv&d5EbZLk6MYh%=EbBs{cF*VT742|Ze9K4XlFvI z&oXugn!5>#odTg)%r||y+YJAEK|lYb$^QCCr|8gsF#bg_YKNko*ld}xS@Lf_YyOml z;vOAf(j}(GSE_qC(4_xLbstsrex(xBtbr|HZfe#kc>(w;sp0N7eh@WBju8c*+~>U6t-jt1}h*1Q&b~Z&k@tvBPV{ zQ&}UXF%|oCC8lDZK`?w4!SFc*!+#+dK2MM4RP1o^0^+0XiH|Sp_d;hX_9fQfyg-Mx_q-Z&KlgXWl`39gNfO>H}0}m$zm7NwgwRfve zC>CV5T-oV&NA_{z18pZSrLhxZ`u0Nu=8pjL$AI}0!2Bufo?uM&-V! zaN}w>aNjOtGi}jt?pWVwYqEf)#|R(S5Fp_1dgWb_H~Vme52W`$nDD-_GSU|w1BP) zBEi#cV_c7B-!k$n@>R11+-xEAUO}~@zUlGn!|fEC;whX;`od$E0-Q2>ROpohy^6lh z#4}l;sFeQ-G^`EmYV^~fxvPQupA7qhR`EN zzjbxDV)MRw+(kU&ZfIXe3nK*jSP_3;ul)sk<)ntdDp@SFXB#P>8Uly)#mK3Kyfsj0 zI6W#gM^NF0{N!`ZM$+#jzZ=6wQK``4(4KA#i+N($7H$nkCZ*@-zD5ii!wS}dDf;X^ zF{$4zHBp2{mhiKcq2gGmxHVK92NkygQRBf$%)`k9Dy2WiC(AXlFB|wI)?l*Mpbhel z>FdeKrf}J*(6%@1vSv|rt=KlJu7*+8^@UMx2L-pMM}@#NATS-e&Y(v&%C)FZU$vMC z?RWKPKa1seZE*({ezq3AA-$x^7VG67Lu1-V;Z$3kV-VEb3xQRD%?QR6VCFi zcKNm|({`V8E)ykbw7W164EoeYD9-ssJG12cDeenIP_8rP>7Q}*gp4lx)s)*J59JK^ zYA~!8ht(QkwI*1t8I((aU^x%LS}51Te-j{DOW2>2Y@?L6Q5ygv^SL6yHqJW__PkO4 zXKHgQr=lM_tW({n9PpZAa^P#AFLP>Vo18SOn=lgczv_TOk^R(@?ZYO_IP@p zI>t~d|7~UEgxyXyCF8UnMaTYPu_0DEk)mp>#)L#f-CNesu+AiEuR%t_tyVneS0@`< zQ)z;;Ru_r4sP!Z&F=?XC&cD$9c57?3N!n^9@GX((%!r&{?UhiU6J=a2|7(8seFqlk-CB0Eg=w6Ui4cs8p* zv*UQGFim37?23Q^5Z2&iVu3Y$@(@3SUt5aXk(sY9Zj%Tjb5pyV?aSKeS0-FGCfbX- zf)RCh7_N|pD`embop6Pn;0gk+FyG?}*%BRf(~TM+k;o}tb}`rHgKM5_-CFpz5;I0z zz~y>$IUOVJT!JBF7f8Mqi<6b2?MkGOO_4Y1tJe@)@ zw?~M5l!p7Vr29d`JX!bGS}rIl5HThxmj0W3OdOy@KafQ~2%`V3LL6Mc^oOuiheE2Q zd3t4c3*xX6P3Xf*K%xqe?WPkA|_2$!qLmwXx|I8*WYwd-@OFlNc3|Q})yhfS%E?fC(P}xR0GOl8h&Hn&LEodAb4S836N4fO!_c zJR4x1lNZc$HJDNe-=vA+Jf-9LEX)PHkX%>@$??Eok^6RWp=$IZZuDXx@TV%h#EY}N z(dtreebBS>%)%zZN@y_>7%JLADE^jCXx)vb)jZ5od@)?aCOdkM&P z2im!lf9B0qB(ZyQ)m0H?k{0lJir1zSmNa( z30`Ph)o`CW<+&(vf_O-^_b|8jh;HwXRrY9!FRzWP#+-em_^3p87`u7m$d9%B_O$&ImjBZduW#m^wtpsnOs?HVI`^Ko ze_n#F<_k#rB~HUP>Y^ zQL2X%sP#jMXNEhF^De3L&Uu$+9V%kd;jBJ@)h+*^7yjvnnyyYu{>;D7z)vqS4C|CV zPbsh#eCU*uA?Od*4aeDpK76H za=N)F8?&bKKj=Oq2?!nQmzDO=CIjcDNy3Ttu+rg{&J1HQ~tXTnopmFeKV$%ao+J@ z$NEy+4W*7-CYq<$nrKZ+fwNt$t%+qOvbZf(O>%esD!gLd1x=AqIp&rw%r%m@SQf9Kkb$!Na3UGyzi&r?B$OpF4t@} zuRuwZB6Mg060MX}P$dCXs?=QmXe-6?$2`i^2F%*?V%DKCGdGN+m1-Flu@kD9d3Mrz zHJN~!3mdD^x2WP(78AI;|Idj`Gsybk2ANAdUF=Mv*if ziO9v})JyGu=Xo7X=*Y9x1;}Uimse*QygD0roCCnl1+UHnO6LQmQ#>eLpi%0-yca5H zE@F)@2H~K`>0Wd$;k=gu9dhJp&iq>Ta0{GpiQZD_vDO#yW~;uVBO&U1h@SN&_=UNTVA_#n)!smL{`3B$vMK00!Y@lw1xsmhURO+Q!K8-iR zi?la$f$8!G-k>Hv4nTSg4@ggY?u<+ zoa+J{t2sd*eQ3d)rl3v;m7@1=Qv9r)!pmMUoGlAv{1hP9TDe4fI+4?dm+UzV(XTZ_ zzfwe|;;=@#M4VsV$%vkqH9gHCwqO5bFWunj`ndWyPU|zx)=>6xUL_tHqr++me?voT z7=GnT8u+@OhK5=efFpRjx>h<$MH@L9y)SEUea2?{=o_=lpC$ z1`qWNSVL>AmW=S*_d5=WiF-6%Zp_01<6Yu=4c^}eBi|1eJOJK52-82LP4Brn@nOni zd+sA__ecNV?th!zAJcZfE05ic{_b(Z?oYt(Pr~j`!R}AP?$5YfUYY#aQaz`-*7qN3 zVDVfjcf8LtWnTbg|8q5ZQFDR(5VOsfSjCs2B1MHJ!Nn`3nkTOsJb4W~c^y1?13Y;X zJb9~BPnD>3n<;NoQcncYq0Y z7ZZCX`7syz1chYESJ=bFr$Fd41EJ4>&=)}HOCaeFRwuFZwlBU_ntsPZ zf8PtOk4?19$>g>^+I#R9|H5+o3OQEdRTWPUDt?10 ze>Y6&E7PVNP^L|}SeZ8E;$_;DOO)j^<-jt>lq=9$if4+sWEq1ssEit3s?2M{UrGxw zegy{8-Rm!{>hg14%jmlD=3TbTjh1?#*@@Ja<0_U%6_W<2$ll%i$v&)|zhmXp%OJ|G zY!JJ%Q$MBBeti0MS3%#H+GQtd+S1%4t?o+q=iitdvuFX;R;tcl;7MGjO}1u-?W$5c zY*(Y&sM(>xvS!kaK=#fr{;;N>`Qt5joz$~uvwRXf)1ov{8zlMGgB(AMLL0aF*q-d= znXBE2M!PQ`oQfr4{+i+A#*C>M67!1{G~|5*V=I<{e=C81D}#TlfPbrkf2)-h2*y^Y zJa#a)2Ag(Gn0Dg-oAytdR+MPVlH(K!w@MAmmcg2PaT z-#=?Y5mG%*n7LI6ZvEqeRcXr*?=jFvSkh{l=6n0xnCb48( zTZSd$C}paJ0b^x)Xdpps6Aq&!TQJYY@!<;75iIFQV45fED6M6rtiYJR0!KeCpAw^0 z3uCy2v1lP*-f>tr*uK0i@Z7FUGi!TFdbcm@ z?sNzGtKB>7$au}wc(t+eO1%cdZgI5J$UpP;Ws*401M*E}*u&fmr4kUZ1xDQ*Ms1}e z`*7brkSt@5PO#yQ5FX)%OAovJG9K(GwoJp^h|dRFh|hCxX9r!^F-<${*=|k z5v0t0va(GE7>as#9v;c&be@Yjim?EsN6TdWa2F6!8wlF)FM+Uk*SUc>rVRJ&9}80) z2U8pmQ=A}^$wBch+Xg3=A)p)JQ`bzK#PFO9c=!*dzZgdYPT|Z8k=eB?b99|Jwaizf z6EUzktqkGa=^)n`(CAEPbQUx^o07(^%+cbUGTp6Q;ptY+)$-fBGS6fA&+kQ_yt^_l zAn?Yuk-H1nJ%-+1NvODm98sw`5qvPvupN(bcf=EFbL= z9Bpl8pW!sO>Cw2@(PP=-TixnWlbqUYOb=0*6R>Xgj=pO&SI8_yc0gWhV0|61z8+ZL z0IY8WS8f6`uJ$nFX3Dkjuhj0AGVZW$Wi)ToXtqJ?tIC`J%8n3j=e&0S`8xR@d*gOC zp+>X(QTOKSZ?to&lU6R&sy?lW%0dkdEpk9iG&I=rS=Rvya~k8Pz$a!+&soVtdnZk% zI}*86hx}otSu5NaroHLmczb6u9_F3m ziMae-mambKm;{h-sfx=9eKsdkey2V;4$%H^YqmPf!FM27e7rK#Y^9nL@mi}>1$XvK zA*5_v{wACCi^TjC)e;kT7A2Sw(cEPa>~0Y39uVwa5bQn>?0yjJS`WbJ z6b~wPJj51%7#7c$_Ytke?PccF`B5(Xm@cfRhL4w_Z+!wfJV{BVqxg$um>iR`HkdD!`SMPV zUuFbe>5agvhCyG0uCD`(H(<~=DM>;&ljFC_bO2)r@wOJiJvn}dg?LvBF{h&72?6QZJc#X#Hy$d*yE|@b6^?t+*Oeq|o%2YIAqK!WZD$1_Y?K#R8fi zd9p4Z@VQ;whHeQiI}l~neFk=~E|v^vAO{5i+c%~K> z%OC3H7kQ@^VVNyCwvBY|J+-JbT)7I8MxaVHT)Boa*WZ?iHzlLQ4>>pJj;DFbDh-|x zxoAd2)n46bJSqcO`ggO)befMv(i4#OwXXV2$kD?`M?2}{7)^v*GF|Cr_q;`Bp|gll znn!aRe8+V(-X&R`&ZU~vWn`&n2R%b6^Yf81Irm9N7g)Y+OE`ENzy-RITp^&~MBZ^GqW_H9UH)b>K zUAaWPNVz9;y+#bbJG|x*L#$nt6UL-x9fK3=f)f+LiAmtZdf>!laN-W{<&gnB>9P6& zftaGO-hlC&3jF$2ctfq|gn&6M+K6kLrfbuag6RQ_3mZerO(>~g*c33#fWn(mQca6C z4`5ofx{e>cMiVmwm>x|KTTprWDJQlJ=;={yAJZdmrENwvvjUhVk@7bDvje`o)1-Pv zWUJnYY;90r4s_oJ;A{&DY)45F!kH#*AJCzrA;b<^2=_E;M;2nP7Gh3K!D&)2ClCz* z)7C|%OYwkfy3`nOPnVjgv@u;`LmAVhW+%TrT}nXx7J$+k@J^SK0Zf-t0J1HhNi>g= z-s#dEj^nh`U+tK`gMmtGpxRh@rC!D`SSQ-qDWIoIBypbUk_ceBl!a0`2-pQ{?g(qn zr=;FTSb*-`0e0gBEO<}Apcz+33Kg0*4R_Cl`q#zntlHa!+uK#Q_s1&RE#Px?BSuKN zJ2$Wg8gPZAW9!78x@^9_)(A=W3ZU!RJD`cQ4<(f~_k}h0gHiUUq!E&i6$b<~d+zr1 zz6Wag?U3{!mjB>h2FV+e9wM_P$G4Hry+hJN1K{0Zko0hPX65f4Y8ST)plR zZBC?9G7gmeca+X5%UDzfmV9D7naSqlZ?rV-+*}duNo4Inl$XSFqKE!0gGjr!xch1X z8EVF(To2!7L7^($H9@U)$3?T^*oX0Wh$AdMOaC|ftZ+C|$tM_gcB0QoIB6U^`VX~eUvBnx)uij;~QK_@GnL2Ao zIBH)7Ld($#7@lpZO5^JDSyX-Er!(Jiiz>6P`H;br8yIfBqsP*%#>5Gl)(7RGwGmdH zXwc#$(Bfp!;uO$gA!vOnNPM4%#HR&x2vOZ{+{Ebt?h(#l=+6Z7i%`W`TIu81kDRZ> zXLFtBpiWw%^%zQ=8_<}X$Lx1L`kf!JyG}ZEpUc#F3tj+xE(B^91$4h~F<`v}0A3o< zoi#~oV|N)P^^&uALb-TMWuA5^5x~=BMI*Qz%EF zG(TWwsdD;q0GcO>gdCmcI~&|}?f!Vyk`arnldjj8DpK>TttE5`+NQ?~HQ7482ZV=q z8X!~hhg6G_kwHpj{b5~Q*lu(%HR3#+&ezoCGMRSE^PYTzoPAl{iT3s(R=mAC-jns` z=$1Zg;ndqOn{d$xfuHS6Bv@y9?w-ETWnaJjJ*?4ZHof>-~(E!1fZuvkb&@0K&LMnL20jysKc5WrP<3u4RN5lJG_VD+zDHr{03!yiG~(O2Pw9zyA*X z)jqlQF5~f@#-ok(x4$a~;JY87oeu+gC4nS%-=h3c0E-A8L!VC|+ou8T(_{==rq2S7 zPZJu_65{g!GxrM?@XLVLqe<{Ww{YFXse3EKb{2tIYe$q3< z`+}bN{(vAgzgVze^ZmtTw&X2sq95fy zk%;Gbx~_Csn)3c0z)aguC6ebSZ*ivC&v>TU%Qz)$`IN%T290UJI{Yj$X; zEpTRz^UR2+=^at}K0yi;$+>~L?ndT}`RmoIDSbDs7W>utUW%KV6V6#JC4LpMD&%)@rmL=u?Nn)F6`W$>tIr3UPhR9!rHWclG)MI$fKZ z>X5qg8`A!4uBV+|t)P*!G2S$f20R)OJ36I7?MJ5xAo@EMRR-q4R1TuHdVX~vIpI`H zAF;C8C@oLQ!I#F)ep!Mpd$k`HRshmoM0zT@$=)B(5}%);S5|GMGx|2bv_+rTV%9e5 zB7t@eMExok-?`IBZ%t;1JoMGf{=^m&fujCo%x{8*Kb6CuD&S8R{3!%~3d5hC^Y~L` zP|t75d_}1)s+2oL*hQ-0B7K#s(dw15yEz}226IJ2bVd4e%FrM>{rj$}aK0<88`MFBA;d&2g!{YF zBo<;lEySF#uh4fTvyTyzgQj(h#DePwU9sR4`A_qc(gsx8_@u=4F`~e!PJa87(uUA{ zBj7PD=nVv?2N4Kv3=B63YT9f{NpB$doW7xw{%U_x+Ke&UTw~P6$}9C|8n)U3?Q9v; zfgnko=abT`Afmz9P^umRZUsY5f+4r2Bs*??g3|yg-E|w5dE1~tF0P4mDfBf-{>xYE z7u%^Cw&xml&^0)J-ZALQ>(_HRe}mbg{ZTOpzix!hnkcD&YX)!$=-)y~<=3r2`1Pu8 zwRI0Jl0n0@M~D;^r{8j-EvQ|4Xn$N=*V$%NGB23dyW1(5$GbZij&yH0GC?q=6N>Ky zWJFNYAxlXT!tw50FrRmKX(8O+J)ec>)_TpdAhE%&8Xz8U|vr@o054v{Tznl+}?1U z7X)?AhvF9inG1uO7Z*{Igm66l;$S{czeEe+_Vi0xh|9DPeR(=27UJ@tuYaC?MbPEx zR|egleifBAJe{p%c>2{&e%sTpf%4Y^lIwzAPrp70Prm^$-Wb&UxrvemJ^g0-tL^Ex zFif{zzP$eaD3^N7Y+WJtco6>n1WfoO zB^8cO0mr8S$1{|)Ps#*+eMIcf1r28(C7!3U^jl865Y*1TC=t6+!;8VZp8gUg^LYBp z48$wFfp|3t>bwS(Uk4^{1T`<-q$CNU56lGfdHUO02+x5T7UEqkM1Ldp_kzCux%vA+ zmz#eObi4V7RN6c<6Lh=zM^1j*%|C|bp8$_fgI+iPENGmW0ft`$HEq76WI;FoivH@H znPH5+(HOO{@=CpL4O@MOcD@g4Hz$enotX(5XJ(+(PZ02D81fw$@)t@LiP(P)s$(-O z^Y1}}TwD|BQpm??gGT?BdxWoC9j7U$Ru(JQ>{)~=7BBa?`v>Qk4c9pkb<*0gxd0@V zEZ6W4DhK>am23EyF4xrXmuqa7Dc9I8Tb|EJmMeF#rJl@bQ7o^NU4aE#vD^zO37q$^ z4V`BF3l_t~N=lxUS)Nq@)L+%!ss${y8Vj&`5lgKBORZ^GssxrQg{8`1sQ@e$%xkIg z{FbUv$XF~`sF$TyD`crXeLnrt-#@jkD8fqkN*2BfsQz0B7x8ky9?h#++8PsTW$(e| z7|n;k$U`ZqSg;mYPz!rUDXB*DSh=t7dHS$&V?ZA*hEs9+Ehk2l>jAxA(L3hpMkOQ5 z^N#7GC`X<#eKf-{rZ*g8%R&EfP<%X)nNY6jUq?w2!Wq-oF3;x#>u4d|WBR%*#6&Qt z|MT=oE;APy*4Ha{4eOK3-NX9&RF5&Nvz3fteTtLc9@aO2@>2oHhUMO2eWP*=>(c<^ z^m5IgjVW1hSl@*HYIk3oGE6fxOl_>ZQg1WET$`hvndN#|CyDb6>syp#Sl<##&4Pfl zVM{WUEm%Dzi_g=yD(C)TYZiM>xj`|mjMOPKveRWcfBz?mZIr;2AXy*dGUK!|sc4HxMc?u$D!6w0?%FI%n1f|@_R;oTem60l=(e(5jR+|R(;#Qxa%hE#McdD1aJHXI zds@On?3cg$p59o48+-ir;~-W;gBmm&8it524JKh%fjmGanp-HlP%{oe+aJv1uWJg69cv8RE`UO;7Upt288*%zqn=c0=OWPh%UJ!0Y_ zsjswmD=!WxXYVtiY8*m5Is8Y7OQvh-U{9AB;@r$t!`F={xW9AOjbY}@R_a$nxC z=_Cf?QVzl_gvzG^lhevIVNRzc3E_lIXO!!q))3-MErdI4I*WxkTMNjLe9Wz}B%`XBT7ngfurc25ZGhGS{FDuuy zxtx;Tm`OX@74%m-X1bCwx=Lfz#>y-8t~P9S4cfW3T*pi#ah{mzx^l!!*F&irAmEKK z-d4IV!^8>)?LE!XIc|O8FtZ^dtsP@DoN}oqrsKN z_a~Rh*U^fnHROE^%g-3VJ_}%<1F+8n*cSloi{%A|<(DXrJuJV>D!!ssY=c-&<`K&n z7hg5RdJST|4zb>VSZ_kCx3pL@-f<*)yIhZpRsDomyranQE-UaJY}D@x-q)JGTyApy z1FrEy)Yxl@=%aFt!p8;*p8$nVfx>4%;d7wyMY(1@wQl3^B_(?=5q+gp{h9^)MhoWf z{)6%Yyyqtv9r~Feg!op~_#M~yJyc!8Ea4&S4<5YSzVahi^%JU!%Bm90DRl>#UYeo# zP4CKw$-jri&$@v=JmMDv^j`t`Zvg#wfbOf%pbw}h;1P>a9@`@pub?KDsL&n(v3|@W zmf;ZtDx|K zQklGp^@#i_i&SgXOY_*ghFchn7DhUxvLDfCkIQ;<`Vo!%ErrF9{@Q)00q|M?xE26M z0dNce4=ZH%;fCEuur?!McZgL}-0q_cu|`9zF%WAk#2N>&#>4LKI}%N(&|}{~2Tf6@ zEV?#JxDN0}j&-%HBPz_%Ya$n!q>Jcj$$I>g5@|97U7wOllPS<-1DV9b5>qSiu*8Ox zX)09Os6r29B#5olG)l5gbP&SL3Nc+Nw=qk)36#r|byKb7#EN2rTprg5iy5k&&A6S- z(asuX2@f-8dSG=Aa$9g!TcWC+J^ZI9K>A|8#m|TErxE3uP036)k+zou)k!Axt;1d! zq|49f3VE5I&YH{rn@fn6cvC{m($e;Mo4OHd=l?I>^2P%y~rAebQ;{ykf=88OSoKOsGVSriz5OO57 ztlL$XZk*yGZMukd<9QWu<8}zzK}n@a8k%G(OgHYVfE({bnL448sL*aqg4jxBDXC9Q znPwC@rCJxuIUlO^%Gj+nOjQ(c;kkue_+Lnh1xnr?mUm~!8!y}${0m#(#bai7x3Vh> zwHt)0_qkW_nnWUz&L%TCx<`>kQ8LiPCQCOtN-FWXoj=dGu1d!`)2(5@*j)?KM~|^b z1$<*qFlsMQZtn{18~cDr`&Ja_G4`W8c8{??D|`SHp8XdoEDqHA639jRf`bfw4~D*n zK;J{5?_tpQaINo*j~rEx&~CHkpVP~X^h~XeRAfGiVLbY8fbkd&n+LcCx<|B8I-mABsQP7f(Y|n$ZW>Kw z^*`0d0~Amvb`t5X4*G$v>7XTn5o)C%!#jY~4XNoKTX=tSqB9|(N;mO`J>%L{vqjpc zK!<L7Qcq+#_5f zNV!{DB-rVk3n-DGofEpTTA>Hc zkgp$n5vM8QpU!MM18nPG=`*#e$5xnw?O9yi*}6JC*q&2?!S-C}c^)Md5a$Dk3o6XP z_QDDbwii*R3xUYR6?(8GL2NKCsqhsVY%f)6U&eA?4z+t_yh3YuRz-oqHY5M@|33Ej z`q-7qepj*mu7>^o-xhzrEw1r&0>&VAE!*ch*yk?lR@BuKHcHODw6r6U2h>crRJEt0 zG1IQrnH#%uIf-|zl(!=@-@Ah}Op7c9!p)coGKZA*O&j_%O{&SZtka4$nC+OO+cE=`APE6ic=Zr1P~_weHS@NsX2rpkQ=Rqh8> z9spGy1XUgaRUWR;V;{9{v*eKqU%n3?k1FUNW5FKRf;k^P?ye{>#>u2l^8N``{7EkU z6!fzH{ImxL<35jPxX808QsUG1dGMou>DJD;kcN>HylkC#PS=#r!Hlatp07Ya@dBWF zk&+6_mw@HVK~AM~?%(rggJ#`FNdmd!rYcd2ji6Q)Wvp*+zKu zzUAXBg9C3v?suTryWqfkl({~tZuPV^h(ZN*>t5FLM%DXNo|JQL{`i1uNwy`IbZ-9m z#dGt=hfWDwW(C4WEUA6-$Hxr7Cot|9AKj=i-oE8AJVOa*LAbEGPCVP|k)}_z;R)3u zH-da-K=nDG`T|gW38=n;;lGAqfAJXh8_Kot&&mI7h58Q2h&*NLBs;$)0KKN~px0-SyYPQL-C-+`0Q z(m4I*!D)cy;M5;U7qb|V#VwL%2}>ga4Svvw*jo|@a^59%-ufb{8e0+vae-c25|^^H zs!LN+Vd1wl7Ry*#>t&&}Z*jNQ%W>`Y0@Ly=;R;$peivKLm-0V-UhBM2)}Dx~LFx}& zHlOI|%=N^qSqb%~roT=kTIw2P=QVonxQ3Wm(Q@D<^op!Qtz>}^D+7d8fYPd#Cd6uh zW_1mXXB}z{%42hRO~$3<-w2mdjmz?Ra4{UE%)li8T!O%*9Jo{f7t2K%1xd)#G1}q^ z01>v-!43wf3II8Ok7zjwL&Ol(T%bl5z}X55Bi|4RIn>e=Ukh5)TIN(bYGEoJqfAk# zGtAQA1PS7N<)ftj{Ny&H7@<@f$&!wOYI(Ab)>>9u1wxHgd~|xO7cs;b)yi0IWgJ>5 zlz+SzP-dXXoW+ zRz50iu7z;#yqw8GY@vl%q~{2>v`k|c*?u{T>c{rW+47&}_RD%IZEU|}OBvfQw{r5^ z+b_3<`f~uvHkNn$<+c{KUv38=x3@HlcA%tp`=#zscBH@BJ;GcDszC$Q#>y-8;uZ|n zh<2LzXWo8E66e`|*=%9^WdcgIK)_Z@Ta!#>3znoL`)v`vr!02eHWqxIWzdYPBZUg> z!K5ppigfm(T~*z|Ri|~;eU{5uK6me6v#^sZ+6fgARIVXK2v^Y}T+3Q6uH`JdyO%$R zF3ab-vXVHZ8W8g>H|M&Ya&&9u0@$X<(uCXD@)B+r3xwO%(nQ$J()QflDn__H=&$yz zm3uNKdudGC7y+f@-WCYA58Bz+(u5<4=L}NfM@jYlEKqHKsB-{BJJ8ZpBYW5)9b`FF zGr&67V*4M$A|7gasYRk|YI*Lhl>g)RmJj2yhwHNDd&`O(?vIN{aQ-8ae@~fzM!cs{ zJ&9vK1lK4s^Ac%(0xp%#=Hl(`b|)@4S302{K5`ysqXi28wuyAJwYhZ2j?~UHG80{$ zXR#Z*TC+5S#?px#{e#kzQqAj*8Zlzj=!r3Ll;yCpkNEFs!(zw4V#ivVO~=6~$HOQm zSOwz06Df}!|DD9xocwQw%_$n2Bl2Kl#DEJ8Y)%C>rvaPOfz27f=1h&vjKv%eI?K{A z;I@A$2;yvuec&9%{#;=H7dLyJMwP7IrQc^bpXIm!a?l3i{#Z&}XlYAaM8)-^4HsLB zQq3i>(WS85Wt3E=y&R^!0!F;j(!CBTWSj9SO6rZ&{c8VeWshqZhif$sPM>tXW%Nnr zyAHI9CfRzODtkO)eHuNbkd~Gv8t_^_h0LjR z3PYy9p<#Yp$mv2(TD&8^U@mw{LZcG z?U`=%V3>WxlRrna@>9xm{F9%CaIQ}0*XATs=~;+msx|3XuV&K6_9humbfoF->*ltu ztX*2R&)2lZo0>9wv30u~cvsfHK}OIcnzA0}sj_4$of{Gpw`eH) z=reD%&@bEu^4tz~-2u+s2}<2%73eeXraX3^c@LZH-v2jQe@u3tHrY*iOlEZD_ZudA z04947CVL1bdl)8rM4N2J5>8kCsHMAdS{eL9wh@mhw|<HL0O>HY@m{w7TL-=N!D9=^IquD4m`cc5~Y&)I_FEFaQ{ zD}BIR{cC85i`Kc>1TD?yGD7~jvn$uoP%AZ3uT)B1!fS{9{DrRx_ueoNF>A|2XM4Pf zw{5YPg{#*N$Hco@&_2e6_Y5z2A71hSyyQc8$w%;#kF5gZ!Y7o+9v41kKtB6-0OWHG z$lG}UF?!uE3_!jFAYTEHuK~z60OVT@$c&|(UiUjo_qv0ix%ggr$PbLpk3h%F^OKhM zQ_Jibf968JSVotkLHJd*%W$>JqFQgh<#g3< z$d>1VE1)24_Afv(v0_LwVWkk5uyROaw@OHZyJ|=?VYQHkZ1qq+$kqrskkN8)p2o$R zO3xA&w=`r}nCl`n^5V6wkCu=BjB}K!mIK^!5J3I;n#)6Oo47m73U1IsgXjD5L=p{7 zC=sPl!kIC5cX!8<&L5nK%*2MdJZShk_@NiP7)`f~NP!#dq1tMf6Tw_Ie`S8Bwxmo9 z%ZW@Ejp@luhDMH9GS|^An~8~#R;`aNHXH(vDnpt_RUyrzNJ#UjI;4426DrWf4yHVI z7dwO@9QvOL;aVC(VnUHlxz>O%3J7C>a2OyQ4hTnR2xlzgbjl+`x>H^$A68;ih`nJn zBRdAj=FdG=>p-T!8p1d(J|4yC1yLSg_3%Ys!OB|LX6~8hGIhvh0~*r z3-w+`aK7hok!iXJN8Nn@CZ>}l_sQIw3^1hh?zh>PD%I;Un@|=5k4dz8=c=U2>~Xeim-c zRn0+F8xsrvWiBkX329un4S}KC$uxgFb+;t84>=qi(+5Wjwkmdjv33k;^3H`}8eo_> z4AU6ON8YB8&-g0rk+wO+=14GxEg>&`w+LPO{6r^uIa2Bahe~8@{GKoEp zvKUyk%VhoXwuVt#!;TQBoepUPGa-#&XGkNslT0R8)YKLsP+R_wKSX3%?;P~zKbXXH z2LN51e?IbOeEfcjv0p#inP^J2q|`NNMJEpahK6h+%lnY&Aj{m&crMu>|DH*xml6{T zQqs0GdCXeUZJMK*w4D9;okB1rqxKiT#1Z0UC)J%RA%ofgwE}SM;s2I4HzU zc`(Cu2;k~Z*+aE{gf?afhjC?x>&o<`>WB~~RYyX(qe9wMj)wNfgv?3Ru^~*Vj-yP+ z0*2#5x-TL@Y#>gcWUoopiAvv-Sj3Z|ubJl*t=D0peod8MaYe6LZ6+p2aqed+N(k?yV#qJ zN6wv4C$82t|Q?X~=J+ByTTXlG=<;5I2Ri^RDFC zS$MOfg|ngf7MB0kkQej38;Wm}*^=wFkZgec>KA#E_3@{Np5pf8QQ;Fz|QES4jSMY22;a?D7G71=EOa0oCw64Ed{8qzR4 z7Sb?09@1ufBBYJBs>f(gQm%#lm-VR-GyZAT^ck&b8+0HLTpNR*<-E`7ymLkk;7dOn z6BaMr${03F8(LfqS@wA zc+!yoV;m%97WzvaSTDGS7APGcDiLNv)9P>Ai zF|pCH;pF3~v*Ft)Lp6UD7n@_wRQXdSMD{q1;e@SC+ zX&{N4m?*u?t-piT2h(`gPiBdCL)rlEQ5E(y=zW>yeNQr*_<-{8+@}I_pF)+24`HQ` zV7regsf_zcNE`RlkT&CIAw5u%ezpZa4>_Lh2=hgVG5?aa{z_}@bklE#3Qldl<|5zd zB7D7M-yn%^Nd|Kc!}57YtM8~@J%{<8vKUDGAd~fr$2*(Ek0DH4ehO(&ehz6+ehFz% zewE4OZF=JJTL?ovJxA{C7sT%&2FDjBi3WtVrg<|j7S2zo#kuqnC_Rw~^{2WVF)*xw zS~3ip4GP=yS9b}qRM=tM&^{RFDY$f4L+%f2@+}kAI4>L4I4>90I4>X0N4^!pK4XgQ zX=%kUL%kA%wQ|_YLjth?4_DzLs{-F>pFH#cDpm{khmxy@O-imoWej}Q4AZpQqg6>5 z>?{RpWk4+e)PgdZTwb%YJPdYrkV=2+I8&kQVKKNNfcy7L5)Qll$~co-$F%i+N_c7j9hcVvP zz`ldwHbX#`p|JW|VLjdkJmYO`SdX`5#T64#Wv&PB!yBT>-` zJgalTCq{*}_M;8$$3XkB(0&}W9}n#(gmq6r0@#YzQBu!VjYh@VO3!szymhsBPB$?k zTwo?gvvD%Fn5Zh4#1*Uu{d9)O1rS-EOH4tDB^eQ7kJtb}Of`Vm5I}4MAf^F`=>THm zyg+QCfsjJ@GHJ1?5`P8@vso|w*Ds|1(xje4a$~Y#YWR$##@!TR^jYUTAjE(3lG#J1WiQvWN}P%*+$l zdd(^Xm;4_uV>WU(A!mg15NvN$<{HcQja1me}Z8%WhQ8i0Q2)?|e^o&i=+kB5mao9i15w z7pe9ht2q&;RUy7CqPdGBa{7EA3rR6M;<;3l?9FAUoyrL5xfoO3V55&5G*a9Hd1H^U?YmXwKY_N6-J03;zl0F0xyDEHkV>NcyYB)WS2=~ZReCk5*=pvb{UnSn$ zkx8fM07f*MNJQyunz%TO`OhU`?QWNXS(k;K&fD`z>~e0)UR1q;WxWz`(@h}G2{>_8 zSW9@dA>lQU@Y=9;h3g>3^$_ERuqHU+V#{!2*de&9y_*yVZf2ow(L%LdrNO=;Y_OUZ zZxJQj%B5~IVYk<}4bks_=yyW&yCC}A5dEIKqTkE4+2@4s<2LW_-R1*fbQcezp@%4` zBzYK;Jc2eKrKCD1{1{ik$9(C0;g%atS=*BTu_#>E2ZP6n$HUZYPCOz1Z`>C5R*3r~ zB^fREao(p`@~3-C{)~avvykyQDDgbddV!K8fpeVqMPOzK@sbw8KF({e;JnO2ywY2U zSLr9cBJdiiSYxj{JDh`b{AJ7PNX>Ce?Av zmL~Czp~t(_!>y2iCTXT+xn17jUXs8^GX`I=mcn%vfDa%nE=N0ZB<$x(AhOsEsfcw1YRi!9f_ z)|RK%wsBfpfs3wKsI~ERVkK{DD|3-m`q$d3)Y?p^wbi)j>V;YxS0~o+wzei0Dd}Hp zrPSKyPHSacG*GCuv2`NoZLOS(RP?Vki(1>#X)VM>!-ZNKQzt6DtyOW6NdH=^rq;G_ zTC3rrgA27bx=sx7wlTM9Cq7%esmAVH%+|z?^PJe3by@z3DB?i?k(9D*QV-_Wq zbh9aQ{rc)sG~Qev?U1tqdZi=UolK;oyao}??$jRb$TZ7{JDp8MTV$?WG7;_Qq2JY~ zPf<^mlDN)BhpnjUWN9+!Y;-uvv(aH|r$iee?`(9K!{Xa9`8I5lZDEp4rAbD`CfGNP zspDCWz!nK?FPem-B=h!jN$7PaZ#HXsSf8$%(KBm{P3;f1F|nPtDKV$Wo`~%YSa$%d zI|A0ZfVBZOjl+URc`VpSxj10iWRcYBTdSr@j(M6HzQkV$UyFus8>XYN9ix>SPonX_ zVm{y2)P|~pHYwTPbL5;ctU1#(jQ=$(ksij}rbg99*dg>uDVwuW zG%e22Cg@BHJqNBn#qQLV$t9vq$+(a+<%F;XhlfzJ942>)1WlajoM75YH7C+J+8HP; zE@Pn#-IYoEw&V;vP687Yo;#ne~1mWbb95H;vDD`PHEAh_CTAC7)Jgo`!d32Z*yQ3#gV)MNK!zlkSKB18+ z>WjuIZkyqY^Wcl^@Wl@JVj8}ffiE88@x@NAlAV$6f%xlqDt1!7DcC)-aF4&Z*_;Nq zl|9wD!KaJmm=8H<)H8S^x?KgmRx$4HSwMB*{+^ynd*zSn5<62_;{u<>WZV6}&I~)xN!FKgMH! zjYk{nuQWWM61+PQ?Ht5E^X)w(F;73~_8wOJ;7VNIa|rY~6tW#wsb{lf3|pqdDXF*7 zNK1$#D%El>3wV?k(1~zJ@IrU@s5gr8^ortWRp~KY>9M-fA|;Ni^bpBj!8o3)I001* z_vw8g{qA+ei9q`#s!FeXoLu=wt2_m$FRauoI+c>jl&8Uzr^75~z$~pW%bD6Ne@K?I z6x?SsR_FAx;qj&o?JX$W*uAo`|B4YwoU0Hxj}bT@Z29le@B*)c*gfrqtnx)r+1t}z z>?&BKr@f@o)ze;DY4)_2QQ15_?d6s3p7x4Lqo=(RK5`X&p%-P7JyiJta$=yL~TyR%Ze zG#SH|>8?tjr>DKUk~w-03wUp(*Goz8LOt#F)NlTUp_aH$$#y@>_JEe{uW$IlN?+c7 z{~?y-VMsDnO7bs>2*o2H#G_Qdy#?_xGCl2&L?aeAA|9s#ya{ob-8(Nri{c58=E+L! z1W!>?G4W|I@fon{S+L3&D4x@-a!ab<5YHXc<)litCi*;{2FC3V0v99>sOGqMwN0=*6oc-e35$-=)DE>-UfQ_P%=D# zzt||`-mS#AH^8Sh$-Ku(zYnGP4<;RH9h=sR=>Ha8nfZWgP{Mx*8-D~TKZcZ_K*~=k z$tyF1cx7h9aPe8C?%o!9CKI1m=3komq7uE@muTlJ2=XKarR;2B({4d6DTB-x5w_0cW-8J3=eDR`LL6wdr)vYSZ^l31*42+Vlfk z#9nRskxBLwNER7D%OxX*ThnX{*x`d^TfmYQsIz#|#{2!12{>l4W=-96>Xg}*t+qub zu=ue)X#)GYAly{NZ`Y`cF9y>>i){m|p~0@kv4Z;6udQIQ6)bH9i>zSPOpeqvG^jUv zx-(XI7TF@K>Q@i(Xk!eirQ40BTWk(%Dm@7~-BRYD?w`z|q@HfYWxL88EV5$`OPV7l zekNeq8)><>$THe5h70@(7x)b>@H>m{Se4J2y6@)uhYcncui}1v zi7HZdV3nrQKQGymRgQ^%S`rOmx;l{WWs zRodLk!`v%W=`oe0wJp6OWne>(r%3G&N+?!RHd>h#UqvhKjJ*U%-t9u|G|>K?UbU(c zbTt-qby(K`e#v;53Dkm?)A;VDN}P0!25M5z`qU;kr1TVN0}073>q$Z`;}0)({C|D5URe?pp- z|A^{gMUqOkLzT8e8z5P;%9*0j=eyzoQltt2QZ+!Sp`=1>Fi;x;e1=le43I{MwE)>U z-ctuv`2(b=VVxM-83sXy!#X11=Mj7*LG?k4~gwd1{ zbl6;sq*_QmCwv%1btTVEZsmjz=X=73(M}1*&@%s# zq4b~AVZAEm=43`@eT__;p<9*1O}jst!g)6Uih~C5o=#`kMLGrf&rV&`qje;5$qdhF z)s>A25{xc!Oy_FtHwvXlb}l*%?-z+&m*98GtaxXq$SjaC%m_ zarWnbU|~jl!PEuurrZ>&g`Qg>Wa3tLoFCcf$TX)~=q*rsPthLOYw3|RKTD^soV2f- z&L)JMlV@oGOxDK_A0~vXts|apO2ov}qMR_gxeX0YYy?hB11F|~6B~mQn}8D+dN{FZ zl@7BG^8Fi`M9fem+l+~`If(P`CFM+Qx+zR~XW!%&EcTXKY`yVsRuy{U*|1wZC6!^f zf?>CY3F+c(d*9?XRE529k{0yyvQ=zb<P^6=8Jtc~l7w)!F}76ch|&F zwC@BaJ5_nta77i?aI?TMSEVV`MM>`(?uE`8?tC__!l|2aTA*=iW95~4J%+t@MmxLk z&%B0966bkbW!EY!4@7JIYY`&1bu2;ZBxH+OKe~5Ub!K$Os&e0I$7*OU|&P=V;FP>^1FOI81$ag&dZ7phZ zmJ{_|>52MIpsJ`i!{S7JCsr9z-$`t-lVP!yRKzsW8ccKYW)bgB4~dCWG}Ob3M{^4e z{Z55`r$N8dq2C!m_e?-}r3cEhsvN(_FWcEw%)N71lXJBuZIJn-D#sI|ebVE+D$wJ6 zNPR(-rpJX)>mn#{ag~Q2qr@f9>1vNomsaJc$7Ke5m!q94Ajp+~?<&e%zlqxY7Ejw7 z;CM+jL0|l6=~0Faaz4@Cp6O0BM;m*h@u-|t@QSDXVs=Vh{*&zKl;yD<|j_6iHL;b9& z4HS(k@vX)l*(WqN@}u4s#HaE~{Ft~=+k9wop59~teKUZ*1wh{lpl^ejZ--5<^Vsx` zDji{l`=y|`vx=E}7vpm`@abpqd$h9GSD8y<_i}yrp}s-9B*tip`>Qkt4;UCc2n-$q z1`h*+M}WbjReJcMhHdp9qon>0DH{`yEA^gWah}xTID^%_RRtERYSp08f2%*G8hV-= zdIowgaz)R25H%Kxp5w}&N9FT;>Jq(NBAd%fOYxZ1L9giWVy4;#H6}J9HhKa*%TAvt zX_15i?a4Ez>ub;a@usFkr*q|gkCbYGUNVs&N0`~K;yY8r*p6AvvYsD3Z45qz~fy? zD!|?YVDAH(4=8DN?xV$rK{?dh%ObTk(wW2mobboDLew!ebWce6|j|H*#pL3}|?krGZ%|0Ok; z%q6#QdivWuJ^fcs2?pBf>A$WrdirnJOy6oV&Dl})WTVvzE$>{h@266FNRL#@irlpk zKhiZh3s+F_6}~dJy;x3P4CDlrC#&|872-S1gsS3Q{`Us_KLGw80sl{c|7RHg7g+i> zkEMUDa{S_NQ1rJdc7@*=V_!tO0s#1?%Cj0ZAVPT;(|P9zcHb1Ao3;4dY}}fc&UB|O z9K522jfID7N(S33Nn@flmA1RgW`8PIqn69)%S3yReLqb$(>@=!h_-am-n*DsJW|X? zM&GqW1U4EN(KcE#qHQ!NqHVNPMB8ZTh_=xk9vk^1j*b2y<(G-D-IirrEC;&*6f%>t zTd2=2Z21VfuoVEyij-8itpwaw212V)((J;6e*tP?TFu`WY8G2$i1ShoQtX`t6EPLA~q z?IuIJ^`YGqXtx2doeCfy_5itI#6u2`Y#T+G9Mf2n=~|OE$h>aEA;)Tcl4Iit$gv5e z-ZY}gF#~FC1_d^cc*rqM%!E#ldUV<%lAjz~8t~0RJF_83J>c7lGgB)}juB$(2*@#q z{+K*3InyD>6CQGGLlseB2E`%Awh@CI+cBiuN4(@1=Qh9&8t9dalVe9iySdP=0oui( zT_dn<0+3I5fNYL<$l;MK5n*z)uqLfqlQzh_UBn^B3Vo6z838#`kh(3R$uSRVwL^i9 zh=&~GMH)Ii<1HPTmj({Lpz?Y-U^-Xr{t9Dz`KT7wss2y1L3@;ny zv)i;K%>I}v$L1d1(sbB`P6puspK{e z_n!4|uiGiXm^<8C5HYyd!xr0FTWn67vhR4cgJ!zDfn0_sQ)X>tkxFV7<)~yiD%sy? zcz<~h@10OOS&mM;x0_Z{Stpe}CU(&TS++Q-cQvfC8?3TBtg;8JvL`sP7YOjIhX8v= z98&+yO79b4Z`qfz-%n%T1~7Uep742p&U*mtbe@|1IvbNMk!Vk;s9r5@J13WNDf+nP zd{s_62ic@z{BgA-o{L!heUjy74M8oU|f}?sAgjk z!vV){f3*__7PYYvavx;a_+Z%h5ZL%o*!VEm_;A?xdGF#kSII^m{Ra^fM=En2#U?l! zCiue@9-{%-pY7~?D?653I1Vis=NbrWalETwkq=@gP#yRncB1?z&NZAwWj*H_WQQeA zj<`RIof7fkT*E>je=6*8TEzQJ?DPn}iJbu(o(XH6MM>{BvFDv{VrSD|?Q;$1FdpY> zJla@)dvV<0%K2#L0{)r5iIK$aa}5_p@Hy-v=yNe-yCkC56Ui9P5;-OHdZM(1xGchy zxSR#NLJR1uCz9ZW&NbAjmB2sfdE!dd@>SgO)w<JU^JS_@dG6E1uaXVp)A>y>WH^~HTqTO>1lg0 zvR3WB=Ml+Xxuho}nrWwWV;Aq$^;6pz!g`Njw9T3Y1YYu2-XScjltuh>>dyAWm}O0F z&t}v>m`(ELjx-%tNta(457*wrU{h^1|OI7EOH^P6hp&bk1|`#4uhA zk`99^!(qG;l)1h!744vXUy{dkepQCf*+j0ZQ=PDtoxPBOZd0bShqetE(Q`&bn=>+V zI>8I44(%ye=EJw~rew59_BELf>53z%Q9?u?Q=z7lyRj;cBYf#`gwakRTUQ0%m}EX~M%C+!sS9!f^bqdm`K^oOc7*h|a;x;;-q>{oW&E!(*e=08CMXk~>~ZYTigJrKB<4Po0RmCqhQ& z^AqivPP#cl4a#yDYe~d81n8EduN?fF+v$;0+0$f%+6uN=A~z+|o@tdhZPd{?E#~L( zkKX)EiG(`hMpvXzF&0dPFx+#=aW&q`_f+t7z&Q41uhC4KJ$q&YVce9-%uC6!yNibA zT&jsXyO@|-ltSh?7=uC^fkM+jq3NK|#-Pw9pwQPI3T?_&GKb#u{STN#%uwXrj0w3p z2>HLE{Y*`@Db?l@;}#6ZmVjefEHN^D#Vl9JB5RDZsS>O))>oTrj9XDzV~vsiKzDtJ zt*hOOjC4drFEVZeR&NWgZ&&SIWZb?Qi;O$KKX!yC%%!Avk@0J1k+FgPYA-Uz8IeYf zNE-v7RBST*uo>+n_-9^ZB#GUNj4jnzWNd{#NywI}){Bf}4qK)+O0s_vR%8n?ubL^` z&JuQL37wdMBrmkeSW3%;g?pm3syV|ocj}t^Dz;O#n^ne}34*K2_7YO}biLn9$QkH% z0p0mBng7j%?rPl7vH;Nb0NS0a9bKksjr^YFCeP ze6`&*$RETBRMhBDR`t={JH49|Csw;Vn3J4ZsDn8fI-de07FK&Zm{Y6K!JG#4P6tkB zP}1AM{NQvjXVPEo4(2Sz>uea7@lYC{V_4~2v~ymy?qEn_-pEfK3;}U|HTstepw5L5 z?IM`)XqfO~N;3NjLU&0uGx1Uu__At)Q(PG-(!0NjBYJVYG;lfBa)qwNJxv=~C$6ma zdHaa`)3mF&4yESRu-Y}0RM1@u=&l0}*HhA%ri~OgRBKcH7HVoe`ZuZFd!}})VdvW*?CsFz4w&*z%3MFKn|8DCwv}inaZ|{EA=(}1saZ#y z7Pib8S~k%{UoYaVv}Yn0P0UZVM`^QtHY@I;s&A;qeC%#&AbBkd?99i0^~}faaSGWQ zDU|N5HoDRK7@_-N;Tb$R8EI`TC9hG7Us`hhPA_93CAn*_ElY0Ml3OIXr6ivu9?%@Q zDGx`CN!No0zz+f7hXL>-0QgaG0&P5qwG`*am&?tM<&S zp60yI0PXex_O|BcL}w!1oTYP;yy~fzWSu3&8i5x`Z(Y6rHWt4r2^7Sj`q@Y zCNiDviCT+yJZHP?bwJ*$P8WO-2F)qDE+Hd&C`7f_gZ+(NGQ=fV=vWAg)17FvTjgDB z*5pn(%S`BSn`*NI&{#631hF@|)cTF9fQGO_rf~KOaH2g;ho!inUinomx|Vrq4HxE- zTJ>wz=EU#xO|>W)jp^HS1{t3R8D9VyUj!Ln0vTTh8GrYX@fEI;*?7P2zsBz3Rpke- zF}Gg_xBr`Td_&Xb>1uN-_9iR+7L;BIQ!#jgc-vLHNc8khwJUmhx7wVKy+>t@@QEJN z(~XGttKBiv2h~Q*^dY$V5g7b&wKrz^q#7~Pr(peO;P>a0^u|oTJ2BH2^jAA(`jWBv zN@LT;C@4L@HoWT_wDWDXj+sbe_oVE*Y6MN+L!TcY+mF>cXd=VdGW|qJ_BuCUKUXtv ze_=6y)nYm^0*PN}W|r_d8#w;r?oIrrg#4X_^wnsd{e2P)sL4k)j%hiDJ%hzZku27>% zwPH;%!mm^V!mrGTtfCQVV*r$jtJZ+EggzyZt+YlHp3LEV zys7bdS0Ms5>Jtr1SYG4hI!RuL>y^cp6O56yLN#G=6CvG1zsrYf+&nWMLgzZGYFt#C z)zwO$Zd3fySwt7^V_2^?>`((c46e}}83Lq-0_nACwCx8j;U3m&HQc?#iYiQEEdMYN z1L9WJIACuukaZo-c}MgzQ9ivk8mRRe$pxm%ANYRSp|%F2px00A=ZWv zYa@s?4Ps4)SR1?GRuXMeqa(zD4ya<&8Ya;UmT)t`jvSk7SxJp9eVM>aF0zF#q8FC7 zl(bHJBKoD4VAX3(cKXVVk@;RCDn!$pL5@iLk_W> zQf_;ebO$JxC+m({%b7JscV*r_u%a_68gvtLRTB-|L>x`z&D>Z3$|f$|jM8*>kc-J8 zQKLE0QUgx30?8zxPSt2mv;n|*c>!$K08#*>n-m>Nu{4X8sWGg~H8d4MX@F1NY~9HP zcY;p*2UGim>Y8lF7o0zf{O8I1lkHC^u1_nxwH2r~CF!7UbW4lZI%07SuxssWQu#N3 zioTNY2a#^RU8pmj&30!*Gwo{OJxS`YuZmpMRz6h?WuRccRb;w4{W7@Mvj;nlmvaj_ zy5zK7`{-r54Aaer>AGRM1u$I?Ot*7QfnH`8%47F3yE1~i{YN6WyGBstLD1+B_b?FL z6A11F1osAl`vAdxHG(siayrEQH1+?3klJ7Q#NI@kfVjxpF_EXJR~CC&tpuEqFKb>b{tL%v|qSd2fr2E+e3K;v9WD!9%A zT;~Ir3n*zU#*Y#g0;=UaG2=xwP84r1#$U|xU!vtNx)^^cHC0FdCbjciwq@A%atM0` zw7C+ty^1nBmu>NNOxb9>G1HZcs=NRB9xeNh78z}{chPf`>KH;Q9c_=xKl8P|(e_j$ zJyV~^imR!1(q3P-#RAbz85Y}Fl3!7yVqdxCl(Y3xSY5}3oh!E(ryF4Bt$eg}?c6A( zVL*r)DdGP0 z3TJVDjYjPO1GNW%+CxC?VW9R1PRyl0FD<8I9>uAF9VKO0LQC< zMl>#@fWYocTRuepY6l zl1wzsbEd;G=#X=mR6{Lc8PCqsi{SjxkN4Db_Ee5HAo&{_Y$nd_jOUUK4ORzj0Jjf{ zS>afi-&<4xjr<{{t__yOGM$O^+{Sn|(VP+u4SfH;jB=W5dsjf?QaHv83X=eF8qWM_ zIt~-9ZL9bYcM!|2Z_I@q*CbzsPtovIXC{P26N+| zDbr8T?Ux$OVG_hv>(?5G!-IT$Wi&BG{HE0UokjEwb~&VzXTV@budizg%=2UpUw=s_ z{*S%y0Bob!+I1)aMDHDhAw;qzS(a=kae$Bpg!E!UAP~#8Y)O$NGm_(&-h1yQ^xk{# zz4zXG@4ds@b7pqF*;T>GO}O0u@&0$i+MaUG_kDAw?Ci{9KCW|dAJw@8>YT4amefW$ z!S2tcE`?H8;@PuP=VED}R?sp&D9Gc}a4+lAd@SeF3R>Q$QC`7U4CNJl6~+pkS*ut{ zy1gPa0b$~EGWvo#G*)_S)wcN-$LxETu$gX1` zyDpGj56G?$WH$h^8x}>@>p<45Rcs`^u4Dr@E597%pKBB!W&7(2_$)e#ucxZkqo2v`!clyKA;v*4b}+md0x>pH;-*o?ewkRhC)S$_ z(g#~PwNWP67SAMUk4-|~AWtugg3i|tVki|$Zrj86&8YCiQ*5j~c3;OecHi92q`Z*` zZNWaMvHLJaXG^d1nm;qkc`Jv@S8~$qO7kXkdT~>*dvmx}2N6+bz&^r& zb|j!31!zYD+O43Dt)Yc=Tw2(MQq5ZwUXAf_>)e*n8>`Vv!P{XzH7B;mUE?_Icpz;} zdF6Hk`xx>rD;n`kJQuen-d1xJ@mP*u%SqA`$}Xn;5gAWjB|Qvl*rfH(~xuIB== zNrN~a25%?vna)0M4}9RrIE{~bk2HhR?x52)mGRhkkF+CaD0q)F6CUqGj}nrd0m&>l z-wfwBa5*32($#`j3tQL<26wF}bTrj%rjJwEh6b5Tt%6tXMq z*bO!APLJ}QkUgjfbgTn#Cs z$bEbj`UVlAM&Yxs&nCcmgUEgi)&7N09bk}iAV4_?s2vP)4xvXf!oES|P@f)r8AcqY zjd0!|ayT1tgf?RP=z=vYaiq_d9@koW1IJNR7dCJl?W=HHCvptsHm(z4292E?$J*)D zbt1%ki|u=6FJL=9UN!FsdHf9xnTBiFnb<7awpNpHgUd>JBSO|i3@#({J3ax z&NbN9`#YAVS%?au;v!kj#azxMx*TVsOMRv+ta4PGxQugMZq}|AYki0lSNb%eSJ9(H z^=hDc4ZyjU9%Y=k&e!)iA%nZP-e<&#h`50Yqu=GljlTadPRJTkMv*u9ipGhX>9I(h zxP_s*wGgV?e307h0Oby#cBfD4=q`FBBkVYFx35^7xJMh|j1%{=5%*~$<~vTPUR2!g ztLR&tc);g~6A${FapED$ZNv#?(1;Tc+v!!Dcmz;93V#_NK#0%%Hf_FLp zd&obcLS9oqp^ff)sL}6dd7oleyp=8?O3H(})7cK|sVy0^9=OhAW=<@fYzv9^b*+Cf zocq9F?L)Bkkxwh?V^H!5DEZV^VmS91rBTDV&)K^#w09|(^==WfjN#muhFM?1tgm6# zH!$m4nDw1DYy5_`fWOx|SxDgiAi4jMz5A({cc1$z^h->e>Yq9JFQEF03f{t`?u<%X z^PM*P6WJKvu6D*-6R}J(*Qt*-!Mro*(Yw3@-grmI%2)hD1a(MC56`veidjKNP0DTH z=7v{~b8gBvq>6ZFb`Bja74nE*`zov74E}xxe}90#KfzyxU-Q?`UqV)k`5~*t{Zz#g zevRbi|7%E!CH*##KbLO^{rv!PDZd7CX}<vwnH>-o`vuMY`q0J1lvM|TIVY4_4!)f>x=7@JCsO^Q*F zes1iC)HXpq1N^!JCySlCv^Vvm?;Z$$e6Y>$*L^n;qim|8N4={LfK~fhK>;>1sLiyy zXfnUlR&83ATbNBWBu%MdQ^MMmgBs%l;O zncOa1G~dz>kq(EkBjC+Qzn0-BO5D_t%+WDFUD;eNsrI>~<9R;IDHm+Df>EB2)J%$C zwkN}fY0_JqoES|7k)!r9`Bq%_YWm3uYn zy<>88l8tRDy>qcl( z5~>f_!#el5BVE=5j!ubFGxo+jJ;`)iYs?xL+SbX-*Z9~JS%lB{@W@-4%Ekv&`sH@X zu5LcD&eJ85bF47Y5zle)J+X{BYgy$A*hk|vH_OYD0^TtbrjDLs{kLh-sNvH_2Rx&! z-&_Cnj+`=@e)f)&_d2rJVh#5K}Mj}@b8=!+=Z6JO3B z65E&6i!uI~Vd!NC=w(OfWhV5p6ZEn(^x}8vWtLwLL$0j&pCd~&OOeJ{cr6g#|DrFg zS_a#3!?Nf3ZR}he&TUaaFV_DPnTmG57FCBKssu!pgs4&w)oh3=?bl-ovRCP;Q^y}V z)qKHi6dB2EmYwg?&fEP}o4;UvKvqj9`!7%{+(lL>xWXLJUf=@rEL^oG52bDNR z5edsBr~}y|n#m6tOqk zzfS=xMMn|)QdR5F&*XODC}KZ91h_wpJpkSu=+^=~h!Qu|C$c^2z(I=*KGY&Xr?T>n z57!&^Ahj>v3@r|(a>!465OD}s9qOkHv7Ez4Y)KgNVZ!kt4upBX_?I z-fgly98<>VkHNRmmbyPd)RqntM`{7=T|@xJ7~&`cy`zENF+lHFpm!Vua6IUaxadBC zQt3AQA2@NMpPST4jLpd!n-rWo-0vDfoWf~O1&;e$|ESY!dBz%_o6K=k7v1!^MZ3uI z(S=#7c@|$JKv>VyF|?MgoxG9BvQsr?4(cuOd=FjbN6s}j4{VEPdIvT)*I19d(Z+h_ zux|ZKRa!rKa(TKyHy83Y@pb~cTjA1l&yj7XECUAWp#dGjYxO*-tnjqNGx2t7Y$mr@ zwaYzi=7Fa4l}D~SnU|+4%3TX;hg-(>%EO29k~8u$^zJSz2w54@$&5U9Jj>lspBB@H zlc%G|bL$7jmtSfN5$g?!)5hC<()cMfV{FHHlcKZ~+xv+5|7kUv2ExxdEu_Jq#g^f$7BrI%P>NgiQE~C69 z7d9^UI~O*t@EZ#oR|4y+z`)gh_rk_Cek^QU3)Zd!KiAWvdtsx_Uf8&S{;C!>Ze(n3 z(%7UJ1?lI_eyHOX)N?EUnin?6V&}rfZGJ3l+zx;4fNgjB^$D$!1+7i`~z_Q2{$GU)MJz%(gm2Mv!&?6aP?=IP} zs#q)WY9pMxOEzL7Dxox*)-3pdSZwT2NtrR-CRL6x-GHhJ$0n0asT^aI3G-=;;|AL4 z)g}`k5b*=2sw($TuDS|Cxd5;YR%!W#=&|Hbu7>`q;$4`rtJT=0*m>z*#NaTBdg`k5 zP>w7vvdN^r3gfv3I5h|c4hF%*o-%9*J?bu@&y0!2Dvmfq*_X|#3^8&I&s-`D_=T1K=4bvf2DVxirPomvpwHgCk+ap3d}oGuE&%D`w}^ zsa*L)Ob#JwiP8#(9`$#79zAAKv$rLkZJnJ9iILi^znJ`uGBhz7n%JsJ>vd}oz6}T; zQ>Aq{)HV6rmWyOIj{k=uCdNu>jAM$&gW`Xz!4ov0!>i0#Igve>1P?qFdRl7R zQKbVPQK4)~&?C11LTbz;k*s39rP#jN+CDp?k=>JNx4#xPg2$5!R3ggq(YUj4Q9x~p_s znnRCL&^-|JT!^!`N;j8bt{}auR_MP9SX2twO*Youxy|iS(CE9W>~^jO-+OYxz0f!v zZGhp_#J z7C2h;Ez@CC)!Otkxn1~{>F_Fq>my+7k?`iID%~iKro>J4t`|u?)>JFo6HMlUZOL3$ zI@TL+3(|#yLF#6M*-UFZ*puiL$51)sr~Q`cSSl@X6I*A$Vw&iB#dMsVNtrJpIi8JH zub56?I8Fqea)-wt?{Mb}7-=S7!e^T)??vR%0GUaLQ1uQICu#Z#=`!z_PBySR1=yVm z>`nuA^FaUUAbX;V>@z5pu}@{ey*RUqTg6$7&e`R3(U_>;m7^*TFLv=^*zL(oyv^PcAx)B->BMD?kNZm4pOgm0`eM#47%(VKzuEmiK3@U2xC3Eu{8ZU+l@(4%`K zJlP%z-${Q}BjLLkkGnMyfyWrUM2?DT47@k_Y>6+rpA${kU@sX|2g7C?SirB(DjJ(i3pKhR&*%Hod< z)K40y6gw~7``IAu7u54>m5wN6agmk9->MK+euq;}14rwk|ZT5G|S638U_*tRasm~RwjqYxxYR%)y)mogZRJ+BwYBj{UTD2C<>eZV2 zHLA;rb4~iI>h9KJG}hK=q}YA+>Y^IrTo?7MSFOcK7CXDU^{b)F4dBm)u+3YobxBkx zn>MPha4!5*RI%#6AqA7Z^~5<)K&k-<@&0fiZu2~`nj$u z)U~WRgB{!`s&(FC<5Xh?8>mLF7_8PR3elsavIbO!K}#(?8Z+3zB2ulTvz=??8m)HC zVC&fa`U0AY&R`p?WQjFW@v>A^xf?Y9Tk&x%_EA)=Z zWQI3QT0>2myyk;EM#&jBfQikhIP%q=#coc8CT1qqu&1yyTvOOB>>SDkiODcFTuouO zWITq0&*41z8|^4-Av4(nHzNTK9YK*6bi4j@_1bCT=>_`K}Q9yAtP}~YA zZVeS|1I}l-I3Gi)^l0)w_hs8^Ze?Q`sc{;q6nxyW+BKaW&uJ$BRdQuIz5dSGTi{Ux zUO3oWIh&i?TIi6*=H{->*erWHg!LPb{EhuxuHFHek)d3kBHReq~H zyv!3%s&^4_Z>GD`>W*5yw1DR2fuq;Qt6j~_nbYrx+Q(p&P2I1_LRC4J5_5)b~YfH1xT6!Neqy*0Fu^f-FH&G z3XL}1GO6!uYY}njWIG$vp^dSF@{ZL7<2Pgvctt{HPjdDYd{KX%UBdS?r|(31c`l+; ziy{LQvIYuWKw%f4Ab>&+DCCQx(5+FR(-6#B#T@BS4;whQ0FQK8JUpUTX5W>w@8-h8 zBX%!=#~z%1&tiC>8H&At$KD1W`v8x9fyaKpV}IarKv6snEWpFARU9N8I+zVSqyUdS zO5uThc!$ao4&xFIhl@yYL{5=WLoVl4T&@OlMtnzUmc+i^O;S=jZQQG%5-x#F`>v5Z^P zSBbO1$T<|6SBG|xw@x-#{w4jbP2ql;qsqF z`SO+~W2h*e1K7_SV7~ycUj*1M0qmCn_A5ofepQ3LOohCgo2wMBN!MRz)7~gR`k7Kl zTmR$J=-=dwZ^0-2gXz67b$^=^zf0zx0tBhTNLH7XXLFmODGZgCBwKeatE=JB7gGoKeg*4D40a324Kl`L_4 ziU25_$A4)s{S_?!8ZLbUroW}cO{?2h)72lXX}ViBn9YgrC>{A>Ptd=o)QM#ix7!o+ zxNCy`gPlX!CjI@9Em9NopV-l#!P@E;Ya>+se0L((@0~bR{GzG*tO#|+r2ALH<=^1) z?{N7Kxcn!ms|aY0;x3N*S$~q+EN$On0ap9s0kUCDT64Ln zepYRxSSnD?XG5+_2O!sF0@_gzJxU~&4QM2m3uvF0r$@cqR3EGrD*%NK7YZu|xQ!}} zuEfT#tc`CfZmHDhDps<@%PDfWP@}5`K-g+9b9MN!MnDs`CM9m_kvH1VHi+&#Unw8& z%!*!l#f|mrwqR#(P#pl53&un|n8{{>?cEu^3OSaRr)1|vuhq5FnIP&UkXSI!x8YC( zHnv*S)>&nxyE`*Eu@+fE7}>30ZL%lfOT28if|RQjtYha;-b*ak4H&IpJ%)09=zu;= zs1Mbu+goV=L3f_7X=g9xbuRL=|IS{o?IyoycDfmm=TA#N`PKq?07uNre#)K(yBuok zyvomz*g#8&f4AJ29#_X*i+GpFwsp5sT}c{&W-SXk<^5~&X0_?b%#gt~Lk3SB zZOt^|@>5a%i^uxQglTmYc&w+$Sj#QD)OakHvvCd>L60C2jGhTWG zd#oUp4_eIe1rF_5(HU${#?x&%F@_2vFYSJ2TPiN`R^kP_pUJ!WnXz^bWxPaVT)^mO z#xoKVz~p8eUL%%>t?;)!8|jUNEF%Ms{Uh1Tz`R#kNvF|tdZm>iF;P=Lya@G1FEPo0 zZZe>o0_dg!x@n-k2}I{zL~lo_<}DOArU&G5G~+WvfWLV&iOpou)_0 zMkmM)E+%#fxMHJV`*Yg`Dcaw|0!&jfzdY zk$BOLk$bpe6Hk_` znNyBd6)~XA#N%x|0<~&uqeXJ7Dv#60NJtz}R=Y<3aipQ$qoCcRq1|Jk-D9EM zpfCnJ^8y&~oQ~*l20hB~aVEmYSqKzo)1xuqsT1cQbR6Ug9p?sI1D^BP{`0l{Wd}SL zSjiI4rO4;P0ndd-pt}f`UJO?*L7=;o5;yIXZpGuru2h54OZxV{+$Q zJ}xqJd-vR~w51CX%+MWa!JH)_Ym9_aa^f>SER z3EGtbV?1;f19mkCZ{hJnoi%>2d>NS6n{lKS?$i0m7q9ZgJ4X599j$!vvM*lgi&2U- zCA&uJ=)592G6qZ68a!MF9JT;L5Au{54A4w3Ri3D-3J(!EjK%)k($X z#N?b_zR$_Yw>A7)lBS29y+L{uuT#O~wH@!?pyCsoC7!qA-LbBC_okggIU~_|D`3RC zw;7pt!0b2<0ri&fifFGs6b`7D6Wdx=Pi3oR=bMwS9BixU1qD5Z#JgG=&liz~5!v1| zpnV_EegJ4c1hgMP8XrRl$GU{@38k91NZk4~z^&*r#_w~DUkdILw2m0|1*iQIScfd5 z?ByD|a#*$4q88SBr%tlQDqodF(+Eyq8)$w5G`|I!-vQ0ccYKRsKYA_b3 zMOCvA0T&;iIAqsbS^>E!Hqkj`okX0rKUJH4)Pzd5%0{A7D?Fh(JXK67xs zLXKs6?N`TC1^?1Y5uck^zZNTyodlvC#8xD06IUlbw1e0wt{}FOokL+G!CpCN1hG{Z z=v6h)+n>#?y`fBNCtX@IfCjXDJ&W)W4BpB~v>Az3Z5fA3zx$P{M1nqYrtj!8u6L_+ zT9AH`Wfdwv5c3ig>h~eBTF{m+DWyzgT-~654bZN^H-Sh8K%|>Oqyr(+(_A9;agnUji4_Z- zJK>j_s$!i~Lnn)(u7HMdL)NMNU1*Ri5214E9(0GVoz&t@R^542@9U zA_pNvgU&BQ>w*>dGPE9iHGsuILHC!TgM;`obO@Ml1jj?^(fwuUY4(?)o6%p@m!X?8 z9$RQUQtZF^`~m!Tu!&nVb7n)r|i6B){;t>}@JM`+MN z2wMkPE!(hxW3+*Gr%r~K`ZRR&3VBq)0*42&t*m@3S3XWxz7R?tA1p4+30&30U`b(4 za%3zc%*jEAFsB4fVNMMe7v{8}Q0xsa!i=GwmY^0US?m;MYY@V0gFkWD)*jTtBr=pu9YMD+6G8dm z6dRZdx`j!GmlEcYB%gm)e=}QplV)!^wKxAnQ!_zl(=oPZXW9I&priHZsmq{7v5U@I ztXnmvE+UAjOD?Fzo~K8txNazJ4%E{_kH*wxkeD0P3O~!$(e`Tl)zoEIwtu$*F%_M< z>~1AXJewk)3#Tr71kpD3gr$4ImA!*n{rgbjrp=QCyn*f8iBG_%G2D!#vxdl%hzIs#KBq$yB3jxF%3Axfbvj4c^IHP z98ewsDI5vn&vg-h6s0oWlP?T^jt+7QK86uHRwI^zp9cnAL-pf0?eRc2X<0LstFbqq z=eoPPvLf#l$&N&x_UX6IPV#|=%7%9OS`8<`=CdB{!Fk0ERNGGsi1Zir#%}i zIfB~YMsZGA9F3rMZV*B3Jb-sTJxX*h0J;|f$BXFE2x^1H#X$BV7qXWGT|w2xd@4h{(p3c5E0<>DE- zt1cJ|(hJI7x!977x7p`O$ltbP=Zb5oc=Fwjao4d$W6A&5?J#$#E6iPQXHs5Cm~IFf zVeUqT=q6A+nZv?h`F41`wB8#I4dF=P+)<;fxB5}G(`#FA%TNB+vOXkk) zcZ&h^tpNHq0DU`vz5_zJ6SBC}C5yW#)x1UL+ucEKSobiJ_i7|l@cG7|EBxKZY3~Q> z(=E%!WwWz$US3~`Y3q1rAeq=;HTj%(;@FUPI$y1kwuUP4E?$`FrJ1O=y*uA6;vPGr zdjFFPi3iGJZv?vs4eTER_74O5M}YmK!2U5{f4K|$$2Ing(!(bt15YxlPk{k=eqYcP z+MedL&wv3(XdBWfo-K=-5!#*$BD6gZs9vB)iRFvH@+F}5GCdlhZHRaUI9}z#@ztO! zw7tgmzpm{s8`|Emk|mx_kM00q*08MBdZ4jdMh(QR za2K{BU2V|b6hM5zRCWg`Yr#2Mk zL6JS-@D2)vgOjGz>UZemr=@TBX~&GIlg9-obKD?5X*W%*k^exBdX=NRhc_fX(eit( zi2RIz`KdwQXQ1zM(Dw!C`x5f|3Szs~CAP0A)x3WS65j;5aevD!eWzJU0ilnAuJHOj zr~Ltp(z|tgU$!IiczwBeoF6uhGz=abp*LI2Bf2|wpah=H68U^rV@-|qcg_(~k`HA? zN6i+^v-~0PV_BYz;QEun)6d}P7x45ec=`=I{SKb4ck%QG7s*8V=f^?ur-Za3M27VX zX_)4(l*K}}>)$g0sjDRVi*vC{pjbNerthGNB|{pt{!~cQ68yFQQX#dXVwWVAri3?A z4eMFIE?2BrCZw_Tgf!yI(xaqgxsax0`H%*Gg^*s6As-d)D~9a$;V@^V5Tm*>yT6Kd z-;T@#i(ZzwrynDxI-^xN%W6PuL#y1s07|S*Ry<&(9^22b(A_(&!3g%ZrU~65Db}Ps z1{P~sk4;P46^OM%bV{ehW*uO&F0fe-*sM>F8~39R;uS6%u!lHm!)hKIN=&@$;6`vz z{kbyal#sEYvN31b1X-3dJLuYQqZptw7i)S32AhV^Lk|S|K6vPdhgI;fnjX1_UP^vE z92S9)ZjCp&T4ONe>Y_vJK}~@WigwXqs%vxlnH(?drE5b79}!p^g*$biwVo0;P32x% zcgJ>hX!)s;A#ZMQq&TV0*-U^|m?P69S0WOTxf4AxN4J%hWR+OX_8dR^|NwOEb zIYVFI$e+v5E5~d*-yJPqJ&v5Zo!9n4osqbi)(){$rhDDozJ zTU|mKNvY;7dLKuHxb2N*WVh1Drr>*H$klOf&1ts*3pY7>1o^R&(@q|~C;2isYt}@o z8FUGpx1BfQ(pzDVG>axvwz=8Xe4Nfmw7UIH-c%U!PEBT7rg z{-1_$veeKN*2Pq42+(e=HKYRfG)~(D4LJjMZKK$(EH6gjo*qKr-X3JkphxwR2W;&K zUS`sx8Mtf3PN3>;7gallT!DKQd(f;sC>ywARM!^tGdW%uxLXWuwZhsqxD$uA+9`3< z@c7((Jkv%uujg8m*7PY66R}o4ag;agbi_rcHKXe8Ovk$O^7IE>pwT0;nGVrGWs=W! zm`<=6%l1>o+L8J`SENqb`II*jp;X9-)Uz3#H2B?GMzLD&Xxr@JQ%8=m<^bAkIpyD) z&Gss@`C|fHMZso=M5mUFB1(7JpY_l$5rDhGl&=V|==5m8TBfr}ci%@HFijish4Y;^|)Zg=@TN zJgcIQ-ZakkCiMb$yv@@h6N`8&oiAgr<=EzR(g|kvvUo`BT2>ZDB;U=D#qN;B9+1VJ zki}k*#omy`11?$Yqh;~`Jq`OxE$_$r+#gy7J##~@-rxXEdmyyz>D%FUUf!-r#8V;27;e+1}t-s%seiOpX`! z2FDrtJRa7b0C!G=K2M^=P4%6z)?hXloEyx=+G8TAUyNGX%5=nYLGImSX|tQiXT`}> z4*6;K0H;uCiR;)pJN!T43je3tnUwhwlG8#)_@BpcoDM>V$zU1rj*qo^CrmkAy_<@h`N!>y9wpdk$Y~~#m$b~ zWwu4#LIq)4)UDQ!*cNpg2o^5$S+p_R0dNJfwv9Xr+5?B5*DtC6m(MIu#&Rnd$8=dg0A#}p8g|ysWr$@>8 z8{qs+@b?xynw@Y|ydBaad)5^K-q9YYPWWB+;JpGWi*~~AQ(d(8J4KEccETTopwJIt z?MHCuTUUPR#c#mq3kz$uK<~8jJ=vf%#8N&p7r8zmCHM9^y?sE)PCHClhPeC1b5YL^TlAvb5|`Ll$C zeM}htj?Ujnwp+O*h>nd-oHbzY2C#mqO3tcvH;rOQe65?zyG5FeF=qM3klVMA+jo%L z_mJBUXfi*deZ1gmA3ss5dH=@&{yD^v^B30CuUb#C4qY^w4eef0X6i7#96$a9&ZPIqz4aIbWJju&<)Yu146 zwP5YqaAzH`y)GqgO7e}FGAcKyEfRL`kmZ*&Dy+Nu6Y2qITQX%<_izSd?H2X&-XS{N zF&GQBq+^-cv~|K7?TYoNZoC#tmzXVDDuJH-ZR+ zj74?wM0xK-_DzKr9apmaUPDC#r*krLDDU(wqwF0IjRNxQN=x$Oo>#gT5|vtNL~5Bp zys<&kCZK5mXxbDs4TRKu(A66*UHK{1y#J!}RW;mrtC@>{<{|}9yfv;M8RWDf@K%X+ zt!{kd%N`8UpZbPGOxk2OHM`H&`Tn4kRLx2mM z2-diQS|g_&3S68)t-eugRu%yxsBK<@ptc3v9!8H6mo0(Ia3C;(9?hUuFGd2CcU+*1 zs&NIi(d@xi+Jmw|ZEGu8;>HwtT^P}}F(@1ZQ@4dLV?p6KO5C)u8hWY~aBOnrp|f1O z65}Zsxn#$p36wYSOX5a55WVjTL=){C%2M@ut;PsMliBSlAkHt_V!b`gP$pq_Cx37% z7k5Hps%CX`5mt@(G0gy_37~8TP^JTv?ZN5{Q24%!!W}4;-oev%n|G{XdCz3echa7x z;LGG1SF_)l)6R0DRM?XAr~UQ;BDJANC>j#YWl=I(f6PFs1t_%wr8b}x2TJWg=|dMv z9S)TGZgWDSlw{9SKncF=T;mD?vpH=VC^>^bL!;;{3xp8_GBpSSS$N+?j}o3;0FM9= zIeIjMK!eBwn~z=Cbl13oz#R6VM|)5<2+XyTCGJj<*M&i#*I;s2n7SK$*&R&oL5Z6( zCFaTM+<{g;2RNAvw#75F&Asp>l&mmk%XB({d77}89pv+=gYq`}oY<2LAav|_vKN_= zxH56K9Zx=U#go159Lj0+lBdRqC;Kvj`#}S9W!r2hG0Cz&lCK=j{>l3}$-hcIT_k6o zE)w!i6y{`WcHDV{ub7Rqx!d^Mk^Qya<`mJJ5uOe(=sFN|9R#`#23?0hZ-+u$pSi?! z7^Rx`Ux(oE8g9o&FfT`HUQ&Q&-x^o6JBrgD4GxWQLu(>V6H=OuX4C0x4-L4wvX*Fb zjpCTHXd7YfSOe|jfcEh~`vjnUBG5hwXn)~C`(%xFAB{al;&LkcdKz$n6Gv%WMlC5{ z-*DQ~b=syf-fq35_Vx_UFvj`?Us6-0{5lifo<)xmj$s#@ z-@;34CsaAT;V*J?qemTJVIJzB?n{&3kjQm=KE9E^E|srbskgGqOXj=PipPbTw|PbA zmj z;5ra+JqWk~1l;Io1QPq3xGZk>>-`1N;^rD|@wYHVw}PU-%y^sjjOexEL6v;Rbvu`I zhc2nf_VCUcj9%`7TX)y!W_}O+z84i#137o!q|=dC`0mC zAta9*q(1@Yp9DHjf%K>8k&K8bV4fk|3ygSH8$lySynB3(jd)%gvHd^`fIc=f@j{JB zc9~a_FH-qJs#zk=^O&iTD*g~aZM8npi(LFP~NC=vY`i2gz_(z|Tl zBmS%PQ>|R0qDSfO6lUe=3+Q%YE7Yo~7epiU1 ztYE1Md4P)5&xpmtT=EiJ@{%aoOw(T%sen@rbSciXG&0czv*@|RGLC#@+Mp-wXoJg! zD~xRc%TX!DwgBsY70E8KeAw9#SD;MxhJY2rTCgjHHE}D4-K}tyFk0cNVa?@gVNKTR z^jNYLu0elQ8v@p3G}h8+q}YAw;M!rd!gWy3x?$Z4$ztb*fc3&?fa}Ab4Pe`bVJ#%0 zLfPaE+d?9w#!M0$g_+_?wr^u?pWWEV?owL;!lZ)v9Ds;TWPJm;zD;#~3s%^`aB=PV zxO6{CcOTVL<;Yk@eAQux_yS>5e8F%<(W81oVW;|P!iM_7V5>H))fWl7)fWvzeRWVp zJs55Xms8)MFw{4g@ff1RD}S4WCjkU{KdS?5+<=hnK;1ut-$uv3O{X{DO4 zjp2H>MLiu>JyYYY-6EOqwfi7Gl48tgQhtq9(fDMm$mX)`d9O}5GEQp>+$8eZtT&PD zNCZ6jM0d{HlFrIwFytyi&KsX=Ws;_i)u#Q$jA@)9gYl5Tgs_(AL=Zg*L{AQvm@!SE zG-}2)l_8k+-+`b>LqJTFnX_zXKrkH;Y!3)#0D>I=!Hyb&@!#65Z>CoI-|6a3QrSB* z+_N;?DL^natlE$v&}L2^13PC|(EIbay}sn#DkbNt#tLnyJD>gwfCxb>f~`D z?+hzq^D%!hT8FVuaHK62&0gA1nDhDuhp8FW)kXct=;0GxeBHTjKDs*^4LA7h@1QG_ znMzJsneEP3s;d+DOaqT->8rF`4PM*8YaG0`gVzr5nkXghq#^ATgEt%Co%KHeo=9u# zn#;F|P6N9Pu*(9wE?~C{uoGw#-`i~>$7OM&7_m@55_zfjZsuSPI9N!<_h^(-VRLvf zm+R|Aeam5Z!HkJr9XZR4FLnz%#uvMX&GE$^l-C$v&>v_Io!B$%9ANAfHU=1bgOGhd z)4pN%0As%}1{nK;+5I)R53&sORvo9$=8g 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 V>5}v^T?$U1F$I@`^z^|E{s)}Qx6l9p literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/glossary.doctree b/phpmyadmin/doc/doctrees/glossary.doctree new file mode 100644 index 0000000000000000000000000000000000000000..55feceba133f1104a798dbe568da3566ee9b30e1 GIT binary patch literal 120004 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 UFxs~?qinAA9c@E##j5Oo02tU{d;kCd literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/index.doctree b/phpmyadmin/doc/doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..9ffbf04aa85c95e55740bd1e306204c83b18ecdd GIT binary patch literal 6400 zcwXIDcX%Ad75Bh2iMHnN%U`#WDqnO2_h|}KfNVC%3?#`Q872v=I zENpr=z4zXGOCdcW4HD85QbxjyJF*nG03YQAx@D(6y76O1ccOpf?B& zVJgm&fZyUJxN-7y!V1-DBE7UJ8(YzTl!2E$A&GN%$t7Waxh&4!$n z9|B@zs#ok~HrQc6nx)vgSL}n@T}w(FE$J0$vo?Cu-YYsnbDHaTOf2oL#WitS#WG&Q zktfS1$KoV5iX2(-e@TZ<%*wt+u`}d5k4Q7suQkkm4Bs138BMAdZPy%`sUA^O+XM;2*;4tdKA5uIF*Q*KAjp*lS#* z-Jxh~ZBZPC#&k2=P}R)hG;H6@4o6(8VqCRal{kV>9jQ?rMX1&hs-p>2H$gh43eT~8 z#eZWigAqKgD2_*zoJ_C%&(j$mCU?2u80?7%aLm&qcWTu31C?8ctyJg#P#-rs4 z;iBoH8=U}re9SDcl~^wjE|P=PPb9v8(-Pd$!-VFBa6bH>HFk%VL_ z48+E9u_@D2hhr?aerG_OH!jZ4^i0Ev5WAJQU|ej@^i0KJza_-@xVSLWlfaS9hMDVQ zprqI`F1AKShM8ykICIgsxHzMenD>J*a0a*%myC-`BPr}HwxguDY+PKP>1n_j^bmJo z7!y~Fiz}H~#~s_oE$^zWX0zkv-4J(dhc?8kd&M;=el|acZ{+9k3-~zS!Y|^N@XPoW z%xoxFqc#f^7uR;z5TlwXQ`c#(urSA|^0yVm^^+=}>w>>QbKyn`>P-~mndFO#q)Fs818}X9)STg!ehZyP$;k`R)22>C8Hc6%yhFH2-2zyhMSTjyk(= zv+L>`V4kLXpLiJ|Jz8oR<#pl}0`#g5*lT3=bwcqm!t-$g@QKQ5{3NH2^hQy9io!w) zUyQ@98_%b;md}uu&ytqUk(SSsmM=tZpo%YUSI_}+8F#1bDB?|sFQI`qi{i^A18>BL zn=8e{SIFE~Q)WF5=pZY;rYnbDeO*tESm24bw%{QR1uPiANWUFbKpYS84gJpc3%K)% zZ|dbz+2S3-{4GNNZL8FQr`PAj4>*+F`{CpSu|mKt z>Bxlm5qkD+QT#aa4DtU&hwG=L@n

    ns)3x{*EqPgp#K5&ly4a1%dh{S^ZUrF?o|L z{TjJj<f-<9b1E;5#SaS4I=y{2&V$B8ZP7sVflEiGlXNM=Ev_lZAFaD{7v z{7GZ|GhzJ;A^IyJ`WqqodnG~sp$YOqQT&s4*!?*eh}*=CO|#CD3bvia9H94G?I?Dw(z%g?~NRU z1Ws1uADT)lFz(PCLu!d3wvuoq7hpQh5FKC!iJ&(#WAttGjQOBF*nuW6^RT1#U{=`! zL_J#%P|HrSmYwy)dxHd^k_E5}P7o1bP7G~sY;T^9)|^3#51E@!&lQ!PF2I@1n_!_f zpNz~CJq8JoW(c3m3)oc)?-mJH_L6w_=!4zKPBlefkCHo!Vs{qD@!K;7or*#4r9qcT z1AEgv@&@+Nc9%qU2O}GU1g3&RkS>{NkIi(%W|qcgmc?e4M`pT{WMhR9GpSSC*tgoo zJ`*-HpH>=GeA>^b;L|Fj#HY#)74|o(8P#P}FzSF9+JQ0DgN(_HT5ZIPIym;~kl2eg z#ss6ZCx;p_qt8shF+G9(FZ=@We@tac!Og{UopVKakpW% zRDzX|(@XQTw55b2LTGF6nf9JOV9>2B8*OY7`t`B_Z4nQf3b#oKoRTuJ8})-e<=csq zEjOfFyMyn27}R=)NY-pC2ZgT6=;e?EH^R9C(03U-i^o3H!Mr>kf}x;&YKHziE|4r6 zf(ssjn9G$4x;i?P@1tdhss45!20FMZxE3BnCq3 zZk2f44zlshUjpda7ChirK$N7gmQLnlpmgY5%NqzW7g_oy0U^!RFb{^cWgD;Cn1ez9 zBQbuRqpVBkY#1efG1us+#5n2qZi%8; z7hQ;8>qO3x+{2D^ln-!GWGL_Y)=-vVZ*{YHbOfd&ez7Lcd|XkeD(Q$uS^Y%_F3~}o z%DiE?R4a=d4WpTJi10Q*eH#!EMbH!&+(=<>Fk7oh3OA8p>zd5^b=jU3?Vagm z`>$LDH`8Q&{Dl^7q0#F9?du-gs&QlEQfyRFZDW!Y+@>?xh^JWw7Uli+CF0jDZ)W` literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/intro.doctree b/phpmyadmin/doc/doctrees/intro.doctree new file mode 100644 index 0000000000000000000000000000000000000000..43e694b1fc9783e31c6d4c92e39bd9a8f560c39a GIT binary patch literal 29111 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∈D*;rcmHgM5M&5o6Y#$Tt#nuY@*2FfW^S0|Hw^(1x!$=4`XwQrp4+BY6~ zP7plP$cwX>D3g7YDB=ck**?JIw{Nmc_H9T|r%?WlWMLnO35lo5u6?s-v1u~ew=qK4 zM0V{1P?h%e;@!$?S2kUA-V{4;COQY2%#f>$%bD0=7Ij$FHP*KbW}CZx0}juYeGbo& zy$)|7`yGZ$Ck+*<OVUqNr;3km{1i7|ADZrvZuB@$G%C-lcGEa!2r+VkqNHPAr6%r zUXX5y*#%Zi;)UB-8#A-jkI8Hopk3#^9AE9&PaG9`GGQJ(!^AX1?LUrfa|)oH3P6`d z^%-Pwnk-(17Q4r>8Q2cTv03Dt`!D5e3a7vr?=flKp=}XuMzn3BT_D;;L3`dP;M{?| z;!OjpkYt^r)VffPZjz&F%UuMftn8hccEx_XQNO&(B;`L!7IP5@3W<-FaV`SlC?z{a zMx%~J5XZ^xBm}T3C!v8bTLg=i9WR2MfI&_aK~~cAB)N*+Cu7G`-rh;AMA+El>O$PC40<2n-o1q7UrKT2hBfECiBlHt1ck%FO;jAf068(e=#z@ zL@-YyK~CpVnasb8B3>?+%?CVw^RJM}{3{9SRh0i~S(p#d6l z?A8FFtE>S$$FkBniQOQg-H6d{64Cys&&_g`s<;Is+)5FG2lKbNT>`~$yX-55J7jM$ z+$mSCJK(u2gtDp$%BXFsx|Pi?AE{|$n#Ob zGmX4Bi^pWDfyXK06LPr*0FS>0o|LHuo+7AEQ~qaUQ3D_*Bz{(|@gB@SC!<-CQ^ zw`IST@5ml2-z9zClZBP<%RwtYkjcsqWg+}WB<06)RVzP{T`NCDo}USxY2?LOd@hrf zUr@v^<+7E4$8Y6VGFkaGLH&mEe=7?sK}<;eom{pOPO*J2qbWZigdb(sN&r=9Wd!ZQ zUGPt$=g-*l7tz!E{jYKrOMk=GHK7ViaR)7hR%WRj@>v=Rc`XfxDlLWGvl8-K8VPwU z?GX|>^$ZD1dxe6QMnhz2?~pK{Pe@4GH&oTqej(S={vqHwK=4c>FV13Mh%6mM5myP7 zEd@M&OIHn%rGp9T5X!$=NLczCSvoXSwiI^G!$N4xaD*@-e{x$R%*bZyxv4~-PQe5On12FHJwa!UXPiYz`O(UflM`^~3H1lGRV}j84k9bWK z>PR=AnwdArG6W5CihMIx90kn2z6uRLS<^|nzm&{n;TzFkr zMae}D#l=K%YofRfQCvb4mj;xKJ4$Ygptd9EB1d|DK*=U2&GwXL2THRerP+znG?S8} zA;-=_$-hiAAw+FKWU3$8wn0%_u~m{pZRWX(aI<=B>!QZG>s!0)wJtRa6<@pc%-Lh= zVsv`|-ny=JIX7v>;Lk5bZn?{xdfN9 zjtlvhOUH*i%cT>D@QEbANul6!>EsYCmrfzAP9<$l3k8=;sM6^nce!*1@;p=UOd~JO z;;ayO!t2R4Z165#PKm(C5*a_KyRdOqd9AS9McASNWfFjV8coOMwMow*nxTp}Rg zatT0HE|*|u_Q&;fsR()*2E9Dw?&bfu>lGnSA$S&9S7NNIC{`m-*Ho6&W9=EU6^1*^ z{%ZL)VYqD`o@((Voeg{e6kPE|Y4BjBk=yuT3c_7x|wV`7R{W0W?}8)|JvPD@4GiaC6;&#sGQ zjAdGko_&DkGv_awSuf6H+A$*wt0E3RWp?J^cE>Pe*e)PE1nr-dK)2a4qxhv~D#^f_YsJTZNNn7&BGQVTR+62Guxl_b%!8UZ7ImcPixr1oa_77dg_e1#J4rN%JwK`GnGZN@+f$G@p}AVE!lu7W z^h+V?SBUIuKe7*kqJD#|z9mto!2BVe^NY>R<;=}zdc*T-(2Vw6Y?;;#k0SAf1K+Dn zZD~`jiHXTA?7J!gfA28=ftdeD%zq;0KNIs`0s{Z)2>crYtO*MmB1ih0fWT6i(#T5C$k8J#Rv+vCHP)@NrD9Y!Xzh$OeV|E16Zoo|Vk1B;H^Wb4WP2 zl36WGE199B`!LdZcsRI{LB&Ue-IdJh$aN$ci_AEWQI3;qP{dfcypjPtxDtew3=ms0 zObeOOgmf)RzjjzGWI#{IyG|H~l85-ZVf1i41W_Ay*D?Sru$J*GEyiH`v7&v`rXJ7n zI+sz0PXHU)JTp7^Y$^`owXTAevkiRW$TMihC&q8s!qyL0j+#10gnAO8fgETgp5ut; z_^^M}ObFAcnTR+ik+>p98o+x;%?3`I$&_Y8N;8GhY(#0MiZt`;Ajh<@7&YVn4tch* z(0vocH=T6+d!aTJtR{xNBWN=WJc9!F^Nt{)_e{4}U((Ncc90tJ{0!1P3_F)`DUgkT5(aaqY#ZF;&5CN{0 z529vlzq4rHG^@sa$P%6y<45d#-O7I#w^_sNiH{6dKJJPWtFr)MiE!mWYH^fMNr_gn zAxUIYL{)k$HIBMk(+1IcjGq$$lZN|T{9SxS==Y39{K4pRvFPw~$S zGb{wm{D9lTf!)51tqNgx{P`gSlfx5L1$v&68SU+G7PnYM@D4|bPEw+al;|cUb|EEp z4G6xQBX|js?N0bbj`iI*A;B9U$G$@FzsGhzA@BYOZ-pOT zDJbs&*y=!%SA~RTHVbdSfioEVh^(dhOOB!&>xDvoYGY$(XJ>=^Qk;gIR%q1Ctd_|0 zR*kr5&*0;#Hnf`Fl88pxK~?NH*wN__(&i=9>fO5p4i;pnNz@HAprt>Nhc(NXAf z<*SX#&vKm+#!2~140sj=gol*>agELfL|l|}AW1w7PouMQ`R~8;{w#JL{~jMPEi!|h z4~-}B#(xI^yMQFWkSw?eesXIrCTlJsD=rO-T?i-#Zd?||0r)#0FBhI%ff8OBcK0Y} zhG~z2ds=$Z?JC@;kL03XjXka*(KqB7{-(O@TF}Y0HN~zA(?dH*qgEdS%3qJlJ96H@ zKcyX2ZiJtM@u8iYNSK>Rm|IAgTj6I!#bOA+Wz2RP-~D4o-6pVrRRx{$yCU+cZ40VQ z!w+!2#b80`EEWZ-g;EzkUZ%4D%jxrD6=yct2H?j1_?Q)Ovdcw z!?81WG4gx^-PS#Zo^kfvNenk@ z(OQ&OBwq9Y%VLYST#VK11ll2Ew6?^Y1LoS6mil`5x_%ef-ZBP4HkvHvPfN|CZu8b% zCh*n`vDjjKUs^d}R_*3>WSio3YR*YVuEA8ew`FPzSEa$o87&R$n+l_QI;yg7$?ESw zPtT*R-^2DHxOe;kzkO>qx`SD{%m>mRcc)4+}%t+$FTln*Z?wYAQ?7@3|mDQHg5*FwW=bH z1mHabD;1s%R&XX6f?lmgUj2TTp#mk?>z;-hh5?3C0MF%UaFLC0y9CZbtqwihb5J7{ z@8#%GO6BEfu0C5s@t=T-DV`HhYmz9VNu;%u;0dU;6*>X64(Yir>9?K|JOPDD)++7^ zs4>WMtl*hOUYy1Hjze`6u^u*v6HtK1e>u8Ap)*j81a%zcAFqhR2M`m_ZYnj-7BH&y&z!WZpe=4OiD%o&Qu%$cOnEJc{Pxe_#UwnApkA?dduF}GBznmJc- z&D;u^&J#@2NQ~2%uaKDwDB?n;Y$o9Go4H6KGZz!otttODiZB!8gv3h}G!uA(kZh@f zzQhs3wuCsmTCRS`}mm7tR;g`Ct#_cl_pU8(A%uDDJb$T%$+r;!|| zvP>Z-GZZnal$``TekXGZIcXBqJmt3(;UvfkiJ5{ia_^st1Yg!>9 z+f(uTx?J)2x)+JHw<3JqM+y46uR^}=M=tD7x~@>F`g(xk`g$O8JxFj(BQrS5r;x9Q zP{c!(vaf*0@9SX-`Fc1(J%aKdsR&;|P)K}~QsX?!gi^Aj6*T7<1aYk5nhLNgO@-%- zsx3#@aU#y~80Q2LXXUL=RH~SM681e=so1~b0}rRTT>_S$s`xBFP4QZOx>C7+g$Ewa zQ2d6Usdx-Oi&Q*Y5r&_m1Pwn|A;Zrjd(J1pFHou)exc$Tei8D#Sny0EFV5l;g$%!x zB3`DH4F^1a!!K9J@GA)Fm6ZP~MHmiZLgK5H8t(%S*C=SywFu!l#kCtiRoXog4E(+2 zCA(e(ya5B=C<6Y8ZZ|1a3gBi8a*I;2SH{&VyVdOzsDRrPUj^K*cq`xzrE;$f%U*V; z;xB=_6i*4;n0gw|CKcmz*du0%kJ*%K)&mo5A6}JWeRb>sp zUk7lH9M}t@_lwy3CDA+B=4Hj>ZspsNIee8L*1e*L=bSLoYZM92)d!AF*z2Uv8;(A2 zl0I)K!ko8BfpMvx zu?X=AhWL~?_?vv@6~ig@&#}W7%F1?dU%H(Fwf>djtM#uHZ>@i$tZWDOt>Q2C?-Wn5 ze^2`TKzjbD1dIJAg^K-WlKvNx`d6iDvHzyH#aRyo={|+u1L5F%Hh&~b5WPtVi)gG;7eMRqn*t>tE zvf6o@0THjkRMi8q#~|v_&s)`a5Y1MJ2pv{+bQnxJ42cL6RwJfEiRrM2zo>@`rct-3 zd0;j|0A3x_kMz(TSf*PpWw;CNuN=&?Q6l&n7(7PY{&JKxtLZfwW3E*O%#~RiKX3)s zAw|}OpIoW+NU7Qg)jphLU}N|vH6CUr|9vd~Jw1kmTR$LNoe&OgdZ6dnKoE^Y z%-dj`z&yHAL|!{J4ZQDo>^p(_;?^=r&HEqFi}xNwk$uv`)j8 z8}onT1ATwo24QT1-%bz2iLV+6BN}gtjW>f(z4)vluE4PwxOFBdI7OG^eVo6s1AlIX z%|h;j%5s$dAP?IdyUmVNz8=@^whLOhWt7c{U@ANy%s(T87Pw zIOi?rM?_&QfN$v!-LQqQab2jdMG;Xzi{Weh>o9C<>>Cf`+`A2KpSy6*BDN#~HO7l; zDfEF;gKW>HJW8ziD zvC;TW;n6Vzu1XY~C!>;Ds)6ks!KzLml9n=((P_YjWvn-g-CRGvq)ZhJptN8x^BQf9 zfKNS*l=z!RED1t{;(fgpW3yBQJk$8Uc!p1n_jSrZ6i6FFX$Rc~7&&pFB_W8|Ovla! zeA(013h>~L&C&qdEr2#=!mGhk(QVaC5w2h?rNOHVxJvLAVH274;fMGMxcfFyWEqwR5F_YXbHOxuWdOjm&}; zz2F{R4gd5Ii@+npeNu@EU`}5CTls?g_%<-*Snx*^Q@cjqf-e{;=2G}KGZlfq>0B>O6mji^29l z9x1K0*v|IEj03c6s|Iz`ozd_`25dRsen5PrSuEs>g_XtMD}sZPLrWIe-lz!tv7}rv zo9Kd>g6$(r?GMM5iSh(uvwelUyk_7!8a3WeH0}rQ1BYBZuBK+${@8Xf*akZhFh9Wu zLLRQpu@zW~{JZ*f#!X7G1K{I8t;;CD7$_8NQt?2cVnn=io*m?R&WpRlu#JMr*uf%E zGGnUC5*lBEWfE#C1*e<2;)h`IjO0DCz8O`NQNqrHu!o{(AuZRz4#QxAc;42EDb6yR zVTY64{J@LXF+3N^a(oxej==4MKs~$Iihs(9R5=o3_7*c=0&m|xO2CKV;3?#zMaF<* z>=-n=SZJ%C!j6UCqZA4T(QzV@k@Iyq9?KWI)Z1LH6X0|IM9Q$?&guk-cp~=g#iyG* zM`3ialb{)lIJGs=X`~7|I~io}8Sm#WQg#Y7>^EcKlDUbdi4BwL$8R)w3Of}x_MpG& z#!iDz)Bm$SR>n?8+Zv zC9Z@F#n$-X;Ic&QtgeDi`0`zwT^)g4#WfMw8x9fIp;ptU;l)Z^+vtPSaNm)*gb6Di zeW*T7AExX2aJ(p5gul(_`HO;L<#jDay^jCOcdAqHW}*n~>~DyOo%@Xuv9rG^QsXW* zZjLyMjawpO-+yZaa`bZdskfm}w_`6bgmbt9v)w5;G_$)R{?(a2w3*!v;YO*&Vr#?y E0~lUBJpcdz literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/other.doctree b/phpmyadmin/doc/doctrees/other.doctree new file mode 100644 index 0000000000000000000000000000000000000000..335834ff9ce337758bcc3ecdc643d0237ed2dd8f GIT binary patch literal 5433 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 literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/privileges.doctree b/phpmyadmin/doc/doctrees/privileges.doctree new file mode 100644 index 0000000000000000000000000000000000000000..3fb07662ee3ce5d2ca2adfba810ba2965d438426 GIT binary patch literal 11974 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 AIsgCw literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/require.doctree b/phpmyadmin/doc/doctrees/require.doctree new file mode 100644 index 0000000000000000000000000000000000000000..77571f79935bd1d0dc553610834c534a79283ea2 GIT binary patch literal 16868 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 Riz9}%i|_C_S_f3&{{cr56`244 literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/setup.doctree b/phpmyadmin/doc/doctrees/setup.doctree new file mode 100644 index 0000000000000000000000000000000000000000..4a56db92f80e9eb604d98cd92734312a2e07392f GIT binary patch literal 132201 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%0A}icd2aMf|vOvOEMbl^m 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 literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/user.doctree b/phpmyadmin/doc/doctrees/user.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d29bc1652506b8200b0b9ba1c9f88b26c95a8b86 GIT binary patch literal 2928 zcwVJe>3lD-~>!CR|ramBdH)lCPVK`?{=e^>8b7> zX%`rXffx(O!4)7U_kG{@ec$K*L-p)vE$#2eCqBsXuBy9Uy?XVk@0kuG73NmPrk$#Y zn}++C@YFW&qN~p0bb$w&P)}LH?J(m8X9}F%XiQB_<%a9a`?-ub&Upq7nY?SPv~-n9 zgNXMG&KFpNrHpCAgM=Hy`gFeTV*{4LTx-e^7?tag<3SG^5f7DS?ldlVaG2#*^^~%y zvOF-BX^V^N7s0$kA|r!K1uly@XgC_~w} zsWQ#BD-g$E3g!qc;lfMAG|W}sUpje>=9$h@8PbOaK564LkD+!KeE8G?))#W(<9Lx{uF*T9<{J+I8RxAFqT1j;?3=*c2-a zW=E&4^6^<>j^!{D%ar4@*Qe>qs`2<7F)fI`R&%m&YHv&>w~4(@fhU{dSg8bXO1P

    ACMAn zn9TEhV(bM4o+b#wT-M3)ih7KT=NKDwN8OB;}n9gh7s{brSTA7vja2zSatEWI}XTg4$|!o zH8|9FI9#uTd1|AU)aMN!U*GgLmWe&9S!#MpC*_P8yz?Bs!7F*qwA_+0chh;-IrP1a zS^830LAmcfhXIEWw?FAk#3;X}sxxLFQw(Dee?^iMu(}5;llAY=n%^_h?8S_cceR#XmxCg&L=ykJ_!N9$l^N?XF6dr*^6qb!CR<5!I2z_$f!sI)Z-dgps)|3e0|!UT)lJbTSM7wNQ2_eFjQ>Sbih5D8y~*Nl9#V|P^SUTD4`tSSIL*^mUV+|8IgN^ zZJk~%`*nn0hov*#Z8rxS*S6PMS6_eKDf|Y^@4jBX38(+R{r@dkCNr?K>fB5b)fT^f z9_oFba(WR_)4oF`mV{rR_PaDRCLsd~FfUE#dt}Z|GUGY_K3rDK`S$j9I~!V|(sIrt zzSW^f)4?A&b4@K91VZ*jOg|QXNN)l~CI1Lc>}PdC_&*j8!IJa6-~y9BfoU1xPYEn- zwml91*$x~ZjVtj{dIoWA#dvssPD4@kCKzp&U-Zeq&#&^jPO@9F$d}4 zHvZz*&Vx&W#!mVhFYm(9$z3qA?BA|Wjb25+EAaPXMI13C)4k8v(f0X6fqxXMv?XXe z|EYW#{MoJCzqpnA*YWf4Z?wy4^Zwm!-hbp!zpw`W>Epj(&M`x&{$1dI@^1UTt2IcL literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/vendors.doctree b/phpmyadmin/doc/doctrees/vendors.doctree new file mode 100644 index 0000000000000000000000000000000000000000..551c30c347d556e986a64701ffac5cc4bad06ddc GIT binary patch literal 8707 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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 or Bzip a dump or a CSV export? It does not seem to work. +---------------------------------------------------------------------------- + +These features are based on the ``gzencode()`` and ``bzcompress()`` +PHP functions to be more independent of the platform (Unix/Windows, +Safe Mode or not, and so on). So, you must have Zlib/Bzip2 support +(``--with-zlib`` and ``--with-bz2``). + +.. _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. + +.. _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 3.0 only PHP 5.2 and newer. For older PHP versions, use +phpMyAdmin 2.11.x. + +.. _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=databas +e&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, being able to choose a table in another database, or +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. + +.. _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 +* in Links, for "town\_code" choose "REL\_towns->code" +* in Links, for "country\_code" choose "REL\_countries->country\_code" +* 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 000000000..d558b4405 --- /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 000000000..65e743185 --- /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: 391ce1d2159bfa0058ee08a87344a0a5 +tags: fbb0d17656682115ca4d033fb2f83ba1 diff --git a/phpmyadmin/doc/html/_sources/config.txt b/phpmyadmin/doc/html/_sources/config.txt new file mode 100644 index 000000000..2b9ced27b --- /dev/null +++ b/phpmyadmin/doc/html/_sources/config.txt @@ -0,0 +1,2776 @@ +.. 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`. + +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 some 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 not longer be displayed + +.. config:option:: $cfg['TranslationWarningThreshold'] + + :type: integer + :default: 80 + + Show warning about incomplete translations on certain threshold. + +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 + +.. 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 connection to 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. + +.. _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``) + + +.. _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]['DisableIS'] + + :type: boolean + :default: true + + Disable using ``INFORMATION_SCHEMA`` to retrieve information (use + ``SHOW`` commands instead), because of speed issues when many + databases are present. Currently used in some parts of the code, more + to come. + +.. config:option:: $cfg['Servers'][$i]['ShowDatabasesCommand'] + + :type: string + :default: ``'SHOW DATABASES'`` + + On a server with a huge number of databases, the default ``SHOW DATABASES`` + command used to fetch the name of available databases will probably be too + slow, so it can be replaced by faster commands. You can use ``#user#`` + string will be replaced by current user. + + When using ``false``, it will disable fetching databases from the server, + only databases in :config:option:`$cfg['Servers'][$i]['only_db']` will be + displayed. + + Examples: + + * ``'SHOW DATABASES'`` + * ``"SHOW DATABASES LIKE '#user#\_%'"`` + * ``'SELECT DISTINCT TABLE_SCHEMA FROM information_schema.SCHEMA_PRIVILEGES'`` + * ``'SELECT SCHEMA_NAME FROM information_schema.SCHEMATA'`` + * ``false`` + +.. 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']`. + + Takes effect only if :config:option:`$cfg['Servers'][$i]['DisableIS']` is + ``true``. + +.. 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['MaxDbList'] + + :type: integer + :default: 100 + + The maximum number of database names to be displayed in the main panel's + database list. + +.. config:option:: $cfg['MaxNavigationItems'] + + :type: integer + :default: 25 + + The number of items that can be displayed on each page of the + navigation tree. + +.. 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. + +.. 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: ``'0'`` + + Set the number of bytes a script is allowed to allocate. If set to + zero, 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. + +Navigation panel setup +---------------------- + +.. 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['ShowTooltip'] + + :type: boolean + :default: true + + Defines whether to display item comments as tooltips in navigation + panel or not. + +.. 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['NavigationBarIconic'] + + :type: string + :default: true + + Defines whether navigation bar buttons contain text or symbols only. A + value of true displays icons, false displays text and 'both' displays + both icons and text. + +.. 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 5 × :config:option:`$cfg['MaxRows']` rows) to avoid + performance issues while getting too many rows. + +.. config:option:: $cfg['MaxRows'] + + :type: integer + :default: 30 + + 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. + +.. 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['PropertiesIconic'] + + :type: string + :default: ``'both'`` + + If set to ``true``, will display icons instead of text for db and table + properties links (like :guilabel:`Browse`, :guilabel:`Select`, + :guilabel:`Insert`, ...) and for the menu tabs. Can be set to ``'both'`` + if you want icons AND text. When set to ``false``, 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`` + +Documentation +------------- + +.. config:option:: $cfg['MySQLManualBase'] + + :type: string + :default: ``'http://dev.mysql.com/doc/refman'`` + + If set to an :term:`URL` which points to + the MySQL documentation (type depends on + :config:option:`$cfg['MySQLManualType']`), appropriate help links are + generated. + + See `MySQL Documentation page `_ for more + information about MySQL manuals and their types. + +.. config:option:: $cfg['MySQLManualType'] + + :type: string + :default: ``'viewable'`` + + Type of MySQL documentation: + + * viewable - "viewable online", current one used on MySQL website + * searchable - "Searchable, with user comments" + * chapters - "HTML, one page per chapter" + * big - "HTML, all on one page" + * none - do not show documentation links + +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 + * 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 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. + +.. 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 navi frame. 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 parser settings +------------------- + +.. config:option:: $cfg['SQP']['fmtType'] + + :type: string + :default: ``'html'`` + + The main use of the new :term:`SQL` Parser + is to pretty-print :term:`SQL` queries. By + default we use HTML to format the query, but you can disable this by + setting this variable to ``'none'``. + + Available options: + + * ``'html'`` + * ``'none'`` + +.. _cfg_SQP: +.. config:option:: $cfg['SQP']['fmtInd'] + + :type: float + :default: ``'1'`` + +.. config:option:: $cfg['SQP']['fmtIndUnit'] + + :type: string + :default: ``'em'`` + + For the pretty-printing of :term:`SQL` queries, + under some cases the part of a query inside a bracket is indented. By + changing :config:option:`$cfg['SQP']['fmtInd']` you can change the amount + of this indent. + + Related in purpose is :config:option:`$cfg['SQP']['fmtIndUnit']` which + specifies the units of the indent amount that you specified. This is used + via stylesheets. + + You can use any HTML unit, for example: + + * ``'em'`` + * ``'ex'`` + * ``'pt'`` + * ``'px'`` + +.. config:option:: $cfg['SQP']['fmtColor'] + + :type: array of string tuples + :default: + + This array is used to define the colours for each type of element of + the pretty-printed :term:`SQL` queries. + The tuple format is *class* => [*HTML colour code* | *empty string*] + + + If you specify an empty string for the color of a class, it is ignored + in creating the stylesheet. You should not alter the class names, only + the colour strings. + + **Class name key:** + + comment + Applies to all comment sub-classes + comment\_mysql + Comments as ``"#...\n"`` + comment\_ansi + Comments as ``"-- ...\n"`` + comment\_c + Comments as ``"/*...*/"`` + digit + Applies to all digit sub-classes + digit\_hex + Hexadecimal numbers + digit\_integer + Integer numbers + digit\_float + Floating point numbers + punct + Applies to all punctuation sub-classes + punct\_bracket\_open\_round + Opening brackets ``"("`` + punct\_bracket\_close\_round + Closing brackets ``")"`` + punct\_listsep + List item Separator ``","`` + punct\_qualifier + Table/Column Qualifier ``"."`` + punct\_queryend + End of query marker ``";"`` + alpha + Applies to all alphabetic classes + alpha\_columnType + Identifiers matching a column type + alpha\_columnAttrib + Identifiers matching a database/table/column attribute + alpha\_functionName + Identifiers matching a MySQL function name + alpha\_reservedWord + Identifiers matching any other reserved word + alpha\_variable + Identifiers matching a :term:`SQL` variable ``"@foo"`` + alpha\_identifier + All other identifiers + quote + Applies to all quotation mark classes + quote\_double + Double quotes ``"`` + quote\_single + Single quotes ``'`` + quote\_backtick + Backtick quotes ````` + +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['Error_Handler']['display'] + + :type: boolean + :default: false + + Whether to display errors from PHP or not. + +.. config:option:: $cfg['Error_Handler']['gather'] + + :type: boolean + :default: false + + Whether to gather 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 000000000..cfcb86394 --- /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 000000000..21f5e1892 --- /dev/null +++ b/phpmyadmin/doc/html/_sources/credits.txt @@ -0,0 +1,597 @@ +.. _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 + +* 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 + +* 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 + +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 000000000..557452769 --- /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 000000000..c77f42866 --- /dev/null +++ b/phpmyadmin/doc/html/_sources/faq.txt @@ -0,0 +1,2001 @@ +.. _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 or Bzip a dump or a CSV export? It does not seem to work. +---------------------------------------------------------------------------- + +These features are based on the ``gzencode()`` and ``bzcompress()`` +PHP functions to be more independent of the platform (Unix/Windows, +Safe Mode or not, and so on). So, you must have Zlib/Bzip2 support +(``--with-zlib`` and ``--with-bz2``). + +.. _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. + +.. _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 3.0 only PHP 5.2 and newer. For older PHP versions, use +phpMyAdmin 2.11.x. + +.. _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=databas +e&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, being able to choose a table in another database, or +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. + +.. _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 +* in Links, for "town\_code" choose "REL\_towns->code" +* in Links, for "country\_code" choose "REL\_countries->country\_code" +* 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 000000000..d558b4405 --- /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 000000000..917ddf810 --- /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 000000000..9d81e44a4 --- /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` :term:`RFC 1952` or + :term:`Bzip2` formats) dumps and :term:`CSV` exports if you use PHP with + :term:`Zlib` support (``--with-zlib``) and/or :term:`Bzip2` support + (``--with-bz2``). 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 000000000..aa9545121 --- /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 000000000..0c12932d0 --- /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 000000000..1452ee34f --- /dev/null +++ b/phpmyadmin/doc/html/_sources/require.txt @@ -0,0 +1,55 @@ +.. _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.2.0 or newer, with ``session`` support, the Standard PHP Library + (SPL) extension and JSON support. + +* To support uploading of ZIP files, you need the PHP ``zip`` extension. + +* For proper support of multibyte strings (eg. UTF-8, which is currently + the default), you should install the ``mbstring`` and ``ctype`` extensions. + +* 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 PHP + 5.2.17 or newer and the `libxml `_ + extension. + +.. seealso:: :ref:`faq1_31`, :ref:`authentication_modes` + +Database +-------- + +phpMyAdmin support MySQL compatible databases. + +* MySQL 5.0 or newer +* MariaDB 5.0 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 000000000..850d67a2c --- /dev/null +++ b/phpmyadmin/doc/html/_sources/setup.txt @@ -0,0 +1,424 @@ +.. _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``"). + +.. _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. + + +Manualy creating 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:: php + + + + +Or, if you prefer to not be prompted every time you log in: + +.. code-block:: 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. 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 (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. + +If you want to use the many new relation and bookmark features: (this of +course requires that your :ref:`linked-tables` be set up). + +.. 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 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*: + +.. 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 +* prevent access to ``libraries`` directory from browser, + as it is not needed, supplied ``.htaccess`` file does this +* 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 diff --git a/phpmyadmin/doc/html/_sources/transformations.txt b/phpmyadmin/doc/html/_sources/transformations.txt new file mode 100644 index 000000000..4c3ce46c9 --- /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 000000000..ceaf72332 --- /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 000000000..13d7e550a --- /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 zcwTe&bhEHb6krfw_{6~Q|Nno%(3)e{?)x>&1u}A`t?OF7Z|1gRivOgXi&7IyQd1Pl zGfOfQ60;I3a`F>X^fL3(@);C=vM_KlFfb_o=k{|A33hf2a5d61U}gjg=>RbU$Z!T` zV~$;S{u!L|%oa}Ou;P%M!|pdDjnj3b;h|k3GY@XlOE_|<@Pcl%gyr33?3NNd>|WW= zJs6-yGa{Q~0y4+1M^Qn#g=hDMXI(CZPJtl_hLQ>iKCaPHD{5r6mfnAxD8b&Ka9!e2 zo3rF5RTV8Es6kA~2AOf}GE&w)<#=MknJHoVY^}*Md|xE}K6*MO&RAU_^MUKk=Djk< zR%kOtz7_w&*nF7ZXl07j{QWFYqnOeBmZYkE%BXGPn>k_et=-EwTNQa&3|-n2Wdv8b zHEp;k&zuw#``K3Bz(Pl=|HP6aOCOluSdh&z;@DNBuI=?aMdX9TXP-tMwX(wrF-aj) zT3dF?Wkfn@o 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 zcwPal4O8-oP)Oz@Z0f2-7z;ux~O9+4z06=<WDR*FRcSTFz- zW=q650N5=6FiBTtNC2?60Km==3$g$R3;-}uh=nNt1bYBr$Ri_o0EC$U6h`t_Jn<{8 z5a%iY0C<_QJh>z}MS)ugEpZ1|S1ukX&Pf+56gFW3VVXcL!g-k)GJ!M?;PcD?0HBc- z5#WRK{dmp}uFlRjj{U%*%WZ25jX z{P*?XzTzZ-GF^d31o+^>%=Ap99M6&ogks$0k4OBs3;+Bb(;~!4V!2o<6ys46agIcq zjPo+3B8fthDa9qy|77CdEc*jK-!%ZRYCZvbku9iQV*~a}ClFY4z~c7+0P?$U!PF=S z1Au6Q;m>#f??3%Vpd|o+W=WE9003S@Bra6Svp>fO002awfhw>;8}z{#EWidF!3EsG z3;bXU&9EIRU@z1_9W=mEXoiz;4lcq~xDGvV5BgyU zp1~-*fe8db$Osc*A=-!mVv1NJjtCc-h4>-CNCXm#Bp}I%6j35eku^v$Qi@a{RY)E3 zJ#qp$hg?Rwkvqr$GJ^buyhkyVfwECO)C{#lxu`c9ghrwZ&}4KmnvWKso6vH!8a<3Q zq36)6Xb;+tK10Vaz~~qUGsJ8#F2=(`u{bOVlVi)VBCHIn#u~6ztOL7=^<&SmcLWlF zMZgI*1b0FpVIDz9SWH+>*hr`#93(Um+6gxa1B6k+CnA%mOSC4s5&6UzVlpv@SV$}* z))J2sFA#f(L&P^E5{W}HC%KRUNwK6<(h|}}(r!{C=`5+6G)NjFlgZj-YqAG9lq?`C z$c5yc>d>VnA`E_*3F2Qp##d8RZb=H01_mm@+|Cqnc9PsG(F5HIG_C zt)aG3uTh7n6Et<2In9F>NlT@zqLtGcXcuVrX|L#Xx)I%#9!{6gSJKPrN9dR61N3(c z4Tcqi$B1Vr8Jidf7-t!G7_XR2rWwr)$3XQ?}=hpK0&Z&W{| zep&sA23f;Q!%st`QJ}G3cbou<7-yIK2z4nfCCCtN2-XOGSWo##{8Q{ATurxr~;I`ytDs%xbip}RzP zziy}Qn4Z2~fSycmr`~zJ=lUFdFa1>gZThG6M+{g7vkW8#+YHVaJjFF}Z#*3@$J_By zLtVo_L#1JrVVB{Ak-5=4qt!-@Mh}c>#$4kh<88)m#-k<%CLtzEP3leVno>={htGUuD;o7bD)w_sX$S}eAxwzy?UvgBH(S?;#HZiQMoS*2K2 zT3xe7t(~nU*1N5{rxB;QPLocnp4Ml>u<^FZwyC!nu;thW+pe~4wtZn|Vi#w(#jeBd zlf9FDx_yoPJqHbk*$%56S{;6Kv~mM9!g3B(KJ}#RZ#@)!hR|78Dq|Iq-afF%KE1Brn_fm;Im z_u$xr8UFki1L{Ox>G0o)(&RAZ;=|I=wN2l97;cLaHH6leTB-XXa*h%dBOEvi`+x zi?=Txl?TadvyiL>SuF~-LZ;|cS}4~l2eM~nS7yJ>iOM;atDY;(?aZ^v+mJV$@1Ote z62cPUlD4IWOIIx&SmwQ~YB{nzae3Pc;}r!fhE@iwJh+OsDs9zItL;~pu715HdQEGA zUct(O!LkCy1<%NCg+}G`0PgpNm-?d@-hMgNe6^V+j6x$b<6@S<$+<4_1hi}Ti zncS4LsjI}fWY1>OX6feMEuLErma3QLmkw?X+1j)X-&VBk_4Y;EFPF_I+q;9dL%E~B zJh;4Nr^(LEJ3myURP{Rblsw%57T)g973R8o)DE9*xN#~;4_o$q%o z4K@u`jhx2fBXC4{U8Qn{*%*B$Ge=nny$HAYq{=vy|sI0 z_vss+H_qMky?OB#|JK!>IX&II^LlUh#rO5!7TtbwC;iULyV-Xq?ybB}ykGP{?LpZ? z-G|jbTmIbG@7#ZCz;~eY(cDM(28Dyq{*m>M4?_iynUBkc4TkHUI6gT!;y-fz>HMcd z&t%Ugo)`Y2{>!cx7B7DI)$7;J(U{Spm-3gBzioV_{p!H$8L!*M!p0uH$#^p{Ui4P` z?ZJ24cOCDe-w#jZd?0@)|7iKK^;6KN`;!@ylm7$*nDhK&GcDTy000JJOGiWi{{a60 z|De66lK=n!32;bRa{vGf6951U69E94oEQKA00(qQO+^RV2niQ93PPz|JOBU!-bqA3 zR5;6pl1pe^WfX zkSdl!omi0~*ntl;2q{jA^;J@WT8O!=A(Gck8fa>hn{#u{`Tyg)!KXI6l>4dj==iVKK6+%4zaRizy(5eryC3d2 z+5Y_D$4}k5v2=Siw{=O)SWY2HJwR3xX1*M*9G^XQ*TCNXF$Vj(kbMJXK0DaS_Sa^1 z?CEa!cFWDhcwxy%a?i@DN|G6-M#uuWU>lss@I>;$xmQ|`u3f;MQ|pYuHxxvMeq4TW;>|7Z2*AsqT=`-1O~nTm6O&pNEK?^cf9CX= zkq5|qAoE7un3V z^yy=@%6zqN^x`#qW+;e7j>th{6GV}sf*}g7{(R#T)yg-AZh0C&U;WA`AL$qz8()5^ zGFi2`g&L7!c?x+A2oOaG0c*Bg&YZt8cJ{jq_W{uTdA-<;`@iP$$=$H?gYIYc_q^*$ z#k(Key`d40R3?+GmgK8hHJcwiQ~r4By@w9*PuzR>x3#(F?YW_W5pPc(t(@-Y{psOt zz2!UE_5S)bLF)Oz@Z0f2-7z;ux~O9+4z06=<WDR*FRcSTFz- zW=q650N5=6FiBTtNC2?60Km==3$g$R3;-}uh=nNt1bYBr$Ri_o0EC$U6h`t_Jn<{8 z5a%iY0C<_QJh>z}MS)ugEpZ1|S1ukX&Pf+56gFW3VVXcL!g-k)GJ!M?;PcD?0HBc- z5#WRK{dmp}uFlRjj{U%*%WZ25jX z{P*?XzTzZ-GF^d31o+^>%=Ap99M6&ogks$0k4OBs3;+Bb(;~!4V!2o<6ys46agIcq zjPo+3B8fthDa9qy|77CdEc*jK-!%ZRYCZvbku9iQV*~a}ClFY4z~c7+0P?$U!PF=S z1Au6Q;m>#f??3%Vpd|o+W=WE9003S@Bra6Svp>fO002awfhw>;8}z{#EWidF!3EsG z3;bXU&9EIRU@z1_9W=mEXoiz;4lcq~xDGvV5BgyU zp1~-*fe8db$Osc*A=-!mVv1NJjtCc-h4>-CNCXm#Bp}I%6j35eku^v$Qi@a{RY)E3 zJ#qp$hg?Rwkvqr$GJ^buyhkyVfwECO)C{#lxu`c9ghrwZ&}4KmnvWKso6vH!8a<3Q zq36)6Xb;+tK10Vaz~~qUGsJ8#F2=(`u{bOVlVi)VBCHIn#u~6ztOL7=^<&SmcLWlF zMZgI*1b0FpVIDz9SWH+>*hr`#93(Um+6gxa1B6k+CnA%mOSC4s5&6UzVlpv@SV$}* z))J2sFA#f(L&P^E5{W}HC%KRUNwK6<(h|}}(r!{C=`5+6G)NjFlgZj-YqAG9lq?`C z$c5yc>d>VnA`E_*3F2Qp##d8RZb=H01_mm@+|Cqnc9PsG(F5HIG_C zt)aG3uTh7n6Et<2In9F>NlT@zqLtGcXcuVrX|L#Xx)I%#9!{6gSJKPrN9dR61N3(c z4Tcqi$B1Vr8Jidf7-t!G7_XR2rWwr)$3XQ?}=hpK0&Z&W{| zep&sA23f;Q!%st`QJ}G3cbou<7-yIK2z4nfCCCtN2-XOGSWo##{8Q{ATurxr~;I`ytDs%xbip}RzP zziy}Qn4Z2~fSycmr`~zJ=lUFdFa1>gZThG6M+{g7vkW8#+YHVaJjFF}Z#*3@$J_By zLtVo_L#1JrVVB{Ak-5=4qt!-@Mh}c>#$4kh<88)m#-k<%CLtzEP3leVno>={htGUuD;o7bD)w_sX$S}eAxwzy?UvgBH(S?;#HZiQMoS*2K2 zT3xe7t(~nU*1N5{rxB;QPLocnp4Ml>u<^FZwyC!nu;thW+pe~4wtZn|Vi#w(#jeBd zlf9FDx_yoPJqHbk*$%56S{;6Kv~mM9!g3B(KJ}#RZ#@)!hR|78Dq|Iq-afF%KE1Brn_fm;Im z_u$xr8UFki1L{Ox>G0o)(&RAZ;=|I=wN2l97;cLaHH6leTB-XXa*h%dBOEvi`+x zi?=Txl?TadvyiL>SuF~-LZ;|cS}4~l2eM~nS7yJ>iOM;atDY;(?aZ^v+mJV$@1Ote z62cPUlD4IWOIIx&SmwQ~YB{nzae3Pc;}r!fhE@iwJh+OsDs9zItL;~pu715HdQEGA zUct(O!LkCy1<%NCg+}G`0PgpNm-?d@-hMgNe6^V+j6x$b<6@S<$+<4_1hi}Ti zncS4LsjI}fWY1>OX6feMEuLErma3QLmkw?X+1j)X-&VBk_4Y;EFPF_I+q;9dL%E~B zJh;4Nr^(LEJ3myURP{Rblsw%57T)g973R8o)DE9*xN#~;4_o$q%o z4K@u`jhx2fBXC4{U8Qn{*%*B$Ge=nny$HAYq{=vy|sI0 z_vss+H_qMky?OB#|JK!>IX&II^LlUh#rO5!7TtbwC;iULyV-Xq?ybB}ykGP{?LpZ? z-G|jbTmIbG@7#ZCz;~eY(cDM(28Dyq{*m>M4?_iynUBkc4TkHUI6gT!;y-fz>HMcd z&t%Ugo)`Y2{>!cx7B7DI)$7;J(U{Spm-3gBzioV_{p!H$8L!*M!p0uH$#^p{Ui4P` z?ZJ24cOCDe-w#jZd?0@)|7iKK^;6KN`;!@ylm7$*nDhK&GcDTy000JJOGiWi{{a60 z|De66lK=n!32;bRa{vGf6951U69E94oEQKA00(qQO+^RV2oe()A>y0J-2easEJ;K` zR5;6Jl3z%jbr{D#&+mQTbB>-f&3W<<%ayjKi&ZjBc2N<@)`~{dMXWB0(ajbV85_gJ zf(EU`iek}4Bt%55ix|sVMm1u8KvB#hnmU~_r<Ogd(A5vg_omvd-#L!=(BMVklxVqhdT zofSj`QA^|)G*lu58>#vhvA)%0Or&dIsb%b)st*LV8`ANnOipDbh%_*c7`d6# z21*z~Xd?ovgf>zq(o0?Et~9ti+pljZC~#_KvJhA>u91WRaq|uqBBKP6V0?p-NL59w zrK0w($_m#SDPQ!Z$nhd^JO|f+7k5xca94d2OLJ&sSxlB7F%NtrF@@O7WWlkHSDtor zzD?u;b&KN$*MnHx;JDy9P~G<{4}9__s&MATBV4R+MuA8TjlZ3ye&qZMCUe8ihBnHI zhMSu zSERHwrmBb$SWVr+)Yk2k^FgTMR6mP;@FY2{}BeV|SUo=mNk<-XSOHNErw>s{^rR-bu$@aN7= zj~-qXcS2!BA*(Q**BOOl{FggkyHdCJi_Fy>?_K+G+DYwIn8`29DYPg&s4$}7D`fv? zuyJ2sMfJX(I^yrf6u!(~9anf(AqAk&ke}uL0SIb-H!SaDQvd(}07*qoM6N<$g1Ha7 A2LJ#7 literal 0 HcwPel00001 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 zcwXxa@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^PXN zr}OT5AjMhW5m^k>ejS7voit`w00r4gJbhi+Z?SVR=!%sIxhVsMK6tt~hFF|Fdr8rs z*-?P?!TVcYIttp_4huY`c*=xj79}0t?-2gc+-;JAhu@=(62FueG?^^qvp8e6)8x8Y z$j3>(Wo7sFm~YO(E^~|bwejS7voit`w00r4gJbhi+Z?Q9qD{&ls8(Iw%dhO}r7-Dhy?4^Z% z&W-}C7e3$e(oxXXc33deM8b}teZ?dF3!#75CM{v=kJD+ZV+om{c7>7O*f%aN?smXY zU$dJxcNV`t^G<8&m$#ikUi;e31Hpn_IZI+KCAk@-(*{WbyZ0Q800Jr&aOfuZ~xSaN^s{3*Wmzu;`bFa#-^`E@BxaF9}`^tsBI!cdLoPC=+qxeciuhsX(dPyKv3Dac5 yW<0$)zy9{7DVy#blYDbw$DPzo-VcuMKdvwI%3ZN(!Awa|FnPNAxvXOL$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 HcwPel00001 diff --git a/phpmyadmin/doc/html/_static/jquery.js b/phpmyadmin/doc/html/_static/jquery.js new file mode 100644 index 000000000..7c2430802 --- /dev/null +++ b/phpmyadmin/doc/html/_static/jquery.js @@ -0,0 +1,154 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
    a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

    ";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
    ";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
    ","
    "];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
    ").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, +serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), +function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, +global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| +c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= +this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
    "; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); +c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/phpmyadmin/doc/html/_static/minus.png b/phpmyadmin/doc/html/_static/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..da1c5620d10c047525a467a425abe9ff5269cfc2 GIT binary patch literal 199 zcwXxa@N?(olHy`uVBq!ia0vp^+#t-s1SHkYJtzcHoCO|{#XvD(5N2eUHAey{$X?>< z>&kweokM_|(Po{+Q=kw>iEBiObAE1aYF-J$w=>iB1I2R$WLpMkF=>bh=@O1TaS?83{1OVknK< z>&kweokM`jkU7Va11Q8%;u=xnoS&PUnpeW`?aZ|OK(QcC7sn8Z%gHvy&v=;Q4jejg zV8NnAO`-4Z@2~&zopr02WF_WB>pF literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/html/_static/pygments.css b/phpmyadmin/doc/html/_static/pygments.css new file mode 100644 index 000000000..1a14f2ae1 --- /dev/null +++ b/phpmyadmin/doc/html/_static/pygments.css @@ -0,0 +1,62 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #303030 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0040D0 } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/phpmyadmin/doc/html/_static/searchtools.js b/phpmyadmin/doc/html/_static/searchtools.js new file mode 100644 index 000000000..663be4c90 --- /dev/null +++ b/phpmyadmin/doc/html/_static/searchtools.js @@ -0,0 +1,560 @@ +/* + * searchtools.js_t + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilties for the full-text search. + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words, hlwords is the list of normal, unstemmed + * words. the first one is used to find the occurance, the + * latter for highlighting it. + */ + +jQuery.makeSearchSummary = function(text, keywords, hlwords) { + var textLower = text.toLowerCase(); + var start = 0; + $.each(keywords, function() { + var i = textLower.indexOf(this.toLowerCase()); + if (i > -1) + start = i; + }); + start = Math.max(start - 120, 0); + var excerpt = ((start > 0) ? '...' : '') + + $.trim(text.substr(start, 240)) + + ((start + 240 - text.length) ? '...' : ''); + var rv = $('
    ').text(excerpt); + $.each(hlwords, function() { + rv = rv.highlightText(this, 'highlighted'); + }); + return rv; +} + + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + + +/** + * Search Module + */ +var Search = { + + _index : null, + _queued_query : null, + _pulse_status : -1, + + init : function() { + var params = $.getQueryParameters(); + if (params.q) { + var query = params.q[0]; + $('input[name="q"]')[0].value = query; + this.performSearch(query); + } + }, + + loadIndex : function(url) { + $.ajax({type: "GET", url: url, data: null, success: null, + dataType: "script", cache: true}); + }, + + setIndex : function(index) { + var q; + this._index = index; + if ((q = this._queued_query) !== null) { + this._queued_query = null; + Search.query(q); + } + }, + + hasIndex : function() { + return this._index !== null; + }, + + deferQuery : function(query) { + this._queued_query = query; + }, + + stopPulse : function() { + this._pulse_status = 0; + }, + + startPulse : function() { + if (this._pulse_status >= 0) + return; + function pulse() { + Search._pulse_status = (Search._pulse_status + 1) % 4; + var dotString = ''; + for (var i = 0; i < Search._pulse_status; i++) + dotString += '.'; + Search.dots.text(dotString); + if (Search._pulse_status > -1) + window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something + */ + performSearch : function(query) { + // create the required interface elements + this.out = $('#search-results'); + this.title = $('

    ' + _('Searching') + '

    ').appendTo(this.out); + this.dots = $('').appendTo(this.title); + this.status = $('

    ').appendTo(this.out); + this.output = $('

    sK?yH9`@F?gi!EF1eNuxvt#PCD)hxy5t6c+(@Gaya|9e1L&4=S*Ki) zM!JTV$11267{^nH-N7Si|A$eUx9egM+tYm!zE ziaA7_v1c|Q4+G>8fIJG2#{lwpxr8!E_RQrRN~vGg*Bnol%SM`6pYAm4Gr~$Gw%-|^ zCxV~lxt}XH`TCv+e%{pg0_uAa^}U4pUe;qxe|aj}j#SkvC+H>5C4y~Z;1gz)Rk^G134#5oUhTa#pNdg5`B%x#Sfj0g-@ zZ%Vz-rnBKEhTk&mZ-f0Eu)hoT_mIu|$R^G6f#lOU`41(fkC^;pArFJ;b&~-vx=;9! zPf^^&b?BXLZo+Dbt0qg2b#}rDT6*63{KW>dQq9dyq{XGJ-Jpaur**;hv#S<6b@E|c z){LapVkay;LAD!oY(S_hRTgLq}3QFMvdH% zQY2{won=lW-poLQ8)=py`k&*Gfck8e^tm%XH|c+Y^uI*-B3peR}cu)eGzQ^W9r^ z>nC{KY1G&~`U!T=euCMnpJ0w|!_4L>=nk_t%k>etB@6YO6QXv+NrbFfPPCam2eYXv zl8E9N-iW(Qr&J~DgYO!wmQXzNH61!qS~yliT+uI9eaNYA(ue80m!OI_H&e`d?b>w_ z$I^!cZT+KOxB+XrUS*L)JUfwUY;+Pbmz}g)<0&hlmu!UAki|FCt0d9v)VmF>tkA67 zsI6M9CP%N}Saz~b)5@|7=*6hl{KB|}`wnY_KEaN#LXMx=iUi$VYIhmRx2Q@u$?U;1 zqRo0cU?rX9$*Klddosk*>$$~=L};|Fx>RG8a_E?VH9wL{SW#-Bgtjl@sBAadtn|eZ zy@DkXP#g5)s3}}T$=7{-`(dSRh{!fVlpFVxm6n4DbNgjp_vO*wX@%!=eg*%{@86qW zq2$*)ogbemicEgR$gc$Xl_I|~gd8p1%_LL-B^7j6{HN7rd)kN zlyDnkZi8EI$CBDRefx;px<%lEMWKn~=Tu*Dqg8F8W=71X5{uzEVbA}j%GsIw=A%@@#F%)Nr&3$M1N^^#< zVlM;#o4gz*UT)$$+YUEgj)0dV;pHfJIT~JWfwS#6c5;lIZQojrbNtBc{~x|>DJQ?N zykfTc-?U=J$%?7+pNO_*E2?3|jal;DN!Da1;wJPNw_1LfgC~+F#q~L^(OICkA9X4o zZ*l@l>jU-nwqi_rW0M`xwxsMvr^<~5on}Y>M^{>>ZA&HjPK38Ix`u>47snbCbY{1$ zgwsqP)vND9^jVkg7qaPoVU;tsyyU_A!svk7ru~!4wx%JrLqm*5Lrg$JOhiLW@||2J zo0H2F_GjwD%{!ErMs9e-Ia^o?LVs6S}AscujO_(#o8#g4#n1^*dU5^&~g*F z)COs}y;oZrwcMHu`xn&JDD4ws%iaGd%fn*%uKr$VV%7*)kJYS`Lds28Gwu4Ogx(xf z*VC`~RQUR&6XAP&%MJ#0<0VqfydR)_jXYY|kc!n)^ChzNJ-qBX_%Z;y4(w-ebL!gx z+ov48Ptj+ADa-9>bHo|YR-Ha$j0_A9sA&7G5i_eLj@8nP)v^?;MPaohe65i*t&!r| zm;EQ#-XgU(`8s8}sl64ouR!g4p!Pjc`(EgjNnH8f(kVx+u2O20uGjf5D03faoP9Zv z{r-~!*+3y-*Lj;o+sAB-mC(SlX!qp3*J)#}*^ zN6{vouT@>zUn{3E6|q(N1fh?nTeMx)2Gl|Acgw+M#Ty{%; zw;aV49{vBm!egYu1AIMktf}xgRCqipJOLG+hzd_aPfX?dPL`fXwqFl#@cymUoFYsA zRCf2Y|M%{mF76)XU*Kmj;F$nitO2L#dokCESQ8Q3-S-}@^ z2^XV;MgO)E)Fo2E8NL;Isj1*HRB$;exB?Yii3+a53Z2gUSIY`r*e)+E(0@pKjjX_H z*`4eD{q9^Z?p)+qVGf>iyMY;Q1Vfmg38RNi*Ysv!y}Qu!;}M5S^H=~s&{#=(e%bQt zL%eNbTQR4_GMkcd>L%gxKcjcEN$nP-b}Lf54XNFZ)b2oPv)Z02yHk?;zg)*%lIPv* z4b%m#=f&SY`H1t*_5@(;Y=5`haNxYq9GzY65+ByTAR6SDK6;K*kRu z3Y!{5%4F0Rg{=fETm{{E`Ixf3t{}#pqYq#aCf8Dtpox zjh9Vvku`l2t%;-)t&QrFu09E<*XUqf_v@zaH}nrR-6Hh52=%7^dDc2q^;>Y^Z5p?; zYr4zRSn3`6y^MT%7rwklw_iWv#vJuN-F*F;^^>j5j{1QAK4b3GdFn&4Zr1w7xsT|! zv>ZO>LOzi~=v%-|Hjh z)?^1Adeac4sD9wTmJ%U)Fb>r zZ;jtGOs_r*^$Lv&Wrv5;2mbU9f6gBUq6_?mkM18Ta0s!cH$R@GPx4Vmsb5)ngEm#= zG$hn-Eb=?0&{O|`v=izN{^OtY$Bh!L(Ykn~*4!$g{?dQmRsBu>xN$}mJYQA?{p&jV zzcqQjo5}&}@&W770ll>8Y)V3{&wuTv|4ZT5^f5N_g6UqtmbKMlR%t@@;G6ZNn{A}m zNv{gx&aUvRlin3rCw(f?3wVPHvw-_n$g0_p{?)ABjVjFQ-MB&)QBFnM>docbV)f?f zU&69(wfXrKSg!@lQRw9;G91MfvR+G|Tv{RPwG2|_6}(=b834n2_R1Ouv~LY|Fgmi`s#RZDc~RU6tg{F*FdS^#uv(Mx3jJKoa` zVrgzdMXy`4fj94j+LYZNNZxEyOMMxi9mzCPf0qlVD=(Al5!H+YIFVX`i_t1t)gRVa@y7vo%G0-gbGMF zxr+KNSZf|7u6H%&%r`Ej`DtwxqwU>%`PpRu1Yjl+Ga9thNF_XH+W-d7R|ZM^~!vBVuxf z*_sc`4(Tl)4y&fay47p|zKESjXy|R|xX|>uHDx;SxT@8q#OZ3GR({p@Q$c<2ueRkB zsepvOVMyyov>9qUt|RE^`y@4<6*qFCbq=kVR(i36<0RDt{rAIa%HyeIb1J#I`6pIz z>uI$5q?*KzB=mBLrJ}XVsoT|L33WqyIeJUZ1g+;gJ7Hu!I0x~c=43$TSPO?in5Gq6U}7o zTsCbzC$>z@MElVH6L~_Z;tDA%&)nO*^z|Wp8uXh?j=%nNmpOI!Id3& z&fao=mF(gn79+)wwFH9G;0cXx!RcyqmHxdYFpf3GNg7P+k4jZ&0M5vS30oo zgt-f5)Giqn7+p1Dt1)BMZuG|<=FYd4ej7h5-kcoP9JQ+&T|I`H@%_KUloN6Ed0<%j z38t#idV@K7m|jrBaAFN89q;Z;u1{U`vK8uX9g|*$oMo>@N8cyVM{B7%v4O)%XHw69 z?USJIcC1~R;`3&Z)96EsvF%LckVpm2L@g~Xf#%j^C?4Z8QP5d7Odp&WrWz{bE;*L8 zm)C~e#!y86KdBlk`0gpLZ3)qjWtmy{8qU>+gt^iB()qkLZGM>kxUL&iP5iIg2=5|_ zFm|b&M6`K)lB=bw)V5Pfl&jqU>2j+jRIGx|_i>uCfSXTm9rW&n?kx0PLNA7(YOdg} z?XB#Vw!bZvziq&Vw%t!CQb^U+GEm2 zPyt^+$tC_M{Tp3Fg@@38=rT$^uxsbg!j$f$RGmJpCR5BRmqyEY(iZ(+egC-yKbBsB zd-m1}xhG#yA@}TiRAi;EDfX-|*A#nI$Q}LOdQ8>yO5dIC!#?fHx1v0B3H!0y{&b5` OyQ%|d>~CwT!2bb&5Nf&r literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/developers.doctree b/phpmyadmin/doc/doctrees/developers.doctree new file mode 100644 index 0000000000000000000000000000000000000000..de460981f7e5607991a80a9bd66b737d8aa66794 GIT binary patch literal 4726 zcwW_5cbFST6+fS^NV2c^+*`7~G$llmo!G%KNx;M;F^6Tq9_Ipx^-4R^EVtU-H#2*8 z0+z&tz#YAW-a~I8^xk{#9YXKD_wwGT-kFkofj{^@`J|nF^X9$Z@3rwY{S`N?#M<*! zJ_uc|GW1yIfzH5+vrj;O0xPpD9XNHa8xdD9kicMeI@8zJ=ki(ZhY^v}08XR@HHPhd?}4AH)hI}>78W~qws zd>74w^(EMlU5+!FQsap7Mnrj20-F(K>CCkp*)lzbh~@K^-8Ew$Y-K};0{RQvL_Zs9 z$!=e+S@KB6fmgwY44g83DQYT&kuF4aCs*_ETSWDS*Dh;PzcLJ;gc9hw$c4~wlOtPV-8*m!SIJ$+2g3}W?BgqkfKnR=8`I8@BQ3 z_6h72Lt>K>lWe%91}+rn(!Q)fd+#97%!>p%avWir>CGpcS>Ntn4mMz`a7Q-8lLu%x=YdY0}0#(O*iRvpqpL?dm{2O^lA@zg$56r zt#CP+dxbIgAenntGIxs1y&D;NsAD3XUtE6tQ9h4xdHCO*d3TJ3dn9mAG)>U?2ja4G zG6@*0PE9(I$iNZw$6SHa0 zSc3ae1~t~58E*9$*_aU51g!51v z=lhDo|BtTQNcHgq9HN?FIBKXCL})pI3K4oedUX|QCao30D>GQtwdMGzLZIqUDX;AL zp7zkrr4He7D3Uq;AA3XQBB6D(uTYqqo6C0#SU%voAi_GgBkT$VuO7*8mXp9G$L&10 zUD|}2 z5_L&Tzz}T@Le_4XF;^oq*CcSF-4+0&nsU1XCOjB}oO<)M2|R@GJP-BWdbHp=)+NY= zhfb|9woZ!E2*ZbEJD4m8SH=;E8NpHR|Qix7(5m zo>YP-vo%Y`D6{)1C3q@Zw@keG>S-l-I!jkPZJLFGXO!TXrXj9w&ugZaKMTjRj)mRH z?%5@H&PnaOp)~KvWZ=0-%nb=VuSp*w`FxYuFJOZ{H7s}`;*4m%h@gCNXHt3z76L@{ zrG)6qS_8$)aiAEW(H3681`ZZ4I}A4(pkHY!+)W9*s&mGx%^9yD6|W`5ucISgPs-jv z5qJY_dn2;56WO=|HA*~S#%c~o)?{~@nxwjqXj$FB$ithE&NnCUmUckiWCBuL*^JB4 zr2xQNaha%#LaCA4w-s5+b6ex>+tH(uUcMB(qXh3{BW*&OB)uzvce8OXa6L&gO4CdQ z?NqOzab3-avQ`kf?ib*rER9i8;iMWq zwtzPQ9(6}51s^XWJecm0T?y+n7Ap7z#<~tGJ=T1Z4dNTwfKRaz-wA3lqG;2E44-EG zIHG@srCkT1(oQ{s&ys}(Te}%fpPRziMKADT5;O;(&*M!)IDT8;3sZw^q-8{FnEhf= zTwY|`xRjx^(bCXGK<(zEz+UVlZ(m~LWTL_?0uS`jOZYMyba^?h!B>iGoY%{ocy0Jx z36692R~OlK>>E+6|CP?KVYs6q6%99|Nl0xF*X?;qG59)CGUmqh$nK<_f^Q&JNHN`U zT4LWsvC%n42BaKyaij55Hi8v99L!!Y^5-wVmSmSGd~?mPr1ZrHy1xAqc-= zW47xlr|eS*8eD!`WNA#`i0(V{@H?#CY3-ElInUJsem|9Bqf6rm{=i1}7mpmYr_ayt z&h5JJg1zuZHr&1j|A}4t-?;GonT=sd(0Ci5%tF95{AGcqYdqk1!A9!-ijErCy8!JA%kjf1vOT0jFY3eNxh-+7_!k3s^tMH!RSzFy) z8!(-XPYY&@qV*U{pcCApryvn9EKJZW`KxsevBdCE=nD_@eE@jGVePLGjW djQ?BBE^}>Ha+^7AJMEY#$y4ZilY>^}{{dpZvseHC literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/environment.pickle b/phpmyadmin/doc/doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..170f0783cc9f649cf2796f45e8c8e103fed2edad GIT binary patch literal 243711 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 literal 0 HcwPel00001 diff --git a/phpmyadmin/doc/doctrees/faq.doctree b/phpmyadmin/doc/doctrees/faq.doctree new file mode 100644 index 0000000000000000000000000000000000000000..115a6f91c89dd4f279c9c9e418dd1e7c33b455d0 GIT binary patch literal 595349 zcwX#%1$-OF^1m76Hf5%Z3xQgS*@+8oib>PDX%n|9+Gpu(og(nHA z_?Wa(nSfI~XNB0B?YefVf52q$yTx3m zVkBJ8e~Y9Uv)qAnD$0L0Tq}~X(Di2SBg$ryPN8r>XGp3{G;s-xOGM{o5S5R%7Czory)6IhdLhau(|hSBS2rb~ieUkA%nZPuYP) z+KdjcbU$arb;fDrG_*KNh(gSAvX+}M5_ZzgxXzLz;eaT_>%}?K&Qc@cmH9X6RKiYK zMuwRwSJ28aVe{>X9A?bJwZb(S0PxNGj7>MTDJUV?uTBCv)sR>}qV zR~QK|qrUb_X2lVNts&Gf)eqZBo#9!C=QK`Hzm+j8#yAy84wu<)xyE43N*P(u52H31 z0W0)Sz$kh8KPy`j5tnzPD?_HnASs^X-ndz!PF{$q=?y8f}* zSwsKW<{0|NR%g8avB9Yw2{$2&jR2`RU`9A)f+i!vOgHA|W*|0@95$m#E-q(Ho#G~E zExqAJXYG;j()=S;Fg(Rrr!!n53ihVc^O7c;=S&z0@5R4r2{lMOxv10G42+tjl}xi? z0dO7vJ_>Y3(y0tfCtSm1mXS)Qf_>Q(jx#e+C&M23xd)^NMz zgbRd^Lq6_Zz{BLyNpKjAC^rZRb6D}h(ctsGWfiW-7%|>E(TAJ&J9^Oych-D^9MR;$TNP_S}qxoOL_Ho1t2? z@siBy<1oaGiOd4?Gzrj_)=ua}B+Us0^8iwZ#s;kfemB6!WXP%O4DW{4q(!qPyu}RQ zH&NKUNd@hS)P2*4W|IRQdhKkAe_I>kBIm=}1`8AvgQC~&hr&*1B)lyeiiRfAY+)== zxZKoO3>xPaog0QkB0b2N?;VEDdJTjgbltR5NI}Yo4G-{oA!kZw_RX}@!@B-;}4+hh8yA5k(!}x9z)Lh8lBUe4MxK2Al{9w8s5@wnFjYKIHTMkLfsB$!_M%My!13KZQo4Y(HUN= zsIZTbNptrJhFEvPO7&-A&PJM}(^&6J*Cw>4sm{jw$7#+cBjGxn1GqYnD#S9G0mIC4 zL8LNvM7TRBdfVniZrT|>3|VU6s2PK13P+w9jdFf^6X{;hdV@*~WYJdG+!_vX%Wl}2 zIux-365(+&St`1@$q1Q>$$nk zWTUf%{;|oKp?|D*X6hdsoGtZ_tK|L2?eve0&YY2OBg&4NT%NCirxvjej>g05+(@ncIm@NF#Sb z#xkjL9s{YxEHjFZIJX)}0dr7($!Ej_ACplo2JpeTMb9&n!Y`QMiebyr+$1JDoGu-T z250+`@T!{r^6@17V?OJ8db@)LZF9X7)&ZI7?5Ka7=Ik^Q?!|%Itc;9j!y?=rv#nh9 z1<#ew+7T0q%o`7W1vADuXPY>hEy6#q7_O9B7r(A14q!cIeOIe!P*flYoq82MklV0K6QSL7Q>D zIRpAo;J%lOw#ZD)6Eg`fV2Y={Y$5?bMA+~ER}Lc*SUln7o2o% zP{0#R4`4bYasa(7>ym%3$Vp4r}f0l`8ex8;b;1PC0 zq+JjYoP?4i;hl=WOV!{23pEkL7~p>rpWl;-AXs}BIFym2R3=-@*+!BJE{ORKnijYZ zpC0d|I?<&mRen7c59v4ii?rA=KO;?2c{B zx4FV-b`g*^T?~#ur@=7tU~@i~Fdrv%g{8_rW>fQ0+>4aFh8$OfQ9PoN&OAZ3BzOzX6^o1Mv#HN9E7bhJ*GnOOeba!Ksdvx2#-Tj_5vZr>`2(=zqEyP zW%9C1q63wN0p|+G4Yz0gS!vF)1O1H8(8%f#j~GCuyx;4jD5GgK3nsV)^E<-^?~uAs zDLu$h@Ho!ub-8!$4330n7eTzy;4?0Os_q~NV9|w_8ThZ&hSWhG5!TNzfmh?MT5MsvtT5=o)}{dnknKm@E+1x*KmiEy*z%p=Oz_DK#Geq zA8|cHxqD}LdjvLrl8sr30nEp!xGTzM{X}{IXGktPZC*oP-Hl;=jJG0|742~L=nTh- zz!_*j8wk+210m(qXR-q#eZd=KCPb_Q!~TXrbSRdTC2X6VytyJHWN0%Zd{*bigd5#G z6>7o=ID6?%Qj@c{{;|>7NB`L1>^p+dL<0}pe9^>yYAS2vQ`!C_^r_J~K>O6>95@ml zMu9Xo^AR#Ae4Bi)6P%NbJ>LstIXs~u&!R`tNx;{$ZZUIUz)E?OZB7|6hoS2~kTj#c z9nL|zA6f4lJQAKN=$WcTQGyky40&(9d5#{Q5XlFQxtu)okEJ3^0n#>zm zF5@k8WGtAeT<5UP@Q$MEHp6d$`IPUuyO?tU48g2{u?BZzyfK*RQxmw1;6c?P^J#J4 zN6h7iYjX$>h>j56xe#8`Ol3KEL2nM_mMdcpIY%nJXy~5m9Ho7l<{UkONqZT6aSCJ(jD&YU$QwBV{I`f@OA9JJPdP_H;wm>+SqHF!)#s9o%tOieCPN*A=GNkSovJo5~Hq739RP&Az@j6~LVkaRB z5ADu}bePG|pXaoksSln;=d2MNtSz7r$b`y*HHX?-;2Qnf*#2w4bpanTou=M;J zm>-ZHbWlk_VGiY-g`BfR0NM(UxA+N+0FTd^FW`%yCxDnF?FdV|=|0e!h?NjZ*x{Vh z8J;FU6sdt!HrdOOmdPiylQtiU(O%*Az*LTd1D6891wOYkJV)52dLae$>P1pnIbk_= z9w8B4as-2GIddzA4kX;+oF~@(JfCtPt*@Y+KjN+XwfQHq3p&HA6@ho%<|VfwlJJP) z-Eie`F6;~+EDTVKaP_>=C&!JEl7l1>__jn1Vb;WGYd(4J>ImyO{3 zm?wq;e*NVm;Ty$ZZZj#;&_e#)#C8bAnVA@boFC(^5=*)H8LB!yABgo{vdwZ{&PnJ% z4m{1RgdyV(vEU%OS`X-OZOCc~KbZnm(R!_OMQ3 zdAZ;aOfL$Aq&d%LhyZml20V=lIahXii?YproxZ9wd^Qr+Iz~zw64t!OR!UE+kY^&g zyS3<<05N@O-gE7w+&m6fc)Jf4Xut$fY%E6uqzYsdQwJT%Y!pV*UI=xy@KPE$DY>hv znCZ149ODyJpBaH)y=7Rgu~R_a&_(Wgv*(vX{yF4aBS(rC=wI6z?hqowB!iLW0}~>4 zKIGJtDY6Ex$QFSI?o02~c5sj3y3X*{Mc~6X`ZJdnA6wvjas|Z|TXS9xQ*xsAR$44> z?_>_A!@0f_r@Mrmn&(AU&JD^NZ-ET&jUu?=vqFAq9hAa1)oN?I=~M)b>Trj1lOFpw zJ2&e|s21mM`o~u17L^&0hVa%AwPG!|S2(wg;KGnO5OHqT*5;d>JH&!|8!lzz#ENkFf5iy|`Nbx2+oI5);wp*RMM#5VNMQ^1MA{->6*X|e2nQ)UPidFJDvHk!l zFm50rVDl_4A0BsihM7=;W~p}2t=U>98V9`s&F8|#1g9`Ve!RsBgy-OR6P4MQ!No$8 zPygr*cnL&4&@EW2yhlXPoGtva`99>((F8>=~|2Pu=c6d zc|`lv<~*u>YIGjc9L_f9@sY44m}=B>qB15N;-gih)U7^~yP&EFXhRypsR)m|hjSLN zW$Fi0fPEM;$UQkvh`ln+p=RHztC-IEc}U}`iNc#Dv<)W(7Suw{lM0g-9z;Dg5{?(4 zlQT8X#Rabr-CT^nrDC{Z7Zq%S5dK;nDAO<|PdVxXm|x(7Acku@m_!0vyy79}X|4Y@ z=a~`u)a*Q~eQI%@(>^si&ugEWoEN;UH%%>zvVtg`u1LS#;k>93(BQnJnr-E9ysV`% zc;Nqv_G7E_sz$+7=d}^JzoIEGssQ7H6Q1y446!8!rR&*^4(Gj292ZTYhTl;^?$jC>Yz@XB$=(m?b}+Zl zlL*N%1CA3OJovZcr0fXyCI7C;u+@2g1os{_hNeMCEj)71*n2zij9!yDALv`$ra2#a zacQ%En**O#aPg`)opHtH9x=xJGjoUYQ77)^i}DDM))kzO#a21q2{(}(Dw_u#Y36() zwm`H%Fge=VzF0n!^JK{Rv@<*fMWJUIyamTv&z1{oS4%r5KGV5ub3PX_aV9bl?UNSU z`9hnt8ycK1^^Z-?SNf`Flk@cmhQWNSsW6y(bhv;h{qFg;iIR4``B2DEOnI0G68p}) zjWoE5CRU)pftK5j(Ep;<2(f62DWzTu5+0C4`o?o$o0|L%>_0@9*&1psfR&e?lXD!0 z8N;Gr?{HA=>FRL4?L@ujEw|=6x3w+x_0lIc)rJ}Ti92@Rb%r+)a%~f;+Q<3oOApnN z-@&Ivi%$v|?|N}JWMn~aXptf0eBUXPR?RZfEu?k`HYZJ*G*DLNqVXBxK8y^%a6c>s zGa>-{p))*5P^uCko(}mFBEq{3IX`;)LK^&7|I`^iUC=qU4^Dn%Uc}XI)Z&o#R(!!U zL$V~HR?ck~r7i+2U_wN1BJPi*L1?(1fH`zDGv4L_*enooe(v-()k-p)Uq+;gO!F;S zyK1#m3}RS6+?d8JyI<@o@$}G* z*#i`-Tewxt3x!0+P((YdsJN)8(@Q>2^SN@Up%`gogpJ~qiZxZS;ZfRUR*X$7C7NjQ z36hoIZ_f**P+a84ej@A>*@!}OEMTVTyXOrLrsZJ41hTa2(mBTMkpOa?Fc9!v8odVm z4tEQ{Hb|Ef6^Z$_CSuh(Pla)%7F$ls^cK42=cAy$q3Kx(cr)Lbxg3nN!cEc@pUf6gg)6`BRG^(};I zHi+bW)QSfAjA`3?fQ^ZVev2hx&QB(|X69_D75hFytOi?r2ZTLZz3J_5ymD zr^q+e2Knf91Xy!@Gk5NM8IVbSJYW|#4l*y)EVye(7*7%4k#?g$l(UzGErvX;DHOL& zU?`StAiU%9&~^)Tu*I=7nDkt;&BozRFeV0vU3+l2pDlr7VrQX75RYp)%#84*y?tSF zu~84KwyH#MA8q$S-7(|+QC-94#yW2NQvg|yJRb3$I=;Y?rvi% z`M+poEBn7_VXOGRXlAS87p4$(n`f(V@jxs!ih=756WkmT%l6CtvJi^eqcI$F0h(cl^3iw-JzEu zoNQQb6aElqVqQw_L+aykt#8$)$apLSyc>~z}*w}Eqk zWhNLC|PMvbMvZt z4YBcR#Q0W3>l>O_Ekao(e!`v9Y)$-XoPb-OLDs?_deExSc4}!IVM_>lvNF0C^T`xd zEN7w#$_#j~utr%hqqy1%NQBthNO2U$zswSO(KDZaP1f)2*21NQrZIWJ?JDO~=D%=D~XkX!VvGC?X zRMWK3M~VS=4sa0o^APRJ)O-!K>?hsDx?*ouZ-9AMss04+Ri(PYBJ#KmkA5&4gSiQy zpK#7Ytv*Zl1)WmBO6~Luu^_hIjt03QB)Ab(X{s+Dl8$EKT!#S(1i8IML`L2u*}=ONVr@mK=Phvesg4R^{JJV{Q0N2THot@b+d!vW$r&xVBIy_wQ&)QgpIK zOxD4s=JeLgruk>VCf1H$z}81^*5z(XXfj(*k(GpH)@UzVKZnqIwn5G}4Q#`lZyH&L zzr#kh5q<&ITAYoe9Vl$NUb_L>+c@W&Mz%@LH%)BQoNt=hW;x%qu+4M6X=PjFeAC8e z1^*g|YMR$>+kOT_9;O@{x( zi}JfQTL&B7yf{WI?X#_lJxkw;?rRD+NllTHn3zBGlQ9_Y*{;};=edaTd|saxlk?CN z%@ZH5xb@Zx@1^dujut)Xni31sedz?mymgeZkJ;P=ut?0#J#>fxh6pOad~!<>V%uW# zbwUaaG^Eu8ud-^8YO-98g2l)6c34d;zBM))-VRnk7=1QyS28kaQ2V57Mc%rOV@gqj zm{CG(jt&ZP$mSv_uy=#cL=xcv*mmRMITh9gzh}Faacq<3)%WR}4&j0pyt;8J+&TKa>bX%#2747aF?uIeS=3%h}P}-DBTn1df zOn@Z?hbb(YRve->ghEC)@41}~02YGdIB*&V0=goOOc z&Op;$rFPV1*h!vCWUEqY5<3w17Q7sUFbU!ghOY%pBk(BrI0POApNAsjt8-$4w7ML`%cF0;d+ z0uXD(1v`gBwb;F}CMz39!pq{4+!YE6oO68y5_hE6QXFLJ#syDDL34RJU}q9sHIFVv z6*vZ~A6u+cz~Cyd`Sfjhgt0j-i%-X_$+n8{TF1LFDws4WTIK3Fh)fq_QnF@k9aR=yR zd(CWbZdY*Nqo0`ru>d=(7=b(+TRBIy626U-Fk9?+#VH#SpXqr99E#^2Y0p;L?vlXz zkhyA~GG%aZFr;ldIq6$}THLd0vi$TtSlfooZJqHbI8@vQ|Sb zz^*DrSznDkTthv;=JG!#QFbk1cpWs{RfbmfdT1UN8uixM4aH!4A)013yAg_jL-Ega z$!;Ps+)Tpx8$1f>-BPTicWbed(`^6|p(SN>J3KBdNa`KMD3m*qv%3^z-duY%LT*Zx zQc$zI@%y-(sP4hq_o~{sfcsBk%1zakLX)et8UqA#mZdO_|4Vp$b{!ZzJXo8S)8l(IkXC&?Ja0083(R~9}?Hx zkGG4-u)aftzFVv~d9PTh=HH7^aV4?u!w*2Q=Vp8WKgT*_Nzcs~=kXxCi4VOBk`}?) zM@WJ68$QN@pA;+6Km5F2;)0f4Hr>}~YNWLys z=#TTG{|yvcm_yG$ic!bE#Xi4NB*%$P;0EV;PxHRVvOlP@xY<%_9uL&p*^jDjAs#ig z`>B}J?&o5~*e~!XIRCX+asFGe;<2ctNUB{0^ciem#U+aCCH-8Nl;}EFS_1u+mE`JN z4xvKl%6YNaNpaveU*{@HNIsP%ipr`I#YT0Bl1~5%cb%CWmZ|oj?FPNW-$7Ux3_=b# zXa>E*-$8Ns8_Icyzk_KOBugH|!{59H?%fQ6xq$+vc!I;}sSO_i%3Kifp-;WN8;C;o8Mf^Y)&# zB7OZkPuOPTEf&}V6L#$}08EpfuOTHtSTIT^^Ic60-9l;%o{$3fAk1^#)?Hu>|rBkeIM7mo=5Zcg@fi z%-^`hm$j5g*T=6GtQD&weZhLx25rJu88#JZ!D_Ip+%G(#W9u3I#^PG_Y5cF1B~T>j z?IlHCfRBB$^-6RfeSJh`gM4H*EFtlC5C$6&NYhJ{_&0_}pv9E1uv#|#AcQ#rQZ^I>8j-4 z!Zt28t3>)Fq8qjq%8vgE%V2D4{^<}5e`G$b(~|~%8BHfmJH@u~+7J}8*#z6R1m<>7 zs|LcHA=p)9XV@HQT?$|>381S)DdF}dGM?no65FA~%cF%$v;io9-?1b=?~;I}H69+Y zodnD~Bh0%fnBy}DmR(Co8FnLDx)H511hEIc2Hvy_GlCK}vjiq?!DuhBA0bwvB}!jF z+>&ey9?@PD7)O02XfFDZ>{yAWz}O71qe9e5$t<%=JUg$

'); + } + // Prettify the comment rating. + comment.pretty_rating = comment.rating + ' point' + + (comment.rating == 1 ? '' : 's'); + // Make a class (for displaying not yet moderated comments differently) + comment.css_class = comment.displayed ? '' : ' moderate'; + // Create a div for this comment. + var context = $.extend({}, opts, comment); + var div = $(renderTemplate(commentTemplate, context)); + + // If the user has voted on this comment, highlight the correct arrow. + if (comment.vote) { + var direction = (comment.vote == 1) ? 'u' : 'd'; + div.find('#' + direction + 'v' + comment.id).hide(); + div.find('#' + direction + 'u' + comment.id).show(); + } + + if (opts.moderator || comment.text != '[deleted]') { + div.find('a.reply').show(); + if (comment.proposal_diff) + div.find('#sp' + comment.id).show(); + if (opts.moderator && !comment.displayed) + div.find('#cm' + comment.id).show(); + if (opts.moderator || (opts.username == comment.username)) + div.find('#dc' + comment.id).show(); + } + return div; + } + + /** + * A simple template renderer. Placeholders such as <%id%> are replaced + * by context['id'] with items being escaped. Placeholders such as <#id#> + * are not escaped. + */ + function renderTemplate(template, context) { + var esc = $(document.createElement('div')); + + function handle(ph, escape) { + var cur = context; + $.each(ph.split('.'), function() { + cur = cur[this]; + }); + return escape ? esc.text(cur || "").html() : cur; + } + + return template.replace(/<([%#])([\w\.]*)\1>/g, function() { + return handle(arguments[2], arguments[1] == '%' ? true : false); + }); + } + + /** Flash an error message briefly. */ + function showError(message) { + $(document.createElement('div')).attr({'class': 'popup-error'}) + .append($(document.createElement('div')) + .attr({'class': 'error-message'}).text(message)) + .appendTo('body') + .fadeIn("slow") + .delay(2000) + .fadeOut("slow"); + } + + /** Add a link the user uses to open the comments popup. */ + $.fn.comment = function() { + return this.each(function() { + var id = $(this).attr('id').substring(1); + var count = COMMENT_METADATA[id]; + var title = count + ' comment' + (count == 1 ? '' : 's'); + var image = count > 0 ? opts.commentBrightImage : opts.commentImage; + var addcls = count == 0 ? ' nocomment' : ''; + $(this) + .append( + $(document.createElement('a')).attr({ + href: '#', + 'class': 'sphinx-comment-open' + addcls, + id: 'ao' + id + }) + .append($(document.createElement('img')).attr({ + src: image, + alt: 'comment', + title: title + })) + .click(function(event) { + event.preventDefault(); + show($(this).attr('id').substring(2)); + }) + ) + .append( + $(document.createElement('a')).attr({ + href: '#', + 'class': 'sphinx-comment-close hidden', + id: 'ah' + id + }) + .append($(document.createElement('img')).attr({ + src: opts.closeCommentImage, + alt: 'close', + title: 'close' + })) + .click(function(event) { + event.preventDefault(); + hide($(this).attr('id').substring(2)); + }) + ); + }); + }; + + var opts = { + processVoteURL: '/_process_vote', + addCommentURL: '/_add_comment', + getCommentsURL: '/_get_comments', + acceptCommentURL: '/_accept_comment', + deleteCommentURL: '/_delete_comment', + commentImage: '/static/_static/comment.png', + closeCommentImage: '/static/_static/comment-close.png', + loadingImage: '/static/_static/ajax-loader.gif', + commentBrightImage: '/static/_static/comment-bright.png', + upArrow: '/static/_static/up.png', + downArrow: '/static/_static/down.png', + upArrowPressed: '/static/_static/up-pressed.png', + downArrowPressed: '/static/_static/down-pressed.png', + voting: false, + moderator: false + }; + + if (typeof COMMENT_OPTIONS != "undefined") { + opts = jQuery.extend(opts, COMMENT_OPTIONS); + } + + var popupTemplate = '\ +
\ +

\ + Sort by:\ + best rated\ + newest\ + oldest\ +

\ +
Comments
\ +
\ + loading comments...
\ +
    \ +
    \ +

    Add a comment\ + (markup):

    \ +
    \ + reStructured text markup: *emph*, **strong**, \ + ``code``, \ + code blocks: :: and an indented block after blank line
    \ +
    \ + \ +

    \ + \ + Propose a change ▹\ + \ + \ + Propose a change ▿\ + \ +

    \ + \ + \ + \ + \ +
    \ +
    \ +
    '; + + var commentTemplate = '\ +
    \ +
    \ +
    \ + \ + \ + \ + \ + \ + \ +
    \ +
    \ + \ + \ + \ + \ + \ + \ +
    \ +
    \ +
    \ +

    \ + <%username%>\ + <%pretty_rating%>\ + <%time.delta%>\ +

    \ +
    <#text#>
    \ +

    \ + \ + reply ▿\ + proposal ▹\ + proposal ▿\ + \ + \ +

    \ +
    \
    +<#proposal_diff#>\
    +        
    \ +
      \ +
      \ +
      \ +
      \ + '; + + var replyTemplate = '\ +
    • \ +
      \ +
      \ + \ + \ + \ + \ + \ +
      \ +
      \ +
    • '; + + $(document).ready(function() { + init(); + }); +})(jQuery); + +$(document).ready(function() { + // add comment anchors for all paragraphs that are commentable + $('.sphinx-has-comment').comment(); + + // highlight search words in search results + $("div.context").each(function() { + var params = $.getQueryParameters(); + var terms = (params.q) ? params.q[0].split(/\s+/) : []; + var result = $(this); + $.each(terms, function() { + result.highlightText(this.toLowerCase(), 'highlighted'); + }); + }); + + // directly open comment window if requested + var anchor = document.location.hash; + if (anchor.substring(0, 9) == '#comment-') { + $('#ao' + anchor.substring(9)).click(); + document.location.hash = '#s' + anchor.substring(9); + } +}); diff --git a/phpmyadmin/doc/html/config.html b/phpmyadmin/doc/html/config.html new file mode 100644 index 000000000..9646bdfb8 --- /dev/null +++ b/phpmyadmin/doc/html/config.html @@ -0,0 +1,4896 @@ + + + + + + + + + + Configuration — phpMyAdmin 4.0.4 documentation + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      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.

      +

      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 some 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 not longer be displayed

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

      Show warning about incomplete translations on certain threshold.

      +
      + +
      +
      +

      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
      • +
      +
      + +
      +
      +$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 connection to 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]['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]['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]['DisableIS']
      +
      +++ + + + + + +
      Type:boolean
      Default value:true
      +

      Disable using INFORMATION_SCHEMA to retrieve information (use +SHOW commands instead), because of speed issues when many +databases are present. Currently used in some parts of the code, more +to come.

      +
      + +
      +
      +$cfg['Servers'][$i]['ShowDatabasesCommand']
      +
      +++ + + + + + +
      Type:string
      Default value:'SHOW DATABASES'
      +

      On a server with a huge number of databases, the default SHOW DATABASES +command used to fetch the name of available databases will probably be too +slow, so it can be replaced by faster commands. You can use #user# +string will be replaced by current user.

      +

      When using false, it will disable fetching databases from the server, +only databases in $cfg['Servers'][$i]['only_db'] will be +displayed.

      +

      Examples:

      +
        +
      • 'SHOW DATABASES'
      • +
      • "SHOW DATABASES LIKE '#user#\_%'"
      • +
      • 'SELECT DISTINCT TABLE_SCHEMA FROM information_schema.SCHEMA_PRIVILEGES'
      • +
      • 'SELECT SCHEMA_NAME FROM information_schema.SCHEMATA'
      • +
      • false
      • +
      +
      + +
      +
      +$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'].

      +

      Takes effect only if $cfg['Servers'][$i]['DisableIS'] is +true.

      +
      + +
      +
      +$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['MaxDbList']
      +
      +++ + + + + + +
      Type:integer
      Default value:100
      +

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

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

      The number of items that can be displayed on each page of the +navigation tree.

      +
      + +
      +
      +$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.

      +
      + +
      +
      +$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:'0'
      +

      Set the number of bytes a script is allowed to allocate. If set to +zero, 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['NavigationBarIconic']
      +
      +++ + + + + + +
      Type:string
      Default value:true
      +

      Defines whether navigation bar buttons contain text or symbols only. A +value of true displays icons, false displays text and ‘both’ displays +both icons and text.

      +
      + +
      +
      +$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 5 × $cfg['MaxRows'] rows) to avoid +performance issues while getting too many rows.

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

      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.

      +
      + +
      +
      +$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['PropertiesIconic']
      +
      +++ + + + + + +
      Type:string
      Default value:'both'
      +

      If set to true, will display icons instead of text for db and table +properties links (like Browse, Select, +Insert, ...) and for the menu tabs. Can be set to 'both' +if you want icons AND text. When set to false, 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
      • +
      +
      + +
      +
      +

      Documentation

      +
      +
      +$cfg['MySQLManualBase']
      +
      +++ + + + + + +
      Type:string
      Default value:'http://dev.mysql.com/doc/refman'
      +

      If set to an URL which points to +the MySQL documentation (type depends on +$cfg['MySQLManualType']), appropriate help links are +generated.

      +

      See MySQL Documentation page for more +information about MySQL manuals and their types.

      +
      + +
      +
      +$cfg['MySQLManualType']
      +
      +++ + + + + + +
      Type:string
      Default value:'viewable'
      +

      Type of MySQL documentation:

      +
        +
      • viewable - “viewable online”, current one used on MySQL website
      • +
      • searchable - “Searchable, with user comments”
      • +
      • chapters - “HTML, one page per chapter”
      • +
      • big - “HTML, all on one page”
      • +
      • none - do not show documentation links
      • +
      +
      + +
      +
      +

      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
      • +
      • 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 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.

      +
      + +
      +
      +$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 navi frame. 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 parser settings

      +
      +
      +$cfg['SQP']['fmtType']
      +
      +++ + + + + + +
      Type:string
      Default value:'html'
      +

      The main use of the new SQL Parser +is to pretty-print SQL queries. By +default we use HTML to format the query, but you can disable this by +setting this variable to 'none'.

      +

      Available options:

      +
        +
      • 'html'
      • +
      • 'none'
      • +
      +
      + +
      +
      +$cfg['SQP']['fmtInd']
      +
      +++ + + + + + +
      Type:float
      Default value:'1'
      +
      + +
      +
      +$cfg['SQP']['fmtIndUnit']
      +
      +++ + + + + + +
      Type:string
      Default value:'em'
      +

      For the pretty-printing of SQL queries, +under some cases the part of a query inside a bracket is indented. By +changing $cfg['SQP']['fmtInd'] you can change the amount +of this indent.

      +

      Related in purpose is $cfg['SQP']['fmtIndUnit'] which +specifies the units of the indent amount that you specified. This is used +via stylesheets.

      +

      You can use any HTML unit, for example:

      +
        +
      • 'em'
      • +
      • 'ex'
      • +
      • 'pt'
      • +
      • 'px'
      • +
      +
      + +
      +
      +$cfg['SQP']['fmtColor']
      +
      +++ + + + + + +
      Type:array of string tuples
      Default value:
      +

      This array is used to define the colours for each type of element of +the pretty-printed SQL queries. +The tuple format is class => [HTML colour code | empty string]

      +

      If you specify an empty string for the color of a class, it is ignored +in creating the stylesheet. You should not alter the class names, only +the colour strings.

      +

      Class name key:

      +
      +
      comment
      +
      Applies to all comment sub-classes
      +
      comment_mysql
      +
      Comments as "#...\n"
      +
      comment_ansi
      +
      Comments as "-- ...\n"
      +
      comment_c
      +
      Comments as "/*...*/"
      +
      digit
      +
      Applies to all digit sub-classes
      +
      digit_hex
      +
      Hexadecimal numbers
      +
      digit_integer
      +
      Integer numbers
      +
      digit_float
      +
      Floating point numbers
      +
      punct
      +
      Applies to all punctuation sub-classes
      +
      punct_bracket_open_round
      +
      Opening brackets "("
      +
      punct_bracket_close_round
      +
      Closing brackets ")"
      +
      punct_listsep
      +
      List item Separator ","
      +
      punct_qualifier
      +
      Table/Column Qualifier "."
      +
      punct_queryend
      +
      End of query marker ";"
      +
      alpha
      +
      Applies to all alphabetic classes
      +
      alpha_columnType
      +
      Identifiers matching a column type
      +
      alpha_columnAttrib
      +
      Identifiers matching a database/table/column attribute
      +
      alpha_functionName
      +
      Identifiers matching a MySQL function name
      +
      alpha_reservedWord
      +
      Identifiers matching any other reserved word
      +
      alpha_variable
      +
      Identifiers matching a SQL variable "@foo"
      +
      alpha_identifier
      +
      All other identifiers
      +
      quote
      +
      Applies to all quotation mark classes
      +
      quote_double
      +
      Double quotes "
      +
      quote_single
      +
      Single quotes '
      +
      quote_backtick
      +
      Backtick quotes `
      +
      +
      + +
      +
      +

      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['Error_Handler']['display']
      +
      +++ + + + + + +
      Type:boolean
      Default value:false
      +

      Whether to display errors from PHP or not.

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

      Whether to gather 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 000000000..f6a207a3f --- /dev/null +++ b/phpmyadmin/doc/html/copyright.html @@ -0,0 +1,134 @@ + + + + + + + + + + Copyright — phpMyAdmin 4.0.4 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 000000000..747dfd900 --- /dev/null +++ b/phpmyadmin/doc/html/credits.html @@ -0,0 +1,658 @@ + + + + + + + + + + Credits — phpMyAdmin 4.0.4 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
        • +
        +
      • +
      • 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
        • +
        +
      • +
      • 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
        • +
        +
      • +
      +

      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 000000000..d1789e636 --- /dev/null +++ b/phpmyadmin/doc/html/developers.html @@ -0,0 +1,118 @@ + + + + + + + + + + Developers Information — phpMyAdmin 4.0.4 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 000000000..f3ecca503 --- /dev/null +++ b/phpmyadmin/doc/html/faq.html @@ -0,0 +1,1780 @@ + + + + + + + + + + FAQ - Frequently Asked Questions — phpMyAdmin 4.0.4 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 or Bzip a dump or a CSV export? It does not seem to work.

      +

      These features are based on the gzencode() and bzcompress() +PHP functions to be more independent of the platform (Unix/Windows, +Safe Mode or not, and so on). So, you must have Zlib/Bzip2 support +(--with-zlib and --with-bz2).

      +
      +
      +

      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.

      +
      + +
      +

      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 3.0 only PHP 5.2 and newer. For older PHP versions, use +phpMyAdmin 2.11.x.

      +
      +
      +

      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=databas +e&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, being able to choose a table in another database, or +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.

      +
      +
      +
      +

      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
      • +
      • in Links, for “town_code” choose “REL_towns->code”
      • +
      • in Links, for “country_code” choose “REL_countries->country_code”
      • +
      • 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 000000000..0519e3049 --- /dev/null +++ b/phpmyadmin/doc/html/genindex.html @@ -0,0 +1,3699 @@ + + + + + + + + + + + + Index — phpMyAdmin 4.0.4 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['AllowArbitraryServer'], [1], [2] +
      + + +
      $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['CharEditing'], [1] +
      + + +
      $cfg['CharTextareaCols'] +
      + + +
      $cfg['CharTextareaRows'] +
      + + +
      $cfg['CheckConfigurationPermissions'] +
      + + +
      $cfg['CodemirrorEnable'] +
      + + +
      $cfg['CompressOnFly'], [1] +
      + + +
      $cfg['Confirm'] +
      + + +
      $cfg['CSPAllow'] +
      + + +
      $cfg['DBG'] +
      + + +
      $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['Error_Handler']['gather'] +
      + + +
      $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'], [1] +
      + + +
      $cfg['MaxSizeForInputField'] +
      + + +
      $cfg['MaxTableList'] +
      + + +
      $cfg['McryptDisableWarning'] +
      + + +
      $cfg['MemoryLimit'] +
      + + +
      $cfg['MinSizeForInputField'] +
      + + +
      $cfg['MySQLManualBase'] +
      + + +
      $cfg['MySQLManualType'], [1] +
      + + +
      $cfg['NaturalOrder'] +
      + + +
      $cfg['NaviBackground'] +
      + + +
      $cfg['NavigationBarIconic'] +
      + + +
      $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['PersistentConnections'] +
      + + +
      $cfg['PmaAbsoluteUri'], [1], [2], [3], [4], [5] +
      + + +
      $cfg['PmaNoRelation_DisableWarning'] +
      + + +
      $cfg['PropertiesIconic'] +
      + + +
      $cfg['PropertiesNumColumns'] +
      + + +
      $cfg['ProtectBinary'] +
      + + +
      $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['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]['controluser'], [1], [2], [3] +
      + + +
      $cfg['Servers'][$i]['designer_coords'], [1] +
      + + +
      $cfg['Servers'][$i]['DisableIS'], [1] +
      + + +
      $cfg['Servers'][$i]['extension'], [1] +
      + + +
      $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]['nopassword'] +
      + + +
      $cfg['Servers'][$i]['only_db'], [1], [2] +
      + + +
      $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] +
      + + +
      $cfg['Servers'][$i]['port'] +
      + + +
      $cfg['Servers'][$i]['recent'], [1] +
      + + +
      $cfg['Servers'][$i]['relation'], [1] +
      + + +
      $cfg['Servers'][$i]['ShowDatabasesCommand'] +
      + + +
      $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]['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]['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['ShowTooltip'] +
      + + +
      $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['SQP']['fmtColor'] +
      + + +
      $cfg['SQP']['fmtInd'], [1] +
      + + +
      $cfg['SQP']['fmtIndUnit'], [1] +
      + + +
      $cfg['SQP']['fmtType'] +
      + + +
      $cfg['SuhosinDisableWarning'], [1] +
      + + +
      $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'] +
      + + +
      $cfg['VersionCheck'] +
      + + +
      $cfg['ZipDump'] +
      + + +
      .htaccess +
      + +
      + +

      A

      + + + +
      + +
      ACL +
      + + +
      AllowArbitraryServer +
      + + +
      AllowDeny, order +
      + + +
      AllowDeny, rules +
      + + +
      AllowNoPassword +
      + + +
      AllowRoot +
      + +
      + +
      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

      + + + +
      + +
      CGI +
      + + +
      Changelog +
      + + +
      CharEditing +
      + + +
      CharTextareaCols +
      + + +
      CharTextareaRows +
      + + +
      CheckConfigurationPermissions +
      + + +
      Client +
      + + +
      CodemirrorEnable +
      + + +
      column +
      + + +
      column_info +
      + + +
      compress +
      + + +
      CompressOnFly +
      + +
      + +
      + Config +
      + +
      + +
      Authentication mode +
      + +
      + +
      config.inc.php +
      + + +
      + configuration option +
      + +
      + +
      $cfg['AllowArbitraryServer'], [1], [2] +
      + + +
      $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['CharEditing'], [1] +
      + + +
      $cfg['CharTextareaCols'] +
      + + +
      $cfg['CharTextareaRows'] +
      + + +
      $cfg['CheckConfigurationPermissions'] +
      + + +
      $cfg['CodemirrorEnable'] +
      + + +
      $cfg['CompressOnFly'], [1] +
      + + +
      $cfg['Confirm'] +
      + + +
      $cfg['DBG'] +
      + + +
      $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['Error_Handler']['gather'] +
      + + +
      $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'], [1] +
      + + +
      $cfg['MaxSizeForInputField'] +
      + + +
      $cfg['MaxTableList'] +
      + + +
      $cfg['McryptDisableWarning'] +
      + + +
      $cfg['MemoryLimit'] +
      + + +
      $cfg['MinSizeForInputField'] +
      + + +
      $cfg['MySQLManualBase'] +
      + + +
      $cfg['MySQLManualType'], [1] +
      + + +
      $cfg['NaturalOrder'] +
      + + +
      $cfg['NaviBackground'] +
      + + +
      $cfg['NaviPointerBackground'] +
      + + +
      $cfg['NaviPointerColor'] +
      + + +
      $cfg['NaviWidth'] +
      + + +
      $cfg['NavigationBarIconic'] +
      + + +
      $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['PersistentConnections'] +
      + + +
      $cfg['PmaAbsoluteUri'], [1], [2], [3], [4], [5] +
      + + +
      $cfg['PmaNoRelation_DisableWarning'] +
      + + +
      $cfg['PropertiesIconic'] +
      + + +
      $cfg['PropertiesNumColumns'] +
      + + +
      $cfg['ProtectBinary'] +
      + + +
      $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['SQP']['fmtColor'] +
      + + +
      $cfg['SQP']['fmtInd'], [1] +
      + + +
      $cfg['SQP']['fmtIndUnit'], [1] +
      + + +
      $cfg['SQP']['fmtType'] +
      + + +
      $cfg['SaveCellsAtOnce'] +
      + + +
      $cfg['SaveDir'] +
      + + +
      $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]['DisableIS'], [1] +
      + + +
      $cfg['Servers'][$i]['LogoutURL'] +
      + + +
      $cfg['Servers'][$i]['MaxTableUiprefs'] +
      + + +
      $cfg['Servers'][$i]['ShowDatabasesCommand'] +
      + + +
      $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]['controluser'], [1], [2], [3] +
      + + +
      $cfg['Servers'][$i]['designer_coords'], [1] +
      + + +
      $cfg['Servers'][$i]['extension'], [1] +
      + + +
      $cfg['Servers'][$i]['hide_db'] +
      + + +
      $cfg['Servers'][$i]['history'], [1], [2] +
      + + +
      $cfg['Servers'][$i]['host'], [1], [2], [3], [4] +
      + + +
      $cfg['Servers'][$i]['nopassword'] +
      + + +
      $cfg['Servers'][$i]['only_db'], [1], [2] +
      + + +
      $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] +
      + + +
      $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]['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]['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['ShowTooltip'] +
      + + +
      $cfg['SkipLockedTables'] +
      + + +
      $cfg['SuhosinDisableWarning'], [1] +
      + + +
      $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'] +
      + + +
      $cfg['VersionCheck'] +
      + + +
      $cfg['ZipDump'] +
      + + +
      $cfg['blowfish_secret'], [1] +
      + +
      + +
      Configuration storage +
      + + +
      Confirm +
      + + +
      connect_type +
      + + +
      controlhost +
      + + +
      controlpass +
      + + +
      controluser +
      + + +
      Cookie +
      + +
      + +
      Authentication mode +
      + +
      + +
      CSPAllow +
      + + +
      CSV +
      + +
      + +

      D

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

      E

      + + + +
      + +
      EditInWindow +
      + + +
      Engine +
      + + +
      Error_Handler, display +
      + + +
      Error_Handler, gather +
      + +
      + +
      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 +
      + + +
      MySQLManualBase +
      + + +
      MySQLManualType +
      + +
      + +

      N

      + + + +
      + +
      NaturalOrder +
      + + +
      NaviBackground +
      + + +
      NavigationBarIconic +
      + + +
      NavigationDisplayLogo +
      + + +
      NavigationDisplayServers +
      + + +
      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 +
      + + +
      PEAR +
      + + +
      PersistentConnections +
      + + +
      PHP +
      + + +
      phpMyAdmin configuration storage +
      + +
      + +
      PmaAbsoluteUri +
      + + +
      pmadb, [1] +
      + + +
      PmaNoRelation_DisableWarning +
      + + +
      port, [1] +
      + + +
      PropertiesIconic +
      + + +
      PropertiesNumColumns +
      + + +
      ProtectBinary +
      + +
      + +

      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 +
      + + +
      Server +
      + + +
      + server configuration +
      + +
      + +
      AllowDeny, order +
      + + +
      AllowDeny, rules +
      + + +
      AllowNoPassword +
      + + +
      AllowRoot +
      + + +
      DisableIS +
      + + +
      LogoutURL +
      + + +
      MaxTableUiprefs +
      + + +
      ShowDatabasesCommand +
      + + +
      SignonScript +
      + + +
      SignonSession +
      + + +
      SignonURL +
      + + +
      StatusCacheDatabases +
      + + +
      StatusCacheLifetime +
      + + +
      auth_http_realm +
      + + +
      auth_swekey_config +
      + + +
      auth_type +
      + + +
      bookmarktable +
      + + +
      column_info +
      + + +
      compress +
      + + +
      connect_type +
      + + +
      controlhost +
      + + +
      controlpass +
      + + +
      controluser +
      + + +
      designer_coords +
      + + +
      extension +
      + + +
      hide_db +
      + + +
      history +
      + + +
      host +
      + + +
      nopassword +
      + + +
      only_db +
      + + +
      password +
      + + +
      pdf_pages +
      + + +
      pmadb +
      + + +
      port +
      + + +
      recent +
      + + +
      relation +
      + + +
      socket +
      + + +
      ssl +
      + + +
      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 +
      + + +
      verbose +
      + +
      + +
      ServerDefault +
      + + +
      ServerLibraryDifference_DisableWarning +
      + + +
      Servers +
      + + +
      SessionSavePath +
      + + +
      Setup script +
      + + +
      ShowAll +
      + + +
      ShowBrowseComments +
      + + +
      ShowChgPassword +
      + + +
      ShowCreateDb +
      + + +
      ShowDatabasesCommand +
      + + +
      ShowDbStructureCreation +
      + + +
      ShowDbStructureLastCheck +
      + + +
      ShowDbStructureLastUpdate +
      + + +
      ShowDisplayDirection +
      + + +
      ShowFieldTypesInDataEditView +
      + + +
      ShowFunctionFields +
      + + +
      ShowHint +
      + + +
      ShowPhpInfo +
      + + +
      ShowPropertyComments +
      + + +
      ShowServerInfo +
      + + +
      ShowSQL +
      + + +
      ShowStats +
      + + +
      ShowTooltip +
      + + +
      + 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 +
      + + +
      SQP, fmtColor +
      + + +
      SQP, fmtInd +
      + + +
      SQP, fmtIndUnit +
      + + +
      SQP, fmtType +
      + + +
      SSL +
      + + +
      ssl +
      + + +
      StatusCacheDatabases +
      + + +
      StatusCacheLifetime +
      + + +
      Storage Engines +
      + + +
      Stored procedure +
      + + +
      SuhosinDisableWarning +
      + + +
      + Swekey +
      + +
      + +
      Authentication mode +
      + +
      +
      + +

      T

      + + + +
      + +
      table +
      + + +
      table_coords +
      + + +
      table_info +
      + + +
      table_uiprefs +
      + + +
      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 +
      + + +
      UserprefsDeveloperTab +
      + + +
      UserprefsDisallow +
      + +
      + +

      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 000000000..757eb4908 --- /dev/null +++ b/phpmyadmin/doc/html/glossary.html @@ -0,0 +1,627 @@ + + + + + + + + + + Glossary — phpMyAdmin 4.0.4 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 000000000..bb0068868 --- /dev/null +++ b/phpmyadmin/doc/html/index.html @@ -0,0 +1,206 @@ + + + + + + + + + + Welcome to phpMyAdmin’s documentation! — phpMyAdmin 4.0.4 documentation + + + + + + + + + + + + + + + +
      + +
      +
      +

      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 000000000..5d3bfbefe --- /dev/null +++ b/phpmyadmin/doc/html/intro.html @@ -0,0 +1,182 @@ + + + + + + + + + + Introduction — phpMyAdmin 4.0.4 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 RFC 1952 or +Bzip2 formats) dumps and CSV exports if you use PHP with +Zlib support (--with-zlib) and/or Bzip2 support +(--with-bz2). 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..51678917a1bb1e434920b78e06dde59f85e4f721 GIT binary patch literal 9513 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 + + + + + + + Other sources of information — phpMyAdmin 4.0.4 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 000000000..be2036750 --- /dev/null +++ b/phpmyadmin/doc/html/privileges.html @@ -0,0 +1,169 @@ + + + + + + + + + + User management — phpMyAdmin 4.0.4 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 000000000..b47afe5f0 --- /dev/null +++ b/phpmyadmin/doc/html/require.html @@ -0,0 +1,170 @@ + + + + + + + + + + Requirements — phpMyAdmin 4.0.4 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.2.0 or newer, with session support, the Standard PHP Library +(SPL) extension and JSON support.
      • +
      • To support uploading of ZIP files, you need the PHP zip extension.
      • +
      • For proper support of multibyte strings (eg. UTF-8, which is currently +the default), you should install the mbstring and ctype extensions.
      • +
      • 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 PHP +5.2.17 or newer and the libxml +extension.
      • +
      + +
      +
      +

      Database

      +

      phpMyAdmin support MySQL compatible databases.

      +
        +
      • MySQL 5.0 or newer
      • +
      • MariaDB 5.0 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 000000000..83caa39b3 --- /dev/null +++ b/phpmyadmin/doc/html/search.html @@ -0,0 +1,100 @@ + + + + + + + + + + Search — phpMyAdmin 4.0.4 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 000000000..c4dfde218 --- /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['GZipDump']":[13,0,1,"cfg_GZipDump"],"$cfg['SQLValidator']":[13,0,1,"cfg_SQLValidator"],"$cfg['ShowBrowseComments']":[13,0,1,"cfg_ShowBrowseComments"],"$cfg['CompressOnFly']":[13,0,1,"cfg_CompressOnFly"],"$cfg['NavigationTreePointerEnable']":[13,0,1,"cfg_NavigationTreePointerEnable"],"$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['Servers'][$i]['SignonSession']":[13,0,1,"cfg_Servers_SignonSession"],"$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['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['MemoryLimit']":[13,0,1,"cfg_MemoryLimit"],"$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['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['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['SQP']['fmtInd']":[13,0,1,"cfg_SQP_fmtInd"],"$cfg['Order']":[13,0,1,"cfg_Order"],"$cfg['GD2Available']":[13,0,1,"cfg_GD2Available"],"$cfg['PmaAbsoluteUri']":[13,0,1,"cfg_PmaAbsoluteUri"],"$cfg['PropertiesIconic']":[13,0,1,"cfg_PropertiesIconic"],"$cfg['NavigationBarIconic']":[13,0,1,"cfg_NavigationBarIconic"],"$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['RepeatCells']":[13,0,1,"cfg_RepeatCells"],"$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['ShowDbStructureLastUpdate']":[13,0,1,"cfg_ShowDbStructureLastUpdate"],"$cfg['Servers'][$i]['connect_type']":[13,0,1,"cfg_Servers_connect_type"],"$cfg['MaxNavigationItems']":[13,0,1,"cfg_MaxNavigationItems"],"$cfg['ThemeManager']":[13,0,1,"cfg_ThemeManager"],"$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['LimitChars']":[13,0,1,"cfg_LimitChars"],"$cfg['ShowTooltip']":[13,0,1,"cfg_ShowTooltip"],"$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['ZipDump']":[13,0,1,"cfg_ZipDump"],"$cfg['Servers'][$i]['bookmarktable']":[13,0,1,"cfg_Servers_bookmarktable"],"$cfg['NavigationDisplayLogo']":[13,0,1,"cfg_NavigationDisplayLogo"],"$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['SQP']['fmtIndUnit']":[13,0,1,"cfg_SQP_fmtIndUnit"],"$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['ShowDbStructureLastCheck']":[13,0,1,"cfg_ShowDbStructureLastCheck"],"$cfg['DefaultTabServer']":[13,0,1,"cfg_DefaultTabServer"],"$cfg['MySQLManualBase']":[13,0,1,"cfg_MySQLManualBase"],"$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['Servers'][$i]['SignonScript']":[13,0,1,"cfg_Servers_SignonScript"],"$cfg['HeaderFlipType']":[13,0,1,"cfg_HeaderFlipType"],"$cfg['SuhosinDisableWarning']":[13,0,1,"cfg_SuhosinDisableWarning"],"$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['ShowChgPassword']":[13,0,1,"cfg_ShowChgPassword"],"$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['Error_Handler']['gather']":[13,0,1,"cfg_Error_Handler_gather"],"$cfg['Servers'][$i]['StatusCacheDatabases']":[13,0,1,"cfg_Servers_StatusCacheDatabases"],"$cfg['BrowseMarkerBackground']":[13,0,1,"cfg_BrowseMarkerBackground"],"$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]['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['MySQLManualType']":[13,0,1,"cfg_MySQLManualType"],"$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['ThemePath']":[13,0,1,"cfg_ThemePath"],"$cfg['BrowseMarkerEnable']":[13,0,1,"cfg_BrowseMarkerEnable"],"$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['McryptDisableWarning']":[13,0,1,"cfg_McryptDisableWarning"],"$cfg['TitleTable']":[13,0,1,"cfg_TitleTable"],"$cfg['AllowArbitraryServer']":[13,0,1,"cfg_AllowArbitraryServer"],"$cfg['RecodingEngine']":[13,0,1,"cfg_RecodingEngine"],"$cfg['Servers']":[13,0,1,"cfg_Servers"],"$cfg['NaviBackground']":[13,0,1,"cfg_NaviBackground"],"$cfg['VersionCheck']":[13,0,1,"cfg_VersionCheck"],"$cfg['BrowsePointerBackground']":[13,0,1,"cfg_BrowsePointerBackground"],"$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['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['ServerDefault']":[13,0,1,"cfg_ServerDefault"],"$cfg['ShowDisplayDirection']":[13,0,1,"cfg_ShowDisplayDirection"],"$cfg['IgnoreMultiSubmitErrors']":[13,0,1,"cfg_IgnoreMultiSubmitErrors"],"$cfg['SessionSavePath']":[13,0,1,"cfg_SessionSavePath"],"$cfg['ShowCreateDb']":[13,0,1,"cfg_ShowCreateDb"],"$cfg['SQP']['fmtColor']":[13,0,1,"cfg_SQP_fmtColor"],"$cfg['InsertRows']":[13,0,1,"cfg_InsertRows"],"$cfg['LoginCookieDeleteAll']":[13,0,1,"cfg_LoginCookieDeleteAll"],"$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['ForceSSL']":[13,0,1,"cfg_ForceSSL"],"$cfg['SQLQuery']['Edit']":[13,0,1,"cfg_SQLQuery_Edit"],"$cfg['CheckConfigurationPermissions']":[13,0,1,"cfg_CheckConfigurationPermissions"],"$cfg['NavigationTreeDbSeparator']":[13,0,1,"cfg_NavigationTreeDbSeparator"],"$cfg['Servers'][$i]['LogoutURL']":[13,0,1,"cfg_Servers_LogoutURL"],"$cfg['SQP']['fmtType']":[13,0,1,"cfg_SQP_fmtType"],"$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['Servers'][$i]['history']":[13,0,1,"cfg_Servers_history"],"$cfg['Import']":[13,0,1,"cfg_Import"],"$cfg['DBG']":[13,0,1,"cfg_DBG"],"$cfg['AvailableCharsets']":[13,0,1,"cfg_AvailableCharsets"],"$cfg['Servers'][$i]['ShowDatabasesCommand']":[13,0,1,"cfg_Servers_ShowDatabasesCommand"],"$cfg['MaxSizeForInputField']":[13,0,1,"cfg_MaxSizeForInputField"],"$cfg['Servers'][$i]['DisableIS']":[13,0,1,"cfg_Servers_DisableIS"],"$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['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]['AllowDeny']['rules']":[13,0,1,"cfg_Servers_AllowDeny_rules"],"$cfg['Servers'][$i]['pmadb']":[13,0,1,"cfg_Servers_pmadb"],"$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,digit:13,everi:[4,5,13],risk:[5,13],dutch:8,max_value_length:5,alberty_at_neptunlab:8,affect:[5,13],opendocu:[3,10],viewabl:13,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,here:[4,5,13,1],beck:8,path:[4,5,13,9],interpret:5,michal:[8,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,13],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,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,defaultconnectioncol:13,root:[4,5,13,14],overrid:4,give:[4,5,9],autodetect:13,delislma_at_collegesherbrook:8,indic:0,pandithawatta:8,unavail:13,want:[4,5,13,1,9],web_brows:3,unsign:1,horizonta:13,end:[4,5,13,1],chanaka:8,quot:[5,13],travel:4,zzzz:13,march:8,how:[4,5,13,1],func_numb:13,disappear:[5,13],pikto:5,answer:3,config:[4,5,13,9],updat:[8,4,5,13],process_priv:4,chines:8,after:[4,5,13],lump:5,manuali:4,befor:[4,5,13],wrong:[5,13],star_at_origin:8,router:4,allowuserdropdatabas:13,averag:5,autoconnect:13,attempt:[5,13],third:[5,13,7],grant:[4,5,14],credenti:[4,13],think:5,matiasbellone_at_gmail:8,witten:8,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],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,alpha_columntyp:13,timeout:[5,13],rowactionlink:13,complet:[8,5,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:[3,0,4,13,1],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,primari:[3,8,5],fontfamilyfix:13,top:[4,5,13],sometim:5,amalesh:8,master:[7,13],too:[5,13,12],pma__designer_coord:13,danish:8,mysqlmanualtyp:13,tool:[8,5,13,12],"17a":5,sync:8,past:13,max_link:5,provid:[1,3,4,5,9,13],tree:[8,13],project:[3,0,5,8],serverlibrarydifference_disablewarn:13,swekei:[4,13],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,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,13],lose:[5,13],doe:[1,4,5,10,13,6,14],omniexplorer_bot:5,bracket:13,wildcard:[5,13],neg:5,winningham:8,mrbendig_at_mrbendig:8,dot:[5,13],ldi_:8,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],tracking_default_stat:13,hopefulli:1,databas:[0,3,4,5,8,10,11,13,6,14],wikipedia:3,tracking_version_auto_cr:13,bgone:13,wiltave_at_gmail:8,atul:8,yahooseek:5,adnan:8,approach:13,attribut:13,accord:13,extend:[3,5,1],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],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,5,13],properti:[8,5,13,1],sourceforg:[8,5,2],rouslan:8,pmanorelation_disablewarn:13,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],suggest:[8,4,5,6],make:[4,5,13,1,12],ammar:8,complex:[5,10],descend:13,roszatycki:8,schema_privileg: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,punct_queryend: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],alpha_columnattrib: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],jan_at_nrw:8,applic:[3,4,5,13],mayb:5,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,manual:[13,4,5,10,1],zoom:[8,5],soap:[3,5,13],create_priv:4,sebastian:[8,2],underli:5,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,thu:5,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,13],localhost:[4,5,13],core:3,plu:[8,5],titleserv:13,connect_typ:13,punct_bracket_close_round: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],tbl_dump:5,kissu:8,curiou:5,"float":13,profession:3,bound:1,repl_client_priv:4,down:[14,5,13,1,9],slurp:5,xavier:8,netscap:5,wrap:13,storag:[3,0,4,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],"class":[5,13,1],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,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,legenhausen:8,featur:[0,3,4,5,8,10,12,13],classic:[5,13],request:[3,4,5,13],filterlanguag:13,decrypt:5,zend:5,mysql_fetch_field:1,seoma:5,showdisplaydirect:13,exist:[4,5,8,11,13,14],ship:[3,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],why:[5,13],sqp:13,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,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,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,6,5,13,1],fando:5,initialslidersst:13,maxcharactersindisplayedsql:13,insertrow:13,word:[13,0,5,10],brows:[13,0,5,10,8],seealso:3,administr:[8,4,5,13,14],level:[3,4,5,13],did:5,win2k:5,"gesch\u00e9":8,item:[3,5,13],team:4,cooki:[0,3,4,5,8,13,6],dir:[5,1],prevent:[4,5,13],slower:6,obrador:8,bravo:8,applytransform:1,cost:4,dev:[3,5,13],turnitinbot:5,port:[3,5,13],digit_integ:13,appear:[5,13],session_save_path:13,abdullah:8,uniform:3,current:[3,4,5,8,9,10,13,6],portugues:8,axel:8,navigationtreepointeren:13,chartextarearow:13,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,getinfo:1,circumv:5,tweak:4,modul:[3,5],prefer:[8,4,5,13],backtick: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],stylesheet:13,handler:3,everywher:5,criteria:5,scope:4,translit:13,maxime_at_fre:8,chapter:[5,13],said: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: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,sensi:5,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,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,showdatabasescommand: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,navigationbaricon:13,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:[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],maxnavigationitem:13,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],didn:13,separ:[3,8,5,13],comment_c:13,gergo314_at_gmail:8,compressonfli:[5,13],compil:5,domain:[5,13],replac:[4,5,13,9],individu:14,continu:13,contributor:8,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],fmtind:13,internet:[3,4,5,13],ufpdf:[3,8],correct:[5,13],integr:[13,5,10],iusr_machin:5,dbc334_at_gmail:8,state:13,migrat:5,xhtml1:8,recodingengin:13,phpmyadmin_x:4,mime:[3,8,5,13,1],superus:[4,14],fmtcolor:13,ruleant_at_us:8,mysqli:[3,8,5,10,13],"byte":13,care:[5,1],quote_doubl:13,diagram:5,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,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],punct_qualifi: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,quote_backtick:13,transformationsplugin:1,tecnick:8,n8falke_at_us:8,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],maintain:8,harald:5,take:[5,13,1],advis:13,noth:5,sqlqueri:13,parti:[5,7],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],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],comment_mysql:13,analys:8,offici:[7,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,punct_listsep:13,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,refman:13,come:[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,"abstract":[8,1],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,destin:3,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],alphabet:13,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,defaulttabt:13,webserv:[3,4,5,13],screenshot:5,nest:[8,5,13],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:[13,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,gather:13,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],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,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,nokeepal:5,complic:13,refer:[3,5,13],column_info:[13,1],schaefer:8,arrow:5,olof:8,quit:[8,5,13],each:[1,3,4,5,13,14],xzvf:4,broken:5,stdpass:13,found:[4,5,13],navigationtreedbsepar:13,digit_float: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,strip:[9,5,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],lot:[5,13],ipv6:[3,13],submiss:13,machin:[3,4,5,13,6],hindi:8,hard:13,tupl:[3,13],bundl:5,regard:[10,1],upload_max_files:5,cryptograph:3,realli:[4,5,13],adler:3,faster:13,pull:13,possibl:[4,5,13,1,12],"default":[0,1,3,4,5,13,6],textarearow:13,embed:13,expect:5,scanner:5,creat:[3,4,5,8,10,11,13,14],multibyt:6,certain:[3,13,1],certail:5,mike:8,strongli:[6,5],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],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,13],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],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],"\u010diha\u0159":[8,2],pbm:8,tbl_creat:8,enterpris:5,homonym:5,internetwork:3,template_abstract:1,path_to_phpmyadmin:5,showbrowsecom:13,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,13],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,2],full:[4,5,13,14],hash:5,berkelei:13,wilk:8,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],fmtindunit:13,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],webmaster_at_trafficg:8,bulgarian:8,desir:10,showtooltip:13,kristof:8,hundr:5,mozilla:5,oleg:8,particular:[3,4,14,2],known:[3,0,9,5,13],"bokm\u00e5l":8,cach:[5,13],town:5,none:13,der:8,showfieldtypesindataeditview:13,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,alpha_reservedword:13,csv:[3,5,10],simpl:[3,4,5],css:[5,13],resourc:3,unprivileg:13,quote_singl:13,reflect:3,sven:8,okai:4,mendel:[8,2],mariadb:[6,5],associ:4,pma__rec:13,svec:8,mous:[5,13],"short":3,john1db:5,footer:13,themepath:[5,13],caus:[6,5,13],media:5,checkbox:[14,5,13],rotat:13,hypertext:3,soon:5,soom:8,paper:5,through:[3,13,5,10,1],same:[4,5,13,14],urdu:8,ipmask:13,"montr\u00e9al":5,disablei:13,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],alpha_vari:13,might:[4,5,13,9],alter:[13,5,10],good:[4,5,13,1],"return":[5,13,1],timestamp:[4,13],disable_funct:13,select_priv:4,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,schema_nam: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,qualifi:13,proxi:[4,5,13],advanc:[4,13],browsepointerbackground:13,asc:13,quick:[3,0,4,5,13],reason:[5,13],base:[3,6,5,8,9,13],ask:[3,0,5],ash:8,english:[8,4,13],repl_slave_priv:4,bakondi:8,perhap:4,schemata:13,pma__rel:5,vainauska:8,lifetim:13,assign:[14,5,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],differ:[1,3,4,5,8,10,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,builder:8,pma:4,comput:3,well:[13,8,5,10],wysiwyg:8,packag:[0,9,5],translationwarningthreshold:13,mod_rewrit:5,"null":[5,13],wilson:8,unintend:13,bz2:[13,5,10],equival:13,self:[4,13],also:[1,3,4,5,8,9,10,13,6,14],build:[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,13],max_var:5,kempf:8,filesystem:13,clear:[4,5],qbe:[8,10],usual:[3,4,5,13,1],microsoft:[3,5,10],visibl:[5,13],paul: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],cspallow:13,impact:[4,5,13],access:[3,4,5,8,13,6],beck_at_web:8,pretti:[8,13],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,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,navigationtreetablesepar:[5,13],altern:[4,5,13],numer:[5,13],serverdefault:13,javascript:[8,6,5,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:[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,memory_limit:5,bzip:5,org:[3,8,5,13,2],repeatcel:13,mind:4,imag:[3,6,5,10,1],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],error:[4,5,13],anonym:[5,13],everyon:8,pack:5,real:[5,13],mac_os_x:3,readi:4,table_schema:13,jpg:3,asuni:8,itself:5,alter_priv:4,ignacio:8,minim:[4,5],shorten:5,shorter:5,conflict:5,higher:5,signon:[4,13],veeven_at_gmail:8,proxypassreversecookiepath:5,optim:[8,5,13],alert:5,"tom\u00e1\u0161":8,temporari:[4,5,13],winhttp:5,maxdblist:13,winnt4:5,recent:[3,5,13],lower:[5,13],drop_priv:4,lib:[4,5,1,9],older:[0,4,5,13],kelli:8,entri:[4,13],maxsizeforinputfield:13,person:[3,5,13],userstatu:5,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,shortcut:13,mydatabas:13,input:[4,5,13],useless:5,bin: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,punct_bracket_open_round:13,often:[5,13],creation:[8,13],some:[1,3,4,5,8,9,13],back:[3,4,5,14],scratchboard:[8,5],sampl:[4,5,13],pmadb:[5,13],mirror:5,scale:5,per:13,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,fmttype:13,ummer:5,weis:8,cochran:8,step:[4,5],bruguera:8,impos:13,blowfish_:3,proce:5,mmcach:5,delisl:[8,7,2],dialog:[4,5],func_char:13,mcrypt:[3,4,5,13,6],italian:8,gamma:5,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,serif:13,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,6],consist:5,mrbendig:8,hamann:8,reorder:5,mj12bot:5,highlight:13,similar:[4,5,13],enlarg:5,parser:[0,13,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,declar:[5,1],urltrend:5,tempdir:[5,13],browsemarkerbackground:13,navipointercolor:13,show_db_priv:4,heis:5,drag:5,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,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],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,comment_ansi:13,button:[5,13],michael:[8,2],stuffit:4,fewer:13,"try":[4,5,13],mathia:8,alia:8,queryhistorymax: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,punct:13,firewal:[4,5,13],logout:13,ubuntu:13,vertic:[3,8,13],sinc:[8,4,5,13,6],pma_dbi:8,convert:5,copyright:[0,2],themedefault:[5,13],baishui:8,larger:[5,13],technolog:[3,5],delorm:8,typim:8,auth_kei:4,typic:[3,5],forkik_at_gmail:8,control:[3,4,5,8,13,14],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,5,13,12],few:[4,5,13],lesli:8,webcrawl:5,ninad:8,sort:[3,5,13],pencil:14,client_:3,proxypass:5,newsblog:5,trail:13,defaultqueryt:13,central:[4,5,13],harvest:5,abtract:1,acko:[3,8],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,fetch:13,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,13],delai:5,andersen:8,siu:8,slovenian:8,subdirectori:[4,5,13],instead:[4,5,13],chri:8,pink:5,klau:5,mysqlmanualbas:13,attent:4,mod_ssl:5,nordenberg:8,alloc:13,walton_at_nordicdm:8,light:13,astarita:8,correspond:[5,13,1],element:[3,5,13,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,mention:[4,5],srnka:8,databa:5,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,consum:3,drizzl:[8,6,5,13],httrack:5,our:[7,5,13,1,12],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,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,indent: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],alpha_identifi:13,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,attach:3,attack:5,appl:3,lower_case_table_nam:5,pavel:8,rfc2616_header:5,lacina:8,ipv4:3,shell:5,mbstring:6,methodolog:3,slider:13,obgzip:[5,13],textfield:1,haven:5,gzipdump:13,photograph:3,digit_hex:13,alpha_functionnam:13,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,bzcompress:5,probabl:[4,5,13,9],rout:13,propertiesicon: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,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:5,turek:[8,2],"mat\u00eda":8,controlus:[4,5,13],redirect:[5,13],textual:5,locat:[3,4,5],anticip:3,auth_typ:[4,5,13],should:[2,4,5,8,9,13,6],manufactur:3,bernard:8,tape:3,local:[4,5,13],"lu\u00ed":8,hope:2,contribut:[8,5,12],autom:8,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,alessandro:8,temporarili:5,tracking_add_drop_t:13,statu:[8,5,13],convers:[8,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],server_privileg:13,addit:[3,8,4,5,13],revers:[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,searchabl:[4,13],disablemultitablemainten:13,"10_at_windowsl":8,addition:13,quotat: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:[5,13],present:[5,13],hitowerdigit_at_hotmail:8,replic:8,multi:[0,3,4,5,8,13],tbl_chang:[8,13],showdbstructurecr:13,plain:[4,5,13,1],align:5,yuichiro:8,harden:5,defin:[3,14,5,13,1],scatter:5,glossari:[3,0],server_databas:13,ini:[13,5,10],layer:3,purchas:4,dieter:8,almost: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,largest:5,abravo_at_hq:8,linklengthlimit:13,inc:[4,5,13,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:5,nevertheless:4,colour:13,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,geert:8,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,punctuat:13,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,drop:[1,14,5,8,10,13],prepend:1,convei:3,jan:8,"kozio\u0142":8,linux:[4,13,9],"landh\u00e4u\u00df":8,"export":[13,0,5,10,8],unstuff:4,proper:[1,4,5,10,13,6],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,13],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,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,transformation_overview:1,automat:[3,8,5,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,"var":[9,5],information_schema:13,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,"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,bzip2:[3,13,5,10],detail:[4,5,13,2],logincookierecal:13,book:[7,11],futur:[5,13],branch:5,php4:[8,5],blowfish_secret:[4,13],php3:8,repeat:[5,13],star:8,mysql_upgrad:5,june:8,kanichet_at_hotmail:8,server_statu:13,showpropertycom:13,debian:13,gergo314:8,markup:3,outsourc:8,fund:4,reliabl:5,kanji:8,rule:[4,5,13,1],post_max_s:5,portion:13,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 000000000..aec2ae169 --- /dev/null +++ b/phpmyadmin/doc/html/setup.html @@ -0,0 +1,481 @@ + + + + + + + + + + Installation — phpMyAdmin 4.0.4 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”).

      +
      +
      +

      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. +
      +
      +

      Manualy creating 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. 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 (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.

      +

      If you want to use the many new relation and bookmark features: (this of +course requires that your phpMyAdmin configuration storage be set up).

      +
      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:

      +
        +
      • remove setup directory from phpMyAdmin, you will probably not +use it after initial setup
      • +
      • prevent access to libraries directory from browser, +as it is not needed, supplied .htaccess file does this
      • +
      • properly choose authentication method - Cookie authentication mode +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 $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
      • +
      +
      +
      + + +
      +
      +
      + +
      +
      + + + + \ 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 000000000..887884e1a --- /dev/null +++ b/phpmyadmin/doc/html/transformations.html @@ -0,0 +1,240 @@ + + + + + + + + + + Transformations — phpMyAdmin 4.0.4 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 000000000..8af33c0c4 --- /dev/null +++ b/phpmyadmin/doc/html/user.html @@ -0,0 +1,135 @@ + + + + + + + + + + User Guide — phpMyAdmin 4.0.4 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 000000000..a54f81d29 --- /dev/null +++ b/phpmyadmin/doc/html/vendors.html @@ -0,0 +1,147 @@ + + + + + + + + + + Distributing and packaging phpMyAdmin — phpMyAdmin 4.0.4 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 000000000..917ddf810 --- /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 000000000..9d81e44a4 --- /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` :term:`RFC 1952` or + :term:`Bzip2` formats) dumps and :term:`CSV` exports if you use PHP with + :term:`Zlib` support (``--with-zlib``) and/or :term:`Bzip2` support + (``--with-bz2``). 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 000000000..19b60901f --- /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 000000000..aa9545121 --- /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 000000000..0c12932d0 --- /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 000000000..1452ee34f --- /dev/null +++ b/phpmyadmin/doc/require.rst @@ -0,0 +1,55 @@ +.. _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.2.0 or newer, with ``session`` support, the Standard PHP Library + (SPL) extension and JSON support. + +* To support uploading of ZIP files, you need the PHP ``zip`` extension. + +* For proper support of multibyte strings (eg. UTF-8, which is currently + the default), you should install the ``mbstring`` and ``ctype`` extensions. + +* 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 PHP + 5.2.17 or newer and the `libxml `_ + extension. + +.. seealso:: :ref:`faq1_31`, :ref:`authentication_modes` + +Database +-------- + +phpMyAdmin support MySQL compatible databases. + +* MySQL 5.0 or newer +* MariaDB 5.0 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 000000000..850d67a2c --- /dev/null +++ b/phpmyadmin/doc/setup.rst @@ -0,0 +1,424 @@ +.. _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``"). + +.. _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. + + +Manualy creating 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:: php + + + + +Or, if you prefer to not be prompted every time you log in: + +.. code-block:: 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. 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 (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. + +If you want to use the many new relation and bookmark features: (this of +course requires that your :ref:`linked-tables` be set up). + +.. 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 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*: + +.. 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 +* prevent access to ``libraries`` directory from browser, + as it is not needed, supplied ``.htaccess`` file does this +* 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 diff --git a/phpmyadmin/doc/transformations.rst b/phpmyadmin/doc/transformations.rst new file mode 100644 index 000000000..4c3ce46c9 --- /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 000000000..ceaf72332 --- /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 000000000..13d7e550a --- /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/examples/config.manyhosts.inc.php b/phpmyadmin/examples/config.manyhosts.inc.php new file mode 100644 index 000000000..ad29c3a83 --- /dev/null +++ b/phpmyadmin/examples/config.manyhosts.inc.php @@ -0,0 +1,46 @@ + array( + 'user' => 'root', + 'password' => '', + ), + ); + +/** + * Simple function to show HTML page with given content. + * + * @return void + */ +function show_page($contents) +{ + header('Content-Type: text/html; charset=utf-8'); + echo '' . "\n"; + ?> + + + + + + + phpMyAdmin OpenID signon example + + +' . $_SESSION['PMA_single_signon_message'] . '

      '; + unset($_SESSION['PMA_single_signon_message']); +} +echo $contents; +?> + + + +OpenID:
      + + + +'; + show_page($content); + exit; +} + +/* Grab identifier */ +if (isset($_POST['identifier'])) { + $identifier = $_POST['identifier']; +} else if (isset($_SESSION['identifier'])) { + $identifier = $_SESSION['identifier']; +} else { + $identifier = null; +} + +/* Create OpenID object */ +try { + $o = new OpenID_RelyingParty($returnTo, $realm, $identifier); +} catch (OpenID_Exception $e) { + $contents = "
      \n"; + $contents .= "
      " . $e->getMessage() . "
      \n"; + $contents .= "
      "; + show_page($contents); + exit; +} + +/* Redirect to OpenID provider */ +if (isset($_POST['start'])) { + try { + $authRequest = $o->prepare(); + } catch (OpenID_Exception $e) { + $contents = "
      \n"; + $contents .= "
      " . $e->getMessage() . "
      \n"; + $contents .= "
      "; + show_page($contents); + exit; + } + + $url = $authRequest->getAuthorizeURL(); + + header("Location: $url"); + exit; +} else { + /* Grab query string */ + if (!count($_POST)) { + list(, $queryString) = explode('?', $_SERVER['REQUEST_URI']); + } else { + // I hate php sometimes + $queryString = file_get_contents('php://input'); + } + + /* Check reply */ + $message = new OpenID_Message($queryString, OpenID_Message::FORMAT_HTTP); + + $id = $message->get('openid.claimed_id'); + + if (!empty($id) && isset($AUTH_MAP[$id])) { + $_SESSION['PMA_single_signon_user'] = $AUTH_MAP[$id]['user']; + $_SESSION['PMA_single_signon_password'] = $AUTH_MAP[$id]['password']; + session_write_close(); + /* Redirect to phpMyAdmin (should use absolute URL here!) */ + header('Location: ../index.php'); + } else { + show_page('

      User not allowed!

      '); + exit; + } +} diff --git a/phpmyadmin/examples/signon-script.php b/phpmyadmin/examples/signon-script.php new file mode 100644 index 000000000..0ef97340d --- /dev/null +++ b/phpmyadmin/examples/signon-script.php @@ -0,0 +1,29 @@ + diff --git a/phpmyadmin/examples/signon.php b/phpmyadmin/examples/signon.php new file mode 100644 index 000000000..6ab9e240a --- /dev/null +++ b/phpmyadmin/examples/signon.php @@ -0,0 +1,65 @@ + 'Signon test'); + $id = session_id(); + /* Close that session */ + session_write_close(); + /* Redirect to phpMyAdmin (should use absolute URL here!) */ + header('Location: ../index.php'); +} else { + /* Show simple form */ + 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)
      + +
      + + + diff --git a/phpmyadmin/examples/swekey.sample.conf b/phpmyadmin/examples/swekey.sample.conf new file mode 100644 index 000000000..ebf1aedf0 --- /dev/null +++ b/phpmyadmin/examples/swekey.sample.conf @@ -0,0 +1,44 @@ +# This is a typical file used to enable Swekey hardware authentication. +# +# To activate the Swekey authentication add the following line to your config.inc.php file. +# $cfg['Servers'][$i]['auth_swekey_config'] = '/etc/swekey-pma.conf'; +# Then rename this file "swekey-pma.conf" and copy it to the /etc directory. +# Add all the Swekey ids you want to grant access to in the file. +# After each Swekey id put the corresponding user name. +# +# If you don't know the id of a Swekey just visit http://www.swekey.com?sel=support +# while your Swekey is connected. +# +# If you need to purchase a Swekey please visit http://phpmyadmin.net/auth_key +# since this link provides funding to PhpMyAdmin. +# + +0000000000000000000000000000763A:root +000000000000000000000000000089E4:steve +0000000000000000000000000000231E:scott + +# +# It is recommended to include the following lines to contact the +# authentication servers in SSL mode. +# + +SERVER_CHECK=https://auth-check-ssl.musbe.net +SERVER_RNDTOKEN=https://auth-rnd-gen-ssl.musbe.net +SERVER_STATUS=https://auth-status-ssl.musbe.net + +# +# The path of the root certificate file used to ensure a secure +# communication with the authentication servers in SSL mode. +# If not specified, will use musbe-ca.crt found in your +# phpMyAdmin/libraries/auth/swekey. +# + +#CA_FILE=/var/http-root/phpmyadmin/libraries/auth/swekey/musbe-ca.crt + +# +# If your server receives many login requests, you can enable the random +# token caching to accelerate the authentication process. +# Token caching is enabled by default. +# + +#ENABLE_TOKEN_CACHE=0 diff --git a/phpmyadmin/examples/upgrade_tables_mysql_4_1_2+.sql b/phpmyadmin/examples/upgrade_tables_mysql_4_1_2+.sql new file mode 100644 index 000000000..df4046a49 --- /dev/null +++ b/phpmyadmin/examples/upgrade_tables_mysql_4_1_2+.sql @@ -0,0 +1,144 @@ +-- ------------------------------------------------------------- +-- SQL Commands to upgrade pmadb for normal phpMyAdmin operation +-- with MySQL 4.1.2 and above. +-- +-- This file is meant for use with MySQL 4.1.2 and above! +-- For older MySQL releases, please use create_tables.sql +-- +-- If you are running one MySQL 4.1.0 or 4.1.1, please create the tables using +-- create_tables.sql, then use this script. +-- +-- Please don't forget to set up the tablenames in config.inc.php +-- + +-- -------------------------------------------------------- + +-- +-- Database : `phpmyadmin` +-- +ALTER DATABASE `phpmyadmin` + DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; +USE phpmyadmin; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pma__bookmark` +-- +ALTER TABLE `pma__bookmark` + DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; + +ALTER TABLE `pma__bookmark` + CHANGE `dbase` `dbase` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +ALTER TABLE `pma__bookmark` + CHANGE `user` `user` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +ALTER TABLE `pma__bookmark` + CHANGE `label` `label` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''; +ALTER TABLE `pma__bookmark` + CHANGE `query` `query` TEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pma__column_info` +-- + +ALTER TABLE `pma__column_info` + DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; + +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` + CHANGE `table_name` `table_name` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +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` + CHANGE `comment` `comment` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''; +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` + CHANGE `transformation` `transformation` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +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` +-- +ALTER TABLE `pma__history` + DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; + +ALTER TABLE `pma__history` + CHANGE `username` `username` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +ALTER TABLE `pma__history` + CHANGE `db` `db` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +ALTER TABLE `pma__history` + CHANGE `table` `table` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +ALTER TABLE `pma__history` + CHANGE `sqlquery` `sqlquery` TEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pma__pdf_pages` +-- + +ALTER TABLE `pma__pdf_pages` + DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; + +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` + CHANGE `page_descr` `page_descr` VARCHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL default ''; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pma__relation` +-- +ALTER TABLE `pma__relation` + DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; + +ALTER TABLE `pma__relation` + CHANGE `master_db` `master_db` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +ALTER TABLE `pma__relation` + CHANGE `master_table` `master_table` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +ALTER TABLE `pma__relation` + CHANGE `master_field` `master_field` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +ALTER TABLE `pma__relation` + CHANGE `foreign_db` `foreign_db` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +ALTER TABLE `pma__relation` + CHANGE `foreign_table` `foreign_table` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +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` +-- + +ALTER TABLE `pma__table_coords` + DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; + +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` + CHANGE `table_name` `table_name` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pma__table_info` +-- + +ALTER TABLE `pma__table_info` + DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; + +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` + CHANGE `table_name` `table_name` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; +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 new file mode 100644 index 000000000..c2373e305 --- /dev/null +++ b/phpmyadmin/export.php @@ -0,0 +1,979 @@ + $export_type, + 'single_table' => isset($single_table) + ) +); + +// Backward compatbility +$type = $what; + +// Check export type +if (! isset($export_plugin)) { + PMA_fatalError(__('Bad type!')); +} + +/** + * valid compression methods + */ +$compression_methods = array( + 'zip', + 'gzip', + 'bzip2', +); + +/** + * 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; +} + +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; + } +} + +// 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 { + $active_page = 'tbl_export.php'; + include 'tbl_export.php'; + } + 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(); + } +} elseif ($export_type == 'table' && strlen($db) && strlen($table)) { + $err_url = 'tbl_export.php?' . PMA_generate_common_url($db, $table); +} else { + PMA_fatalError(__('Bad parameters!')); +} + +/** + * 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']); +} + +// Start with empty buffer +$dump_buffer = ''; +$dump_buffer_len = 0; + +// We send fake headers to avoid browser timeout when buffering +$time_start = time(); + + +/** + * Detect ob_gzhandler + * + * @return bool + */ +function PMA_isGzHandlerEnabled() +{ + return in_array('ob_gzhandler', ob_list_handlers()); +} + +/** + * 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() +{ + if (@function_exists('gzencode') + && ! @ini_get('zlib.output_compression') + // Here, we detect Apache's mod_deflate so we bet that + // this module is active for this instance of phpMyAdmin + // and therefore, will gzip encode the content + && ! (function_exists('apache_get_modules') + && in_array('mod_deflate', apache_get_modules())) + && ! PMA_isGzHandlerEnabled() + ) { + 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 + */ +function PMA_exportOutputHandler($line) +{ + global $time_start, $dump_buffer, $dump_buffer_len, $save_filename; + + // Kanji encoding convert feature + if ($GLOBALS['output_kanji_conversion']) { + $line = PMA_kanji_str_conv( + $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']) { + + $dump_buffer .= $line; + if ($GLOBALS['onfly_compression']) { + + $dump_buffer_len += strlen($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 + ); + } + // as bzipped + if ($GLOBALS['compression'] == 'bzip2' + && @function_exists('bzcompress') + ) { + $dump_buffer = bzcompress($dump_buffer); + } elseif ($GLOBALS['compression'] == 'gzip' + && PMA_gzencodeNeeded() + ) { + // as a gzipped file + // 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.') + ); + $GLOBALS['message']->addParam($save_filename); + return false; + } + } else { + echo $dump_buffer; + } + $dump_buffer = ''; + $dump_buffer_len = 0; + } + } else { + $time_now = time(); + if ($time_start >= $time_now + 30) { + $time_start = $time_now; + header('X-pmaPing: Pong'); + } // end if + } + } else { + if ($GLOBALS['asfile']) { + if ($GLOBALS['output_charset_conversion']) { + $line = PMA_convert_string( + '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.') + ); + $GLOBALS['message']->addParam($save_filename); + return false; + } + $time_now = time(); + if ($time_start >= $time_now + 30) { + $time_start = $time_now; + header('X-pmaPing: Pong'); + } // end if + } else { + // We export as file - output normally + echo $line; + } + } else { + // We export as html - replace special chars + echo htmlspecialchars($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_Util::whichCrlf(); +} + +$output_kanji_conversion = function_exists('PMA_kanji_str_conv') && $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; + } + + 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 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; +} + +// 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 + ); + } + } + $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; + } + $mime_type = $export_plugin->getProperties()->getMimeType(); + + // 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_Util::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.') + ); + $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)) { + 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_sanitizeFilename($filename); + + PMA_downloadHeader($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.')); + $active_page = 'db_export.php'; + include 'db_export.php'; + exit(); + } + } + $backup_cfgServer = $cfg['Server']; + $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 = '

      [ $value) { + $back_button .= '&' . urlencode($name) . '=' . urlencode($value); + } + $back_button .= '&repopulate=1">Back ]

      '; + + echo $back_button; + echo '
      ' . "\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; + + echo "\n"; + echo '
      ' . "\n"; + echo "\n"; +?> + + diff --git a/phpmyadmin/favicon.ico b/phpmyadmin/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..2352b5fa4e6302b1a6009cb377bb74064d37ae7f GIT binary patch literal 18902 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 'png', + 'image/svg+xml' => 'svg', + ); + + /* Check whether MIME type is allowed */ + if (! isset($allowed[$_REQUEST['type']])) { + PMA_fatalError(__('Invalid export type')); + } + + /* + * Check file name to match mime type and not contain new lines + * to prevent response splitting. + */ + $extension = $allowed[$_REQUEST['type']]; + $valid_match = '/^[^\n\r]*\.' . $extension . '$/'; + if (! preg_match($valid_match, $_REQUEST['filename'])) { + if (! preg_match('/^[^\n\r]*$/', $_REQUEST['filename'])) { + /* Filename is unsafe, discard it */ + $filename = 'download.' . $extension; + } else { + /* Add extension */ + $filename = $_REQUEST['filename'] . '.' . $extension; + } + } else { + /* Filename from request should be safe here */ + $filename = $_REQUEST['filename']; + } + + /* Decode data */ + if ($extension != 'svg') { + $data = substr($_REQUEST['image'], strpos($_REQUEST['image'], ',') + 1); + $data = base64_decode($data); + } else { + $data = $_REQUEST['image']; + } + + /* Send download header */ + PMA_downloadHeader($filename, $_REQUEST['type'], strlen($data)); + + /* Send data */ + echo $data; + +} else if (isset($_REQUEST['monitorconfig'])) { + /* For monitor chart config export */ + PMA_downloadHeader('monitor.cfg', 'application/force-download'); + echo urldecode($_REQUEST['monitorconfig']); + +} else if (isset($_REQUEST['import'])) { + /* For monitor chart config import */ + header('Content-type: text/plain'); + 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 new file mode 100644 index 000000000..229e36bdb --- /dev/null +++ b/phpmyadmin/gis_data_editor.php @@ -0,0 +1,416 @@ +generateParams($_REQUEST['value']) + ); +} + +// Generate Well Known Text +$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' +); +$data = array(array('wkt' => $wkt_with_zero, 'srid' => $srid)); +$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 +if (isset($_REQUEST['generate']) && $_REQUEST['generate'] == true) { + $extra_data = array( + 'result' => $result, + 'visualization' => $visualization, + 'openLayers' => $open_layers, + ); + $response = PMA_Response::getInstance(); + $response->addJSON($extra_data); + exit; +} + +ob_start(); + +echo '
      '; +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 ''; +} +echo PMA_generate_common_hidden_inputs(); + +echo ''; +echo '
      '; +echo $visualization; +echo '
      '; + +echo '
      '; +echo '
      '; + +echo '
      '; +echo ''; +echo ''; +echo '
      '; + +echo ''; +echo ''; + + +echo ''; +echo '
      '; +echo ''; +echo '    '; +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 '

      '; + echo __("Geometry") . ' ' . ($a + 1) . ': '; + echo '
      '; + if (isset($gis_data[$a]['gis_type'])) { + $type = $gis_data[$a]['gis_type']; + } else { + $type = $gis_types[0]; + } + 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') { + echo __("Linestring") . ' ' . ($i + 1) . ':'; + } else { + if ($i == 0) { + echo __("Outer Ring") . ':'; + } else { + echo __("Inner Ring") . ' ' . $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 ': '; + echo ''; + echo ''; + echo ''; + echo ''; + } + echo ''; + } + $caption = ($type == 'MULTILINESTRING') + ? __('Add a linestring') + : __('Add an inner ring'); + echo '
      '; + echo ''; + + } elseif ($type == 'MULTIPOLYGON') { + $no_of_polygons = isset($gis_data[$a][$type]['no_of_polygons']) + ? $gis_data[$a][$type]['no_of_polygons'] : 1; + if ($no_of_polygons < 1) { + $no_of_polygons = 1; + } + if (isset($gis_data[$a][$type]['add_polygon'])) { + $no_of_polygons++; + } + echo ''; + + for ($k = 0; $k < $no_of_polygons; $k++) { + echo '
      '; + echo __("Polygon") . ' ' . ($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") . ' ' . $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 ': '; + echo ''; + echo ''; + echo ''; + echo ''; + } + echo ''; + } + echo '
      '; + echo ''; + echo '
      '; + } + echo '
      '; + echo ''; + } +} +if ($geom_type == 'GEOMETRYCOLLECTION') { + echo '

      '; + 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 new file mode 100644 index 000000000..9d193ae63 --- /dev/null +++ b/phpmyadmin/import.php @@ -0,0 +1,601 @@ +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(); + exit; // the footer is displayed automatically +} + +/** + * Sets globals from $_POST patterns, for import plugins + * We only need to load the selected plugin + */ + +$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_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'; + +// Create error and goto url +if ($import_type == 'table') { + $err_url = 'tbl_import.php?' . PMA_generate_common_url($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); + $_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(); + $_SESSION['Import_message']['go_back_url'] = $err_url; + $goto = 'server_import.php'; +} else { + if (empty($goto) || !preg_match('@^(server|db|tbl)(_[a-z]*)*\.php$@i', $goto)) { + if (strlen($table) && strlen($db)) { + $goto = 'tbl_structure.php'; + } elseif (strlen($db)) { + $goto = 'db_structure.php'; + } else { + $goto = 'server_sql.php'; + } + } + if (strlen($table) && strlen($db)) { + $common = PMA_generate_common_url($db, $table); + } elseif (strlen($db)) { + $common = PMA_generate_common_url($db); + } else { + $common = PMA_generate_common_url(); + } + $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); +} + +@set_time_limit($cfg['ExecTimeLimit']); +if (! empty($cfg['MemoryLimit'])) { + @ini_set('memory_limit', $cfg['MemoryLimit']); +} + +$timestamp = time(); +if (isset($allow_interrupt)) { + $maximum_time = ini_get('max_execution_time'); +} else { + $maximum_time = 0; +} + +// set default values +$timeout_passed = false; +$error = false; +$read_multiply = 1; +$finished = false; +$offset = 0; +$max_sql_len = 0; +$file_to_unlink = ''; +$sql_query = ''; +$sql_query_disabled = false; +$go_sql = false; +$executed_queries = 0; +$run_query = true; +$charset_conversion = false; +$reset_charset = false; +$bookmark_created = false; + +// Bookmark Support: get a query back from bookmark if required +if (! empty($id_bookmark)) { + $id_bookmark = (int)$id_bookmark; + 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_Util::sqlAddSlashes($bookmark_variable) . '${2}', + $import_text + ); + } + + // refresh navigation and main panels + if (preg_match('/^(DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $import_text)) { + $GLOBALS['reload'] = true; + } + + // 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 + +// Do no run query if we show PHP code +if (isset($GLOBALS['show_as_php'])) { + $run_query = false; + $go_sql = true; +} + +// 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 +if (empty($memory_limit)) { + $memory_limit = 2 * 1024 * 1024; +} +// In case no memory limit we work on 10MB chunks +if ($memory_limit == -1) { + $memory_limit = 10 * 1024 * 1024; +} + +// Calculate value of the 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; +} + +// Just to be sure, there might be lot of memory needed for uncompression +$read_limit = $memory_limit / 8; + +// handle filenames +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_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) { + // work around open_basedir and other limitations + $open_basedir = @ini_get('open_basedir'); + + // If we are on a server with open_basedir, we must move the file + // before opening it. The doc explains how to create the "./tmp" + // directory + + if (! empty($open_basedir)) { + + $tmp_subdir = (PMA_IS_WINDOWS ? '.\\tmp\\' : 'tmp/'); + + if (is_writable($tmp_subdir)) { + + + $import_file_new = $tmp_subdir . basename($import_file) . uniqid(); + if (move_uploaded_file($import_file, $import_file_new)) { + $import_file = $import_file_new; + $file_to_unlink = $import_file_new; + } + + $size = filesize($import_file); + } + } + + /** + * Handle file compression + * @todo duplicate code exists in File.class.php + */ + $compression = PMA_detectCompression($import_file); + if ($compression === false) { + $message = PMA_Message::error(__('File could not be read')); + $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); + $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; + } + 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) { + $message = PMA_Message::error(__('File could not be read')); + $error = true; + } +} 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 [doc@faq1-16]FAQ 1.16[/doc].') + ); + $error = true; + } +} + +// so we can obtain the message +//$_SESSION['Import_message'] = $message->getDisplay(); + +// Convert the file's charset if necessary +if ($GLOBALS['PMA_recoding_engine'] != PMA_CHARSET_NONE && isset($charset_of_file)) { + if ($charset_of_file != 'utf-8') { + $charset_conversion = true; + } +} 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 + $error = true; + $message = PMA_Message::error( + __('Cannot convert file\'s character set without character set conversion library') + ); + } else { + PMA_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; + } +} + +// Something to skip? +if (! $error && isset($skip)) { + $original_skip = $skip; + while ($skip > 0) { + PMA_importGetNextChunk($skip < $read_limit ? $skip : $read_limit); + // Disable read progresivity, otherwise we eat all memory! + $read_multiply = 1; + $skip -= $read_limit; + } + unset($skip); +} + +// 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 + 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!') + ); + } else { + // Do the real import + $import_plugin->doImport($sql_data); + } +} + +if (! $error && false !== $import_handle && null !== $import_handle) { + fclose($import_handle); +} + +// Cleanup temporary file +if ($file_to_unlink != '') { + unlink($file_to_unlink); +} + +// 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 . '\'' + ); +} + +// Show correct message +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) { + $message = PMA_Message::notice(__('Showing bookmark')); +} elseif ($bookmark_created) { + $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->addString($import_notice); + if (isset($local_import_file)) { + $message->addString('(' . $local_import_file . ')'); + } else { + $message->addString('(' . $_FILES['import_file']['name'] . ')'); + } + } else { + $message = PMA_Message::success( + __('Import has been successfully finished, %d queries executed.') + ); + $message->addParam($executed_queries); + if (isset($local_import_file)) { + $message->addString('(' . $local_import_file . ')'); + } else { + $message->addString('(' . $_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.') + ); + 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.') + ); + } +} + +// 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(); +} +// 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'; +} + +// There was an error? +if (isset($my_die)) { + 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'; +} else { + $active_page = $goto; + include '' . $goto; +} +?> diff --git a/phpmyadmin/import_status.php b/phpmyadmin/import_status.php new file mode 100644 index 000000000..9b79f3fff --- /dev/null +++ b/phpmyadmin/import_status.php @@ -0,0 +1,105 @@ +=') + && 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]); + } + } +} + +/** + * Sets globals from $_GET + */ +$get_params = array( + 'message', + 'id' +); +foreach ($get_params as $one_get_param) { + if (isset($_GET[$one_get_param])) { + $GLOBALS[$one_get_param] = $_GET[$one_get_param]; + } +} + +// AJAX requests can't be cached! +PMA_noCacheHeader(); + +// $GLOBALS["message"] is used for asking for an import message +if (isset($GLOBALS["message"]) && $GLOBALS["message"]) { + + header('Content-type: text/html'); + + // wait 0.3 sec before we check for $_SESSION variable, + // which is set inside import.php + usleep(300000); + + // wait until message is available + while ($_SESSION['Import_message']['message'] == null) { + usleep(250000); // 0.25 sec + } + + echo $_SESSION['Import_message']['message']; + echo '
      ' . "\n"; + echo ' [ ' . __('Back') . ' ]' . "\n"; + echo '
      '."\n"; + +} else { + PMA_importAjaxStatus($GLOBALS["id"]); +} +?> diff --git a/phpmyadmin/index.php b/phpmyadmin/index.php new file mode 100644 index 000000000..0e87ccdaf --- /dev/null +++ b/phpmyadmin/index.php @@ -0,0 +1,616 @@ +addJSON( + 'options', + PMA_RecentTable::getInstance()->getHtmlSelectOption() + ); + exit; +} + +if ($GLOBALS['PMA_Config']->isGitRevision()) { + if (isset($_REQUEST['git_revision']) && $GLOBALS['is_ajax_request'] == true) { + PMA_printGitRevision(); + exit; + } + echo '
      '; +} + +// 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); +} + +$common_url_query = PMA_generate_common_url('', ''); + +// 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 .= PMA_DBI_get_host_info(); + } + if (! empty($cfg['Server']['verbose']) && $GLOBALS['cfg']['ShowServerInfo']) { + $server_info .= ')'; + } + $mysql_cur_user_and_host = PMA_DBI_fetch_value('SELECT USER();'); + + // should we add the port info here? + $short_server_info = (!empty($GLOBALS['cfg']['Server']['verbose']) + ? $GLOBALS['cfg']['Server']['verbose'] + : $GLOBALS['cfg']['Server']['host']); +} + +echo '
      ' . "\n"; +echo '
      '; +if ($server > 0 || count($cfg['Servers']) > 1 +) { + echo '
      '; + echo '

      ' . __('General Settings') . '

      '; + echo '
        '; + + /** + * 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'; + + // Logout for advanced authentication + if ($cfg['Server']['auth_type'] != 'config') { + if ($cfg['ShowChgPassword']) { + $conditional_class = 'ajax'; + PMA_printListItem( + PMA_Util::getImage('s_passwd.png') . " " . __('Change password'), + 'li_change_password', + 'user_password.php?' . $common_url_query, + null, + null, + 'change_password_anchor', + "no_bullets", + $conditional_class + ); + } + } // end if + echo '
      • '; + echo '
        ' . "\n" + . PMA_generate_common_hidden_inputs(null, null, 4, 'collation_connection') + . ' ' . "\n" + + . PMA_generateCharsetDropdownBox( + PMA_CSDROPDOWN_COLLATION, + 'collation_connection', + 'select_collation_connection', + $collation_connection, + true, + 4, + true + ) + . '
        ' . "\n" + . '
      • ' . "\n"; + } // end of if ($server > 0 && !PMA_DRIZZLE) + echo '
      '; + echo '
      '; +} + +echo '
      '; +echo '

      ' . __('Appearance Settings') . '

      '; +echo '
        '; + +// Displays language selection combo +if (empty($cfg['Lang']) && count($GLOBALS['available_languages']) > 1) { + echo '
      • '; + include_once 'libraries/display_select_lang.lib.php'; + echo PMA_Util::getImage('s_lang.png') . " " . PMA_getLanguageSelectorHtml(); + echo '
      • '; +} + +// ThemeManager if available + +if ($GLOBALS['cfg']['ThemeManager']) { + echo '
      • '; + echo PMA_Util::getImage('s_theme.png') . " " + . $_SESSION['PMA_Theme_Manager']->getHtmlSelectBox(); + echo '
      • '; +} +echo '
      • '; +echo PMA_Config::getFontsizeForm(); +echo '
      • '; + +echo '
      '; + +// User preferences + +if ($server > 0) { + echo '
        '; + PMA_printListItem( + PMA_Util::getImage('b_tblops.png')." " .__('More settings'), + 'li_user_preferences', + 'prefs_manage.php?' . $common_url_query, + null, + null, + null, + "no_bullets" + ); + echo '
      '; +} + +echo '
      '; + + +echo '
      '; +echo '
      '; + + +if ($server > 0 && $GLOBALS['cfg']['ShowServerInfo']) { + + echo '
      '; + echo '

      ' . __('Database server') . '

      '; + echo '
        ' . "\n"; + PMA_printListItem( + __('Server') . ': ' . $server_info, + 'li_server_info' + ); + PMA_printListItem( + __('Server type') . ': ' . PMA_Util::getServerType(), + 'li_server_type' + ); + PMA_printListItem( + __('Server version') . ': ' . PMA_MYSQL_STR_VERSION . ' - ' . PMA_MYSQL_VERSION_COMMENT, + 'li_server_version' + ); + PMA_printListItem( + __('Protocol version') . ': ' . PMA_DBI_get_proto_info(), + 'li_mysql_proto' + ); + PMA_printListItem( + __('User') . ': ' . htmlspecialchars($mysql_cur_user_and_host), + 'li_user_info' + ); + + echo '
      • '; + echo ' ' . __('Server charset') . ': ' + . ' ' + . ' ' . $mysql_charsets_descriptions[$mysql_charset_map['utf-8']] . "\n" + . ' (' . $mysql_charset_map['utf-8'] . ')' . "\n" + . ' ' . "\n" + . '
      • ' . "\n"; + echo '
      '; + echo '
      '; +} + +if ($GLOBALS['cfg']['ShowServerInfo'] || $GLOBALS['cfg']['ShowPhpInfo']) { + echo '
      '; + echo '

      ' . __('Web server') . '

      '; + echo '
        '; + if ($GLOBALS['cfg']['ShowServerInfo']) { + PMA_printListItem($_SERVER['SERVER_SOFTWARE'], 'li_web_server_software'); + + if ($server > 0) { + $client_version_str = PMA_DBI_get_client_info(); + if (preg_match('#\d+\.\d+\.\d+#', $client_version_str) + && in_array($GLOBALS['cfg']['Server']['extension'], array('mysql', 'mysqli')) + ) { + $client_version_str = 'libmysql - ' . $client_version_str; + } + PMA_printListItem( + __('Database client version') . ': ' . $client_version_str, + 'li_mysql_client_version' + ); + + $php_ext_string = __('PHP extension') . ': ' + . $GLOBALS['cfg']['Server']['extension'] . ' ' + . PMA_Util::showPHPDocu( + 'book.' . $GLOBALS['cfg']['Server']['extension'] . '.php' + ); + PMA_printListItem( + $php_ext_string, + 'li_used_php_extension' + ); + } + } + + if ($cfg['ShowPhpInfo']) { + PMA_printListItem( + __('Show PHP information'), + 'li_phpinfo', + 'phpinfo.php?' . $common_url_query, + null, + '_blank' + ); + } + echo '
      '; + 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' +); +?> +
      +
      + +
      + +
      + + 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 + ); +} + +/** + * Nijel: 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. You should remove it once phpMyAdmin has been configured.'), + 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, PMA_DBI_get_client_info() is not defined yet. + * Drizzle can speak MySQL protocol, so don't warn about version mismatch for + * Drizzle servers. + */ +if (function_exists('PMA_DBI_get_client_info') && !PMA_DRIZZLE) { + $_client_info = PMA_DBI_get_client_info(); + 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 + */ +if ($cfg['SuhosinDisableWarning'] == false + && @ini_get('suhosin.request.max_value_length') + // warn about Suhosin only if its simulation mode is not enabled + && @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 contributing.', + 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 '
    • '; +} +?> diff --git a/phpmyadmin/js/OpenStreetMap.js b/phpmyadmin/js/OpenStreetMap.js new file mode 100644 index 000000000..dbef7b02e --- /dev/null +++ b/phpmyadmin/js/OpenStreetMap.js @@ -0,0 +1 @@ +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{if(this.src.match(/^http:\/\/[def]\.tah\.openstreetmap\.org\//)){}else{OpenLayers.Util.OSM.originalOnImageLoadError}}};OpenLayers.Layer.OSM.Mapnik=OpenLayers.Class(OpenLayers.Layer.OSM,{initialize:function(d,c){var 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"];c=OpenLayers.Util.extend({numZoomLevels:19,buffer:0,transitionEffect:"resize"},c);var a=[d,b,c];OpenLayers.Layer.OSM.prototype.initialize.apply(this,a)},CLASS_NAME:"OpenLayers.Layer.OSM.Mapnik"});OpenLayers.Layer.OSM.Osmarender=OpenLayers.Class(OpenLayers.Layer.OSM,{initialize:function(d,c){var 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"];c=OpenLayers.Util.extend({numZoomLevels:18,buffer:0,transitionEffect:"resize"},c);var a=[d,b,c];OpenLayers.Layer.OSM.prototype.initialize.apply(this,a)},CLASS_NAME:"OpenLayers.Layer.OSM.Osmarender"});OpenLayers.Layer.OSM.CycleMap=OpenLayers.Class(OpenLayers.Layer.OSM,{initialize:function(d,c){var 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"];c=OpenLayers.Util.extend({numZoomLevels:19,buffer:0,transitionEffect:"resize"},c);var a=[d,b,c];OpenLayers.Layer.OSM.prototype.initialize.apply(this,a)},CLASS_NAME:"OpenLayers.Layer.OSM.CycleMap"}); \ No newline at end of file diff --git a/phpmyadmin/js/ajax.js b/phpmyadmin/js/ajax.js new file mode 100644 index 000000000..a4d659f14 --- /dev/null +++ b/phpmyadmin/js/ajax.js @@ -0,0 +1 @@ +var AJAX={active:false,source:null,_callback:function(){},_debug:false,$msgbox:null,hash:function(c){c+="";var a=c.length,d=0,b=0;for(;b>6)}d+=(d<<3);d^=(d>>11);d+=(d<<15);return Math.abs(d)},registerOnload:function(b,c){var a="onload_"+AJAX.hash(b);$(document).bind(a,c);this._debug&&console.log("Registered event "+a+" for file "+b);return this},registerTeardown:function(b,c){var a="teardown_"+AJAX.hash(b);$(document).bind(a,c);this._debug&&console.log("Registered event "+a+" for file "+b);return this},fireOnload:function(b){var a="onload_"+AJAX.hash(b);$(document).trigger(a);this._debug&&console.log("Fired event "+a+" for file "+b)},fireTeardown:function(b){var a="teardown_"+AJAX.hash(b);$(document).triggerHandler(a);this._debug&&console.log("Fired event "+a+" for file "+b)},requestHandler:function(d){var b=$(this).attr("href");if(d.shiftKey||d.ctrlKey){return true}else{if($(this).attr("target")){return true}else{if($(this).hasClass("ajax")||$(this).hasClass("disableAjax")){return true}else{if(b&&b.match(/^#/)){return true}else{if(b&&b.match(/^mailto/)){return true}else{if($(this).hasClass("ui-datepicker-next")||$(this).hasClass("ui-datepicker-prev")){return true}}}}}}if(typeof d!="undefined"){d.preventDefault();d.stopImmediatePropagation()}if(AJAX.active==true){return false}AJAX.source=$(this);$("html, body").animate({scrollTop:0},"fast");var e=!!b||false;var c=e?b:$(this).attr("action");var f="ajax_request=true&ajax_page_request=true";if(!e){f+="&"+$(this).serialize()}f+=AJAX.cache.menus.getRequestParam();AJAX._debug&&console.log("Loading: "+c);if(e){AJAX.active=true;AJAX.$msgbox=PMA_ajaxShowMessage();$.get(c,f,AJAX.responseHandler)}else{var a=$(this).data("onsubmit");if(typeof a!=="function"||a.apply(this,[d])){AJAX.active=true;AJAX.$msgbox=PMA_ajaxShowMessage();$.post(c,f,AJAX.responseHandler)}}},responseHandler:function(a){if(a.success){$table_clone=false;PMA_ajaxRemoveMessage(AJAX.$msgbox);if(a._redirect){PMA_ajaxShowMessage(a._redirect,false);AJAX.active=false;return}AJAX.scriptHandler.reset(function(){if(a._reloadNavigation){PMA_reloadNavigation()}if(a._reloadQuerywindow){var b=a._reloadQuerywindow;PMA_querywindow.reload(b.db,b.table,b.sql_query)}if(a._focusQuerywindow){PMA_querywindow.focus(a._focusQuerywindow)}if(a._title){$("title").replaceWith(a._title)}if(a._menu){AJAX.cache.menus.replace(a._menu);AJAX.cache.menus.add(a._menuHash,a._menu)}else{if(a._menuHash){AJAX.cache.menus.replace(AJAX.cache.menus.get(a._menuHash))}}$("body").children().not("#pma_navigation").not("#floating_menubar").not("#goto_pagetop").not("#page_content").not("#selflink").not("#session_debug").remove();if(a.message&&a.message.length>0){$("#page_content").replaceWith("
      "+a.message+"
      ")}if(a._selflink){$("#selflink > a").attr("href",a._selflink)}if(a._scripts){AJAX.scriptHandler.load(a._scripts)}if(a._selflink&&a._scripts&&a._menuHash&&a._params){AJAX.cache.add(a._selflink,a._scripts,a._menuHash,a._params,AJAX.source.attr("rel"))}if(a._params){PMA_commonParams.setAll(a._params)}if(a._displayMessage){$("#page_content").prepend(a._displayMessage)}$("#pma_errors").remove();if(a._errors){$("
      ",{id:"pma_errors"}).insertAfter("#selflink").append(a._errors)}if(typeof AJAX._callback==="function"){AJAX._callback.call()}AJAX._callback=function(){}})}else{PMA_ajaxShowMessage(a.error,false);AJAX.active=false}},scriptHandler:{_scripts:[],_scriptsToBeLoaded:[],_scriptsToBeFired:[],add:function(a,b){this._scripts.push(a);if(b){this._scriptsToBeFired.push(a)}return this},load:function(g){var b=this;b._scriptsToBeLoaded=[];b._scriptsToBeFired=[];for(var d in g){b._scriptsToBeLoaded.push(g[d].name);if(g[d].fire){b._scriptsToBeFired.push(g[d].name)}}var f=[];var e=false;for(var c in b._scriptsToBeLoaded){var a=b._scriptsToBeLoaded[c];if($.inArray(a,b._scripts)==-1){e=true;this.add(a);f.push("scripts[]="+a)}}if(e){$.ajax({url:"js/get_scripts.js.php?"+f.join("&"),cache:true,success:function(){b.done()},dataType:"script"})}else{b.done()}},done:function(){for(var a in this._scriptsToBeFired){AJAX.fireOnload(this._scriptsToBeFired[a])}AJAX.active=false},reset:function(b){for(var a in this._scriptsToBeFired){AJAX.fireTeardown(this._scriptsToBeFired[a])}this._scriptsToBeFired=[];$("a").die("click").live("click",AJAX.requestHandler);$("form").die("submit").live("submit",AJAX.requestHandler);AJAX.cache.update();b()}}};AJAX.registerOnload("functions.js",function(){$("form").not(".ajax").not(".disableAjax").each(function(){if($(this).attr("onsubmit")){$(this).data("onsubmit",this.onsubmit).attr("onsubmit","")}})});AJAX.cache={MAX:6,primer:{},pages:[],current:0,add:function(d,b,f,e,a){if(this.pages.length>AJAX.cache.MAX){for(var c=0;c'+PMA_messages.strInvalidPage+"
      ",false)}else{AJAX.active=true;var a=this.pages[b];AJAX.scriptHandler.reset(function(){$("#page_content").html(a.content);$("#selflink").html(a.selflink);AJAX.cache.menus.replace(AJAX.cache.menus.get(a.menu));PMA_commonParams.setAll(a.params);AJAX.scriptHandler.load(a.scripts);AJAX.cache.current=++b})}},update:function(){var a=this.pages[this.current-1];if(a){a.content=$("#page_content").html()}},menus:{size:function(c){var b=0,a;for(a in c){if(c.hasOwnProperty(a)){b++}}return b},data:{},add:function(e,d){if(this.size(this.data)>AJAX.cache.MAX){var a,c,f=0;for(var b in this.data){if(this.data[b]){if(!f||this.data[b].timestamp.getTime() link[href=favicon\\.ico]").appendTo("head")}}function b(h,i){a=false;if(c){d.location.hash="PMAURL-"+h+":"+i;e()}else{g="PMAURL-"+h+":"+i}}if(d.location.hash.substring(0,8)=="#PMAURL-"){d.location=d.location.hash.substring(d.location.hash.indexOf(":")+1)}else{f(function(){if(g!=""){d.location.hash=g;g="";e()}c=true})}f(function(){f(d).hashchange(function(){if(a===false){a=true}else{if(/^#PMAURL-\d+:/.test(d.location.hash)){var h=d.location.hash.substring(8,d.location.hash.indexOf(":"));AJAX.cache.navigate(h)}}})});return b})(jQuery,window);$(function(){if(AJAX.cache.primer.url){AJAX.cache.menus.add(AJAX.cache.primer.menuHash,$("
      ").append("
      ").append($("#serverinfo").clone()).append($("#topmenucontainer").clone()).html())}$(function(){if(AJAX.cache.primer.url){AJAX.cache.add(AJAX.cache.primer.url,AJAX.cache.primer.scripts,AJAX.cache.primer.menuHash)}})});$("a").live("click",AJAX.requestHandler);$("form").live("submit",AJAX.requestHandler);$(document).ajaxError(function(d,c,b){if(c.status!==0){var e=$.sprintf(PMA_messages.strErrorCode,c.status);var a=$.sprintf(PMA_messages.strErrorText,c.statusText);PMA_ajaxShowMessage('
      '+PMA_messages.strErrorProcessingRequest+"
      "+e+"
      "+a+"
      ",false);AJAX.active=false}}); \ No newline at end of file diff --git a/phpmyadmin/js/canvg/MIT-LICENSE.txt b/phpmyadmin/js/canvg/MIT-LICENSE.txt new file mode 100644 index 000000000..40f19bd70 --- /dev/null +++ b/phpmyadmin/js/canvg/MIT-LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2010-2011 Gabe Lerner (gabelerner@gmail.com) - http://code.google.com/p/canvg/ + + 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. \ No newline at end of file diff --git a/phpmyadmin/js/canvg/canvg.js b/phpmyadmin/js/canvg/canvg.js new file mode 100644 index 000000000..fcea2ecda --- /dev/null +++ b/phpmyadmin/js/canvg/canvg.js @@ -0,0 +1 @@ +if(!window.console){window.console={};window.console.log=function(a){};window.console.dir=function(a){}}if(!Array.indexOf){Array.prototype.indexOf=function(b){for(var a=0;a]*>/,"");var d=new ActiveXObject("Microsoft.XMLDOM");d.async="false";d.loadXML(c);return d}};b.Property=function(c,e){this.name=c;this.value=e;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=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 d=this;this.Color={addOpacity:function(g){var h=d.value;if(g!=null&&g!=""){var f=new RGBColor(d.value);if(f.ok){h="rgba("+f.r+", "+f.g+", "+f.b+", "+g+")"}}return new b.Property(d.name,h)}};this.Definition={getDefinition:function(){var f=d.value.replace(/^(url\()?#([^\)]+)\)?$/,"$2");return b.Definitions[f]},isUrl:function(){return d.value.indexOf("url(")==0},getFillStyle:function(g){var f=this.getDefinition();if(f!=null&&f.createGradient){return f.createGradient(b.ctx,g)}if(f!=null&&f.createPattern){return f.createPattern(b.ctx,g)}return null}};this.Length={DPI:function(f){return 96},EM:function(h){var f=12;var g=new b.Property("fontSize",b.Font.Parse(b.ctx.font).fontSize);if(g.hasValue()){f=g.Length.toPixels(h)}return f},toPixels:function(g){if(!d.hasValue()){return 0}var f=d.value+"";if(f.match(/em$/)){return d.numValue()*this.EM(g)}if(f.match(/ex$/)){return d.numValue()*this.EM(g)/2}if(f.match(/px$/)){return d.numValue()}if(f.match(/pt$/)){return d.numValue()*1.25}if(f.match(/pc$/)){return d.numValue()*15}if(f.match(/cm$/)){return d.numValue()*this.DPI(g)/2.54}if(f.match(/mm$/)){return d.numValue()*this.DPI(g)/25.4}if(f.match(/in$/)){return d.numValue()*this.DPI(g)}if(f.match(/%$/)){return d.numValue()*b.ViewPort.ComputeSize(g)}return d.numValue()}};this.Time={toMilliseconds:function(){if(!d.hasValue()){return 0}var f=d.value+"";if(f.match(/s$/)){return d.numValue()*1000}if(f.match(/ms$/)){return d.numValue()}return d.numValue()}};this.Angle={toRadians:function(){if(!d.hasValue()){return 0}var f=d.value+"";if(f.match(/deg$/)){return d.numValue()*(Math.PI/180)}if(f.match(/grad$/)){return d.numValue()*(Math.PI/200)}if(f.match(/rad$/)){return d.numValue()}return d.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(l,h,e,k,d,g){var j=g!=null?this.Parse(g):this.CreateFont("","","","","",b.ctx.font);return{fontFamily:d||j.fontFamily,fontSize:k||j.fontSize,fontStyle:l||j.fontStyle,fontWeight:e||j.fontWeight,fontVariant:h||j.fontVariant,toString:function(){return[this.fontStyle,this.fontVariant,this.fontWeight,this.fontSize,this.fontFamily].join(" ")}}};var c=this;this.Parse=function(h){var j={};var k=b.trim(b.compressSpaces(h||"")).split(" ");var l={fontSize:false,fontStyle:false,fontWeight:false,fontVariant:false};var e="";for(var g=0;gthis.x2){this.x2=g}}if(h!=null){if(isNaN(this.y1)||isNaN(this.y2)){this.y1=h;this.y2=h}if(hthis.y2){this.y2=h}}};this.addX=function(g){this.addPoint(g,null)};this.addY=function(g){this.addPoint(null,g)};this.addBoundingBox=function(g){this.addPoint(g.x1,g.y1);this.addPoint(g.x2,g.y2)};this.addQuadraticCurve=function(m,l,h,g,o,n){var k=m+2/3*(h-m);var j=l+2/3*(g-l);var q=k+1/3*(o-m);var p=j+1/3*(n-l);this.addBezierCurve(m,l,k,q,j,p,o,n)};this.addBezierCurve=function(v,u,l,j,q,o,x,w){var m=[v,u],k=[l,j],h=[q,o],g=[x,w];this.addPoint(m[0],m[1]);this.addPoint(g[0],g[1]);for(i=0;i<=1;i++){var y=function(C){return Math.pow(1-C,3)*m[i]+3*Math.pow(1-C,2)*C*k[i]+3*(1-C)*Math.pow(C,2)*h[i]+Math.pow(C,3)*g[i]};var A=6*m[i]-12*k[i]+6*h[i];var B=-3*m[i]+9*k[i]-9*h[i]+3*g[i];var z=3*k[i]-3*m[i];if(B==0){if(A==0){continue}var s=-z/A;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=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 d=new b.Point(this.getScalar(),this.getScalar());return this.makeAbsolute(d)};this.getAsControlPoint=function(){var d=this.getPoint();this.control=d;return d};this.getAsCurrentPoint=function(){var d=this.getPoint();this.current=d;return d};this.getReflectedControlPoint=function(){if(this.previousCommand.toLowerCase()!="c"&&this.previousCommand.toLowerCase()!="s"){return this.current}var d=new b.Point(2*this.current.x-this.control.x,2*this.current.y-this.control.y);return d};this.makeAbsolute=function(d){if(this.isRelativeCommand()){d.x=this.current.x+d.x;d.y=this.current.y+d.y}return d};this.addMarker=function(d,g){this.addMarkerAngle(d,g==null?null:g.angleTo(d))};this.addMarkerAngle=function(g,d){this.points.push(g);this.angles.push(d)};this.getMarkerPoints=function(){return this.points};this.getMarkerAngles=function(){for(var g=0;g1){q*=Math.sqrt(I);o*=Math.sqrt(I)}var B=(w==n?-1:1)*Math.sqrt(((Math.pow(q,2)*Math.pow(o,2))-(Math.pow(q,2)*Math.pow(P.y,2))-(Math.pow(o,2)*Math.pow(P.x,2)))/(Math.pow(q,2)*Math.pow(P.y,2)+Math.pow(o,2)*Math.pow(P.x,2)));if(isNaN(B)){B=0}var A=new b.Point(B*q*P.y/o,B*-o*P.x/q);var h=new b.Point((K.x+x.x)/2+Math.cos(f)*A.x-Math.sin(f)*A.y,(K.y+x.y)/2+Math.sin(f)*A.x+Math.cos(f)*A.y);var G=function(l){return Math.sqrt(Math.pow(l[0],2)+Math.pow(l[1],2))};var D=function(m,l){return(m[0]*l[0]+m[1]*l[1])/(G(m)*G(l))};var N=function(m,l){return(m[0]*l[1]=1){L=0}if(n==0&&L>0){L=L-2*Math.PI}if(n==1&&L<0){L=L+2*Math.PI}var d=new b.Point(h.x-q*Math.cos((O+L)/2),h.y-o*Math.sin((O+L)/2));J.addMarkerAngle(d,(O+L)/2+(n==0?1:-1)*Math.PI/2);J.addMarkerAngle(x,L+(n==0?1:-1)*Math.PI/2);t.addPoint(x.x,x.y);if(H!=null){var D=q>o?q:o;var E=q>o?1:q/o;var C=q>o?o/q:1;H.translate(h.x,h.y);H.rotate(f);H.scale(E,C);H.arc(0,0,D,O,O+L,1-n);H.scale(1/E,1/C);H.rotate(-f);H.translate(-h.x,-h.y)}}break;case"Z":if(H!=null){H.closePath()}J.current=J.start}}return t};this.getMarkers=function(){var f=this.PathParser.getMarkerPoints();var h=this.PathParser.getMarkerAngles();var g=[];for(var 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=this.duration+g;var d=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 l=this.r.toString(16);var k=this.g.toString(16);var j=this.b.toString(16);if(l.length==1){l="0"+l}if(k.length==1){k="0"+k}if(j.length==1){j="0"+j}return"#"+l+k+j};this.getHelpXML=function(){var m=new Array();for(var o=0;o "+s.toRGB()+" -> "+s.toHex());q.appendChild(u);q.appendChild(k);p.appendChild(q)}catch(r){}}return p}}; \ No newline at end of file diff --git a/phpmyadmin/js/canvg/flashcanvas.js b/phpmyadmin/js/canvg/flashcanvas.js new file mode 100644 index 000000000..4ae4f5bcb --- /dev/null +++ b/phpmyadmin/js/canvg/flashcanvas.js @@ -0,0 +1 @@ +if(window.ActiveXObject&&!window.CanvasRenderingContext2D){(function(window,document,undefined){var NULL=null;var CANVAS="canvas";var CANVAS_RENDERING_CONTEXT_2D="CanvasRenderingContext2D";var CANVAS_GRADIENT="CanvasGradient";var CANVAS_PATTERN="CanvasPattern";var FLASH_CANVAS="FlashCanvas";var G_VML_CANVAS_MANAGER="G_vmlCanvasManager";var OBJECT_ID_PREFIX="external";var ON_FOCUS="onfocus";var ON_PROPERTY_CHANGE="onpropertychange";var ON_READY_STATE_CHANGE="onreadystatechange";var ON_UNLOAD="onunload";var config=window[FLASH_CANVAS+"Options"]||{};var BASE_URL=config.swfPath||getScriptUrl().replace(/[^\/]+$/,"");var SWF_URL=BASE_URL+"flashcanvas.swf";var INDEX_SIZE_ERR=1;var NOT_SUPPORTED_ERR=9;var INVALID_STATE_ERR=11;var SYNTAX_ERR=12;var TYPE_MISMATCH_ERR=17;var SECURITY_ERR=18;function Lookup(array){for(var i=0,n=array.length;i0){return eval(this._swf.CallFunction(''+commands.join("�")+""))}},_resize:function(width,height){this._executeCommand();this._initialize();if(width>0){this._swf.width=width}if(height>0){this._swf.height=height}this._queue.push(properties.resize,width,height)}};var CanvasGradient=function(ctx){this._ctx=ctx;this.id=ctx._gradientPatternId++};CanvasGradient.prototype={addColorStop:function(offset,color){if(isNaN(offset)||offset<0||offset>1){throwException(INDEX_SIZE_ERR)}this._ctx._queue.push(properties.addColorStop,this.id,offset,color)}};var CanvasPattern=function(ctx){this.id=ctx._gradientPatternId++};var TextMetrics=function(width){this.width=width};var DOMException=function(code){this.code=code;this.message=DOMExceptionNames[code]};DOMException.prototype=new Error;var DOMExceptionNames={1:"INDEX_SIZE_ERR",9:"NOT_SUPPORTED_ERR",11:"INVALID_STATE_ERR",12:"SYNTAX_ERR",17:"TYPE_MISMATCH_ERR",18:"SECURITY_ERR"};function onReadyStateChange(){if(document.readyState==="complete"){document.detachEvent(ON_READY_STATE_CHANGE,onReadyStateChange);var canvases=document.getElementsByTagName(CANVAS);for(var i=0,n=canvases.length;i';canvases[canvasId]=canvas;var swf=canvas.firstChild;spans[canvasId]=canvas.lastChild;var documentContains=document.body.contains;if(documentContains(canvas)){swf.movie=SWF_URL}else{var intervalId=setInterval(function(){if(documentContains(canvas)){clearInterval(intervalId);swf.movie=SWF_URL}},0)}if(document.compatMode==="BackCompat"||!window.XMLHttpRequest){spans[canvasId].style.overflow="hidden"}var ctx=new CanvasRenderingContext2D(canvas,swf);canvas.getContext=function(contextId){return contextId==="2d"?ctx:NULL};canvas.toDataURL=function(type,quality){if((""+type).replace(/[A-Z]+/g,toLowerCase)==="image/jpeg"){ctx._queue.push(properties.toDataURL,type,typeof quality==="number"?quality:"")}else{ctx._queue.push(properties.toDataURL,type)}return ctx._executeCommand()};swf.attachEvent(ON_FOCUS,onFocus);return canvas},saveImage:function(canvas){var swf=canvas.firstChild;swf.saveImage()},setOptions:function(options){},trigger:function(canvasId,type){var canvas=canvases[canvasId];canvas.fireEvent("on"+type)},unlock:function(canvasId,ready){if(lock[canvasId]){--lock[canvasId]}if(ready){var canvas=canvases[canvasId];var swf=canvas.firstChild;var width;var height;setCanvasSize(canvas);width=canvas.width;height=canvas.height;canvas.style.width=width+"px";canvas.style.height=height+"px";if(width>0){swf.width=width}if(height>0){swf.height=height}swf.resize(width,height);canvas.attachEvent(ON_PROPERTY_CHANGE,onPropertyChange);isReady[canvasId]=true}}};function getScriptUrl(){var scripts=document.getElementsByTagName("script");var script=scripts[scripts.length-1];if(document.documentMode>=8){return script.src}else{return script.getAttribute("src",4)}}function getUniqueId(){return Math.random().toString(36).slice(2)||"0"}function encodeXML(str){return(""+str).replace(/&/g,"&").replace(/9^hmO7%f>biJ}yp>fH;q^A>~Me&>Zjq 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 literal 0 HcwPel00001 diff --git a/phpmyadmin/js/chart.js b/phpmyadmin/js/chart.js new file mode 100644 index 000000000..6192c58af --- /dev/null +++ b/phpmyadmin/js/chart.js @@ -0,0 +1 @@ +var ChartType={LINE:"line",SPLINE:"spline",AREA:"area",BAR:"bar",COLUMN:"column",PIE:"pie",TIMELINE:"timeline"};var ChartFactory=function(){};ChartFactory.prototype={createChart:function(b,a){throw new Error("createChart must be implemented by a subclass")}};var Chart=function(a){this.elementId=a};Chart.prototype={draw:function(b,a){throw new Error("draw must be implemented by a subclass")},redraw:function(a){throw new Error("redraw must be implemented by a subclass")},destroy:function(){throw new Error("destroy must be implemented by a subclass")}};var BaseChart=function(a){Chart.call(this,a)};BaseChart.prototype=new Chart();BaseChart.prototype.constructor=BaseChart;BaseChart.prototype.validateColumns=function(c){var b=c.getColumns();if(b.length<2){throw new Error("Minimum of two columns are required for this chart")}for(var a=1;a2){throw new Error("Pie charts can draw only one series")}return BaseChart.prototype.validateColumns.call(this,b)};var TimelineChart=function(a){BaseChart.call(this,a)};TimelineChart.prototype=new BaseChart();TimelineChart.prototype.constructor=TimelineChart;TimelineChart.prototype.validateColumns=function(c){var a=BaseChart.prototype.validateColumns.call(this,c);if(a){var b=c.getColumns();if(b[0].type!=ColumnType.DATE){throw new Error("First column of timeline chart need to be a date column")}}return a};var DataTable=function(){var a=[];var b;this.addColumn=function(e,d){a.push({type:e,name:d})};this.getColumns=function(){return a};this.setData=function(d){b=d;c()};this.getData=function(){return b};var c=function(){if(a.length==0){throw new Error("Set columns first")}var g,f;for(var e=0;ea.length){g.splice(a.length-1,g.length-a.length)}else{if(g.length + +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. diff --git a/phpmyadmin/js/codemirror/lib/codemirror.js b/phpmyadmin/js/codemirror/lib/codemirror.js new file mode 100644 index 000000000..5188f162a --- /dev/null +++ b/phpmyadmin/js/codemirror/lib/codemirror.js @@ -0,0 +1 @@ +window.CodeMirror=(function(){function r(a9,a5){var ct={},bG=r.defaults;for(var aX in bG){if(bG.hasOwnProperty(aX)){ct[aX]=(a5&&a5.hasOwnProperty(aX)?a5:bG)[aX]}}var bJ=ak("textarea",null,null,"position: absolute; padding: 0; width: 1px; height: 1em");bJ.setAttribute("wrap","off");bJ.setAttribute("autocorrect","off");bJ.setAttribute("autocapitalize","off");var cp=ak("div",[bJ],null,"overflow: hidden; position: relative; width: 3px; height: 0px;");var cR=ak("div",null,"CodeMirror-scrollbar-inner");var a8=ak("div",[cR],"CodeMirror-scrollbar");var aO=ak("div"),bD=ak("div",null,null,"position: relative; z-index: -1");var bA=ak("pre","\u00a0","CodeMirror-cursor"),bu=ak("pre","\u00a0","CodeMirror-cursor","visibility: hidden");var aT=ak("div",null,null,"position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden;");var bU=ak("div",[aT,bA,bu,bD,aO],null,"position: relative; z-index: 0");var bl=ak("div",null,"CodeMirror-gutter-text"),a3=ak("div",[bl],"CodeMirror-gutter");var cM=ak("div",[a3,ak("div",[bU],"CodeMirror-lines")],null,"position: relative");var cC=ak("div",[cM],null,"position: relative");var bH=ak("div",[cC],"CodeMirror-scroll");bH.setAttribute("tabIndex","-1");var a1=ak("div",[cp,a8,bH],"CodeMirror"+(ct.lineWrapping?" CodeMirror-wrap":""));if(a9.appendChild){a9.appendChild(a1)}else{a9(a1)}c8();c1();if(i){bJ.style.width="0px"}if(!m){bH.draggable=true}bU.style.outline="none";if(ct.tabindex!=null){bJ.tabIndex=ct.tabindex}if(ct.autofocus){b1()}if(!ct.gutter&&!ct.lineNumbers){a3.style.display="none"}if(ah){cp.style.height="1px",cp.style.position="absolute"}if(W){a8.style.zIndex=-2;a8.style.visibility="hidden"}else{if(L){a8.style.minWidth="18px"}}var cA=new j(),aU=new j(),dl;var cH,c4=new al([new Q([new J("")])]),df=0,cO;cm();var dt={from:{line:0,ch:0},to:{line:0,ch:0},inverted:false};var cN,bO,bn,bW=0,bz,cT=false,cY=false,cf=false;var cV,cz,aZ,dj,bc,bf,c5;var bB=0,dm=0,cc=0,cd=0;var cw;var b6=db(0),c9=false,bN=true;var bS=false;var c0=null;aP(function(){bj(ct.value||"");cV=false})();var bx=new F();aE(bH,"mousedown",aP(cP));aE(bH,"dblclick",aP(co));aE(bU,"selectstart",f);if(!x){aE(bH,"contextmenu",bp)}aE(bH,"scroll",cE);aE(a8,"scroll",b2);aE(a8,"mousedown",function(){if(cO){setTimeout(b1,0)}});var cD=aE(window,"resize",function(){if(a1.parentNode){cJ(true)}else{cD()}},true);aE(bJ,"keyup",aP(cQ));aE(bJ,"input",bd);aE(bJ,"keydown",aP(cI));aE(bJ,"keypress",aP(bK));aE(bJ,"focus",dr);aE(bJ,"blur",a2);function b5(dv){if(ct.onDragEvent&&ct.onDragEvent(cF,R(dv))){return}ae(dv)}if(ct.dragDrop){aE(bH,"dragstart",a4);aE(bH,"dragenter",b5);aE(bH,"dragover",b5);aE(bH,"drop",aP(aK))}aE(bH,"paste",function(){b1();bd()});aE(bJ,"paste",function(){cf=true;bd()});aE(bJ,"cut",aP(function(){if(!ct.readOnly){bR("")}}));if(ah){aE(cC,"mouseup",function(){if(document.activeElement==bJ){bJ.blur()}b1()})}var c2;try{c2=(document.activeElement==bJ)}catch(cB){}if(c2||ct.autofocus){setTimeout(dr,20)}else{a2()}function bQ(dv){return dv>=0&&dvdv&&dz.y>dx.offsetHeight){dA=dz.y-dx.offsetHeight}if(dw+dx.offsetWidth>dC){dw=dC-dx.offsetWidth}}}dx.style.top=(dA+cX())+"px";dx.style.left=dx.style.right="";if(dD=="right"){dw=cC.clientWidth-dx.offsetWidth;dx.style.right="0px"}else{if(dD=="left"){dw=0}else{if(dD=="middle"){dw=(cC.clientWidth-dx.offsetWidth)/2}}dx.style.left=(dw+bt())+"px"}if(dB){aY(dw,dA,dw+dx.offsetWidth,dA+dx.offsetHeight)}},lineCount:function(){return c4.size},clipPos:bg,getCursor:function(dv){if(dv==null||dv=="head"){dv=dt.inverted}if(dv=="anchor"){dv=!dt.inverted}if(dv=="end"){dv=false}return aa(dv?dt.from:dt.to)},somethingSelected:function(){return !T(dt.from,dt.to)},setCursor:aP(function(dv,dx,dw){if(dx==null&&typeof dv.line=="number"){bv(dv.line,dv.ch,dw)}else{bv(dv,dx,dw)}}),setSelection:aP(function(dx,dw,dv){(dv?bZ:bX)(bg(dx),bg(dw||dx))}),getLine:function(dv){if(bQ(dv)){return db(dv).text}},getLineHandle:function(dv){if(bQ(dv)){return db(dv)}},setLine:aP(function(dv,dw){if(bQ(dv)){ci(dw,{line:dv,ch:0},{line:dv,ch:db(dv).text.length})}}),removeLine:aP(function(dv){if(bQ(dv)){ci("",{line:dv,ch:0},bg({line:dv+1,ch:0}))}}),replaceRange:aP(ci),getRange:function(dx,dw,dv){return dk(bg(dx),bg(dw),dv)},triggerOnKeyDown:aP(cI),execCommand:function(dv){return t[dv](cF)},moveH:aP(da),deleteH:aP(cS),moveV:aP(c3),toggleOverwrite:function(){if(cT){cT=false;bA.className=bA.className.replace(" CodeMirror-overwrite","")}else{cT=true;bA.className+=" CodeMirror-overwrite"}},posFromIndex:function(dw){var dx=0,dv;c4.iter(0,c4.size,function(dy){var dz=dy.text.length+1;if(dz>dw){dv=dw;return true}dw-=dz;++dx});return bg({line:dx,ch:dv})},indexFromPos:function(dw){if(dw.line<0||dw.ch<0){return 0}var dv=dw.ch;c4.iter(0,dw.line,function(dx){dv+=dx.text.length+1});return dv},scrollTo:function(dv,dw){if(dv!=null){bH.scrollLeft=dv}if(dw!=null){a8.scrollTop=bH.scrollTop=dw}cJ([])},getScrollInfo:function(){return{x:bH.scrollLeft,y:a8.scrollTop,height:a8.scrollHeight,width:bH.scrollWidth}},scrollIntoView:function(dw){var dv=dn(dw?bg(dw):dt.inverted?dt.from:dt.to);aY(dv.x,dv.y,dv.x,dv.yBot)},setSize:function(dx,dv){function dw(dy){dy=String(dy);return/^\d+$/.test(dy)?dy+"px":dy}if(dx!=null){a1.style.width=dw(dx)}if(dv!=null){bH.style.height=dw(dv)}cF.refresh()},operation:function(dv){return aP(dv)()},compoundChange:function(dv){return cg(dv)},refresh:function(){cJ(true,null,bW);if(a8.scrollHeight>bW){a8.scrollTop=bW}},getInputField:function(){return bJ},getWrapperElement:function(){return a1},getScrollerElement:function(){return bH},getGutterElement:function(){return a3}};function db(dv){return M(c4,dv)}function br(dw,dv){bf=true;var dx=dv-dw.height;for(var dy=dw;dy;dy=dy.parent){dy.height+=dx}}function ce(dv,dw){if(!dv.styles){dv.highlight(cH,dv.stateAfter=cZ(X(dv)),ct.tabSize)}return dv.getContent(ct.tabSize,dw,ct.lineWrapping)}function bj(dv){var dw={line:0,ch:0};bb(dw,{line:c4.size-1,ch:db(c4.size-1).text.length},h(dv),dw,dw);cV=true}function cu(dw){var dv=[];c4.iter(0,c4.size,function(dx){dv.push(dx.text)});return dv.join(dw||"\n")}function b2(dv){if(Math.abs(a8.scrollTop-bW)>1){bW=bH.scrollTop=a8.scrollTop;cJ([])}}function cE(dv){if(ct.fixedGutter&&a3.style.left!=bH.scrollLeft+"px"){a3.style.left=bH.scrollLeft+"px"}if(Math.abs(bH.scrollTop-bW)>1){bW=bH.scrollTop;if(a8.scrollTop!=bW){a8.scrollTop=bW}cJ([])}if(ct.onScroll){ct.onScroll(cF)}}function cP(dH){bs(ad(dH,"shiftKey"));for(var dB=ar(dH);dB!=a1;dB=dB.parentNode){if(dB.parentNode==cC&&dB!=cM){return}}for(var dB=ar(dH);dB!=a1;dB=dB.parentNode){if(dB.parentNode==bl){if(ct.onGutterClick){ct.onGutterClick(cF,u(bl.childNodes,dB)+dm,dH)}return f(dH)}}var dw=bq(dH);switch(E(dH)){case 3:if(x){bp(dH)}return;case 2:if(dw){bv(dw.line,dw.ch,true)}setTimeout(b1,20);f(dH);return}if(!dw){if(ar(dH)==bH){f(dH)}return}if(!cO){dr()}var dx=+new Date,dK="single";if(bn&&bn.time>dx-400&&T(bn.pos,dw)){dK="triple";f(dH);setTimeout(b1,20);a6(dw.line)}else{if(bO&&bO.time>dx-400&&T(bO.pos,dw)){dK="double";bn={time:dx,pos:dw};f(dH);var dv=bT(dw);bZ(dv.from,dv.to)}else{bO={time:dx,pos:dw}}}function dC(dM){if(m){bH.draggable=false}bz=false;dG();dA();if(Math.abs(dH.clientX-dM.clientX)+Math.abs(dH.clientY-dM.clientY)<10){f(dM);bv(dw.line,dw.ch,true);b1()}}var dL=dw,dz;if(ct.dragDrop&&ac&&!ct.readOnly&&!T(dt.from,dt.to)&&!D(dw,dt.from)&&!D(dt.to,dw)&&dK=="single"){if(m){bH.draggable=true}var dG=aE(document,"mouseup",aP(dC),true);var dA=aE(bH,"drop",aP(dC),true);bz=true;if(bH.dragDrop){bH.dragDrop()}return}f(dH);if(dK=="single"){bv(dw.line,dw.ch,true)}var dJ=dt.from,dy=dt.to;function dE(dN){if(dK=="single"){bZ(bg(dw),dN);return}dJ=bg(dJ);dy=bg(dy);if(dK=="double"){var dM=bT(dN);if(D(dN,dJ)){bZ(dM.from,dy)}else{bZ(dJ,dM.to)}}else{if(dK=="triple"){if(D(dN,dJ)){bZ(dy,bg({line:dN.line,ch:0}))}else{bZ(dJ,bg({line:dN.line+1,ch:0}))}}}}function dI(dM){var dO=bq(dM,true);if(dO&&!T(dO,dL)){if(!cO){dr()}dL=dO;dE(dO);cV=false;var dN=b3();if(dO.line>=dN.to||dO.line-1){setTimeout(aP(function(){b0(dt.to.line,"smart")}),75)}}if(cq(dy,dw)){return}bd()}function cQ(dv){if(ct.onKeyEvent&&ct.onKeyEvent(cF,R(dv))){return}if(ad(dv,"keyCode")==16){cN=null}}function dr(){if(ct.readOnly=="nocursor"){return}if(!cO){if(ct.onFocus){ct.onFocus(cF)}cO=true;if(bH.className.search(/\bCodeMirror-focused\b/)==-1){bH.className+=" CodeMirror-focused"}}aJ();di()}function a2(){if(cO){if(ct.onBlur){ct.onBlur(cF)}cO=false;if(cw){aP(function(){if(cw){cw();cw=null}})()}bH.className=bH.className.replace(" CodeMirror-focused","")}clearInterval(dl);setTimeout(function(){if(!cO){cN=null}},150)}function bb(dB,dA,dz,dw,dv){if(cY){return}var dy=[];c4.iter(dB.line,dA.line+1,function(dC){dy.push(k(dC.text,dC.markedSpans))});if(bx){bx.addChange(dB.line,dz.length,dy);while(bx.done.length>ct.undoDepth){bx.done.shift()}}var dx=Y(e(dy[0]),e(P(dy)),dB.ch,dA.ch,dz);aQ(dB,dA,dx,dw,dv)}function cG(dA,dB){if(!dA.length){return}var dC=dA.pop(),dw=[];for(var dx=dC.length-1;dx>=0;dx-=1){var dz=dC[dx];var dD=[],dv=dz.start+dz.added;c4.iter(dz.start,dv,function(dE){dD.push(k(dE.text,dE.markedSpans))});dw.push({start:dz.start,added:dz.old.length,old:dD});var dy={line:dz.start+dz.old.length-1,ch:C(au(P(dD)),au(P(dz.old)))};aQ({line:dz.start,ch:0},{line:dv-1,ch:db(dv-1).text.length},dz.old,dy,dy)}cV=true;dB.push(dw)}function dq(){cG(bx.done,bx.undone)}function de(){cG(bx.undone,bx.done)}function aQ(dK,dz,dw,dv,dO){if(cY){return}var dN=false,dy=b6.text.length;if(!ct.lineWrapping){c4.iter(dK.line,dz.line+1,function(dP){if(!dP.hidden&&dP.text.length==dy){dN=true;return true}})}if(dK.line!=dz.line||dw.length>1){bf=true}var dI=dz.line-dK.line,dH=db(dK.line),dx=db(dz.line);var dE=P(dw);if(dK.ch==0&&dz.ch==0&&au(dE)==""){var dF=[],dG=null;for(var dL=0,dM=dw.length-1;dL1){c4.remove(dK.line+1,dI-1,c5)}c4.insert(dK.line+1,dF)}}}if(ct.lineWrapping){var dB=Math.max(5,bH.clientWidth/bE()-3);c4.iter(dK.line,dK.line+dw.length,function(dP){if(dP.hidden){return}var dQ=Math.ceil(dP.text.length/dB)||1;if(dQ!=dP.height){br(dP,dQ)}})}else{c4.iter(dK.line,dK.line+dw.length,function(dQ){var dP=dQ.text;if(!dQ.hidden&&dP.length>dy){b6=dQ;dy=dP.length;bN=true;dN=false}});if(dN){c9=true}}df=Math.min(df,dK.line);b8(400);var dD=dw.length-dI-1;aZ.push({from:dK.line,to:dz.line+1,diff:dD});if(ct.onChange){for(var dL=0;dLbH.offsetHeight?dv:false}function aR(dw){var dv=aN();a8.style.display=dv?"block":"none";if(dv){cR.style.height=cC.style.minHeight=dv+"px";a8.style.height=bH.clientHeight+"px";if(dw!=null){a8.scrollTop=bH.scrollTop=dw;if(m){setTimeout(function(){if(a8.scrollTop!=dw){return}a8.scrollTop=dw+(dw?-1:1);a8.scrollTop=dw},0)}}}else{cC.style.minHeight=""}cM.style.top=bB*ch()+"px"}function bY(){b6=db(0);bN=true;var dv=b6.text.length;c4.iter(1,c4.size,function(dx){var dw=dx.text;if(!dx.hidden&&dw.length>dv){dv=dw.length;b6=dx}});c9=false}function ci(dw,dz,dy){dz=bg(dz);if(!dy){dy=dz}else{dy=bg(dy)}dw=h(dw);function dx(dC){if(D(dC,dz)){return dC}if(!D(dy,dC)){return dv}var dA=dC.line+dw.length-(dy.line-dz.line)-1;var dB=dC.ch;if(dC.line==dy.line){dB+=P(dw).length-(dy.ch-(dy.line==dz.line?dz.ch:0))}return{line:dA,ch:dB}}var dv;a0(dw,dz,dy,function(dA){dv=dA;return{from:dx(dt.from),to:dx(dt.to)}});return dv}function bR(dv,dw){a0(h(dv),dt.from,dt.to,function(dx){if(dw=="end"){return{from:dx,to:dx}}else{if(dw=="start"){return{from:dt.from,to:dt.from}}else{return{from:dt.from,to:dx}}}})}function a0(dy,dA,dz,dv){var dx=dy.length==1?dy[0].length+dA.ch:P(dy).length;var dw=dv({line:dA.line+dy.length-1,ch:dx});bb(dA,dz,dy,dw.from,dw.to)}function dk(dA,dz,dy){var dw=dA.line,dv=dz.line;if(dw==dv){return db(dw).text.slice(dA.ch,dz.ch)}var dx=[db(dw).text.slice(dA.ch)];c4.iter(dw+1,dv,function(dB){dx.push(dB.text)});dx.push(db(dv).text.slice(0,dz.ch));return dx.join(dy||"\n")}function cv(dv){return dk(dt.from,dt.to,dv)}function aJ(){if(bS){return}cA.set(ct.pollInterval,function(){cb();if(cO){aJ()}})}function bd(){var dv=false;bS=true;function dw(){var dx=cb();if(!dx&&!dv){dv=true;cA.set(60,dw)}else{bS=false;aJ()}}cA.set(20,dw)}var by="";function cb(){if(!cO||b(bJ)||ct.readOnly){return false}var dw=bJ.value;if(dw==by){return false}if(!cW){ba()}cN=null;var dx=0,dv=Math.min(by.length,dw.length);while(dx1000){bJ.value=by=""}else{by=dw}if(!cW){aW()}cf=false;return true}function c7(dv){if(!T(dt.from,dt.to)){by="";bJ.value=cv();if(cO){aF(bJ)}}else{if(dv){by=bJ.value=""}}}function b1(){if(ct.readOnly!="nocursor"&&(I||document.activeElement!=bJ)){bJ.focus()}}function cL(){var dy=cj();aY(dy.x,dy.y,dy.x,dy.yBot);if(!cO){return}var dw=cC.getBoundingClientRect(),dv=null;if(dy.y+dw.top<0){dv=true}else{if(dy.y+dw.top+ch()>(window.innerHeight||document.documentElement.clientHeight)){dv=false}}if(dv!=null){var dx=bA.style.display=="none";if(dx){bA.style.display="";bA.style.left=dy.x+"px";bA.style.top=(dy.y-bB)+"px"}bA.scrollIntoView(dv);if(dx){bA.style.display="none"}}}function cj(){var dw=dn(dt.inverted?dt.from:dt.to);var dv=ct.lineWrapping?Math.min(dw.x,bU.offsetWidth):dw.x;return{x:dv,y:dw.y,yBot:dw.yBot}}function aY(dw,dy,dv,dx){var dz=bm(dw,dy,dv,dx);if(dz.scrollLeft!=null){bH.scrollLeft=dz.scrollLeft}if(dz.scrollTop!=null){a8.scrollTop=bH.scrollTop=dz.scrollTop}}function bm(dy,dF,dw,dE){var dB=bt(),dK=cX();dF+=dK;dE+=dK;dy+=dB;dw+=dB;var dH=bH.clientHeight,dz=a8.scrollTop,dJ={};var dx=aN()||Infinity;var dv=dFdx-10;if(dFdz+dH){dJ.scrollTop=(dD?dx:dE)-dH}}var dG=bH.clientWidth,dI=bH.scrollLeft;var dC=ct.fixedGutter?a3.clientWidth:0;var dA=dydG+dI-3){dJ.scrollLeft=dw+10-dG}}return dJ}function b3(dz){var dv=ch(),dy=(dz!=null?dz:a8.scrollTop)-cX();var dx=Math.max(0,Math.floor(dy/dv));var dw=Math.ceil((dy+bH.clientHeight)/dv);return{from:af(c4,dx),to:af(c4,dw)}}function cJ(dE,dA,dy){if(!bH.clientWidth){dm=cc=bB=0;return}var dz=b3(dy);if(dE!==true&&dE.length==0&&dz.from>dm&&dz.todG&&cc-dG<20){dG=Math.min(c4.size,cc)}var dI=dE===true?[]:cs([{from:dm,to:cc,domStart:0}],dE);var dD=0;for(var dB=0;dBdG){dC.to=dG}if(dC.from>=dC.to){dI.splice(dB--,1)}else{dD+=dC.to-dC.from}}if(dD==dG-dF&&dF==dm&&dG==cc){aR(dy);return}dI.sort(function(dK,dJ){return dK.domStart-dJ.domStart});var dx=ch(),dv=a3.style.display;aO.style.display="none";be(dF,dG,dI);aO.style.display=a3.style.display="";var dw=dF!=dm||dG!=cc||cd!=bH.clientHeight+dx;if(dw){cd=bH.clientHeight+dx}if(dF!=dm||dG!=cc&&ct.onViewportChange){setTimeout(function(){if(ct.onViewportChange){ct.onViewportChange(cF,dF,dG)}})}dm=dF;cc=dG;bB=a(c4,dF);b8(100);if(aO.childNodes.length!=cc-dm){throw new Error("BAD PATCH! "+JSON.stringify(dI)+" size="+(cc-dm)+" nodes="+aO.childNodes.length)}function dH(){var dK=aO.firstChild,dJ=false;c4.iter(dm,cc,function(dM){if(!dK){return}if(!dM.hidden){var dL=Math.round(dK.offsetHeight/dx)||1;if(dM.height!=dL){br(dM,dL);bf=dJ=true}}dK=dK.nextSibling});return dJ}if(ct.lineWrapping){dH()}a3.style.display=dv;if(dw||bf){a7()&&ct.lineWrapping&&dH()&&a7()}aR(dy);ds();if(!dA&&ct.onUpdate){ct.onUpdate(cF)}return true}function cs(dE,dC){for(var dz=0,dx=dC.length||0;dz=dA.to){dv.push(dA)}else{if(dB.from>dA.from){dv.push({from:dA.from,to:dB.from,domStart:dA.domStart})}if(dB.todz){dx=dv(dx);dz++}for(var dy=0,dC=dF.to-dF.from;dydy){if(dH.hidden){var dI=ak("pre")}else{var dI=ce(dH);if(dH.className){dI.className=dH.className}if(dH.bgClassName){var dJ=ak("pre","\u00a0",dH.bgClassName,"position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: -2");dI=ak("div",[dJ,dI],null,"position: relative")}}aO.insertBefore(dI,dx)}else{dx=dx.nextSibling}++dy})}function a7(){if(!ct.gutter&&!ct.lineNumbers){return}var dw=cM.offsetHeight,dE=bH.clientHeight;a3.style.height=(dw-dE<2?dE:dw)+"px";var dC=document.createDocumentFragment(),dA=dm,dD;c4.iter(dm,Math.max(cc,dm+1),function(dG){if(dG.hidden){dC.appendChild(ak("pre"))}else{var dF=dG.gutterMarker;var dJ=ct.lineNumbers?ct.lineNumberFormatter(dA+ct.firstLineNumber):null;if(dF&&dF.text){dJ=dF.text.replace("%N%",dJ!=null?dJ:"")}else{if(dJ==null){dJ="\u00a0"}}var dI=dC.appendChild(ak("pre",null,dF&&dF.style));dI.innerHTML=dJ;for(var dH=1;dH2;bU.style.marginLeft=a3.offsetWidth+"px";bf=false;return dB}function ds(){var dy=T(dt.from,dt.to);var dJ=dn(dt.from,true);var dE=dy?dJ:dn(dt.to,true);var dC=dt.inverted?dJ:dE,dw=ch();var dv=B(a1),dx=B(aO);cp.style.top=Math.max(0,Math.min(bH.offsetHeight,dC.y+dx.top-dv.top))+"px";cp.style.left=Math.max(0,Math.min(bH.offsetWidth,dC.x+dx.left-dv.left))+"px";if(dy||ct.showCursorWhenSelecting){bA.style.top=dC.y+"px";bA.style.left=(ct.lineWrapping?Math.min(dC.x,bU.offsetWidth):dC.x)+"px";bA.style.display=""}else{bA.style.display="none"}if(!dy){var dH=dJ.y==dE.y,dB=document.createDocumentFragment();var dF=bU.clientWidth||bU.offsetWidth;var dA=bU.clientHeight||bU.offsetHeight;var dI=function(dO,dN,dM,dK){var dL=n?"width: "+(!dM?dF:dF-dM-dO)+"px":"right: "+(dM-1)+"px";dB.appendChild(ak("div",null,"CodeMirror-selected","position: absolute; left: "+dO+"px; top: "+dN+"px; "+dL+"; height: "+dK+"px"))};if(dt.from.ch&&dJ.y>=0){var dG=dH?dF-dE.x:0;dI(dJ.x,dJ.y,dG,dw)}var dz=Math.max(0,dJ.y+(dt.from.ch?dw:0));var dD=Math.min(dE.y,dA)-dz;if(dD>0.2*dw){dI(0,dz,0,dD)}if((!dH||!dt.from.ch)&&dE.ydx||dE>dB.text.length){dE=dB.text.length}return{line:dF,ch:dE}}dF+=dD}}var dv=db(dA.line);var dy=dA.ch==dv.text.length&&dA.ch!=dx;if(!dv.hidden){return dA}if(dA.line>=dw){return dz(1)||dz(-1)}else{return dz(-1)||dz(1)}}function bv(dv,dx,dw){var dy=bg({line:dv,ch:dx||0});(dw?bZ:bX)(dy,dy)}function cr(dv){return Math.max(0,Math.min(dv,c4.size-1))}function bg(dx){if(dx.line<0){return{line:0,ch:0}}if(dx.line>=c4.size){return{line:c4.size-1,ch:db(c4.size-1).text.length}}var dv=dx.ch,dw=db(dx.line).text.length;if(dv==null||dv>dw){return{line:dx.line,ch:dw}}else{if(dv<0){return{line:dx.line,ch:0}}else{return dx}}}function cU(dy,dC){var dz=dt.inverted?dt.from:dt.to,dD=dz.line,dv=dz.ch;var dB=db(dD);function dw(){for(var dE=dD+dy,dG=dy<0?-1:c4.size;dE!=dG;dE+=dy){var dF=db(dE);if(!dF.hidden){dD=dE;dB=dF;return true}}}function dA(dE){if(dv==(dy<0?0:dB.text.length)){if(!dE&&dw()){dv=dy<0?dB.text.length:0}else{return false}}else{dv+=dy}return true}if(dC=="char"){dA()}else{if(dC=="column"){dA(true)}else{if(dC=="word"){var dx=false;for(;;){if(dy<0){if(!dA()){break}}if(N(dB.text.charAt(dv))){dx=true}else{if(dx){if(dy<0){dy=1;dA()}break}}if(dy>0){if(!dA()){break}}}}}}return{line:dD,ch:dv}}function da(dv,dw){var dx=dv<0?dt.from:dt.to;if(cN||T(dt.from,dt.to)){dx=cU(dv,dw)}bv(dx.line,dx.ch,true)}function cS(dv,dw){if(!T(dt.from,dt.to)){ci("",dt.from,dt.to)}else{if(dv<0){ci("",cU(dv,dw),dt.to)}else{ci("",dt.from,cU(dv,dw))}}cz=true}function c3(dw,dy){var dA=0,dB=dn(dt.inverted?dt.from:dt.to,true);if(c0!=null){dB.x=c0}if(dy=="page"){var dv=Math.min(bH.clientHeight,window.innerHeight||document.documentElement.clientHeight);var dz=b9(dB.x,dB.y+dv*dw)}else{if(dy=="line"){var dx=ch();var dz=b9(dB.x,dB.y+0.5*dx+dw*dx)}}if(dy=="page"){a8.scrollTop+=dn(dz,true).y-dB.y}bv(dz.line,dz.ch,true);c0=dB.x}function bT(dA){var dy=db(dA.line).text;var dz=dA.ch,dx=dA.ch;if(dy){if(dA.after===false||dx==dy.length){--dz}else{++dx}var dw=dy.charAt(dz);var dv=N(dw)?N:/\s/.test(dw)?function(dB){return/\s/.test(dB)}:function(dB){return !/\s/.test(dB)&&N(dB)};while(dz>0&&dv(dy.charAt(dz-1))){--dz}while(dx=dz.ch)){dy.push(dx.marker)}}}return dy}function cn(dv,dx,dw){if(typeof dv=="number"){dv=db(cr(dv))}dv.gutterMarker={text:dx,style:dw};bf=true;return dv}function aS(dv){if(typeof dv=="number"){dv=db(cr(dv))}dv.gutterMarker=null;bf=true}function bk(dw,dy){var dx=dw,dv=dw;if(typeof dw=="number"){dv=db(cr(dw))}else{dx=X(dw)}if(dx==null){return null}if(dy(dv,dx)){aZ.push({from:dx,to:dx+1})}else{return null}return dv}function bI(dw,dv,dx){return bk(dw,function(dy){if(dy.className!=dv||dy.bgClassName!=dx){dy.className=dv;dy.bgClassName=dx;return true}})}function dg(dw,dv){return bk(dw,function(dx,dA){if(dx.hidden!=dv){dx.hidden=dv;if(!ct.lineWrapping){if(dv&&dx.text.length==b6.text.length){c9=true}else{if(!dv&&dx.text.length>b6.text.length){b6=dx;c9=false}}}br(dx,dv?0:1);var dz=dt.from.line,dy=dt.to.line;if(dv&&(dz==dA||dy==dA)){var dC=dz==dA?ck({line:dz,ch:0},dz,0):dt.from;var dB=dy==dA?ck({line:dy,ch:0},dy,0):dt.to;if(!dB){return}bX(dC,dB)}return(bf=true)}})}function bi(dw){if(typeof dw=="number"){if(!bQ(dw)){return null}var dx=dw;dw=db(dw);if(!dw){return null}}else{var dx=X(dw);if(dx==null){return null}}var dv=dw.gutterMarker;return{line:dx,handle:dw,text:dw.text,markerText:dv&&dv.text,markerClass:dv&&dv.style,lineClass:dw.className,bgClass:dw.bgClassName}}function cx(dv,dy){if(dy==0){return{top:0,left:0}}var dB=ce(dv,dy);s(aT,dB);var dx=dB.anchor;var dA=dx.offsetTop,dz=dx.offsetLeft;if(U&&dA==0&&dz==0){var dw=ak("span","x");dx.parentNode.insertBefore(dw,dx.nextSibling);dA=dw.offsetTop}return{top:dA,left:dz}}function dn(dA,dy){var dv,dw=ch(),dz=dw*(a(c4,dA.line)-(dy?bB:0));if(dA.ch==0){dv=0}else{var dx=cx(db(dA.line),dA.ch);dv=dx.left;if(ct.lineWrapping){dz+=Math.max(0,dx.top)}}return{x:dv,y:dz,yBot:dz+dw}}function b9(dG,dF){var dD=ch(),dA=bE(),dM=bB+Math.floor(dF/dD);if(dM<0){return{line:0,ch:0}}var dH=af(c4,dM);if(dH>=c4.size){return{line:c4.size-1,ch:db(c4.size-1).text.length}}var dw=db(dH),dJ=dw.text;var dO=ct.lineWrapping,dE=dO?dM-a(c4,dH):0;if(dG<=0&&dE==0){return{line:dH,ch:0}}var dB=false;function dN(dQ){var dR=cx(dw,dQ);if(dO){var dS=Math.round(dR.top/dD);dB=dS!=dE;return Math.max(0,dR.left+(dS-dE)*bH.clientWidth)}return dR.left}var dL=0,dK=0,dx=dJ.length,dv;var dI=Math.min(dx,Math.ceil((dG+dE*bH.clientWidth*0.9)/dA));for(;;){var dC=dN(dI);if(dC<=dG&&dIdv){return{line:dH,ch:dx}}dI=Math.floor(dx*0.8);dC=dN(dI);if(dCdG){dx=dP;dv=dy;if(dB){dv+=1000}}else{dL=dP;dK=dy}}}function aM(dx){var dv=dn(dx,true),dw=B(bU);return{x:dw.left+dv.x,y:dw.top+dv.y,yBot:dw.top+dv.yBot}}var bo,aV,aL;function ch(){if(aL==null){aL=ak("pre");for(var dw=0;dw<49;++dw){aL.appendChild(document.createTextNode("x"));aL.appendChild(ak("br"))}aL.appendChild(document.createTextNode("x"))}var dv=aO.clientHeight;if(dv==aV){return bo}aV=dv;s(aT,aL.cloneNode(true));bo=aT.firstChild.offsetHeight/50||1;aH(aT);return bo}var dp,bV=0;function bE(){if(bH.clientWidth==bV){return dp}bV=bH.clientWidth;var dv=ak("span","x");var dw=ak("pre",[dv]);s(aT,dw);return(dp=dv.offsetWidth||10)}function cX(){return bU.offsetTop}function bt(){return bU.offsetLeft}function bq(dz,dy){var dx=B(bH,true),dv,dA;try{dv=dz.clientX;dA=dz.clientY}catch(dz){return null}if(!dy&&(dv-dx.left>bH.clientWidth||dA-dx.top>bH.clientHeight)){return null}var dw=B(bU,true);return b9(dv-dw.left,dA-dw.top)}var bP;function bp(dw){var dA=bq(dw),dz=a8.scrollTop;if(!dA||ax){return}if(T(dt.from,dt.to)||D(dA,dt.from)||!D(dA,dt.to)){aP(bv)(dA.line,dA.ch)}var dy=bJ.style.cssText;cp.style.position="absolute";bJ.style.cssText="position: fixed; width: 30px; height: 30px; top: "+(dw.clientY-5)+"px; left: "+(dw.clientX-5)+"px; z-index: 1000; background: white; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";b1();c7(true);if(T(dt.from,dt.to)){bJ.value=by=" "}function dv(){cp.style.position="relative";bJ.style.cssText=dy;if(I){a8.scrollTop=dz}aJ();if(bJ.selectionStart!=null){clearTimeout(bP);var dC=bJ.value=" "+(T(dt.from,dt.to)?"":bJ.value),dB=0;by=" ";bJ.selectionStart=1;bJ.selectionEnd=dC.length;bP=setTimeout(function dD(){if(by==" "&&bJ.selectionStart==0){aP(t.selectAll)(cF)}else{if(dB++<10){bP=setTimeout(dD,500)}else{c7()}}},200)}}if(x){ae(dw);var dx=aE(window,"mouseup",function(){dx();setTimeout(dv,20)},true)}else{setTimeout(dv,50)}}function di(){clearInterval(dl);var dv=true;bA.style.visibility="";dl=setInterval(function(){bA.style.visibility=(dv=!dv)?"":"hidden"},ct.cursorBlinkRate)}var bM={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"};function cK(dB){var dv=dt.inverted?dt.from:dt.to,dD=db(dv.line),dw=dv.ch-1;var dA=(dw>=0&&bM[dD.text.charAt(dw)])||bM[dD.text.charAt(++dw)];if(!dA){return}var dE=dA.charAt(0),dC=dA.charAt(1)==">",dO=dC?1:-1,dJ=dD.styles;for(var dP=dw+1,dL=0,dN=dJ.length;dL=dW&&dV"==dC){dy.push(dY)}else{if(dy.pop()!=dT.charAt(0)){return{pos:dV,match:false}}else{if(!dy.length){return{pos:dV,match:true}}}}}}}}for(var dL=dv.line,dN=dC?Math.min(dL+100,c4.size):Math.max(-1,dL-100);dL!=dN;dL+=dO){var dD=db(dL),dz=dL==dv.line;var dF=dG(dD,dz&&dC?dw+1:0,dz&&!dC?dw:dD.text.length);if(dF){break}}if(!dF){dF={pos:null,match:false}}var dM=dF.match?"CodeMirror-matchingbracket":"CodeMirror-nonmatchingbracket";var dK=b7({line:dv.line,ch:dw},{line:dv.line,ch:dw+1},dM),dx=dF.pos!=null&&b7({line:dL,ch:dF.pos},{line:dL,ch:dF.pos+1},dM);var dH=aP(function(){dK.clear();dx&&dx.clear()});if(dB){setTimeout(dH,800)}else{cw=dH}}function bw(dB){var dA,dx;for(var dw=dB,dy=dB-40;dw>dy;--dw){if(dw==0){return 0}var dv=db(dw-1);if(dv.stateAfter){return dw}var dz=dv.indentation(ct.tabSize);if(dx==null||dA>dz){dx=dw-1;dA=dz}}return dx}function cZ(dx){var dw=bw(dx),dv=dw&&db(dw-1).stateAfter;if(!dv){dv=v(cH)}else{dv=o(cH,dv)}c4.iter(dw,dx,function(dy){dy.process(cH,dv,ct.tabSize);dy.stateAfter=(dw==dx-1||dw%5==0)?o(cH,dv):null});return dv}function cl(){if(df>=cc){return}var dv=+new Date+ct.workTime,dx=o(cH,cZ(df));var dw=df;c4.iter(df,cc,function(dy){if(df>=dm){dy.highlight(cH,dx,ct.tabSize);dy.stateAfter=o(cH,dx)}else{dy.process(cH,dx,ct.tabSize);dy.stateAfter=df%5==0?o(cH,dx):null}++df;if(+new Date>dv){b8(ct.workDelay);return true}});if(cc>dw&&df>=dm){aP(function(){aZ.push({from:dw,to:df})})()}}function b8(dv){if(df2){aL.dependencies=[];for(var aK=2;aK0&&aL.ch=this.string.length},sol:function(){return this.pos==0},peek:function(){return this.string.charAt(this.pos)||undefined},next:function(){if(this.posaK},eatSpace:function(){var aJ=this.pos;while(/[\s\u00a0]/.test(this.string.charAt(this.pos))){++this.pos}return this.pos>aJ},skipToEnd:function(){this.pos=this.string.length},skipTo:function(aJ){var aK=this.string.indexOf(aJ,this.pos);if(aK>-1){this.pos=aK;return true}},backUp:function(aJ){this.pos-=aJ},column:function(){return ap(this.string,this.start,this.tabSize)},indentation:function(){return ap(this.string,null,this.tabSize)},match:function(aM,aK,aJ){if(typeof aM=="string"){var aN=function(aO){return aJ?aO.toLowerCase():aO};if(aN(this.string).indexOf(aN(aM),this.pos)==this.pos){if(aK!==false){this.pos+=aM.length}return true}}else{var aL=this.string.slice(this.pos).match(aM);if(aL&&aL.index>0){return null}if(aL&&aK!==false){this.pos+=aL[0].length}return aL}},current:function(){return this.string.slice(this.start,this.pos)}};r.StringStream=ai;function Z(aL,aK,aJ){this.from=aL;this.to=aK;this.marker=aJ}function aI(aL,aJ){if(aL){for(var aK=0;aK=aL:aR.to>aL);(aQ||(aQ=[])).push({from:aR.from,to:aM?null:aR.to,marker:aP})}}}return aQ}function aw(aL,aO){if(aL){for(var aN=0,aK;aN=aO:aP.to>aO);if(aQ||aJ.type=="bookmark"&&aP.from==aO){var aM=aP.from==null||(aJ.inclusiveLeft?aP.from<=aO:aP.from0&&aP){for(var aM=0;aM5000){aJ[aQ++]=this.text.slice(aO.pos);aJ[aQ++]=null;break}}},process:function(aM,aJ,aK){var aL=new ai(this.text,aK);if(this.text==""&&aM.blankLine){aM.blankLine(aJ)}while(!aL.eol()&&aL.pos<=5000){aM.token(aL,aJ);aL.start=aL.pos}},getTokenAt:function(aP,aM,aN,aL){var aJ=this.text,aO=new ai(aJ,aN);while(aO.pos=a3&&aJaJ+10&&/\s/.test(bm)){a9=function(){}}}}}}var a2=this.styles,aR=this.text,aZ=this.markedSpans;var bd=aR.length;function aM(bh){if(!bh){return null}return"cm-"+bh.replace(/ +/g," cm-")}if(!aR&&aJ==null){a9(aX," ")}else{if(!aZ||!aZ.length){for(var ba=0,aT=0;aTbd){a1=a1.slice(0,bd-aT)}aT+=a4;a9(aX,a1,aM(bc))}}else{aZ.sort(function(bi,bh){return bi.from-bh.from});var aO=0,ba=0,aW="",bc,bg=0;var bf=aZ[0].from||0,a8=[],be=0;var bb=function(){var bh;while(beaV?aW.slice(0,aV-aO):aW,aK);if(aL>=aV){aW=aW.slice(aV-aO);aO=aV;break}aO=aL}aW=a2[ba++];bc=aM(a2[ba++])}}}}return aX},cleanUp:function(){this.parent=null;aA(this)}};function Q(aK){this.lines=aK;this.parent=null;for(var aL=0,aM=aK.length,aJ=0;aL50){while(aJ.lines.length>50){var aM=aJ.lines.splice(aJ.lines.length-25,25);var aP=new Q(aM);aJ.height-=aP.height;this.children.splice(aL+1,0,aP);aP.parent=this}this.maybeSpill()}break}aK-=aO}},maybeSpill:function(){if(this.children.length<=10){return}var aM=this;do{var aK=aM.children.splice(aM.children.length-5,5);var aL=new al(aK);if(!aM.parent){var aN=new al(aM.children);aN.parent=aM;aM.children=[aN,aL];aM=aN}else{aM.size-=aL.size;aM.height-=aL.height;var aJ=u(aM.parent.children,aM);aM.parent.children.splice(aJ+1,0,aL)}aL.parent=aM.parent}while(aM.children.length>10);aM.parent.maybeSpill()},iter:function(aL,aK,aJ){this.iterN(aL,aK-aL,aJ)},iterN:function(aJ,aQ,aP){for(var aK=0,aN=this.children.length;aK400||!aR||this.closed||aR.start>aJ+aK.length||aR.start+aR.added0;--aM){aR.old.unshift(aK[aM-1])}for(var aM=aS;aM>0;--aM){aR.old.push(aK[aK.length-aM])}if(aP){aR.start=aJ}aR.added+=aO-(aK.length-aP-aS)}}this.time=aL},startCompound:function(){if(!this.compound++){this.closed=true}},endCompound:function(){if(!--this.compound){this.closed=true}}};function z(){ae(this)}function R(aJ){if(!aJ.stop){aJ.stop=z}return aJ}function f(aJ){if(aJ.preventDefault){aJ.preventDefault()}else{aJ.returnValue=false}}function q(aJ){if(aJ.stopPropagation){aJ.stopPropagation()}else{aJ.cancelBubble=true}}function ae(aJ){f(aJ);q(aJ)}r.e_stop=ae;r.e_preventDefault=f;r.e_stopPropagation=q;function ar(aJ){return aJ.target||aJ.srcElement}function E(aK){var aJ=aK.which;if(aJ==null){if(aK.button&1){aJ=1}else{if(aK.button&2){aJ=3}else{if(aK.button&4){aJ=2}}}}if(K&&aK.ctrlKey&&aJ==1){aJ=3}return aJ}function ad(aK,aL){var aJ=aK.override&&aK.override.hasOwnProperty(aL);return aJ?aK.override[aL]:aK[aL]}function aE(aM,aL,aK,aJ){if(typeof aM.addEventListener=="function"){aM.addEventListener(aL,aK,false);if(aJ){return function(){aM.removeEventListener(aL,aK,false)}}}else{var aN=function(aO){aK(aO||window.event)};aM.attachEvent("on"+aL,aN);if(aJ){return function(){aM.detachEvent("on"+aL,aN)}}}}r.connect=aE;function j(){this.id=null}j.prototype={set:function(aJ,aK){clearTimeout(this.id);this.id=setTimeout(aK,aJ)}};var aq=r.Pass={toString:function(){return"CodeMirror.Pass"}};var ac=function(){if(I){return false}var aJ=ak("div");return"draggable" in aJ||"dragDrop" in aJ}();var S=function(){var aJ=ak("textarea");aJ.value="foo\nbar";if(aJ.value.indexOf("\r")>-1){return"\r\n"}return"\n"}();var H=/^$/;if(x){H=/$'/}else{if(G){H=/\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/}else{if(p){H=/\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/}}}function ap(aK,aJ,aM){if(aJ==null){aJ=aK.search(/[^\s\u00a0]/);if(aJ==-1){aJ=aK.length}}for(var aL=0,aN=0;aL=0&&aJ>=0;--aK,--aJ){if(aM.charAt(aK)!=aL.charAt(aJ)){break}}return aJ+1}function u(aM,aJ){if(aM.indexOf){return aM.indexOf(aJ)}for(var aK=0,aL=aM.length;aK"\x80"&&(aJ.toUpperCase()!=aJ.toLowerCase()||O.test(aJ))}var h="\n\nb".split(/\n/).length!=3?function(aO){var aP=0,aJ=[],aN=aO.length;while(aP<=aN){var aM=aO.indexOf("\n",aP);if(aM==-1){aM=aO.length}var aL=aO.slice(aP,aO.charAt(aM-1)=="\r"?aM-1:aM);var aK=aL.indexOf("\r");if(aK!=-1){aJ.push(aL.slice(0,aK));aP+=aK+1}else{aJ.push(aL);aP=aM+1}}return aJ}:function(aJ){return aJ.split(/\r\n?|\n/)};r.splitLines=h;var b=window.getSelection?function(aK){try{return aK.selectionStart!=aK.selectionEnd}catch(aJ){return false}}:function(aL){try{var aJ=aL.ownerDocument.selection.createRange()}catch(aK){}if(!aJ||aJ.parentElement()!=aL){return false}return aJ.compareEndPoints("StartToEnd",aJ)!=0};r.defineMode("null",function(){return{token:function(aJ){aJ.skipToEnd()}}});r.defineMIME("text/plain","null");var w={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"};r.keyNames=w;(function(){for(var aJ=0;aJ<10;aJ++){w[aJ+48]=String(aJ)}for(var aJ=65;aJ<=90;aJ++){w[aJ]=String.fromCharCode(aJ)}for(var aJ=1;aJ<=12;aJ++){w[aJ+111]=w[aJ+63235]="F"+aJ}})();r.version="2.38";return r})(); \ No newline at end of file diff --git a/phpmyadmin/js/codemirror/mode/mysql/mysql.js b/phpmyadmin/js/codemirror/mode/mysql/mysql.js new file mode 100644 index 000000000..029094cef --- /dev/null +++ b/phpmyadmin/js/codemirror/mode/mysql/mysql.js @@ -0,0 +1 @@ +CodeMirror.defineMode("mysql",function(b){var e=b.indentUnit;var l;function g(n){return new RegExp("^(?:"+n.join("|")+")$","i")}var a=g(["str","lang","langmatches","datatype","bound","sameterm","isiri","isuri","isblank","isliteral","union","a"]);var d=g([("ACCESSIBLE"),("ALTER"),("AS"),("BEFORE"),("BINARY"),("BY"),("CASE"),("CHARACTER"),("COLUMN"),("CONTINUE"),("CROSS"),("CURRENT_TIMESTAMP"),("DATABASE"),("DAY_MICROSECOND"),("DEC"),("DEFAULT"),("DESC"),("DISTINCT"),("DOUBLE"),("EACH"),("ENCLOSED"),("EXIT"),("FETCH"),("FLOAT8"),("FOREIGN"),("GRANT"),("HIGH_PRIORITY"),("HOUR_SECOND"),("IN"),("INNER"),("INSERT"),("INT2"),("INT8"),("INTO"),("JOIN"),("KILL"),("LEFT"),("LINEAR"),("LOCALTIME"),("LONG"),("LOOP"),("MATCH"),("MEDIUMTEXT"),("MINUTE_SECOND"),("NATURAL"),("NULL"),("OPTIMIZE"),("OR"),("OUTER"),("PRIMARY"),("RANGE"),("READ_WRITE"),("REGEXP"),("REPEAT"),("RESTRICT"),("RIGHT"),("SCHEMAS"),("SENSITIVE"),("SHOW"),("SPECIFIC"),("SQLSTATE"),("SQL_CALC_FOUND_ROWS"),("STARTING"),("TERMINATED"),("TINYINT"),("TRAILING"),("UNDO"),("UNLOCK"),("USAGE"),("UTC_DATE"),("VALUES"),("VARCHARACTER"),("WHERE"),("WRITE"),("ZEROFILL"),("ALL"),("AND"),("ASENSITIVE"),("BIGINT"),("BOTH"),("CASCADE"),("CHAR"),("COLLATE"),("CONSTRAINT"),("CREATE"),("CURRENT_TIME"),("CURSOR"),("DAY_HOUR"),("DAY_SECOND"),("DECLARE"),("DELETE"),("DETERMINISTIC"),("DIV"),("DUAL"),("ELSEIF"),("EXISTS"),("FALSE"),("FLOAT4"),("FORCE"),("FULLTEXT"),("HAVING"),("HOUR_MINUTE"),("IGNORE"),("INFILE"),("INSENSITIVE"),("INT1"),("INT4"),("INTERVAL"),("ITERATE"),("KEYS"),("LEAVE"),("LIMIT"),("LOAD"),("LOCK"),("LONGTEXT"),("MASTER_SSL_VERIFY_SERVER_CERT"),("MEDIUMINT"),("MINUTE_MICROSECOND"),("MODIFIES"),("NO_WRITE_TO_BINLOG"),("ON"),("OPTIONALLY"),("OUT"),("PRECISION"),("PURGE"),("READS"),("REFERENCES"),("RENAME"),("REQUIRE"),("REVOKE"),("SCHEMA"),("SELECT"),("SET"),("SPATIAL"),("SQLEXCEPTION"),("SQL_BIG_RESULT"),("SSL"),("TABLE"),("TINYBLOB"),("TO"),("TRUE"),("UNIQUE"),("UPDATE"),("USING"),("UTC_TIMESTAMP"),("VARCHAR"),("WHEN"),("WITH"),("YEAR_MONTH"),("ADD"),("ANALYZE"),("ASC"),("BETWEEN"),("BLOB"),("CALL"),("CHANGE"),("CHECK"),("CONDITION"),("CONVERT"),("CURRENT_DATE"),("CURRENT_USER"),("DATABASES"),("DAY_MINUTE"),("DECIMAL"),("DELAYED"),("DESCRIBE"),("DISTINCTROW"),("DROP"),("ELSE"),("ESCAPED"),("EXPLAIN"),("FLOAT"),("FOR"),("FROM"),("GROUP"),("HOUR_MICROSECOND"),("IF"),("INDEX"),("INOUT"),("INT"),("INT3"),("INTEGER"),("IS"),("KEY"),("LEADING"),("LIKE"),("LINES"),("LOCALTIMESTAMP"),("LONGBLOB"),("LOW_PRIORITY"),("MEDIUMBLOB"),("MIDDLEINT"),("MOD"),("NOT"),("NUMERIC"),("OPTION"),("ORDER"),("OUTFILE"),("PROCEDURE"),("READ"),("REAL"),("RELEASE"),("REPLACE"),("RETURN"),("RLIKE"),("SECOND_MICROSECOND"),("SEPARATOR"),("SMALLINT"),("SQL"),("SQLWARNING"),("SQL_SMALL_RESULT"),("STRAIGHT_JOIN"),("THEN"),("TINYTEXT"),("TRIGGER"),("UNION"),("UNSIGNED"),("USE"),("UTC_TIME"),("VARBINARY"),("VARYING"),("WHILE"),("XOR"),("FULL"),("COLUMNS"),("MIN"),("MAX"),("STDEV"),("COUNT")]);var f=/[*+\-<>=&|]/;function c(r,p){var o=r.next();l=null;if(o=="$"||o=="?"){r.match(/^[\w\d]*/);return"variable-2"}else{if(o=="<"&&!r.match(/^[\s\u00a0=]/,false)){r.match(/^[^\s\u00a0>]*>?/);return"atom"}else{if(o=='"'||o=="'"){p.tokenize=m(o);return p.tokenize(r,p)}else{if(o=="`"){p.tokenize=j(o);return p.tokenize(r,p)}else{if(/[{}\(\),\.;\[\]]/.test(o)){l=o;return null}else{if(o=="-"&&r.eat("-")){r.skipToEnd();return"comment"}else{if(o=="/"&&r.eat("*")){p.tokenize=i;return p.tokenize(r,p)}else{if(f.test(o)){r.eatWhile(f);return null}else{if(o==":"){r.eatWhile(/[\w\d\._\-]/);return"atom"}else{r.eatWhile(/[_\w\d]/);if(r.eat(":")){r.eatWhile(/[\w\d_\-]/);return"atom"}var q=r.current(),n;if(a.test(q)){return null}else{if(d.test(q)){return"keyword"}else{return"variable"}}}}}}}}}}}}function m(n){return function(r,p){var q=false,o;while((o=r.next())!=null){if(o==n&&!q){p.tokenize=c;break}q=!q&&o=="\\"}return"string"}}function j(n){return function(r,p){var q=false,o;while((o=r.next())!=null){if(o==n&&!q){p.tokenize=c;break}q=!q&&o=="\\"}return"variable-2"}}function i(o,n){for(;;){if(o.skipTo("*")){o.next();if(o.eat("/")){n.tokenize=c;break}}else{o.skipToEnd();break}}return"comment"}function h(p,o,n){p.context={prev:p.context,indent:p.indent,col:n,type:o}}function k(n){n.indent=n.context.indent;n.context=n.context.prev}return{startState:function(n){return{tokenize:c,context:null,indent:0,col:0}},token:function(p,o){if(p.sol()){if(o.context&&o.context.align==null){o.context.align=false}o.indent=p.indentation()}if(p.eatSpace()){return null}var n=o.tokenize(p,o);if(n!="comment"&&o.context&&o.context.align==null&&o.context.type!="pattern"){o.context.align=true}if(l=="("){h(o,")",p.column())}else{if(l=="["){h(o,"]",p.column())}else{if(l=="{"){h(o,"}",p.column())}else{if(/[\]\}\)]/.test(l)){while(o.context&&o.context.type=="pattern"){k(o)}if(o.context&&l==o.context.type){k(o)}}else{if(l=="."&&o.context&&o.context.type=="pattern"){k(o)}else{if(/atom|string|variable/.test(n)&&o.context){if(/[\}\]]/.test(o.context.type)){h(o,"pattern",p.column())}else{if(o.context.type=="pattern"&&!o.context.align){o.context.align=true;o.context.col=p.column()}}}}}}}}return n},indent:function(r,n){var q=n&&n.charAt(0);var p=r.context;if(/[\]\}]/.test(q)){while(p&&p.type=="pattern"){p=p.prev}}var o=p&&q==p.type;if(!p){return 0}else{if(p.type=="pattern"){return p.col}else{if(p.align){return p.col+(o?0:1)}else{return p.indent+(o?0:e)}}}}}});CodeMirror.defineMIME("text/x-mysql","mysql"); \ No newline at end of file diff --git a/phpmyadmin/js/common.js b/phpmyadmin/js/common.js new file mode 100644 index 000000000..ca3343eef --- /dev/null +++ b/phpmyadmin/js/common.js @@ -0,0 +1 @@ +$(function(){$("#pma_open_querywindow").click(function(a){a.preventDefault();PMA_querywindow.focus()})});var PMA_commonParams=(function(){var a={};return{setAll:function(d){var c=false;for(var b in d){if(a[b]!==undefined&&a[b]!==d[b]){c=true}a[b]=d[b]}if(c){PMA_querywindow.refresh()}},get:function(b){return a[b]||""},set:function(b,c){if(a[b]!==undefined&&a[b]!==c){PMA_querywindow.refresh();PMA_reloadNavigation()}a[b]=c;return this},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")))}}})();var PMA_commonActions={setDb:function(a){if(a!=PMA_commonParams.get("db")){PMA_commonParams.set("db",a);PMA_querywindow.refresh()}},openDb:function(a){PMA_commonParams.set("db",a).set("table","");PMA_querywindow.refresh();this.refreshMain(PMA_commonParams.get("opendb_url"))},refreshMain:function(a,b){if(!a){a=$("#selflink a").attr("href");a=a.substring(0,a.indexOf("?"))}a+=PMA_commonParams.getUrlQuery();$("",{href:a}).appendTo("body").click().remove();AJAX._callback=b}};var PMA_querywindow=(function(d,c){var b={};var a="";return{open:function(f,g){if(!f){f="querywindow.php"+PMA_commonParams.getUrlQuery()}if(g){f+="&sql_query="+encodeURIComponent(g)}if(!b.closed&&b.location){var e=b.location.href;if(e!=f&&e!=PMA_commonParams.get("pma_absolute_uri")+f){if(PMA_commonParams.get("safari_browser")){b.location.href=targeturl}else{b.location.replace(targeturl)}b.focus()}}else{b=c.open(f+"&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(!b.opener){b.opener=c.window}if(c.focus){b.focus()}},focus:function(f){if(!b||b.closed||!b.location){a=f;this.open(false,f)}else{var e=b.document.getElementById("hiddenqueryform");if(e.querydisplay_tab!="sql"){e.querydisplay_tab.value="sql";e.sql_query.value=f;d(e).addClass("disableAjax");e.submit();b.focus()}else{b.focus()}}},refresh:function(f){if(!b.closed&&b.location){var e=d(b.document).find("#sqlqueryform");if(e.find("#checkbox_lock:checked").length==0){PMA_querywindow.open(f)}}},reload:function(f,g,i){if(!b.closed&&b.location){var e=d(b.document).find("#sqlqueryform");if(e.find("#checkbox_lock:checked").length==0){var h=d(b.document).find("#hiddenqueryform");h.find("input[name=db]").val(f);h.find("input[name=table]").val(g);if(i){h.find("input[name=sql_query]").val(i)}h.addClass("disableAjax").submit()}}}}})(jQuery,window); \ No newline at end of file diff --git a/phpmyadmin/js/config.js b/phpmyadmin/js/config.js new file mode 100644 index 000000000..fafd12168 --- /dev/null +++ b/phpmyadmin/js/config.js @@ -0,0 +1 @@ +AJAX.registerTeardown("config.js",function(){$("input[id], select[id], textarea[id]").unbind("change").unbind("keyup");$("input[type=button][name=submit_reset]").unbind("click");$("div.tabs_contents").undelegate();$("#import_local_storage, #export_local_storage").unbind("click");$("form.prefs-form").unbind("change").unbind("submit");$("div.click-hide-message").die("click");$("#prefs_autoload").find("a").unbind("click")});AJAX.registerOnload("config.js",function(){$("#topmenu2").find("li.active a").attr("rel","samepage");$("#topmenu2").find("li:not(.active) a").attr("rel","newpage")});var defaultValues={};function getFieldType(b){b=$(b);var a=b.prop("tagName");if(a=="INPUT"){return b.attr("type")}else{if(a=="SELECT"){return"select"}else{if(a=="TEXTAREA"){return"text"}}}return""}function setFieldValue(f,e,d){f=$(f);switch(e){case"text":f.attr("value",(d!=undefined?d:f.attr("defaultValue")));break;case"checkbox":f.attr("checked",(d!=undefined?d:f.attr("defaultChecked")));break;case"select":var a=f.prop("options");var c,b=a.length;if(d==undefined){for(c=0;c');g.find("table").before(d)}else{d=$('
      ');g.closest("td").append(d)}}var c="";for(var b=0,a=h.length;b"+h[b]+""}d.html(c)}else{if(d!==null){d.remove()}}}}function validate_fieldset(a,b,e){a=$(a);if(a.length&&typeof validators._fieldset[a.attr("id")]!="undefined"){var c=validators._fieldset[a.attr("id")].apply(a[0],[b]);for(var d in c){if(typeof e[d]=="undefined"){e[d]=[]}if(typeof c[d]=="string"){c[d]=[c[d]]}$.merge(e[d],c[d])}}}function validate_field(g,b,h){g=$(g);var e=g.attr("id");h[e]=[];var f=getFieldValidators(e,b);for(var d=0;d9?"":"0")+a}function isDate(c,b){var a=getDateFromFormat(c,b);if(a==0){return false}return true}function compareDates(e,f,c,d){var b=getDateFromFormat(e,f);var a=getDateFromFormat(c,d);if(b==0||a==0){return -1}else{if(b>a){return 1}}return 0}function formatDate(I,D){D=D+"";var l="";var v=0;var G="";var f="";var j=I.getYear()+"";var g=I.getMonth()+1;var F=I.getDate();var o=I.getDay();var n=I.getHours();var x=I.getMinutes();var q=I.getSeconds();var t,u,b,r,J,e,C,B,z,p,N,n,L,i,a,A;var w=new Object();if(j.length<4){j=""+(j-0+1900)}w.y=""+j;w.yyyy=j;w.yy=j.substring(2,4);w.M=g;w.MM=LZ(g);w.MMM=MONTH_NAMES[g-1];w.NNN=MONTH_NAMES[g+11];w.d=F;w.dd=LZ(F);w.E=DAY_NAMES[o+7];w.EE=DAY_NAMES[o];w.H=n;w.HH=LZ(n);if(n==0){w.h=12}else{if(n>12){w.h=n-12}else{w.h=n}}w.hh=LZ(w.h);if(n>11){w.K=n-12}else{w.K=n}w.k=n+1;w.KK=LZ(w.K);w.kk=LZ(w.k);if(n>11){w.a="PM"}else{w.a="AM"}w.m=x;w.mm=LZ(x);w.s=q;w.ss=LZ(q);while(v=e;a--){var b=f.substring(d,d+a);if(b.length70){j=1900+(j-0)}else{j=2000+(j-0)}}}else{if(f=="MMM"||f=="NNN"){t=0;for(var o=0;o11)){t=o+1;if(t>12){t-=12}v+=e.length;break}}}if((t<1)||(t>12)){return 0}}else{if(f=="EE"||f=="E"){for(var o=0;o12)){return 0}v+=t.length}else{if(f=="dd"||f=="d"){s=_getInt(w,v,f.length,2);if(s==null||(s<1)||(s>31)){return 0}v+=s.length}else{if(f=="hh"||f=="h"){d=_getInt(w,v,f.length,2);if(d==null||(d<1)||(d>12)){return 0}v+=d.length}else{if(f=="HH"||f=="H"){d=_getInt(w,v,f.length,2);if(d==null||(d<0)||(d>23)){return 0}v+=d.length}else{if(f=="KK"||f=="K"){d=_getInt(w,v,f.length,2);if(d==null||(d<0)||(d>11)){return 0}v+=d.length}else{if(f=="kk"||f=="k"){d=_getInt(w,v,f.length,2);if(d==null||(d<1)||(d>24)){return 0}v+=d.length;d--}else{if(f=="mm"||f=="m"){q=_getInt(w,v,f.length,2);if(q==null||(q<0)||(q>59)){return 0}v+=q.length}else{if(f=="ss"||f=="s"){n=_getInt(w,v,f.length,2);if(n==null||(n<0)||(n>59)){return 0}v+=n.length}else{if(f=="a"){if(w.substring(v,v+2).toLowerCase()=="am"){k="AM"}else{if(w.substring(v,v+2).toLowerCase()=="pm"){k="PM"}else{return 0}}v+=2}else{if(w.substring(v,v+f.length)!=f){return 0}else{v+=f.length}}}}}}}}}}}}}}if(v!=w.length){return 0}if(t==2){if(((j%4==0)&&(j%100!=0))||(j%400==0)){if(s>29){return 0}}else{if(s>28){return 0}}}if((t==4)||(t==6)||(t==9)||(t==11)){if(s>30){return 0}}if(d<12&&k=="PM"){d=d-0+12}else{if(d>11&&k=="AM"){d-=12}}var a=new Date(j,t-1,s,d,q,n);return a.getTime()}function parseDate(h){var f=(arguments.length==2)?arguments[1]:false;generalFormats=new Array("y-M-d","MMM d, y","MMM d,y","y-MMM-d","d-MMM-y","MMM d");monthFirst=new Array("M/d/y","M-d-y","M.d.y","MMM-d","M/d","M-d");dateFirst=new Array("d/M/y","d-M-y","d.M.y","d-MMM","d/M","d-M");var b=new Array("generalFormats",f?"dateFirst":"monthFirst",f?"monthFirst":"dateFirst");var g=null;for(var e=0;e').insertAfter("#searchresults").hide();$('
      ').insertAfter("#togglesearchresultsdiv").show();$("#togglesearchresultlink").html(PMA_messages.strHideSearchResults).bind("click",function(){var b=$(this);$("#searchresults").slideToggle();if(b.text()==PMA_messages.strHideSearchResults){b.text(PMA_messages.strShowSearchResults)}else{b.text(PMA_messages.strHideSearchResults)}return false});$('
      ').insertAfter("#db_search_form").hide();$("#togglequerybox").hide().bind("click",function(){var b=$(this);$("#sqlqueryform").slideToggle("medium");if(b.text()==PMA_messages.strHideQueryBox){b.text(PMA_messages.strShowQueryBox)}else{b.text(PMA_messages.strHideQueryBox)}return false});$("#togglesearchformlink").html(PMA_messages.strShowSearchCriteria).bind("click",function(){var b=$(this);$("#db_search_form").slideToggle();if(b.text()==PMA_messages.strHideSearchCriteria){b.text(PMA_messages.strShowSearchCriteria)}else{b.text(PMA_messages.strHideSearchCriteria)}return false});$("#db_search_form.ajax").live("submit",function(d){d.preventDefault();var e=PMA_ajaxShowMessage(PMA_messages.strSearching,false);var b=$(this);PMA_prepareForAjaxRequest(b);var c=b.serialize()+"&submit_search="+$("#buttonGo").val();$.post(b.attr("action"),c,function(f){if(f.success==true){$("#searchresults").html(f.message);$("#togglesearchresultlink").text(PMA_messages.strHideSearchResults);$("#togglesearchresultsdiv").show();$("#searchresults").show();$("#db_search_form").slideToggle().hide();$("#togglesearchformlink").text(PMA_messages.strShowSearchCriteria);$("#togglesearchformdiv").show()}else{$("#sqlqueryresults").html(f.error)}PMA_ajaxRemoveMessage(e)})})}); \ No newline at end of file diff --git a/phpmyadmin/js/db_structure.js b/phpmyadmin/js/db_structure.js new file mode 100644 index 000000000..7fd952be5 --- /dev/null +++ b/phpmyadmin/js/db_structure.js @@ -0,0 +1 @@ +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")});function PMA_adjustTotals(){var a=new Array(PMA_messages.strB,PMA_messages.strKiB,PMA_messages.strMiB,PMA_messages.strGiB,PMA_messages.strTiB,PMA_messages.strPiB,PMA_messages.strEiB);var g=$("#tablesForm table.data tbody:first tr");var h=g.size();var d=0;var c=0;var f=0;var l=false;g.each(function(){var u=$(this);var r=u.find(".tbl_rows").text();if(r.indexOf("~")==0){l=true;r=r.substring(1,r.length-1)}r=r.replace(/[,.]/g,"");var p=parseInt(r,10);if(!isNaN(p)){d+=p}var w=0;var n=0;var s=$.trim(u.find(".tbl_size span:not(.unit)").text());var v=$.trim(u.find(".tbl_size span.unit").text());var t=$.trim(u.find(".tbl_overhead span:not(.unit)").text());var q=$.trim(u.find(".tbl_overhead span.unit").text());for(var o=0;o=1024){c/=1024;e++}while(f>=1024){f/=1024;i++}c=Math.round(c*10)/10;f=Math.round(f*10)/10;var b=$("#tbl_summary_row");b.find(".tbl_num").text($.sprintf(PMA_messages.strTables,h));b.find(".tbl_rows").text(k);b.find(".tbl_size").text(c+" "+a[e]);b.find(".tbl_overhead").text(f+" "+a[i])}AJAX.registerOnload("db_structure.js",function(){$("#tablesForm").submit(function(b){var a=$(this);if(a.find("select[name=submit_mult]").val()==="print"){b.preventDefault();b.stopPropagation();$("form#clone").remove();var c=a.clone().hide().appendTo("body");c.find("select[name=submit_mult]").val("print");c.attr("target","printview").attr("id","clone").submit()}});$("span.fkc_switch").click(function(a){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)});$("a.truncate_table_anchor.ajax").live("click",function(c){c.preventDefault();var b=$(this);var d=b.parents("tr").children("th").children("a").text();var a=PMA_messages.strTruncateTableStrongWarning+" "+$.sprintf(PMA_messages.strDoYouReally,"TRUNCATE "+escapeHtml(d));b.PMA_confirm(a,b.attr("href"),function(e){PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);$.get(e,{is_js_confirmed:1,ajax_request:true},function(h){if(h.success==true){PMA_ajaxShowMessage(h.message);var g=b.closest("tr");g.find(".tbl_rows").text("0");g.find(".tbl_size, .tbl_overhead").text("-");var f=b.html().replace(/b_empty/,"bd_empty");b.replaceWith(f).removeClass("truncate_table_anchor");PMA_adjustTotals()}else{PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest+" : "+h.error,false)}})})});$("a.drop_table_anchor.ajax").live("click",function(e){e.preventDefault();var d=$(this);var b=d.parents("tr");var f=b.children("th").children("a").text();var c=b.hasClass("is_view")||d.hasClass("view");var a;if(!c){a=PMA_messages.strDropTableStrongWarning+" "+$.sprintf(PMA_messages.strDoYouReally,"DROP TABLE "+escapeHtml(f))}else{a=$.sprintf(PMA_messages.strDoYouReally,"DROP VIEW "+escapeHtml(f))}d.PMA_confirm(a,d.attr("href"),function(h){var g=PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);$.get(h,{is_js_confirmed:1,ajax_request:true},function(i){if(i.success==true){PMA_ajaxShowMessage(i.message);toggleRowColors(b.next());b.hide("medium").remove();PMA_adjustTotals();PMA_reloadNavigation();PMA_ajaxRemoveMessage(g)}else{PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest+" : "+i.error,false)}})})});$("a.drop_tracking_anchor.ajax").live("click",function(c){c.preventDefault();var b=$(this);var d=b.parents("tr");var a=PMA_messages.strDeleteTrackingData;b.PMA_confirm(a,b.attr("href"),function(e){PMA_ajaxShowMessage(PMA_messages.strDeletingTrackingData);$.get(e,{is_js_confirmed:1,ajax_request:true},function(j){if(j.success==true){var i=d.parents("table");var f=d.find("td:nth-child(2)").text();if(i.find("tbody tr").length===1){$("#tracked_tables").hide("slow").remove()}else{toggleRowColors(d.next());d.hide("slow",function(){$(this).remove()})}var h=$("table#noversions");if(h.length>0){var g=h.find("tbody tr");g.each(function(m){var k=$(this);var p=k.find("td:first-child").text();var n=(m==(g.length-1));if(p>f||n){var l=k.clone();l.find("td:first-child").text(f);var o=l.find("td:nth-child(2) a").attr("href").replace("table="+p,"table="+encodeURIComponent(f));l.find("td:nth-child(2) a").attr("href",o);if(p>f){l.insertBefore(k);toggleRowColors(k);return false}else{l.insertAfter(k);toggleRowColors(l)}}})}PMA_ajaxShowMessage(j.message)}else{PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest+" : "+j.error,false)}})})});$("#real_end_input").live("click",function(b){b.preventDefault();var a=PMA_messages.strOperationTakesLongTime;$(this).PMA_confirm(a,"",function(){return true});return false})}); \ No newline at end of file diff --git a/phpmyadmin/js/export.js b/phpmyadmin/js/export.js new file mode 100644 index 000000000..d2bece333 --- /dev/null +++ b/phpmyadmin/js/export.js @@ -0,0 +1 @@ +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(){$("#plugins").change(function(){$("#format_specific_opts div.format_specific_options").hide();var a=$("#plugins option:selected").val();$("#"+a+"_options").show()});$("input[type='radio'][name='sql_structure_or_data']").change(function(){var b=$("#checkbox_sql_include_comments").prop("checked");var a=$("input[type='radio'][name='sql_structure_or_data']:checked").val();if(a=="data"){if(b){$("#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{if(b){$("#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)}})});function toggle_structure_data_opts(e){var d=e+"_structure_or_data";var b="#"+e+"_data";var c="#"+e+"_structure";var a=$("input[type='radio'][name='"+d+"']:checked").val();if(a=="data"){$(b).slideDown("slow");$(c).slideUp("slow")}else{$(c).slideDown("slow");if(a=="structure"){$(b).slideUp("slow")}else{$(b).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")})});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)});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($("#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(){var b=$("#checkbox_sql_create_table_statements");var a=$("#ul_create_table_statements input");b.change(function(){a.prop("checked",$(this).prop("checked"))});a.change(function(){if(a.is(":checked")){b.prop("checked",true)}});$("#plugins").change(function(){var d=$("#plugins option:selected").val();var c=$("#force_file_"+d).val();if(c=="true"){$("#radio_view_as_text").prop("disabled",true).parent().fadeTo("fast",0.4)}else{$("#radio_view_as_text").removeProp("disabled").parent().fadeTo("fast",1)}})});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 a=$("#plugins option:selected").val();$("#"+a+"_options").show()}else{$("#databases_and_tables").hide();$("#rows").hide();$("#output").hide();$("#format_specific_opts").hide();$("#output_quick_export").show()}}AJAX.registerOnload("export.js",function(){$("input[type='radio'][name='quick_or_custom']").change(toggle_quick_or_custom);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();disable_dump_some_rows_sub_options();$("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()}})});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")}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","")}; \ No newline at end of file diff --git a/phpmyadmin/js/functions.js b/phpmyadmin/js/functions.js new file mode 100644 index 000000000..aa663d471 --- /dev/null +++ b/phpmyadmin/js/functions.js @@ -0,0 +1 @@ +var $table_clone=false;var sql_box_locked=false;var only_once_elements=[];var ajax_message_count=0;var codemirror_editor=false;var codemirror_inline_editor=false;var chart_activeTimeouts={};$.ajaxPrefilter(function(a,d,c){var b=new Date().getTime()+""+Math.floor(Math.random()*1000000);if(typeof a.data=="string"){a.data+="&_nocache="+b}else{if(typeof a.data=="object"){a.data=$.extend(d.data,{_nocache:b})}}});function PMA_prepareForAjaxRequest(a){if(!a.find("input:hidden").is("#ajax_request_hidden")){a.append('')}}function suggestPassword(a){var d="abcdefhjmnpqrstuvwxyz23456789ABCDEFGHJKLMNPQRSTUVWYXZ";var e=16;var b=a.generated_pw;b.value="";for(var c=0;c=2){if(f[1].substr(0,2)=="rc"){g=-20-parseInt(f[1].substr(2))}else{if(f[1].substr(0,4)=="beta"){g=-40-parseInt(f[1].substr(4))}else{if(f[1].substr(0,5)=="alpha"){g=-60-parseInt(f[1].substr(5))}else{if(f[1].substr(0,3)=="dev"){g=0}}}}}var a=h.split(".");var c=parseInt(a[0])||0;var d=parseInt(a[1])||0;var b=parseInt(a[2])||0;var e=parseInt(a[3])||0;return c*100000000+d*1000000+b*10000+e*100+g}function PMA_current_version(d){if(d&&d.version&&d.date){var e=parseVersionString(pmaversion);var b=parseVersionString(d.version);var f=PMA_messages.strLatestAvailable+" "+escapeHtml(d.version);if(b>e){var c=$.sprintf(PMA_messages.strNewerVersion,escapeHtml(d.version),escapeHtml(d.date));if(Math.floor(b/10000)===Math.floor(e/10000)){var a="error"}else{var a="notice"}$("#maincontainer").after('
      '+c+"
      ")}if(b===e){f=" ("+PMA_messages.strUpToDate+")"}$("#li_pma_version").append(f)}}function PMA_display_git_revision(){$("#is_git_revision").remove();$.get("index.php",{server:PMA_commonParams.get("server"),token:PMA_commonParams.get("token"),git_revision:true,ajax_request:true},function(a){if(a.success==true){$(a.message).insertAfter("#li_pma_version")}})}function displayPasswordGenerateButton(){$("#tr_element_before_generate_password").parent().append(''+PMA_messages.strGeneratePassword+'');$("#div_element_before_generate_password").parent().append('
      ')}function PMA_addDatepicker(d,b){var c=false;if(d.is(".datetimefield")){c=true}var a={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(e,f){d.data("comes_from","datepicker");setTimeout(function(){$("#ui-timepicker-div").css("z-index",$("#ui-datepicker-div").css("z-index"))},0)},onClose:function(f,e){d.data("comes_from","")}};if(c||(typeof(b)!="undefined"&&b.showTimepicker)){d.datetimepicker($.extend(a,b))}else{d.datepicker($.extend(a,b))}}function selectContent(b,a,c){if(c&&only_once_elements[b.name]){return}only_once_elements[b.name]=true;if(a){return}b.select()}function confirmLink(d,b){if(PMA_messages.strDoYouReally==""||typeof(window.opera)!="undefined"){return true}var a=confirm($.sprintf(PMA_messages.strDoYouReally,b));if(a){if($(d).hasClass("formLinkSubmit")){var c="is_js_confirmed";if($(d).attr("href").indexOf("usesubform")!=-1){c="subform["+$(d).attr("href").substr("#").match(/usesubform\[(\d+)\]/i)[1]+"][is_js_confirmed]"}$(d).parents("form").append('')}else{if(typeof(d.href)!="undefined"){d.href+="&is_js_confirmed=1"}else{if(typeof(d.form)!="undefined"){d.form.action+="?is_js_confirmed=1"}}}}return a}function confirmQuery(d,e){if(PMA_messages.strDoYouReally==""){return true}if(PMA_messages.strNoDropDatabases!=""){var f=new RegExp("(^|;)\\s*DROP\\s+(IF EXISTS\\s+)?DATABASE\\s","i");if(f.test(e.value)){alert(PMA_messages.strNoDropDatabases);d.reset();e.focus();return false}}var b=new RegExp("^\\s*DROP\\s+(IF EXISTS\\s+)?(TABLE|DATABASE|PROCEDURE)\\s","i");var a=new RegExp("^\\s*ALTER\\s+TABLE\\s+((`[^`]+`)|([A-Za-z0-9_$]+))\\s+DROP\\s","i");var h=new RegExp("^\\s*DELETE\\s+FROM\\s","i");var g=new RegExp("^\\s*TRUNCATE\\s","i");if(b.test(e.value)||a.test(e.value)||h.test(e.value)||g.test(e.value)){var i=(e.value.length>100)?e.value.substr(0,100)+"\n ...":e.value;var c=confirm($.sprintf(PMA_messages.strDoYouReally,i));if(c){d.elements.is_js_confirmed.value=1;return true}else{window.focus();e.focus();return false}}return true}function checkSqlQuery(d){if(codemirror_editor){d.elements.sql_query.value=codemirror_editor.getValue()}var b=d.elements.sql_query;var c=1;var a=new RegExp("\\s+");if(typeof(d.elements.sql_file)!="undefined"&&d.elements.sql_file.value.replace(a,"")!=""){return true}if(typeof(d.elements.sql_localfile)!="undefined"&&d.elements.sql_localfile.value.replace(a,"")!=""){return true}if(c&&typeof(d.elements.id_bookmark)!="undefined"&&(d.elements.id_bookmark.value!=null||d.elements.id_bookmark.value!="")&&d.elements.id_bookmark.selectedIndex!=0){return true}if(b.value.replace(a,"")!=""){if(confirmQuery(d,b)){return true}else{return false}}d.reset();c=1;if(c){b.select();alert(PMA_messages.strFormEmpty);b.focus();return false}return true}function emptyCheckTheField(d,b){var a=d.elements[b];var c=new RegExp("\\s+");return(a.value.replace(c,"")=="")?1:0}function emptyFormElements(d,b){var a=d.elements[b];var c=emptyCheckTheField(d,b);return c}function checkFormElementInRange(g,d,e,c,b){var a=g.elements[d];var f=parseInt(a.value);if(typeof(c)=="undefined"){c=0}if(typeof(b)=="undefined"){b=Number.MAX_VALUE}if(isNaN(f)){a.select();alert(PMA_messages.strNotNumber);a.focus();return false}else{if(fb){a.select();alert($.sprintf(e,f));a.focus();return false}else{a.value=f}}return true}function checkTableEditForm(g,j){var f=0;var e,h,a,k,d,c;for(e=0;e=0){if(last_shift_clicked_row>=last_clicked_row){h=last_clicked_row;a=last_shift_clicked_row}else{h=last_shift_clicked_row;a=last_clicked_row}d.parent().find("tr.odd:not(.noclick), tr.even:not(.noclick)").slice(h,a+1).removeClass("marked").find(":checkbox").prop("checked",false).trigger("change")}var f=$("tr.odd:not(.noclick), tr.even:not(.noclick)").index(d);if(f>=last_clicked_row){h=last_clicked_row;a=f}else{h=f;a=last_clicked_row}d.parent().find("tr.odd:not(.noclick), tr.even:not(.noclick)").slice(h,a+1).addClass("marked").find(":checkbox").prop("checked",true).trigger("change");last_shift_clicked_row=f}});addDateTimePicker();if(navigator.userAgent.match(/(iphone|ipod|ipad)/i)){$("input[type=text]").attr("autocapitalize","off").attr("autocorrect","off")}});var last_click_checked=false;var last_clicked_row=-1;var last_shift_clicked_row=-1;var marked_row=[];function markAllRows(a){$("#"+a).find("input:checkbox:enabled").prop("checked",true).trigger("change").parents("tr").addClass("marked");return true}function unMarkAllRows(a){$("#"+a).find("input:checkbox:enabled").prop("checked",false).trigger("change").parents("tr").removeClass("marked");return true}function setCheckboxes(b,a){$("#"+b).find("input:checkbox").prop("checked",a);return true}function setSelectOptions(b,a,c){$("form[name='"+b+"'] select[name='"+a+"']").find("option").prop("selected",c);return true}function setQuery(a){if(codemirror_editor){codemirror_editor.setValue(a);codemirror_editor.focus()}else{document.sqlform.sql_query.value=a;document.sqlform.sql_query.focus()}}function insertQuery(c){if(c=="clear"){setQuery("");return}var f="";var a=document.sqlform.dummy;var h=document.sqlform.table.value;if(a.options.length>0){sql_box_locked=true;var b="";var g="";var e="";var j=0;for(var d=0;d1){b+=", ";g+=",";e+=","}b+=a.options[d].value;g+="[value-"+j+"]";e+=a.options[d].value+"=[value-"+j+"]"}if(c=="selectall"){f="SELECT * FROM `"+h+"` WHERE 1"}else{if(c=="select"){f="SELECT "+b+" FROM `"+h+"` WHERE 1"}else{if(c=="insert"){f="INSERT INTO `"+h+"`("+b+") VALUES ("+g+")"}else{if(c=="update"){f="UPDATE `"+h+"` SET "+e+" WHERE 1"}else{if(c=="delete"){f="DELETE FROM `"+h+"` WHERE 1"}}}}}setQuery(f);sql_box_locked=false}}function insertValueQuery(){var h=document.sqlform.sql_query;var d=document.sqlform.dummy;if(d.options.length>0){sql_box_locked=true;var e="";var j=0;for(var f=0;f1){e+=", "}e+=d.options[f].value}}if(codemirror_editor){codemirror_editor.replaceSelection(e)}else{if(document.selection){h.focus();var c=document.selection.createRange();c.text=e;document.sqlform.insert.focus()}else{if(document.sqlform.sql_query.selectionStart||document.sqlform.sql_query.selectionStart=="0"){var g=document.sqlform.sql_query.selectionStart;var b=document.sqlform.sql_query.selectionEnd;var a=document.sqlform.sql_query.value;h.value=a.substring(0,g)+e+a.substring(b,a.length)}else{h.value+=e}}}sql_box_locked=false}}function addDateTimePicker(){if($.timepicker!=undefined){$("input.datefield, input.datetimefield").each(function(){PMA_addDatepicker($(this))})}}function refreshLayout(){var c=$("#pdflayout");var d=$("#orientation_opt").val();if($("#paper_opt").length==1){var e=$("#paper_opt").val()}else{var e="A4"}if(d=="P"){var b="x";var a="y"}else{var b="y";var a="x"}c.css("width",pdfPaperSize(e,b)+"px");c.css("height",pdfPaperSize(e,a)+"px")}function TableDragInit(){$(".pdflayout_table").each(function(){var c=$(this);var b=c.data("number");var a=$("#c_table_"+b+"_x").val();var d=$("#c_table_"+b+"_y").val();c.css("left",a+"px");c.css("top",d+"px");c.draggable({containment:"parent",drag:function(e,g){var f=c.data("number");$("#c_table_"+f+"_x").val(parseInt(g.position.left));$("#c_table_"+f+"_y").val(parseInt(g.position.top))}})})}function resetDrag(){$(".pdflayout_table").each(function(){var b=$(this);var a=b.data("x");var c=b.data("y");b.css("left",a+"px");b.css("top",c+"px")})}$(function(){$(".position-change").live("change",function(){var b=$(this);var a=$("#table_"+b.data("number"));a.css(b.data("axis"),b.val()+"px")});$(".paper-change").live("change",function(){var a=$("#pdflayout");if(a.css("visibility")=="visible"){refreshLayout();TableDragInit()}});$("#toggle-dragdrop").live("click",function(){var a=$("#pdflayout");if(a.css("visibility")=="hidden"){refreshLayout();TableDragInit();a.css("visibility","visible");a.css("display","block");$("#showwysiwyg").val("1")}else{a.css("visibility","hidden");a.css("display","none");$("#showwysiwyg").val("0")}});$("#reset-dragdrop").live("click",function(){resetDrag()})});function pdfPaperSize(b,a){switch(b.toUpperCase()){case"4A0":if(a=="x"){return 4767.87}else{return 6740.79}break;case"2A0":if(a=="x"){return 3370.39}else{return 4767.87}break;case"A0":if(a=="x"){return 2383.94}else{return 3370.39}break;case"A1":if(a=="x"){return 1683.78}else{return 2383.94}break;case"A2":if(a=="x"){return 1190.55}else{return 1683.78}break;case"A3":if(a=="x"){return 841.89}else{return 1190.55}break;case"A4":if(a=="x"){return 595.28}else{return 841.89}break;case"A5":if(a=="x"){return 419.53}else{return 595.28}break;case"A6":if(a=="x"){return 297.64}else{return 419.53}break;case"A7":if(a=="x"){return 209.76}else{return 297.64}break;case"A8":if(a=="x"){return 147.4}else{return 209.76}break;case"A9":if(a=="x"){return 104.88}else{return 147.4}break;case"A10":if(a=="x"){return 73.7}else{return 104.88}break;case"B0":if(a=="x"){return 2834.65}else{return 4008.19}break;case"B1":if(a=="x"){return 2004.09}else{return 2834.65}break;case"B2":if(a=="x"){return 1417.32}else{return 2004.09}break;case"B3":if(a=="x"){return 1000.63}else{return 1417.32}break;case"B4":if(a=="x"){return 708.66}else{return 1000.63}break;case"B5":if(a=="x"){return 498.9}else{return 708.66}break;case"B6":if(a=="x"){return 354.33}else{return 498.9}break;case"B7":if(a=="x"){return 249.45}else{return 354.33}break;case"B8":if(a=="x"){return 175.75}else{return 249.45}break;case"B9":if(a=="x"){return 124.72}else{return 175.75}break;case"B10":if(a=="x"){return 87.87}else{return 124.72}break;case"C0":if(a=="x"){return 2599.37}else{return 3676.54}break;case"C1":if(a=="x"){return 1836.85}else{return 2599.37}break;case"C2":if(a=="x"){return 1298.27}else{return 1836.85}break;case"C3":if(a=="x"){return 918.43}else{return 1298.27}break;case"C4":if(a=="x"){return 649.13}else{return 918.43}break;case"C5":if(a=="x"){return 459.21}else{return 649.13}break;case"C6":if(a=="x"){return 323.15}else{return 459.21}break;case"C7":if(a=="x"){return 229.61}else{return 323.15}break;case"C8":if(a=="x"){return 161.57}else{return 229.61}break;case"C9":if(a=="x"){return 113.39}else{return 161.57}break;case"C10":if(a=="x"){return 79.37}else{return 113.39}break;case"RA0":if(a=="x"){return 2437.8}else{return 3458.27}break;case"RA1":if(a=="x"){return 1729.13}else{return 2437.8}break;case"RA2":if(a=="x"){return 1218.9}else{return 1729.13}break;case"RA3":if(a=="x"){return 864.57}else{return 1218.9}break;case"RA4":if(a=="x"){return 609.45}else{return 864.57}break;case"SRA0":if(a=="x"){return 2551.18}else{return 3628.35}break;case"SRA1":if(a=="x"){return 1814.17}else{return 2551.18}break;case"SRA2":if(a=="x"){return 1275.59}else{return 1814.17}break;case"SRA3":if(a=="x"){return 907.09}else{return 1275.59}break;case"SRA4":if(a=="x"){return 637.8}else{return 907.09}break;case"LETTER":if(a=="x"){return 612}else{return 792}break;case"LEGAL":if(a=="x"){return 612}else{return 1008}break;case"EXECUTIVE":if(a=="x"){return 521.86}else{return 756}break;case"FOLIO":if(a=="x"){return 612}else{return 936}break}return 0}AJAX.registerTeardown("functions.js",function(){$("a.inline_edit_sql").die("click");$("input#sql_query_edit_save").die("click");$("input#sql_query_edit_discard").die("click");$("input.sqlbutton").unbind("click");$("#export_type").unbind("change");$("#sqlquery").unbind("keydown");$("#sql_query_edit").unbind("keydown");if(codemirror_inline_editor){$("#sql_query_edit").text(codemirror_inline_editor.getValue());$(codemirror_inline_editor.getWrapperElement()).unbind("keydown");codemirror_inline_editor.toTextArea();codemirror_inline_editor=false}if(codemirror_editor){$(codemirror_editor.getWrapperElement()).unbind("keydown")}});AJAX.registerOnload("functions.js",function(){bindCodeMirrorToInlineEditor();$("a.inline_edit_sql").live("click",function(){if($("#sql_query_edit").length){return false}var a=$(this).prev("form");var f=a.find("input[name='sql_query']").val();var e=$(this).parent().prev().find(".inner_sql");var d=e.html();var c='\n";c+='\n';c+='\n';var b=$("div#inline_editor");if(b.length==0){b=$('
      ');b.insertBefore(e)}b.html(c);e.hide();bindCodeMirrorToInlineEditor();return false});$("input#sql_query_edit_save").live("click",function(){if(codemirror_inline_editor){var b=codemirror_inline_editor.getValue()}else{var b=$(this).prev().val()}var a=$("a.inline_edit_sql").prev("form");var c=$("
      ",{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:b}));c.appendTo($("body")).submit()});$("input#sql_query_edit_discard").live("click",function(){$("div#inline_editor_outer").empty().siblings(".inner_sql").show()});$("input.sqlbutton").click(function(a){insertQuery(a.target.id);return false});$("#export_type").change(function(){if($("#export_type").val()=="svg"){$("#show_grid_opt").prop("disabled",true);$("#orientation_opt").prop("disabled",true);$("#with_doc").prop("disabled",true);$("#show_table_dim_opt").removeProp("disabled");$("#all_tables_same_width").removeProp("disabled");$("#paper_opt").removeProp("disabled");$("#show_color_opt").removeProp("disabled")}else{if($("#export_type").val()=="dia"){$("#show_grid_opt").prop("disabled",true);$("#with_doc").prop("disabled",true);$("#show_table_dim_opt").prop("disabled",true);$("#all_tables_same_width").prop("disabled",true);$("#paper_opt").removeProp("disabled");$("#show_color_opt").removeProp("disabled");$("#orientation_opt").removeProp("disabled")}else{if($("#export_type").val()=="eps"){$("#show_grid_opt").prop("disabled",true);$("#orientation_opt").removeProp("disabled");$("#with_doc").prop("disabled",true);$("#show_table_dim_opt").prop("disabled",true);$("#all_tables_same_width").prop("disabled",true);$("#paper_opt").prop("disabled",true);$("#show_color_opt").prop("disabled",true)}else{if($("#export_type").val()=="pdf"){$("#show_grid_opt").removeProp("disabled");$("#orientation_opt").removeProp("disabled");$("#with_doc").removeProp("disabled");$("#show_table_dim_opt").removeProp("disabled");$("#all_tables_same_width").removeProp("disabled");$("#paper_opt").removeProp("disabled");$("#show_color_opt").removeProp("disabled")}else{}}}}});if($("#input_username")){if($("#input_username").val()==""){$("#input_username").focus()}else{$("#input_password").focus()}}});function bindCodeMirrorToInlineEditor(){var b=$("#sql_query_edit");if(b.length>0){if(typeof CodeMirror!=="undefined"){var a=$("#sql_query_edit").css("height");codemirror_inline_editor=CodeMirror.fromTextArea(b[0],{lineNumbers:true,matchBrackets:true,indentUnit:4,mode:"text/x-mysql",lineWrapping:true});codemirror_inline_editor.getScrollerElement().style.height=a;codemirror_inline_editor.refresh();codemirror_inline_editor.focus();$(codemirror_inline_editor.getWrapperElement()).bind("keydown",catchKeypressesFromSqlTextboxes)}else{b.focus().bind("keydown",catchKeypressesFromSqlTextboxes)}}}function catchKeypressesFromSqlTextboxes(a){if(a.ctrlKey&&(a.keyCode==13||a.keyCode==10)){if($("#sql_query_edit").length>0){$("#sql_query_edit_save").trigger("click")}else{if($("#sqlquery").length>0){$("#button_submit_query").trigger("click")}}}}function PMA_ajaxShowMessage(c,d){var b=true;var e=true;if(c==""){return true}else{if(!c){c=PMA_messages.strLoading;e=false;b=false}else{if(c==PMA_messages.strProcessingRequest){e=false;b=false}}}if(d==undefined){d=5000}else{if(d===false){b=false}}if($("#loading_parent").length==0){$('
      ').prependTo("body")}ajax_message_count++;$("span.ajax_notification[id^=ajax_message_num]").remove();var a=$('').hide().appendTo("#loading_parent").html(c).show();if(b){a.delay(d).fadeOut("medium",function(){if($(this).is(".dismissable")){$(this).tooltip("destroy")}$(this).remove()})}if(e){a.addClass("dismissable").css("cursor","pointer");PMA_tooltip(a,"span",PMA_messages.strDismiss)}return a}function PMA_ajaxRemoveMessage(a){if(a!=undefined&&a instanceof jQuery){a.stop(true,true).fadeOut("medium");if(a.is(".dismissable")){if($.isFunction(a.tooltip)){a.tooltip("destroy")}}else{a.remove()}}}$(function(){$("span.ajax_notification.dismissable").live("click",function(){PMA_ajaxRemoveMessage($(this))});$("span.ajax_notification a, span.ajax_notification button, span.ajax_notification input").live("mouseover",function(){$(this).parents("span.ajax_notification").tooltip("disable")}).live("mouseout",function(){$(this).parents("span.ajax_notification").tooltip("enable")})});function PMA_showNoticeForEnum(a){var b=a.attr("id").split("_")[1];b+="_"+(parseInt(a.attr("id").split("_")[2])+1);var c=a.val();if(c=="ENUM"||c=="SET"){$("p#enum_notice_"+b).show()}else{$("p#enum_notice_"+b).hide()}}function PMA_createProfilingChartJqplot(b,a){return $.jqplot(b,[a],{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){if(!b){b=2}b=Math.pow(10,b);if(a*1000<0.1){a=Math.round(b*(a*1000*1000))/b+"µ"}else{if(a<0.1){a=Math.round(b*(a*1000))/b+"m"}else{a=Math.round(b*a)/b}}return a+"s"}function PMA_SQLPrettyPrint(a){if(typeof CodeMirror=="undefined"){return a}var l=CodeMirror.getMode({},"text/x-mysql");var e=new CodeMirror.StringStream(a);var d=l.startState();var g,m=[];var h="";var t=function(y){var w="";for(var x=0;x<4*y;x++){w+=" "}return w};var u={select:["select","from","on","where","having","limit","order by","group by"],update:["update","set","where"],"insert into":["insert into","values"]};var k={";":true,",":true,".":true,"(":true};var n={".":true};var o="";while(!e.eol()){e.start=e.pos;g=l.token(e,d);if(g!=null){m.push([g,e.current().toLowerCase()])}}var q=m[0][1];if(!u[q]){return a}var s=[];var f;var b,c;var p=0;var j,v=u[q][0];s.unshift("statement");for(var r=0;r0&&m[r-1][0]=="builtin"){s.unshift(b="function")}else{s.unshift(b="generic")}}}else{b=null}if(m[r][1]==")"){c=s[0];s.shift()}else{c=null}if(r>0&&b=="statement"){p++;h+="\n"+t(p)+m[r][1]+" "+m[r+1][1].toUpperCase()+"\n"+t(p+1);q=m[r+1][1];r++;continue}if(c=="statement"&&p>0){h+="\n"+t(p);p--}j=u[q].indexOf(m[r][1]);if(j!=-1){if(r>0){h+="\n"}h+=t(p)+m[r][1].toUpperCase();h+="\n"+t(p+1);v=m[r][1]}else{if(!k[m[r][1]]&&!(r>0&&n[m[r-1][1]])&&h.charAt(h.length-1)!=" "){h+=" "}if(m[r][0]=="keyword"){h+=m[r][1].toUpperCase()}else{h+=m[r][1]}}if((v=="select"||v=="where"||v=="set")&&m[r][1]==","&&s[0]=="statement"){h+="\n"+t(p+1)}if(v=="where"&&(m[r][1]=="and"||m[r][1]=="or"||m[r][1]=="xor")){if(s[0]=="statement"){h+="\n"+t(p+1)}}}return h}jQuery.fn.PMA_confirm=function(b,d,a){var e=PMA_commonParams.get("confirm");if(e===""||e==="1"){if($.isFunction(a)){a.call(this,d);return true}}if(PMA_messages.strDoYouReally==""){return true}var c={};c[PMA_messages.strOK]=function(){$(this).dialog("close");if($.isFunction(a)){a.call(this,d)}};c[PMA_messages.strCancel]=function(){$(this).dialog("close")};$("
      ",{id:"confirm_dialog"}).prepend(b).dialog({buttons:c,close:function(){$(this).remove()},modal:true})};jQuery.fn.PMA_sort_table=function(a){return this.each(function(){var c=$(this);var b=$(this).find("tr").get();$.each(b,function(d,e){e.sortKey=$.trim($(e).find(a).text().toLowerCase())});b.sort(function(e,d){if(e.sortKeyd.sortKey){return 1}return 0});$.each(b,function(d,e){$(c).append(e);e.sortKey=null});$(this).find("tr:odd").removeClass("even").addClass("odd").end().find("tr:even").removeClass("odd").addClass("even")})};AJAX.registerTeardown("functions.js",function(){$("#create_table_form_minimal.ajax").die("submit");$("form.create_table_form.ajax").die("submit");$("form.create_table_form.ajax input[name=submit_num_fields]").die("click");$("form.create_table_form.ajax input").die("keyup")});AJAX.registerOnload("functions.js",function(){$("form.create_table_form.ajax").live("submit",function(b){b.preventDefault();var a=$(this);if(checkTableEditForm(a[0],a.find("input[name=orig_num_fields]").val())){PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);PMA_prepareForAjaxRequest(a);$.post(a.attr("action"),a.serialize()+"&do_save_data=1",function(i){if(i.success==true){$("#properties_message").removeClass("error").html("");PMA_ajaxShowMessage(i.message);if($("#create_table_dialog").length>0){$("#create_table_dialog").dialog("close").remove()}$("#tableslistcontainer").before(i.formatted_sql);var f=$("#tablesForm").find("tbody").not("#tbl_summary_row");if(f.length==0){PMA_commonActions.refreshMain(PMA_commonParams.get("opendb_url"))}else{var h=$(f).find("tr:last");var g=$(h).find("input:checkbox").attr("id").match(/\d+/)[0];var d=parseFloat(g);var c=d+1;var e="checkbox_tbl_"+c;i.new_table_string=i.new_table_string.replace(/checkbox_tbl_/,e);$(i.new_table_string).appendTo(f);$(f).PMA_sort_table("th");PMA_adjustTotals()}PMA_reloadNavigation()}else{PMA_ajaxShowMessage('
      '+i.error+"
      ",false)}})}});$("form.create_table_form.ajax input[name=submit_num_fields]").live("click",function(b){b.preventDefault();var a=$(this).closest("form");var c=PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);PMA_prepareForAjaxRequest(a);$.post(a.attr("action"),a.serialize()+"&submit_num_fields=1",function(d){if(d.success){$("#page_content").html(d.message);PMA_verifyColumnsProperties();PMA_ajaxRemoveMessage(c)}else{PMA_ajaxShowMessage(d.error)}})});$("form.create_table_form.ajax input").live("keydown",function(a){if(a.keyCode==13){a.preventDefault();a.stopImmediatePropagation();$(this).closest("form").append('').submit()}})});AJAX.registerTeardown("functions.js",function(){$("#copyTable.ajax").die("submit");$("#moveTableForm").die("submit");$("#tableOptionsForm").die("submit");$("#tbl_maintenance li a.maintain_action.ajax").die("click")});AJAX.registerOnload("functions.js",function(){$("#copyTable.ajax").live("submit",function(b){b.preventDefault();var a=$(this);PMA_prepareForAjaxRequest(a);$.post(a.attr("action"),a.serialize()+"&submit_copy=Go",function(c){if(c.success==true){if(a.find("input[name='switch_to_new']").prop("checked")){PMA_commonParams.set("db",c.db);PMA_commonParams.set("table",a.find("input[name='new_name']").val());PMA_commonActions.refreshMain(false,function(){PMA_ajaxShowMessage(c.message)})}else{PMA_ajaxShowMessage(c.message)}PMA_reloadNavigation()}else{PMA_ajaxShowMessage(c.error,false)}})});$("#moveTableForm").live("submit",function(c){c.preventDefault();var b=$(this);var a=b.find("select[name=target_db]").val();var d=b.find("input[name=new_name]").val();PMA_prepareForAjaxRequest(b);$.post(b.attr("action"),b.serialize()+"&submit_move=1",function(e){if(e.success==true){PMA_commonParams.set("db",a);PMA_commonParams.set("table",d);PMA_commonActions.refreshMain(false,function(){PMA_ajaxShowMessage(e.message)});PMA_reloadNavigation()}else{PMA_ajaxShowMessage(e.error,false)}})});$("#tableOptionsForm").live("submit",function(c){c.preventDefault();c.stopPropagation();var b=$(this);var a=b.find("input[name=new_name]");if(a.val()!==a[0].defaultValue){PMA_prepareForAjaxRequest(b);var d=a.val();$.post(b.attr("action"),b.serialize(),function(e){if(e.success==true){PMA_commonParams.set("table",d);PMA_commonActions.refreshMain(false,function(){$("#page_content").html(e.message)})}else{PMA_ajaxShowMessage(e.error,false)}})}else{b.removeClass("ajax").submit().addClass("ajax")}});$("#tbl_maintenance li a.maintain_action.ajax").live("click",function(a){a.preventDefault();if($("#sqlqueryresults").length!=0){$("#sqlqueryresults").remove()}if($("#result_query").length!=0){$("#result_query").remove()}$.post($(this).attr("href"),{ajax_request:1},function(f){function d(){$("html, body").animate({scrollTop:0})}if(f.success==true&&f.sql_query!=undefined){PMA_ajaxShowMessage(f.message);$("
      ").prependTo("#page_content");$("#sqlqueryresults").html(f.sql_query);d()}else{if(f.success==true){var c=$("
      ");c.html(f.message);var e=c.find("#result_query .success");PMA_ajaxShowMessage(e);$("
      ").prependTo("#page_content");$("#sqlqueryresults").html(f.message);PMA_init_slider();$("#sqlqueryresults").children("fieldset,br").remove();d()}else{var c=$("
      ");c.html(f.error);var b=c.find("code").addClass("error");PMA_ajaxShowMessage(b,false)}}})})});AJAX.registerTeardown("functions.js",function(){$("#drop_db_anchor.ajax").die("click")});AJAX.registerOnload("functions.js",function(){$("#drop_db_anchor.ajax").live("click",function(b){b.preventDefault();var a=PMA_messages.strDropDatabaseStrongWarning+" ";a+=$.sprintf(PMA_messages.strDoYouReally,"DROP DATABASE "+escapeHtml(PMA_commonParams.get("db")));$(this).PMA_confirm(a,$(this).attr("href"),function(c){PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);$.get(c,{is_js_confirmed:"1",ajax_request:true},function(d){if(d.success){PMA_reloadNavigation();PMA_commonParams.set("db","");PMA_commonActions.refreshMain("server_databases.php",function(){PMA_ajaxShowMessage(d.message)})}else{PMA_ajaxShowMessage(d.error,false)}})})})});function PMA_checkPassword(e){if(e.find("#nopass_1").is(":checked")){return true}else{var d=e.find("#select_pred_password");if(d.length&&(d.val()=="none"||d.val()=="keep")){return true}}var a=e.find("input[name=pma_pw]");var c=e.find("input[name=pma_pw2]");var b=false;if(a.val()==""){b=PMA_messages.strPasswordEmpty}else{if(a.val()!=c.val()){b=PMA_messages.strPasswordNotSame}}if(b){alert(b);a.val("");c.val("");a.focus();return false}return true}AJAX.registerTeardown("functions.js",function(){$("#change_password_anchor.ajax").die("click")});AJAX.registerOnload("functions.js",function(){$("#change_password_anchor.ajax").live("click",function(b){b.preventDefault();var c=PMA_ajaxShowMessage();var a={};a[PMA_messages.strGo]=function(){b.preventDefault();var f=$("#change_password_form");if(!PMA_checkPassword(f)){return false}var d=$(this).val();var e=PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);f.append('');$.post(f.attr("action"),f.serialize()+"&change_pw="+d,function(g){if(g.success==true){$("#page_content").prepend(g.message);$("#change_password_dialog").hide().remove();$("#edit_user_dialog").dialog("close").remove();PMA_ajaxRemoveMessage(e)}else{PMA_ajaxShowMessage(g.error,false)}})};a[PMA_messages.strCancel]=function(){$(this).dialog("close")};$.get($(this).attr("href"),{ajax_request:true},function(d){if(d.success){$('
      ').dialog({title:PMA_messages.strChangePassword,width:600,close:function(e,f){$(this).remove()},buttons:a,modal:true}).append(d.message);$("fieldset#fieldset_change_password").find("legend").remove().end().find("table.noclick").unwrap().addClass("some-margin").find("input#text_pma_pw").focus();displayPasswordGenerateButton();$("#fieldset_change_password_footer").hide();PMA_ajaxRemoveMessage(c);$("#change_password_form").bind("submit",function(f){f.preventDefault();$(this).closest(".ui-dialog").find(".ui-dialog-buttonpane .ui-button").first().click()})}else{PMA_ajaxShowMessage(d.error,false)}})})});AJAX.registerTeardown("functions.js",function(){$("select.column_type").die("change");$("select.default_type").die("change");$("input.allow_null").die("change")});AJAX.registerOnload("functions.js",function(){PMA_verifyColumnsProperties();$("select.column_type").live("change",function(){PMA_showNoticeForEnum($(this))});$("select.default_type").live("change",function(){PMA_hideShowDefaultValue($(this))});$("input.allow_null").live("change",function(){PMA_validateDefaultValue($(this))})});function PMA_verifyColumnsProperties(){$("select.column_type").each(function(){PMA_showNoticeForEnum($(this))});$("select.default_type").each(function(){PMA_hideShowDefaultValue($(this))})}function PMA_hideShowDefaultValue(b){if(b.val()=="USER_DEFINED"){b.siblings(".default_value").show().focus()}else{b.siblings(".default_value").hide();if(b.val()=="NULL"){var a=b.closest("tr").find(".allow_null");a.prop("checked",true)}}}function PMA_validateDefaultValue(b){if(!b.prop("checked")){var a=b.closest("tr").find(".default_type");if(a.val()=="NULL"){a.val("NONE")}}}AJAX.registerTeardown("functions.js",function(){$("a.open_enum_editor").die("click");$("input.add_value").die("click");$("#enum_editor td.drop").die("click")});var $enum_editor_dialog=null;AJAX.registerOnload("functions.js",function(){$("a.open_enum_editor").live("click",function(){var e=$(this).closest("tr").find("input:first").val();if(e.length<1){var m=PMA_messages.enum_newColumnVals}else{var m=PMA_messages.enum_columnVals.replace(/%s/,'"'+decodeURIComponent(e)+'"')}var k=$(this).closest("td").find("input").val();k=$("
      ").text(k).html();var n=[];var j=false;var o,f,c="";for(var d=0;d0){n.push(c)}var g="";if(n.length==0){n.push("","","","")}var l=PMA_getImage("b_drop.png");for(var d=0;d"+l+""}var h="
      "+m+"

      "+PMA_getImage("s_notice.png")+PMA_messages.enum_hint+"

      "+g+"
      ";var b={};b[PMA_messages.strGo]=function(){var i=[];$(this).find(".values input").each(function(q,s){var r=s.value.replace(/\\/g,"\\\\").replace(/'/g,"''");i.push("'"+r+"'")});var p=$(this).find("input[type='hidden']").val();$("input#"+p).val(i.join(","));$(this).dialog("close")};b[PMA_messages.strClose]=function(){$(this).dialog("close")};var a=parseInt((parseInt($("html").css("font-size"),10)/13)*340,10);if(!a){a=340}$enum_editor_dialog=$(h).dialog({minWidth:a,modal:true,title:PMA_messages.enum_editor,buttons:b,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(i,p){$(this).closest("table").find("input[type=submit]").val($.sprintf(PMA_messages.enum_addValue,p.value))}});$("a.ui-slider-handle").addClass("ui-state-focus");return false});$("input.add_value").live("click",function(a){a.preventDefault();var b=$enum_editor_dialog.find("div.slider").slider("value");while(b--){$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()})})});function checkIndexName(b){if($("#"+b).length==0){return false}var a=$("#input_index_name");var c=$("#select_index_type");if(c.find("option:selected").val()=="PRIMARY"){a.val("PRIMARY");a.prop("disabled",true)}else{if(a.val()=="PRIMARY"){a.val("")}a.prop("disabled",false)}return true}AJAX.registerTeardown("functions.js",function(){$("#index_frm input[type=submit]").die("click")});AJAX.registerOnload("functions.js",function(){$("#index_frm input[type=submit]").live("click",function(a){a.preventDefault();var b=$(this).closest("fieldset").find(".slider").slider("value");while(b--){var c=$("#index_columns").find("tbody > tr:first").clone().appendTo($("#index_columns").find("tbody"));c.find(":input").each(function(){$(this).val("")});c.find("select").change(function(){if($(this).find("option:selected").val()==""){return true}$(this).closest("tr").find("input").focus()})}})});function indexEditorDialog(d,g,f,b){if($("#edit_index_dialog").length!=0){$("#edit_index_dialog").remove()}var a=$('
      ');var c={};c[PMA_messages.strGo]=function(){var h=$("#index_frm");PMA_prepareForAjaxRequest(h);$.post(h.attr("action"),h.serialize()+"&do_save_data=1",function(k){if($("#sqlqueryresults").length!=0){$("#sqlqueryresults").remove()}if(k.success==true){PMA_ajaxShowMessage(k.message);if($("#result_query").length){$("#result_query").remove()}if(k.sql_query){$('
      ').html(k.sql_query).prependTo("#page_content")}$("#result_query .notice").remove();$("#result_query").prepend(k.message);$("#table_index").remove();var j=$("
      ").append(k.index_table);j.find("#table_index").insertAfter("#index_header");if($("#edit_index_dialog").length>0){$("#edit_index_dialog").dialog("close")}$("div.no_indexes_defined").hide();if(f){f()}PMA_reloadNavigation()}else{var j=$("
      ").append(k.error);if(j.find(".error code").length!=0){var i=j.find(".error code").addClass("error")}else{var i=j}if(b){b()}PMA_ajaxShowMessage(i,false)}})};c[PMA_messages.strCancel]=function(){$(this).dialog("close")};var e=PMA_ajaxShowMessage();$.get("tbl_indexes.php",d,function(i){if(i.success==false){PMA_ajaxShowMessage(i.error,false)}else{PMA_ajaxRemoveMessage(e);a.append(i.message).dialog({title:g,width:450,open:PMA_verifyColumnsProperties,modal:true,buttons:c,close:function(){$(this).remove()}});checkIndexType();checkIndexName("index_frm");PMA_showHints(a);a.find(".slider").slider({animate:true,value:1,min:1,max:16,slide:function(j,k){$(this).closest("fieldset").find("input[type=submit]").val($.sprintf(PMA_messages.strAddToIndex,k.value))}});a.find("table#index_columns select").change(function(){if($(this).find("option:selected").val()==""){return true}$(this).closest("tr").find("input").focus()});$("a.ui-slider-handle").addClass("ui-state-focus");var h=a.find("input#input_index_name");h.val()||h.focus()}})}function PMA_showHints(a){if(a==undefined||!a instanceof jQuery||a.length==0){a=$("body")}a.find(".pma_hint").each(function(){PMA_tooltip($(this).children("img"),"img",$(this).children("span").html())})}AJAX.registerOnload("functions.js",function(){PMA_showHints()});function PMA_mainMenuResizerCallback(){return $(document.body).width()-5}$(function(){$("#topmenu").menuResizer(PMA_mainMenuResizerCallback);$(window).resize(function(){$("#topmenu").menuResizer("resize")})});function PMA_getRowNumber(a){return parseInt(a.split(/\s+row_/)[1])}function PMA_set_status_label(a){var b=a.css("display")=="none"?"+ ":"- ";a.closest(".slide-wrapper").prev().find("span").text(b)}var toggleButton=function($obj){if($("span.text_direction",$obj).text()=="ltr"){var right="right"}else{var right="left"}var h=$obj.height();$("img",$obj).height(h);$("table",$obj).css("bottom",h-1);var on=$("td.toggleOn",$obj).width();var off=$("td.toggleOff",$obj).width();$("td.toggleOn > div",$obj).width(Math.max(on,off)+2);$("td.toggleOff > div",$obj).width(Math.max(on,off)+2);var w=parseInt(($("img",$obj).height()/16)*22,10);$("table td:nth-child(2) > div",$obj).width(w);var imgw=$("img",$obj).width();var tblw=$("table",$obj).width();var offset=parseInt(((imgw-tblw)/2),10);$obj.find("img").css(right,offset);var offw=$("td.toggleOff",$obj).outerWidth();var btnw=$("table td:nth-child(2)",$obj).outerWidth();$obj.width(offw+btnw+2);var move=$("td.toggleOff",$obj).outerWidth();if($("div.container",$obj).hasClass("off")){if(right=="right"){$("div.container",$obj).animate({left:"-="+move+"px"},0)}else{$("div.container",$obj).animate({left:"+="+move+"px"},0)}}$("div.container",$obj).click(function(){if($(this).hasClass("isActive")){return false}else{$(this).addClass("isActive")}var $msg=PMA_ajaxShowMessage();var $container=$(this);var callback=$("span.callback",this).text();if($(this).hasClass("on")){if(right=="right"){var operator="-="}else{var operator="+="}var url=$(this).find("td.toggleOff > span").text();var removeClass="on";var addClass="off"}else{if(right=="right"){var operator="+="}else{var operator="-="}var url=$(this).find("td.toggleOn > span").text();var removeClass="off";var addClass="on"}$.post(url,{ajax_request:true},function(data){if(data.success==true){PMA_ajaxRemoveMessage($msg);$container.removeClass(removeClass).addClass(addClass).animate({left:operator+move+"px"},function(){$container.removeClass("isActive")});eval(callback)}else{PMA_ajaxShowMessage(data.error,false);$container.removeClass("isActive")}})})};AJAX.registerTeardown("functions.js",function(){$("div.container").unbind("click")});AJAX.registerOnload("functions.js",function(){$("div.toggleAjax").each(function(){var a=$(this).show();a.find("img").each(function(){if(this.complete){toggleButton(a)}else{$(this).load(function(){toggleButton(a)})}})})});AJAX.registerTeardown("functions.js",function(){$(".vpointer").die("hover");$(".vmarker").die("click");$("#pageselector").die("change");$("a.formLinkSubmit").die("click");$("#update_recent_tables").unbind("ready")});AJAX.registerOnload("functions.js",function(){$(".vpointer").live("hover",function(c){var a=$(this);var b=PMA_getRowNumber(a.attr("class"));$(".vpointer").filter(".row_"+b).toggleClass("hover")});$(".vmarker").live("click",function(f){if($(f.target).is("a, img, a *")){return}var c=$(this);var d=PMA_getRowNumber(c.attr("class"));var a=$(".vmarker").filter(".row_"+d+":first").find(":checkbox");if(a.length){var b=a.prop("checked");if(!$(f.target).is(":checkbox, label")){b=!b;a.prop("checked",b)}if(b){$(".vmarker").filter(".row_"+d).addClass("marked")}else{$(".vmarker").filter(".row_"+d).removeClass("marked")}}else{$(".vmarker").filter(".row_"+d).toggleClass("marked")}});$("select.pageselector").live("change",function(a){a.stopPropagation();if($(this).closest("#pma_navigation").length==0){$(this).closest("form").submit()}else{PMA_navigationTreePagination($(this))}});if($("li.jsversioncheck").length>0){$.getJSON("version_check.php",{},PMA_current_version)}if($("#is_git_revision").length>0){setTimeout(PMA_display_git_revision,10)}PMA_init_slider();$("a.formLinkSubmit").live("click",function(b){if($(this).attr("href").indexOf("=")!=-1){var a=$(this).attr("href").substr($(this).attr("href").indexOf("#")+1).split("=",2);$(this).parents("form").append('')}$(this).parents("form").submit();return false});if($("#update_recent_tables").length){$.get($("#update_recent_tables").attr("href"),function(a){if(a.success==true){$("#recentTable").html(a.options)}})}});function PMA_init_slider(){$("div.pma_auto_slider").each(function(){var b=$(this);if(b.data("slider_init_done")){return}var a=$("
      ",{"class":"slide-wrapper"});a.toggle(b.is(":visible"));$("",{href:"#"+this.id,"class":"ajax"}).text(this.title).prepend($("")).insertBefore(b).click(function(){var c=b.closest(".slide-wrapper");var d=b.is(":visible");if(!d){c.show()}b[d?"hide":"show"]("blind",function(){c.toggle(!d);PMA_set_status_label(b)});return false});b.wrap(a);PMA_set_status_label(b);b.data("slider_init_done",1)})}AJAX.registerOnload("functions.js",function(){PMA_init_slider()});AJAX.registerTeardown("functions.js",function(){$("div.pma_auto_slider").each(function(){var a=$(this);a.removeData();a.parent().replaceWith(a);a.parent().children("a").remove()})});function PMA_slidingMessage(b,c){if(b==undefined||b.length==0){return false}if(c==undefined||!c instanceof jQuery||c.length==0){if($("#PMA_slidingMessage").length==0){$("#page_content").prepend('')}c=$("#PMA_slidingMessage")}if(c.has("div").length>0){c.find("div").first().fadeOut(function(){c.children().remove();c.append('
      '+b+"
      ").animate({height:c.find("div").first().height()}).find("div").first().fadeIn()})}else{var a=c.width("100%").html('
      '+b+"
      ").find("div").first().height();c.find("div").first().css("height",0).show().animate({height:a},function(){c.height(c.find("div").first().height())})}return true}AJAX.registerTeardown("functions.js",function(){$("#drop_tbl_anchor.ajax").die("click");$("#truncate_tbl_anchor.ajax").die("click")});AJAX.registerOnload("functions.js",function(){$("#drop_tbl_anchor.ajax").live("click",function(b){b.preventDefault();var a=PMA_messages.strDropTableStrongWarning+" ";a+=$.sprintf(PMA_messages.strDoYouReally,"DROP TABLE "+PMA_commonParams.get("table"));$(this).PMA_confirm(a,$(this).attr("href"),function(c){var d=PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);$.get(c,{is_js_confirmed:"1",ajax_request:true},function(e){if(e.success==true){PMA_ajaxRemoveMessage(d);PMA_reloadNavigation();PMA_commonParams.set("table","");PMA_commonActions.refreshMain(PMA_commonParams.get("opendb_url"),function(){PMA_ajaxShowMessage(e.message)})}else{PMA_ajaxShowMessage(e.error,false)}})})});$("#truncate_tbl_anchor.ajax").live("click",function(b){b.preventDefault();var a=PMA_messages.strTruncateTableStrongWarning+" ";a+=$.sprintf(PMA_messages.strDoYouReally,"TRUNCATE "+PMA_commonParams.get("table"));$(this).PMA_confirm(a,$(this).attr("href"),function(c){PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);$.get(c,{is_js_confirmed:"1",ajax_request:true},function(d){if($("#sqlqueryresults").length!=0){$("#sqlqueryresults").remove()}if($("#result_query").length!=0){$("#result_query").remove()}if(d.success==true){PMA_ajaxShowMessage(d.message);$("
      ").prependTo("#page_content");$("#sqlqueryresults").html(d.sql_query)}else{PMA_ajaxShowMessage(d.error,false)}})})})});AJAX.registerOnload("functions.js",function(){var a=$("#sqlquery");if(a.length>0){if(typeof CodeMirror!="undefined"){codemirror_editor=CodeMirror.fromTextArea(a[0],{lineNumbers:true,matchBrackets:true,indentUnit:4,mode:"text/x-mysql",lineWrapping:true});codemirror_editor.focus();$(codemirror_editor.getWrapperElement()).bind("keydown",catchKeypressesFromSqlTextboxes)}else{a.focus().bind("keydown",catchKeypressesFromSqlTextboxes)}}});AJAX.registerTeardown("functions.js",function(){if(codemirror_editor){$("#sqlquery").text(codemirror_editor.getValue());codemirror_editor.toTextArea();codemirror_editor=false}});(function(a){a.fn.noSelect=function(c){var b=(c==null)?true:c;if(b){return this.each(function(){if(a.browser.msie||a.browser.safari){a(this).bind("selectstart",function(){return false})}else{if(a.browser.mozilla){a(this).css("MozUserSelect","none");a("body").trigger("focus")}else{if(a.browser.opera){a(this).bind("mousedown",function(){return false})}else{a(this).attr("unselectable","on")}}}})}else{return this.each(function(){if(a.browser.msie||a.browser.safari){a(this).unbind("selectstart")}else{if(a.browser.mozilla){a(this).css("MozUserSelect","inherit")}else{if(a.browser.opera){a(this).unbind("mousedown")}else{a(this).removeAttr("unselectable")}}}})}}})(jQuery);(function(a){a.fn.filterByValue=function(b){return this.filter(function(){return a(this).val()===b})}})(jQuery);function PMA_tooltip(d,e,c,b){if($("#no_hint").length>0){return}var a={content:c,items:e,tooltipClass:"tooltip",track:true,show:false,hide:false};d.tooltip($.extend(true,a,b))}function PMA_getCellValue(b){var a=$(b);if(a.is(".null")){return""}else{if(!a.is(".to_be_saved")&&a.data("original_data")){return a.data("original_data")}else{return a.text()}}}AJAX.registerTeardown("functions.js",function(){$("a.themeselect").die("click");$(".autosubmit").die("change");$("a.take_theme").unbind("click")});AJAX.registerOnload("functions.js",function(){$("a.themeselect").live("click",function(a){window.open(a.target,"themes","left=10,top=20,width=510,height=350,scrollbars=yes,status=yes,resizable=yes");return false});$(".autosubmit").live("change",function(a){$(this).closest("form").submit()});$("a.take_theme").click(function(b){var a=this.name;if(window.opener&&window.opener.document.forms.setTheme.elements.set_theme){window.opener.document.forms.setTheme.elements.set_theme.value=a;window.opener.document.forms.setTheme.submit();window.close();return false}return true})});function PMA_clearSelection(){if(document.selection&&document.selection.empty){document.selection.empty()}else{if(window.getSelection){var a=window.getSelection();if(a.empty){a.empty()}if(a.removeAllRanges){a.removeAllRanges()}}}}function escapeHtml(a){return a.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function printPage(){if(typeof(window.print)!="undefined"){window.print()}}AJAX.registerTeardown("functions.js",function(){$("input#print").unbind("click");$("span a.create_view.ajax").die("click");$("#createViewDialog").find("input, select").die("keydown")});AJAX.registerOnload("functions.js",function(){$("input#print").click(printPage);$("span a.create_view.ajax").live("click",function(a){a.preventDefault();PMA_createViewDialog($(this))});$("#createViewDialog").find("input, select").live("keydown",function(a){if(a.which===13){a.preventDefault();$(this).closest(".ui-dialog").find(".ui-button:first").click()}})});function PMA_createViewDialog(c){var a=PMA_ajaxShowMessage();var b=null;$.get(c.attr("href")+"&ajax_request=1",function(g){if(g.success==true){PMA_ajaxRemoveMessage(a);var h={};h[PMA_messages.strGo]=function(){if(typeof CodeMirror!=="undefined"){b.save()}a=PMA_ajaxShowMessage();$.get("view_create.php",$("#createViewDialog").find("form").serialize(),function(i){PMA_ajaxRemoveMessage(a);if(i.success===true){$("#createViewDialog").dialog("close");$("#result_query").html(i.message);PMA_reloadNavigation()}else{PMA_ajaxShowMessage(i.error,false)}})};h[PMA_messages.strClose]=function(){$(this).dialog("close")};var f=$("
      ").attr("id","createViewDialog").append(g.message).dialog({width:500,minWidth:300,maxWidth:620,modal:true,buttons:h,title:$("legend",$(g.message)).html(),close:function(){$(this).remove()}});f.find("legend").remove();if(typeof CodeMirror!=="undefined"){var d=f.find("textarea");var e={lineNumbers:true,matchBrackets:true,indentUnit:4,mode:"text/x-mysql"};b=CodeMirror.fromTextArea(d[0],e)}$("input:visible[type=text]",f).first().focus()}else{PMA_ajaxShowMessage(g.error)}})}$(function(){if($("#floating_menubar").length&&$("#PMA_disable_floating_menubar").length==0){var a=$("html").attr("dir")=="ltr"?"left":"right";$("#floating_menubar").css("margin-"+a,$("#pma_navigation").width()+$("#pma_navigation_resizer").width()).css(a,0).css({position:"fixed",top:0,width:"100%","z-index":500}).append($("#serverinfo")).append($("#topmenucontainer"));setTimeout(function(){$("body").css("padding-top",$("#floating_menubar").outerHeight(true));$("#topmenu").menuResizer("resize")},4)}});$(function(){$(document).delegate("#serverinfo, #goto_pagetop","click",function(a){a.preventDefault();$("html, body").animate({scrollTop:0},"fast")})});var checkboxes_sel="input.checkall:checkbox:enabled";$(checkboxes_sel).live("change",function(){var a=$(this.form);var c=a.find(checkboxes_sel).length;var d=a.find(checkboxes_sel+":checked").length;var b=a.find("input#checkall");if(c==d){b.prop({checked:true,indeterminate:false})}else{if(d>0){b.prop({checked:true,indeterminate:true})}else{b.prop({checked:false,indeterminate:false})}}});$("input#checkall").live("change",function(){var a=$(this).is(":checked");$(this.form).find(checkboxes_sel).prop("checked",a).parents("tr").toggleClass("marked",a)});function toggleRowColors(b){for(var a=b;a.length>0;a=a.next()){if(a.hasClass("odd")){a.removeClass("odd").addClass("even")}else{if(a.hasClass("even")){a.removeClass("even").addClass("odd")}}}}function formatBytes(b,f,a){if(!f){var f=0}if(!a){var a="."}var c=["B","KiB","MiB","GiB"];for(var e=0;b>1024&&egetPath() . '/sprites.lib.php')) { + include $_SESSION['PMA_Theme']->getPath() . '/sprites.lib.php'; +} +$sprites = array(); +if (function_exists('PMA_sprites')) { + $sprites = PMA_sprites(); +} +// We only need the keys from the array of sprites data, +// since they contain the (partial) class names +$keys = array(); +foreach ($sprites as $key => $value) { + $keys[] = "'$key'"; +} + +?> +/** + * 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 object attributes An associative array of other attributes + * + * @return Object The requested image, this object has two methods: + * .toString() - Returns the IMG tag for the requested image + * .attr(name) - Returns a particular attribute of the IMG + * tag given it's name + * .attr(name, value) - Sets a particular attribute of the IMG + * tag to the given value + * And one property: + * .isSprite - Whether the image is a sprite or not + */ +function PMA_getImage(image, alternate, attributes) { + var in_array = function (needle, haystack) { + for (var i in haystack) { + if (haystack[i] == needle) { + return true; + } + } + return false; + }; + var sprites = [ + + ]; + // custom image object, it will eventually be returned by this functions + var retval = { + data: { + // this is private + alt: '', + title: '', + src: (typeof PMA_TEST_THEME == 'undefined' ? '' : '../') + + 'themes/dot.gif' + }, + isSprite: true, + attr: function (name, value) { + if (value == undefined) { + if (this.data[name] == undefined) { + return ''; + } else { + return this.data[name]; + } + } else { + this.data[name] = value; + } + }, + toString: function () { + var retval = '<' + 'img'; + for (var i in this.data) { + retval += ' ' + i + '="' + this.data[i] + '"'; + } + retval += ' /' + '>'; + return retval; + } + }; + // initialise missing parameters + if (attributes == undefined) { + attributes = {}; + } + if (alternate == undefined) { + alternate = ''; + } + // set alt + if (attributes.alt != undefined) { + retval.attr('alt', attributes.alt); + } else { + retval.attr('alt', alternate); + } + // set title + if (attributes.title != undefined) { + retval.attr('title', attributes.title); + } else { + retval.attr('title', alternate); + } + // set src + var klass = image.replace('.gif', '').replace('.png', ''); + if (in_array(klass, sprites)) { + // it's an icon from a sprite + retval.attr('class', 'icon ic_' + klass); + } else { + // it's an image file + retval.isSprite = false; + retval.attr('src', "getImgPath(); ?>" + image); + } + // set all other attrubutes + for (var i in attributes) { + if (i == 'src') { + // do not allow to override the 'src' attribute + continue; + } else if (i == 'class') { + retval.attr(i, retval.attr('class') + ' ' + attributes[i]); + } else { + retval.attr(i, attributes[i]); + } + } + + return retval; +} +// \ No newline at end of file diff --git a/phpmyadmin/js/get_scripts.js.php b/phpmyadmin/js/get_scripts.js.php new file mode 100644 index 000000000..564fda7dd --- /dev/null +++ b/phpmyadmin/js/get_scripts.js.php @@ -0,0 +1,38 @@ + $filename) { + if (! preg_match("@^\.+$@", $filename) + && preg_match("@^[\w\.-]+$@", $filename) + ) { + // Disallow "." and ".." alone + // Allow alphanumeric, "." and "-" chars only + $script_name .= DIRECTORY_SEPARATOR . $filename; + } + } + // Output file contents + if (preg_match("@\.js$@", $script_name) && is_readable($script_name)) { + readfile($script_name); + echo ";\n\n"; + } + } +} + +?> diff --git a/phpmyadmin/js/gis_data_editor.js b/phpmyadmin/js/gis_data_editor.js new file mode 100644 index 000000000..233df5ed7 --- /dev/null +++ b/phpmyadmin/js/gis_data_editor.js @@ -0,0 +1 @@ +var gisEditorLoaded=false;function closeGISEditor(){$("#popup_background").fadeOut("fast");$("#gis_editor").fadeOut("fast",function(){$(this).empty()})}function prepareJSVersion(){$("#gis_editor input[name='gis_data[save]']").val(PMA_messages.strCopy).insertAfter($("#gis_data_textarea")).before("

      ");$("#gis_data_editor").prepend('
      '+PMA_messages.strClose+"");$(' '+PMA_messages.strCancel+"").insertAfter($("input[name='gis_data[save]']"));$("div#gis_data_output p").remove();$("#gis_editor input.add").each(function(c){var b=$(this);b.addClass("addJs").removeClass("add");var a=b.attr("class");b.replaceWith('+ '+b.val()+"")})}function addDataPoint(a,b){return"
      "+$.sprintf(PMA_messages.strPointN,(a+1))+': '}function initGISEditorVisualization(){selectVisualization();styleOSM();loadSVG();addZoomPanControllers();zoomAndPan()}function loadJSAndGISEditor(j,h,e,c,a){var f=document.getElementsByTagName("head")[0];var g;var d=["js/jquery/jquery.svg.js","js/jquery/jquery.mousewheel.js","js/jquery/jquery.event.drag-2.0.js","js/tbl_gis_visualization.js"];for(var b=0;b
      ');f.fadeIn("fast");a.fadeIn("fast")}function insertDataAndClose(){var a=$("form#gis_data_editor_form");var b=a.find("input[name='input_name']").val();$.post("gis_data_editor.php",a.serialize()+"&generate=true&ajax_request=true",function(c){if(c.success==true){$("input[name='"+b+"']").val(c.result)}else{PMA_ajaxShowMessage(c.error,false)}},"json");closeGISEditor()}AJAX.registerTeardown("gis_data_editor.js",function(){$("#gis_editor input[name='gis_data[save]']").die("click");$("#gis_editor").die("submit");$("#gis_editor").find("input[type='text']").die("change");$("#gis_editor select.gis_type").die("change");$("#gis_editor a.close_gis_editor, #gis_editor a.cancel_gis_editor").die("click");$("#gis_editor a.addJs.addPoint").die("click");$("#gis_editor a.addLine.addJs").die("click");$("#gis_editor a.addJs.addPolygon").die("click");$("#gis_editor a.addJs.addGeom").die("click")});AJAX.registerOnload("gis_data_editor.js",function(){$("span.open_gis_editor a").removeClass("formLinkSubmit");$("#gis_editor input[name='gis_data[save]']").live("click",function(event){event.preventDefault();insertDataAndClose()});$("#gis_editor").live("submit",function(event){event.preventDefault();insertDataAndClose()});$("#gis_editor").find("input[type='text']").live("change",function(){var $form=$("form#gis_data_editor_form");$.post("gis_data_editor.php",$form.serialize()+"&generate=true&ajax_request=true",function(data){if(data.success==true){$("#gis_data_textarea").val(data.result);$("#placeholder").empty().removeClass("hasSVG").html(data.visualization);$("#openlayersmap").empty();eval(data.openLayers);initGISEditorVisualization()}else{PMA_ajaxShowMessage(data.error,false)}},"json")});$("#gis_editor select.gis_type").live("change",function(event){var $gis_editor=$("#gis_editor");var $form=$("form#gis_data_editor_form");$.post("gis_data_editor.php",$form.serialize()+"&get_gis_editor=true&ajax_request=true",function(data){if(data.success==true){$gis_editor.html(data.gis_editor);initGISEditorVisualization();prepareJSVersion()}else{PMA_ajaxShowMessage(data.error,false)}},"json")});$("#gis_editor a.close_gis_editor, #gis_editor a.cancel_gis_editor").live("click",function(){closeGISEditor()});$("#gis_editor a.addJs.addPoint").live("click",function(){var $a=$(this);var name=$a.attr("name");var prefix=name.substr(0,name.length-11);var $noOfPointsInput=$("input[name='"+prefix+"[no_of_points]']");var noOfPoints=parseInt($noOfPointsInput.val());var html=addDataPoint(noOfPoints,prefix);$a.before(html);$noOfPointsInput.val(noOfPoints+1)});$("#gis_editor a.addLine.addJs").live("click",function(){var $a=$(this);var name=$a.attr("name");var prefix=name.substr(0,name.length-10);var type=prefix.slice(prefix.lastIndexOf("[")+1,prefix.lastIndexOf("]"));var $noOfLinesInput=$("input[name='"+prefix+"[no_of_lines]']");var noOfLines=parseInt($noOfLinesInput.val());var html="
      ";if(type=="MULTILINESTRING"){html+=PMA_messages.strLineString+" "+(noOfLines+1)+":";var noOfPoints=2}else{html+=PMA_messages.strInnerRing+" "+noOfLines+":";var noOfPoints=4}html+='';for(var i=0;i+ '+PMA_messages.strAddPoint+"
      ";$a.before(html);$noOfLinesInput.val(noOfLines+1)});$("#gis_editor a.addJs.addPolygon").live("click",function(){var $a=$(this);var name=$a.attr("name");var prefix=name.substr(0,name.length-13);var $noOfPolygonsInput=$("input[name='"+prefix+"[no_of_polygons]']");var noOfPolygons=parseInt($noOfPolygonsInput.val());var html=PMA_messages.strPolygon+" "+(noOfPolygons+1)+":
      ";html+='
      '+PMA_messages.strOuterRing+':';for(var i=0;i<4;i++){html+=addDataPoint(i,(prefix+"["+noOfPolygons+"][0]"))}html+='+ '+PMA_messages.strAddPoint+'
      + '+PMA_messages.strAddInnerRing+"

      ";$a.before(html);$noOfPolygonsInput.val(noOfPolygons+1)});$("#gis_editor a.addJs.addGeom").live("click",function(){var $a=$(this);var prefix="gis_data[GEOMETRYCOLLECTION]";var $noOfGeomsInput=$("input[name='"+prefix+"[geom_count]']");var noOfGeoms=parseInt($noOfGeomsInput.val());var html1=PMA_messages.strGeometry+" "+(noOfGeoms+1)+":
      ";var $geomType=$("select[name='gis_data["+(noOfGeoms-1)+"][gis_type]']").clone();$geomType.attr("name","gis_data["+noOfGeoms+"][gis_type]").val("POINT");var html2="
      "+PMA_messages.strPoint+' :

      ';$a.before(html1);$geomType.insertBefore($a);$a.before(html2);$noOfGeomsInput.val(noOfGeoms+1)})}); \ No newline at end of file diff --git a/phpmyadmin/js/import.js b/phpmyadmin/js/import.js new file mode 100644 index 000000000..c250baedc --- /dev/null +++ b/phpmyadmin/js/import.js @@ -0,0 +1 @@ +function changePluginOpts(){$("#format_specific_opts div.format_specific_options").each(function(){$(this).hide()});var a=$("#plugins option:selected").val();$("#"+a+"_options").fadeIn("slow");if(a=="csv"){$("#import_notification").text(PMA_messages.strImportCSV)}else{$("#import_notification").text("")}}function matchFile(d){var b=d.toLowerCase().split(".");var a=b.length;if(a!=0){var c=b[a-1];if(c=="gz"||c=="bz2"||c=="zip"){a--}if($("select[name='format'] option").filterByValue(b[a-1]).length==1){$("select[name='format'] option").filterByValue(b[a-1]).prop("selected",true);changePluginOpts()}}}AJAX.registerTeardown("import.js",function(){$("#plugins").unbind("change");$("#input_import_file").unbind("change");$("#select_local_import_file").unbind("change");$("#input_import_file").unbind("change").unbind("focus");$("#select_local_import_file").unbind("focus")});AJAX.registerOnload("import.js",function(){changePluginOpts();$("#plugins").change(function(){changePluginOpts()});$("#input_import_file").change(function(){matchFile($(this).val())});$("#select_local_import_file").change(function(){matchFile($(this).val())});$("#input_import_file").bind("focus change",function(){$("#radio_import_file").prop("checked",true);$("#radio_local_import_file").prop("checked",false)});$("#select_local_import_file").focus(function(){$("#radio_local_import_file").prop("checked",true);$("#radio_import_file").prop("checked",false)});$("#scroll_to_options_msg").hide();$("#format_specific_opts div.format_specific_options").css({border:0,margin:0,padding:0}).find("h3").remove()}); \ No newline at end of file diff --git a/phpmyadmin/js/indexes.js b/phpmyadmin/js/indexes.js new file mode 100644 index 000000000..ec86dc574 --- /dev/null +++ b/phpmyadmin/js/indexes.js @@ -0,0 +1 @@ +function checkIndexType(){$select_index_type=$("#select_index_type");$size_header=$("#index_columns thead tr th:nth-child(2)");$column_inputs=$('select[name="index[columns][names][]"]');$size_inputs=$('input[name="index[columns][sub_parts][]"]');$add_more=$("#index_frm .tblFooters");if($select_index_type.val()=="SPATIAL"){$size_header.hide();$size_inputs.each(function(){$(this).prop("disabled",true).parent("td").hide()});var a=true;$column_inputs.each(function(){$column_input=$(this);if(!a){$column_input.prop("disabled",true).parent("td").hide()}else{a=false}});$add_more.hide()}else{$size_header.show();$size_inputs.each(function(){$(this).prop("disabled",false).parent("td").show()});$column_inputs.each(function(){$(this).prop("disabled",false).parent("td").show()});$add_more.show()}}AJAX.registerTeardown("indexes.js",function(){$("#select_index_type").die("change");$("a.drop_primary_key_index_anchor.ajax").die("click");$("#table_index tbody tr td.edit_index.ajax, #indexes .add_index.ajax").die("click");$("#index_frm input[type=submit]").die("click")});AJAX.registerOnload("indexes.js",function(){checkIndexType();checkIndexName("index_frm");$("#select_index_type").live("change",function(a){a.preventDefault();checkIndexType();checkIndexName("index_frm")});$("a.drop_primary_key_index_anchor.ajax").live("click",function(f){f.preventDefault();var e=$(this);var c=e.parents("tr");var g=e.parents("td").attr("rowspan")||1;var h=c;for(var d=1,a=c.next();d tr").length){k.hide("medium",function(){$("div.no_indexes_defined").show("medium");h.remove()});k.siblings("div.notice").hide("medium")}else{toggleRowColors(h.last().next());h.hide("medium",function(){$(this).remove()})}if($("#result_query").length){$("#result_query").remove()}if(l.sql_query){$('
      ').html(l.sql_query).prependTo("#page_content")}PMA_commonActions.refreshMain(false,function(){$("a.ajax[href^=#indexes]").click()});PMA_reloadNavigation()}else{PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest+" : "+l.error,false)}})})});$("#table_index tbody tr td.edit_index.ajax, #indexes .add_index.ajax").live("click",function(c){c.preventDefault();if($(this).find("a").length==0){var b=checkFormElementInRange($(this).closest("form")[0],"added_fields","Column count has to be larger than zero.");if(!b){return}var a=$(this).closest("form").serialize();var d=PMA_messages.strAddIndex}else{var a=$(this).find("a").attr("href");if(a.substring(0,16)=="tbl_indexes.php?"){a=a.substring(16,a.length)}var d=PMA_messages.strEditIndex}a+="&ajax_request=true";indexEditorDialog(a,d,function(){PMA_commonActions.refreshMain(false,function(){$("a.ajax[href^=#indexes]").click()})})})}); \ No newline at end of file diff --git a/phpmyadmin/js/jqplot/excanvas.js b/phpmyadmin/js/jqplot/excanvas.js new file mode 100644 index 000000000..f583bbb81 --- /dev/null +++ b/phpmyadmin/js/jqplot/excanvas.js @@ -0,0 +1 @@ +if(!document.createElement("canvas").getContext){(function(){var ab=Math;var n=ab.round;var l=ab.sin;var A=ab.cos;var H=ab.abs;var N=ab.sqrt;var d=10;var f=d/2;var z=+navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];function y(){return this.context_||(this.context_=new D(this))}var t=Array.prototype.slice;function g(j,m,p){var i=t.call(arguments,2);return function(){return j.apply(m,i.concat(t.call(arguments)))}}function af(i){return String(i).replace(/&/g,"&").replace(/"/g,""")}function Y(m,j,i){if(!m.namespaces[j]){m.namespaces.add(j,i,"#default#VML")}}function R(j){Y(j,"g_vml_","urn:schemas-microsoft-com:vml");Y(j,"g_o_","urn:schemas-microsoft-com:office:office");if(!j.styleSheets.ex_canvas_){var i=j.createStyleSheet();i.owningElement.id="ex_canvas_";i.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}"}}R(document);var e={init:function(i){var j=i||document;j.createElement("canvas");j.attachEvent("onreadystatechange",g(this.init_,this,j))},init_:function(p){var m=p.getElementsByTagName("canvas");for(var j=0;j1){m--}if(6*m<1){return j+(i-j)*6*m}else{if(2*m<1){return i}else{if(3*m<2){return j+(i-j)*(2/3-m)*6}else{return j}}}}var C={};function F(j){if(j in C){return C[j]}var ag,Z=1;j=String(j);if(j.charAt(0)=="#"){ag=j}else{if(/^rgb/.test(j)){var p=M(j);var ag="#",ah;for(var m=0;m<3;m++){if(p[m].indexOf("%")!=-1){ah=Math.floor(c(p[m])*255)}else{ah=+p[m]}ag+=k[r(ah,0,255)]}Z=+p[3]}else{if(/^hsl/.test(j)){var p=M(j);ag=I(p);Z=p[3]}else{ag=b[j]||j}}}return C[j]={color:ag,alpha:Z}}var o={style:"normal",variant:"normal",weight:"normal",size:10,family:"sans-serif"};var L={};function E(i){if(L[i]){return L[i]}var p=document.createElement("div");var m=p.style;try{m.font=i}catch(j){}return L[i]={style:m.fontStyle||o.style,variant:m.fontVariant||o.variant,weight:m.fontWeight||o.weight,size:m.fontSize||o.size,family:m.fontFamily||o.family}}function u(m,j){var i={};for(var ah in m){i[ah]=m[ah]}var ag=parseFloat(j.currentStyle.fontSize),Z=parseFloat(m.size);if(typeof m.size=="number"){i.size=m.size}else{if(m.size.indexOf("px")!=-1){i.size=Z}else{if(m.size.indexOf("em")!=-1){i.size=ag*Z}else{if(m.size.indexOf("%")!=-1){i.size=(ag/100)*Z}else{if(m.size.indexOf("pt")!=-1){i.size=Z/0.75}else{i.size=ag}}}}}i.size*=0.981;i.family="'"+i.family.replace(/(\'|\")/g,"").replace(/\s*,\s*/g,"', '")+"'";return i}function ac(i){return i.style+" "+i.variant+" "+i.weight+" "+i.size+"px "+i.family}var s={butt:"flat",round:"round"};function S(i){return s[i]||"square"}function D(i){this.m_=B();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=d*1;this.globalAlpha=1;this.font="10px sans-serif";this.textAlign="left";this.textBaseline="alphabetic";this.canvas=i;var m="width:"+i.clientWidth+"px;height:"+i.clientHeight+"px;overflow:hidden;position:absolute";var j=i.ownerDocument.createElement("div");j.style.cssText=m;i.appendChild(j);var p=j.cloneNode(false);p.style.backgroundColor="red";p.style.filter="alpha(opacity=0)";i.appendChild(p);this.element_=j;this.arcScaleX_=1;this.arcScaleY_=1;this.lineScale_=1}var q=D.prototype;q.clearRect=function(){if(this.textMeasureEl_){this.textMeasureEl_.removeNode(true);this.textMeasureEl_=null}this.element_.innerHTML=""};q.beginPath=function(){this.currentPath_=[]};q.moveTo=function(j,i){var m=V(this,j,i);this.currentPath_.push({type:"moveTo",x:m.x,y:m.y});this.currentX_=m.x;this.currentY_=m.y};q.lineTo=function(j,i){var m=V(this,j,i);this.currentPath_.push({type:"lineTo",x:m.x,y:m.y});this.currentX_=m.x;this.currentY_=m.y};q.bezierCurveTo=function(m,j,ak,aj,ai,ag){var i=V(this,ai,ag);var ah=V(this,m,j);var Z=V(this,ak,aj);K(this,ah,Z,i)};function K(i,Z,m,j){i.currentPath_.push({type:"bezierCurveTo",cp1x:Z.x,cp1y:Z.y,cp2x:m.x,cp2y:m.y,x:j.x,y:j.y});i.currentX_=j.x;i.currentY_=j.y}q.quadraticCurveTo=function(ai,m,j,i){var ah=V(this,ai,m);var ag=V(this,j,i);var aj={x:this.currentX_+2/3*(ah.x-this.currentX_),y:this.currentY_+2/3*(ah.y-this.currentY_)};var Z={x:aj.x+(ag.x-this.currentX_)/3,y:aj.y+(ag.y-this.currentY_)/3};K(this,aj,Z,ag)};q.arc=function(al,aj,ak,ag,j,m){ak*=d;var ap=m?"at":"wa";var am=al+A(ag)*ak-f;var ao=aj+l(ag)*ak-f;var i=al+A(j)*ak-f;var an=aj+l(j)*ak-f;if(am==i&&!m){am+=0.125}var Z=V(this,al,aj);var ai=V(this,am,ao);var ah=V(this,i,an);this.currentPath_.push({type:ap,x:Z.x,y:Z.y,radius:ak,xStart:ai.x,yStart:ai.y,xEnd:ah.x,yEnd:ah.y})};q.rect=function(m,j,i,p){this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath()};q.strokeRect=function(m,j,i,p){var Z=this.currentPath_;this.beginPath();this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath();this.stroke();this.currentPath_=Z};q.fillRect=function(m,j,i,p){var Z=this.currentPath_;this.beginPath();this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath();this.fill();this.currentPath_=Z};q.createLinearGradient=function(j,p,i,m){var Z=new U("gradient");Z.x0_=j;Z.y0_=p;Z.x1_=i;Z.y1_=m;return Z};q.createRadialGradient=function(p,ag,m,j,Z,i){var ah=new U("gradientradial");ah.x0_=p;ah.y0_=ag;ah.r0_=m;ah.x1_=j;ah.y1_=Z;ah.r1_=i;return ah};q.drawImage=function(aq,m){var aj,ah,al,ay,ao,am,at,aA;var ak=aq.runtimeStyle.width;var ap=aq.runtimeStyle.height;aq.runtimeStyle.width="auto";aq.runtimeStyle.height="auto";var ai=aq.width;var aw=aq.height;aq.runtimeStyle.width=ak;aq.runtimeStyle.height=ap;if(arguments.length==3){aj=arguments[1];ah=arguments[2];ao=am=0;at=al=ai;aA=ay=aw}else{if(arguments.length==5){aj=arguments[1];ah=arguments[2];al=arguments[3];ay=arguments[4];ao=am=0;at=ai;aA=aw}else{if(arguments.length==9){ao=arguments[1];am=arguments[2];at=arguments[3];aA=arguments[4];aj=arguments[5];ah=arguments[6];al=arguments[7];ay=arguments[8]}else{throw Error("Invalid number of arguments")}}}var az=V(this,aj,ah);var p=at/2;var j=aA/2;var ax=[];var i=10;var ag=10;ax.push(" ','","");this.element_.insertAdjacentHTML("BeforeEnd",ax.join(""))};q.stroke=function(al){var aj=[];var Z=false;var m=10;var am=10;aj.push("ak.x){ak.x=j.x}if(ag.y==null||j.yak.y){ak.y=j.y}}}aj.push(' ">');if(!al){w(this,aj)}else{G(this,aj,ag,ak)}aj.push("");this.element_.insertAdjacentHTML("beforeEnd",aj.join(""))};function w(m,ag){var j=F(m.strokeStyle);var p=j.color;var Z=j.alpha*m.globalAlpha;var i=m.lineScale_*m.lineWidth;if(i<1){Z*=i}ag.push("')}function G(aq,ai,aK,ar){var aj=aq.fillStyle;var aB=aq.arcScaleX_;var aA=aq.arcScaleY_;var j=ar.x-aK.x;var p=ar.y-aK.y;if(aj instanceof U){var an=0;var aF={x:0,y:0};var ax=0;var am=1;if(aj.type_=="gradient"){var al=aj.x0_/aB;var m=aj.y0_/aA;var ak=aj.x1_/aB;var aM=aj.y1_/aA;var aJ=V(aq,al,m);var aI=V(aq,ak,aM);var ag=aI.x-aJ.x;var Z=aI.y-aJ.y;an=Math.atan2(ag,Z)*180/Math.PI;if(an<0){an+=360}if(an<0.000001){an=0}}else{var aJ=V(aq,aj.x0_,aj.y0_);aF={x:(aJ.x-aK.x)/j,y:(aJ.y-aK.y)/p};j/=aB*d;p/=aA*d;var aD=ab.max(j,p);ax=2*aj.r0_/aD;am=2*aj.r1_/aD-ax}var av=aj.colors_;av.sort(function(aN,i){return aN.offset-i.offset});var ap=av.length;var au=av[0].color;var at=av[ap-1].color;var az=av[0].alpha*aq.globalAlpha;var ay=av[ap-1].alpha*aq.globalAlpha;var aE=[];for(var aH=0;aH')}else{if(aj instanceof T){if(j&&p){var ah=-aK.x;var aC=-aK.y;ai.push("')}}else{var aL=F(aq.fillStyle);var aw=aL.color;var aG=aL.alpha*aq.globalAlpha;ai.push('')}}}q.fill=function(){this.stroke(true)};q.closePath=function(){this.currentPath_.push({type:"close"})};function V(j,Z,p){var i=j.m_;return{x:d*(Z*i[0][0]+p*i[1][0]+i[2][0])-f,y:d*(Z*i[0][1]+p*i[1][1]+i[2][1])-f}}q.save=function(){var i={};v(this,i);this.aStack_.push(i);this.mStack_.push(this.m_);this.m_=J(B(),this.m_)};q.restore=function(){if(this.aStack_.length){v(this.aStack_.pop(),this);this.m_=this.mStack_.pop()}};function h(i){return isFinite(i[0][0])&&isFinite(i[0][1])&&isFinite(i[1][0])&&isFinite(i[1][1])&&isFinite(i[2][0])&&isFinite(i[2][1])}function aa(j,i,p){if(!h(i)){return}j.m_=i;if(p){var Z=i[0][0]*i[1][1]-i[0][1]*i[1][0];j.lineScale_=N(H(Z))}}q.translate=function(m,j){var i=[[1,0,0],[0,1,0],[m,j,1]];aa(this,J(i,this.m_),false)};q.rotate=function(j){var p=A(j);var m=l(j);var i=[[p,m,0],[-m,p,0],[0,0,1]];aa(this,J(i,this.m_),false)};q.scale=function(m,j){this.arcScaleX_*=m;this.arcScaleY_*=j;var i=[[m,0,0],[0,j,0],[0,0,1]];aa(this,J(i,this.m_),true)};q.transform=function(Z,p,ah,ag,j,i){var m=[[Z,p,0],[ah,ag,0],[j,i,1]];aa(this,J(m,this.m_),true)};q.setTransform=function(ag,Z,ai,ah,p,j){var i=[[ag,Z,0],[ai,ah,0],[p,j,1]];aa(this,i,true)};q.drawText_=function(am,ak,aj,ap,ai){var ao=this.m_,at=1000,j=0,ar=at,ah={x:0,y:0},ag=[];var i=u(E(this.font),this.element_);var p=ac(i);var au=this.element_.currentStyle;var Z=this.textAlign.toLowerCase();switch(Z){case"left":case"center":case"right":break;case"end":Z=au.direction=="ltr"?"right":"left";break;case"start":Z=au.direction=="rtl"?"right":"left";break;default:Z="left"}switch(this.textBaseline){case"hanging":case"top":ah.y=i.size/1.75;break;case"middle":break;default:case null:case"alphabetic":case"ideographic":case"bottom":ah.y=-i.size/2.25;break}switch(Z){case"right":j=at;ar=0.05;break;case"center":j=ar=at/2;break}var aq=V(this,ak+ah.x,aj+ah.y);ag.push('');if(ai){w(this,ag)}else{G(this,ag,{x:-j,y:0},{x:ar,y:i.size})}var an=ao[0][0].toFixed(3)+","+ao[1][0].toFixed(3)+","+ao[0][1].toFixed(3)+","+ao[1][1].toFixed(3)+",0,0";var al=n(aq.x/d+1-ao[0][0])+","+n(aq.y/d-2*ao[1][0]);ag.push('','','');this.element_.insertAdjacentHTML("beforeEnd",ag.join(""))};q.fillText=function(m,i,p,j){this.drawText_(m,i,p,j,false)};q.strokeText=function(m,i,p,j){this.drawText_(m,i,p,j,true)};q.measureText=function(m){if(!this.textMeasureEl_){var i='';this.element_.insertAdjacentHTML("beforeEnd",i);this.textMeasureEl_=this.element_.lastChild}var j=this.element_.ownerDocument;this.textMeasureEl_.innerHTML="";this.textMeasureEl_.style.font=this.font;this.textMeasureEl_.appendChild(j.createTextNode(m));return{width:this.textMeasureEl_.offsetWidth}};q.clip=function(){};q.arcTo=function(){};q.createPattern=function(j,i){return new T(j,i)};function U(i){this.type_=i;this.x0_=0;this.y0_=0;this.r0_=0;this.x1_=0;this.y1_=0;this.r1_=0;this.colors_=[]}U.prototype.addColorStop=function(j,i){i=F(i);this.colors_.push({offset:j,color:i.color,alpha:i.alpha})};function T(j,i){Q(j);switch(i){case"repeat":case null:case"":this.repetition_="repeat";break;case"repeat-x":case"repeat-y":case"no-repeat":this.repetition_=i;break;default:O("SYNTAX_ERR")}this.src_=j.src;this.width_=j.width;this.height_=j.height}function O(i){throw new P(i)}function Q(i){if(!i||i.nodeType!=1||i.tagName!="IMG"){O("TYPE_MISMATCH_ERR")}if(i.readyState!="complete"){O("INVALID_STATE_ERR")}}function P(i){this.code=this[i];this.message=i+": DOM Exception "+this.code}var X=P.prototype=new Error;X.INDEX_SIZE_ERR=1;X.DOMSTRING_SIZE_ERR=2;X.HIERARCHY_REQUEST_ERR=3;X.WRONG_DOCUMENT_ERR=4;X.INVALID_CHARACTER_ERR=5;X.NO_DATA_ALLOWED_ERR=6;X.NO_MODIFICATION_ALLOWED_ERR=7;X.NOT_FOUND_ERR=8;X.NOT_SUPPORTED_ERR=9;X.INUSE_ATTRIBUTE_ERR=10;X.INVALID_STATE_ERR=11;X.SYNTAX_ERR=12;X.INVALID_MODIFICATION_ERR=13;X.NAMESPACE_ERR=14;X.INVALID_ACCESS_ERR=15;X.VALIDATION_ERR=16;X.TYPE_MISMATCH_ERR=17;G_vmlCanvasManager=e;CanvasRenderingContext2D=D;CanvasGradient=U;CanvasPattern=T;DOMException=P;G_vmlCanvasManager._version=888})()}; \ No newline at end of file diff --git a/phpmyadmin/js/jqplot/jquery.jqplot.js b/phpmyadmin/js/jqplot/jquery.jqplot.js new file mode 100644 index 000000000..b7aee6538 --- /dev/null +++ b/phpmyadmin/js/jqplot/jquery.jqplot.js @@ -0,0 +1 @@ +(function(H){var r;H.fn.emptyForce=function(){for(var ab=0,ac;(ac=H(this)[ab])!=null;ab++){if(ac.nodeType===1){H.cleanData(ac.getElementsByTagName("*"))}if(H.jqplot.use_excanvas){ac.outerHTML=""}else{while(ac.firstChild){ac.removeChild(ac.firstChild)}}ac=null}return H(this)};H.fn.removeChildForce=function(ab){while(ab.firstChild){this.removeChildForce(ab.firstChild);ab.removeChild(ab.firstChild)}};H.fn.jqplot=function(){var ab=[];var ad=[];for(var ae=0,ac=arguments.length;ae'+ai+"
      ");H("#"+ah).addClass("jqplot-error");document.getElementById(ah).style.background=H.jqplot.config.errorBackground;document.getElementById(ah).style.border=H.jqplot.config.errorBorder;document.getElementById(ah).style.fontFamily=H.jqplot.config.errorFontFamily;document.getElementById(ah).style.fontSize=H.jqplot.config.errorFontSize;document.getElementById(ah).style.fontStyle=H.jqplot.config.errorFontStyle;document.getElementById(ah).style.fontWeight=H.jqplot.config.errorFontWeight}}else{ag.init(ah,ad,ab);ag.draw();ag.themeEngine.init.call(ag);return ag}};H.jqplot.version="1.0.4";H.jqplot.revision="1121";H.jqplot.targetCounter=1;H.jqplot.CanvasManager=function(){if(typeof H.jqplot.CanvasManager.canvases=="undefined"){H.jqplot.CanvasManager.canvases=[];H.jqplot.CanvasManager.free=[]}var ab=[];this.getCanvas=function(){var ae;var ad=true;if(!H.jqplot.use_excanvas){for(var af=0,ac=H.jqplot.CanvasManager.canvases.length;af887){H.jqplot.support_canvas_text.result=true}else{H.jqplot.support_canvas_text.result=!!(document.createElement("canvas").getContext&&typeof document.createElement("canvas").getContext("2d").fillText=="function")}}return H.jqplot.support_canvas_text.result};H.jqplot.use_excanvas=(H.browser.msie&&!H.jqplot.support_canvas())?true:false;H.jqplot.preInitHooks=[];H.jqplot.postInitHooks=[];H.jqplot.preParseOptionsHooks=[];H.jqplot.postParseOptionsHooks=[];H.jqplot.preDrawHooks=[];H.jqplot.postDrawHooks=[];H.jqplot.preDrawSeriesHooks=[];H.jqplot.postDrawSeriesHooks=[];H.jqplot.preDrawLegendHooks=[];H.jqplot.addLegendRowHooks=[];H.jqplot.preSeriesInitHooks=[];H.jqplot.postSeriesInitHooks=[];H.jqplot.preParseSeriesOptionsHooks=[];H.jqplot.postParseSeriesOptionsHooks=[];H.jqplot.eventListenerHooks=[];H.jqplot.preDrawSeriesShadowHooks=[];H.jqplot.postDrawSeriesShadowHooks=[];H.jqplot.ElemContainer=function(){this._elem;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null}};H.jqplot.ElemContainer.prototype.createElement=function(ae,ag,ac,ad,ah){this._offsets=ag;var ab=ac||"jqplot";var af=document.createElement(ae);this._elem=H(af);this._elem.addClass(ab);this._elem.css(ad);this._elem.attr(ah);af=null;return this._elem};H.jqplot.ElemContainer.prototype.getWidth=function(){if(this._elem){return this._elem.outerWidth(true)}else{return null}};H.jqplot.ElemContainer.prototype.getHeight=function(){if(this._elem){return this._elem.outerHeight(true)}else{return null}};H.jqplot.ElemContainer.prototype.getPosition=function(){if(this._elem){return this._elem.position()}else{return{top:null,left:null,bottom:null,right:null}}};H.jqplot.ElemContainer.prototype.getTop=function(){return this.getPosition().top};H.jqplot.ElemContainer.prototype.getLeft=function(){return this.getPosition().left};H.jqplot.ElemContainer.prototype.getBottom=function(){return this._elem.css("bottom")};H.jqplot.ElemContainer.prototype.getRight=function(){return this._elem.css("right")};function s(ab){H.jqplot.ElemContainer.call(this);this.name=ab;this._series=[];this.show=false;this.tickRenderer=H.jqplot.AxisTickRenderer;this.tickOptions={};this.labelRenderer=H.jqplot.AxisLabelRenderer;this.labelOptions={};this.label=null;this.showLabel=true;this.min=null;this.max=null;this.autoscale=false;this.pad=1.2;this.padMax=null;this.padMin=null;this.ticks=[];this.numberTicks;this.tickInterval;this.renderer=H.jqplot.LinearAxisRenderer;this.rendererOptions={};this.showTicks=true;this.showTickMarks=true;this.showMinorTicks=true;this.drawMajorGridlines=true;this.drawMinorGridlines=false;this.drawMajorTickMarks=true;this.drawMinorTickMarks=true;this.useSeriesColor=false;this.borderWidth=null;this.borderColor=null;this.scaleToHiddenSeries=false;this._dataBounds={min:null,max:null};this._intervalStats=[];this._offsets={min:null,max:null};this._ticks=[];this._label=null;this.syncTicks=null;this.tickSpacing=75;this._min=null;this._max=null;this._tickInterval=null;this._numberTicks=null;this.__ticks=null;this._options={}}s.prototype=new H.jqplot.ElemContainer();s.prototype.constructor=s;s.prototype.init=function(){if(H.isFunction(this.renderer)){this.renderer=new this.renderer()}this.tickOptions.axis=this.name;if(this.tickOptions.showMark==null){this.tickOptions.showMark=this.showTicks}if(this.tickOptions.showMark==null){this.tickOptions.showMark=this.showTickMarks}if(this.tickOptions.showLabel==null){this.tickOptions.showLabel=this.showTicks}if(this.label==null||this.label==""){this.showLabel=false}else{this.labelOptions.label=this.label}if(this.showLabel==false){this.labelOptions.show=false}if(this.pad==0){this.pad=1}if(this.padMax==0){this.padMax=1}if(this.padMin==0){this.padMin=1}if(this.padMax==null){this.padMax=(this.pad-1)/2+1}if(this.padMin==null){this.padMin=(this.pad-1)/2+1}this.pad=this.padMax+this.padMin-1;if(this.min!=null||this.max!=null){this.autoscale=false}if(this.syncTicks==null&&this.name.indexOf("y")>-1){this.syncTicks=true}else{if(this.syncTicks==null){this.syncTicks=false}}this.renderer.init.call(this,this.rendererOptions)};s.prototype.draw=function(ab,ac){if(this.__ticks){this.__ticks=null}return this.renderer.draw.call(this,ab,ac)};s.prototype.set=function(){this.renderer.set.call(this)};s.prototype.pack=function(ac,ab){if(this.show){this.renderer.pack.call(this,ac,ab)}if(this._min==null){this._min=this.min;this._max=this.max;this._tickInterval=this.tickInterval;this._numberTicks=this.numberTicks;this.__ticks=this._ticks}};s.prototype.reset=function(){this.renderer.reset.call(this)};s.prototype.resetScale=function(ab){H.extend(true,this,{min:null,max:null,numberTicks:null,tickInterval:null,_ticks:[],ticks:[]},ab);this.resetDataBounds()};s.prototype.resetDataBounds=function(){var ai=this._dataBounds;ai.min=null;ai.max=null;var ac,aj,ag;var ad=(this.show)?true:false;for(var af=0;afai.max)||ai.max==null){ai.max=ag[ae][0]}}else{if((ag[ae][ab]!=null&&ag[ae][ab]ai.max)||ai.max==null){ai.max=ag[ae][ah]}}}if(ad&&aj.renderer.constructor!==H.jqplot.BarRenderer){ad=false}else{if(ad&&this._options.hasOwnProperty("forceTickAt0")&&this._options.forceTickAt0==false){ad=false}else{if(ad&&aj.renderer.constructor===H.jqplot.BarRenderer){if(aj.barDirection=="vertical"&&this.name!="xaxis"&&this.name!="x2axis"){if(this._options.pad!=null||this._options.padMin!=null){ad=false}}else{if(aj.barDirection=="horizontal"&&(this.name=="xaxis"||this.name=="x2axis")){if(this._options.pad!=null||this._options.padMin!=null){ad=false}}}}}}}}if(ad&&this.renderer.constructor===H.jqplot.LinearAxisRenderer&&ai.min>=0){this.padMin=1;this.forceTickAt0=true}};function n(ab){H.jqplot.ElemContainer.call(this);this.show=false;this.location="ne";this.labels=[];this.showLabels=true;this.showSwatches=true;this.placement="insideGrid";this.xoffset=0;this.yoffset=0;this.border;this.background;this.textColor;this.fontFamily;this.fontSize;this.rowSpacing="0.5em";this.renderer=H.jqplot.TableLegendRenderer;this.rendererOptions={};this.preDraw=false;this.marginTop=null;this.marginRight=null;this.marginBottom=null;this.marginLeft=null;this.escapeHtml=false;this._series=[];H.extend(true,this,ab)}n.prototype=new H.jqplot.ElemContainer();n.prototype.constructor=n;n.prototype.setOptions=function(ab){H.extend(true,this,ab);if(this.placement=="inside"){this.placement="insideGrid"}if(this.xoffset>0){if(this.placement=="insideGrid"){switch(this.location){case"nw":case"w":case"sw":if(this.marginLeft==null){this.marginLeft=this.xoffset+"px"}this.marginRight="0px";break;case"ne":case"e":case"se":default:if(this.marginRight==null){this.marginRight=this.xoffset+"px"}this.marginLeft="0px";break}}else{if(this.placement=="outside"){switch(this.location){case"nw":case"w":case"sw":if(this.marginRight==null){this.marginRight=this.xoffset+"px"}this.marginLeft="0px";break;case"ne":case"e":case"se":default:if(this.marginLeft==null){this.marginLeft=this.xoffset+"px"}this.marginRight="0px";break}}}this.xoffset=0}if(this.yoffset>0){if(this.placement=="outside"){switch(this.location){case"sw":case"s":case"se":if(this.marginTop==null){this.marginTop=this.yoffset+"px"}this.marginBottom="0px";break;case"ne":case"n":case"nw":default:if(this.marginBottom==null){this.marginBottom=this.yoffset+"px"}this.marginTop="0px";break}}else{if(this.placement=="insideGrid"){switch(this.location){case"sw":case"s":case"se":if(this.marginBottom==null){this.marginBottom=this.yoffset+"px"}this.marginTop="0px";break;case"ne":case"n":case"nw":default:if(this.marginTop==null){this.marginTop=this.yoffset+"px"}this.marginBottom="0px";break}}}this.yoffset=0}};n.prototype.init=function(){if(H.isFunction(this.renderer)){this.renderer=new this.renderer()}this.renderer.init.call(this,this.rendererOptions)};n.prototype.draw=function(ac,ad){for(var ab=0;ab
      ');this.target.append(at);at.height(ax);at.width(au);at.css("top",this.eventCanvas._offsets.top);at.css("left",this.eventCanvas._offsets.left);var aw=H('
      ');at.append(aw);aw.html(this.noDataIndicator.indicator);var av=aw.height();var ar=aw.width();aw.height(av);aw.width(ar);aw.css("top",(ax-av)/2+"px")})}}this.data=H.extend(true,[],al);this.parseOptions(aq);if(this.textColor){this.target.css("color",this.textColor)}if(this.fontFamily){this.target.css("font-family",this.fontFamily)}if(this.fontSize){this.target.css("font-size",this.fontSize)}this.title.init();this.legend.init();this._sumy=0;this._sumx=0;this.computePlotData();for(var am=0;am0){for(var ak=an;ak--;){var ah=this._plotData[ak][aj][ao];if(ap*ah>=0){this._plotData[an][aj][ao]+=ah;this._stackData[an][aj][ao]+=ah;break}}}}}else{for(var al=0;al0){am._prevPlotData=this.series[an-1]._plotData}am._sumy=0;am._sumx=0;for(al=am.data.length-1;al>-1;al--){am._sumy+=am.data[al][1];am._sumx+=am.data[al][0]}}};this.populatePlotData=function(an,ao){this._plotData=[];this._stackData=[];an._stackData=[];an._plotData=[];var ar={x:[],y:[]};if(this.stackSeries&&!an.disableStack){an._stack=true;var aq=(an._stackAxis==="x")?0:1;var at=H.extend(true,[],an.data);var au=H.extend(true,[],an.data);var ah,ag,ai,ap,af;for(var al=0;al=0){au[ak][aq]+=ap}}}for(var am=0;am0){an._prevPlotData=this.series[ao-1]._plotData}an._sumy=0;an._sumx=0;for(am=an.data.length-1;am>-1;am--){an._sumy+=an.data[am][1];an._sumx+=an.data[am][0]}};this.getNextSeriesColor=(function(ag){var af=0;var ah=ag.seriesColors;return function(){if(af=0&&ah>=0){af.top+=aE;af.bottom+=aE;af.left+=ah;af.right+=ah}}var ag=["top","bottom","left","right"];for(var au in ag){if(this._gridPadding[ag[au]]==null&&af[ag[au]]>0){this._gridPadding[ag[au]]=af[ag[au]]}else{if(this._gridPadding[ag[au]]==null){this._gridPadding[ag[au]]=this._defaultGridPadding[ag[au]]}}}var at=this._gridPadding;if(this.legend.placement==="outsideGrid"){at={top:this.title.getHeight(),left:0,right:0,bottom:0};if(this.legend.location==="s"){at.left=this._gridPadding.left;at.right=this._gridPadding.right}}al.xaxis.pack({position:"absolute",bottom:this._gridPadding.bottom-al.xaxis.getHeight(),left:0,width:this._width},{min:this._gridPadding.left,max:this._width-this._gridPadding.right});al.yaxis.pack({position:"absolute",top:0,left:this._gridPadding.left-al.yaxis.getWidth(),height:this._height},{min:this._height-this._gridPadding.bottom,max:this._gridPadding.top});al.x2axis.pack({position:"absolute",top:this._gridPadding.top-al.x2axis.getHeight(),left:0,width:this._width},{min:this._gridPadding.left,max:this._width-this._gridPadding.right});for(aB=8;aB>0;aB--){al[aA[aB-1]].pack({position:"absolute",top:0,right:this._gridPadding.right-ar[aB-1]},{min:this._height-this._gridPadding.bottom,max:this._gridPadding.top})}var an=(this._width-this._gridPadding.left-this._gridPadding.right)/2+this._gridPadding.left-al.yMidAxis.getWidth()/2;al.yMidAxis.pack({position:"absolute",top:0,left:an,zIndex:9,textAlign:"center"},{min:this._height-this._gridPadding.bottom,max:this._gridPadding.top});this.target.append(this.grid.createElement(this._gridPadding,this));this.grid.draw();var ak=this.series;var aD=ak.length;for(aB=0,ay=aD;aBaq)?ao:aq;var al=this.series[ap];var ak=this.series[an];if(ak.renderer.smooth){var aj=ak.renderer._smoothedData.slice(0).reverse()}else{var aj=ak.gridData.slice(0).reverse()}if(al.renderer.smooth){var am=al.renderer._smoothedData.concat(aj)}else{var am=al.gridData.concat(aj)}var ai=(ah.color!==null)?ah.color:this.series[aq].fillColor;var ar=(ah.baseSeries!==null)?ah.baseSeries:ap;var ag=this.series[ar].renderer.shapeRenderer;var af={fillStyle:ai,fill:true,closePath:true};ag.draw(al.shadowCanvas._ctx,am,af)};this.bindCustomEvents=function(){this.eventCanvas._elem.bind("click",{plot:this},this.onClick);this.eventCanvas._elem.bind("dblclick",{plot:this},this.onDblClick);this.eventCanvas._elem.bind("mousedown",{plot:this},this.onMouseDown);this.eventCanvas._elem.bind("mousemove",{plot:this},this.onMouseMove);this.eventCanvas._elem.bind("mouseenter",{plot:this},this.onMouseEnter);this.eventCanvas._elem.bind("mouseleave",{plot:this},this.onMouseLeave);if(this.captureRightClick){this.eventCanvas._elem.bind("mouseup",{plot:this},this.onRightClick);this.eventCanvas._elem.get(0).oncontextmenu=function(){return false}}else{this.eventCanvas._elem.bind("mouseup",{plot:this},this.onMouseUp)}};function ac(ao){var am=ao.data.plot;var ai=am.eventCanvas._elem.offset();var al={x:ao.pageX-ai.left,y:ao.pageY-ai.top};var aj={xaxis:null,yaxis:null,x2axis:null,y2axis:null,y3axis:null,y4axis:null,y5axis:null,y6axis:null,y7axis:null,y8axis:null,y9axis:null,yMidAxis:null};var ak=["xaxis","yaxis","x2axis","y2axis","y3axis","y4axis","y5axis","y6axis","y7axis","y8axis","y9axis","yMidAxis"];var af=am.axes;var ag,ah;for(ag=11;ag>0;ag--){ah=ak[ag-1];if(af[ah].show){aj[ah]=af[ah].series_p2u(al[ah.charAt(0)])}}return{offsets:ai,gridPos:al,dataPos:aj}}function ae(af,ag){var ak=ag.series;var aQ,aO,aN,aI,aJ,aD,aC,ap,an,at,au,aE;var aM,aR,aK,al,aB,aG,aP;var ah,aH;for(aN=ag.seriesStack.length-1;aN>=0;aN--){aQ=ag.seriesStack[aN];aI=ak[aQ];aP=aI._highlightThreshold;switch(aI.renderer.constructor){case H.jqplot.BarRenderer:aD=af.x;aC=af.y;for(aO=0;aOaB[0][0]&&aDaB[2][1]&&aCaB[0][0]+aP[0][0]&&aDaB[2][1]&&aC0&&-aC>=0){ap=2*Math.PI-Math.atan(-aC/aD)}else{if(aD>0&&-aC<0){ap=-Math.atan(-aC/aD)}else{if(aD<0){ap=Math.PI-Math.atan(-aC/aD)}else{if(aD==0&&-aC>0){ap=3*Math.PI/2}else{if(aD==0&&-aC<0){ap=Math.PI/2}else{if(aD==0&&aC==0){ap=0}}}}}}if(at){ap-=at;if(ap<0){ap+=2*Math.PI}else{if(ap>2*Math.PI){ap-=2*Math.PI}}}an=aI.sliceMargin/180*Math.PI;if(aJaI._innerRadius){for(aO=0;aO0)?aI.gridData[aO-1][1]+an:an;aE=aI.gridData[aO][1];if(ap>au&&ap0&&-aC>=0){ap=2*Math.PI-Math.atan(-aC/aD)}else{if(aD>0&&-aC<0){ap=-Math.atan(-aC/aD)}else{if(aD<0){ap=Math.PI-Math.atan(-aC/aD)}else{if(aD==0&&-aC>0){ap=3*Math.PI/2}else{if(aD==0&&-aC<0){ap=Math.PI/2}else{if(aD==0&&aC==0){ap=0}}}}}}if(at){ap-=at;if(ap<0){ap+=2*Math.PI}else{if(ap>2*Math.PI){ap-=2*Math.PI}}}an=aI.sliceMargin/180*Math.PI;if(aJ0)?aI.gridData[aO-1][1]+an:an;aE=aI.gridData[aO][1];if(ap>au&&ap=ar[0][1]&&aC<=ar[3][1]&&aD>=am[0]&&aD<=ay[0]){return{seriesIndex:aI.index,pointIndex:aO,gridData:null,data:aI.data[aO]}}}break;case H.jqplot.LineRenderer:aD=af.x;aC=af.y;aJ=aI.renderer;if(aI.show){if((aI.fill||(aI.renderer.bands.show&&aI.renderer.bands.fill))&&(!ag.plugins.highlighter||!ag.plugins.highlighter.show)){var aq=false;if(aD>aI._boundingBox[0][0]&&aDaI._boundingBox[1][1]&&aC=aC||av[1]=aC){if(aw[0]+(aC-aw[1])/(av[1]-aw[1])*(av[0]-aw[0])0)?aH:0;for(var aO=0;aO=aK[0]-aJ._bodyWidth/2&&aD<=aK[0]+aJ._bodyWidth/2&&aC>=ao(aI.data[aO][2])&&aC<=ao(aI.data[aO][3])){return{seriesIndex:aQ,pointIndex:aO,gridData:aK,data:aI.data[aO]}}}else{if(!aJ.hlc){var ao=aI._yaxis.series_u2p;if(aD>=aK[0]-aJ._tickLength&&aD<=aK[0]+aJ._tickLength&&aC>=ao(aI.data[aO][2])&&aC<=ao(aI.data[aO][3])){return{seriesIndex:aQ,pointIndex:aO,gridData:aK,data:aI.data[aO]}}}else{var ao=aI._yaxis.series_u2p;if(aD>=aK[0]-aJ._tickLength&&aD<=aK[0]+aJ._tickLength&&aC>=ao(aI.data[aO][1])&&aC<=ao(aI.data[aO][2])){return{seriesIndex:aQ,pointIndex:aO,gridData:aK,data:aI.data[aO]}}}}}else{if(aK[0]!=null&&aK[1]!=null){aR=Math.sqrt((aD-aK[0])*(aD-aK[0])+(aC-aK[1])*(aC-aK[1]));if(aR<=ah&&(aR<=aM||aM==null)){aM=aR;return{seriesIndex:aQ,pointIndex:aO,gridData:aK,data:aI.data[aO]}}}}}}}break;default:aD=af.x;aC=af.y;aJ=aI.renderer;if(aI.show){aH=aI.markerRenderer.size/2+aI.neighborThreshold;ah=(aH>0)?aH:0;for(var aO=0;aO=aK[0]-aJ._bodyWidth/2&&aD<=aK[0]+aJ._bodyWidth/2&&aC>=ao(aI.data[aO][2])&&aC<=ao(aI.data[aO][3])){return{seriesIndex:aQ,pointIndex:aO,gridData:aK,data:aI.data[aO]}}}else{if(!aJ.hlc){var ao=aI._yaxis.series_u2p;if(aD>=aK[0]-aJ._tickLength&&aD<=aK[0]+aJ._tickLength&&aC>=ao(aI.data[aO][2])&&aC<=ao(aI.data[aO][3])){return{seriesIndex:aQ,pointIndex:aO,gridData:aK,data:aI.data[aO]}}}else{var ao=aI._yaxis.series_u2p;if(aD>=aK[0]-aJ._tickLength&&aD<=aK[0]+aJ._tickLength&&aC>=ao(aI.data[aO][1])&&aC<=ao(aI.data[aO][2])){return{seriesIndex:aQ,pointIndex:aO,gridData:aK,data:aI.data[aO]}}}}}else{aR=Math.sqrt((aD-aK[0])*(aD-aK[0])+(aC-aK[1])*(aC-aK[1]));if(aR<=ah&&(aR<=aM||aM==null)){aM=aR;return{seriesIndex:aQ,pointIndex:aO,gridData:aK,data:aI.data[aO]}}}}}break}}return null}this.onClick=function(ah){var ag=ac(ah);var aj=ah.data.plot;var ai=ae(ag.gridPos,aj);var af=H.Event("jqplotClick");af.pageX=ah.pageX;af.pageY=ah.pageY;H(this).trigger(af,[ag.gridPos,ag.dataPos,ai,aj])};this.onDblClick=function(ah){var ag=ac(ah);var aj=ah.data.plot;var ai=ae(ag.gridPos,aj);var af=H.Event("jqplotDblClick");af.pageX=ah.pageX;af.pageY=ah.pageY;H(this).trigger(af,[ag.gridPos,ag.dataPos,ai,aj])};this.onMouseDown=function(ah){var ag=ac(ah);var aj=ah.data.plot;var ai=ae(ag.gridPos,aj);var af=H.Event("jqplotMouseDown");af.pageX=ah.pageX;af.pageY=ah.pageY;H(this).trigger(af,[ag.gridPos,ag.dataPos,ai,aj])};this.onMouseUp=function(ah){var ag=ac(ah);var af=H.Event("jqplotMouseUp");af.pageX=ah.pageX;af.pageY=ah.pageY;H(this).trigger(af,[ag.gridPos,ag.dataPos,null,ah.data.plot])};this.onRightClick=function(ah){var ag=ac(ah);var aj=ah.data.plot;var ai=ae(ag.gridPos,aj);if(aj.captureRightClick){if(ah.which==3){var af=H.Event("jqplotRightClick");af.pageX=ah.pageX;af.pageY=ah.pageY;H(this).trigger(af,[ag.gridPos,ag.dataPos,ai,aj])}else{var af=H.Event("jqplotMouseUp");af.pageX=ah.pageX;af.pageY=ah.pageY;H(this).trigger(af,[ag.gridPos,ag.dataPos,ai,aj])}}};this.onMouseMove=function(ah){var ag=ac(ah);var aj=ah.data.plot;var ai=ae(ag.gridPos,aj);var af=H.Event("jqplotMouseMove");af.pageX=ah.pageX;af.pageY=ah.pageY;H(this).trigger(af,[ag.gridPos,ag.dataPos,ai,aj])};this.onMouseEnter=function(ah){var ag=ac(ah);var ai=ah.data.plot;var af=H.Event("jqplotMouseEnter");af.pageX=ah.pageX;af.pageY=ah.pageY;af.relatedTarget=ah.relatedTarget;H(this).trigger(af,[ag.gridPos,ag.dataPos,null,ai])};this.onMouseLeave=function(ah){var ag=ac(ah);var ai=ah.data.plot;var af=H.Event("jqplotMouseLeave");af.pageX=ah.pageX;af.pageY=ah.pageY;af.relatedTarget=ah.relatedTarget;H(this).trigger(af,[ag.gridPos,ag.dataPos,null,ai])};this.drawSeries=function(ah,af){var aj,ai,ag;af=(typeof(ah)==="number"&&af==null)?ah:af;ah=(typeof(ah)==="object")?ah:{};if(af!=r){ai=this.series[af];ag=ai.shadowCanvas._ctx;ag.clearRect(0,0,ag.canvas.width,ag.canvas.height);ai.drawShadow(ag,ah,this);ag=ai.canvas._ctx;ag.clearRect(0,0,ag.canvas.width,ag.canvas.height);ai.draw(ag,ah,this);if(ai.renderer.constructor==H.jqplot.BezierCurveRenderer){if(af660)?ab[ad]*0.85:0.73*ab[ad]+90;ab[ad]=parseInt(ab[ad],10);(ab[ad]>255)?255:ab[ad]}ab[3]=0.3+0.35*af[3];ae.push("rgba("+ab[0]+","+ab[1]+","+ab[2]+","+ab[3]+")")}}else{var af=H.jqplot.getColorComponents(ac);var ab=[af[0],af[1],af[2]];var ah=ab[0]+ab[1]+ab[2];for(var ad=0;ad<3;ad++){ab[ad]=(ah>660)?ab[ad]*0.85:0.73*ab[ad]+90;ab[ad]=parseInt(ab[ad],10);(ab[ad]>255)?255:ab[ad]}ab[3]=0.3+0.35*af[3];ae="rgba("+ab[0]+","+ab[1]+","+ab[2]+","+ab[3]+")"}return ae};H.jqplot.ColorGenerator=function(ac){ac=ac||H.jqplot.config.defaultColors;var ab=0;this.next=function(){if(ab0){return ac[ab--]}else{ab=ac.length-1;return ac[ab]}};this.get=function(ae){var ad=ae-ac.length*Math.floor(ae/ac.length);return ac[ad]};this.setColors=function(ad){ac=ad};this.reset=function(){ab=0};this.getIndex=function(){return ab};this.setIndex=function(ad){ab=ad}};H.jqplot.hex2rgb=function(ad,ab){ad=ad.replace("#","");if(ad.length==3){ad=ad.charAt(0)+ad.charAt(0)+ad.charAt(1)+ad.charAt(1)+ad.charAt(2)+ad.charAt(2)}var ac;ac="rgba("+parseInt(ad.slice(0,2),16)+", "+parseInt(ad.slice(2,4),16)+", "+parseInt(ad.slice(4,6),16);if(ab){ac+=", "+ab}ac+=")";return ac};H.jqplot.rgb2hex=function(ag){var ad=/rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *(?:, *[0-9.]*)?\)/;var ab=ag.match(ad);var af="#";for(var ae=1;ae<4;ae++){var ac;if(ab[ae].search(/%/)!=-1){ac=parseInt(255*ab[ae]/100,10).toString(16);if(ac.length==1){ac="0"+ac}}else{ac=parseInt(ab[ae],10).toString(16);if(ac.length==1){ac="0"+ac}}af+=ac}return af};H.jqplot.normalize2rgb=function(ac,ab){if(ac.search(/^ *rgba?\(/)!=-1){return ac}else{if(ac.search(/^ *#?[0-9a-fA-F]?[0-9a-fA-F]/)!=-1){return H.jqplot.hex2rgb(ac,ab)}else{throw"invalid color spec"}}};H.jqplot.getColorComponents=function(ag){ag=H.jqplot.colorKeywordMap[ag]||ag;var ae=H.jqplot.normalize2rgb(ag);var ad=/rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *,? *([0-9.]* *)?\)/;var ab=ae.match(ad);var ac=[];for(var af=1;af<4;af++){if(ab[af].search(/%/)!=-1){ac[af-1]=parseInt(255*ab[af]/100,10)}else{ac[af-1]=parseInt(ab[af],10)}}ac[3]=parseFloat(ab[4])?parseFloat(ab[4]):1;return ac};H.jqplot.colorKeywordMap={aliceblue:"rgb(240, 248, 255)",antiquewhite:"rgb(250, 235, 215)",aqua:"rgb( 0, 255, 255)",aquamarine:"rgb(127, 255, 212)",azure:"rgb(240, 255, 255)",beige:"rgb(245, 245, 220)",bisque:"rgb(255, 228, 196)",black:"rgb( 0, 0, 0)",blanchedalmond:"rgb(255, 235, 205)",blue:"rgb( 0, 0, 255)",blueviolet:"rgb(138, 43, 226)",brown:"rgb(165, 42, 42)",burlywood:"rgb(222, 184, 135)",cadetblue:"rgb( 95, 158, 160)",chartreuse:"rgb(127, 255, 0)",chocolate:"rgb(210, 105, 30)",coral:"rgb(255, 127, 80)",cornflowerblue:"rgb(100, 149, 237)",cornsilk:"rgb(255, 248, 220)",crimson:"rgb(220, 20, 60)",cyan:"rgb( 0, 255, 255)",darkblue:"rgb( 0, 0, 139)",darkcyan:"rgb( 0, 139, 139)",darkgoldenrod:"rgb(184, 134, 11)",darkgray:"rgb(169, 169, 169)",darkgreen:"rgb( 0, 100, 0)",darkgrey:"rgb(169, 169, 169)",darkkhaki:"rgb(189, 183, 107)",darkmagenta:"rgb(139, 0, 139)",darkolivegreen:"rgb( 85, 107, 47)",darkorange:"rgb(255, 140, 0)",darkorchid:"rgb(153, 50, 204)",darkred:"rgb(139, 0, 0)",darksalmon:"rgb(233, 150, 122)",darkseagreen:"rgb(143, 188, 143)",darkslateblue:"rgb( 72, 61, 139)",darkslategray:"rgb( 47, 79, 79)",darkslategrey:"rgb( 47, 79, 79)",darkturquoise:"rgb( 0, 206, 209)",darkviolet:"rgb(148, 0, 211)",deeppink:"rgb(255, 20, 147)",deepskyblue:"rgb( 0, 191, 255)",dimgray:"rgb(105, 105, 105)",dimgrey:"rgb(105, 105, 105)",dodgerblue:"rgb( 30, 144, 255)",firebrick:"rgb(178, 34, 34)",floralwhite:"rgb(255, 250, 240)",forestgreen:"rgb( 34, 139, 34)",fuchsia:"rgb(255, 0, 255)",gainsboro:"rgb(220, 220, 220)",ghostwhite:"rgb(248, 248, 255)",gold:"rgb(255, 215, 0)",goldenrod:"rgb(218, 165, 32)",gray:"rgb(128, 128, 128)",grey:"rgb(128, 128, 128)",green:"rgb( 0, 128, 0)",greenyellow:"rgb(173, 255, 47)",honeydew:"rgb(240, 255, 240)",hotpink:"rgb(255, 105, 180)",indianred:"rgb(205, 92, 92)",indigo:"rgb( 75, 0, 130)",ivory:"rgb(255, 255, 240)",khaki:"rgb(240, 230, 140)",lavender:"rgb(230, 230, 250)",lavenderblush:"rgb(255, 240, 245)",lawngreen:"rgb(124, 252, 0)",lemonchiffon:"rgb(255, 250, 205)",lightblue:"rgb(173, 216, 230)",lightcoral:"rgb(240, 128, 128)",lightcyan:"rgb(224, 255, 255)",lightgoldenrodyellow:"rgb(250, 250, 210)",lightgray:"rgb(211, 211, 211)",lightgreen:"rgb(144, 238, 144)",lightgrey:"rgb(211, 211, 211)",lightpink:"rgb(255, 182, 193)",lightsalmon:"rgb(255, 160, 122)",lightseagreen:"rgb( 32, 178, 170)",lightskyblue:"rgb(135, 206, 250)",lightslategray:"rgb(119, 136, 153)",lightslategrey:"rgb(119, 136, 153)",lightsteelblue:"rgb(176, 196, 222)",lightyellow:"rgb(255, 255, 224)",lime:"rgb( 0, 255, 0)",limegreen:"rgb( 50, 205, 50)",linen:"rgb(250, 240, 230)",magenta:"rgb(255, 0, 255)",maroon:"rgb(128, 0, 0)",mediumaquamarine:"rgb(102, 205, 170)",mediumblue:"rgb( 0, 0, 205)",mediumorchid:"rgb(186, 85, 211)",mediumpurple:"rgb(147, 112, 219)",mediumseagreen:"rgb( 60, 179, 113)",mediumslateblue:"rgb(123, 104, 238)",mediumspringgreen:"rgb( 0, 250, 154)",mediumturquoise:"rgb( 72, 209, 204)",mediumvioletred:"rgb(199, 21, 133)",midnightblue:"rgb( 25, 25, 112)",mintcream:"rgb(245, 255, 250)",mistyrose:"rgb(255, 228, 225)",moccasin:"rgb(255, 228, 181)",navajowhite:"rgb(255, 222, 173)",navy:"rgb( 0, 0, 128)",oldlace:"rgb(253, 245, 230)",olive:"rgb(128, 128, 0)",olivedrab:"rgb(107, 142, 35)",orange:"rgb(255, 165, 0)",orangered:"rgb(255, 69, 0)",orchid:"rgb(218, 112, 214)",palegoldenrod:"rgb(238, 232, 170)",palegreen:"rgb(152, 251, 152)",paleturquoise:"rgb(175, 238, 238)",palevioletred:"rgb(219, 112, 147)",papayawhip:"rgb(255, 239, 213)",peachpuff:"rgb(255, 218, 185)",peru:"rgb(205, 133, 63)",pink:"rgb(255, 192, 203)",plum:"rgb(221, 160, 221)",powderblue:"rgb(176, 224, 230)",purple:"rgb(128, 0, 128)",red:"rgb(255, 0, 0)",rosybrown:"rgb(188, 143, 143)",royalblue:"rgb( 65, 105, 225)",saddlebrown:"rgb(139, 69, 19)",salmon:"rgb(250, 128, 114)",sandybrown:"rgb(244, 164, 96)",seagreen:"rgb( 46, 139, 87)",seashell:"rgb(255, 245, 238)",sienna:"rgb(160, 82, 45)",silver:"rgb(192, 192, 192)",skyblue:"rgb(135, 206, 235)",slateblue:"rgb(106, 90, 205)",slategray:"rgb(112, 128, 144)",slategrey:"rgb(112, 128, 144)",snow:"rgb(255, 250, 250)",springgreen:"rgb( 0, 255, 127)",steelblue:"rgb( 70, 130, 180)",tan:"rgb(210, 180, 140)",teal:"rgb( 0, 128, 128)",thistle:"rgb(216, 191, 216)",tomato:"rgb(255, 99, 71)",turquoise:"rgb( 64, 224, 208)",violet:"rgb(238, 130, 238)",wheat:"rgb(245, 222, 179)",white:"rgb(255, 255, 255)",whitesmoke:"rgb(245, 245, 245)",yellow:"rgb(255, 255, 0)",yellowgreen:"rgb(154, 205, 50)"};H.jqplot.AxisLabelRenderer=function(ab){H.jqplot.ElemContainer.call(this);this.axis;this.show=true;this.label="";this.fontFamily=null;this.fontSize=null;this.textColor=null;this._elem;this.escapeHTML=false;H.extend(true,this,ab)};H.jqplot.AxisLabelRenderer.prototype=new H.jqplot.ElemContainer();H.jqplot.AxisLabelRenderer.prototype.constructor=H.jqplot.AxisLabelRenderer;H.jqplot.AxisLabelRenderer.prototype.init=function(ab){H.extend(true,this,ab)};H.jqplot.AxisLabelRenderer.prototype.draw=function(ab,ac){if(this._elem){this._elem.emptyForce();this._elem=null}this._elem=H('
      ');if(Number(this.label)){this._elem.css("white-space","nowrap")}if(!this.escapeHTML){this._elem.html(this.label)}else{this._elem.text(this.label)}if(this.fontFamily){this._elem.css("font-family",this.fontFamily)}if(this.fontSize){this._elem.css("font-size",this.fontSize)}if(this.textColor){this._elem.css("color",this.textColor)}return this._elem};H.jqplot.AxisLabelRenderer.prototype.pack=function(){};H.jqplot.AxisTickRenderer=function(ab){H.jqplot.ElemContainer.call(this);this.mark="outside";this.axis;this.showMark=true;this.showGridline=true;this.isMinorTick=false;this.size=4;this.markSize=6;this.show=true;this.showLabel=true;this.label=null;this.value=null;this._styles={};this.formatter=H.jqplot.DefaultTickFormatter;this.prefix="";this.suffix="";this.formatString="";this.fontFamily;this.fontSize;this.textColor;this.escapeHTML=false;this._elem;this._breakTick=false;H.extend(true,this,ab)};H.jqplot.AxisTickRenderer.prototype.init=function(ab){H.extend(true,this,ab)};H.jqplot.AxisTickRenderer.prototype=new H.jqplot.ElemContainer();H.jqplot.AxisTickRenderer.prototype.constructor=H.jqplot.AxisTickRenderer;H.jqplot.AxisTickRenderer.prototype.setTick=function(ab,ad,ac){this.value=ab;this.axis=ad;if(ac){this.isMinorTick=true}return this};H.jqplot.AxisTickRenderer.prototype.draw=function(){if(this.label===null){this.label=this.prefix+this.formatter(this.formatString,this.value)+this.suffix}var ac={position:"absolute"};if(Number(this.label)){ac.whitSpace="nowrap"}if(this._elem){this._elem.emptyForce();this._elem=null}this._elem=H(document.createElement("div"));this._elem.addClass("jqplot-"+this.axis+"-tick");if(!this.escapeHTML){this._elem.html(this.label)}else{this._elem.text(this.label)}this._elem.css(ac);for(var ab in this._styles){this._elem.css(ab,this._styles[ab])}if(this.fontFamily){this._elem.css("font-family",this.fontFamily)}if(this.fontSize){this._elem.css("font-size",this.fontSize)}if(this.textColor){this._elem.css("color",this.textColor)}if(this._breakTick){this._elem.addClass("jqplot-breakTick")}return this._elem};H.jqplot.DefaultTickFormatter=function(ab,ac){if(typeof ac=="number"){if(!ab){ab=H.jqplot.config.defaultTickFormatString}return H.jqplot.sprintf(ab,ac)}else{return String(ac)}};H.jqplot.PercentTickFormatter=function(ab,ac){if(typeof ac=="number"){ac=100*ac;if(!ab){ab=H.jqplot.config.defaultTickFormatString}return H.jqplot.sprintf(ab,ac)}else{return String(ac)}};H.jqplot.AxisTickRenderer.prototype.pack=function(){};H.jqplot.CanvasGridRenderer=function(){this.shadowRenderer=new H.jqplot.ShadowRenderer()};H.jqplot.CanvasGridRenderer.prototype.init=function(ac){this._ctx;H.extend(true,this,ac);var ab={lineJoin:"miter",lineCap:"round",fill:false,isarc:false,angle:this.shadowAngle,offset:this.shadowOffset,alpha:this.shadowAlpha,depth:this.shadowDepth,lineWidth:this.shadowWidth,closePath:false,strokeStyle:this.shadowColor};this.renderer.shadowRenderer.init(ab)};H.jqplot.CanvasGridRenderer.prototype.createElement=function(ae){var ad;if(this._elem){if(H.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==r){ad=this._elem.get(0);window.G_vmlCanvasManager.uninitElement(ad);ad=null}this._elem.emptyForce();this._elem=null}ad=ae.canvasManager.getCanvas();var ab=this._plotDimensions.width;var ac=this._plotDimensions.height;ad.width=ab;ad.height=ac;this._elem=H(ad);this._elem.addClass("jqplot-grid-canvas");this._elem.css({position:"absolute",left:0,top:0});ad=ae.canvasManager.initCanvas(ad);this._top=this._offsets.top;this._bottom=ac-this._offsets.bottom;this._left=this._offsets.left;this._right=ab-this._offsets.right;this._width=this._right-this._left;this._height=this._bottom-this._top;ad=null;return this._elem};H.jqplot.CanvasGridRenderer.prototype.draw=function(){this._ctx=this._elem.get(0).getContext("2d");var am=this._ctx;var ap=this._axes;am.save();am.clearRect(0,0,this._plotDimensions.width,this._plotDimensions.height);am.fillStyle=this.backgroundColor||this.background;am.fillRect(this._left,this._top,this._width,this._height);am.save();am.lineJoin="miter";am.lineCap="butt";am.lineWidth=this.gridLineWidth;am.strokeStyle=this.gridLineColor;var at,ar,aj,ak;var ag=["xaxis","yaxis","x2axis","y2axis"];for(var aq=4;aq>0;aq--){var aw=ag[aq-1];var ab=ap[aw];var au=ab._ticks;var al=au.length;if(ab.show){if(ab.drawBaseline){var av={};if(ab.baselineWidth!==null){av.lineWidth=ab.baselineWidth}if(ab.baselineColor!==null){av.strokeStyle=ab.baselineColor}switch(aw){case"xaxis":ai(this._left,this._bottom,this._right,this._bottom,av);break;case"yaxis":ai(this._left,this._bottom,this._left,this._top,av);break;case"x2axis":ai(this._left,this._bottom,this._right,this._bottom,av);break;case"y2axis":ai(this._right,this._bottom,this._right,this._top,av);break}}for(var an=al;an>0;an--){var ah=au[an-1];if(ah.show){var ae=Math.round(ab.u2p(ah.value))+0.5;switch(aw){case"xaxis":if(ah.showGridline&&this.drawGridlines&&((!ah.isMinorTick&&ab.drawMajorGridlines)||(ah.isMinorTick&&ab.drawMinorGridlines))){ai(ae,this._top,ae,this._bottom)}if(ah.showMark&&ah.mark&&((!ah.isMinorTick&&ab.drawMajorTickMarks)||(ah.isMinorTick&&ab.drawMinorTickMarks))){aj=ah.markSize;ak=ah.mark;var ae=Math.round(ab.u2p(ah.value))+0.5;switch(ak){case"outside":at=this._bottom;ar=this._bottom+aj;break;case"inside":at=this._bottom-aj;ar=this._bottom;break;case"cross":at=this._bottom-aj;ar=this._bottom+aj;break;default:at=this._bottom;ar=this._bottom+aj;break}if(this.shadow){this.renderer.shadowRenderer.draw(am,[[ae,at],[ae,ar]],{lineCap:"butt",lineWidth:this.gridLineWidth,offset:this.gridLineWidth*0.75,depth:2,fill:false,closePath:false})}ai(ae,at,ae,ar)}break;case"yaxis":if(ah.showGridline&&this.drawGridlines&&((!ah.isMinorTick&&ab.drawMajorGridlines)||(ah.isMinorTick&&ab.drawMinorGridlines))){ai(this._right,ae,this._left,ae)}if(ah.showMark&&ah.mark&&((!ah.isMinorTick&&ab.drawMajorTickMarks)||(ah.isMinorTick&&ab.drawMinorTickMarks))){aj=ah.markSize;ak=ah.mark;var ae=Math.round(ab.u2p(ah.value))+0.5;switch(ak){case"outside":at=this._left-aj;ar=this._left;break;case"inside":at=this._left;ar=this._left+aj;break;case"cross":at=this._left-aj;ar=this._left+aj;break;default:at=this._left-aj;ar=this._left;break}if(this.shadow){this.renderer.shadowRenderer.draw(am,[[at,ae],[ar,ae]],{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}ai(at,ae,ar,ae,{strokeStyle:ab.borderColor})}break;case"x2axis":if(ah.showGridline&&this.drawGridlines&&((!ah.isMinorTick&&ab.drawMajorGridlines)||(ah.isMinorTick&&ab.drawMinorGridlines))){ai(ae,this._bottom,ae,this._top)}if(ah.showMark&&ah.mark&&((!ah.isMinorTick&&ab.drawMajorTickMarks)||(ah.isMinorTick&&ab.drawMinorTickMarks))){aj=ah.markSize;ak=ah.mark;var ae=Math.round(ab.u2p(ah.value))+0.5;switch(ak){case"outside":at=this._top-aj;ar=this._top;break;case"inside":at=this._top;ar=this._top+aj;break;case"cross":at=this._top-aj;ar=this._top+aj;break;default:at=this._top-aj;ar=this._top;break}if(this.shadow){this.renderer.shadowRenderer.draw(am,[[ae,at],[ae,ar]],{lineCap:"butt",lineWidth:this.gridLineWidth,offset:this.gridLineWidth*0.75,depth:2,fill:false,closePath:false})}ai(ae,at,ae,ar)}break;case"y2axis":if(ah.showGridline&&this.drawGridlines&&((!ah.isMinorTick&&ab.drawMajorGridlines)||(ah.isMinorTick&&ab.drawMinorGridlines))){ai(this._left,ae,this._right,ae)}if(ah.showMark&&ah.mark&&((!ah.isMinorTick&&ab.drawMajorTickMarks)||(ah.isMinorTick&&ab.drawMinorTickMarks))){aj=ah.markSize;ak=ah.mark;var ae=Math.round(ab.u2p(ah.value))+0.5;switch(ak){case"outside":at=this._right;ar=this._right+aj;break;case"inside":at=this._right-aj;ar=this._right;break;case"cross":at=this._right-aj;ar=this._right+aj;break;default:at=this._right;ar=this._right+aj;break}if(this.shadow){this.renderer.shadowRenderer.draw(am,[[at,ae],[ar,ae]],{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}ai(at,ae,ar,ae,{strokeStyle:ab.borderColor})}break;default:break}}}ah=null}ab=null;au=null}ag=["y3axis","y4axis","y5axis","y6axis","y7axis","y8axis","y9axis","yMidAxis"];for(var aq=7;aq>0;aq--){var ab=ap[ag[aq-1]];var au=ab._ticks;if(ab.show){var ac=au[ab.numberTicks-1];var af=au[0];var ad=ab.getLeft();var ao=[[ad,ac.getTop()+ac.getHeight()/2],[ad,af.getTop()+af.getHeight()/2+1]];if(this.shadow){this.renderer.shadowRenderer.draw(am,ao,{lineCap:"butt",fill:false,closePath:false})}ai(ao[0][0],ao[0][1],ao[1][0],ao[1][1],{lineCap:"butt",strokeStyle:ab.borderColor,lineWidth:ab.borderWidth});for(var an=au.length;an>0;an--){var ah=au[an-1];aj=ah.markSize;ak=ah.mark;var ae=Math.round(ab.u2p(ah.value))+0.5;if(ah.showMark&&ah.mark){switch(ak){case"outside":at=ad;ar=ad+aj;break;case"inside":at=ad-aj;ar=ad;break;case"cross":at=ad-aj;ar=ad+aj;break;default:at=ad;ar=ad+aj;break}ao=[[at,ae],[ar,ae]];if(this.shadow){this.renderer.shadowRenderer.draw(am,ao,{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}ai(at,ae,ar,ae,{strokeStyle:ab.borderColor})}ah=null}af=null}ab=null;au=null}am.restore();function ai(aB,aA,ay,ax,az){am.save();az=az||{};if(az.lineWidth==null||az.lineWidth!=0){H.extend(true,am,az);am.beginPath();am.moveTo(aB,aA);am.lineTo(ay,ax);am.stroke();am.restore()}}if(this.shadow){var ao=[[this._left,this._bottom],[this._right,this._bottom],[this._right,this._top]];this.renderer.shadowRenderer.draw(am,ao)}if(this.borderWidth!=0&&this.drawBorder){ai(this._left,this._top,this._right,this._top,{lineCap:"round",strokeStyle:ap.x2axis.borderColor,lineWidth:ap.x2axis.borderWidth});ai(this._right,this._top,this._right,this._bottom,{lineCap:"round",strokeStyle:ap.y2axis.borderColor,lineWidth:ap.y2axis.borderWidth});ai(this._right,this._bottom,this._left,this._bottom,{lineCap:"round",strokeStyle:ap.xaxis.borderColor,lineWidth:ap.xaxis.borderWidth});ai(this._left,this._bottom,this._left,this._top,{lineCap:"round",strokeStyle:ap.yaxis.borderColor,lineWidth:ap.yaxis.borderWidth})}am.restore();am=null;ap=null};H.jqplot.DivTitleRenderer=function(){};H.jqplot.DivTitleRenderer.prototype.init=function(ab){H.extend(true,this,ab)};H.jqplot.DivTitleRenderer.prototype.draw=function(){if(this._elem){this._elem.emptyForce();this._elem=null}var ae=this.renderer;var ad=document.createElement("div");this._elem=H(ad);this._elem.addClass("jqplot-title");if(!this.text){this.show=false;this._elem.height(0);this._elem.width(0)}else{if(this.text){var ab;if(this.color){ab=this.color}else{if(this.textColor){ab=this.textColor}}var ac={position:"absolute",top:"0px",left:"0px"};if(this._plotWidth){ac.width=this._plotWidth+"px"}if(this.fontSize){ac.fontSize=this.fontSize}if(typeof this.textAlign==="string"){ac.textAlign=this.textAlign}else{ac.textAlign="center"}if(ab){ac.color=ab}if(this.paddingBottom){ac.paddingBottom=this.paddingBottom}if(this.fontFamily){ac.fontFamily=this.fontFamily}this._elem.css(ac);if(this.escapeHtml){this._elem.text(this.text)}else{this._elem.html(this.text)}}}ad=null;return this._elem};H.jqplot.DivTitleRenderer.prototype.pack=function(){};var o=0.1;H.jqplot.LinePattern=function(ap,ak){var aj={dotted:[o,H.jqplot.config.dotGapLength],dashed:[H.jqplot.config.dashLength,H.jqplot.config.gapLength],solid:null};if(typeof ak==="string"){if(ak[0]==="."||ak[0]==="-"){var aq=ak;ak=[];for(var ai=0,af=aq.length;ai0)&&(aw>0)){au/=av;at/=av;while(true){var ax=aw*al;if(ax=ak.length){ae=0}al=ak[ae]}else{an=ar;am=ay;if((ae&1)==0){ap.lineTo(an,am)}else{ap.moveTo(an,am)}al-=av/aw;break}}}};var ac=function(){ap.beginPath()};var ag=function(){ad(ah,ab)};return{moveTo:ao,lineTo:ad,beginPath:ac,closePath:ag}};H.jqplot.LineRenderer=function(){this.shapeRenderer=new H.jqplot.ShapeRenderer();this.shadowRenderer=new H.jqplot.ShadowRenderer()};H.jqplot.LineRenderer.prototype.init=function(ac,ah){ac=ac||{};this._type="line";this.renderer.animation={show:false,direction:"left",speed:2500,_supported:true};this.renderer.smooth=false;this.renderer.tension=null;this.renderer.constrainSmoothing=true;this.renderer._smoothedData=[];this.renderer._smoothedPlotData=[];this.renderer._hiBandGridData=[];this.renderer._lowBandGridData=[];this.renderer._hiBandSmoothedData=[];this.renderer._lowBandSmoothedData=[];this.renderer.bandData=[];this.renderer.bands={show:false,hiData:[],lowData:[],color:this.color,showLines:false,fill:true,fillColor:null,_min:null,_max:null,interval:"3%"};var af={highlightMouseOver:ac.highlightMouseOver,highlightMouseDown:ac.highlightMouseDown,highlightColor:ac.highlightColor};delete (ac.highlightMouseOver);delete (ac.highlightMouseDown);delete (ac.highlightColor);H.extend(true,this.renderer,ac);this.renderer.options=ac;if(this.renderer.bandData.length>1&&(!ac.bands||ac.bands.show==null)){this.renderer.bands.show=true}else{if(ac.bands&&ac.bands.show==null&&ac.bands.interval!=null){this.renderer.bands.show=true}}if(this.fill){this.renderer.bands.show=false}if(this.renderer.bands.show){this.renderer.initBands.call(this,this.renderer.options,ah)}if(this._stack){this.renderer.smooth=false}var ag={lineJoin:this.lineJoin,lineCap:this.lineCap,fill:this.fill,isarc:false,strokeStyle:this.color,fillStyle:this.fillColor,lineWidth:this.lineWidth,linePattern:this.linePattern,closePath:this.fill};this.renderer.shapeRenderer.init(ag);var ad=ac.shadowOffset;if(ad==null){if(this.lineWidth>2.5){ad=1.25*(1+(Math.atan((this.lineWidth/2.5))/0.785398163-1)*0.6)}else{ad=1.25*Math.atan((this.lineWidth/2.5))/0.785398163}}var ab={lineJoin:this.lineJoin,lineCap:this.lineCap,fill:this.fill,isarc:false,angle:this.shadowAngle,offset:ad,alpha:this.shadowAlpha,depth:this.shadowDepth,lineWidth:this.lineWidth,linePattern:this.linePattern,closePath:this.fill};this.renderer.shadowRenderer.init(ab);this._areaPoints=[];this._boundingBox=[[],[]];if(!this.isTrendline&&this.fill||this.renderer.bands.show){this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColor=null;if(af.highlightMouseDown&&af.highlightMouseOver==null){af.highlightMouseOver=false}H.extend(true,this,{highlightMouseOver:af.highlightMouseOver,highlightMouseDown:af.highlightMouseDown,highlightColor:af.highlightColor});if(!this.highlightColor){var ae=(this.renderer.bands.show)?this.renderer.bands.fillColor:this.fillColor;this.highlightColor=H.jqplot.computeHighlightColors(ae)}if(this.highlighter){this.highlighter.show=false}}if(!this.isTrendline&&ah){ah.plugins.lineRenderer={};ah.postInitHooks.addOnce(v);ah.postDrawHooks.addOnce(Z);ah.eventListenerHooks.addOnce("jqplotMouseMove",g);ah.eventListenerHooks.addOnce("jqplotMouseDown",d);ah.eventListenerHooks.addOnce("jqplotMouseUp",Y);ah.eventListenerHooks.addOnce("jqplotClick",f);ah.eventListenerHooks.addOnce("jqplotRightClick",p)}};H.jqplot.LineRenderer.prototype.initBands=function(ae,ao){var af=ae.bandData||[];var ah=this.renderer.bands;ah.hiData=[];ah.lowData=[];var av=this.data;ah._max=null;ah._min=null;if(af.length==2){if(H.isArray(af[0][0])){var ai;var ab=0,al=0;for(var ap=0,am=af[0].length;apah._max)||ah._max==null){ah._max=ai[1]}if((ai[1]!=null&&ai[1]ah._max)||ah._max==null){ah._max=ai[1];al=1}if((ai[1]!=null&&ai[1]af[1][0])?0:1;var aw=(ad)?0:1;for(var ap=0,am=av.length;ap2&&!H.isArray(af[0][0])){var ad=(af[0][0]>af[0][1])?0:1;var aw=(ad)?0:1;for(var ap=0,am=af.length;apah._max)||ah._max==null){ah._max=ag[ap][1]}}for(var ap=0,am=aj.length;ap0){aL=Math.abs((aj[aK][1]-aj[aK-1][1])/(aj[aK][0]-aj[aK-1][0]))}ag=aL/aA+ay;aG=az*w(ag)-az*w(ay)+aM;aN=(aI+aG)/2}else{aN=aO}for(aE=0;aE2){var ai;if(this.renderer.constrainSmoothing){ai=F.call(this,this.gridData);this.renderer._smoothedData=ai[0];this.renderer._smoothedPlotData=ai[1];if(ae.show){ai=F.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ai[0];ai=F.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ai[0]}ai=null}else{ai=B.call(this,this.gridData);this.renderer._smoothedData=ai[0];this.renderer._smoothedPlotData=ai[1];if(ae.show){ai=B.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ai[0];ai=B.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ai[0]}ai=null}}};H.jqplot.LineRenderer.prototype.makeGridData=function(ai,ak){var ag=this._xaxis.series_u2p;var ab=this._yaxis.series_u2p;var al=[];var ad=[];this.renderer._smoothedData=[];this.renderer._smoothedPlotData=[];this.renderer._hiBandGridData=[];this.renderer._lowBandGridData=[];this.renderer._hiBandSmoothedData=[];this.renderer._lowBandSmoothedData=[];var af=this.renderer.bands;var ac=false;for(var ah=0;ah2){var aj;if(this.renderer.constrainSmoothing){aj=F.call(this,al);this.renderer._smoothedData=aj[0];this.renderer._smoothedPlotData=aj[1];if(af.show){aj=F.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=aj[0];aj=F.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=aj[0]}aj=null}else{aj=B.call(this,al);this.renderer._smoothedData=aj[0];this.renderer._smoothedPlotData=aj[1];if(af.show){aj=B.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=aj[0];aj=B.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=aj[0]}aj=null}}return al};H.jqplot.LineRenderer.prototype.draw=function(aq,aC,ac,av){var aw;var ak=H.extend(true,{},ac);var ae=(ak.shadow!=r)?ak.shadow:this.shadow;var aD=(ak.showLine!=r)?ak.showLine:this.showLine;var au=(ak.fill!=r)?ak.fill:this.fill;var ab=(ak.fillAndStroke!=r)?ak.fillAndStroke:this.fillAndStroke;var al,ar,ao,ay;aq.save();if(aC.length){if(aD){if(au){if(this.fillToZero){var az=this.negativeColor;if(!this.useNegativeColors){az=ak.fillStyle}var ai=false;var aj=ak.fillStyle;if(ab){var aB=aC.slice(0)}if(this.index==0||!this._stack){var ap=[];var aF=(this.renderer.smooth)?this.renderer._smoothedPlotData:this._plotData;this._areaPoints=[];var aA=this._yaxis.series_u2p(this.fillToValue);var ad=this._xaxis.series_u2p(this.fillToValue);ak.closePath=true;if(this.fillAxis=="y"){ap.push([aC[0][0],aA]);this._areaPoints.push([aC[0][0],aA]);for(var aw=0;aw0;aw--){aC.push(an[aw-1])}if(ae){this.renderer.shadowRenderer.draw(aq,aC,ak)}this._areaPoints=aC;this.renderer.shapeRenderer.draw(aq,aC,ak)}}else{if(ab){var aB=aC.slice(0)}if(this.index==0||!this._stack){var af=aq.canvas.height;aC.unshift([aC[0][0],af]);var ax=aC.length;aC.push([aC[ax-1][0],af])}else{var an=this._prevGridData;for(var aw=an.length;aw>0;aw--){aC.push(an[aw-1])}}this._areaPoints=aC;if(ae){this.renderer.shadowRenderer.draw(aq,aC,ak)}this.renderer.shapeRenderer.draw(aq,aC,ak)}if(ab){var at=H.extend(true,{},ak,{fill:false,closePath:false});this.renderer.shapeRenderer.draw(aq,aB,at);if(this.markerRenderer.show){if(this.renderer.smooth){aB=this.gridData}for(aw=0;awam[0]||al==null){al=am[0]}if(ayam[1]||ar==null){ar=am[1]}}if(this.type==="line"&&this.renderer.bands.show){ay=this._yaxis.series_u2p(this.renderer.bands._min);ar=this._yaxis.series_u2p(this.renderer.bands._max)}this._boundingBox=[[al,ay],[ao,ar]];if(this.markerRenderer.show&&!au){if(this.renderer.smooth){aC=this.gridData}for(aw=0;awai){ai=ad}}}af=null;ag=null;if(ab){ac=this._label._elem.outerWidth(true);ah=this._label._elem.outerHeight(true)}if(this.name=="xaxis"){ai=ai+ah;this._elem.css({height:ai+"px",left:"0px",bottom:"0px"})}else{if(this.name=="x2axis"){ai=ai+ah;this._elem.css({height:ai+"px",left:"0px",top:"0px"})}else{if(this.name=="yaxis"){ai=ai+ac;this._elem.css({width:ai+"px",left:"0px",top:"0px"});if(ab&&this._label.constructor==H.jqplot.AxisLabelRenderer){this._label._elem.css("width",ac+"px")}}else{ai=ai+ac;this._elem.css({width:ai+"px",right:"0px",top:"0px"});if(ab&&this._label.constructor==H.jqplot.AxisLabelRenderer){this._label._elem.css("width",ac+"px")}}}}}};H.jqplot.LinearAxisRenderer.prototype.createTicks=function(ad){var aN=this._ticks;var aE=this.ticks;var at=this.name;var av=this._dataBounds;var ab=(this.name.charAt(0)==="x")?this._plotDimensions.width:this._plotDimensions.height;var ah;var a0,aC;var aj,ai;var aY,aU;var aB=this.min;var aZ=this.max;var aQ=this.numberTicks;var a4=this.tickInterval;var ag=30;this._scalefact=(Math.max(ab,ag+1)-ag)/300;if(aE.length){for(aU=0;aUthis.breakPoints[0]&&aI[0]<=this.breakPoints[1]){aO.show=false;aO.showGridline=false;aO.label=aI[1]}else{aO.label=aI[1]}}}else{aO.label=aI[1]}aO.setTick(aI[0],this.name);this._ticks.push(aO)}else{if(H.isPlainObject(aI)){H.extend(true,aO,aI);aO.axis=this.name;this._ticks.push(aO)}else{aO.value=aI;if(this.breakPoints){if(aI==this.breakPoints[0]){aO.label=this.breakTickLabel;aO._breakTick=true;aO.showGridline=false;aO.showMark=false}else{if(aI>this.breakPoints[0]&&aI<=this.breakPoints[1]){aO.show=false;aO.showGridline=false}}}aO.setTick(aI,this.name);this._ticks.push(aO)}}}this.numberTicks=aE.length;this.min=this._ticks[0].value;this.max=this._ticks[this.numberTicks-1].value;this.tickInterval=(this.max-this.min)/(this.numberTicks-1)}else{if(at=="xaxis"||at=="x2axis"){ab=this._plotDimensions.width}else{ab=this._plotDimensions.height}var aq=this.numberTicks;if(this.alignTicks){if(this.name==="x2axis"&&ad.axes.xaxis.show){aq=ad.axes.xaxis.numberTicks}else{if(this.name.charAt(0)==="y"&&this.name!=="yaxis"&&this.name!=="yMidAxis"&&ad.axes.yaxis.show){aq=ad.axes.yaxis.numberTicks}}}a0=((this.min!=null)?this.min:av.min);aC=((this.max!=null)?this.max:av.max);var ao=aC-a0;var aM,ar;var am;if(this.tickOptions==null||!this.tickOptions.formatString){this._overrideFormatString=true}if(this.min==null||this.max==null&&this.tickInterval==null&&!this.autoscale){if(this.forceTickAt0){if(a0>0){a0=0}if(aC<0){aC=0}}if(this.forceTickAt100){if(a0>100){a0=100}if(aC<100){aC=100}}var ay=false,aV=false;if(this.min!=null){ay=true}else{if(this.max!=null){aV=true}}var aJ=H.jqplot.LinearTickGenerator(a0,aC,this._scalefact,aq,ay,aV);var ap=(this.min!=null)?a0:a0+ao*(this.padMin-1);var aK=(this.max!=null)?aC:aC-ao*(this.padMax-1);if(a0aK){ap=(this.min!=null)?a0:a0-ao*(this.padMin-1);aK=(this.max!=null)?aC:aC+ao*(this.padMax-1);aJ=H.jqplot.LinearTickGenerator(ap,aK,this._scalefact,aq,ay,aV)}this.min=aJ[0];this.max=aJ[1];this.numberTicks=aJ[2];this._autoFormatString=aJ[3];this.tickInterval=aJ[4]}else{if(a0==aC){var ac=0.05;if(a0>0){ac=Math.max(Math.log(a0)/Math.LN10,0.05)}a0-=ac;aC+=ac}if(this.autoscale&&this.min==null&&this.max==null){var ae,af,al;var aw=false;var aH=false;var au={min:null,max:null,average:null,stddev:null};for(var aU=0;aUaW){aW=aL[aT]}}}var an=(aW-aA)/aW;if(aP.renderer.constructor==H.jqplot.BarRenderer){if(aA>=0&&(aP.fillToZero||an>0.1)){aw=true}else{aw=false;if(aP.fill&&aP.fillToZero&&aA<0&&aW>0){aH=true}else{aH=false}}}else{if(aP.fill){if(aA>=0&&(aP.fillToZero||an>0.1)){aw=true}else{if(aA<0&&aW>0&&aP.fillToZero){aw=false;aH=true}else{aw=false;aH=false}}}else{if(aA<0){aw=false}}}}}if(aw){this.numberTicks=2+Math.ceil((ab-(this.tickSpacing-1))/this.tickSpacing);this.min=0;aB=0;af=aC/(this.numberTicks-1);am=Math.pow(10,Math.abs(Math.floor(Math.log(af)/Math.LN10)));if(af/am==parseInt(af/am,10)){af+=am}this.tickInterval=Math.ceil(af/am)*am;this.max=this.tickInterval*(this.numberTicks-1)}else{if(aH){this.numberTicks=2+Math.ceil((ab-(this.tickSpacing-1))/this.tickSpacing);var aD=Math.ceil(Math.abs(a0)/ao*(this.numberTicks-1));var a3=this.numberTicks-1-aD;af=Math.max(Math.abs(a0/aD),Math.abs(aC/a3));am=Math.pow(10,Math.abs(Math.floor(Math.log(af)/Math.LN10)));this.tickInterval=Math.ceil(af/am)*am;this.max=this.tickInterval*a3;this.min=-this.tickInterval*aD}else{if(this.numberTicks==null){if(this.tickInterval){this.numberTicks=3+Math.ceil(ao/this.tickInterval)}else{this.numberTicks=2+Math.ceil((ab-(this.tickSpacing-1))/this.tickSpacing)}}if(this.tickInterval==null){af=ao/(this.numberTicks-1);if(af<1){am=Math.pow(10,Math.abs(Math.floor(Math.log(af)/Math.LN10)))}else{am=1}this.tickInterval=Math.ceil(af*am*this.pad)/am}else{am=1/this.tickInterval}ae=this.tickInterval*(this.numberTicks-1);al=(ae-ao)/2;if(this.min==null){this.min=Math.floor(am*(a0-al))/am}if(this.max==null){this.max=this.min+ae}}}var az=H.jqplot.getSignificantFigures(this.tickInterval);var aG;if(az.digitsLeft>=az.significantDigits){aG="%d"}else{var am=Math.max(0,5-az.digitsLeft);am=Math.min(am,az.digitsRight);aG="%."+am+"f"}this._autoFormatString=aG}else{aM=(this.min!=null)?this.min:a0-ao*(this.padMin-1);ar=(this.max!=null)?this.max:aC+ao*(this.padMax-1);ao=ar-aM;if(this.numberTicks==null){if(this.tickInterval!=null){this.numberTicks=Math.ceil((ar-aM)/this.tickInterval)+1}else{if(ab>100){this.numberTicks=parseInt(3+(ab-100)/75,10)}else{this.numberTicks=2}}}if(this.tickInterval==null){this.tickInterval=ao/(this.numberTicks-1)}if(this.max==null){ar=aM+this.tickInterval*(this.numberTicks-1)}if(this.min==null){aM=ar-this.tickInterval*(this.numberTicks-1)}var az=H.jqplot.getSignificantFigures(this.tickInterval);var aG;if(az.digitsLeft>=az.significantDigits){aG="%d"}else{var am=Math.max(0,5-az.digitsLeft);am=Math.min(am,az.digitsRight);aG="%."+am+"f"}this._autoFormatString=aG;this.min=aM;this.max=ar}if(this.renderer.constructor==H.jqplot.LinearAxisRenderer&&this._autoFormatString==""){ao=this.max-this.min;var a1=new this.tickRenderer(this.tickOptions);var aF=a1.formatString||H.jqplot.config.defaultTickFormatString;var aF=aF.match(H.jqplot.sprintf.regex)[0];var aX=0;if(aF){if(aF.search(/[fFeEgGpP]/)>-1){var aS=aF.match(/\%\.(\d{0,})?[eEfFgGpP]/);if(aS){aX=parseInt(aS[1],10)}else{aX=6}}else{if(aF.search(/[di]/)>-1){aX=0}}var ak=Math.pow(10,-aX);if(this.tickIntervalthis.breakPoints[0]&&authis.breakPoints[0]&&authis.breakPoints[0]&&au=this.breakPoints[1]){return(au-an)*ae/af}else{return(au+this.breakPoints[1]-this.breakPoints[0]-an)*ae/af}};this.series_p2u=function(au){return au*af/ae+an}}}else{this.p2u=function(au){return(au-ag)*af/ae+am};this.u2p=function(au){return(au-am)*ae/af+ag};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(au){return(au-am)*ae/af};this.series_p2u=function(au){return au*af/ae+am}}else{this.series_u2p=function(au){return(au-an)*ae/af};this.series_p2u=function(au){return au*af/ae+an}}}if(this.show){if(this.name=="xaxis"||this.name=="x2axis"){for(var ao=0;ao0){ab=-aj._textRenderer.height*Math.cos(-aj._textRenderer.angle)/2}else{ab=-aj.getHeight()+aj._textRenderer.height*Math.cos(aj._textRenderer.angle)/2}break;case"middle":ab=-aj.getHeight()/2;break;default:ab=-aj.getHeight()/2;break}}else{ab=-aj.getHeight()/2}var at=this.u2p(aj.value)+ab+"px";aj._elem.css("top",at);aj.pack()}}if(ak){var ap=this._label._elem.outerHeight(true);this._label._elem.css("top",ai-ae/2-ap/2+"px");if(this.name=="yaxis"){this._label._elem.css("left","0px")}else{this._label._elem.css("right","0px")}this._label.pack()}}}ar=null};function h(ac){var ab;ac=Math.abs(ac);if(ac>=10){ab="%d"}else{if(ac>1){if(ac===parseInt(ac,10)){ab="%d"}else{ab="%.1f"}}else{var ad=-Math.floor(Math.log(ac)/Math.LN10);ab="%."+ad+"f"}}return ab}var a=[0.1,0.2,0.3,0.4,0.5,0.8,1,2,3,4,5];var b=function(ac){var ab=a.indexOf(ac);if(ab>0){return a[ab-1]}else{return a[a.length-1]/100}};var i=function(ac){var ab=a.indexOf(ac);if(ab5){ab=10*ad}else{if(ag>2){ab=5*ad}else{if(ag>1){ab=2*ad}else{ab=ad}}}}else{if(ag>5){ab=10*ad}else{if(ag>4){ab=5*ad}else{if(ag>3){ab=4*ad}else{if(ag>2){ab=3*ad}else{if(ag>1){ab=2*ad}else{ab=ad}}}}}}return ab}function M(ac,ab){ab=ab||1;var ae=Math.floor(Math.log(ac)/Math.LN10);var ag=Math.pow(10,ae);var af=ac/ag;var ad;af=af/ab;if(af<=0.38){ad=0.1}else{if(af<=1.6){ad=0.2}else{if(af<=4){ad=0.5}else{if(af<=8){ad=1}else{if(af<=16){ad=2}else{ad=5}}}}}return ad*ag}function t(ad,ac){var af=Math.floor(Math.log(ad)/Math.LN10);var ah=Math.pow(10,af);var ag=ad/ah;var ab;var ae;ag=ag/ac;if(ag<=0.38){ae=0.1}else{if(ag<=1.6){ae=0.2}else{if(ag<=4){ae=0.5}else{if(ag<=8){ae=1}else{if(ag<=16){ae=2}else{ae=5}}}}}ab=ae*ah;return[ab,ae,ah]}H.jqplot.LinearTickGenerator=function(ah,ak,ad,ae,ai,al){ai=(ai===null)?false:ai;al=(al===null||ai)?false:al;if(ah===ak){ak=(ak)?0:1}ad=ad||1;if(akam){am=av}if(ac>au){au=ac}})}ah.width=am+Number(ao);ah.height=au+Number(aq);var ae=ah.getContext("2d");ae.save();ae.fillStyle=af;ae.fillRect(0,0,ah.width,ah.height);ae.restore();ae.translate(an,al);ae.textAlign="left";ae.textBaseline="top";function aw(ay){var az=parseInt(H(ay).css("line-height"),10);if(isNaN(az)){az=parseInt(H(ay).css("font-size"),10)*1.2}return az}function ax(az,ay,aM,aA,aI,aB){var aK=aw(az);var aE=H(az).innerWidth();var aF=H(az).innerHeight();var aH=aM.split(/\s+/);var aL=aH.length;var aJ="";var aG=[];var aO=aI;var aN=aA;for(var aD=0;aDaE){aG.push(aD);aJ="";aD--}}if(aG.length===0){if(H(az).css("textAlign")==="center"){aN=aA+(aB-ay.measureText(aJ).width)/2-an}ay.fillText(aM,aN,aI)}else{aJ=aH.slice(0,aG[0]).join(" ");if(H(az).css("textAlign")==="center"){aN=aA+(aB-ay.measureText(aJ).width)/2-an}ay.fillText(aJ,aN,aO);aO+=aK;for(var aD=1,aC=aG.length;aD0){ae.strokeRect(aC,aF,H(aA).innerWidth(),H(aA).innerHeight())}H(aA).find("div.jqplot-table-legend-swatch-outline").each(function(){var aO=H(this);ae.strokeStyle=aO.css("border-top-color");var aK=aC+aO.position().left;var aL=aF+aO.position().top;ae.strokeRect(aK,aL,aO.innerWidth(),aO.innerHeight());aK+=parseInt(aO.css("padding-left"),10);aL+=parseInt(aO.css("padding-top"),10);var aN=aO.innerHeight()-2*parseInt(aO.css("padding-top"),10);var aJ=aO.innerWidth()-2*parseInt(aO.css("padding-left"),10);var aM=aO.children("div.jqplot-table-legend-swatch");ae.fillStyle=aM.css("background-color");ae.fillRect(aK,aL,aJ,aN)});H(aA).find("td.jqplot-table-legend-label").each(function(){var aL=H(this);var aJ=aC+aL.position().left;var aK=aF+aL.position().top+parseInt(aL.css("padding-top"),10);ae.font=aL.jqplotGetComputedFontStyle();ae.fillStyle=aL.css("color");ax(aL,ae,aL.text(),aJ,aK,aG)});var aB=null}else{if(aH=="canvas"){ae.drawImage(aA,aC,aF)}}}}H(this).children().each(function(){ap(this,ao,aq)});return ah};H.fn.jqplotToImageStr=function(ac){var ab=H(this).jqplotToImageCanvas(ac);if(ab){return ab.toDataURL("image/png")}else{return null}};H.fn.jqplotToImageElem=function(ab){var ac=document.createElement("img");var ad=H(this).jqplotToImageStr(ab);ac.src=ad;return ac};H.fn.jqplotToImageElemStr=function(ab){var ac="";return ac};H.fn.jqplotSaveImage=function(){var ab=H(this).jqplotToImageStr({});if(ab){window.location.href=ab.replace("image/png","image/octet-stream")}};H.fn.jqplotViewImage=function(){var ac=H(this).jqplotToImageElemStr({});var ad=H(this).jqplotToImageStr({});if(ac){var ab=window.open("");ab.document.open("image/png");ab.document.write(ac);ab.document.close();ab=null}};var aa=function(){this.syntax=aa.config.syntax;this._type="jsDate";this.proxy=new Date();this.options={};this.locale=aa.regional.getLocale();this.formatString="";this.defaultCentury=aa.config.defaultCentury;switch(arguments.length){case 0:break;case 1:if(j(arguments[0])=="[object Object]"&&arguments[0]._type!="jsDate"){var ad=this.options=arguments[0];this.syntax=ad.syntax||this.syntax;this.defaultCentury=ad.defaultCentury||this.defaultCentury;this.proxy=aa.createDate(ad.date)}else{this.proxy=aa.createDate(arguments[0])}break;default:var ab=[];for(var ac=0;ac0?"floor":"ceil"](ae))};aa.prototype.getAbbrDayName=function(){return aa.regional[this.locale]["dayNamesShort"][this.proxy.getDay()]};aa.prototype.getAbbrMonthName=function(){return aa.regional[this.locale]["monthNamesShort"][this.proxy.getMonth()]};aa.prototype.getAMPM=function(){return this.proxy.getHours()>=12?"PM":"AM"};aa.prototype.getAmPm=function(){return this.proxy.getHours()>=12?"pm":"am"};aa.prototype.getCentury=function(){return parseInt(this.proxy.getFullYear()/100,10)};aa.prototype.getDate=function(){return this.proxy.getDate()};aa.prototype.getDay=function(){return this.proxy.getDay()};aa.prototype.getDayOfWeek=function(){var ab=this.proxy.getDay();return ab===0?7:ab};aa.prototype.getDayOfYear=function(){var ac=this.proxy;var ab=ac-new Date(""+ac.getFullYear()+"/1/1 GMT");ab+=ac.getTimezoneOffset()*60000;ac=null;return parseInt(ab/60000/60/24,10)+1};aa.prototype.getDayName=function(){return aa.regional[this.locale]["dayNames"][this.proxy.getDay()]};aa.prototype.getFullWeekOfYear=function(){var ae=this.proxy;var ab=this.getDayOfYear();var ad=6-ae.getDay();var ac=parseInt((ab+ad)/7,10);return ac};aa.prototype.getFullYear=function(){return this.proxy.getFullYear()};aa.prototype.getGmtOffset=function(){var ab=this.proxy.getTimezoneOffset()/60;var ac=ab<0?"+":"-";ab=Math.abs(ab);return ac+J(Math.floor(ab),2)+":"+J((ab%1)*60,2)};aa.prototype.getHours=function(){return this.proxy.getHours()};aa.prototype.getHours12=function(){var ab=this.proxy.getHours();return ab>12?ab-12:(ab==0?12:ab)};aa.prototype.getIsoWeek=function(){var ae=this.proxy;var ad=ae.getWeekOfYear();var ab=(new Date(""+ae.getFullYear()+"/1/1")).getDay();var ac=ad+(ab>4||ab<=1?0:1);if(ac==53&&(new Date(""+ae.getFullYear()+"/12/31")).getDay()<4){ac=1}else{if(ac===0){ae=new aa(new Date(""+(ae.getFullYear()-1)+"/12/31"));ac=ae.getIsoWeek()}}ae=null;return ac};aa.prototype.getMilliseconds=function(){return this.proxy.getMilliseconds()};aa.prototype.getMinutes=function(){return this.proxy.getMinutes()};aa.prototype.getMonth=function(){return this.proxy.getMonth()};aa.prototype.getMonthName=function(){return aa.regional[this.locale]["monthNames"][this.proxy.getMonth()]};aa.prototype.getMonthNumber=function(){return this.proxy.getMonth()+1};aa.prototype.getSeconds=function(){return this.proxy.getSeconds()};aa.prototype.getShortYear=function(){return this.proxy.getYear()%100};aa.prototype.getTime=function(){return this.proxy.getTime()};aa.prototype.getTimezoneAbbr=function(){return this.proxy.toString().replace(/^.*\(([^)]+)\)$/,"$1")};aa.prototype.getTimezoneName=function(){var ab=/(?:\((.+)\)$| ([A-Z]{3}) )/.exec(this.toString());return ab[1]||ab[2]||"GMT"+this.getGmtOffset()};aa.prototype.getTimezoneOffset=function(){return this.proxy.getTimezoneOffset()};aa.prototype.getWeekOfYear=function(){var ab=this.getDayOfYear();var ad=7-this.getDayOfWeek();var ac=parseInt((ab+ad)/7,10);return ac};aa.prototype.getUnix=function(){return Math.round(this.proxy.getTime()/1000,0)};aa.prototype.getYear=function(){return this.proxy.getYear()};aa.prototype.next=function(ab){ab=ab||"day";return this.clone().add(1,ab)};aa.prototype.set=function(){switch(arguments.length){case 0:this.proxy=new Date();break;case 1:if(j(arguments[0])=="[object Object]"&&arguments[0]._type!="jsDate"){var ad=this.options=arguments[0];this.syntax=ad.syntax||this.syntax;this.defaultCentury=ad.defaultCentury||this.defaultCentury;this.proxy=aa.createDate(ad.date)}else{this.proxy=aa.createDate(arguments[0])}break;default:var ab=[];for(var ac=0;ac0?"floor":"ceil"](ab/12));var ac=ad.getMonth()+(ab%12);if(ac==12){ac=0;ad.setYear(ad.getFullYear()+1)}else{if(ac==-1){ac=11;ad.setYear(ad.getFullYear()-1)}}ad.setMonth(ac)},diff:function(af,ad){var ab=af.getFullYear()-ad.getFullYear();var ac=af.getMonth()-ad.getMonth()+(ab*12);var ae=af.getDate()-ad.getDate();return ac+(ae/30)}},year:{add:function(ac,ab){ac.setYear(ac.getFullYear()+Math[ab>0?"floor":"ceil"](ab))},diff:function(ac,ab){return A.month.diff(ac,ab)/12}}};for(var T in A){if(T.substring(T.length-1)!="s"){A[T+"s"]=A[T]}}var D=function(af,ae,ac){if(aa.formats[ac]["shortcuts"][ae]){return aa.strftime(af,aa.formats[ac]["shortcuts"][ae],ac)}else{var ab=(aa.formats[ac]["codes"][ae]||"").split(".");var ad=af["get"+ab[0]]?af["get"+ab[0]]():"";if(ab[1]){ad=J(ad,ab[1])}return ad}};aa.strftime=function(ah,ae,ad,ai){var ac="perl";var ag=aa.regional.getLocale();if(ad&&aa.formats.hasOwnProperty(ad)){ac=ad}else{if(ad&&aa.regional.hasOwnProperty(ad)){ag=ad}}if(ai&&aa.formats.hasOwnProperty(ai)){ac=ai}else{if(ai&&aa.regional.hasOwnProperty(ai)){ag=ai}}if(j(ah)!="[object Object]"||ah._type!="jsDate"){ah=new aa(ah);ah.locale=ag}if(!ae){ae=ah.formatString||aa.regional[ag]["formatString"]}var ab=ae||"%Y-%m-%d",aj="",af;while(ab.length>0){if(af=ab.match(aa.formats[ac].codes.matcher)){aj+=ab.slice(0,af.index);aj+=(af[1]||"")+D(ah,af[2],ac);ab=ab.slice(af.index+af[0].length)}else{aj+=ab;ab=""}}return aj};aa.formats={ISO:"%Y-%m-%dT%H:%M:%S.%N%G",SQL:"%Y-%m-%d %H:%M:%S"};aa.formats.perl={codes:{matcher:/()%(#?(%|[a-z]))/i,Y:"FullYear",y:"ShortYear.2",m:"MonthNumber.2","#m":"MonthNumber",B:"MonthName",b:"AbbrMonthName",d:"Date.2","#d":"Date",e:"Date",A:"DayName",a:"AbbrDayName",w:"Day",H:"Hours.2","#H":"Hours",I:"Hours12.2","#I":"Hours12",p:"AMPM",M:"Minutes.2","#M":"Minutes",S:"Seconds.2","#S":"Seconds",s:"Unix",N:"Milliseconds.3","#N":"Milliseconds",O:"TimezoneOffset",Z:"TimezoneName",G:"GmtOffset"},shortcuts:{F:"%Y-%m-%d",T:"%H:%M:%S",X:"%H:%M:%S",x:"%m/%d/%y",D:"%m/%d/%y","#c":"%a %b %e %H:%M:%S %Y",v:"%e-%b-%Y",R:"%H:%M",r:"%I:%M:%S %p",t:"\t",n:"\n","%":"%"}};aa.formats.php={codes:{matcher:/()%((%|[a-z]))/i,a:"AbbrDayName",A:"DayName",d:"Date.2",e:"Date",j:"DayOfYear.3",u:"DayOfWeek",w:"Day",U:"FullWeekOfYear.2",V:"IsoWeek.2",W:"WeekOfYear.2",b:"AbbrMonthName",B:"MonthName",m:"MonthNumber.2",h:"AbbrMonthName",C:"Century.2",y:"ShortYear.2",Y:"FullYear",H:"Hours.2",I:"Hours12.2",l:"Hours12",p:"AMPM",P:"AmPm",M:"Minutes.2",S:"Seconds.2",s:"Unix",O:"TimezoneOffset",z:"GmtOffset",Z:"TimezoneAbbr"},shortcuts:{D:"%m/%d/%y",F:"%Y-%m-%d",T:"%H:%M:%S",X:"%H:%M:%S",x:"%m/%d/%y",R:"%H:%M",r:"%I:%M:%S %p",t:"\t",n:"\n","%":"%"}};aa.createDate=function(ad){if(ad==null){return new Date()}if(ad instanceof Date){return ad}if(typeof ad=="number"){return new Date(ad)}var ai=String(ad).replace(/^\s*(.+)\s*$/g,"$1");ai=ai.replace(/^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,4})/,"$1/$2/$3");ai=ai.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{4})/i,"$1 $2 $3");var ah=ai.match(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i);if(ah&&ah.length>3){var am=parseFloat(ah[3]);var ag=aa.config.defaultCentury+am;ag=String(ag);ai=ai.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i,ah[1]+" "+ah[2]+" "+ag)}ah=ai.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})[^0-9]/);function al(aq,ap){var aw=parseFloat(ap[1]);var av=parseFloat(ap[2]);var au=parseFloat(ap[3]);var at=aa.config.defaultCentury;var ao,an,ax,ar;if(aw>31){an=au;ax=av;ao=at+aw}else{an=av;ax=aw;ao=at+au}ar=ax+"/"+an+"/"+ao;return aq.replace(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})/,ar)}if(ah&&ah.length>3){ai=al(ai,ah)}var ah=ai.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})$/);if(ah&&ah.length>3){ai=al(ai,ah)}var af=0;var ac=aa.matchers.length;var ak,ab,aj=ai,ae;while(af31){ab=ah;ac=ag+ai}else{ab=ai;ac=ag+ah}var aj=W(ad[2],aa.regional[aa.regional.getLocale()]["monthNamesShort"]);if(aj==-1){aj=W(ad[2],aa.regional[aa.regional.getLocale()]["monthNames"])}ae.setFullYear(ac,aj,ab);ae.setHours(0,0,0,0);return ae}else{return af}}];function W(ad,ae){if(ae.indexOf){return ae.indexOf(ad)}for(var ab=0,ac=ae.length;ab=aj)?"":Array(1+aj-an.length>>>0).join(ak);return am?an+al:al+an}function ae(al){var ak=new String(al);for(var aj=10;aj>0;aj--){if(ak==(ak=ak.replace(/^(\d+)(\d{3})/,"$1"+H.jqplot.sprintf.thousandsSeparator+"$2"))){break}}return ak}function ad(ao,an,aq,al,am,ak){var ap=al-ao.length;if(ap>0){var aj=" ";if(ak){aj=" "}if(aq||!am){ao=ah(ao,al,aj,aq)}else{ao=ao.slice(0,an.length)+ah("",ap,"0",true)+ao.slice(an.length)}}return ao}function ai(ar,ak,ap,al,aj,ao,aq,an){var am=ar>>>0;ap=ap&&am&&{"2":"0b","8":"0","16":"0x"}[ak]||"";ar=ap+ah(am.toString(ak),ao||0,"0",false);return ad(ar,ap,al,aj,aq,an)}function ab(an,ao,al,aj,am,ak){if(aj!=null){an=an.slice(0,aj)}return ad(an,"",ao,al,am,ak)}var ac=arguments,af=0,ag=ac[af++];return ag.replace(H.jqplot.sprintf.regex,function(aG,aq,ar,av,aI,aD,ao){if(aG=="%%"){return"%"}var ax=false,at="",au=false,aF=false,ap=false,an=false;for(var aC=0;ar&&aC-1?6:(ao=="d")?0:void (0)}else{if(aD=="*"){aD=+ac[af++]}else{if(aD.charAt(0)=="*"){aD=+ac[aD.slice(1,-1)]}else{aD=+aD}}}var az=aq?ac[aq.slice(0,-1)]:ac[af++];switch(ao){case"s":if(az==null){return""}return ab(String(az),ax,av,aD,au,ap);case"c":return ab(String.fromCharCode(+az),ax,av,aD,au,ap);case"b":return ai(az,2,aF,ax,av,aD,au,ap);case"o":return ai(az,8,aF,ax,av,aD,au,ap);case"x":return ai(az,16,aF,ax,av,aD,au,ap);case"X":return ai(az,16,aF,ax,av,aD,au,ap).toUpperCase();case"u":return ai(az,10,aF,ax,av,aD,au,ap);case"i":var al=parseInt(+az,10);if(isNaN(al)){return""}var aB=al<0?"-":at;var aE=an?ae(String(Math.abs(al))):String(Math.abs(al));az=aB+ah(aE,aD,"0",false);return ad(az,aB,ax,av,au,ap);case"d":var al=Math.round(+az);if(isNaN(al)){return""}var aB=al<0?"-":at;var aE=an?ae(String(Math.abs(al))):String(Math.abs(al));az=aB+ah(aE,aD,"0",false);return ad(az,aB,ax,av,au,ap);case"e":case"E":case"f":case"F":case"g":case"G":var al=+az;if(isNaN(al)){return""}var aB=al<0?"-":at;var am=["toExponential","toFixed","toPrecision"]["efg".indexOf(ao.toLowerCase())];var aH=["toString","toUpperCase"]["eEfFgG".indexOf(ao)%2];var aE=Math.abs(al)[am](aD);aE=an?ae(aE):aE;az=aB+aE;var aw=ad(az,aB,ax,av,au,ap)[aH]();if(H.jqplot.sprintf.decimalMark!=="."&&H.jqplot.sprintf.decimalMark!==H.jqplot.sprintf.thousandsSeparator){return aw.replace(/\./,H.jqplot.sprintf.decimalMark)}else{return aw}case"p":case"P":var al=+az;if(isNaN(al)){return""}var aB=al<0?"-":at;var ay=String(Number(Math.abs(al)).toExponential()).split(/e|E/);var ak=(ay[0].indexOf(".")!=-1)?ay[0].length-1:ay[0].length;var aA=(ay[1]<0)?-ay[1]-1:0;if(Math.abs(al)<1){if(ak+aA<=aD){az=aB+Math.abs(al).toPrecision(ak)}else{if(ak<=aD-1){az=aB+Math.abs(al).toExponential(ak-1)}else{az=aB+Math.abs(al).toExponential(aD-1)}}}else{var aj=(ak<=aD)?ak:aD;az=aB+Math.abs(al).toPrecision(aj)}var aH=["toString","toUpperCase"]["pP".indexOf(ao)%2];return ad(az,aB,ax,av,au,ap)[aH]();case"n":return"";default:return aG}})};H.jqplot.sprintf.thousandsSeparator=",";H.jqplot.sprintf.decimalMark=".";H.jqplot.sprintf.regex=/%%|%(\d+\$)?([-+#0&\' ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([nAscboxXuidfegpEGP])/g;H.jqplot.getSignificantFigures=function(af){var ah=String(Number(Math.abs(af)).toExponential()).split(/e|E/);var ag=(ah[0].indexOf(".")!=-1)?ah[0].length-1:ah[0].length;var ac=(ah[1]<0)?-ah[1]-1:0;var ab=parseInt(ah[1],10);var ad=(ab+1>0)?ab+1:0;var ae=(ag<=ad)?0:ag-ab-1;return{significantDigits:ag,digitsLeft:ad,digitsRight:ae,zeros:ac,exponent:ab}};H.jqplot.getPrecision=function(ab){return H.jqplot.getSignificantFigures(ab).digitsRight}})(jQuery);var backCompat=$.uiBackCompat!==false;$.jqplot.effects={effect:{}};var dataSpace="jqplot.storage.";$.extend($.jqplot.effects,{version:"1.9pre",save:function(b,c){for(var a=0;a
      ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),a={width:b.width(),height:b.height()},d=document.activeElement;b.wrap(e);if(b[0]===d||$.contains(b[0],d)){$(d).focus()}e=b.parent();if(b.css("position")==="static"){e.css({position:"relative"});b.css({position:"relative"})}else{$.extend(c,{position:b.css("position"),zIndex:b.css("z-index")});$.each(["top","left","bottom","right"],function(f,g){c[g]=b.css(g);if(isNaN(parseInt(c[g],10))){c[g]="auto"}});b.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}b.css(a);return e.css(c).show()},removeWrapper:function(a){var b=document.activeElement;if(a.parent().is(".ui-effects-wrapper")){a.parent().replaceWith(a);if(a[0]===b||$.contains(a[0],b)){$(b).focus()}}return a}});function _normalizeArguments(b,a,c,d){if($.isPlainObject(b)){return b}b={effect:b};if(a===undefined){a={}}if($.isFunction(a)){d=a;c=null;a={}}if($.type(a)==="number"||$.fx.speeds[a]){d=c;c=a;a={}}if($.isFunction(c)){d=c;c=null}if(a){$.extend(b,a)}c=c||a.duration;b.duration=$.fx.off?0:typeof c==="number"?c:c in $.fx.speeds?$.fx.speeds[c]:$.fx.speeds._default;b.complete=d||a.complete;return b}function standardSpeed(a){if(!a||typeof a==="number"||$.fx.speeds[a]){return true}if(typeof a==="string"&&!$.jqplot.effects.effect[a]){if(backCompat&&$.jqplot.effects[a]){return false}return true}return false}$.fn.extend({jqplotEffect:function(i,j,b,h){var g=_normalizeArguments.apply(this,arguments),d=g.mode,e=g.queue,f=$.jqplot.effects.effect[g.effect],a=!f&&backCompat&&$.jqplot.effects[g.effect];if($.fx.off||!(f||a)){if(d){return this[d](g.duration,g.complete)}else{return this.each(function(){if(g.complete){g.complete.call(this)}})}}function c(m){var n=$(this),l=g.complete,o=g.mode;function k(){if($.isFunction(l)){l.call(n[0])}if($.isFunction(m)){m()}}if(n.is(":hidden")?o==="hide":o==="show"){k()}else{f.call(n[0],g,k)}}if(f){return e===false?this.each(c):this.queue(e||"fx",c)}else{return a.call(this,{options:g,duration:g.duration,callback:g.complete,mode:g.mode})}}});var rvertical=/up|down|vertical/,rpositivemotion=/up|left|vertical|horizontal/;$.jqplot.effects.effect.blind=function(c,h){var d=$(this),k=["position","top","bottom","left","right","height","width"],i=$.jqplot.effects.setMode(d,c.mode||"hide"),m=c.direction||"up",f=rvertical.test(m),e=f?"height":"width",j=f?"top":"left",p=rpositivemotion.test(m),g={},n=i==="show",b,a,l;if(d.parent().is(".ui-effects-wrapper")){$.jqplot.effects.save(d.parent(),k)}else{$.jqplot.effects.save(d,k)}d.show();l=parseInt(d.css("top"),10);b=$.jqplot.effects.createWrapper(d).css({overflow:"hidden"});a=f?b[e]()+l:b[e]();g[e]=n?String(a):"0";if(!p){d.css(f?"bottom":"right",0).css(f?"top":"left","").css({position:"absolute"});g[j]=n?"0":String(a)}if(n){b.css(e,0);if(!p){b.css(j,a)}}b.animate(g,{duration:c.duration,easing:c.easing,queue:false,complete:function(){if(i==="hide"){d.hide()}$.jqplot.effects.restore(d,k);$.jqplot.effects.removeWrapper(d);h()}})}; \ No newline at end of file diff --git a/phpmyadmin/js/jqplot/plugins/jqplot.barRenderer.js b/phpmyadmin/js/jqplot/plugins/jqplot.barRenderer.js new file mode 100644 index 000000000..f97ca6169 --- /dev/null +++ b/phpmyadmin/js/jqplot/plugins/jqplot.barRenderer.js @@ -0,0 +1 @@ +(function(d){d.jqplot.BarRenderer=function(){d.jqplot.LineRenderer.call(this)};d.jqplot.BarRenderer.prototype=new d.jqplot.LineRenderer();d.jqplot.BarRenderer.prototype.constructor=d.jqplot.BarRenderer;d.jqplot.BarRenderer.prototype.init=function(o,q){this.barPadding=8;this.barMargin=10;this.barDirection="vertical";this.barWidth=null;this.shadowOffset=2;this.shadowDepth=5;this.shadowAlpha=0.08;this.waterfall=false;this.groups=1;this.varyBarColor=false;this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColors=[];this.transposedData=true;this.renderer.animation={show:false,direction:"down",speed:3000,_supported:true};this._type="bar";if(o.highlightMouseDown&&o.highlightMouseOver==null){o.highlightMouseOver=false}d.extend(true,this,o);d.extend(true,this.renderer,o);this.fill=true;if(this.barDirection==="horizontal"&&this.rendererOptions.animation&&this.rendererOptions.animation.direction==null){this.renderer.animation.direction="left"}if(this.waterfall){this.fillToZero=false;this.disableStack=true}if(this.barDirection=="vertical"){this._primaryAxis="_xaxis";this._stackAxis="y";this.fillAxis="y"}else{this._primaryAxis="_yaxis";this._stackAxis="x";this.fillAxis="x"}this._highlightedPoint=null;this._plotSeriesInfo=null;this._dataColors=[];this._barPoints=[];var p={lineJoin:"miter",lineCap:"round",fill:true,isarc:false,strokeStyle:this.color,fillStyle:this.color,closePath:this.fill};this.renderer.shapeRenderer.init(p);var n={lineJoin:"miter",lineCap:"round",fill:true,isarc:false,angle:this.shadowAngle,offset:this.shadowOffset,alpha:this.shadowAlpha,depth:this.shadowDepth,closePath:this.fill};this.renderer.shadowRenderer.init(n);q.postInitHooks.addOnce(h);q.postDrawHooks.addOnce(j);q.eventListenerHooks.addOnce("jqplotMouseMove",b);q.eventListenerHooks.addOnce("jqplotMouseDown",a);q.eventListenerHooks.addOnce("jqplotMouseUp",l);q.eventListenerHooks.addOnce("jqplotClick",e);q.eventListenerHooks.addOnce("jqplotRightClick",m)};function g(t,p,o,w){if(this.rendererOptions.barDirection=="horizontal"){this._stackAxis="x";this._primaryAxis="_yaxis"}if(this.rendererOptions.waterfall==true){this._data=d.extend(true,[],this.data);var s=0;var u=(!this.rendererOptions.barDirection||this.rendererOptions.barDirection==="vertical"||this.transposedData===false)?1:0;for(var q=0;q0){this.data[q][u]+=this.data[q-1][u]}}this.data[this.data.length]=(u==1)?[this.data.length+1,s]:[s,this.data.length+1];this._data[this._data.length]=(u==1)?[this._data.length+1,s]:[s,this._data.length+1]}if(this.rendererOptions.groups>1){this.breakOnNull=true;var n=this.data.length;var v=parseInt(n/this.rendererOptions.groups,10);var r=0;for(var q=v;q570)?n[p]*0.8:n[p]+0.3*(255-n[p]);n[p]=parseInt(n[p],10)}q.push("rgb("+n[0]+","+n[1]+","+n[2]+")")}return q}function i(v,u,s,t,o){var q=v,w=v-1,n,p,r=(o==="x")?0:1;if(q>0){p=t.series[w]._plotData[u][r];if((s*p)<0){n=i(w,u,s,t,o)}else{n=t.series[w].gridData[u][r]}}else{n=(r===0)?t.series[q]._xaxis.series_u2p(0):t.series[q]._yaxis.series_u2p(0)}return n}d.jqplot.BarRenderer.prototype.draw=function(E,L,q,G){var I;var A=d.extend({},q);var w=(A.shadow!=undefined)?A.shadow:this.shadow;var O=(A.showLine!=undefined)?A.showLine:this.showLine;var F=(A.fill!=undefined)?A.fill:this.fill;var p=this.xaxis;var J=this.yaxis;var y=this._xaxis.series_u2p;var K=this._yaxis.series_u2p;var D,C;this._dataColors=[];this._barPoints=[];if(this.barWidth==null){this.renderer.setBarWidth.call(this)}var N=this._plotSeriesInfo=this.renderer.calcSeriesNumbers.call(this);var x=N[0];var v=N[1];var s=N[2];var H=[];if(this._stack){this._barNudge=0}else{this._barNudge=(-Math.abs(v/2-0.5)+s)*(this.barWidth+this.barPadding)}if(O){var u=new d.jqplot.ColorGenerator(this.negativeSeriesColors);var B=new d.jqplot.ColorGenerator(this.seriesColors);var M=u.get(this.index);if(!this.useNegativeColors){M=A.fillStyle}var t=A.fillStyle;var r;var P;var o;if(this.barDirection=="vertical"){for(var I=0;I0&&I=0){o=this._yaxis.series_u2p(0)}else{if(this._yaxis.min>0){o=E.canvas.height}else{o=0}}}else{if(this.waterfall&&I==this.gridData.length-1){if(this._yaxis.min<=0&&this._yaxis.max>=0){o=this._yaxis.series_u2p(0)}else{if(this._yaxis.min>0){o=E.canvas.height}else{o=0}}}else{o=E.canvas.height}}}}}if((this.fillToZero&&this._plotData[I][1]<0)||(this.waterfall&&this._data[I][1]<0)){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){A.fillStyle=u.next()}else{A.fillStyle=B.next()}}else{A.fillStyle=M}}else{if(this.varyBarColor&&!this._stack){A.fillStyle=B.next()}else{A.fillStyle=t}}if(!this.fillToZero||this._plotData[I][1]>=0){H.push([r-this.barWidth/2,o]);H.push([r-this.barWidth/2,L[I][1]]);H.push([r+this.barWidth/2,L[I][1]]);H.push([r+this.barWidth/2,o])}else{H.push([r-this.barWidth/2,L[I][1]]);H.push([r-this.barWidth/2,o]);H.push([r+this.barWidth/2,o]);H.push([r+this.barWidth/2,L[I][1]])}this._barPoints.push(H);if(w&&!this._stack){var z=d.extend(true,{},A);delete z.fillStyle;this.renderer.shadowRenderer.draw(E,H,z)}var n=A.fillStyle||this.color;this._dataColors.push(n);this.renderer.shapeRenderer.draw(E,H,A)}}else{if(this.barDirection=="horizontal"){for(var I=0;I0&&I=0){P=this._xaxis.series_u2p(0)}else{if(this._xaxis.min>0){P=0}else{P=0}}}else{if(this.waterfall&&I==this.gridData.length-1){if(this._xaxis.min<=0&&this._xaxis.max>=0){P=this._xaxis.series_u2p(0)}else{if(this._xaxis.min>0){P=0}else{P=E.canvas.width}}}else{P=0}}}}}if((this.fillToZero&&this._plotData[I][1]<0)||(this.waterfall&&this._data[I][1]<0)){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){A.fillStyle=u.next()}else{A.fillStyle=B.next()}}}else{if(this.varyBarColor&&!this._stack){A.fillStyle=B.next()}else{A.fillStyle=t}}if(!this.fillToZero||this._plotData[I][0]>=0){H.push([P,r+this.barWidth/2]);H.push([P,r-this.barWidth/2]);H.push([L[I][0],r-this.barWidth/2]);H.push([L[I][0],r+this.barWidth/2])}else{H.push([L[I][0],r+this.barWidth/2]);H.push([L[I][0],r-this.barWidth/2]);H.push([P,r-this.barWidth/2]);H.push([P,r+this.barWidth/2])}this._barPoints.push(H);if(w&&!this._stack){var z=d.extend(true,{},A);delete z.fillStyle;this.renderer.shadowRenderer.draw(E,H,z)}var n=A.fillStyle||this.color;this._dataColors.push(n);this.renderer.shapeRenderer.draw(E,H,A)}}}}if(this.highlightColors.length==0){this.highlightColors=d.jqplot.computeHighlightColors(this._dataColors)}else{if(typeof(this.highlightColors)=="string"){var N=this.highlightColors;this.highlightColors=[];for(var I=0;I=1024&&d<=6){f/=1024;d++}var e="%.1f";if(Math.floor(f)===f){e="%.0f"}return b.jqplot.sprintf(e+" "+c[d],f)};b.jqplot.byteFormatter=function(c){c=c||0;return function(d,e){if(typeof e==="number"){e=parseFloat(e)||0;return a(e,c)}else{return String(e)}}}})(jQuery); \ No newline at end of file diff --git a/phpmyadmin/js/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js b/phpmyadmin/js/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js new file mode 100644 index 000000000..5c72b7e2f --- /dev/null +++ b/phpmyadmin/js/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js @@ -0,0 +1 @@ +(function(a){a.jqplot.CanvasAxisLabelRenderer=function(b){this.angle=0;this.axis;this.show=true;this.showLabel=true;this.label="";this.fontFamily='"Trebuchet MS", Arial, Helvetica, sans-serif';this.fontSize="11pt";this.fontWeight="normal";this.fontStretch=1;this.textColor="#666666";this.enableFontSupport=true;this.pt2px=null;this._elem;this._ctx;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null};a.extend(true,this,b);if(b.angle==null&&this.axis!="xaxis"&&this.axis!="x2axis"){this.angle=-90}var c={fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily};if(this.pt2px){c.pt2px=this.pt2px}if(this.enableFontSupport){if(a.jqplot.support_canvas_text()){this._textRenderer=new a.jqplot.CanvasFontRenderer(c)}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}};a.jqplot.CanvasAxisLabelRenderer.prototype.init=function(b){a.extend(true,this,b);this._textRenderer.init({fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily})};a.jqplot.CanvasAxisLabelRenderer.prototype.getWidth=function(d){if(this._elem){return this._elem.outerWidth(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.sin(f.angle)*e)+Math.abs(Math.cos(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getHeight=function(d){if(this._elem){return this._elem.outerHeight(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.cos(f.angle)*e)+Math.abs(Math.sin(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getAngleRad=function(){var b=this.angle*Math.PI/180;return b};a.jqplot.CanvasAxisLabelRenderer.prototype.draw=function(c,f){if(this._elem){if(a.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==undefined){window.G_vmlCanvasManager.uninitElement(this._elem.get(0))}this._elem.emptyForce();this._elem=null}var e=f.canvasManager.getCanvas();this._textRenderer.setText(this.label,c);var b=this.getWidth(c);var d=this.getHeight(c);e.width=b;e.height=d;e.style.width=b;e.style.height=d;e=f.canvasManager.initCanvas(e);this._elem=a(e);this._elem.css({position:"absolute"});this._elem.addClass("jqplot-"+this.axis+"-label");e=null;return this._elem};a.jqplot.CanvasAxisLabelRenderer.prototype.pack=function(){this._textRenderer.draw(this._elem.get(0).getContext("2d"),this.label)}})(jQuery); \ No newline at end of file diff --git a/phpmyadmin/js/jqplot/plugins/jqplot.canvasTextRenderer.js b/phpmyadmin/js/jqplot/plugins/jqplot.canvasTextRenderer.js new file mode 100644 index 000000000..0bbe5c07c --- /dev/null +++ b/phpmyadmin/js/jqplot/plugins/jqplot.canvasTextRenderer.js @@ -0,0 +1 @@ +(function(a){a.jqplot.CanvasTextRenderer=function(b){this.fontStyle="normal";this.fontVariant="normal";this.fontWeight="normal";this.fontSize="10px";this.fontFamily="sans-serif";this.fontStretch=1;this.fillStyle="#666666";this.angle=0;this.textAlign="start";this.textBaseline="alphabetic";this.text;this.width;this.height;this.pt2px=1.28;a.extend(true,this,b);this.normalizedFontSize=this.normalizeFontSize(this.fontSize);this.setHeight()};a.jqplot.CanvasTextRenderer.prototype.init=function(b){a.extend(true,this,b);this.normalizedFontSize=this.normalizeFontSize(this.fontSize);this.setHeight()};a.jqplot.CanvasTextRenderer.prototype.normalizeFontSize=function(b){b=String(b);var c=parseFloat(b);if(b.indexOf("px")>-1){return c/this.pt2px}else{if(b.indexOf("pt")>-1){return c}else{if(b.indexOf("em")>-1){return c*12}else{if(b.indexOf("%")>-1){return c*12/100}else{return c/this.pt2px}}}}};a.jqplot.CanvasTextRenderer.prototype.fontWeight2Float=function(b){if(Number(b)){return b/400}else{switch(b){case"normal":return 1;break;case"bold":return 1.75;break;case"bolder":return 2.25;break;case"lighter":return 0.75;break;default:return 1;break}}};a.jqplot.CanvasTextRenderer.prototype.getText=function(){return this.text};a.jqplot.CanvasTextRenderer.prototype.setText=function(c,b){this.text=c;this.setWidth(b);return this};a.jqplot.CanvasTextRenderer.prototype.getWidth=function(b){return this.width};a.jqplot.CanvasTextRenderer.prototype.setWidth=function(c,b){if(!b){this.width=this.measure(c,this.text)}else{this.width=b}return this};a.jqplot.CanvasTextRenderer.prototype.getHeight=function(b){return this.height};a.jqplot.CanvasTextRenderer.prototype.setHeight=function(b){if(!b){this.height=this.normalizedFontSize*this.pt2px}else{this.height=b}return this};a.jqplot.CanvasTextRenderer.prototype.letter=function(b){return this.letters[b]};a.jqplot.CanvasTextRenderer.prototype.ascent=function(){return this.normalizedFontSize};a.jqplot.CanvasTextRenderer.prototype.descent=function(){return 7*this.normalizedFontSize/25};a.jqplot.CanvasTextRenderer.prototype.measure=function(d,g){var f=0;var b=g.length;for(var e=0;e30)?2:2+(30-this.normalizedFontSize)/20;s.lineWidth=t*k*this.fontWeight2Float(this.fontWeight);for(var g=0;g":{width:24,points:[[4,18],[20,9],[4,0]]},"?":{width:18,points:[[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],[-1,-1],[9,2],[8,1],[9,0],[10,1],[9,2]]},"@":{width:27,points:[[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],[-1,-1],[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],[-1,-1],[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],[-1,-1],[19,16],[18,8],[18,6],[19,5]]},A:{width:18,points:[[9,21],[1,0],[-1,-1],[9,21],[17,0],[-1,-1],[4,7],[14,7]]},B:{width:21,points:[[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[-1,-1],[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]]},C:{width:21,points:[[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]]},D:{width:21,points:[[4,21],[4,0],[-1,-1],[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]]},E:{width:19,points:[[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11],[-1,-1],[4,0],[17,0]]},F:{width:18,points:[[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11]]},G:{width:21,points:[[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],[-1,-1],[13,8],[18,8]]},H:{width:22,points:[[4,21],[4,0],[-1,-1],[18,21],[18,0],[-1,-1],[4,11],[18,11]]},I:{width:8,points:[[4,21],[4,0]]},J:{width:16,points:[[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]]},K:{width:21,points:[[4,21],[4,0],[-1,-1],[18,21],[4,7],[-1,-1],[9,12],[18,0]]},L:{width:17,points:[[4,21],[4,0],[-1,-1],[4,0],[16,0]]},M:{width:24,points:[[4,21],[4,0],[-1,-1],[4,21],[12,0],[-1,-1],[20,21],[12,0],[-1,-1],[20,21],[20,0]]},N:{width:22,points:[[4,21],[4,0],[-1,-1],[4,21],[18,0],[-1,-1],[18,21],[18,0]]},O:{width:22,points:[[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]]},P:{width:21,points:[[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]]},Q:{width:22,points:[[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],[-1,-1],[12,4],[18,-2]]},R:{width:21,points:[[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],[-1,-1],[11,11],[18,0]]},S:{width:20,points:[[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]]},T:{width:16,points:[[8,21],[8,0],[-1,-1],[1,21],[15,21]]},U:{width:22,points:[[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]]},V:{width:18,points:[[1,21],[9,0],[-1,-1],[17,21],[9,0]]},W:{width:24,points:[[2,21],[7,0],[-1,-1],[12,21],[7,0],[-1,-1],[12,21],[17,0],[-1,-1],[22,21],[17,0]]},X:{width:20,points:[[3,21],[17,0],[-1,-1],[17,21],[3,0]]},Y:{width:18,points:[[1,21],[9,11],[9,0],[-1,-1],[17,21],[9,11]]},Z:{width:20,points:[[17,21],[3,0],[-1,-1],[3,21],[17,21],[-1,-1],[3,0],[17,0]]},"[":{width:14,points:[[4,25],[4,-7],[-1,-1],[5,25],[5,-7],[-1,-1],[4,25],[11,25],[-1,-1],[4,-7],[11,-7]]},"\\":{width:14,points:[[0,21],[14,-3]]},"]":{width:14,points:[[9,25],[9,-7],[-1,-1],[10,25],[10,-7],[-1,-1],[3,25],[10,25],[-1,-1],[3,-7],[10,-7]]},"^":{width:16,points:[[6,15],[8,18],[10,15],[-1,-1],[3,12],[8,17],[13,12],[-1,-1],[8,17],[8,0]]},_:{width:16,points:[[0,-2],[16,-2]]},"`":{width:10,points:[[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]]},a:{width:19,points:[[15,14],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},b:{width:19,points:[[4,21],[4,0],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]]},c:{width:18,points:[[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},d:{width:19,points:[[15,21],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},e:{width:18,points:[[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},f:{width:12,points:[[10,21],[8,21],[6,20],[5,17],[5,0],[-1,-1],[2,14],[9,14]]},g:{width:19,points:[[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},h:{width:19,points:[[4,21],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]]},i:{width:8,points:[[3,21],[4,20],[5,21],[4,22],[3,21],[-1,-1],[4,14],[4,0]]},j:{width:10,points:[[5,21],[6,20],[7,21],[6,22],[5,21],[-1,-1],[6,14],[6,-3],[5,-6],[3,-7],[1,-7]]},k:{width:17,points:[[4,21],[4,0],[-1,-1],[14,14],[4,4],[-1,-1],[8,8],[15,0]]},l:{width:8,points:[[4,21],[4,0]]},m:{width:30,points:[[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],[-1,-1],[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]]},n:{width:19,points:[[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]]},o:{width:19,points:[[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]]},p:{width:19,points:[[4,14],[4,-7],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]]},q:{width:19,points:[[15,14],[15,-7],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},r:{width:13,points:[[4,14],[4,0],[-1,-1],[4,8],[5,11],[7,13],[9,14],[12,14]]},s:{width:17,points:[[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]]},t:{width:12,points:[[5,21],[5,4],[6,1],[8,0],[10,0],[-1,-1],[2,14],[9,14]]},u:{width:19,points:[[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],[-1,-1],[15,14],[15,0]]},v:{width:16,points:[[2,14],[8,0],[-1,-1],[14,14],[8,0]]},w:{width:22,points:[[3,14],[7,0],[-1,-1],[11,14],[7,0],[-1,-1],[11,14],[15,0],[-1,-1],[19,14],[15,0]]},x:{width:17,points:[[3,14],[14,0],[-1,-1],[14,14],[3,0]]},y:{width:16,points:[[2,14],[8,0],[-1,-1],[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]]},z:{width:17,points:[[14,14],[3,0],[-1,-1],[3,14],[14,14],[-1,-1],[3,0],[14,0]]},"{":{width:14,points:[[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],[-1,-1],[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],[-1,-1],[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]]},"|":{width:8,points:[[4,25],[4,-7]]},"}":{width:14,points:[[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],[-1,-1],[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],[-1,-1],[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]]},"~":{width:24,points:[[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],[-1,-1],[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]]}};a.jqplot.CanvasFontRenderer=function(b){b=b||{};if(!b.pt2px){b.pt2px=1.5}a.jqplot.CanvasTextRenderer.call(this,b)};a.jqplot.CanvasFontRenderer.prototype=new a.jqplot.CanvasTextRenderer({});a.jqplot.CanvasFontRenderer.prototype.constructor=a.jqplot.CanvasFontRenderer;a.jqplot.CanvasFontRenderer.prototype.measure=function(c,e){var d=this.fontSize+" "+this.fontFamily;c.save();c.font=d;var b=c.measureText(e).width;c.restore();return b};a.jqplot.CanvasFontRenderer.prototype.draw=function(e,g){var c=0;var h=this.height*0.72;e.save();var d,b;if((-Math.PI/2<=this.angle&&this.angle<=0)||(Math.PI*3/2<=this.angle&&this.angle<=Math.PI*2)){d=0;b=-Math.sin(this.angle)*this.width}else{if((0b.max||b.max==null){b.max=h[c][0]}}else{if(h[c][1]b.max||b.max==null){b.max=h[c][1]}}}}if(this.groupLabels.length){this.groups=this.groupLabels.length}};a.jqplot.CategoryAxisRenderer.prototype.createTicks=function(){var D=this._ticks;var z=this.ticks;var F=this.name;var C=this._dataBounds;var v,A;var q,w;var d,c;var b,x;if(z.length){if(this.groups>1&&!this._grouped){var r=z.length;var p=parseInt(r/this.groups,10);var e=0;for(var x=p;x1&&!this._grouped){var r=y.length;var p=parseInt(r/this.groups,10);var e=0;for(var x=p;x0&&o
      ');if(this.name=="xaxis"||this.name=="x2axis"){this._elem.width(this._plotDimensions.width)}else{this._elem.height(this._plotDimensions.height)}this.labelOptions.axis=this.name;this._label=new this.labelRenderer(this.labelOptions);if(this._label.show){var g=this._label.draw(b,j);g.appendTo(this._elem)}var f=this._ticks;for(var e=0;e
      ');g.html(this.groupLabels[e]);this._groupLabels.push(g);g.appendTo(this._elem)}}return this._elem};a.jqplot.CategoryAxisRenderer.prototype.set=function(){var e=0;var m;var k=0;var f=0;var d=(this._label==null)?false:this._label.show;if(this.show){var n=this._ticks;for(var c=0;ce){e=m}}}var j=0;for(var c=0;cj){j=m}}if(d){k=this._label._elem.outerWidth(true);f=this._label._elem.outerHeight(true)}if(this.name=="xaxis"){e+=j+f;this._elem.css({height:e+"px",left:"0px",bottom:"0px"})}else{if(this.name=="x2axis"){e+=j+f;this._elem.css({height:e+"px",left:"0px",top:"0px"})}else{if(this.name=="yaxis"){e+=j+k;this._elem.css({width:e+"px",left:"0px",top:"0px"});if(d&&this._label.constructor==a.jqplot.AxisLabelRenderer){this._label._elem.css("width",k+"px")}}else{e+=j+k;this._elem.css({width:e+"px",right:"0px",top:"0px"});if(d&&this._label.constructor==a.jqplot.AxisLabelRenderer){this._label._elem.css("width",k+"px")}}}}}};a.jqplot.CategoryAxisRenderer.prototype.pack=function(e,c){var C=this._ticks;var v=this.max;var s=this.min;var n=c.max;var l=c.min;var q=(this._label==null)?false:this._label.show;var x;for(var r in e){this._elem.css(r,e[r])}this._offsets=c;var g=n-l;var k=v-s;if(!this.reverse){this.u2p=function(h){return(h-s)*g/k+l};this.p2u=function(h){return(h-l)*k/g+s};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(h){return(h-s)*g/k};this.series_p2u=function(h){return h*k/g+s}}else{this.series_u2p=function(h){return(h-v)*g/k};this.series_p2u=function(h){return h*k/g+v}}}else{this.u2p=function(h){return l+(v-h)*g/k};this.p2u=function(h){return s+(h-l)*k/g};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(h){return(v-h)*g/k};this.series_p2u=function(h){return h*k/g+v}}else{this.series_u2p=function(h){return(s-h)*g/k};this.series_p2u=function(h){return h*k/g+s}}}if(this.show){if(this.name=="xaxis"||this.name=="x2axis"){for(x=0;x0){b=-o._textRenderer.height*Math.cos(-o._textRenderer.angle)/2}else{b=-o.getHeight()+o._textRenderer.height*Math.cos(o._textRenderer.angle)/2}break;case"middle":b=-o.getHeight()/2;break;default:b=-o.getHeight()/2;break}}else{b=-o.getHeight()/2}var D=this.u2p(o.value)+b+"px";o._elem.css("top",D);o.pack()}}var z=["left",0];if(q){var y=this._label._elem.outerHeight(true);this._label._elem.css("top",n-g/2-y/2+"px");if(this.name=="yaxis"){this._label._elem.css("left","0px");z=["left",this._label._elem.outerWidth(true)]}else{this._label._elem.css("right","0px");z=["right",this._label._elem.outerWidth(true)]}this._label.pack()}var d=parseInt(this._ticks.length/this.groups,10);for(x=0;x6&&Math.abs(G.y-I._zoom.start[1])>6)||(I.constrainZoomTo=="x"&&Math.abs(G.x-I._zoom.start[0])>6)||(I.constrainZoomTo=="y"&&Math.abs(G.y-I._zoom.start[1])>6)){if(!C.plugins.cursor.zoomProxy){for(var y in t){if(I._zoom.axes[y]==undefined){I._zoom.axes[y]={};I._zoom.axes[y].numberTicks=F[y].numberTicks;I._zoom.axes[y].tickInterval=F[y].tickInterval;I._zoom.axes[y].daTickInterval=F[y].daTickInterval;I._zoom.axes[y].min=F[y].min;I._zoom.axes[y].max=F[y].max;I._zoom.axes[y].tickFormatString=(F[y].tickOptions!=null)?F[y].tickOptions.formatString:""}if((I.constrainZoomTo=="none")||(I.constrainZoomTo=="x"&&y.charAt(0)=="x")||(I.constrainZoomTo=="y"&&y.charAt(0)=="y")){z=t[y];if(z!=null){if(z>w[y]){v=w[y];x=z}else{D=w[y]-z;v=z;x=w[y]}q=F[y];H=null;if(q.alignTicks){if(q.name==="x2axis"&&C.axes.xaxis.show){H=C.axes.xaxis.numberTicks}else{if(q.name.charAt(0)==="y"&&q.name!=="yaxis"&&q.name!=="yMidAxis"&&C.axes.yaxis.show){H=C.axes.yaxis.numberTicks}}}if(this.looseZoom&&(F[y].renderer.constructor===j.jqplot.LinearAxisRenderer||F[y].renderer.constructor===j.jqplot.LogAxisRenderer)){J=j.jqplot.LinearTickGenerator(v,x,q._scalefact,H);if(F[y].tickInset&&J[0]F[y].max-F[y].tickInset*F[y].tickInterval){J[1]-=J[4];J[2]-=1}if(F[y].renderer.constructor===j.jqplot.LogAxisRenderer&&J[0]"}if(J.useAxesFormatters){for(var D=0;D"}w+=j.jqplot.sprintf(J.tooltipFormatString,t,z,x);N=true}}}}J._tooltipElem.html(w)}function g(C,A){var E=A.plugins.cursor;var z=E.cursorCanvas._ctx;z.clearRect(0,0,z.canvas.width,z.canvas.height);if(E.showVerticalLine){E.shapeRenderer.draw(z,[[C.x,0],[C.x,z.canvas.height]])}if(E.showHorizontalLine){E.shapeRenderer.draw(z,[[0,C.y],[z.canvas.width,C.y]])}var G=d(A,C.x,C.y);if(E.showCursorLegend){var r=j(A.targetId+" td.jqplot-cursor-legend-label");for(var B=0;B0;r--){s=v[r-1];if(q[s].show){u[s]=q[s].series_p2u(w[s.charAt(0)])}}return{offsets:t,gridPos:w,dataPos:u}}function h(z){var x=z.data.plot;var y=x.plugins.cursor;if(y.show&&y.zoom&&y._zoom.started&&!y.zoomTarget){z.preventDefault();var B=y.zoomCanvas._ctx;var v=o(z);var w=v.gridPos;var t=v.dataPos;y._zoom.gridpos=w;y._zoom.datapos=t;y._zoom.zooming=true;var u=w.x;var s=w.y;var A=B.canvas.height;var q=B.canvas.width;if(y.showTooltip&&!y.onGrid&&y.showTooltipOutsideZoom){e(w,t,x);if(y.followMouse){n(w,x)}}if(y.constrainZoomTo=="x"){y._zoom.end=[u,A]}else{if(y.constrainZoomTo=="y"){y._zoom.end=[q,s]}else{y._zoom.end=[u,s]}}var r=window.getSelection;if(document.selection&&document.selection.empty){document.selection.empty()}else{if(r&&!r().isCollapsed){r().collapse()}}l.call(y);B=null}}function a(w,s,r,x,t){var v=t.plugins.cursor;if(t.plugins.mobile){j(document).one("vmouseup.jqplot_cursor",{plot:t},p)}else{j(document).one("mouseup.jqplot_cursor",{plot:t},p)}var u=t.axes;if(document.onselectstart!=undefined){v._oldHandlers.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!=undefined){v._oldHandlers.ondrag=document.ondrag;document.ondrag=function(){return false}}if(document.onmousedown!=undefined){v._oldHandlers.onmousedown=document.onmousedown;document.onmousedown=function(){return false}}if(v.zoom){if(!v.zoomProxy){var y=v.zoomCanvas._ctx;y.clearRect(0,0,y.canvas.width,y.canvas.height);y=null}if(v.constrainZoomTo=="x"){v._zoom.start=[s.x,0]}else{if(v.constrainZoomTo=="y"){v._zoom.start=[0,s.y]}else{v._zoom.start=[s.x,s.y]}}v._zoom.started=true;for(var q in r){v._zoom.axes.start[q]=r[q]}if(t.plugins.mobile){j(document).bind("vmousemove.jqplotCursor",{plot:t},h)}else{j(document).bind("mousemove.jqplotCursor",{plot:t},h)}}}function p(y){var v=y.data.plot;var x=v.plugins.cursor;if(x.zoom&&x._zoom.zooming&&!x.zoomTarget){var u=x._zoom.gridpos.x;var r=x._zoom.gridpos.y;var t=x._zoom.datapos;var z=x.zoomCanvas._ctx.canvas.height;var q=x.zoomCanvas._ctx.canvas.width;var w=v.axes;if(x.constrainOutsideZoom&&!x.onGrid){if(u<0){u=0}else{if(u>q){u=q}}if(r<0){r=0}else{if(r>z){r=z}}for(var s in t){if(t[s]){if(s.charAt(0)=="x"){t[s]=w[s].series_p2u(u)}else{t[s]=w[s].series_p2u(r)}}}}if(x.constrainZoomTo=="x"){r=z}else{if(x.constrainZoomTo=="y"){u=q}}x._zoom.end=[u,r];x._zoom.gridpos={x:u,y:r};x.doZoom(x._zoom.gridpos,t,v,x)}x._zoom.started=false;x._zoom.zooming=false;j(document).unbind("mousemove.jqplotCursor",h);if(document.onselectstart!=undefined&&x._oldHandlers.onselectstart!=null){document.onselectstart=x._oldHandlers.onselectstart;x._oldHandlers.onselectstart=null}if(document.ondrag!=undefined&&x._oldHandlers.ondrag!=null){document.ondrag=x._oldHandlers.ondrag;x._oldHandlers.ondrag=null}if(document.onmousedown!=undefined&&x._oldHandlers.onmousedown!=null){document.onmousedown=x._oldHandlers.onmousedown;x._oldHandlers.onmousedown=null}}function l(){var y=this._zoom.start;var u=this._zoom.end;var s=this.zoomCanvas._ctx;var r,v,x,q;if(u[0]>y[0]){r=y[0];q=u[0]-y[0]}else{r=u[0];q=y[0]-u[0]}if(u[1]>y[1]){v=y[1];x=u[1]-y[1]}else{v=u[1];x=y[1]-u[1]}s.fillStyle="rgba(0,0,0,0.2)";s.strokeStyle="#999999";s.lineWidth=1;s.clearRect(0,0,s.canvas.width,s.canvas.height);s.fillRect(0,0,s.canvas.width,s.canvas.height);s.clearRect(r,v,q,x);s.strokeRect(r,v,q,x);s=null}j.jqplot.CursorLegendRenderer=function(q){j.jqplot.TableLegendRenderer.call(this,q);this.formatString="%s"};j.jqplot.CursorLegendRenderer.prototype=new j.jqplot.TableLegendRenderer();j.jqplot.CursorLegendRenderer.prototype.constructor=j.jqplot.CursorLegendRenderer;j.jqplot.CursorLegendRenderer.prototype.draw=function(){if(this._elem){this._elem.emptyForce();this._elem=null}if(this.show){var w=this._series,A;var r=document.createElement("div");this._elem=j(r);r=null;this._elem.addClass("jqplot-legend jqplot-cursor-legend");this._elem.css("position","absolute");var q=false;for(var x=0;x').appendTo(this._elem);E.data("seriesIndex",s);j('
      ').appendTo(E);var G=j('');G.appendTo(E);G.data("seriesIndex",s);if(this.escapeHtml){G.text(D)}else{G.html(D)}E=null;G=null}return this._elem}})(jQuery); \ No newline at end of file diff --git a/phpmyadmin/js/jqplot/plugins/jqplot.dateAxisRenderer.js b/phpmyadmin/js/jqplot/plugins/jqplot.dateAxisRenderer.js new file mode 100644 index 000000000..86d52c5b0 --- /dev/null +++ b/phpmyadmin/js/jqplot/plugins/jqplot.dateAxisRenderer.js @@ -0,0 +1 @@ +(function(h){h.jqplot.DateAxisRenderer=function(){h.jqplot.LinearAxisRenderer.call(this);this.date=new h.jsDate()};var c=1000;var e=60*c;var f=60*e;var l=24*f;var b=7*l;var j=30.4368499*l;var k=365.242199*l;var g=[31,28,31,30,31,30,31,30,31,30,31,30];var i=["%M:%S.%#N","%M:%S.%#N","%M:%S.%#N","%M:%S","%M:%S","%M:%S","%M:%S","%H:%M:%S","%H:%M:%S","%H:%M","%H:%M","%H:%M","%H:%M","%H:%M","%H:%M","%a %H:%M","%a %H:%M","%b %e %H:%M","%b %e %H:%M","%b %e %H:%M","%b %e %H:%M","%v","%v","%v","%v","%v","%v","%v"];var m=[0.1*c,0.2*c,0.5*c,c,2*c,5*c,10*c,15*c,30*c,e,2*e,5*e,10*e,15*e,30*e,f,2*f,4*f,6*f,8*f,12*f,l,2*l,3*l,4*l,5*l,b,2*b];var d=[];function a(p,s,t){var o=Number.MAX_VALUE;var u,r,v;for(var q=0,n=m.length;qC.max)||C.max==null){C.max=y[r][0]}if(r>0){o=Math.abs(y[r][0]-y[r-1][0]);u.intervals.push(o);if(u.frequencies.hasOwnProperty(o)){u.frequencies[o]+=1}else{u.frequencies[o]=1}}x+=o}else{y[r][1]=new h.jsDate(y[r][1]).getTime();A[r][1]=new h.jsDate(y[r][1]).getTime();z[r][1]=new h.jsDate(y[r][1]).getTime();if((y[r][1]!=null&&y[r][1]C.max)||C.max==null){C.max=y[r][1]}if(r>0){o=Math.abs(y[r][1]-y[r-1][1]);u.intervals.push(o);if(u.frequencies.hasOwnProperty(o)){u.frequencies[o]+=1}else{u.frequencies[o]=1}}}x+=o}if(D.renderer.bands){if(D.renderer.bands.hiData.length){var w=D.renderer.bands.hiData;for(var r=0,q=w.length;rC.max)||C.max==null){C.max=w[r][0]}}else{w[r][1]=new h.jsDate(w[r][1]).getTime();if((w[r][1]!=null&&w[r][1]>C.max)||C.max==null){C.max=w[r][1]}}}}if(D.renderer.bands.lowData.length){var w=D.renderer.bands.lowData;for(var r=0,q=w.length;r6){D=6}}var U=new h.jsDate(ad).setDate(1).setHours(0,0,0,0);var q=new h.jsDate(J);var z=new h.jsDate(J).setDate(1).setHours(0,0,0,0);if(q.getTime()!==z.getTime()){z=z.add(1,"month")}var T=z.diff(U,"month");ab=Math.ceil(T/D)+1;this.min=U.getTime();this.max=U.clone().add((ab-1)*D,"month").getTime();this.numberTicks=ab;for(var Z=0;Z200){this.numberTicks=parseInt(3+(n-200)/100,10)}else{this.numberTicks=2}}}O=B/(this.numberTicks-1)/1000;if(this.daTickInterval==null){this.daTickInterval=[O,"seconds"]}for(var Z=0;Z=0.6)?l[3]*0.6:l[3]*(2-l[3]);i.color="rgba("+n[0]+","+n[1]+","+n[2]+","+k+")";i.init();i.draw(p.gridData[o.pointIndex][0],p.gridData[o.pointIndex][1],j.highlightCanvas._ctx)}function g(A,q,m){var k=A.plugins.highlighter;var D=k._tooltipElem;var r=q.highlighter||{};var t=d.extend(true,{},k,r);if(t.useAxesFormatters){var w=q._xaxis._ticks[0].formatter;var h=q._yaxis._ticks[0].formatter;var E=q._xaxis._ticks[0].formatString;var s=q._yaxis._ticks[0].formatString;var z;var u=w(E,m.data[0]);var l=[];for(var B=1;B570)?o[p]*0.8:o[p]+0.3*(255-o[p]);o[p]=parseInt(o[p],10)}this.highlightColors.push("rgb("+o[0]+","+o[1]+","+o[2]+")")}}this.highlightColorGenerator=new e.jqplot.ColorGenerator(this.highlightColors);u.postParseOptionsHooks.addOnce(m);u.postInitHooks.addOnce(g);u.eventListenerHooks.addOnce("jqplotMouseMove",b);u.eventListenerHooks.addOnce("jqplotMouseDown",a);u.eventListenerHooks.addOnce("jqplotMouseUp",l);u.eventListenerHooks.addOnce("jqplotClick",f);u.eventListenerHooks.addOnce("jqplotRightClick",n);u.postDrawHooks.addOnce(i)};e.jqplot.PieRenderer.prototype.setGridData=function(t){var p=[];var u=[];var o=this.startAngle/180*Math.PI;var s=0;this._drawData=false;for(var r=0;r0){p[r]+=p[r-1]}s+=this.data[r][1]}var q=Math.PI*2/p[p.length-1];for(var r=0;r0){p[r]+=p[r-1]}s+=t[r][1]}var q=Math.PI*2/p[p.length-1];for(var r=0;r0&&s>0.01&&s<6.282){w=parseFloat(p)/2/h(q)}return w}e.jqplot.PieRenderer.prototype.drawSlice=function(B,z,y,u,w){if(this._drawData){var p=this._radius;var A=this.fill;var x=this.lineWidth;var s=this.sliceMargin;if(this.fill==false){s+=this.lineWidth}B.save();B.translate(this._center[0],this._center[1]);var D=j(z,y,this.sliceMargin,this.fill,this.lineWidth);var o=D*Math.cos((z+y)/2);var C=D*Math.sin((z+y)/2);if((y-z)<=Math.PI){p-=D}else{p+=D}B.translate(o,C);if(w){for(var v=0,t=this.shadowDepth;v6.282+this.startAngle){y=6.282+this.startAngle;if(z>y){z=6.281+this.startAngle}}if(z>=y){return}B.beginPath();B.fillStyle=u;B.strokeStyle=u;B.lineWidth=x;B.arc(0,0,r,z,y,false);B.lineTo(0,0);B.closePath();if(A){B.fill()}else{B.stroke()}}};e.jqplot.PieRenderer.prototype.draw=function(B,z,E,o){var W;var H=(E!=undefined)?E:{};var t=0;var s=0;var N=1;var L=new e.jqplot.ColorGenerator(this.seriesColors);if(E.legendInfo&&E.legendInfo.placement=="insideGrid"){var J=E.legendInfo;switch(J.location){case"nw":t=J.width+J.xoffset;break;case"w":t=J.width+J.xoffset;break;case"sw":t=J.width+J.xoffset;break;case"ne":t=J.width+J.xoffset;N=-1;break;case"e":t=J.width+J.xoffset;N=-1;break;case"se":t=J.width+J.xoffset;N=-1;break;case"n":s=J.height+J.yoffset;break;case"s":s=J.height+J.yoffset;N=-1;break;default:break}}var K=(H.shadow!=undefined)?H.shadow:this.shadow;var A=(H.fill!=undefined)?H.fill:this.fill;var C=B.canvas.width;var I=B.canvas.height;var Q=C-t-2*this.padding;var X=I-s-2*this.padding;var M=Math.min(Q,X);var Y=M;this._sliceAngles=[];var v=this.sliceMargin;if(this.fill==false){v+=this.lineWidth}var q;var G=0;var R,aa,Z,ab;var D=this.startAngle/180*Math.PI;for(var W=0,V=z.length;WMath.PI){G=Math.max(q,G)}}if(this.diameter!=null&&this.diameter>0){this._diameter=this.diameter-2*G}else{this._diameter=Y-2*G}if(this._diameter<6){e.jqplot.log("Diameter of pie too small, not rendering.");return}var S=this._radius=this._diameter/2;this._center=[(C-N*t)/2+N*t+G*Math.cos(D),(I-N*s)/2+N*s+G*Math.sin(D)];if(this.shadow){for(var W=0,V=z.length;W=this.dataLabelThreshold){var F,U=(this._sliceAngles[W][0]+this._sliceAngles[W][1])/2,T;if(this.dataLabels=="label"){F=this.dataLabelFormatString||"%s";T=e.jqplot.sprintf(F,z[W][0])}else{if(this.dataLabels=="value"){F=this.dataLabelFormatString||"%d";T=e.jqplot.sprintf(F,this.data[W][1])}else{if(this.dataLabels=="percent"){F=this.dataLabelFormatString||"%d%%";T=e.jqplot.sprintf(F,z[W][2]*100)}else{if(this.dataLabels.constructor==Array){F=this.dataLabelFormatString||"%s";T=e.jqplot.sprintf(F,this.dataLabels[W])}}}}var p=(this._radius)*this.dataLabelPositionFactor+this.sliceMargin+this.dataLabelNudge;var P=this._center[0]+Math.cos(U)*p+this.canvas._offsets.left;var O=this._center[1]+Math.sin(U)*p+this.canvas._offsets.top;var u=e('
      '+T+"
      ").insertBefore(o.eventCanvas._elem);if(this.dataLabelCenterOn){P-=u.width()/2;O-=u.height()/2}else{P-=u.width()*Math.sin(U/2);O-=u.height()/2}P=Math.round(P);O=Math.round(O);u.css({left:P,top:O})}}};e.jqplot.PieAxisRenderer=function(){e.jqplot.LinearAxisRenderer.call(this)};e.jqplot.PieAxisRenderer.prototype=new e.jqplot.LinearAxisRenderer();e.jqplot.PieAxisRenderer.prototype.constructor=e.jqplot.PieAxisRenderer;e.jqplot.PieAxisRenderer.prototype.init=function(o){this.tickRenderer=e.jqplot.PieTickRenderer;e.extend(true,this,o);this._dataBounds={min:0,max:100};this.min=0;this.max=100;this.showTicks=false;this.ticks=[];this.showMark=false;this.show=false};e.jqplot.PieLegendRenderer=function(){e.jqplot.TableLegendRenderer.call(this)};e.jqplot.PieLegendRenderer.prototype=new e.jqplot.TableLegendRenderer();e.jqplot.PieLegendRenderer.prototype.constructor=e.jqplot.PieLegendRenderer;e.jqplot.PieLegendRenderer.prototype.init=function(o){this.numberRows=null;this.numberColumns=null;e.extend(true,this,o)};e.jqplot.PieLegendRenderer.prototype.draw=function(){var r=this;if(this.show){var B=this._series;this._elem=e(document.createElement("table"));this._elem.addClass("jqplot-table-legend");var E={position:"absolute"};if(this.background){E.background=this.background}if(this.border){E.border=this.border}if(this.fontSize){E.fontSize=this.fontSize}if(this.fontFamily){E.fontFamily=this.fontFamily}if(this.textColor){E.textColor=this.textColor}if(this.marginTop!=null){E.marginTop=this.marginTop}if(this.marginBottom!=null){E.marginBottom=this.marginBottom}if(this.marginLeft!=null){E.marginLeft=this.marginLeft}if(this.marginRight!=null){E.marginRight=this.marginRight}this._elem.css(E);var I=false,A=false,o,y;var C=B[0];var p=new e.jqplot.ColorGenerator(C.seriesColors);if(C.show){var J=C.data;if(this.numberRows){o=this.numberRows;if(!this.numberColumns){y=Math.ceil(J.length/o)}else{y=this.numberColumns}}else{if(this.numberColumns){y=this.numberColumns;o=Math.ceil(J.length/this.numberColumns)}else{o=J.length;y=1}}var H,G;var q,w,v;var x,z,F;var D=0;var u,t;for(H=0;H0){I=true}else{I=false}}else{if(H==o-1){I=false}else{I=true}}z=(I)?this.rowSpacing:"0";w=e(document.createElement("td"));w.addClass("jqplot-table-legend jqplot-table-legend-swatch");w.css({textAlign:"center",paddingTop:z});u=e(document.createElement("div"));u.addClass("jqplot-table-legend-swatch-outline");t=e(document.createElement("div"));t.addClass("jqplot-table-legend-swatch");t.css({backgroundColor:F,borderColor:F});w.append(u.append(t));v=e(document.createElement("td"));v.addClass("jqplot-table-legend jqplot-table-legend-label");v.css("paddingTop",z);if(this.escapeHtml){v.text(x)}else{v.html(x)}if(A){v.prependTo(q);w.prependTo(q)}else{w.appendTo(q);v.appendTo(q)}I=true}D++}}}}return this._elem};e.jqplot.PieRenderer.prototype.handleMove=function(q,p,t,s,r){if(s){var o=[s.seriesIndex,s.pointIndex,s.data];r.target.trigger("jqplotDataMouseOver",o);if(r.series[o[0]].highlightMouseOver&&!(o[0]==r.plugins.pieRenderer.highlightedSeriesIndex&&o[1]==r.series[o[0]]._highlightedPoint)){r.target.trigger("jqplotDataHighlight",o);d(r,o[0],o[1])}}else{if(s==null){k(r)}}};function c(s,r,p){p=p||{};p.axesDefaults=p.axesDefaults||{};p.legend=p.legend||{};p.seriesDefaults=p.seriesDefaults||{};var o=false;if(p.seriesDefaults.renderer==e.jqplot.PieRenderer){o=true}else{if(p.series){for(var q=0;qB||s+C>m){z.remove()}z=null;f=null}}};c.jqplot.postSeriesInitHooks.push(c.jqplot.PointLabels.init);c.jqplot.postDrawSeriesHooks.push(c.jqplot.PointLabels.draw)})(jQuery); \ No newline at end of file diff --git a/phpmyadmin/js/jquery/jquery-1.8.3.js b/phpmyadmin/js/jquery/jquery-1.8.3.js new file mode 100644 index 000000000..3f4b546f9 --- /dev/null +++ b/phpmyadmin/js/jquery/jquery-1.8.3.js @@ -0,0 +1,21 @@ +/*! + * jQuery JavaScript Library v1.8.3 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: Tue Nov 13 2012 08:20:33 GMT-0500 (Eastern Standard Time) + */ +(function(a2,aB){var w,af,o=a2.document,aI=a2.location,d=a2.navigator,bg=a2.jQuery,I=a2.$,am=Array.prototype.push,a4=Array.prototype.slice,aK=Array.prototype.indexOf,z=Object.prototype.toString,V=Object.prototype.hasOwnProperty,aO=String.prototype.trim,bG=function(e,bZ){return new bG.fn.init(e,bZ,w)},bx=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,aa=/\S/,aV=/\s+/,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,bo=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,a=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,bf=/^[\],:{}\s]*$/,bi=/(?:^|:|,)(?:\s*\[)+/g,bD=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,a0=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,bP=/^-ms-/,aU=/-([\da-z])/gi,N=function(e,bZ){return(bZ+"").toUpperCase()},aF=function(){if(o.addEventListener){o.removeEventListener("DOMContentLoaded",aF,false);bG.ready()}else{if(o.readyState==="complete"){o.detachEvent("onreadystatechange",aF);bG.ready()}}},Z={};bG.fn=bG.prototype={constructor:bG,init:function(e,b2,b1){var b0,b3,bZ,b4;if(!e){return this}if(e.nodeType){this.context=this[0]=e;this.length=1;return this}if(typeof e==="string"){if(e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3){b0=[null,e,null]}else{b0=bo.exec(e)}if(b0&&(b0[1]||!b2)){if(b0[1]){b2=b2 instanceof bG?b2[0]:b2;b4=(b2&&b2.nodeType?b2.ownerDocument||b2:o);e=bG.parseHTML(b0[1],b4,true);if(a.test(b0[1])&&bG.isPlainObject(b2)){this.attr.call(e,b2,true)}return bG.merge(this,e)}else{b3=o.getElementById(b0[2]);if(b3&&b3.parentNode){if(b3.id!==b0[2]){return b1.find(e)}this.length=1;this[0]=b3}this.context=o;this.selector=e;return this}}else{if(!b2||b2.jquery){return(b2||b1).find(e)}else{return this.constructor(b2).find(e)}}}else{if(bG.isFunction(e)){return b1.ready(e)}}if(e.selector!==aB){this.selector=e.selector;this.context=e.context}return bG.makeArray(e,this)},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return a4.call(this)},get:function(e){return e==null?this.toArray():(e<0?this[this.length+e]:this[e])},pushStack:function(bZ,b1,e){var b0=bG.merge(this.constructor(),bZ);b0.prevObject=this;b0.context=this.context;if(b1==="find"){b0.selector=this.selector+(this.selector?" ":"")+e}else{if(b1){b0.selector=this.selector+"."+b1+"("+e+")"}}return b0},each:function(bZ,e){return bG.each(this,bZ,e)},ready:function(e){bG.ready.promise().done(e);return this},eq:function(e){e=+e;return e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(a4.apply(this,arguments),"slice",a4.call(arguments).join(","))},map:function(e){return this.pushStack(bG.map(this,function(b0,bZ){return e.call(b0,bZ,b0)}))},end:function(){return this.prevObject||this.constructor(null)},push:am,sort:[].sort,splice:[].splice};bG.fn.init.prototype=bG.fn;bG.extend=bG.fn.extend=function(){var b7,b0,e,bZ,b4,b5,b3=arguments[0]||{},b2=1,b1=arguments.length,b6=false;if(typeof b3==="boolean"){b6=b3;b3=arguments[1]||{};b2=2}if(typeof b3!=="object"&&!bG.isFunction(b3)){b3={}}if(b1===b2){b3=this;--b2}for(;b20){return}af.resolveWith(o,[bG]);if(bG.fn.trigger){bG(o).trigger("ready").off("ready")}},isFunction:function(e){return bG.type(e)==="function"},isArray:Array.isArray||function(e){return bG.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return !isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):Z[z.call(e)]||"object"},isPlainObject:function(b1){if(!b1||bG.type(b1)!=="object"||b1.nodeType||bG.isWindow(b1)){return false}try{if(b1.constructor&&!V.call(b1,"constructor")&&!V.call(b1.constructor.prototype,"isPrototypeOf")){return false}}catch(b0){return false}var bZ;for(bZ in b1){}return bZ===aB||V.call(b1,bZ)},isEmptyObject:function(bZ){var e;for(e in bZ){return false}return true},error:function(e){throw new Error(e)},parseHTML:function(b1,b0,e){var bZ;if(!b1||typeof b1!=="string"){return null}if(typeof b0==="boolean"){e=b0;b0=0}b0=b0||o;if((bZ=a.exec(b1))){return[b0.createElement(bZ[1])]}bZ=bG.buildFragment([b1],b0,e?null:[]);return bG.merge([],(bZ.cacheable?bG.clone(bZ.fragment):bZ.fragment).childNodes)},parseJSON:function(e){if(!e||typeof e!=="string"){return null}e=bG.trim(e);if(a2.JSON&&a2.JSON.parse){return a2.JSON.parse(e)}if(bf.test(e.replace(bD,"@").replace(a0,"]").replace(bi,""))){return(new Function("return "+e))()}bG.error("Invalid JSON: "+e)},parseXML:function(b1){var bZ,b0;if(!b1||typeof b1!=="string"){return null}try{if(a2.DOMParser){b0=new DOMParser();bZ=b0.parseFromString(b1,"text/xml")}else{bZ=new ActiveXObject("Microsoft.XMLDOM");bZ.async="false";bZ.loadXML(b1)}}catch(b2){bZ=aB}if(!bZ||!bZ.documentElement||bZ.getElementsByTagName("parsererror").length){bG.error("Invalid XML: "+b1)}return bZ},noop:function(){},globalEval:function(e){if(e&&aa.test(e)){(a2.execScript||function(bZ){a2["eval"].call(a2,bZ)})(e)}},camelCase:function(e){return e.replace(bP,"ms-").replace(aU,N)},nodeName:function(bZ,e){return bZ.nodeName&&bZ.nodeName.toLowerCase()===e.toLowerCase()},each:function(b3,b4,b0){var bZ,b1=0,b2=b3.length,e=b2===aB||bG.isFunction(b3);if(b0){if(e){for(bZ in b3){if(b4.apply(b3[bZ],b0)===false){break}}}else{for(;b10&&e[0]&&e[bZ-1])||bZ===0||bG.isArray(e));if(b1){for(;b0-1){b5.splice(ca,1);if(b2){if(ca<=b3){b3--}if(ca<=b4){b4--}}}})}return this},has:function(b9){return bG.inArray(b9,b5)>-1},empty:function(){b5=[];return this},disable:function(){b5=b6=b1=aB;return this},disabled:function(){return !b5},lock:function(){b6=aB;if(!b1){b7.disable()}return this},locked:function(){return !b6},fireWith:function(ca,b9){b9=b9||[];b9=[ca,b9.slice?b9.slice():b9];if(b5&&(!e||b6)){if(b2){b6.push(b9)}else{bZ(b9)}}return this},fire:function(){b7.fireWith(this,arguments);return this},fired:function(){return !!e}};return b7};bG.extend({Deferred:function(b0){var bZ=[["resolve","done",bG.Callbacks("once memory"),"resolved"],["reject","fail",bG.Callbacks("once memory"),"rejected"],["notify","progress",bG.Callbacks("memory")]],b1="pending",b2={state:function(){return b1},always:function(){e.done(arguments).fail(arguments);return this},then:function(){var b3=arguments;return bG.Deferred(function(b4){bG.each(bZ,function(b6,b5){var b8=b5[0],b7=b3[b6];e[b5[1]](bG.isFunction(b7)?function(){var b9=b7.apply(this,arguments);if(b9&&bG.isFunction(b9.promise)){b9.promise().done(b4.resolve).fail(b4.reject).progress(b4.notify)}else{b4[b8+"With"](this===e?b4:this,[b9])}}:b4[b8])});b3=null}).promise()},promise:function(b3){return b3!=null?bG.extend(b3,b2):b2}},e={};b2.pipe=b2.then;bG.each(bZ,function(b4,b3){var b6=b3[2],b5=b3[3];b2[b3[1]]=b6.add;if(b5){b6.add(function(){b1=b5},bZ[b4^1][2].disable,bZ[2][2].lock)}e[b3[0]]=b6.fire;e[b3[0]+"With"]=b6.fireWith});b2.promise(e);if(b0){b0.call(e,e)}return e},when:function(b2){var b0=0,b4=a4.call(arguments),e=b4.length,bZ=e!==1||(b2&&bG.isFunction(b2.promise))?e:0,b7=bZ===1?b2:bG.Deferred(),b1=function(b9,ca,b8){return function(cb){ca[b9]=this;b8[b9]=arguments.length>1?a4.call(arguments):cb;if(b8===b6){b7.notifyWith(ca,b8)}else{if(!(--bZ)){b7.resolveWith(ca,b8)}}}},b6,b3,b5;if(e>1){b6=new Array(e);b3=new Array(e);b5=new Array(e);for(;b0
      a";ca=b0.getElementsByTagName("*");b8=b0.getElementsByTagName("a")[0];if(!ca||!b8||!ca.length){return{}}b9=o.createElement("select");b2=b9.appendChild(o.createElement("option"));b7=b0.getElementsByTagName("input")[0];b8.style.cssText="top:1px;float:left;opacity:.5";cb={leadingWhitespace:(b0.firstChild.nodeType===3),tbody:!b0.getElementsByTagName("tbody").length,htmlSerialize:!!b0.getElementsByTagName("link").length,style:/top/.test(b8.getAttribute("style")),hrefNormalized:(b8.getAttribute("href")==="/a"),opacity:/^0.5/.test(b8.style.opacity),cssFloat:!!b8.style.cssFloat,checkOn:(b7.value==="on"),optSelected:b2.selected,getSetAttribute:b0.className!=="t",enctype:!!o.createElement("form").enctype,html5Clone:o.createElement("nav").cloneNode(true).outerHTML!=="<:nav>",boxModel:(o.compatMode==="CSS1Compat"),submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true,boxSizingReliable:true,pixelPosition:false};b7.checked=true;cb.noCloneChecked=b7.cloneNode(true).checked;b9.disabled=true;cb.optDisabled=!b2.disabled;try{delete b0.test}catch(b5){cb.deleteExpando=false}if(!b0.addEventListener&&b0.attachEvent&&b0.fireEvent){b0.attachEvent("onclick",bZ=function(){cb.noCloneEvent=false});b0.cloneNode(true).fireEvent("onclick");b0.detachEvent("onclick",bZ)}b7=o.createElement("input");b7.value="t";b7.setAttribute("type","radio");cb.radioValue=b7.value==="t";b7.setAttribute("checked","checked");b7.setAttribute("name","t");b0.appendChild(b7);b6=o.createDocumentFragment();b6.appendChild(b0.lastChild);cb.checkClone=b6.cloneNode(true).cloneNode(true).lastChild.checked;cb.appendChecked=b7.checked;b6.removeChild(b7);b6.appendChild(b0);if(b0.attachEvent){for(b3 in {submit:true,change:true,focusin:true}){b4="on"+b3;b1=(b4 in b0);if(!b1){b0.setAttribute(b4,"return;");b1=(typeof b0[b4]==="function")}cb[b3+"Bubbles"]=b1}}bG(function(){var cc,cg,ce,cf,cd="padding:0;margin:0;border:0;display:block;overflow:hidden;",e=o.getElementsByTagName("body")[0];if(!e){return}cc=o.createElement("div");cc.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";e.insertBefore(cc,e.firstChild);cg=o.createElement("div");cc.appendChild(cg);cg.innerHTML="
      t
      ";ce=cg.getElementsByTagName("td");ce[0].style.cssText="padding:0;margin:0;border:0;display:none";b1=(ce[0].offsetHeight===0);ce[0].style.display="";ce[1].style.display="none";cb.reliableHiddenOffsets=b1&&(ce[0].offsetHeight===0);cg.innerHTML="";cg.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";cb.boxSizing=(cg.offsetWidth===4);cb.doesNotIncludeMarginInBodyOffset=(e.offsetTop!==1);if(a2.getComputedStyle){cb.pixelPosition=(a2.getComputedStyle(cg,null)||{}).top!=="1%";cb.boxSizingReliable=(a2.getComputedStyle(cg,null)||{width:"4px"}).width==="4px";cf=o.createElement("div");cf.style.cssText=cg.style.cssText=cd;cf.style.marginRight=cf.style.width="0";cg.style.width="1px";cg.appendChild(cf);cb.reliableMarginRight=!parseFloat((a2.getComputedStyle(cf,null)||{}).marginRight)}if(typeof cg.style.zoom!=="undefined"){cg.innerHTML="";cg.style.cssText=cd+"width:1px;padding:1px;display:inline;zoom:1";cb.inlineBlockNeedsLayout=(cg.offsetWidth===3);cg.style.display="block";cg.style.overflow="visible";cg.innerHTML="
      ";cg.firstChild.style.width="5px";cb.shrinkWrapBlocks=(cg.offsetWidth!==3);cc.style.zoom=1}e.removeChild(cc);cc=cg=ce=cf=null});b6.removeChild(b0);ca=b8=b9=b2=b7=b6=b0=null;return cb})();var bt=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,aL=/([A-Z])/g;bG.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(bG.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(e){e=e.nodeType?bG.cache[e[bG.expando]]:e[bG.expando];return !!e&&!O(e)},data:function(b1,bZ,b3,b2){if(!bG.acceptData(b1)){return}var b4,b6,b7=bG.expando,b5=typeof bZ==="string",b8=b1.nodeType,e=b8?bG.cache:b1,b0=b8?b1[b7]:b1[b7]&&b7;if((!b0||!e[b0]||(!b2&&!e[b0].data))&&b5&&b3===aB){return}if(!b0){if(b8){b1[b7]=b0=bG.deletedIds.pop()||bG.guid++}else{b0=b7}}if(!e[b0]){e[b0]={};if(!b8){e[b0].toJSON=bG.noop}}if(typeof bZ==="object"||typeof bZ==="function"){if(b2){e[b0]=bG.extend(e[b0],bZ)}else{e[b0].data=bG.extend(e[b0].data,bZ)}}b4=e[b0];if(!b2){if(!b4.data){b4.data={}}b4=b4.data}if(b3!==aB){b4[bG.camelCase(bZ)]=b3}if(b5){b6=b4[bZ];if(b6==null){b6=b4[bG.camelCase(bZ)]}}else{b6=b4}return b6},removeData:function(b1,bZ,b2){if(!bG.acceptData(b1)){return}var b5,b4,b3,b6=b1.nodeType,e=b6?bG.cache:b1,b0=b6?b1[bG.expando]:bG.expando;if(!e[b0]){return}if(bZ){b5=b2?e[b0]:e[b0].data;if(b5){if(!bG.isArray(bZ)){if(bZ in b5){bZ=[bZ]}else{bZ=bG.camelCase(bZ);if(bZ in b5){bZ=[bZ]}else{bZ=bZ.split(" ")}}}for(b4=0,b3=bZ.length;b41,null,false)},removeData:function(e){return this.each(function(){bG.removeData(this,e)})}});function bv(b1,b0,b2){if(b2===aB&&b1.nodeType===1){var bZ="data-"+b0.replace(aL,"-$1").toLowerCase();b2=b1.getAttribute(bZ);if(typeof b2==="string"){try{b2=b2==="true"?true:b2==="false"?false:b2==="null"?null:+b2+""===b2?+b2:bt.test(b2)?bG.parseJSON(b2):b2}catch(b3){}bG.data(b1,b0,b2)}else{b2=aB}}return b2}function O(bZ){var e;for(e in bZ){if(e==="data"&&bG.isEmptyObject(bZ[e])){continue}if(e!=="toJSON"){return false}}return true}bG.extend({queue:function(b0,bZ,b1){var e;if(b0){bZ=(bZ||"fx")+"queue";e=bG._data(b0,bZ);if(b1){if(!e||bG.isArray(b1)){e=bG._data(b0,bZ,bG.makeArray(b1))}else{e.push(b1)}}return e||[]}},dequeue:function(b3,b2){b2=b2||"fx";var bZ=bG.queue(b3,b2),b4=bZ.length,b1=bZ.shift(),e=bG._queueHooks(b3,b2),b0=function(){bG.dequeue(b3,b2)};if(b1==="inprogress"){b1=bZ.shift();b4--}if(b1){if(b2==="fx"){bZ.unshift("inprogress")}delete e.stop;b1.call(b3,b0,e)}if(!b4&&e){e.empty.fire()}},_queueHooks:function(b0,bZ){var e=bZ+"queueHooks";return bG._data(b0,e)||bG._data(b0,e,{empty:bG.Callbacks("once memory").add(function(){bG.removeData(b0,bZ+"queue",true);bG.removeData(b0,e,true)})})}});bG.fn.extend({queue:function(e,bZ){var b0=2;if(typeof e!=="string"){bZ=e;e="fx";b0--}if(arguments.length1)},removeAttr:function(e){return this.each(function(){bG.removeAttr(this,e)})},prop:function(e,bZ){return bG.access(this,bG.prop,e,bZ,arguments.length>1)},removeProp:function(e){e=bG.propFix[e]||e;return this.each(function(){try{this[e]=aB;delete this[e]}catch(bZ){}})},addClass:function(b2){var b4,b0,bZ,b1,b3,b5,e;if(bG.isFunction(b2)){return this.each(function(b6){bG(this).addClass(b2.call(this,b6,this.className))})}if(b2&&typeof b2==="string"){b4=b2.split(aV);for(b0=0,bZ=this.length;b0=0){b2=b2.replace(" "+b1[b5]+" "," ")}}b3.className=b4?bG.trim(b2):""}}}return this},toggleClass:function(b1,bZ){var b0=typeof b1,e=typeof bZ==="boolean";if(bG.isFunction(b1)){return this.each(function(b2){bG(this).toggleClass(b1.call(this,b2,this.className,bZ),bZ)})}return this.each(function(){if(b0==="string"){var b4,b3=0,b2=bG(this),b5=bZ,b6=b1.split(aV);while((b4=b6[b3++])){b5=e?b5:!b2.hasClass(b4);b2[b5?"addClass":"removeClass"](b4)}}else{if(b0==="undefined"||b0==="boolean"){if(this.className){bG._data(this,"__className__",this.className)}this.className=this.className||b1===false?"":bG._data(this,"__className__")||""}}})},hasClass:function(e){var b1=" "+e+" ",b0=0,bZ=this.length;for(;b0=0){return true}}return false},val:function(b1){var e,bZ,b2,b0=this[0];if(!arguments.length){if(b0){e=bG.valHooks[b0.type]||bG.valHooks[b0.nodeName.toLowerCase()];if(e&&"get" in e&&(bZ=e.get(b0,"value"))!==aB){return bZ}bZ=b0.value;return typeof bZ==="string"?bZ.replace(ai,""):bZ==null?"":bZ}return}b2=bG.isFunction(b1);return this.each(function(b4){var b5,b3=bG(this);if(this.nodeType!==1){return}if(b2){b5=b1.call(this,b4,b3.val())}else{b5=b1}if(b5==null){b5=""}else{if(typeof b5==="number"){b5+=""}else{if(bG.isArray(b5)){b5=bG.map(b5,function(b6){return b6==null?"":b6+""})}}}e=bG.valHooks[this.type]||bG.valHooks[this.nodeName.toLowerCase()];if(!e||!("set" in e)||e.set(this,b5,"value")===aB){this.value=b5}})}});bG.extend({valHooks:{option:{get:function(e){var bZ=e.attributes.value;return !bZ||bZ.specified?e.value:e.text}},select:{get:function(e){var b4,b0,b6=e.options,b2=e.selectedIndex,b1=e.type==="select-one"||b2<0,b5=b1?null:[],b3=b1?b2+1:b6.length,bZ=b2<0?b3:b1?b2:0;for(;bZ=0});if(!e.length){bZ.selectedIndex=-1}return e}}},attrFn:{},attr:function(b4,b1,b5,b3){var b0,e,b2,bZ=b4.nodeType;if(!b4||bZ===3||bZ===8||bZ===2){return}if(b3&&bG.isFunction(bG.fn[b1])){return bG(b4)[b1](b5)}if(typeof b4.getAttribute==="undefined"){return bG.prop(b4,b1,b5)}b2=bZ!==1||!bG.isXMLDoc(b4);if(b2){b1=b1.toLowerCase();e=bG.attrHooks[b1]||(M.test(b1)?bV:a7)}if(b5!==aB){if(b5===null){bG.removeAttr(b4,b1);return}else{if(e&&"set" in e&&b2&&(b0=e.set(b4,b5,b1))!==aB){return b0}else{b4.setAttribute(b1,b5+"");return b5}}}else{if(e&&"get" in e&&b2&&(b0=e.get(b4,b1))!==null){return b0}else{b0=b4.getAttribute(b1);return b0===null?aB:b0}}},removeAttr:function(b1,b3){var b2,b4,bZ,e,b0=0;if(b3&&b1.nodeType===1){b4=b3.split(aV);for(;b0=0)}}})});var bE=/^(?:textarea|input|select)$/i,br=/^([^\.]*|)(?:\.(.+)|)$/,ba=/(?:^|\s)hover(\.\S+|)\b/,a3=/^key/,bK=/^(?:mouse|contextmenu)|click/,by=/^(?:focusinfocus|focusoutblur)$/,aq=function(e){return bG.event.special.hover?e:e.replace(ba,"mouseenter$1 mouseleave$1")};bG.event={add:function(b1,b5,cc,b3,b2){var b6,b4,cd,cb,ca,b8,e,b9,bZ,b0,b7;if(b1.nodeType===3||b1.nodeType===8||!b5||!cc||!(b6=bG._data(b1))){return}if(cc.handler){bZ=cc;cc=bZ.handler;b2=bZ.selector}if(!cc.guid){cc.guid=bG.guid++}cd=b6.events;if(!cd){b6.events=cd={}}b4=b6.handle;if(!b4){b6.handle=b4=function(ce){return typeof bG!=="undefined"&&(!ce||bG.event.triggered!==ce.type)?bG.event.dispatch.apply(b4.elem,arguments):aB};b4.elem=b1}b5=bG.trim(aq(b5)).split(" ");for(cb=0;cb=0){ca=ca.slice(0,-1);b1=true}if(ca.indexOf(".")>=0){b0=ca.split(".");ca=b0.shift();b0.sort()}if((!b4||bG.event.customEvent[ca])&&!bG.event.global[ca]){return}bZ=typeof bZ==="object"?bZ[bG.expando]?bZ:new bG.Event(ca,bZ):new bG.Event(ca);bZ.type=ca;bZ.isTrigger=true;bZ.exclusive=b1;bZ.namespace=b0.join(".");bZ.namespace_re=bZ.namespace?new RegExp("(^|\\.)"+b0.join("\\.(?:.*\\.|)")+"(\\.|$)"):null;b2=ca.indexOf(":")<0?"on"+ca:"";if(!b4){e=bG.cache;for(b7 in e){if(e[b7].events&&e[b7].events[ca]){bG.event.trigger(bZ,b6,e[b7].handle.elem,true)}}return}bZ.result=aB;if(!bZ.target){bZ.target=b4}b6=b6!=null?bG.makeArray(b6):[];b6.unshift(bZ);b9=bG.event.special[ca]||{};if(b9.trigger&&b9.trigger.apply(b4,b6)===false){return}b5=[[b4,b9.bindType||ca]];if(!cd&&!b9.noBubble&&!bG.isWindow(b4)){cc=b9.delegateType||ca;cb=by.test(cc+ca)?b4:b4.parentNode;for(b3=b4;cb;cb=cb.parentNode){b5.push([cb,cc]);b3=cb}if(b3===(b4.ownerDocument||o)){b5.push([b3.defaultView||b3.parentWindow||a2,cc])}}for(b7=0;b7=0:bG.find(b1,this,null,[ce]).length}if(b7[b1]){b6.push(cc)}}if(b6.length){cb.push({elem:ce,matches:b6})}}}}if(b2.length>b3){cb.push({elem:this,matches:b2.slice(b3)})}for(b5=0;b50?this.on(e,null,b1,b0):this.trigger(e)};if(a3.test(e)){bG.event.fixHooks[e]=bG.event.keyHooks}if(bK.test(e)){bG.event.fixHooks[e]=bG.event.mouseHooks}}); +/*! + * Sizzle CSS Selector Engine + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://sizzlejs.com/ + */ +(function(cS,ch){var cX,ca,cL,b0,cm,cA,cd,cg,cc,cJ,b9=true,cu="undefined",cZ=("sizcache"+Math.random()).replace(".",""),b4=String,b8=cS.document,cb=b8.documentElement,cr=0,cf=0,cE=[].pop,cW=[].push,cl=[].slice,co=[].indexOf||function(c8){var c7=0,e=this.length;for(;c7cL.cacheLength){delete e[c7.shift()]}return(e[c8+" "]=c9)},e)},cU=c5(),cV=c5(),cn=c5(),cy="[\\x20\\t\\r\\n\\f]",ck="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",ci=ck.replace("w","w#"),c4="([*^$|!~]?=)",cP="\\["+cy+"*("+ck+")"+cy+"*(?:"+c4+cy+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+ci+")|)|)"+cy+"*\\]",c6=":("+ck+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+cP+")|[^:]|\\\\.)*|.*))\\)|)",cz=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+cy+"*((?:-\\d)?\\d*)"+cy+"*\\)|)(?=[^-]|$)",cT=new RegExp("^"+cy+"+|((?:^|[^\\\\])(?:\\\\.)*)"+cy+"+$","g"),b5=new RegExp("^"+cy+"*,"+cy+"*"),cH=new RegExp("^"+cy+"*([\\x20\\t\\r\\n\\f>+~])"+cy+"*"),cM=new RegExp(c6),cO=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,cD=/^:not/,cR=/[\x20\t\r\n\f]*[+~]/,c0=/:not\($/,cs=/h\d/i,cN=/input|select|textarea|button/i,ct=/\\(?!\\)/g,cG={ID:new RegExp("^#("+ck+")"),CLASS:new RegExp("^\\.("+ck+")"),NAME:new RegExp("^\\[name=['\"]?("+ck+")['\"]?\\]"),TAG:new RegExp("^("+ck.replace("w","w*")+")"),ATTR:new RegExp("^"+cP),PSEUDO:new RegExp("^"+c6),POS:new RegExp(cz,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+cy+"*(even|odd|(([+-]|)(\\d*)n|)"+cy+"*(?:([+-]|)"+cy+"*(\\d+)|))"+cy+"*\\)|)","i"),needsContext:new RegExp("^"+cy+"*[>+~]|"+cz,"i")},cK=function(c7){var c9=b8.createElement("div");try{return c7(c9)}catch(c8){return false}finally{c9=null}},b7=cK(function(e){e.appendChild(b8.createComment(""));return !e.getElementsByTagName("*").length}),cC=cK(function(e){e.innerHTML="";return e.firstChild&&typeof e.firstChild.getAttribute!==cu&&e.firstChild.getAttribute("href")==="#"}),cq=cK(function(c7){c7.innerHTML="";var e=typeof c7.lastChild.getAttribute("multiple");return e!=="boolean"&&e!=="string"}),cB=cK(function(e){e.innerHTML="";if(!e.getElementsByClassName||!e.getElementsByClassName("e").length){return false}e.lastChild.className="e";return e.getElementsByClassName("e").length===2}),bZ=cK(function(c7){c7.id=cZ+0;c7.innerHTML="
      ";cb.insertBefore(c7,cb.firstChild);var e=b8.getElementsByName&&b8.getElementsByName(cZ).length===2+b8.getElementsByName(cZ+0).length;ca=!b8.getElementById(cZ);cb.removeChild(c7);return e});try{cl.call(cb.childNodes,0)[0].nodeType}catch(c3){cl=function(c7){var c8,e=[];for(;(c8=this[c7]);c7++){e.push(c8)}return e}}function cQ(c9,e,db,de){db=db||[];e=e||b8;var dc,c7,dd,c8,da=e.nodeType;if(!c9||typeof c9!=="string"){return db}if(da!==1&&da!==9){return[]}dd=cm(e);if(!dd&&!de){if((dc=cO.exec(c9))){if((c8=dc[1])){if(da===9){c7=e.getElementById(c8);if(c7&&c7.parentNode){if(c7.id===c8){db.push(c7);return db}}else{return db}}else{if(e.ownerDocument&&(c7=e.ownerDocument.getElementById(c8))&&cA(e,c7)&&c7.id===c8){db.push(c7);return db}}}else{if(dc[2]){cW.apply(db,cl.call(e.getElementsByTagName(c9),0));return db}else{if((c8=dc[3])&&cB&&e.getElementsByClassName){cW.apply(db,cl.call(e.getElementsByClassName(c8),0));return db}}}}}return cY(c9.replace(cT,"$1"),e,db,de,dd)}cQ.matches=function(c7,e){return cQ(c7,null,null,e)};cQ.matchesSelector=function(e,c7){return cQ(c7,null,null,[e]).length>0};function cI(e){return function(c8){var c7=c8.nodeName.toLowerCase();return c7==="input"&&c8.type===e}}function b3(e){return function(c8){var c7=c8.nodeName.toLowerCase();return(c7==="input"||c7==="button")&&c8.type===e}}function cF(e){return c1(function(c7){c7=+c7;return c1(function(c8,dc){var da,c9=e([],c8.length,c7),db=c9.length;while(db--){if(c8[(da=c9[db])]){c8[da]=!(dc[da]=c8[da])}}})})}b0=cQ.getText=function(da){var c9,c7="",c8=0,e=da.nodeType;if(e){if(e===1||e===9||e===11){if(typeof da.textContent==="string"){return da.textContent}else{for(da=da.firstChild;da;da=da.nextSibling){c7+=b0(da)}}}else{if(e===3||e===4){return da.nodeValue}}}else{for(;(c9=da[c8]);c8++){c7+=b0(c9)}}return c7};cm=cQ.isXML=function(e){var c7=e&&(e.ownerDocument||e).documentElement;return c7?c7.nodeName!=="HTML":false};cA=cQ.contains=cb.contains?function(c7,e){var c9=c7.nodeType===9?c7.documentElement:c7,c8=e&&e.parentNode;return c7===c8||!!(c8&&c8.nodeType===1&&c9.contains&&c9.contains(c8))}:cb.compareDocumentPosition?function(c7,e){return e&&!!(c7.compareDocumentPosition(e)&16)}:function(c7,e){while((e=e.parentNode)){if(e===c7){return true}}return false};cQ.attr=function(c8,c7){var c9,e=cm(c8);if(!e){c7=c7.toLowerCase()}if((c9=cL.attrHandle[c7])){return c9(c8)}if(e||cq){return c8.getAttribute(c7)}c9=c8.getAttributeNode(c7);return c9?typeof c8[c7]==="boolean"?c8[c7]?c7:null:c9.specified?c9.value:null:null};cL=cQ.selectors={cacheLength:50,createPseudo:c1,match:cG,attrHandle:cC?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:ca?function(c9,c8,c7){if(typeof c8.getElementById!==cu&&!c7){var e=c8.getElementById(c9);return e&&e.parentNode?[e]:[]}}:function(c9,c8,c7){if(typeof c8.getElementById!==cu&&!c7){var e=c8.getElementById(c9);return e?e.id===c9||typeof e.getAttributeNode!==cu&&e.getAttributeNode("id").value===c9?[e]:ch:[]}},TAG:b7?function(e,c7){if(typeof c7.getElementsByTagName!==cu){return c7.getElementsByTagName(e)}}:function(e,da){var c9=da.getElementsByTagName(e);if(e==="*"){var db,c8=[],c7=0;for(;(db=c9[c7]);c7++){if(db.nodeType===1){c8.push(db)}}return c8}return c9},NAME:bZ&&function(e,c7){if(typeof c7.getElementsByName!==cu){return c7.getElementsByName(name)}},CLASS:cB&&function(c8,c7,e){if(typeof c7.getElementsByClassName!==cu&&!e){return c7.getElementsByClassName(c8)}}},relative:{">":{dir:"parentNode",first:true}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:true},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){e[1]=e[1].replace(ct,"");e[3]=(e[4]||e[5]||"").replace(ct,"");if(e[2]==="~="){e[3]=" "+e[3]+" "}return e.slice(0,4)},CHILD:function(e){e[1]=e[1].toLowerCase();if(e[1]==="nth"){if(!e[2]){cQ.error(e[0])}e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd"));e[4]=+((e[6]+e[7])||e[2]==="odd")}else{if(e[2]){cQ.error(e[0])}}return e},PSEUDO:function(c7){var c8,e;if(cG.CHILD.test(c7[0])){return null}if(c7[3]){c7[2]=c7[3]}else{if((c8=c7[4])){if(cM.test(c8)&&(e=b1(c8,true))&&(e=c8.indexOf(")",c8.length-e)-c8.length)){c8=c8.slice(0,e);c7[0]=c7[0].slice(0,e)}c7[2]=c8}}return c7.slice(0,3)}},filter:{ID:ca?function(e){e=e.replace(ct,"");return function(c7){return c7.getAttribute("id")===e}}:function(e){e=e.replace(ct,"");return function(c8){var c7=typeof c8.getAttributeNode!==cu&&c8.getAttributeNode("id");return c7&&c7.value===e}},TAG:function(e){if(e==="*"){return function(){return true}}e=e.replace(ct,"").toLowerCase();return function(c7){return c7.nodeName&&c7.nodeName.toLowerCase()===e}},CLASS:function(e){var c7=cU[cZ][e+" "];return c7||(c7=new RegExp("(^|"+cy+")"+e+"("+cy+"|$)"))&&cU(e,function(c8){return c7.test(c8.className||(typeof c8.getAttribute!==cu&&c8.getAttribute("class"))||"")})},ATTR:function(c8,c7,e){return function(db,da){var c9=cQ.attr(db,c8);if(c9==null){return c7==="!="}if(!c7){return true}c9+="";return c7==="="?c9===e:c7==="!="?c9!==e:c7==="^="?e&&c9.indexOf(e)===0:c7==="*="?e&&c9.indexOf(e)>-1:c7==="$="?e&&c9.substr(c9.length-e.length)===e:c7==="~="?(" "+c9+" ").indexOf(e)>-1:c7==="|="?c9===e||c9.substr(0,e.length+1)===e+"-":false}},CHILD:function(e,c8,c9,c7){if(e==="nth"){return function(dc){var db,dd,da=dc.parentNode;if(c9===1&&c7===0){return true}if(da){dd=0;for(db=da.firstChild;db;db=db.nextSibling){if(db.nodeType===1){dd++;if(dc===db){break}}}}dd-=c7;return dd===c9||(dd%c9===0&&dd/c9>=0)}}return function(db){var da=db;switch(e){case"only":case"first":while((da=da.previousSibling)){if(da.nodeType===1){return false}}if(e==="first"){return true}da=db;case"last":while((da=da.nextSibling)){if(da.nodeType===1){return false}}return true}}},PSEUDO:function(c9,c8){var e,c7=cL.pseudos[c9]||cL.setFilters[c9.toLowerCase()]||cQ.error("unsupported pseudo: "+c9);if(c7[cZ]){return c7(c8)}if(c7.length>1){e=[c9,c9,"",c8];return cL.setFilters.hasOwnProperty(c9.toLowerCase())?c1(function(dc,de){var db,da=c7(dc,c8),dd=da.length;while(dd--){db=co.call(dc,da[dd]);dc[db]=!(de[db]=da[dd])}}):function(da){return c7(da,0,e)}}return c7}},pseudos:{not:c1(function(e){var c7=[],c8=[],c9=cd(e.replace(cT,"$1"));return c9[cZ]?c1(function(db,dg,de,dc){var df,da=c9(db,null,dc,[]),dd=db.length;while(dd--){if((df=da[dd])){db[dd]=!(dg[dd]=df)}}}):function(dc,db,da){c7[0]=dc;c9(c7,null,da,c8);return !c8.pop()}}),has:c1(function(e){return function(c7){return cQ(e,c7).length>0}}),contains:c1(function(e){return function(c7){return(c7.textContent||c7.innerText||b0(c7)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===false},disabled:function(e){return e.disabled===true},checked:function(e){var c7=e.nodeName.toLowerCase();return(c7==="input"&&!!e.checked)||(c7==="option"&&!!e.selected)},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !cL.pseudos.empty(e)},empty:function(c7){var e;c7=c7.firstChild;while(c7){if(c7.nodeName>"@"||(e=c7.nodeType)===3||e===4){return false}c7=c7.nextSibling}return true},header:function(e){return cs.test(e.nodeName)},text:function(c8){var c7,e;return c8.nodeName.toLowerCase()==="input"&&(c7=c8.type)==="text"&&((e=c8.getAttribute("type"))==null||e.toLowerCase()===c7)},radio:cI("radio"),checkbox:cI("checkbox"),file:cI("file"),password:cI("password"),image:cI("image"),submit:b3("submit"),reset:b3("reset"),button:function(c7){var e=c7.nodeName.toLowerCase();return e==="input"&&c7.type==="button"||e==="button"},input:function(e){return cN.test(e.nodeName)},focus:function(e){var c7=e.ownerDocument;return e===c7.activeElement&&(!c7.hasFocus||c7.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:cF(function(){return[0]}),last:cF(function(e,c7){return[c7-1]}),eq:cF(function(e,c8,c7){return[c7<0?c7+c8:c7]}),even:cF(function(e,c8){for(var c7=0;c7=0;){e.push(c7)}return e}),gt:cF(function(e,c9,c8){for(var c7=c8<0?c8+c9:c8;++c71?function(da,c9,c7){var c8=e.length;while(c8--){if(!e[c8](da,c9,c7)){return false}}return true}:e[0]}function cv(e,c7,c8,c9,dc){var da,df=[],db=0,dd=e.length,de=c7!=null;for(;db-1){dm[dp]=!(dj[dp]=dg)}}}}else{di=cv(di===dj?di.splice(dd,di.length):di);if(db){db(null,dj,di,dl)}else{cW.apply(dj,di)}}})}function cx(dc){var c7,da,c8,db=dc.length,df=cL.relative[dc[0].type],dg=df||cL.relative[" "],c9=df?1:0,dd=cw(function(dh){return dh===c7},dg,true),de=cw(function(dh){return co.call(c7,dh)>-1},dg,true),e=[function(dj,di,dh){return(!df&&(dh||di!==cJ))||((c7=di).nodeType?dd(dj,di,dh):de(dj,di,dh))}];for(;c91&&ce(e),c9>1&&dc.slice(0,c9-1).join("").replace(cT,"$1"),da,c90,da=c9.length>0,c7=function(dk,de,dj,di,dr){var df,dg,dl,dq=[],dp=0,dh="0",db=dk&&[],dm=dr!=null,dn=cJ,dd=dk||da&&cL.find.TAG("*",dr&&de.parentNode||de),dc=(cr+=dn==null?1:Math.E);if(dm){cJ=de!==b8&&de;cX=c7.el}for(;(df=dd[dh])!=null;dh++){if(da&&df){for(dg=0;(dl=c9[dg]);dg++){if(dl(df,de,dj)){di.push(df);break}}if(dm){cr=dc;cX=++c7.el}}if(e){if((df=!dl&&df)){dp--}if(dk){db.push(df)}}}dp+=dh;if(e&&dh!==dp){for(dg=0;(dl=c8[dg]);dg++){dl(db,dq,de,dj)}if(dk){if(dp>0){while(dh--){if(!(db[dh]||dq[dh])){dq[dh]=cE.call(di)}}}dq=cv(dq)}cW.apply(di,dq);if(dm&&!dk&&dq.length>0&&(dp+c8.length)>1){cQ.uniqueSort(di)}}if(dm){cr=dc;cJ=dn}return db};c7.el=0;return e?c1(c7):c7}cd=cQ.compile=function(e,db){var c8,c7=[],da=[],c9=cn[cZ][e+" "];if(!c9){if(!db){db=b1(e)}c8=db.length;while(c8--){c9=cx(db[c8]);if(c9[cZ]){c7.push(c9)}else{da.push(c9)}}c9=cn(e,b6(da,c7))}return c9};function cp(c7,da,c9){var c8=0,e=da.length;for(;c82&&(c7=dh[0]).type==="ID"&&e.nodeType===9&&!dd&&cL.relative[dh[1].type]){e=cL.find.ID(c7.matches[0].replace(ct,""),e,dd)[0];if(!e){return da}c8=c8.slice(dh.shift().length)}for(db=cG.POS.test(c8)?-1:dh.length-1;db>=0;db--){c7=dh[db];if(cL.relative[(dg=c7.type)]){break}if((df=cL.find[dg])){if((de=df(c7.matches[0].replace(ct,""),cR.test(dh[0].type)&&e.parentNode||e,dd))){dh.splice(db,1);c8=de.length&&dh.join("");if(!c8){cW.apply(da,cl.call(de,0));return da}break}}}}}cd(c8,dc)(de,e,dd,da,cR.test(c8));return da}if(b8.querySelectorAll){(function(){var db,dc=cY,da=/'|\\/g,c8=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,c7=[":focus"],e=[":active"],c9=cb.matchesSelector||cb.mozMatchesSelector||cb.webkitMatchesSelector||cb.oMatchesSelector||cb.msMatchesSelector;cK(function(dd){dd.innerHTML="";if(!dd.querySelectorAll("[selected]").length){c7.push("\\["+cy+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)")}if(!dd.querySelectorAll(":checked").length){c7.push(":checked")}});cK(function(dd){dd.innerHTML="

      ";if(dd.querySelectorAll("[test^='']").length){c7.push("[*^$]="+cy+"*(?:\"\"|'')")}dd.innerHTML="";if(!dd.querySelectorAll(":enabled").length){c7.push(":enabled",":disabled")}});c7=new RegExp(c7.join("|"));cY=function(dj,de,dl,dp,dn){if(!dp&&!dn&&!c7.test(dj)){var dh,dm,dg=true,dd=cZ,df=de,dk=de.nodeType===9&&dj;if(de.nodeType===1&&de.nodeName.toLowerCase()!=="object"){dh=b1(dj);if((dg=de.getAttribute("id"))){dd=dg.replace(da,"\\$&")}else{de.setAttribute("id",dd)}dd="[id='"+dd+"'] ";dm=dh.length;while(dm--){dh[dm]=dd+dh[dm].join("")}df=cR.test(dj)&&de.parentNode||de;dk=dh.join(",")}if(dk){try{cW.apply(dl,cl.call(df.querySelectorAll(dk),0));return dl}catch(di){}finally{if(!dg){de.removeAttribute("id")}}}}return dc(dj,de,dl,dp,dn)};if(c9){cK(function(de){db=c9.call(de,"div");try{c9.call(de,"[test!='']:sizzle");e.push("!=",c6)}catch(dd){}});e=new RegExp(e.join("|"));cQ.matchesSelector=function(de,dg){dg=dg.replace(c8,"='$1']");if(!cm(de)&&!e.test(dg)&&!c7.test(dg)){try{var dd=c9.call(de,dg);if(dd||db||de.document&&de.document.nodeType!==11){return dd}}catch(df){}}return cQ(dg,null,null,[de]).length>0}}})()}cL.pseudos.nth=cL.pseudos.eq;function cj(){}cL.filters=cj.prototype=cL.pseudos;cL.setFilters=new cj();cQ.attr=bG.attr;bG.find=cQ;bG.expr=cQ.selectors;bG.expr[":"]=bG.expr.pseudos;bG.unique=cQ.uniqueSort;bG.text=cQ.getText;bG.isXMLDoc=cQ.isXML;bG.contains=cQ.contains})(a2);var ag=/Until$/,bq=/^(?:parents|prev(?:Until|All))/,al=/^.[^:#\[\.,]*$/,y=bG.expr.match.needsContext,bu={children:true,contents:true,next:true,prev:true};bG.fn.extend({find:function(e){var b2,bZ,b4,b5,b3,b1,b0=this;if(typeof e!=="string"){return bG(e).filter(function(){for(b2=0,bZ=b0.length;b20){for(b5=b4;b5=0:bG.filter(e,this).length>0:this.filter(e).length>0)},closest:function(b2,b1){var b3,b0=0,e=this.length,bZ=[],b4=y.test(b2)||typeof b2!=="string"?bG(b2,b1||this.context):0;for(;b0-1:bG.find.matchesSelector(b3,b2)){bZ.push(b3);break}b3=b3.parentNode}}bZ=bZ.length>1?bG.unique(bZ):bZ;return this.pushStack(bZ,"closest",b2)},index:function(e){if(!e){return(this[0]&&this[0].parentNode)?this.prevAll().length:-1}if(typeof e==="string"){return bG.inArray(this[0],bG(e))}return bG.inArray(e.jquery?e[0]:e,this)},add:function(e,bZ){var b1=typeof e==="string"?bG(e,bZ):bG.makeArray(e&&e.nodeType?[e]:e),b0=bG.merge(this.get(),b1);return this.pushStack(aR(b1[0])||aR(b0[0])?b0:bG.unique(b0))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}});bG.fn.andSelf=bG.fn.addBack;function aR(e){return !e||!e.parentNode||e.parentNode.nodeType===11}function aY(bZ,e){do{bZ=bZ[e]}while(bZ&&bZ.nodeType!==1);return bZ}bG.each({parent:function(bZ){var e=bZ.parentNode;return e&&e.nodeType!==11?e:null},parents:function(e){return bG.dir(e,"parentNode")},parentsUntil:function(bZ,e,b0){return bG.dir(bZ,"parentNode",b0)},next:function(e){return aY(e,"nextSibling")},prev:function(e){return aY(e,"previousSibling")},nextAll:function(e){return bG.dir(e,"nextSibling")},prevAll:function(e){return bG.dir(e,"previousSibling")},nextUntil:function(bZ,e,b0){return bG.dir(bZ,"nextSibling",b0)},prevUntil:function(bZ,e,b0){return bG.dir(bZ,"previousSibling",b0)},siblings:function(e){return bG.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return bG.sibling(e.firstChild)},contents:function(e){return bG.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:bG.merge([],e.childNodes)}},function(e,bZ){bG.fn[e]=function(b2,b0){var b1=bG.map(this,bZ,b2);if(!ag.test(e)){b0=b2}if(b0&&typeof b0==="string"){b1=bG.filter(b0,b1)}b1=this.length>1&&!bu[e]?bG.unique(b1):b1;if(this.length>1&&bq.test(e)){b1=b1.reverse()}return this.pushStack(b1,e,a4.call(arguments).join(","))}});bG.extend({filter:function(b0,e,bZ){if(bZ){b0=":not("+b0+")"}return e.length===1?bG.find.matchesSelector(e[0],b0)?[e[0]]:[]:bG.find.matches(b0,e)},dir:function(b0,bZ,b2){var e=[],b1=b0[bZ];while(b1&&b1.nodeType!==9&&(b2===aB||b1.nodeType!==1||!bG(b1).is(b2))){if(b1.nodeType===1){e.push(b1)}b1=b1[bZ]}return e},sibling:function(b0,bZ){var e=[];for(;b0;b0=b0.nextSibling){if(b0.nodeType===1&&b0!==bZ){e.push(b0)}}return e}});function aM(b1,b0,e){b0=b0||0;if(bG.isFunction(b0)){return bG.grep(b1,function(b3,b2){var b4=!!b0.call(b3,b2,b3);return b4===e})}else{if(b0.nodeType){return bG.grep(b1,function(b3,b2){return(b3===b0)===e})}else{if(typeof b0==="string"){var bZ=bG.grep(b1,function(b2){return b2.nodeType===1});if(al.test(b0)){return bG.filter(b0,bZ,!e)}else{b0=bG.filter(b0,bZ)}}}}return bG.grep(b1,function(b3,b2){return(bG.inArray(b3,b0)>=0)===e})}function A(e){var b0=c.split("|"),bZ=e.createDocumentFragment();if(bZ.createElement){while(b0.length){bZ.createElement(b0.pop())}}return bZ}var c="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",av=/ jQuery\d+="(?:null|\d+)"/g,bY=/^\s+/,ay=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,p=/<([\w:]+)/,bT=/]","i"),aE=/^(?:checkbox|radio)$/,bR=/checked\s*(?:[^=]|=\s*.checked.)/i,bw=/\/(java|ecma)script/i,aH=/^\s*\s*$/g,T={option:[1,""],legend:[1,"
      ","
      "],thead:[1,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],col:[2,"","
      "],area:[1,"",""],_default:[0,"",""]},aQ=A(o),l=aQ.appendChild(o.createElement("div"));T.optgroup=T.option;T.tbody=T.tfoot=T.colgroup=T.caption=T.thead;T.th=T.td;if(!bG.support.htmlSerialize){T._default=[1,"X
      ","
      "]}bG.fn.extend({text:function(e){return bG.access(this,function(bZ){return bZ===aB?bG.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(bZ))},null,e,arguments.length)},wrapAll:function(e){if(bG.isFunction(e)){return this.each(function(b0){bG(this).wrapAll(e.call(this,b0))})}if(this[0]){var bZ=bG(e,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){bZ.insertBefore(this[0])}bZ.map(function(){var b0=this;while(b0.firstChild&&b0.firstChild.nodeType===1){b0=b0.firstChild}return b0}).append(this)}return this},wrapInner:function(e){if(bG.isFunction(e)){return this.each(function(bZ){bG(this).wrapInner(e.call(this,bZ))})}return this.each(function(){var bZ=bG(this),b0=bZ.contents();if(b0.length){b0.wrapAll(e)}else{bZ.append(e)}})},wrap:function(e){var bZ=bG.isFunction(e);return this.each(function(b0){bG(this).wrapAll(bZ?e.call(this,b0):e)})},unwrap:function(){return this.parent().each(function(){if(!bG.nodeName(this,"body")){bG(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1||this.nodeType===11){this.appendChild(e)}})},prepend:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1||this.nodeType===11){this.insertBefore(e,this.firstChild)}})},before:function(){if(!aR(this[0])){return this.domManip(arguments,false,function(bZ){this.parentNode.insertBefore(bZ,this)})}if(arguments.length){var e=bG.clean(arguments);return this.pushStack(bG.merge(e,this),"before",this.selector)}},after:function(){if(!aR(this[0])){return this.domManip(arguments,false,function(bZ){this.parentNode.insertBefore(bZ,this.nextSibling)})}if(arguments.length){var e=bG.clean(arguments);return this.pushStack(bG.merge(this,e),"after",this.selector)}},remove:function(e,b1){var b0,bZ=0;for(;(b0=this[bZ])!=null;bZ++){if(!e||bG.filter(e,[b0]).length){if(!b1&&b0.nodeType===1){bG.cleanData(b0.getElementsByTagName("*"));bG.cleanData([b0])}if(b0.parentNode){b0.parentNode.removeChild(b0)}}}return this},empty:function(){var bZ,e=0;for(;(bZ=this[e])!=null;e++){if(bZ.nodeType===1){bG.cleanData(bZ.getElementsByTagName("*"))}while(bZ.firstChild){bZ.removeChild(bZ.firstChild)}}return this},clone:function(bZ,e){bZ=bZ==null?false:bZ;e=e==null?bZ:e;return this.map(function(){return bG.clone(this,bZ,e)})},html:function(e){return bG.access(this,function(b2){var b1=this[0]||{},b0=0,bZ=this.length;if(b2===aB){return b1.nodeType===1?b1.innerHTML.replace(av,""):aB}if(typeof b2==="string"&&!aj.test(b2)&&(bG.support.htmlSerialize||!K.test(b2))&&(bG.support.leadingWhitespace||!bY.test(b2))&&!T[(p.exec(b2)||["",""])[1].toLowerCase()]){b2=b2.replace(ay,"<$1>");try{for(;b01&&typeof b5==="string"&&bR.test(b5)){return this.each(function(){bG(this).domManip(b4,b8,b7)})}if(bG.isFunction(b5)){return this.each(function(ca){var b9=bG(this);b4[0]=b5.call(this,ca,b8?b9.html():aB);b9.domManip(b4,b8,b7)})}if(this[0]){b0=bG.buildFragment(b4,this,bZ);b3=b0.fragment;b2=b3.firstChild;if(b3.childNodes.length===1){b3=b2}if(b2){b8=b8&&bG.nodeName(b2,"tr");for(b6=b0.cacheable||e-1;b10?this.clone(true):this).get();bG(b6[b4])[bZ](b2);b3=b3.concat(b2)}return this.pushStack(b3,e,b6.selector)}}});function m(e){if(typeof e.getElementsByTagName!=="undefined"){return e.getElementsByTagName("*")}else{if(typeof e.querySelectorAll!=="undefined"){return e.querySelectorAll("*")}else{return[]}}}function bS(e){if(aE.test(e.type)){e.defaultChecked=e.checked}}bG.extend({clone:function(b2,b4,b0){var e,bZ,b1,b3;if(bG.support.html5Clone||bG.isXMLDoc(b2)||!K.test("<"+b2.nodeName+">")){b3=b2.cloneNode(true)}else{l.innerHTML=b2.outerHTML;l.removeChild(b3=l.firstChild)}if((!bG.support.noCloneEvent||!bG.support.noCloneChecked)&&(b2.nodeType===1||b2.nodeType===11)&&!bG.isXMLDoc(b2)){F(b2,b3);e=m(b2);bZ=m(b3);for(b1=0;e[b1];++b1){if(bZ[b1]){F(e[b1],bZ[b1])}}}if(b4){ao(b2,b3);if(b0){e=m(b2);bZ=m(b3);for(b1=0;e[b1];++b1){ao(e[b1],bZ[b1])}}}e=bZ=null;return b3},clean:function(cb,b0,e,b1){var b8,b7,ca,cf,b4,ce,b5,b2,bZ,b9,cd,b6,b3=b0===o&&aQ,cc=[];if(!b0||typeof b0.createDocumentFragment==="undefined"){b0=o}for(b8=0;(ca=cb[b8])!=null;b8++){if(typeof ca==="number"){ca+=""}if(!ca){continue}if(typeof ca==="string"){if(!J.test(ca)){ca=b0.createTextNode(ca)}else{b3=b3||A(b0);b5=b0.createElement("div");b3.appendChild(b5);ca=ca.replace(ay,"<$1>");cf=(p.exec(ca)||["",""])[1].toLowerCase();b4=T[cf]||T._default;ce=b4[0];b5.innerHTML=b4[1]+ca+b4[2];while(ce--){b5=b5.lastChild}if(!bG.support.tbody){b2=bT.test(ca);bZ=cf==="table"&&!b2?b5.firstChild&&b5.firstChild.childNodes:b4[1]===""&&!b2?b5.childNodes:[];for(b7=bZ.length-1;b7>=0;--b7){if(bG.nodeName(bZ[b7],"tbody")&&!bZ[b7].childNodes.length){bZ[b7].parentNode.removeChild(bZ[b7])}}}if(!bG.support.leadingWhitespace&&bY.test(ca)){b5.insertBefore(b0.createTextNode(bY.exec(ca)[0]),b5.firstChild)}ca=b5.childNodes;b5.parentNode.removeChild(b5)}}if(ca.nodeType){cc.push(ca)}else{bG.merge(cc,ca)}}if(b5){ca=b5=b3=null}if(!bG.support.appendChecked){for(b8=0;(ca=cc[b8])!=null;b8++){if(bG.nodeName(ca,"input")){bS(ca)}else{if(typeof ca.getElementsByTagName!=="undefined"){bG.grep(ca.getElementsByTagName("input"),bS)}}}}if(e){cd=function(cg){if(!cg.type||bw.test(cg.type)){return b1?b1.push(cg.parentNode?cg.parentNode.removeChild(cg):cg):e.appendChild(cg)}};for(b8=0;(ca=cc[b8])!=null;b8++){if(!(bG.nodeName(ca,"script")&&cd(ca))){e.appendChild(ca);if(typeof ca.getElementsByTagName!=="undefined"){b6=bG.grep(bG.merge([],ca.getElementsByTagName("script")),cd);cc.splice.apply(cc,[b8+1,0].concat(b6));b8+=b6.length}}}}return cc},cleanData:function(bZ,b7){var b2,b0,b1,b6,b3=0,b8=bG.expando,e=bG.cache,b4=bG.support.deleteExpando,b5=bG.event.special;for(;(b1=bZ[b3])!=null;b3++){if(b7||bG.acceptData(b1)){b0=b1[b8];b2=b0&&e[b0];if(b2){if(b2.events){for(b6 in b2.events){if(b5[b6]){bG.event.remove(b1,b6)}else{bG.removeEvent(b1,b6,b2.handle)}}}if(e[b0]){delete e[b0];if(b4){delete b1[b8]}else{if(b1.removeAttribute){b1.removeAttribute(b8)}else{b1[b8]=null}}bG.deletedIds.push(b0)}}}}}});(function(){var e,bZ;bG.uaMatch=function(b1){b1=b1.toLowerCase();var b0=/(chrome)[ \/]([\w.]+)/.exec(b1)||/(webkit)[ \/]([\w.]+)/.exec(b1)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(b1)||/(msie) ([\w.]+)/.exec(b1)||b1.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(b1)||[];return{browser:b0[1]||"",version:b0[2]||"0"}};e=bG.uaMatch(d.userAgent);bZ={};if(e.browser){bZ[e.browser]=true;bZ.version=e.version}if(bZ.chrome){bZ.webkit=true}else{if(bZ.webkit){bZ.safari=true}}bG.browser=bZ;bG.sub=function(){function b0(b3,b4){return new b0.fn.init(b3,b4)}bG.extend(true,b0,this);b0.superclass=this;b0.fn=b0.prototype=this();b0.fn.constructor=b0;b0.sub=this.sub;b0.fn.init=function b2(b3,b4){if(b4&&b4 instanceof bG&&!(b4 instanceof b0)){b4=b0(b4)}return bG.fn.init.call(this,b3,b4,b1)};b0.fn.init.prototype=b0.fn;var b1=b0(o);return b0}})();var E,az,aW,be=/alpha\([^)]*\)/i,aS=/opacity=([^)]*)/,bk=/^(top|right|bottom|left)$/,G=/^(none|table(?!-c[ea]).+)/,aZ=/^margin/,a8=new RegExp("^("+bx+")(.*)$","i"),W=new RegExp("^("+bx+")(?!px)[a-z%]+$","i"),S=new RegExp("^([-+])=("+bx+")","i"),bh={BODY:"block"},a9={position:"absolute",visibility:"hidden",display:"block"},bA={letterSpacing:0,fontWeight:400},bQ=["Top","Right","Bottom","Left"],ar=["Webkit","O","Moz","ms"],aJ=bG.fn.toggle;function b(b1,bZ){if(bZ in b1){return bZ}var b2=bZ.charAt(0).toUpperCase()+bZ.slice(1),e=bZ,b0=ar.length;while(b0--){bZ=ar[b0]+b2;if(bZ in b1){return bZ}}return e}function Q(bZ,e){bZ=e||bZ;return bG.css(bZ,"display")==="none"||!bG.contains(bZ.ownerDocument,bZ)}function s(b3,e){var b2,b4,bZ=[],b0=0,b1=b3.length;for(;b01)},show:function(){return s(this,true)},hide:function(){return s(this)},toggle:function(b0,bZ){var e=typeof b0==="boolean";if(bG.isFunction(b0)&&bG.isFunction(bZ)){return aJ.apply(this,arguments)}return this.each(function(){if(e?b0:Q(this)){bG(this).show()}else{bG(this).hide()}})}});bG.extend({cssHooks:{opacity:{get:function(b0,bZ){if(bZ){var e=E(b0,"opacity");return e===""?"1":e}}}},cssNumber:{fillOpacity:true,fontWeight:true,lineHeight:true,opacity:true,orphans:true,widows:true,zIndex:true,zoom:true},cssProps:{"float":bG.support.cssFloat?"cssFloat":"styleFloat"},style:function(b1,b0,b7,b2){if(!b1||b1.nodeType===3||b1.nodeType===8||!b1.style){return}var b5,b6,b8,b3=bG.camelCase(b0),bZ=b1.style;b0=bG.cssProps[b3]||(bG.cssProps[b3]=b(bZ,b3));b8=bG.cssHooks[b0]||bG.cssHooks[b3];if(b7!==aB){b6=typeof b7;if(b6==="string"&&(b5=S.exec(b7))){b7=(b5[1]+1)*b5[2]+parseFloat(bG.css(b1,b0));b6="number"}if(b7==null||b6==="number"&&isNaN(b7)){return}if(b6==="number"&&!bG.cssNumber[b3]){b7+="px"}if(!b8||!("set" in b8)||(b7=b8.set(b1,b7,b2))!==aB){try{bZ[b0]=b7}catch(b4){}}}else{if(b8&&"get" in b8&&(b5=b8.get(b1,false,b2))!==aB){return b5}return bZ[b0]}},css:function(b4,b2,b3,bZ){var b5,b1,e,b0=bG.camelCase(b2);b2=bG.cssProps[b0]||(bG.cssProps[b0]=b(b4.style,b0));e=bG.cssHooks[b2]||bG.cssHooks[b0];if(e&&"get" in e){b5=e.get(b4,true,bZ)}if(b5===aB){b5=E(b4,b2)}if(b5==="normal"&&b2 in bA){b5=bA[b2]}if(b3||bZ!==aB){b1=parseFloat(b5);return b3||bG.isNumeric(b1)?b1||0:b5}return b5},swap:function(b2,b1,b3){var b0,bZ,e={};for(bZ in b1){e[bZ]=b2.style[bZ];b2.style[bZ]=b1[bZ]}b0=b3.call(b2);for(bZ in b1){b2.style[bZ]=e[bZ]}return b0}});if(a2.getComputedStyle){E=function(b5,bZ){var e,b2,b1,b4,b3=a2.getComputedStyle(b5,null),b0=b5.style;if(b3){e=b3.getPropertyValue(bZ)||b3[bZ];if(e===""&&!bG.contains(b5.ownerDocument,b5)){e=bG.style(b5,bZ)}if(W.test(e)&&aZ.test(bZ)){b2=b0.width;b1=b0.minWidth;b4=b0.maxWidth;b0.minWidth=b0.maxWidth=b0.width=e;e=b3.width;b0.width=b2;b0.minWidth=b1;b0.maxWidth=b4}}return e}}else{if(o.documentElement.currentStyle){E=function(b2,b0){var b3,e,bZ=b2.currentStyle&&b2.currentStyle[b0],b1=b2.style;if(bZ==null&&b1&&b1[b0]){bZ=b1[b0]}if(W.test(bZ)&&!bk.test(b0)){b3=b1.left;e=b2.runtimeStyle&&b2.runtimeStyle.left;if(e){b2.runtimeStyle.left=b2.currentStyle.left}b1.left=b0==="fontSize"?"1em":bZ;bZ=b1.pixelLeft+"px";b1.left=b3;if(e){b2.runtimeStyle.left=e}}return bZ===""?"auto":bZ}}}function aG(e,b0,b1){var bZ=a8.exec(b0);return bZ?Math.max(0,bZ[1]-(b1||0))+(bZ[2]||"px"):b0}function at(b1,bZ,e,b3){var b0=e===(b3?"border":"content")?4:bZ==="width"?1:0,b2=0;for(;b0<4;b0+=2){if(e==="margin"){b2+=bG.css(b1,e+bQ[b0],true)}if(b3){if(e==="content"){b2-=parseFloat(E(b1,"padding"+bQ[b0]))||0}if(e!=="margin"){b2-=parseFloat(E(b1,"border"+bQ[b0]+"Width"))||0}}else{b2+=parseFloat(E(b1,"padding"+bQ[b0]))||0;if(e!=="padding"){b2+=parseFloat(E(b1,"border"+bQ[b0]+"Width"))||0}}}return b2}function u(b1,bZ,e){var b2=bZ==="width"?b1.offsetWidth:b1.offsetHeight,b0=true,b3=bG.support.boxSizing&&bG.css(b1,"boxSizing")==="border-box";if(b2<=0||b2==null){b2=E(b1,bZ);if(b2<0||b2==null){b2=b1.style[bZ]}if(W.test(b2)){return b2}b0=b3&&(bG.support.boxSizingReliable||b2===b1.style[bZ]);b2=parseFloat(b2)||0}return(b2+at(b1,bZ,e||(b3?"border":"content"),b0))+"px"}function bC(b0){if(bh[b0]){return bh[b0]}var e=bG("<"+b0+">").appendTo(o.body),bZ=e.css("display");e.remove();if(bZ==="none"||bZ===""){az=o.body.appendChild(az||bG.extend(o.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!aW||!az.createElement){aW=(az.contentWindow||az.contentDocument).document;aW.write("");aW.close()}e=aW.body.appendChild(aW.createElement(b0));bZ=E(e,"display");o.body.removeChild(az)}bh[b0]=bZ;return bZ}bG.each(["height","width"],function(bZ,e){bG.cssHooks[e]={get:function(b2,b1,b0){if(b1){if(b2.offsetWidth===0&&G.test(E(b2,"display"))){return bG.swap(b2,a9,function(){return u(b2,e,b0)})}else{return u(b2,e,b0)}}},set:function(b1,b2,b0){return aG(b1,b2,b0?at(b1,e,b0,bG.support.boxSizing&&bG.css(b1,"boxSizing")==="border-box"):0)}}});if(!bG.support.opacity){bG.cssHooks.opacity={get:function(bZ,e){return aS.test((e&&bZ.currentStyle?bZ.currentStyle.filter:bZ.style.filter)||"")?(0.01*parseFloat(RegExp.$1))+"":e?"1":""},set:function(b2,b3){var b1=b2.style,bZ=b2.currentStyle,e=bG.isNumeric(b3)?"alpha(opacity="+b3*100+")":"",b0=bZ&&bZ.filter||b1.filter||"";b1.zoom=1;if(b3>=1&&bG.trim(b0.replace(be,""))===""&&b1.removeAttribute){b1.removeAttribute("filter");if(bZ&&!bZ.filter){return}}b1.filter=be.test(b0)?b0.replace(be,e):b0+" "+e}}}bG(function(){if(!bG.support.reliableMarginRight){bG.cssHooks.marginRight={get:function(bZ,e){return bG.swap(bZ,{display:"inline-block"},function(){if(e){return E(bZ,"marginRight")}})}}}if(!bG.support.pixelPosition&&bG.fn.position){bG.each(["top","left"],function(e,bZ){bG.cssHooks[bZ]={get:function(b2,b1){if(b1){var b0=E(b2,bZ);return W.test(b0)?bG(b2).position()[bZ]+"px":b0}}}})}});if(bG.expr&&bG.expr.filters){bG.expr.filters.hidden=function(e){return(e.offsetWidth===0&&e.offsetHeight===0)||(!bG.support.reliableHiddenOffsets&&((e.style&&e.style.display)||E(e,"display"))==="none")};bG.expr.filters.visible=function(e){return !bG.expr.filters.hidden(e)}}bG.each({margin:"",padding:"",border:"Width"},function(e,bZ){bG.cssHooks[e+bZ]={expand:function(b2){var b1,b3=typeof b2==="string"?b2.split(" "):[b2],b0={};for(b1=0;b1<4;b1++){b0[e+bQ[b1]+bZ]=b3[b1]||b3[b1-2]||b3[0]}return b0}};if(!aZ.test(e)){bG.cssHooks[e+bZ].set=aG}});var bs=/%20/g,aP=/\[\]$/,U=/\r?\n/g,bz=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,aD=/^(?:select|textarea)/i;bG.fn.extend({serialize:function(){return bG.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?bG.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||aD.test(this.nodeName)||bz.test(this.type))}).map(function(e,bZ){var b0=bG(this).val();return b0==null?null:bG.isArray(b0)?bG.map(b0,function(b2,b1){return{name:bZ.name,value:b2.replace(U,"\r\n")}}):{name:bZ.name,value:b0.replace(U,"\r\n")}}).get()}});bG.param=function(e,b0){var b1,bZ=[],b2=function(b3,b4){b4=bG.isFunction(b4)?b4():(b4==null?"":b4);bZ[bZ.length]=encodeURIComponent(b3)+"="+encodeURIComponent(b4)};if(b0===aB){b0=bG.ajaxSettings&&bG.ajaxSettings.traditional}if(bG.isArray(e)||(e.jquery&&!bG.isPlainObject(e))){bG.each(e,function(){b2(this.name,this.value)})}else{for(b1 in e){k(b1,e[b1],b0,b2)}}return bZ.join("&").replace(bs,"+")};function k(b0,b2,bZ,b1){var e;if(bG.isArray(b2)){bG.each(b2,function(b4,b3){if(bZ||aP.test(b0)){b1(b0,b3)}else{k(b0+"["+(typeof b3==="object"?b4:"")+"]",b3,bZ,b1)}})}else{if(!bZ&&bG.type(b2)==="object"){for(e in b2){k(b0+"["+e+"]",b2[e],bZ,b1)}}else{b1(b0,b2)}}}var bX,Y,an=/#.*$/,ad=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,B=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,r=/^(?:GET|HEAD)$/,aC=/^\/\//,bN=/\?/,g=/)<[^<]*)*<\/script>/gi,P=/([?&])_=[^&]*/,aT=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,bW=bG.fn.load,v={},a6={},aX=["*/"]+["*"];try{Y=aI.href}catch(bd){Y=o.createElement("a");Y.href="";Y=Y.href}bX=aT.exec(Y.toLowerCase())||[];function bI(e){return function(b2,b4){if(typeof b2!=="string"){b4=b2;b2="*"}var bZ,b5,b6,b1=b2.toLowerCase().split(aV),b0=0,b3=b1.length;if(bG.isFunction(b4)){for(;b0=0){e=b1.slice(b3,b1.length);b1=b1.slice(0,b3)}if(bG.isFunction(b4)){b5=b4;b4=aB}else{if(b4&&typeof b4==="object"){b2="POST"}}bG.ajax({url:b1,type:b2,dataType:"html",data:b4,complete:function(b7,b6){if(b5){bZ.each(b5,b0||[b7.responseText,b6,b7])}}}).done(function(b6){b0=arguments;bZ.html(e?bG("
      ").append(b6.replace(g,"")).find(e):b6)});return this};bG.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,bZ){bG.fn[bZ]=function(b0){return this.on(bZ,b0)}});bG.each(["get","post"],function(e,bZ){bG[bZ]=function(b0,b2,b3,b1){if(bG.isFunction(b2)){b1=b1||b3;b3=b2;b2=aB}return bG.ajax({type:bZ,url:b0,data:b2,success:b3,dataType:b1})}});bG.extend({getScript:function(e,bZ){return bG.get(e,aB,bZ,"script")},getJSON:function(e,bZ,b0){return bG.get(e,bZ,b0,"json")},ajaxSetup:function(bZ,e){if(e){t(bZ,bG.ajaxSettings)}else{e=bZ;bZ=bG.ajaxSettings}t(bZ,e);return bZ},ajaxSettings:{url:Y,isLocal:B.test(bX[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":aX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a2.String,"text html":true,"text json":bG.parseJSON,"text xml":bG.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:bI(v),ajaxTransport:bI(a6),ajax:function(b4,b1){if(typeof b4==="object"){b1=b4;b4=aB}b1=b1||{};var b7,cl,b2,cg,b9,cd,b0,cf,b8=bG.ajaxSetup({},b1),cn=b8.context||b8,cb=cn!==b8&&(cn.nodeType||cn instanceof bG)?bG(cn):bG.event,cm=bG.Deferred(),ci=bG.Callbacks("once memory"),b5=b8.statusCode||{},cc={},cj={},b3=0,b6="canceled",ce={readyState:0,setRequestHeader:function(co,cp){if(!b3){var e=co.toLowerCase();co=cj[e]=cj[e]||co;cc[co]=cp}return this},getAllResponseHeaders:function(){return b3===2?cl:null},getResponseHeader:function(co){var e;if(b3===2){if(!b2){b2={};while((e=ad.exec(cl))){b2[e[1].toLowerCase()]=e[2]}}e=b2[co.toLowerCase()]}return e===aB?null:e},overrideMimeType:function(e){if(!b3){b8.mimeType=e}return this},abort:function(e){e=e||b6;if(cg){cg.abort(e)}ca(0,e);return this}};function ca(cs,co,ct,cq){var e,cw,cu,cr,cv,cp=co;if(b3===2){return}b3=2;if(b9){clearTimeout(b9)}cg=aB;cl=cq||"";ce.readyState=cs>0?4:0;if(ct){cr=h(b8,ce,ct)}if(cs>=200&&cs<300||cs===304){if(b8.ifModified){cv=ce.getResponseHeader("Last-Modified");if(cv){bG.lastModified[b7]=cv}cv=ce.getResponseHeader("Etag");if(cv){bG.etag[b7]=cv}}if(cs===304){cp="notmodified";e=true}else{e=ae(b8,cr);cp=e.state;cw=e.data;cu=e.error;e=!cu}}else{cu=cp;if(!cp||cs){cp="error";if(cs<0){cs=0}}}ce.status=cs;ce.statusText=(co||cp)+"";if(e){cm.resolveWith(cn,[cw,cp,ce])}else{cm.rejectWith(cn,[ce,cp,cu])}ce.statusCode(b5);b5=aB;if(b0){cb.trigger("ajax"+(e?"Success":"Error"),[ce,b8,e?cw:cu])}ci.fireWith(cn,[ce,cp]);if(b0){cb.trigger("ajaxComplete",[ce,b8]);if(!(--bG.active)){bG.event.trigger("ajaxStop")}}}cm.promise(ce);ce.success=ce.done;ce.error=ce.fail;ce.complete=ci.add;ce.statusCode=function(co){if(co){var e;if(b3<2){for(e in co){b5[e]=[b5[e],co[e]]}}else{e=co[ce.status];ce.always(e)}}return this};b8.url=((b4||b8.url)+"").replace(an,"").replace(aC,bX[1]+"//");b8.dataTypes=bG.trim(b8.dataType||"*").toLowerCase().split(aV);if(b8.crossDomain==null){cd=aT.exec(b8.url.toLowerCase());b8.crossDomain=!!(cd&&(cd[1]!==bX[1]||cd[2]!==bX[2]||(cd[3]||(cd[1]==="http:"?80:443))!=(bX[3]||(bX[1]==="http:"?80:443))))}if(b8.data&&b8.processData&&typeof b8.data!=="string"){b8.data=bG.param(b8.data,b8.traditional)}q(v,b8,b1,ce);if(b3===2){return ce}b0=b8.global;b8.type=b8.type.toUpperCase();b8.hasContent=!r.test(b8.type);if(b0&&bG.active++===0){bG.event.trigger("ajaxStart")}if(!b8.hasContent){if(b8.data){b8.url+=(bN.test(b8.url)?"&":"?")+b8.data;delete b8.data}b7=b8.url;if(b8.cache===false){var bZ=bG.now(),ck=b8.url.replace(P,"$1_="+bZ);b8.url=ck+((ck===b8.url)?(bN.test(b8.url)?"&":"?")+"_="+bZ:"")}}if(b8.data&&b8.hasContent&&b8.contentType!==false||b1.contentType){ce.setRequestHeader("Content-Type",b8.contentType)}if(b8.ifModified){b7=b7||b8.url;if(bG.lastModified[b7]){ce.setRequestHeader("If-Modified-Since",bG.lastModified[b7])}if(bG.etag[b7]){ce.setRequestHeader("If-None-Match",bG.etag[b7])}}ce.setRequestHeader("Accept",b8.dataTypes[0]&&b8.accepts[b8.dataTypes[0]]?b8.accepts[b8.dataTypes[0]]+(b8.dataTypes[0]!=="*"?", "+aX+"; q=0.01":""):b8.accepts["*"]);for(cf in b8.headers){ce.setRequestHeader(cf,b8.headers[cf])}if(b8.beforeSend&&(b8.beforeSend.call(cn,ce,b8)===false||b3===2)){return ce.abort()}b6="abort";for(cf in {success:1,error:1,complete:1}){ce[cf](b8[cf])}cg=q(a6,b8,b1,ce);if(!cg){ca(-1,"No Transport")}else{ce.readyState=1;if(b0){cb.trigger("ajaxSend",[ce,b8])}if(b8.async&&b8.timeout>0){b9=setTimeout(function(){ce.abort("timeout")},b8.timeout)}try{b3=1;cg.send(cc,ca)}catch(ch){if(b3<2){ca(-1,ch)}else{throw ch}}}return ce},active:0,lastModified:{},etag:{}});function h(b7,b6,b3){var b2,b4,b1,e,bZ=b7.contents,b5=b7.dataTypes,b0=b7.responseFields;for(b4 in b0){if(b4 in b3){b6[b0[b4]]=b3[b4]}}while(b5[0]==="*"){b5.shift();if(b2===aB){b2=b7.mimeType||b6.getResponseHeader("content-type")}}if(b2){for(b4 in bZ){if(bZ[b4]&&bZ[b4].test(b2)){b5.unshift(b4);break}}}if(b5[0] in b3){b1=b5[0]}else{for(b4 in b3){if(!b5[0]||b7.converters[b4+" "+b5[0]]){b1=b4;break}if(!e){e=b4}}b1=b1||e}if(b1){if(b1!==b5[0]){b5.unshift(b1)}return b3[b1]}}function ae(b9,b1){var b7,bZ,b5,b3,b6=b9.dataTypes.slice(),b0=b6[0],b8={},b2=0;if(b9.dataFilter){b1=b9.dataFilter(b1,b9.dataType)}if(b6[1]){for(b7 in b9.converters){b8[b7.toLowerCase()]=b9.converters[b7]}}for(;(b5=b6[++b2]);){if(b5!=="*"){if(b0!=="*"&&b0!==b5){b7=b8[b0+" "+b5]||b8["* "+b5];if(!b7){for(bZ in b8){b3=bZ.split(" ");if(b3[1]===b5){b7=b8[b0+" "+b3[0]]||b8["* "+b3[0]];if(b7){if(b7===true){b7=b8[bZ]}else{if(b8[bZ]!==true){b5=b3[0];b6.splice(b2--,0,b5)}}break}}}}if(b7!==true){if(b7&&b9["throws"]){b1=b7(b1)}else{try{b1=b7(b1)}catch(b4){return{state:"parsererror",error:b7?b4:"No conversion from "+b0+" to "+b5}}}}}b0=b5}}return{state:"success",data:b1}}var bp=[],aw=/\?/,a5=/(=)\?(?=&|$)|\?\?/,bl=bG.now();bG.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=bp.pop()||(bG.expando+"_"+(bl++));this[e]=true;return e}});bG.ajaxPrefilter("json jsonp",function(b8,b3,b7){var b6,e,b5,b1=b8.data,bZ=b8.url,b0=b8.jsonp!==false,b4=b0&&a5.test(bZ),b2=b0&&!b4&&typeof b1==="string"&&!(b8.contentType||"").indexOf("application/x-www-form-urlencoded")&&a5.test(b1);if(b8.dataTypes[0]==="jsonp"||b4||b2){b6=b8.jsonpCallback=bG.isFunction(b8.jsonpCallback)?b8.jsonpCallback():b8.jsonpCallback;e=a2[b6];if(b4){b8.url=bZ.replace(a5,"$1"+b6)}else{if(b2){b8.data=b1.replace(a5,"$1"+b6)}else{if(b0){b8.url+=(aw.test(bZ)?"&":"?")+b8.jsonp+"="+b6}}}b8.converters["script json"]=function(){if(!b5){bG.error(b6+" was not called")}return b5[0]};b8.dataTypes[0]="json";a2[b6]=function(){b5=arguments};b7.always(function(){a2[b6]=e;if(b8[b6]){b8.jsonpCallback=b3.jsonpCallback;bp.push(b6)}if(b5&&bG.isFunction(e)){e(b5[0])}b5=e=aB});return"script"}});bG.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){bG.globalEval(e);return e}}});bG.ajaxPrefilter("script",function(e){if(e.cache===aB){e.cache=false}if(e.crossDomain){e.type="GET";e.global=false}});bG.ajaxTransport("script",function(b0){if(b0.crossDomain){var e,bZ=o.head||o.getElementsByTagName("head")[0]||o.documentElement;return{send:function(b1,b2){e=o.createElement("script");e.async="async";if(b0.scriptCharset){e.charset=b0.scriptCharset}e.src=b0.url;e.onload=e.onreadystatechange=function(b4,b3){if(b3||!e.readyState||/loaded|complete/.test(e.readyState)){e.onload=e.onreadystatechange=null;if(bZ&&e.parentNode){bZ.removeChild(e)}e=aB;if(!b3){b2(200,"success")}}};bZ.insertBefore(e,bZ.firstChild)},abort:function(){if(e){e.onload(0,1)}}}}});var ah,aN=a2.ActiveXObject?function(){for(var e in ah){ah[e](0,1)}}:false,au=0;function bB(){try{return new a2.XMLHttpRequest()}catch(bZ){}}function bb(){try{return new a2.ActiveXObject("Microsoft.XMLHTTP")}catch(bZ){}}bG.ajaxSettings.xhr=a2.ActiveXObject?function(){return !this.isLocal&&bB()||bb()}:bB;(function(e){bG.extend(bG.support,{ajax:!!e,cors:!!e&&("withCredentials" in e)})})(bG.ajaxSettings.xhr());if(bG.support.ajax){bG.ajaxTransport(function(e){if(!e.crossDomain||bG.support.cors){var bZ;return{send:function(b5,b0){var b3,b2,b4=e.xhr();if(e.username){b4.open(e.type,e.url,e.async,e.username,e.password)}else{b4.open(e.type,e.url,e.async)}if(e.xhrFields){for(b2 in e.xhrFields){b4[b2]=e.xhrFields[b2]}}if(e.mimeType&&b4.overrideMimeType){b4.overrideMimeType(e.mimeType)}if(!e.crossDomain&&!b5["X-Requested-With"]){b5["X-Requested-With"]="XMLHttpRequest"}try{for(b2 in b5){b4.setRequestHeader(b2,b5[b2])}}catch(b1){}b4.send((e.hasContent&&e.data)||null);bZ=function(ce,b8){var b9,b7,b6,cc,cb;try{if(bZ&&(b8||b4.readyState===4)){bZ=aB;if(b3){b4.onreadystatechange=bG.noop;if(aN){delete ah[b3]}}if(b8){if(b4.readyState!==4){b4.abort()}}else{b9=b4.status;b6=b4.getAllResponseHeaders();cc={};cb=b4.responseXML;if(cb&&cb.documentElement){cc.xml=cb}try{cc.text=b4.responseText}catch(cd){}try{b7=b4.statusText}catch(cd){b7=""}if(!b9&&e.isLocal&&!e.crossDomain){b9=cc.text?200:404}else{if(b9===1223){b9=204}}}}}catch(ca){if(!b8){b0(-1,ca)}}if(cc){b0(b9,b7,cc,b6)}};if(!e.async){bZ()}else{if(b4.readyState===4){setTimeout(bZ,0)}else{b3=++au;if(aN){if(!ah){ah={};bG(a2).unload(aN)}ah[b3]=bZ}b4.onreadystatechange=bZ}}},abort:function(){if(bZ){bZ(0,1)}}}}})}var L,ab,bO=/^(?:toggle|show|hide)$/,bH=new RegExp("^(?:([-+])=|)("+bx+")([a-z%]*)$","i"),bM=/queueHooks$/,ax=[i],a1={"*":[function(e,b5){var b1,b6,b7=this.createTween(e,b5),b2=bH.exec(b5),b3=b7.cur(),bZ=+b3||0,b0=1,b4=20;if(b2){b1=+b2[2];b6=b2[3]||(bG.cssNumber[e]?"":"px");if(b6!=="px"&&bZ){bZ=bG.css(b7.elem,e,true)||b1||1;do{b0=b0||".5";bZ=bZ/b0;bG.style(b7.elem,e,bZ+b6)}while(b0!==(b0=b7.cur()/b3)&&b0!==1&&--b4)}b7.unit=b6;b7.start=bZ;b7.end=b2[1]?bZ+(b2[1]+1)*b1:b1}return b7}]};function bj(){setTimeout(function(){L=aB},0);return(L=bG.now())}function bc(bZ,e){bG.each(e,function(b4,b2){var b3=(a1[b4]||[]).concat(a1["*"]),b0=0,b1=b3.length;for(;b0-1,b7={},b6={},b0,b2;if(b9){b6=b3.position();b0=b6.top;b2=b6.left}else{b0=parseFloat(e)||0;b2=parseFloat(b8)||0}if(bG.isFunction(ca)){ca=ca.call(b1,b4,bZ)}if(ca.top!=null){b7.top=(ca.top-bZ.top)+b0}if(ca.left!=null){b7.left=(ca.left-bZ.left)+b2}if("using" in ca){ca.using.call(b1,b7)}else{b3.css(b7)}}};bG.fn.extend({position:function(){if(!this[0]){return}var b0=this[0],bZ=this.offsetParent(),b1=this.offset(),e=bm.test(bZ[0].nodeName)?{top:0,left:0}:bZ.offset();b1.top-=parseFloat(bG.css(b0,"marginTop"))||0;b1.left-=parseFloat(bG.css(b0,"marginLeft"))||0;e.top+=parseFloat(bG.css(bZ[0],"borderTopWidth"))||0;e.left+=parseFloat(bG.css(bZ[0],"borderLeftWidth"))||0;return{top:b1.top-e.top,left:b1.left-e.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||o.body;while(e&&(!bm.test(e.nodeName)&&bG.css(e,"position")==="static")){e=e.offsetParent}return e||o.body})}});bG.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b0,bZ){var e=/Y/.test(bZ);bG.fn[b0]=function(b1){return bG.access(this,function(b2,b5,b4){var b3=bn(b2);if(b4===aB){return b3?(bZ in b3)?b3[bZ]:b3.document.documentElement[b5]:b2[b5]}if(b3){b3.scrollTo(!e?b4:bG(b3).scrollLeft(),e?b4:bG(b3).scrollTop())}else{b2[b5]=b4}},b0,b1,arguments.length,null)}});function bn(e){return bG.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:false}bG.each({Height:"height",Width:"width"},function(e,bZ){bG.each({padding:"inner"+e,content:bZ,"":"outer"+e},function(b0,b1){bG.fn[b1]=function(b5,b4){var b3=arguments.length&&(b0||typeof b5!=="boolean"),b2=b0||(b5===true||b4===true?"margin":"border");return bG.access(this,function(b7,b6,b8){var b9;if(bG.isWindow(b7)){return b7.document.documentElement["client"+e]}if(b7.nodeType===9){b9=b7.documentElement;return Math.max(b7.body["scroll"+e],b9["scroll"+e],b7.body["offset"+e],b9["offset"+e],b9["client"+e])}return b8===aB?bG.css(b7,b6,b8,b2):bG.style(b7,b6,b8,b2)},bZ,b3?b5:aB,b3,null)}})});a2.jQuery=a2.$=bG;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return bG})}})(window); \ No newline at end of file diff --git a/phpmyadmin/js/jquery/jquery-ui-1.9.2.custom.js b/phpmyadmin/js/jquery/jquery-ui-1.9.2.custom.js new file mode 100644 index 000000000..a2f24a062 --- /dev/null +++ b/phpmyadmin/js/jquery/jquery-ui-1.9.2.custom.js @@ -0,0 +1,16 @@ +/*! jQuery UI - v1.9.2 - 2012-12-19 +* http://jqueryui.com +* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.menu.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js, jquery.ui.effect.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js +* Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */ +(function(b,f){var a=0,e=/^ui-id-\d+$/;b.ui=b.ui||{};if(b.ui.version){return}b.extend(b.ui,{version:"1.9.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}});b.fn.extend({_focus:b.fn.focus,focus:function(g,h){return typeof g==="number"?this.each(function(){var i=this;setTimeout(function(){b(i).focus();if(h){h.call(i)}},g)}):this._focus.apply(this,arguments)},scrollParent:function(){var g;if((b.ui.ie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){g=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(b.css(this,"position"))&&(/(auto|scroll)/).test(b.css(this,"overflow")+b.css(this,"overflow-y")+b.css(this,"overflow-x"))}).eq(0)}else{g=this.parents().filter(function(){return(/(auto|scroll)/).test(b.css(this,"overflow")+b.css(this,"overflow-y")+b.css(this,"overflow-x"))}).eq(0)}return(/fixed/).test(this.css("position"))||!g.length?b(document):g},zIndex:function(j){if(j!==f){return this.css("zIndex",j)}if(this.length){var h=b(this[0]),g,i;while(h.length&&h[0]!==document){g=h.css("position");if(g==="absolute"||g==="relative"||g==="fixed"){i=parseInt(h.css("zIndex"),10);if(!isNaN(i)&&i!==0){return i}}h=h.parent()}}return 0},uniqueId:function(){return this.each(function(){if(!this.id){this.id="ui-id-"+(++a)}})},removeUniqueId:function(){return this.each(function(){if(e.test(this.id)){b(this).removeAttr("id")}})}});function d(i,g){var k,j,h,l=i.nodeName.toLowerCase();if("area"===l){k=i.parentNode;j=k.name;if(!i.href||!j||k.nodeName.toLowerCase()!=="map"){return false}h=b("img[usemap=#"+j+"]")[0];return !!h&&c(h)}return(/input|select|textarea|button|object/.test(l)?!i.disabled:"a"===l?i.href||g:g)&&c(i)}function c(g){return b.expr.filters.visible(g)&&!b(g).parents().andSelf().filter(function(){return b.css(this,"visibility")==="hidden"}).length}b.extend(b.expr[":"],{data:b.expr.createPseudo?b.expr.createPseudo(function(g){return function(h){return !!b.data(h,g)}}):function(j,h,g){return !!b.data(j,g[3])},focusable:function(g){return d(g,!isNaN(b.attr(g,"tabindex")))},tabbable:function(i){var g=b.attr(i,"tabindex"),h=isNaN(g);return(h||g>=0)&&d(i,!h)}});b(function(){var g=document.body,h=g.appendChild(h=document.createElement("div"));h.offsetHeight;b.extend(h.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});b.support.minHeight=h.offsetHeight===100;b.support.selectstart="onselectstart" in h;g.removeChild(h).style.display="none"});if(!b("").outerWidth(1).jquery){b.each(["Width","Height"],function(j,g){var h=g==="Width"?["Left","Right"]:["Top","Bottom"],k=g.toLowerCase(),m={innerWidth:b.fn.innerWidth,innerHeight:b.fn.innerHeight,outerWidth:b.fn.outerWidth,outerHeight:b.fn.outerHeight};function l(o,n,i,p){b.each(h,function(){n-=parseFloat(b.css(o,"padding"+this))||0;if(i){n-=parseFloat(b.css(o,"border"+this+"Width"))||0}if(p){n-=parseFloat(b.css(o,"margin"+this))||0}});return n}b.fn["inner"+g]=function(i){if(i===f){return m["inner"+g].call(this)}return this.each(function(){b(this).css(k,l(this,i)+"px")})};b.fn["outer"+g]=function(i,n){if(typeof i!=="number"){return m["outer"+g].call(this,i)}return this.each(function(){b(this).css(k,l(this,i,true,n)+"px")})}})}if(b("").data("a-b","a").removeData("a-b").data("a-b")){b.fn.removeData=(function(g){return function(h){if(arguments.length){return g.call(this,b.camelCase(h))}else{return g.call(this)}}})(b.fn.removeData)}(function(){var g=/msie ([\w.]+)/.exec(navigator.userAgent.toLowerCase())||[];b.ui.ie=g.length?true:false;b.ui.ie6=parseFloat(g[1],10)===6})();b.fn.extend({disableSelection:function(){return this.bind((b.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(g){g.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});b.extend(b.ui,{plugin:{add:function(h,j,l){var g,k=b.ui[h].prototype;for(g in l){k.plugins[g]=k.plugins[g]||[];k.plugins[g].push([j,l[g]])}},call:function(g,j,h){var k,l=g.plugins[j];if(!l||!g.element[0].parentNode||g.element[0].parentNode.nodeType===11){return}for(k=0;k0){return true}j[g]=1;i=(j[g]>0);j[g]=0;return i},isOverAxis:function(h,g,i){return(h>g)&&(h<(g+i))},isOver:function(l,h,k,j,g,i){return b.ui.isOverAxis(l,k,g)&&b.ui.isOverAxis(h,j,i)}})})(jQuery);(function(b,e){var a=0,d=Array.prototype.slice,c=b.cleanData;b.cleanData=function(f){for(var g=0,h;(h=f[g])!=null;g++){try{b(h).triggerHandler("remove")}catch(j){}}c(f)};b.widget=function(g,j,f){var m,l,i,k,h=g.split(".")[0];g=g.split(".")[1];m=h+"-"+g;if(!f){f=j;j=b.Widget}b.expr[":"][m.toLowerCase()]=function(n){return !!b.data(n,m)};b[h]=b[h]||{};l=b[h][g];i=b[h][g]=function(n,o){if(!this._createWidget){return new i(n,o)}if(arguments.length){this._createWidget(n,o)}};b.extend(i,l,{version:f.version,_proto:b.extend({},f),_childConstructors:[]});k=new j();k.options=b.widget.extend({},k.options);b.each(f,function(o,n){if(b.isFunction(n)){f[o]=(function(){var p=function(){return j.prototype[o].apply(this,arguments)},q=function(r){return j.prototype[o].apply(this,r)};return function(){var t=this._super,r=this._superApply,s;this._super=p;this._superApply=q;s=n.apply(this,arguments);this._super=t;this._superApply=r;return s}})()}});i.prototype=b.widget.extend(k,{widgetEventPrefix:l?k.widgetEventPrefix:g},f,{constructor:i,namespace:h,widgetName:g,widgetBaseClass:m,widgetFullName:m});if(l){b.each(l._childConstructors,function(o,p){var n=p.prototype;b.widget(n.namespace+"."+n.widgetName,i,p._proto)});delete l._childConstructors}else{j._childConstructors.push(i)}b.widget.bridge(g,i)};b.widget.extend=function(k){var g=d.call(arguments,1),j=0,f=g.length,h,i;for(;j",options:{disabled:false,create:null},_createWidget:function(f,g){g=b(g||this.defaultElement||this)[0];this.element=b(g);this.uuid=a++;this.eventNamespace="."+this.widgetName+this.uuid;this.options=b.widget.extend({},this.options,this._getCreateOptions(),f);this.bindings=b();this.hoverable=b();this.focusable=b();if(g!==this){b.data(g,this.widgetName,this);b.data(g,this.widgetFullName,this);this._on(true,this.element,{remove:function(h){if(h.target===g){this.destroy()}}});this.document=b(g.style?g.ownerDocument:g.document||g);this.window=b(this.document[0].defaultView||this.document[0].parentWindow)}this._create();this._trigger("create",null,this._getCreateEventData());this._init()},_getCreateOptions:b.noop,_getCreateEventData:b.noop,_create:b.noop,_init:b.noop,destroy:function(){this._destroy();this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(b.camelCase(this.widgetFullName));this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled ui-state-disabled");this.bindings.unbind(this.eventNamespace);this.hoverable.removeClass("ui-state-hover");this.focusable.removeClass("ui-state-focus")},_destroy:b.noop,widget:function(){return this.element},option:function(j,k){var f=j,l,h,g;if(arguments.length===0){return b.widget.extend({},this.options)}if(typeof j==="string"){f={};l=j.split(".");j=l.shift();if(l.length){h=f[j]=b.widget.extend({},this.options[j]);for(g=0;g=9)&&!d.button){return this._mouseUp(d)}if(this._mouseStarted){this._mouseDrag(d);return d.preventDefault()}if(this._mouseDistanceMet(d)&&this._mouseDelayMet(d)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,d)!==false);(this._mouseStarted?this._mouseDrag(d):this._mouseUp(d))}return !this._mouseStarted},_mouseUp:function(d){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;if(d.target===this._mouseDownEvent.target){b.data(d.target,this.widgetName+".preventClickEvent",true)}this._mouseStop(d)}return false},_mouseDistanceMet:function(d){return(Math.max(Math.abs(this._mouseDownEvent.pageX-d.pageX),Math.abs(this._mouseDownEvent.pageY-d.pageY))>=this.options.distance)},_mouseDelayMet:function(d){return this.mouseDelayMet},_mouseStart:function(d){},_mouseDrag:function(d){},_mouseStop:function(d){},_mouseCapture:function(d){return true}})})(jQuery);(function(e,c){e.ui=e.ui||{};var i,j=Math.max,n=Math.abs,l=Math.round,d=/left|center|right/,g=/top|center|bottom/,a=/[\+\-]\d+%?/,k=/^\w+/,b=/%$/,f=e.fn.position;function m(q,p,o){return[parseInt(q[0],10)*(b.test(q[0])?p/100:1),parseInt(q[1],10)*(b.test(q[1])?o/100:1)]}function h(o,p){return parseInt(e.css(o,p),10)||0}e.position={scrollbarWidth:function(){if(i!==c){return i}var p,o,r=e("
      "),q=r.children()[0];e("body").append(r);p=q.offsetWidth;r.css("overflow","scroll");o=q.offsetWidth;if(p===o){o=r[0].clientWidth}r.remove();return(i=p-o)},getScrollInfo:function(s){var r=s.isWindow?"":s.element.css("overflow-x"),q=s.isWindow?"":s.element.css("overflow-y"),p=r==="scroll"||(r==="auto"&&s.width0?"right":"center",vertical:M<0?"top":P>0?"bottom":"middle"};if(vj(n(P),n(M))){L.important="horizontal"}else{L.important="vertical"}y.using.call(this,O,L)}}D.offset(e.extend(G,{using:K}))})};e.ui.position={fit:{left:function(s,r){var q=r.within,u=q.isWindow?q.scrollLeft:q.offset.left,w=q.width,t=s.left-r.collisionPosition.marginLeft,v=u-t,p=t+r.collisionWidth-w-u,o;if(r.collisionWidth>w){if(v>0&&p<=0){o=s.left+v+r.collisionWidth-w-u;s.left+=v-o}else{if(p>0&&v<=0){s.left=u}else{if(v>p){s.left=u+w-r.collisionWidth}else{s.left=u}}}}else{if(v>0){s.left+=v}else{if(p>0){s.left-=p}else{s.left=j(s.left-t,s.left)}}}},top:function(r,q){var p=q.within,v=p.isWindow?p.scrollTop:p.offset.top,w=q.within.height,t=r.top-q.collisionPosition.marginTop,u=v-t,s=t+q.collisionHeight-w-v,o;if(q.collisionHeight>w){if(u>0&&s<=0){o=r.top+u+q.collisionHeight-w-v;r.top+=u-o}else{if(s>0&&u<=0){r.top=v}else{if(u>s){r.top=v+w-q.collisionHeight}else{r.top=v}}}}else{if(u>0){r.top+=u}else{if(s>0){r.top-=s}else{r.top=j(r.top-t,r.top)}}}}},flip:{left:function(u,t){var s=t.within,y=s.offset.left+s.scrollLeft,B=s.width,q=s.isWindow?s.scrollLeft:s.offset.left,v=u.left-t.collisionPosition.marginLeft,z=v-q,p=v+t.collisionWidth-B-q,x=t.my[0]==="left"?-t.elemWidth:t.my[0]==="right"?t.elemWidth:0,A=t.at[0]==="left"?t.targetWidth:t.at[0]==="right"?-t.targetWidth:0,r=-2*t.offset[0],o,w;if(z<0){o=u.left+x+A+r+t.collisionWidth-B-y;if(o<0||o0){w=u.left-t.collisionPosition.marginLeft+x+A+r-q;if(w>0||n(w)x&&(p<0||p0){z=t.top-s.collisionPosition.marginTop+w+C+q-o;if((t.top+w+C+q)>u&&(z>0||n(z)10&&r<11;s.innerHTML="";u.removeChild(s)})();if(e.uiBackCompat!==false){(function(p){var o=p.fn.position;p.fn.position=function(r){if(!r||!r.offset){return o.call(this,r)}var s=r.offset.split(" "),q=r.at.split(" ");if(s.length===1){s[1]=s[0]}if(/^\d/.test(s[0])){s[0]="+"+s[0]}if(/^\d/.test(s[1])){s[1]="+"+s[1]}if(q.length===1){if(/left|center|right/.test(q[0])){q[1]="center"}else{q[1]=q[0];q[0]="center"}}return o.call(this,p.extend(r,{at:q[0]+s[0]+" "+q[1]+s[1],offset:c}))}}(jQuery))}}(jQuery));(function(a,b){a.widget("ui.draggable",a.ui.mouse,{version:"1.9.2",widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper=="original"&&!(/^(?:r|a|f)/).test(this.element.css("position"))){this.element[0].style.position="relative"}(this.options.addClasses&&this.element.addClass("ui-draggable"));(this.options.disabled&&this.element.addClass("ui-draggable-disabled"));this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy()},_mouseCapture:function(c){var d=this.options;if(this.helper||d.disabled||a(c.target).is(".ui-resizable-handle")){return false}this.handle=this._getHandle(c);if(!this.handle){return false}a(d.iframeFix===true?"iframe":d.iframeFix).each(function(){a('
      ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1000}).css(a(this).offset()).appendTo("body")});return true},_mouseStart:function(c){var d=this.options;this.helper=this._createHelper(c);this.helper.addClass("ui-draggable-dragging");this._cacheHelperProportions();if(a.ui.ddmanager){a.ui.ddmanager.current=this}this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:c.pageX-this.offset.left,top:c.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(c);this.originalPageX=c.pageX;this.originalPageY=c.pageY;(d.cursorAt&&this._adjustOffsetFromHelper(d.cursorAt));if(d.containment){this._setContainment()}if(this._trigger("start",c)===false){this._clear();return false}this._cacheHelperProportions();if(a.ui.ddmanager&&!d.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,c)}this._mouseDrag(c,true);if(a.ui.ddmanager){a.ui.ddmanager.dragStart(this,c)}return true},_mouseDrag:function(c,e){this.position=this._generatePosition(c);this.positionAbs=this._convertPositionTo("absolute");if(!e){var d=this._uiHash();if(this._trigger("drag",c,d)===false){this._mouseUp({});return false}this.position=d.position}if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}if(a.ui.ddmanager){a.ui.ddmanager.drag(this,c)}return false},_mouseStop:function(e){var g=false;if(a.ui.ddmanager&&!this.options.dropBehaviour){g=a.ui.ddmanager.drop(this,e)}if(this.dropped){g=this.dropped;this.dropped=false}var c=this.element[0],f=false;while(c&&(c=c.parentNode)){if(c==document){f=true}}if(!f&&this.options.helper==="original"){return false}if((this.options.revert=="invalid"&&!g)||(this.options.revert=="valid"&&g)||this.options.revert===true||(a.isFunction(this.options.revert)&&this.options.revert.call(this.element,g))){var d=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){if(d._trigger("stop",e)!==false){d._clear()}})}else{if(this._trigger("stop",e)!==false){this._clear()}}return false},_mouseUp:function(c){a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});if(a.ui.ddmanager){a.ui.ddmanager.dragStop(this,c)}return a.ui.mouse.prototype._mouseUp.call(this,c)},cancel:function(){if(this.helper.is(".ui-draggable-dragging")){this._mouseUp({})}else{this._clear()}return this},_getHandle:function(c){var d=!this.options.handle||!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==c.target){d=true}});return d},_createHelper:function(d){var e=this.options;var c=a.isFunction(e.helper)?a(e.helper.apply(this.element[0],[d])):(e.helper=="clone"?this.element.clone().removeAttr("id"):this.element);if(!c.parents("body").length){c.appendTo((e.appendTo=="parent"?this.element[0].parentNode:e.appendTo))}if(c[0]!=this.element[0]&&!(/(fixed|absolute)/).test(c.css("position"))){c.css("position","absolute")}return c},_adjustOffsetFromHelper:function(c){if(typeof c=="string"){c=c.split(" ")}if(a.isArray(c)){c={left:+c[0],top:+c[1]||0}}if("left" in c){this.offset.click.left=c.left+this.margins.left}if("right" in c){this.offset.click.left=this.helperProportions.width-c.right+this.margins.left}if("top" in c){this.offset.click.top=c.top+this.margins.top}if("bottom" in c){this.offset.click.top=this.helperProportions.height-c.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var c=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.contains(this.scrollParent[0],this.offsetParent[0])){c.left+=this.scrollParent.scrollLeft();c.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.ui.ie)){c={top:0,left:0}}return{top:c.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:c.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var c=this.element.position();return{top:c.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:c.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.element.css("marginLeft"),10)||0),top:(parseInt(this.element.css("marginTop"),10)||0),right:(parseInt(this.element.css("marginRight"),10)||0),bottom:(parseInt(this.element.css("marginBottom"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var g=this.options;if(g.containment=="parent"){g.containment=this.helper[0].parentNode}if(g.containment=="document"||g.containment=="window"){this.containment=[g.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,g.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(g.containment=="document"?0:a(window).scrollLeft())+a(g.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(g.containment=="document"?0:a(window).scrollTop())+(a(g.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(g.containment)&&g.containment.constructor!=Array){var h=a(g.containment);var e=h[0];if(!e){return}var f=h.offset();var d=(a(e).css("overflow")!="hidden");this.containment=[(parseInt(a(e).css("borderLeftWidth"),10)||0)+(parseInt(a(e).css("paddingLeft"),10)||0),(parseInt(a(e).css("borderTopWidth"),10)||0)+(parseInt(a(e).css("paddingTop"),10)||0),(d?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(a(e).css("borderLeftWidth"),10)||0)-(parseInt(a(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(d?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(a(e).css("borderTopWidth"),10)||0)-(parseInt(a(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=h}else{if(g.containment.constructor==Array){this.containment=g.containment}}},_convertPositionTo:function(g,i){if(!i){i=this.position}var e=g=="absolute"?1:-1;var f=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,h=(/(html|body)/i).test(c[0].tagName);return{top:(i.top+this.offset.relative.top*e+this.offset.parent.top*e-((this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(h?0:c.scrollTop()))*e)),left:(i.left+this.offset.relative.left*e+this.offset.parent.left*e-((this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():h?0:c.scrollLeft())*e))}},_generatePosition:function(d){var e=this.options,l=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(l[0].tagName);var h=d.pageX;var g=d.pageY;if(this.originalPosition){var c;if(this.containment){if(this.relative_container){var k=this.relative_container.offset();c=[this.containment[0]+k.left,this.containment[1]+k.top,this.containment[2]+k.left,this.containment[3]+k.top]}else{c=this.containment}if(d.pageX-this.offset.click.leftc[2]){h=c[2]+this.offset.click.left}if(d.pageY-this.offset.click.top>c[3]){g=c[3]+this.offset.click.top}}if(e.grid){var j=e.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/e.grid[1])*e.grid[1]:this.originalPageY;g=c?(!(j-this.offset.click.topc[3])?j:(!(j-this.offset.click.topc[2])?f:(!(f-this.offset.click.left=0;v--){var s=g.snapElements[v].left,n=s+g.snapElements[v].width,m=g.snapElements[v].top,A=m+g.snapElements[v].height;if(!((s-y=p&&n<=k)||(m>=p&&m<=k)||(nk))&&((e>=g&&e<=c)||(d>=g&&d<=c)||(ec));break;default:return false;break}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(f,h){var c=a.ui.ddmanager.droppables[f.options.scope]||[];var g=h?h.type:null;var k=(f.currentItem||f.element).find(":data(droppable)").andSelf();droppablesLoop:for(var e=0;e
      ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=k.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var l=this.handles.split(",");this.handles={};for(var f=0;f');g.css({zIndex:k.zIndex});if("se"==j){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[j]=".ui-resizable-"+j;this.element.append(g)}}this._renderAxis=function(q){q=q||this.element;for(var n in this.handles){if(this.handles[n].constructor==String){this.handles[n]=c(this.handles[n],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var o=c(this.handles[n],this.element),p=0;p=/sw|ne|nw|se|n|s/.test(n)?o.outerHeight():o.outerWidth();var m=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");q.css(m,p);this._proportionallyResize()}if(!c(this.handles[n]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!h.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}h.axis=i&&i[1]?i[1]:"se"}});if(k.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").mouseenter(function(){if(k.disabled){return}c(this).removeClass("ui-resizable-autohide");h._handles.show()}).mouseleave(function(){if(k.disabled){return}if(!h.resizing){c(this).addClass("ui-resizable-autohide");h._handles.hide()}})}this._mouseInit()},_destroy:function(){this._mouseDestroy();var e=function(g){c(g).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){e(this.element);var f=this.element;this.originalElement.css({position:f.css("position"),width:f.outerWidth(),height:f.outerHeight(),top:f.css("top"),left:f.css("left")}).insertAfter(f);f.remove()}this.originalElement.css("resize",this.originalResizeStyle);e(this.originalElement);return this},_mouseCapture:function(f){var g=false;for(var e in this.handles){if(c(this.handles[e])[0]==f.target){g=true}}return !this.options.disabled&&g},_mouseStart:function(g){var j=this.options,f=this.element.position(),e=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(e.is(".ui-draggable")||(/absolute/).test(e.css("position"))){e.css({position:"absolute",top:f.top,left:f.left})}this._renderProxy();var k=b(this.helper.css("left")),h=b(this.helper.css("top"));if(j.containment){k+=c(j.containment).scrollLeft()||0;h+=c(j.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:k,top:h};this.size=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalSize=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalPosition={left:k,top:h};this.sizeDiff={width:e.outerWidth()-e.width(),height:e.outerHeight()-e.height()};this.originalMousePosition={left:g.pageX,top:g.pageY};this.aspectRatio=(typeof j.aspectRatio=="number")?j.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var i=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",i=="auto"?this.axis+"-resize":i);e.addClass("ui-resizable-resizing");this._propagate("start",g);return true},_mouseDrag:function(e){var g=this.helper,f=this.options,l={},k=this,i=this.originalMousePosition,m=this.axis;var p=(e.pageX-i.left)||0,n=(e.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var j=h.apply(this,[e,p,n]);this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey){j=this._updateRatio(j,e)}j=this._respectSize(j,e);this._propagate("resize",e);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(j);this._trigger("resize",e,this.ui());return false},_mouseStop:function(h){this.resizing=false;var i=this.options,l=this;if(this._helper){var g=this._proportionallyResizeElements,e=g.length&&(/textarea/i).test(g[0].nodeName),f=e&&c.ui.hasScroll(g[0],"left")?0:l.sizeDiff.height,k=e?0:l.sizeDiff.width;var n={width:(l.helper.width()-k),height:(l.helper.height()-f)},j=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,m=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!i.animate){this.element.css(c.extend(n,{top:m,left:j}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!i.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",h);if(this._helper){this.helper.remove()}return false},_updateVirtualBoundaries:function(g){var j=this.options,i,h,f,k,e;e={minWidth:a(j.minWidth)?j.minWidth:0,maxWidth:a(j.maxWidth)?j.maxWidth:Infinity,minHeight:a(j.minHeight)?j.minHeight:0,maxHeight:a(j.maxHeight)?j.maxHeight:Infinity};if(this._aspectRatio||g){i=e.minHeight*this.aspectRatio;f=e.minWidth/this.aspectRatio;h=e.maxHeight*this.aspectRatio;k=e.maxWidth/this.aspectRatio;if(i>e.minWidth){e.minWidth=i}if(f>e.minHeight){e.minHeight=f}if(hl.width),s=a(l.height)&&i.minHeight&&(i.minHeight>l.height);if(h){l.width=i.minWidth}if(s){l.height=i.minHeight}if(t){l.width=i.maxWidth}if(m){l.height=i.maxHeight}var f=this.originalPosition.left+this.originalSize.width,p=this.position.top+this.size.height;var k=/sw|nw|w/.test(q),e=/nw|ne|n/.test(q);if(h&&k){l.left=f-i.minWidth}if(t&&k){l.left=f-i.maxWidth}if(s&&e){l.top=p-i.minHeight}if(m&&e){l.top=p-i.maxHeight}var n=!l.width&&!l.height;if(n&&!l.left&&l.top){l.top=null}else{if(n&&!l.top&&l.left){l.left=null}}return l},_proportionallyResize:function(){var k=this.options;if(!this._proportionallyResizeElements.length){return}var g=this.helper||this.element;for(var f=0;f');var f=(c.ui.ie6?1:0),g=(c.ui.ie6?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(g,f,e){return{width:this.originalSize.width+f}},w:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{left:i.left+f,width:g.width-f}},n:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{top:i.top+e,height:g.height-e}},s:function(g,f,e){return{height:this.originalSize.height+e}},se:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},sw:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[g,f,e]))},ne:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},nw:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[g,f,e]))}},_propagate:function(f,e){c.ui.plugin.call(this,f,[e,this.ui()]);(f!="resize"&&this._trigger(f,e,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});c.ui.plugin.add("resizable","alsoResize",{start:function(f,g){var e=c(this).data("resizable"),i=e.options;var h=function(j){c(j).each(function(){var k=c(this);k.data("resizable-alsoresize",{width:parseInt(k.width(),10),height:parseInt(k.height(),10),left:parseInt(k.css("left"),10),top:parseInt(k.css("top"),10)})})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.parentNode){if(i.alsoResize.length){i.alsoResize=i.alsoResize[0];h(i.alsoResize)}else{c.each(i.alsoResize,function(j){h(j)})}}else{h(i.alsoResize)}},resize:function(g,i){var f=c(this).data("resizable"),j=f.options,h=f.originalSize,l=f.originalPosition;var k={height:(f.size.height-h.height)||0,width:(f.size.width-h.width)||0,top:(f.position.top-l.top)||0,left:(f.position.left-l.left)||0},e=function(m,n){c(m).each(function(){var q=c(this),r=c(this).data("resizable-alsoresize"),p={},o=n&&n.length?n:q.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];c.each(o,function(s,u){var t=(r[u]||0)+(k[u]||0);if(t&&t>=0){p[u]=t||null}});q.css(p)})};if(typeof(j.alsoResize)=="object"&&!j.alsoResize.nodeType){c.each(j.alsoResize,function(m,n){e(m,n)})}else{e(j.alsoResize)}},stop:function(e,f){c(this).removeData("resizable-alsoresize")}});c.ui.plugin.add("resizable","animate",{stop:function(i,p){var m=c(this).data("resizable"),j=m.options;var h=m._proportionallyResizeElements,e=h.length&&(/textarea/i).test(h[0].nodeName),f=e&&c.ui.hasScroll(h[0],"left")?0:m.sizeDiff.height,l=e?0:m.sizeDiff.width;var g={width:(m.size.width-l),height:(m.size.height-f)},k=(parseInt(m.element.css("left"),10)+(m.position.left-m.originalPosition.left))||null,n=(parseInt(m.element.css("top"),10)+(m.position.top-m.originalPosition.top))||null;m.element.animate(c.extend(g,n&&k?{top:n,left:k}:{}),{duration:j.animateDuration,easing:j.animateEasing,step:function(){var o={width:parseInt(m.element.css("width"),10),height:parseInt(m.element.css("height"),10),top:parseInt(m.element.css("top"),10),left:parseInt(m.element.css("left"),10)};if(h&&h.length){c(h[0]).css({width:o.width,height:o.height})}m._updateCache(o);m._propagate("resize",i)}})}});c.ui.plugin.add("resizable","containment",{start:function(f,s){var q=c(this).data("resizable"),j=q.options,l=q.element;var g=j.containment,k=(g instanceof c)?g.get(0):(/parent/.test(g))?l.parent().get(0):g;if(!k){return}q.containerElement=c(k);if(/document/.test(g)||g==document){q.containerOffset={left:0,top:0};q.containerPosition={left:0,top:0};q.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var n=c(k),i=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){i[p]=b(n.css("padding"+o))});q.containerOffset=n.offset();q.containerPosition=n.position();q.containerSize={height:(n.innerHeight()-i[3]),width:(n.innerWidth()-i[1])};var r=q.containerOffset,e=q.containerSize.height,m=q.containerSize.width,h=(c.ui.hasScroll(k,"left")?k.scrollWidth:m),t=(c.ui.hasScroll(k)?k.scrollHeight:e);q.parentData={element:k,left:r.left,top:r.top,width:h,height:t}}},resize:function(g,r){var m=c(this).data("resizable"),i=m.options,f=m.containerSize,q=m.containerOffset,n=m.size,p=m.position,s=m._aspectRatio||g.shiftKey,e={top:0,left:0},h=m.containerElement;if(h[0]!=document&&(/static/).test(h.css("position"))){e=q}if(p.left<(m._helper?q.left:0)){m.size.width=m.size.width+(m._helper?(m.position.left-q.left):(m.position.left-e.left));if(s){m.size.height=m.size.width/m.aspectRatio}m.position.left=i.helper?q.left:0}if(p.top<(m._helper?q.top:0)){m.size.height=m.size.height+(m._helper?(m.position.top-q.top):m.position.top);if(s){m.size.width=m.size.height*m.aspectRatio}m.position.top=m._helper?q.top:0}m.offset.left=m.parentData.left+m.position.left;m.offset.top=m.parentData.top+m.position.top;var l=Math.abs((m._helper?m.offset.left-e.left:(m.offset.left-e.left))+m.sizeDiff.width),t=Math.abs((m._helper?m.offset.top-e.top:(m.offset.top-q.top))+m.sizeDiff.height);var k=m.containerElement.get(0)==m.element.parent().get(0),j=/relative|absolute/.test(m.containerElement.css("position"));if(k&&j){l-=m.parentData.left}if(l+m.size.width>=m.parentData.width){m.size.width=m.parentData.width-l;if(s){m.size.height=m.size.width/m.aspectRatio}}if(t+m.size.height>=m.parentData.height){m.size.height=m.parentData.height-t;if(s){m.size.width=m.size.height*m.aspectRatio}}},stop:function(f,p){var l=c(this).data("resizable"),g=l.options,m=l.position,n=l.containerOffset,e=l.containerPosition,i=l.containerElement;var j=c(l.helper),r=j.offset(),q=j.outerWidth()-l.sizeDiff.width,k=j.outerHeight()-l.sizeDiff.height;if(l._helper&&!g.animate&&(/relative/).test(i.css("position"))){c(this).css({left:r.left-e.left-n.left,width:q,height:k})}if(l._helper&&!g.animate&&(/static/).test(i.css("position"))){c(this).css({left:r.left-e.left-n.left,width:q,height:k})}}});c.ui.plugin.add("resizable","ghost",{start:function(g,h){var f=c(this).data("resizable"),i=f.options,e=f.size;f.ghost=f.originalElement.clone();f.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof i.ghost=="string"?i.ghost:"");f.ghost.appendTo(f.helper)},resize:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost){e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})}},stop:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost&&e.helper){e.helper.get(0).removeChild(e.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(e,n){var k=c(this).data("resizable"),h=k.options,l=k.size,i=k.originalSize,j=k.originalPosition,p=k.axis,m=h._aspectRatio||e.shiftKey;h.grid=typeof h.grid=="number"?[h.grid,h.grid]:h.grid;var g=Math.round((l.width-i.width)/(h.grid[0]||1))*(h.grid[0]||1),f=Math.round((l.height-i.height)/(h.grid[1]||1))*(h.grid[1]||1);if(/^(se|s|e)$/.test(p)){k.size.width=i.width+g;k.size.height=i.height+f}else{if(/^(ne)$/.test(p)){k.size.width=i.width+g;k.size.height=i.height+f;k.position.top=j.top-f}else{if(/^(sw)$/.test(p)){k.size.width=i.width+g;k.size.height=i.height+f;k.position.left=j.left-g}else{k.size.width=i.width+g;k.size.height=i.height+f;k.position.top=j.top-f;k.position.left=j.left-g}}}}});var b=function(e){return parseInt(e,10)||0};var a=function(e){return !isNaN(parseInt(e,10))}})(jQuery);(function(a,b){a.widget("ui.selectable",a.ui.mouse,{version:"1.9.2",options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var d;this.refresh=function(){d=a(c.options.filter,c.element[0]);d.addClass("ui-selectee");d.each(function(){var e=a(this);var f=e.offset();a.data(this,"selectable-item",{element:this,$element:e,left:f.left,top:f.top,right:f.left+e.outerWidth(),bottom:f.top+e.outerHeight(),startselected:false,selected:e.hasClass("ui-selected"),selecting:e.hasClass("ui-selecting"),unselecting:e.hasClass("ui-unselecting")})})};this.refresh();this.selectees=d.addClass("ui-selectee");this._mouseInit();this.helper=a("
      ")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled");this._mouseDestroy()},_mouseStart:function(e){var d=this;this.opos=[e.pageX,e.pageY];if(this.options.disabled){return}var c=this.options;this.selectees=a(c.filter,this.element[0]);this._trigger("start",e);a(c.appendTo).append(this.helper);this.helper.css({left:e.clientX,top:e.clientY,width:0,height:0});if(c.autoRefresh){this.refresh()}this.selectees.filter(".ui-selected").each(function(){var f=a.data(this,"selectable-item");f.startselected=true;if(!e.metaKey&&!e.ctrlKey){f.$element.removeClass("ui-selected");f.selected=false;f.$element.addClass("ui-unselecting");f.unselecting=true;d._trigger("unselecting",e,{unselecting:f.element})}});a(e.target).parents().andSelf().each(function(){var g=a.data(this,"selectable-item");if(g){var f=(!e.metaKey&&!e.ctrlKey)||!g.$element.hasClass("ui-selected");g.$element.removeClass(f?"ui-unselecting":"ui-selected").addClass(f?"ui-selecting":"ui-unselecting");g.unselecting=!f;g.selecting=f;g.selected=f;if(f){d._trigger("selecting",e,{selecting:g.element})}else{d._trigger("unselecting",e,{unselecting:g.element})}return false}})},_mouseDrag:function(j){var i=this;this.dragged=true;if(this.options.disabled){return}var e=this.options;var d=this.opos[0],h=this.opos[1],c=j.pageX,g=j.pageY;if(d>c){var f=c;c=d;d=f}if(h>g){var f=g;g=h;h=f}this.helper.css({left:d,top:h,width:c-d,height:g-h});this.selectees.each(function(){var k=a.data(this,"selectable-item");if(!k||k.element==i.element[0]){return}var l=false;if(e.tolerance=="touch"){l=(!(k.left>c||k.rightg||k.bottomd&&k.righth&&k.bottom *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1000},_create:function(){var c=this.options;this.containerCache={};this.element.addClass("ui-sortable");this.refresh();this.floating=this.items.length?c.axis==="x"||(/left|right/).test(this.items[0].item.css("float"))||(/inline|table-cell/).test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit();this.ready=true},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled");this._mouseDestroy();for(var c=this.items.length-1;c>=0;c--){this.items[c].item.removeData(this.widgetName+"-item")}return this},_setOption:function(c,d){if(c==="disabled"){this.options[c]=d;this.widget().toggleClass("ui-sortable-disabled",!!d)}else{a.Widget.prototype._setOption.apply(this,arguments)}},_mouseCapture:function(f,g){var e=this;if(this.reverting){return false}if(this.options.disabled||this.options.type=="static"){return false}this._refreshItems(f);var d=null,c=a(f.target).parents().each(function(){if(a.data(this,e.widgetName+"-item")==e){d=a(this);return false}});if(a.data(f.target,e.widgetName+"-item")==e){d=a(f.target)}if(!d){return false}if(this.options.handle&&!g){var h=false;a(this.options.handle,d).find("*").andSelf().each(function(){if(this==f.target){h=true}});if(!h){return false}}this.currentItem=d;this._removeCurrentsFromItems();return true},_mouseStart:function(e,f,c){var g=this.options;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(e);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");this.originalPosition=this._generatePosition(e);this.originalPageX=e.pageX;this.originalPageY=e.pageY;(g.cursorAt&&this._adjustOffsetFromHelper(g.cursorAt));this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};if(this.helper[0]!=this.currentItem[0]){this.currentItem.hide()}this._createPlaceholder();if(g.containment){this._setContainment()}if(g.cursor){if(a("body").css("cursor")){this._storedCursor=a("body").css("cursor")}a("body").css("cursor",g.cursor)}if(g.opacity){if(this.helper.css("opacity")){this._storedOpacity=this.helper.css("opacity")}this.helper.css("opacity",g.opacity)}if(g.zIndex){if(this.helper.css("zIndex")){this._storedZIndex=this.helper.css("zIndex")}this.helper.css("zIndex",g.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){this.overflowOffset=this.scrollParent.offset()}this._trigger("start",e,this._uiHash());if(!this._preserveHelperProportions){this._cacheHelperProportions()}if(!c){for(var d=this.containers.length-1;d>=0;d--){this.containers[d]._trigger("activate",e,this._uiHash(this))}}if(a.ui.ddmanager){a.ui.ddmanager.current=this}if(a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,e)}this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(e);return true},_mouseDrag:function(g){this.position=this._generatePosition(g);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs){this.lastPositionAbs=this.positionAbs}if(this.options.scroll){var h=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if((this.overflowOffset.top+this.scrollParent[0].offsetHeight)-g.pageY=0;e--){var f=this.items[e],d=f.item[0],j=this._intersectsWithPointer(f);if(!j){continue}if(f.instance!==this.currentContainer){continue}if(d!=this.currentItem[0]&&this.placeholder[j==1?"next":"prev"]()[0]!=d&&!a.contains(this.placeholder[0],d)&&(this.options.type=="semi-dynamic"?!a.contains(this.element[0],d):true)){this.direction=j==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f)){this._rearrange(g,f)}else{break}this._trigger("change",g,this._uiHash());break}}this._contactContainers(g);if(a.ui.ddmanager){a.ui.ddmanager.drag(this,g)}this._trigger("sort",g,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(d,e){if(!d){return}if(a.ui.ddmanager&&!this.options.dropBehaviour){a.ui.ddmanager.drop(this,d)}if(this.options.revert){var c=this;var f=this.placeholder.offset();this.reverting=true;a(this.helper).animate({left:f.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:f.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(d)})}else{this._clear(d,e)}return false},cancel:function(){if(this.dragging){this._mouseUp({target:null});if(this.options.helper=="original"){this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else{this.currentItem.show()}for(var c=this.containers.length-1;c>=0;c--){this.containers[c]._trigger("deactivate",null,this._uiHash(this));if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",null,this._uiHash(this));this.containers[c].containerCache.over=0}}}if(this.placeholder){if(this.placeholder[0].parentNode){this.placeholder[0].parentNode.removeChild(this.placeholder[0])}if(this.options.helper!="original"&&this.helper&&this.helper[0].parentNode){this.helper.remove()}a.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});if(this.domPosition.prev){a(this.domPosition.prev).after(this.currentItem)}else{a(this.domPosition.parent).prepend(this.currentItem)}}return this},serialize:function(e){var c=this._getItemsAsjQuery(e&&e.connected);var d=[];e=e||{};a(c).each(function(){var f=(a(e.item||this).attr(e.attribute||"id")||"").match(e.expression||(/(.+)[-=_](.+)/));if(f){d.push((e.key||f[1]+"[]")+"="+(e.key&&e.expression?f[1]:f[2]))}});if(!d.length&&e.key){d.push(e.key+"=")}return d.join("&")},toArray:function(e){var c=this._getItemsAsjQuery(e&&e.connected);var d=[];e=e||{};c.each(function(){d.push(a(e.item||this).attr(e.attribute||"id")||"")});return d},_intersectsWith:function(m){var e=this.positionAbs.left,d=e+this.helperProportions.width,k=this.positionAbs.top,j=k+this.helperProportions.height;var f=m.left,c=f+m.width,n=m.top,i=n+m.height;var o=this.offset.click.top,h=this.offset.click.left;var g=(k+o)>n&&(k+o)f&&(e+h)m[this.floating?"width":"height"])){return g}else{return(f0?"down":"up")},_getDragHorizontalDirection:function(){var c=this.positionAbs.left-this.lastPositionAbs.left;return c!=0&&(c>0?"right":"left")},refresh:function(c){this._refreshItems(c);this.refreshPositions();return this},_connectWith:function(){var c=this.options;return c.connectWith.constructor==String?[c.connectWith]:c.connectWith},_getItemsAsjQuery:function(h){var c=[];var e=[];var g=this._connectWith();if(g&&h){for(var f=g.length-1;f>=0;f--){var l=a(g[f]);for(var d=l.length-1;d>=0;d--){var k=a.data(l[d],this.widgetName);if(k&&k!=this&&!k.options.disabled){e.push([a.isFunction(k.options.items)?k.options.items.call(k.element):a(k.options.items,k.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),k])}}}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var f=e.length-1;f>=0;f--){e[f][0].each(function(){c.push(this)})}return a(c)},_removeCurrentsFromItems:function(){var c=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=a.grep(this.items,function(e){for(var d=0;d=0;f--){var n=a(m[f]);for(var e=n.length-1;e>=0;e--){var h=a.data(n[e],this.widgetName);if(h&&h!=this&&!h.options.disabled){g.push([a.isFunction(h.options.items)?h.options.items.call(h.element[0],c,{item:this.currentItem}):a(h.options.items,h.element),h]);this.containers.push(h)}}}}for(var f=g.length-1;f>=0;f--){var l=g[f][1];var d=g[f][0];for(var e=0,o=d.length;e=0;e--){var f=this.items[e];if(f.instance!=this.currentContainer&&this.currentContainer&&f.item[0]!=this.currentItem[0]){continue}var d=this.options.toleranceElement?a(this.options.toleranceElement,f.item):f.item;if(!c){f.width=d.outerWidth();f.height=d.outerHeight()}var g=d.offset();f.left=g.left;f.top=g.top}if(this.options.custom&&this.options.custom.refreshContainers){this.options.custom.refreshContainers.call(this)}else{for(var e=this.containers.length-1;e>=0;e--){var g=this.containers[e].element.offset();this.containers[e].containerCache.left=g.left;this.containers[e].containerCache.top=g.top;this.containers[e].containerCache.width=this.containers[e].element.outerWidth();this.containers[e].containerCache.height=this.containers[e].element.outerHeight()}}return this},_createPlaceholder:function(d){d=d||this;var e=d.options;if(!e.placeholder||e.placeholder.constructor==String){var c=e.placeholder;e.placeholder={element:function(){var f=a(document.createElement(d.currentItem[0].nodeName)).addClass(c||d.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!c){f.style.visibility="hidden"}return f},update:function(f,g){if(c&&!e.forcePlaceholderSize){return}if(!g.height()){g.height(d.currentItem.innerHeight()-parseInt(d.currentItem.css("paddingTop")||0,10)-parseInt(d.currentItem.css("paddingBottom")||0,10))}if(!g.width()){g.width(d.currentItem.innerWidth()-parseInt(d.currentItem.css("paddingLeft")||0,10)-parseInt(d.currentItem.css("paddingRight")||0,10))}}}}d.placeholder=a(e.placeholder.element.call(d.element,d.currentItem));d.currentItem.after(d.placeholder);e.placeholder.update(d,d.placeholder)},_contactContainers:function(c){var e=null,n=null;for(var h=this.containers.length-1;h>=0;h--){if(a.contains(this.currentItem[0],this.containers[h].element[0])){continue}if(this._intersectsWith(this.containers[h].containerCache)){if(e&&a.contains(this.containers[h].element[0],e.element[0])){continue}e=this.containers[h];n=h}else{if(this.containers[h].containerCache.over){this.containers[h]._trigger("out",c,this._uiHash(this));this.containers[h].containerCache.over=0}}}if(!e){return}if(this.containers.length===1){this.containers[n]._trigger("over",c,this._uiHash(this));this.containers[n].containerCache.over=1}else{var m=10000;var k=null;var l=this.containers[n].floating?"left":"top";var o=this.containers[n].floating?"width":"height";var d=this.positionAbs[l]+this.offset.click[l];for(var f=this.items.length-1;f>=0;f--){if(!a.contains(this.containers[n].element[0],this.items[f].item[0])){continue}if(this.items[f].item[0]==this.currentItem[0]){continue}var p=this.items[f].item.offset()[l];var g=false;if(Math.abs(p-d)>Math.abs(p+this.items[f][o]-d)){g=true;p+=this.items[f][o]}if(Math.abs(p-d)this.containment[2]){e=this.containment[2]+this.offset.click.left}if(f.pageY-this.offset.click.top>this.containment[3]){d=this.containment[3]+this.offset.click.top}}if(i.grid){var h=this.originalPageY+Math.round((d-this.originalPageY)/i.grid[1])*i.grid[1];d=this.containment?(!(h-this.offset.click.topthis.containment[3])?h:(!(h-this.offset.click.topthis.containment[2])?g:(!(g-this.offset.click.left=0;c--){if(!e){f.push((function(g){return function(h){g._trigger("deactivate",h,this._uiHash(this))}}).call(this,this.containers[c]))}if(this.containers[c].containerCache.over){f.push((function(g){return function(h){g._trigger("out",h,this._uiHash(this))}}).call(this,this.containers[c]));this.containers[c].containerCache.over=0}}if(this._storedCursor){a("body").css("cursor",this._storedCursor)}if(this._storedOpacity){this.helper.css("opacity",this._storedOpacity)}if(this._storedZIndex){this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex)}this.dragging=false;if(this.cancelHelperRemoval){if(!e){this._trigger("beforeStop",d,this._uiHash());for(var c=0;c li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var g=this.accordionId="ui-accordion-"+(this.element.attr("id")||++b),f=this.options;this.prevShow=this.prevHide=d();this.element.addClass("ui-accordion ui-widget ui-helper-reset");this.headers=this.element.find(f.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all");this._hoverable(this.headers);this._focusable(this.headers);this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").hide();if(!f.collapsible&&(f.active===false||f.active==null)){f.active=0}if(f.active<0){f.active+=this.headers.length}this.active=this._findActive(f.active).addClass("ui-accordion-header-active ui-state-active").toggleClass("ui-corner-all ui-corner-top");this.active.next().addClass("ui-accordion-content-active").show();this._createIcons();this.refresh();this.element.attr("role","tablist");this.headers.attr("role","tab").each(function(l){var m=d(this),k=m.attr("id"),h=m.next(),j=h.attr("id");if(!k){k=g+"-header-"+l;m.attr("id",k)}if(!j){j=g+"-panel-"+l;h.attr("id",j)}m.attr("aria-controls",j);h.attr("aria-labelledby",k)}).next().attr("role","tabpanel");this.headers.not(this.active).attr({"aria-selected":"false",tabIndex:-1}).next().attr({"aria-expanded":"false","aria-hidden":"true"}).hide();if(!this.active.length){this.headers.eq(0).attr("tabIndex",0)}else{this.active.attr({"aria-selected":"true",tabIndex:0}).next().attr({"aria-expanded":"true","aria-hidden":"false"})}this._on(this.headers,{keydown:"_keydown"});this._on(this.headers.next(),{keydown:"_panelKeyDown"});this._setupEvents(f.event)},_getCreateEventData:function(){return{header:this.active,content:!this.active.length?d():this.active.next()}},_createIcons:function(){var f=this.options.icons;if(f){d("").addClass("ui-accordion-header-icon ui-icon "+f.header).prependTo(this.headers);this.active.children(".ui-accordion-header-icon").removeClass(f.header).addClass(f.activeHeader);this.headers.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var f;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){if(/^ui-accordion/.test(this.id)){this.removeAttribute("id")}});this._destroyIcons();f=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){if(/^ui-accordion/.test(this.id)){this.removeAttribute("id")}});if(this.options.heightStyle!=="content"){f.css("height","")}},_setOption:function(f,g){if(f==="active"){this._activate(g);return}if(f==="event"){if(this.options.event){this._off(this.headers,this.options.event)}this._setupEvents(g)}this._super(f,g);if(f==="collapsible"&&!g&&this.options.active===false){this._activate(0)}if(f==="icons"){this._destroyIcons();if(g){this._createIcons()}}if(f==="disabled"){this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!g)}},_keydown:function(i){if(i.altKey||i.ctrlKey){return}var j=d.ui.keyCode,h=this.headers.length,f=this.headers.index(i.target),g=false;switch(i.keyCode){case j.RIGHT:case j.DOWN:g=this.headers[(f+1)%h];break;case j.LEFT:case j.UP:g=this.headers[(f-1+h)%h];break;case j.SPACE:case j.ENTER:this._eventHandler(i);break;case j.HOME:g=this.headers[0];break;case j.END:g=this.headers[h-1];break}if(g){d(i.target).attr("tabIndex",-1);d(g).attr("tabIndex",0);g.focus();i.preventDefault()}},_panelKeyDown:function(f){if(f.keyCode===d.ui.keyCode.UP&&f.ctrlKey){d(f.currentTarget).prev().focus()}},refresh:function(){var h,i,f=this.options.heightStyle,g=this.element.parent();if(f==="fill"){if(!d.support.minHeight){i=g.css("overflow");g.css("overflow","hidden")}h=g.height();this.element.siblings(":visible").each(function(){var k=d(this),j=k.css("position");if(j==="absolute"||j==="fixed"){return}h-=k.outerHeight(true)});if(i){g.css("overflow",i)}this.headers.each(function(){h-=d(this).outerHeight(true)});this.headers.next().each(function(){d(this).height(Math.max(0,h-d(this).innerHeight()+d(this).height()))}).css("overflow","auto")}else{if(f==="auto"){h=0;this.headers.next().each(function(){h=Math.max(h,d(this).css("height","").height())}).height(h)}}},_activate:function(f){var g=this._findActive(f)[0];if(g===this.active[0]){return}g=g||this.active[0];this._eventHandler({target:g,currentTarget:g,preventDefault:d.noop})},_findActive:function(f){return typeof f==="number"?this.headers.eq(f):d()},_setupEvents:function(g){var f={};if(!g){return}d.each(g.split(" "),function(i,h){f[h]="_eventHandler"});this._on(this.headers,f)},_eventHandler:function(f){var n=this.options,i=this.active,j=d(f.currentTarget),l=j[0]===i[0],g=l&&n.collapsible,h=g?d():j.next(),k=i.next(),m={oldHeader:i,oldPanel:k,newHeader:g?d():j,newPanel:h};f.preventDefault();if((l&&!n.collapsible)||(this._trigger("beforeActivate",f,m)===false)){return}n.active=g?false:this.headers.index(j);this.active=l?d():j;this._toggle(m);i.removeClass("ui-accordion-header-active ui-state-active");if(n.icons){i.children(".ui-accordion-header-icon").removeClass(n.icons.activeHeader).addClass(n.icons.header)}if(!l){j.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top");if(n.icons){j.children(".ui-accordion-header-icon").removeClass(n.icons.header).addClass(n.icons.activeHeader)}j.next().addClass("ui-accordion-content-active")}},_toggle:function(h){var f=h.newPanel,g=this.prevShow.length?this.prevShow:h.oldPanel;this.prevShow.add(this.prevHide).stop(true,true);this.prevShow=f;this.prevHide=g;if(this.options.animate){this._animate(f,g,h)}else{g.hide();f.show();this._toggleComplete(h)}g.attr({"aria-expanded":"false","aria-hidden":"true"});g.prev().attr("aria-selected","false");if(f.length&&g.length){g.prev().attr("tabIndex",-1)}else{if(f.length){this.headers.filter(function(){return d(this).attr("tabIndex")===0}).attr("tabIndex",-1)}}f.attr({"aria-expanded":"true","aria-hidden":"false"}).prev().attr({"aria-selected":"true",tabIndex:0})},_animate:function(f,n,j){var m,l,i,k=this,o=0,p=f.length&&(!n.length||(f.index()",options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},pending:0,_create:function(){var e,d,f;this.isMultiLine=this._isMultiLine();this.valueMethod=this.element[this.element.is("input,textarea")?"val":"text"];this.isNewMenu=true;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off");this._on(this.element,{keydown:function(g){if(this.element.prop("readOnly")){e=true;f=true;d=true;return}e=false;f=false;d=false;var h=a.ui.keyCode;switch(g.keyCode){case h.PAGE_UP:e=true;this._move("previousPage",g);break;case h.PAGE_DOWN:e=true;this._move("nextPage",g);break;case h.UP:e=true;this._keyEvent("previous",g);break;case h.DOWN:e=true;this._keyEvent("next",g);break;case h.ENTER:case h.NUMPAD_ENTER:if(this.menu.active){e=true;g.preventDefault();this.menu.select(g)}break;case h.TAB:if(this.menu.active){this.menu.select(g)}break;case h.ESCAPE:if(this.menu.element.is(":visible")){this._value(this.term);this.close(g);g.preventDefault()}break;default:d=true;this._searchTimeout(g);break}},keypress:function(g){if(e){e=false;g.preventDefault();return}if(d){return}var h=a.ui.keyCode;switch(g.keyCode){case h.PAGE_UP:this._move("previousPage",g);break;case h.PAGE_DOWN:this._move("nextPage",g);break;case h.UP:this._keyEvent("previous",g);break;case h.DOWN:this._keyEvent("next",g);break}},input:function(g){if(f){f=false;g.preventDefault();return}this._searchTimeout(g)},focus:function(){this.selectedItem=null;this.previous=this._value()},blur:function(g){if(this.cancelBlur){delete this.cancelBlur;return}clearTimeout(this.searching);this.close(g);this._change(g)}});this._initSource();this.menu=a("
      ';var thead=(showWeek?'":"");for(var dow=0;dow<7;dow++){var day=(dow+firstDay)%7;thead+="=5?' class="ui-datepicker-week-end"':"")+'>'+dayNamesMin[day]+""}calender+=thead+"";var daysInMonth=this._getDaysInMonth(drawYear,drawMonth);if(drawYear==inst.selectedYear&&drawMonth==inst.selectedMonth){inst.selectedDay=Math.min(inst.selectedDay,daysInMonth)}var leadDays=(this._getFirstDayOfMonth(drawYear,drawMonth)-firstDay+7)%7;var curRows=Math.ceil((leadDays+daysInMonth)/7);var numRows=(isMultiMonth?this.maxRows>curRows?this.maxRows:curRows:curRows);this.maxRows=numRows;var printDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,1-leadDays));for(var dRow=0;dRow";var tbody=(!showWeek?"":'");for(var dow=0;dow<7;dow++){var daySettings=(beforeShowDay?beforeShowDay.apply((inst.input?inst.input[0]:null),[printDate]):[true,""]);var otherMonth=(printDate.getMonth()!=drawMonth);var unselectable=(otherMonth&&!selectOtherMonths)||!daySettings[0]||(minDate&&printDatemaxDate);tbody+='";printDate.setDate(printDate.getDate()+1);printDate=this._daylightSavingAdjust(printDate)}calender+=tbody+""}drawMonth++;if(drawMonth>11){drawMonth=0;drawYear++}calender+="
      '+this._get(inst,"weekHeader")+"
      '+this._get(inst,"calculateWeek")(printDate)+""+(otherMonth&&!showOtherMonths?" ":(unselectable?''+printDate.getDate()+"":''+printDate.getDate()+""))+"
      "+(isMultiMonth?"
      "+((numMonths[0]>0&&col==numMonths[1]-1)?'
      ':""):"");group+=calender}html+=group}html+=buttonPanel+($.ui.ie6&&!inst.inline?'':"");inst._keyEvent=false;return html},_generateMonthYearHeader:function(inst,drawMonth,drawYear,minDate,maxDate,secondary,monthNames,monthNamesShort){var changeMonth=this._get(inst,"changeMonth");var changeYear=this._get(inst,"changeYear");var showMonthAfterYear=this._get(inst,"showMonthAfterYear");var html='
      ';var monthHtml="";if(secondary||!changeMonth){monthHtml+=''+monthNames[drawMonth]+""}else{var inMinYear=(minDate&&minDate.getFullYear()==drawYear);var inMaxYear=(maxDate&&maxDate.getFullYear()==drawYear);monthHtml+='"}if(!showMonthAfterYear){html+=monthHtml+(secondary||!(changeMonth&&changeYear)?" ":"")}if(!inst.yearshtml){inst.yearshtml="";if(secondary||!changeYear){html+=''+drawYear+""}else{var years=this._get(inst,"yearRange").split(":");var thisYear=new Date().getFullYear();var determineYear=function(value){var year=(value.match(/c[+-].*/)?drawYear+parseInt(value.substring(1),10):(value.match(/[+-].*/)?thisYear+parseInt(value,10):parseInt(value,10)));return(isNaN(year)?thisYear:year)};var year=determineYear(years[0]);var endYear=Math.max(year,determineYear(years[1]||""));year=(minDate?Math.max(year,minDate.getFullYear()):year);endYear=(maxDate?Math.min(endYear,maxDate.getFullYear()):endYear);inst.yearshtml+='";html+=inst.yearshtml;inst.yearshtml=null}}html+=this._get(inst,"yearSuffix");if(showMonthAfterYear){html+=(secondary||!(changeMonth&&changeYear)?" ":"")+monthHtml}html+="
      ";return html},_adjustInstDate:function(inst,offset,period){var year=inst.drawYear+(period=="Y"?offset:0);var month=inst.drawMonth+(period=="M"?offset:0);var day=Math.min(inst.selectedDay,this._getDaysInMonth(year,month))+(period=="D"?offset:0);var date=this._restrictMinMax(inst,this._daylightSavingAdjust(new Date(year,month,day)));inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();if(period=="M"||period=="Y"){this._notifyChange(inst)}},_restrictMinMax:function(inst,date){var minDate=this._getMinMaxDate(inst,"min");var maxDate=this._getMinMaxDate(inst,"max");var newDate=(minDate&&datemaxDate?maxDate:newDate);return newDate},_notifyChange:function(inst){var onChange=this._get(inst,"onChangeMonthYear");if(onChange){onChange.apply((inst.input?inst.input[0]:null),[inst.selectedYear,inst.selectedMonth+1,inst])}},_getNumberOfMonths:function(inst){var numMonths=this._get(inst,"numberOfMonths");return(numMonths==null?[1,1]:(typeof numMonths=="number"?[1,numMonths]:numMonths))},_getMinMaxDate:function(inst,minMax){return this._determineDate(inst,this._get(inst,minMax+"Date"),null)},_getDaysInMonth:function(year,month){return 32-this._daylightSavingAdjust(new Date(year,month,32)).getDate()},_getFirstDayOfMonth:function(year,month){return new Date(year,month,1).getDay()},_canAdjustMonth:function(inst,offset,curYear,curMonth){var numMonths=this._getNumberOfMonths(inst);var date=this._daylightSavingAdjust(new Date(curYear,curMonth+(offset<0?offset:numMonths[0]*numMonths[1]),1));if(offset<0){date.setDate(this._getDaysInMonth(date.getFullYear(),date.getMonth()))}return this._isInRange(inst,date)},_isInRange:function(inst,date){var minDate=this._getMinMaxDate(inst,"min");var maxDate=this._getMinMaxDate(inst,"max");return((!minDate||date.getTime()>=minDate.getTime())&&(!maxDate||date.getTime()<=maxDate.getTime()))},_getFormatConfig:function(inst){var shortYearCutoff=this._get(inst,"shortYearCutoff");shortYearCutoff=(typeof shortYearCutoff!="string"?shortYearCutoff:new Date().getFullYear()%100+parseInt(shortYearCutoff,10));return{shortYearCutoff:shortYearCutoff,dayNamesShort:this._get(inst,"dayNamesShort"),dayNames:this._get(inst,"dayNames"),monthNamesShort:this._get(inst,"monthNamesShort"),monthNames:this._get(inst,"monthNames")}},_formatDate:function(inst,day,month,year){if(!day){inst.currentDay=inst.selectedDay;inst.currentMonth=inst.selectedMonth;inst.currentYear=inst.selectedYear}var date=(day?(typeof day=="object"?day:this._daylightSavingAdjust(new Date(year,month,day))):this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return this.formatDate(this._get(inst,"dateFormat"),date,this._getFormatConfig(inst))}});function bindHover(dpDiv){var selector="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return dpDiv.delegate(selector,"mouseout",function(){$(this).removeClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).removeClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).removeClass("ui-datepicker-next-hover")}}).delegate(selector,"mouseover",function(){if(!$.datepicker._isDisabledDatepicker(instActive.inline?dpDiv.parent()[0]:instActive.input[0])){$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");$(this).addClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).addClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).addClass("ui-datepicker-next-hover")}}})}function extendRemove(target,props){$.extend(target,props);for(var name in props){if(props[name]==null||props[name]==undefined){target[name]=props[name]}}return target}$.fn.datepicker=function(options){if(!this.length){return this}if(!$.datepicker.initialized){$(document).mousedown($.datepicker._checkExternalClick).find(document.body).append($.datepicker.dpDiv);$.datepicker.initialized=true}var otherArgs=Array.prototype.slice.call(arguments,1);if(typeof options=="string"&&(options=="isDisabled"||options=="getDate"||options=="widget")){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}if(options=="option"&&arguments.length==2&&typeof arguments[1]=="string"){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}return this.each(function(){typeof options=="string"?$.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this].concat(otherArgs)):$.datepicker._attachDatepicker(this,options)})};$.datepicker=new Datepicker();$.datepicker.initialized=false;$.datepicker.uuid=new Date().getTime();$.datepicker.version="1.9.2";window["DP_jQuery_"+dpuuid]=$})(jQuery);(function(d,e){var b="ui-dialog ui-widget ui-widget-content ui-corner-all ",a={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},c={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true};d.widget("ui.dialog",{version:"1.9.2",options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",of:window,collision:"fit",using:function(g){var f=d(this).css(g).offset().top;if(f<0){d(this).css("top",g.top-f)}}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1000},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string"){this.originalTitle=""}this.oldPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)};this.options.title=this.options.title||this.originalTitle;var k=this,j=this.options,m=j.title||" ",h,l,f,i,g;h=(this.uiDialog=d("
      ")).addClass(b+j.dialogClass).css({display:"none",outline:0,zIndex:j.zIndex}).attr("tabIndex",-1).keydown(function(n){if(j.closeOnEscape&&!n.isDefaultPrevented()&&n.keyCode&&n.keyCode===d.ui.keyCode.ESCAPE){k.close(n);n.preventDefault()}}).mousedown(function(n){k.moveToTop(false,n)}).appendTo("body");this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(h);l=(this.uiDialogTitlebar=d("
      ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").bind("mousedown",function(){h.focus()}).prependTo(h);f=d("").addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").click(function(n){n.preventDefault();k.close(n)}).appendTo(l);(this.uiDialogTitlebarCloseText=d("")).addClass("ui-icon ui-icon-closethick").text(j.closeText).appendTo(f);i=d("").uniqueId().addClass("ui-dialog-title").html(m).prependTo(l);g=(this.uiDialogButtonPane=d("
      ")).addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");(this.uiButtonSet=d("
      ")).addClass("ui-dialog-buttonset").appendTo(g);h.attr({role:"dialog","aria-labelledby":i.attr("id")});l.find("*").add(l).disableSelection();this._hoverable(f);this._focusable(f);if(j.draggable&&d.fn.draggable){this._makeDraggable()}if(j.resizable&&d.fn.resizable){this._makeResizable()}this._createButtons(j.buttons);this._isOpen=false;if(d.fn.bgiframe){h.bgiframe()}this._on(h,{keydown:function(p){if(!j.modal||p.keyCode!==d.ui.keyCode.TAB){return}var o=d(":tabbable",h),q=o.filter(":first"),n=o.filter(":last");if(p.target===n[0]&&!p.shiftKey){q.focus(1);return false}else{if(p.target===q[0]&&p.shiftKey){n.focus(1);return false}}}})},_init:function(){if(this.options.autoOpen){this.open()}},_destroy:function(){var g,f=this.oldPosition;if(this.overlay){this.overlay.destroy()}this.uiDialog.hide();this.element.removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");this.uiDialog.remove();if(this.originalTitle){this.element.attr("title",this.originalTitle)}g=f.parent.children().eq(f.index);if(g.length&&g[0]!==this.element[0]){g.before(this.element)}else{f.parent.append(this.element)}},widget:function(){return this.uiDialog},close:function(i){var h=this,g,f;if(!this._isOpen){return}if(false===this._trigger("beforeClose",i)){return}this._isOpen=false;if(this.overlay){this.overlay.destroy()}if(this.options.hide){this._hide(this.uiDialog,this.options.hide,function(){h._trigger("close",i)})}else{this.uiDialog.hide();this._trigger("close",i)}d.ui.dialog.overlay.resize();if(this.options.modal){g=0;d(".ui-dialog").each(function(){if(this!==h.uiDialog[0]){f=d(this).css("z-index");if(!isNaN(f)){g=Math.max(g,f)}}});d.ui.dialog.maxZ=g}return this},isOpen:function(){return this._isOpen},moveToTop:function(i,h){var g=this.options,f;if((g.modal&&!i)||(!g.stack&&!g.modal)){return this._trigger("focus",h)}if(g.zIndex>d.ui.dialog.maxZ){d.ui.dialog.maxZ=g.zIndex}if(this.overlay){d.ui.dialog.maxZ+=1;d.ui.dialog.overlay.maxZ=d.ui.dialog.maxZ;this.overlay.$el.css("z-index",d.ui.dialog.overlay.maxZ)}f={scrollTop:this.element.scrollTop(),scrollLeft:this.element.scrollLeft()};d.ui.dialog.maxZ+=1;this.uiDialog.css("z-index",d.ui.dialog.maxZ);this.element.attr(f);this._trigger("focus",h);return this},open:function(){if(this._isOpen){return}var h,g=this.options,f=this.uiDialog;this._size();this._position(g.position);f.show(g.show);this.overlay=g.modal?new d.ui.dialog.overlay(this):null;this.moveToTop(true);h=this.element.find(":tabbable");if(!h.length){h=this.uiDialogButtonPane.find(":tabbable");if(!h.length){h=f}}h.eq(0).focus();this._isOpen=true;this._trigger("open");return this},_createButtons:function(h){var g=this,f=false;this.uiDialogButtonPane.remove();this.uiButtonSet.empty();if(typeof h==="object"&&h!==null){d.each(h,function(){return !(f=true)})}if(f){d.each(h,function(i,k){var j,l;k=d.isFunction(k)?{click:k,text:i}:k;k=d.extend({type:"button"},k);l=k.click;k.click=function(){l.apply(g.element[0],arguments)};j=d("",k).appendTo(g.uiButtonSet);if(d.fn.button){j.button()}});this.uiDialog.addClass("ui-dialog-buttons");this.uiDialogButtonPane.appendTo(this.uiDialog)}else{this.uiDialog.removeClass("ui-dialog-buttons")}},_makeDraggable:function(){var h=this,g=this.options;function f(i){return{position:i.position,offset:i.offset}}this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(i,j){d(this).addClass("ui-dialog-dragging");h._trigger("dragStart",i,f(j))},drag:function(i,j){h._trigger("drag",i,f(j))},stop:function(i,j){g.position=[j.position.left-h.document.scrollLeft(),j.position.top-h.document.scrollTop()];d(this).removeClass("ui-dialog-dragging");h._trigger("dragStop",i,f(j));d.ui.dialog.overlay.resize()}})},_makeResizable:function(j){j=(j===e?this.options.resizable:j);var k=this,i=this.options,f=this.uiDialog.css("position"),h=typeof j==="string"?j:"n,e,s,w,se,sw,ne,nw";function g(l){return{originalPosition:l.originalPosition,originalSize:l.originalSize,position:l.position,size:l.size}}this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:i.maxWidth,maxHeight:i.maxHeight,minWidth:i.minWidth,minHeight:this._minHeight(),handles:h,start:function(l,m){d(this).addClass("ui-dialog-resizing");k._trigger("resizeStart",l,g(m))},resize:function(l,m){k._trigger("resize",l,g(m))},stop:function(l,m){d(this).removeClass("ui-dialog-resizing");i.height=d(this).height();i.width=d(this).width();k._trigger("resizeStop",l,g(m));d.ui.dialog.overlay.resize()}}).css("position",f).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var f=this.options;if(f.height==="auto"){return f.minHeight}else{return Math.min(f.minHeight,f.height)}},_position:function(g){var h=[],i=[0,0],f;if(g){if(typeof g==="string"||(typeof g==="object"&&"0" in g)){h=g.split?g.split(" "):[g[0],g[1]];if(h.length===1){h[1]=h[0]}d.each(["left","top"],function(k,j){if(+h[k]===h[k]){i[k]=h[k];h[k]=j}});g={my:h[0]+(i[0]<0?i[0]:"+"+i[0])+" "+h[1]+(i[1]<0?i[1]:"+"+i[1]),at:h.join(" ")}}g=d.extend({},d.ui.dialog.prototype.options.position,g)}else{g=d.ui.dialog.prototype.options.position}f=this.uiDialog.is(":visible");if(!f){this.uiDialog.show()}this.uiDialog.position(g);if(!f){this.uiDialog.hide()}},_setOptions:function(h){var i=this,f={},g=false;d.each(h,function(j,k){i._setOption(j,k);if(j in a){g=true}if(j in c){f[j]=k}});if(g){this._size()}if(this.uiDialog.is(":data(resizable)")){this.uiDialog.resizable("option",f)}},_setOption:function(h,i){var g,j,f=this.uiDialog;switch(h){case"buttons":this._createButtons(i);break;case"closeText":this.uiDialogTitlebarCloseText.text(""+i);break;case"dialogClass":f.removeClass(this.options.dialogClass).addClass(b+i);break;case"disabled":if(i){f.addClass("ui-dialog-disabled")}else{f.removeClass("ui-dialog-disabled")}break;case"draggable":g=f.is(":data(draggable)");if(g&&!i){f.draggable("destroy")}if(!g&&i){this._makeDraggable()}break;case"position":this._position(i);break;case"resizable":j=f.is(":data(resizable)");if(j&&!i){f.resizable("destroy")}if(j&&typeof i==="string"){f.resizable("option","handles",i)}if(!j&&i!==false){this._makeResizable(i)}break;case"title":d(".ui-dialog-title",this.uiDialogTitlebar).html(""+(i||" "));break}this._super(h,i)},_size:function(){var g,j,i,h=this.options,f=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(h.minWidth>h.width){h.width=h.minWidth}g=this.uiDialog.css({height:"auto",width:h.width}).outerHeight();j=Math.max(0,h.minHeight-g);if(h.height==="auto"){if(d.support.minHeight){this.element.css({minHeight:j,height:"auto"})}else{this.uiDialog.show();i=this.element.css("height","auto").height();if(!f){this.uiDialog.hide()}this.element.height(Math.max(i,j))}}else{this.element.height(Math.max(h.height-g,0))}if(this.uiDialog.is(":data(resizable)")){this.uiDialog.resizable("option","minHeight",this._minHeight())}}});d.extend(d.ui.dialog,{uuid:0,maxZ:0,getTitleId:function(f){var g=f.attr("id");if(!g){this.uuid+=1;g=this.uuid}return"ui-dialog-title-"+g},overlay:function(f){this.$el=d.ui.dialog.overlay.create(f)}});d.extend(d.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:d.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(f){return f+".dialog-overlay"}).join(" "),create:function(g){if(this.instances.length===0){setTimeout(function(){if(d.ui.dialog.overlay.instances.length){d(document).bind(d.ui.dialog.overlay.events,function(h){if(d(h.target).zIndex()").addClass("ui-widget-overlay"));d(document).bind("keydown.dialog-overlay",function(h){var i=d.ui.dialog.overlay.instances;if(i.length!==0&&i[i.length-1]===f&&g.options.closeOnEscape&&!h.isDefaultPrevented()&&h.keyCode&&h.keyCode===d.ui.keyCode.ESCAPE){g.close(h);h.preventDefault()}});f.appendTo(document.body).css({width:this.width(),height:this.height()});if(d.fn.bgiframe){f.bgiframe()}this.instances.push(f);return f},destroy:function(f){var g=d.inArray(f,this.instances),h=0;if(g!==-1){this.oldInstances.push(this.instances.splice(g,1)[0])}if(this.instances.length===0){d([document,window]).unbind(".dialog-overlay")}f.height(0).width(0).remove();d.each(this.instances,function(){h=Math.max(h,this.css("z-index"))});this.maxZ=h},height:function(){var g,f;if(d.ui.ie){g=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);f=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);if(g",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element;this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,b.proxy(function(d){if(this.options.disabled){d.preventDefault()}},this));if(this.options.disabled){this.element.addClass("ui-state-disabled").attr("aria-disabled","true")}this._on({"mousedown .ui-menu-item > a":function(d){d.preventDefault()},"click .ui-state-disabled > a":function(d){d.preventDefault()},"click .ui-menu-item:has(a)":function(d){var e=b(d.target).closest(".ui-menu-item");if(!a&&e.not(".ui-state-disabled").length){a=true;this.select(d);if(e.has(".ui-menu").length){this.expand(d)}else{if(!this.element.is(":focus")){this.element.trigger("focus",[true]);if(this.active&&this.active.parents(".ui-menu").length===1){clearTimeout(this.timer)}}}}},"mouseenter .ui-menu-item":function(d){var e=b(d.currentTarget);e.siblings().children(".ui-state-active").removeClass("ui-state-active");this.focus(d,e)},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(f,d){var e=this.active||this.element.children(".ui-menu-item").eq(0);if(!d){this.focus(f,e)}},blur:function(d){this._delay(function(){if(!b.contains(this.element[0],this.document[0].activeElement)){this.collapseAll(d)}})},keydown:"_keydown"});this.refresh();this._on(this.document,{click:function(d){if(!b(d.target).closest(".ui-menu").length){this.collapseAll(d)}a=false}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").andSelf().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show();this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var d=b(this);if(d.data("ui-menu-submenu-carat")){d.remove()}});this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(j){var e,i,k,h,g,d=true;function f(l){return l.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}switch(j.keyCode){case b.ui.keyCode.PAGE_UP:this.previousPage(j);break;case b.ui.keyCode.PAGE_DOWN:this.nextPage(j);break;case b.ui.keyCode.HOME:this._move("first","first",j);break;case b.ui.keyCode.END:this._move("last","last",j);break;case b.ui.keyCode.UP:this.previous(j);break;case b.ui.keyCode.DOWN:this.next(j);break;case b.ui.keyCode.LEFT:this.collapse(j);break;case b.ui.keyCode.RIGHT:if(this.active&&!this.active.is(".ui-state-disabled")){this.expand(j)}break;case b.ui.keyCode.ENTER:case b.ui.keyCode.SPACE:this._activate(j);break;case b.ui.keyCode.ESCAPE:this.collapse(j);break;default:d=false;i=this.previousFilter||"";k=String.fromCharCode(j.keyCode);h=false;clearTimeout(this.filterTimer);if(k===i){h=true}else{k=i+k}g=new RegExp("^"+f(k),"i");e=this.activeMenu.children(".ui-menu-item").filter(function(){return g.test(b(this).children("a").text())});e=h&&e.index(this.active.next())!==-1?this.active.nextAll(".ui-menu-item"):e;if(!e.length){k=String.fromCharCode(j.keyCode);g=new RegExp("^"+f(k),"i");e=this.activeMenu.children(".ui-menu-item").filter(function(){return g.test(b(this).children("a").text())})}if(e.length){this.focus(j,e);if(e.length>1){this.previousFilter=k;this.filterTimer=this._delay(function(){delete this.previousFilter},1000)}else{delete this.previousFilter}}else{delete this.previousFilter}}if(d){j.preventDefault()}},_activate:function(d){if(!this.active.is(".ui-state-disabled")){if(this.active.children("a[aria-haspopup='true']").length){this.expand(d)}else{this.select(d)}}},refresh:function(){var f,e=this.options.icons.submenu,d=this.element.find(this.options.menus);d.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var i=b(this),h=i.prev("a"),g=b("").addClass("ui-menu-icon ui-icon "+e).data("ui-menu-submenu-carat",true);h.attr("aria-haspopup","true").prepend(g);i.attr("aria-labelledby",h.attr("id"))});f=d.add(this.element);f.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()});f.children(":not(.ui-menu-item)").each(function(){var g=b(this);if(!/[^\-—–\s]/.test(g.text())){g.addClass("ui-widget-content ui-menu-divider")}});f.children(".ui-state-disabled").attr("aria-disabled","true");if(this.active&&!b.contains(this.element[0],this.active[0])){this.blur()}},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},focus:function(e,d){var g,f;this.blur(e,e&&e.type==="focus");this._scrollIntoView(d);this.active=d.first();f=this.active.children("a").addClass("ui-state-focus");if(this.options.role){this.element.attr("aria-activedescendant",f.attr("id"))}this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active");if(e&&e.type==="keydown"){this._close()}else{this.timer=this._delay(function(){this._close()},this.delay)}g=d.children(".ui-menu");if(g.length&&(/^mouse/.test(e.type))){this._startOpening(g)}this.activeMenu=d.parent();this._trigger("focus",e,{item:d})},_scrollIntoView:function(g){var j,f,h,d,e,i;if(this._hasScroll()){j=parseFloat(b.css(this.activeMenu[0],"borderTopWidth"))||0;f=parseFloat(b.css(this.activeMenu[0],"paddingTop"))||0;h=g.offset().top-this.activeMenu.offset().top-j-f;d=this.activeMenu.scrollTop();e=this.activeMenu.height();i=g.height();if(h<0){this.activeMenu.scrollTop(d+h)}else{if(h+i>e){this.activeMenu.scrollTop(d+h-e+i)}}}},blur:function(e,d){if(!d){clearTimeout(this.timer)}if(!this.active){return}this.active.children("a").removeClass("ui-state-focus");this.active=null;this._trigger("blur",e,{item:this.active})},_startOpening:function(d){clearTimeout(this.timer);if(d.attr("aria-hidden")!=="true"){return}this.timer=this._delay(function(){this._close();this._open(d)},this.delay)},_open:function(e){var d=b.extend({of:this.active},this.options.position);clearTimeout(this.timer);this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true");e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(d)},collapseAll:function(e,d){clearTimeout(this.timer);this.timer=this._delay(function(){var f=d?this.element:b(e&&e.target).closest(this.element.find(".ui-menu"));if(!f.length){f=this.element}this._close(f);this.blur(e);this.activeMenu=f},this.delay)},_close:function(d){if(!d){d=this.active?this.active.parent():this.element}d.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active")},collapse:function(e){var d=this.active&&this.active.parent().closest(".ui-menu-item",this.element);if(d&&d.length){this._close();this.focus(e,d)}},expand:function(e){var d=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();if(d&&d.length){this._open(d.parent());this._delay(function(){this.focus(e,d)})}},next:function(d){this._move("next","first",d)},previous:function(d){this._move("prev","last",d)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(g,e,f){var d;if(this.active){if(g==="first"||g==="last"){d=this.active[g==="first"?"prevAll":"nextAll"](".ui-menu-item").eq(-1)}else{d=this.active[g+"All"](".ui-menu-item").eq(0)}}if(!d||!d.length||!this.active){d=this.activeMenu.children(".ui-menu-item")[e]()}this.focus(f,d)},nextPage:function(f){var e,g,d;if(!this.active){this.next(f);return}if(this.isLastItem()){return}if(this._hasScroll()){g=this.active.offset().top;d=this.element.height();this.active.nextAll(".ui-menu-item").each(function(){e=b(this);return e.offset().top-g-d<0});this.focus(f,e)}else{this.focus(f,this.activeMenu.children(".ui-menu-item")[!this.active?"first":"last"]())}},previousPage:function(f){var e,g,d;if(!this.active){this.next(f);return}if(this.isFirstItem()){return}if(this._hasScroll()){g=this.active.offset().top;d=this.element.height();this.active.prevAll(".ui-menu-item").each(function(){e=b(this);return e.offset().top-g+d>0});this.focus(f,e)}else{this.focus(f,this.activeMenu.children(".ui-menu-item").first())}},_hasScroll:function(){return this.element.outerHeight()
      ").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");this.valueDiv.remove()},value:function(c){if(c===b){return this._value()}this._setOption("value",c);return this},_setOption:function(c,d){if(c==="value"){this.options.value=d;this._refreshValue();if(this._value()===this.options.max){this._trigger("complete")}}this._super(c,d)},_value:function(){var c=this.options.value;if(typeof c!=="number"){c=0}return Math.min(this.options.max,Math.max(this.min,c))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var d=this.value(),c=this._percentage();if(this.oldValue!==d){this.oldValue=d;this._trigger("change")}this.valueDiv.toggle(d>this.min).toggleClass("ui-corner-right",d===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",d)}})})(jQuery);(function(b,c){var a=5;b.widget("ui.slider",b.ui.mouse,{version:"1.9.2",widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var f,d,j=this.options,h=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),g="",e=[];this._keySliding=false;this._mouseSliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all"+(j.disabled?" ui-slider-disabled ui-disabled":""));this.range=b([]);if(j.range){if(j.range===true){if(!j.values){j.values=[this._valueMin(),this._valueMin()]}if(j.values.length&&j.values.length!==2){j.values=[j.values[0],j.values[0]]}}this.range=b("
      ").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+((j.range==="min"||j.range==="max")?" ui-slider-range-"+j.range:""))}d=(j.values&&j.values.length)||1;for(f=h.length;fp){e=p;h=b(this);l=o}});if(g.range===true&&this.values(1)===g.min){l+=1;h=b(this.handles[l])}n=this._start(f,l);if(n===false){return false}this._mouseSliding=true;this._handleIndex=l;h.addClass("ui-state-active").focus();i=h.offset();d=!b(f.target).parents().andSelf().is(".ui-slider-handle");this._clickOffset=d?{left:0,top:0}:{left:f.pageX-i.left-(h.width()/2),top:f.pageY-i.top-(h.height()/2)-(parseInt(h.css("borderTopWidth"),10)||0)-(parseInt(h.css("borderBottomWidth"),10)||0)+(parseInt(h.css("marginTop"),10)||0)};if(!this.handles.hasClass("ui-state-hover")){this._slide(f,l,m)}this._animateOff=true;return true},_mouseStart:function(){return true},_mouseDrag:function(f){var d={x:f.pageX,y:f.pageY},e=this._normValueFromMouse(d);this._slide(f,this._handleIndex,e);return false},_mouseStop:function(d){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(d,this._handleIndex);this._change(d,this._handleIndex);this._handleIndex=null;this._clickOffset=null;this._animateOff=false;return false},_detectOrientation:function(){this.orientation=(this.options.orientation==="vertical")?"vertical":"horizontal"},_normValueFromMouse:function(e){var d,h,g,f,i;if(this.orientation==="horizontal"){d=this.elementSize.width;h=e.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{d=this.elementSize.height;h=e.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}g=(h/d);if(g>1){g=1}if(g<0){g=0}if(this.orientation==="vertical"){g=1-g}f=this._valueMax()-this._valueMin();i=this._valueMin()+g*f;return this._trimAlignValue(i)},_start:function(f,e){var d={handle:this.handles[e],value:this.value()};if(this.options.values&&this.options.values.length){d.value=this.values(e);d.values=this.values()}return this._trigger("start",f,d)},_slide:function(h,g,f){var d,e,i;if(this.options.values&&this.options.values.length){d=this.values(g?0:1);if((this.options.values.length===2&&this.options.range===true)&&((g===0&&f>d)||(g===1&&f1){this.options.values[e]=this._trimAlignValue(h);this._refreshValue();this._change(null,e);return}if(arguments.length){if(b.isArray(arguments[0])){g=this.options.values;d=arguments[0];for(f=0;f=this._valueMax()){return this._valueMax()}var d=(this.options.step>0)?this.options.step:1,f=(g-this._valueMin())%d,e=g-f;if(Math.abs(f)*2>=d){e+=(f>0)?d:(-d)}return parseFloat(e.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var i,h,l,j,m,g=this.options.range,f=this.options,k=this,e=(!this._animateOff)?f.animate:false,d={};if(this.options.values&&this.options.values.length){this.handles.each(function(n){h=(k.values(n)-k._valueMin())/(k._valueMax()-k._valueMin())*100;d[k.orientation==="horizontal"?"left":"bottom"]=h+"%";b(this).stop(1,1)[e?"animate":"css"](d,f.animate);if(k.options.range===true){if(k.orientation==="horizontal"){if(n===0){k.range.stop(1,1)[e?"animate":"css"]({left:h+"%"},f.animate)}if(n===1){k.range[e?"animate":"css"]({width:(h-i)+"%"},{queue:false,duration:f.animate})}}else{if(n===0){k.range.stop(1,1)[e?"animate":"css"]({bottom:(h)+"%"},f.animate)}if(n===1){k.range[e?"animate":"css"]({height:(h-i)+"%"},{queue:false,duration:f.animate})}}}i=h})}else{l=this.value();j=this._valueMin();m=this._valueMax();h=(m!==j)?(l-j)/(m-j)*100:0;d[this.orientation==="horizontal"?"left":"bottom"]=h+"%";this.handle.stop(1,1)[e?"animate":"css"](d,f.animate);if(g==="min"&&this.orientation==="horizontal"){this.range.stop(1,1)[e?"animate":"css"]({width:h+"%"},f.animate)}if(g==="max"&&this.orientation==="horizontal"){this.range[e?"animate":"css"]({width:(100-h)+"%"},{queue:false,duration:f.animate})}if(g==="min"&&this.orientation==="vertical"){this.range.stop(1,1)[e?"animate":"css"]({height:h+"%"},f.animate)}if(g==="max"&&this.orientation==="vertical"){this.range[e?"animate":"css"]({height:(100-h)+"%"},{queue:false,duration:f.animate})}}}})}(jQuery));(function(b){function a(c){return function(){var d=this.element.val();c.apply(this,arguments);this._refresh();if(d!==this.element.val()){this._trigger("change")}}}b.widget("ui.spinner",{version:"1.9.2",defaultElement:"",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:true,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max);this._setOption("min",this.options.min);this._setOption("step",this.options.step);this._value(this.element.val(),true);this._draw();this._on(this._events);this._refresh();this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var c={},d=this.element;b.each(["min","max","step"],function(e,f){var g=d.attr(f);if(g!==undefined&&g.length){c[f]=g}});return c},_events:{keydown:function(c){if(this._start(c)&&this._keydown(c)){c.preventDefault()}},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(c){if(this.cancelBlur){delete this.cancelBlur;return}this._refresh();if(this.previous!==this.element.val()){this._trigger("change",c)}},mousewheel:function(c,d){if(!d){return}if(!this.spinning&&!this._start(c)){return false}this._spin((d>0?1:-1)*this.options.step,c);clearTimeout(this.mousewheelTimer);this.mousewheelTimer=this._delay(function(){if(this.spinning){this._stop(c)}},100);c.preventDefault()},"mousedown .ui-spinner-button":function(d){var c;c=this.element[0]===this.document[0].activeElement?this.previous:this.element.val();function e(){var f=this.element[0]===this.document[0].activeElement;if(!f){this.element.focus();this.previous=c;this._delay(function(){this.previous=c})}}d.preventDefault();e.call(this);this.cancelBlur=true;this._delay(function(){delete this.cancelBlur;e.call(this)});if(this._start(d)===false){return}this._repeat(null,b(d.currentTarget).hasClass("ui-spinner-up")?1:-1,d)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(c){if(!b(c.currentTarget).hasClass("ui-state-active")){return}if(this._start(c)===false){return false}this._repeat(null,b(c.currentTarget).hasClass("ui-spinner-up")?1:-1,c)},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var c=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton");this.buttons=c.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all");if(this.buttons.height()>Math.ceil(c.height()*0.5)&&c.height()>0){c.height(c.height())}if(this.options.disabled){this.disable()}},_keydown:function(d){var c=this.options,e=b.ui.keyCode;switch(d.keyCode){case e.UP:this._repeat(null,1,d);return true;case e.DOWN:this._repeat(null,-1,d);return true;case e.PAGE_UP:this._repeat(null,c.page,d);return true;case e.PAGE_DOWN:this._repeat(null,-c.page,d);return true}return false},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""},_start:function(c){if(!this.spinning&&this._trigger("start",c)===false){return false}if(!this.counter){this.counter=1}this.spinning=true;return true},_repeat:function(d,c,e){d=d||500;clearTimeout(this.timer);this.timer=this._delay(function(){this._repeat(40,c,e)},d);this._spin(c*this.options.step,e)},_spin:function(d,c){var e=this.value()||0;if(!this.counter){this.counter=1}e=this._adjustValue(e+d*this._increment(this.counter));if(!this.spinning||this._trigger("spin",c,{value:e})!==false){this._value(e);this.counter++}},_increment:function(c){var d=this.options.incremental;if(d){return b.isFunction(d)?d(c):Math.floor(c*c*c/50000-c*c/500+17*c/200+1)}return 1},_precision:function(){var c=this._precisionOf(this.options.step);if(this.options.min!==null){c=Math.max(c,this._precisionOf(this.options.min))}return c},_precisionOf:function(d){var e=d.toString(),c=e.indexOf(".");return c===-1?0:e.length-c-1},_adjustValue:function(e){var d,f,c=this.options;d=c.min!==null?c.min:0;f=e-d;f=Math.round(f/c.step)*c.step;e=d+f;e=parseFloat(e.toFixed(this._precision()));if(c.max!==null&&e>c.max){return c.max}if(c.min!==null&&e1&&g.href.replace(f,"")===location.href.replace(f,"").replace(/\s/g,"%20")}c.widget("ui.tabs",{version:"1.9.2",delay:300,options:{active:null,collapsible:false,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var h=this,g=this.options,i=g.active,j=location.hash.substring(1);this.running=false;this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",g.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(k){if(c(this).is(".ui-state-disabled")){k.preventDefault()}}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){if(c(this).closest("li").is(".ui-state-disabled")){this.blur()}});this._processTabs();if(i===null){if(j){this.tabs.each(function(k,l){if(c(l).attr("aria-controls")===j){i=k;return false}})}if(i===null){i=this.tabs.index(this.tabs.filter(".ui-tabs-active"))}if(i===null||i===-1){i=this.tabs.length?0:false}}if(i!==false){i=this.tabs.index(this.tabs.eq(i));if(i===-1){i=g.collapsible?false:0}}g.active=i;if(!g.collapsible&&g.active===false&&this.anchors.length){g.active=0}if(c.isArray(g.disabled)){g.disabled=c.unique(g.disabled.concat(c.map(this.tabs.filter(".ui-state-disabled"),function(k){return h.tabs.index(k)}))).sort()}if(this.options.active!==false&&this.anchors.length){this.active=this._findActive(this.options.active)}else{this.active=c()}this._refresh();if(this.active.length){this.load(g.active)}},_getCreateEventData:function(){return{tab:this.active,panel:!this.active.length?c():this._getPanelForTab(this.active)}},_tabKeydown:function(i){var h=c(this.document[0].activeElement).closest("li"),g=this.tabs.index(h),j=true;if(this._handlePageNav(i)){return}switch(i.keyCode){case c.ui.keyCode.RIGHT:case c.ui.keyCode.DOWN:g++;break;case c.ui.keyCode.UP:case c.ui.keyCode.LEFT:j=false;g--;break;case c.ui.keyCode.END:g=this.anchors.length-1;break;case c.ui.keyCode.HOME:g=0;break;case c.ui.keyCode.SPACE:i.preventDefault();clearTimeout(this.activating);this._activate(g);return;case c.ui.keyCode.ENTER:i.preventDefault();clearTimeout(this.activating);this._activate(g===this.options.active?false:g);return;default:return}i.preventDefault();clearTimeout(this.activating);g=this._focusNextTab(g,j);if(!i.ctrlKey){h.attr("aria-selected","false");this.tabs.eq(g).attr("aria-selected","true");this.activating=this._delay(function(){this.option("active",g)},this.delay)}},_panelKeydown:function(g){if(this._handlePageNav(g)){return}if(g.ctrlKey&&g.keyCode===c.ui.keyCode.UP){g.preventDefault();this.active.focus()}},_handlePageNav:function(g){if(g.altKey&&g.keyCode===c.ui.keyCode.PAGE_UP){this._activate(this._focusNextTab(this.options.active-1,false));return true}if(g.altKey&&g.keyCode===c.ui.keyCode.PAGE_DOWN){this._activate(this._focusNextTab(this.options.active+1,true));return true}},_findNextTab:function(h,i){var g=this.tabs.length-1;function j(){if(h>g){h=0}if(h<0){h=g}return h}while(c.inArray(j(),this.options.disabled)!==-1){h=i?h+1:h-1}return h},_focusNextTab:function(g,h){g=this._findNextTab(g,h);this.tabs.eq(g).focus();return g},_setOption:function(g,h){if(g==="active"){this._activate(h);return}if(g==="disabled"){this._setupDisabled(h);return}this._super(g,h);if(g==="collapsible"){this.element.toggleClass("ui-tabs-collapsible",h);if(!h&&this.options.active===false){this._activate(0)}}if(g==="event"){this._setupEvents(h)}if(g==="heightStyle"){this._setupHeightStyle(h)}},_tabId:function(g){return g.attr("aria-controls")||"ui-tabs-"+d()},_sanitizeSelector:function(g){return g?g.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var h=this.options,g=this.tablist.children(":has(a[href])");h.disabled=c.map(g.filter(".ui-state-disabled"),function(i){return g.index(i)});this._processTabs();if(h.active===false||!this.anchors.length){h.active=false;this.active=c()}else{if(this.active.length&&!c.contains(this.tablist[0],this.active[0])){if(this.tabs.length===h.disabled.length){h.active=false;this.active=c()}else{this._activate(this._findNextTab(Math.max(0,h.active-1),false))}}else{h.active=this.tabs.index(this.active)}}this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled);this._setupEvents(this.options.event);this._setupHeightStyle(this.options.heightStyle);this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1});this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"});if(!this.active.length){this.tabs.eq(0).attr("tabIndex",0)}else{this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0});this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})}},_processTabs:function(){var g=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist");this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1});this.anchors=this.tabs.map(function(){return c("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1});this.panels=c();this.anchors.each(function(n,l){var h,j,m,k=c(l).uniqueId().attr("id"),o=c(l).closest("li"),p=o.attr("aria-controls");if(b(l)){h=l.hash;j=g.element.find(g._sanitizeSelector(h))}else{m=g._tabId(o);h="#"+m;j=g.element.find(h);if(!j.length){j=g._createPanel(m);j.insertAfter(g.panels[n-1]||g.tablist)}j.attr("aria-live","polite")}if(j.length){g.panels=g.panels.add(j)}if(p){o.data("ui-tabs-aria-controls",p)}o.attr({"aria-controls":h.substring(1),"aria-labelledby":k});j.attr("aria-labelledby",k)});this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.element.find("ol,ul").eq(0)},_createPanel:function(g){return c("
      ").attr("id",g).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",true)},_setupDisabled:function(j){if(c.isArray(j)){if(!j.length){j=false}else{if(j.length===this.anchors.length){j=true}}}for(var h=0,g;(g=this.tabs[h]);h++){if(j===true||c.inArray(h,j)!==-1){c(g).addClass("ui-state-disabled").attr("aria-disabled","true")}else{c(g).removeClass("ui-state-disabled").removeAttr("aria-disabled")}}this.options.disabled=j},_setupEvents:function(h){var g={click:function(i){i.preventDefault()}};if(h){c.each(h.split(" "),function(j,i){g[i]="_eventHandler"})}this._off(this.anchors.add(this.tabs).add(this.panels));this._on(this.anchors,g);this._on(this.tabs,{keydown:"_tabKeydown"});this._on(this.panels,{keydown:"_panelKeydown"});this._focusable(this.tabs);this._hoverable(this.tabs)},_setupHeightStyle:function(g){var i,j,h=this.element.parent();if(g==="fill"){if(!c.support.minHeight){j=h.css("overflow");h.css("overflow","hidden")}i=h.height();this.element.siblings(":visible").each(function(){var l=c(this),k=l.css("position");if(k==="absolute"||k==="fixed"){return}i-=l.outerHeight(true)});if(j){h.css("overflow",j)}this.element.children().not(this.panels).each(function(){i-=c(this).outerHeight(true)});this.panels.each(function(){c(this).height(Math.max(0,i-c(this).innerHeight()+c(this).height()))}).css("overflow","auto")}else{if(g==="auto"){i=0;this.panels.each(function(){i=Math.max(i,c(this).height("").height())}).height(i)}}},_eventHandler:function(g){var p=this.options,k=this.active,l=c(g.currentTarget),j=l.closest("li"),n=j[0]===k[0],h=n&&p.collapsible,i=h?c():this._getPanelForTab(j),m=!k.length?c():this._getPanelForTab(k),o={oldTab:k,oldPanel:m,newTab:h?c():j,newPanel:i};g.preventDefault();if(j.hasClass("ui-state-disabled")||j.hasClass("ui-tabs-loading")||this.running||(n&&!p.collapsible)||(this._trigger("beforeActivate",g,o)===false)){return}p.active=h?false:this.tabs.index(j);this.active=n?c():j;if(this.xhr){this.xhr.abort()}if(!m.length&&!i.length){c.error("jQuery UI Tabs: Mismatching fragment identifier.")}if(i.length){this.load(this.tabs.index(j),g)}this._toggle(g,o)},_toggle:function(m,l){var k=this,g=l.newPanel,j=l.oldPanel;this.running=true;function i(){k.running=false;k._trigger("activate",m,l)}function h(){l.newTab.closest("li").addClass("ui-tabs-active ui-state-active");if(g.length&&k.options.show){k._show(g,k.options.show,i)}else{g.show();i()}}if(j.length&&this.options.hide){this._hide(j,this.options.hide,function(){l.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active");h()})}else{l.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active");j.hide();h()}j.attr({"aria-expanded":"false","aria-hidden":"true"});l.oldTab.attr("aria-selected","false");if(g.length&&j.length){l.oldTab.attr("tabIndex",-1)}else{if(g.length){this.tabs.filter(function(){return c(this).attr("tabIndex")===0}).attr("tabIndex",-1)}}g.attr({"aria-expanded":"true","aria-hidden":"false"});l.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(h){var g,i=this._findActive(h);if(i[0]===this.active[0]){return}if(!i.length){i=this.active}g=i.find(".ui-tabs-anchor")[0];this._eventHandler({target:g,currentTarget:g,preventDefault:c.noop})},_findActive:function(g){return g===false?c():this.tabs.eq(g)},_getIndex:function(g){if(typeof g==="string"){g=this.anchors.index(this.anchors.filter("[href$='"+g+"']"))}return g},_destroy:function(){if(this.xhr){this.xhr.abort()}this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible");this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role");this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeData("href.tabs").removeData("load.tabs").removeUniqueId();this.tabs.add(this.panels).each(function(){if(c.data(this,"ui-tabs-destroy")){c(this).remove()}else{c(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}});this.tabs.each(function(){var g=c(this),h=g.data("ui-tabs-aria-controls");if(h){g.attr("aria-controls",h)}else{g.removeAttr("aria-controls")}});this.panels.show();if(this.options.heightStyle!=="content"){this.panels.css("height","")}},enable:function(g){var h=this.options.disabled;if(h===false){return}if(g===e){h=false}else{g=this._getIndex(g);if(c.isArray(h)){h=c.map(h,function(i){return i!==g?i:null})}else{h=c.map(this.tabs,function(i,j){return j!==g?j:null})}}this._setupDisabled(h)},disable:function(g){var h=this.options.disabled;if(h===true){return}if(g===e){h=true}else{g=this._getIndex(g);if(c.inArray(g,h)!==-1){return}if(c.isArray(h)){h=c.merge([g],h).sort()}else{h=[g]}}this._setupDisabled(h)},load:function(i,m){i=this._getIndex(i);var l=this,j=this.tabs.eq(i),h=j.find(".ui-tabs-anchor"),g=this._getPanelForTab(j),k={tab:j,panel:g};if(b(h[0])){return}this.xhr=c.ajax(this._ajaxSettings(h,m,k));if(this.xhr&&this.xhr.statusText!=="canceled"){j.addClass("ui-tabs-loading");g.attr("aria-busy","true");this.xhr.success(function(n){setTimeout(function(){g.html(n);l._trigger("load",m,k)},1)}).complete(function(o,n){setTimeout(function(){if(n==="abort"){l.panels.stop(false,true)}j.removeClass("ui-tabs-loading");g.removeAttr("aria-busy");if(o===l.xhr){delete l.xhr}},1)})}},_ajaxSettings:function(g,j,i){var h=this;return{url:g.attr("href"),beforeSend:function(l,k){return h._trigger("beforeLoad",j,c.extend({jqXHR:l,ajaxSettings:k},i))}}},_getPanelForTab:function(g){var h=c(g).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+h))}});if(c.uiBackCompat!==false){c.ui.tabs.prototype._ui=function(h,g){return{tab:h,panel:g,index:this.anchors.index(h)}};c.widget("ui.tabs",c.ui.tabs,{url:function(h,g){this.anchors.eq(h).attr("href",g)}});c.widget("ui.tabs",c.ui.tabs,{options:{ajaxOptions:null,cache:false},_create:function(){this._super();var g=this;this._on({tabsbeforeload:function(h,i){if(c.data(i.tab[0],"cache.tabs")){h.preventDefault();return}i.jqXHR.success(function(){if(g.options.cache){c.data(i.tab[0],"cache.tabs",true)}})}})},_ajaxSettings:function(h,i,j){var g=this.options.ajaxOptions;return c.extend({},g,{error:function(m,k){try{g.error(m,k,j.tab.closest("li").index(),j.tab[0])}catch(l){}}},this._superApply(arguments))},_setOption:function(g,h){if(g==="cache"&&h===false){this.anchors.removeData("cache.tabs")}this._super(g,h)},_destroy:function(){this.anchors.removeData("cache.tabs");this._super()},url:function(g){this.anchors.eq(g).removeData("cache.tabs");this._superApply(arguments)}});c.widget("ui.tabs",c.ui.tabs,{abort:function(){if(this.xhr){this.xhr.abort()}}});c.widget("ui.tabs",c.ui.tabs,{options:{spinner:"Loading…"},_create:function(){this._super();this._on({tabsbeforeload:function(i,j){if(i.target!==this.element[0]||!this.options.spinner){return}var h=j.tab.find("span"),g=h.html();h.html(this.options.spinner);j.jqXHR.complete(function(){h.html(g)})}})}});c.widget("ui.tabs",c.ui.tabs,{options:{enable:null,disable:null},enable:function(i){var h=this.options,g;if(i&&h.disabled===true||(c.isArray(h.disabled)&&c.inArray(i,h.disabled)!==-1)){g=true}this._superApply(arguments);if(g){this._trigger("enable",null,this._ui(this.anchors[i],this.panels[i]))}},disable:function(i){var h=this.options,g;if(i&&h.disabled===false||(c.isArray(h.disabled)&&c.inArray(i,h.disabled)===-1)){g=true}this._superApply(arguments);if(g){this._trigger("disable",null,this._ui(this.anchors[i],this.panels[i]))}}});c.widget("ui.tabs",c.ui.tabs,{options:{add:null,remove:null,tabTemplate:"
    • #{label}
    • "},add:function(l,k,j){if(j===e){j=this.anchors.length}var m,h,i=this.options,g=c(i.tabTemplate.replace(/#\{href\}/g,l).replace(/#\{label\}/g,k)),n=!l.indexOf("#")?l.replace("#",""):this._tabId(g);g.addClass("ui-state-default ui-corner-top").data("ui-tabs-destroy",true);g.attr("aria-controls",n);m=j>=this.tabs.length;h=this.element.find("#"+n);if(!h.length){h=this._createPanel(n);if(m){if(j>0){h.insertAfter(this.panels.eq(-1))}else{h.appendTo(this.element)}}else{h.insertBefore(this.panels[j])}}h.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").hide();if(m){g.appendTo(this.tablist)}else{g.insertBefore(this.tabs[j])}i.disabled=c.map(i.disabled,function(o){return o>=j?++o:o});this.refresh();if(this.tabs.length===1&&i.active===false){this.option("active",0)}this._trigger("add",null,this._ui(this.anchors[j],this.panels[j]));return this},remove:function(i){i=this._getIndex(i);var h=this.options,j=this.tabs.eq(i).remove(),g=this._getPanelForTab(j).remove();if(j.hasClass("ui-tabs-active")&&this.anchors.length>2){this._activate(i+(i+1=i?--k:k});this.refresh();this._trigger("remove",null,this._ui(j.find("a")[0],g[0]));return this}});c.widget("ui.tabs",c.ui.tabs,{length:function(){return this.anchors.length}});c.widget("ui.tabs",c.ui.tabs,{options:{idPrefix:"ui-tabs-"},_tabId:function(h){var g=h.is("li")?h.find("a[href]"):h;g=g[0];return c(g).closest("li").attr("aria-controls")||g.title&&g.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF\-]/g,"")||this.options.idPrefix+d()}});c.widget("ui.tabs",c.ui.tabs,{options:{panelTemplate:"
      "},_createPanel:function(g){return c(this.options.panelTemplate).attr("id",g).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",true)}});c.widget("ui.tabs",c.ui.tabs,{_create:function(){var g=this.options;if(g.active===null&&g.selected!==e){g.active=g.selected===-1?false:g.selected}this._super();g.selected=g.active;if(g.selected===false){g.selected=-1}},_setOption:function(h,i){if(h!=="selected"){return this._super(h,i)}var g=this.options;this._super("active",i===-1?false:i);g.selected=g.active;if(g.selected===false){g.selected=-1}},_eventHandler:function(){this._superApply(arguments);this.options.selected=this.options.active;if(this.options.selected===false){this.options.selected=-1}}});c.widget("ui.tabs",c.ui.tabs,{options:{show:null,select:null},_create:function(){this._super();if(this.options.active!==false){this._trigger("show",null,this._ui(this.active.find(".ui-tabs-anchor")[0],this._getPanelForTab(this.active)[0]))}},_trigger:function(j,k,l){var i,g,h=this._superApply(arguments);if(!h){return false}if(j==="beforeActivate"){i=l.newTab.length?l.newTab:l.oldTab;g=l.newPanel.length?l.newPanel:l.oldPanel;h=this._super("select",k,{tab:i.find(".ui-tabs-anchor")[0],panel:g[0],index:i.closest("li").index()})}else{if(j==="activate"&&l.newTab.length){h=this._super("show",k,{tab:l.newTab.find(".ui-tabs-anchor")[0],panel:l.newPanel[0],index:l.newTab.closest("li").index()})}}return h}});c.widget("ui.tabs",c.ui.tabs,{select:function(g){g=this._getIndex(g);if(g===-1){if(this.options.collapsible&&this.options.selected!==-1){g=this.options.selected}else{return}}this.anchors.eq(g).trigger(this.options.event+this.eventNamespace)}});(function(){var g=0;c.widget("ui.tabs",c.ui.tabs,{options:{cookie:null},_create:function(){var h=this.options,i;if(h.active==null&&h.cookie){i=parseInt(this._cookie(),10);if(i===-1){i=false}h.active=i}this._super()},_cookie:function(i){var h=[this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+(++g))];if(arguments.length){h.push(i===false?-1:i);h.push(this.options.cookie)}return c.cookie.apply(null,h)},_refresh:function(){this._super();if(this.options.cookie){this._cookie(this.options.active,this.options.cookie)}},_eventHandler:function(){this._superApply(arguments);if(this.options.cookie){this._cookie(this.options.active,this.options.cookie)}},_destroy:function(){this._super();if(this.options.cookie){this._cookie(null,this.options.cookie)}}})})();c.widget("ui.tabs",c.ui.tabs,{_trigger:function(h,i,j){var g=c.extend({},j);if(h==="load"){g.panel=g.panel[0];g.tab=g.tab.find(".ui-tabs-anchor")[0]}return this._super(h,i,g)}});c.widget("ui.tabs",c.ui.tabs,{options:{fx:null},_getFx:function(){var h,g,i=this.options.fx;if(i){if(c.isArray(i)){h=i[0];g=i[1]}else{h=g=i}}return i?{show:g,hide:h}:null},_toggle:function(n,m){var l=this,g=m.newPanel,j=m.oldPanel,k=this._getFx();if(!k){return this._super(n,m)}l.running=true;function i(){l.running=false;l._trigger("activate",n,m)}function h(){m.newTab.closest("li").addClass("ui-tabs-active ui-state-active");if(g.length&&k.show){g.animate(k.show,k.show.duration,function(){i()})}else{g.show();i()}}if(j.length&&k.hide){j.animate(k.hide,k.hide.duration,function(){m.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active");h()})}else{m.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active");j.hide();h()}}})}})(jQuery);(function(d){var b=0;function c(f,g){var e=(f.attr("aria-describedby")||"").split(/\s+/);e.push(g);f.data("ui-tooltip-id",g).attr("aria-describedby",d.trim(e.join(" ")))}function a(g){var h=g.data("ui-tooltip-id"),f=(g.attr("aria-describedby")||"").split(/\s+/),e=d.inArray(h,f);if(e!==-1){f.splice(e,1)}g.removeData("ui-tooltip-id");f=d.trim(f.join(" "));if(f){g.attr("aria-describedby",f)}else{g.removeAttr("aria-describedby")}}d.widget("ui.tooltip",{version:"1.9.2",options:{content:function(){return d(this).attr("title")},hide:true,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:true,tooltipClass:null,track:false,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"});this.tooltips={};this.parents={};if(this.options.disabled){this._disable()}},_setOption:function(e,g){var f=this;if(e==="disabled"){this[g?"_disable":"_enable"]();this.options[e]=g;return}this._super(e,g);if(e==="content"){d.each(this.tooltips,function(i,h){f._updateContent(h)})}},_disable:function(){var e=this;d.each(this.tooltips,function(h,f){var g=d.Event("blur");g.target=g.currentTarget=f[0];e.close(g,true)});this.element.find(this.options.items).andSelf().each(function(){var f=d(this);if(f.is("[title]")){f.data("ui-tooltip-title",f.attr("title")).attr("title","")}})},_enable:function(){this.element.find(this.options.items).andSelf().each(function(){var e=d(this);if(e.data("ui-tooltip-title")){e.attr("title",e.data("ui-tooltip-title"))}})},open:function(f){var e=this,g=d(f?f.target:this.element).closest(this.options.items);if(!g.length||g.data("ui-tooltip-id")){return}if(g.attr("title")){g.data("ui-tooltip-title",g.attr("title"))}g.data("ui-tooltip-open",true);if(f&&f.type==="mouseover"){g.parents().each(function(){var i=d(this),h;if(i.data("ui-tooltip-open")){h=d.Event("blur");h.target=h.currentTarget=this;e.close(h,true)}if(i.attr("title")){i.uniqueId();e.parents[this.id]={element:this,title:i.attr("title")};i.attr("title","")}})}this._updateContent(g,f)},_updateContent:function(j,i){var h,e=this.options.content,g=this,f=i?i.type:null;if(typeof e==="string"){return this._open(i,j,e)}h=e.call(j[0],function(k){if(!j.data("ui-tooltip-open")){return}g._delay(function(){if(i){i.type=f}this._open(i,j,k)})});if(h){this._open(i,j,h)}},_open:function(i,k,h){var j,g,f,l=d.extend({},this.options.position);if(!h){return}j=this._find(k);if(j.length){j.find(".ui-tooltip-content").html(h);return}if(k.is("[title]")){if(i&&i.type==="mouseover"){k.attr("title","")}else{k.removeAttr("title")}}j=this._tooltip(k);c(k,j.attr("id"));j.find(".ui-tooltip-content").html(h);function e(m){l.of=m;if(j.is(":hidden")){return}j.position(l)}if(this.options.track&&i&&/^mouse/.test(i.type)){this._on(this.document,{mousemove:e});e(i)}else{j.position(d.extend({of:k},this.options.position))}j.hide();this._show(j,this.options.show);if(this.options.show&&this.options.show.delay){f=setInterval(function(){if(j.is(":visible")){e(l.of);clearInterval(f)}},d.fx.interval)}this._trigger("open",i,{tooltip:j});g={keyup:function(m){if(m.keyCode===d.ui.keyCode.ESCAPE){var n=d.Event(m);n.currentTarget=k[0];this.close(n,true)}},remove:function(){this._removeTooltip(j)}};if(!i||i.type==="mouseover"){g.mouseleave="close"}if(!i||i.type==="focusin"){g.focusout="close"}this._on(true,k,g)},close:function(f){var e=this,h=d(f?f.currentTarget:this.element),g=this._find(h);if(this.closing){return}if(h.data("ui-tooltip-title")){h.attr("title",h.data("ui-tooltip-title"))}a(h);g.stop(true);this._hide(g,this.options.hide,function(){e._removeTooltip(d(this))});h.removeData("ui-tooltip-open");this._off(h,"mouseleave focusout keyup");if(h[0]!==this.element[0]){this._off(h,"remove")}this._off(this.document,"mousemove");if(f&&f.type==="mouseleave"){d.each(this.parents,function(j,i){d(i.element).attr("title",i.title);delete e.parents[j]})}this.closing=true;this._trigger("close",f,{tooltip:g});this.closing=false},_tooltip:function(e){var g="ui-tooltip-"+b++,f=d("
      ").attr({id:g,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));d("
      ").addClass("ui-tooltip-content").appendTo(f);f.appendTo(this.document[0].body);if(d.fn.bgiframe){f.bgiframe()}this.tooltips[g]=e;return f},_find:function(e){var f=e.data("ui-tooltip-id");return f?d("#"+f):d()},_removeTooltip:function(e){e.remove();delete this.tooltips[e.attr("id")]},_destroy:function(){var e=this;d.each(this.tooltips,function(h,f){var g=d.Event("blur");g.target=g.currentTarget=f[0];e.close(g,true);d("#"+h).remove();if(f.data("ui-tooltip-title")){f.attr("title",f.data("ui-tooltip-title"));f.removeData("ui-tooltip-title")}})}})}(jQuery));(jQuery.effects||(function(b,d){var a=b.uiBackCompat!==false,c="ui-effects-";b.effects={effect:{}}; +/*! + * jQuery Color Animations v2.0.0 + * http://jquery.com/ + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * Date: Mon Aug 13 13:41:02 2012 -0500 + */ +(function(s,h){var o="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor".split(" "),l=/^([\-+])=\s*(\d+\.?\d*)/,k=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1]*2.55,t[2]*2.55,t[3]*2.55,t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],i=s.Color=function(u,v,t,w){return new s.Color.fn.parse(u,v,t,w)},n={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},r={"byte":{floor:true,max:255},percent:{max:1},degrees:{mod:360,floor:true}},q=i.support={},f=s("

      ")[0],e,p=s.each;f.style.cssText="background-color:rgba(1,1,1,.5)";q.rgba=f.style.backgroundColor.indexOf("rgba")>-1;p(n,function(t,u){u.cache="_"+t;u.props.alpha={idx:3,type:"percent",def:1}});function m(u,w,v){var t=r[w.type]||{};if(u==null){return(v||!w.def)?null:w.def}u=t.floor?~~u:parseFloat(u);if(isNaN(u)){return w.def}if(t.mod){return(u+t.mod)%t.mod}return 0>u?0:t.maxF.mod/2){C+=F.mod}else{if(C-B>F.mod/2){C-=F.mod}}}t[D]=m((B-C)*A+C,G)}});return this[w](t)},blend:function(w){if(this._rgba[3]===1){return this}var v=this._rgba.slice(),u=v.pop(),t=i(w)._rgba;return i(s.map(v,function(x,y){return(1-u)*t[y]+u*x}))},toRgbaString:function(){var u="rgba(",t=s.map(this._rgba,function(w,x){return w==null?(x>2?1:0):w});if(t[3]===1){t.pop();u="rgb("}return u+t.join()+")"},toHslaString:function(){var u="hsla(",t=s.map(this.hsla(),function(w,x){if(w==null){w=x>2?1:0}if(x&&x<3){w=Math.round(w*100)+"%"}return w});if(t[3]===1){t.pop();u="hsl("}return u+t.join()+")"},toHexString:function(t){var u=this._rgba.slice(),v=u.pop();if(t){u.push(~~(v*255))}return"#"+s.map(u,function(w){w=(w||0).toString(16);return w.length===1?"0"+w:w}).join("")},toString:function(){return this._rgba[3]===0?"transparent":this.toRgbaString()}});i.fn.parse.prototype=i.fn;function g(v,u,t){t=(t+1)%1;if(t*6<1){return v+(u-v)*t*6}if(t*2<1){return u}if(t*3<2){return v+(u-v)*((2/3)-t)*6}return v}n.hsla.to=function(v){if(v[0]==null||v[1]==null||v[2]==null){return[null,null,null,v[3]]}var t=v[0]/255,y=v[1]/255,z=v[2]/255,B=v[3],A=Math.max(t,y,z),w=Math.min(t,y,z),C=A-w,D=A+w,u=D*0.5,x,E;if(w===A){x=0}else{if(t===A){x=(60*(y-z)/C)+360}else{if(y===A){x=(60*(z-t)/C)+120}else{x=(60*(t-y)/C)+240}}}if(u===0||u===1){E=u}else{if(u<=0.5){E=C/D}else{E=C/(2-D)}}return[Math.round(x)%360,E,u,B==null?1:B]};n.hsla.from=function(x){if(x[0]==null||x[1]==null||x[2]==null){return[null,null,null,x[3]]}var w=x[0]/360,v=x[1],u=x[2],t=x[3],y=u<=0.5?u*(1+v):u+v-u*v,z=2*u-y;return[Math.round(g(z,y,w+(1/3))*255),Math.round(g(z,y,w)*255),Math.round(g(z,y,w-(1/3))*255),t]};p(n,function(u,w){var v=w.props,t=w.cache,y=w.to,x=w.from;i.fn[u]=function(D){if(y&&!this[t]){this[t]=y(this._rgba)}if(D===h){return this[t].slice()}var A,C=s.type(D),z=(C==="array"||C==="object")?D:arguments,B=this[t].slice();p(v,function(E,G){var F=z[C==="object"?E:G.idx];if(F==null){F=B[G.idx]}B[G.idx]=m(F,G)});if(x){A=i(x(B));A[t]=B;return A}else{return i(B)}};p(v,function(z,A){if(i.fn[z]){return}i.fn[z]=function(E){var G=s.type(E),D=(z==="alpha"?(this._hsla?"hsla":"rgba"):u),C=this[D](),F=C[A.idx],B;if(G==="undefined"){return F}if(G==="function"){E=E.call(this,F);G=s.type(E)}if(E==null&&A.empty){return this}if(G==="string"){B=l.exec(E);if(B){E=F+parseFloat(B[2])*(B[1]==="+"?1:-1)}}C[A.idx]=E;return this[D](C)}})});p(o,function(t,u){s.cssHooks[u]={set:function(z,A){var w,y,v="";if(s.type(A)!=="string"||(w=j(A))){A=i(w||A);if(!q.rgba&&A._rgba[3]!==1){y=u==="backgroundColor"?z.parentNode:z;while((v===""||v==="transparent")&&y&&y.style){try{v=s.css(y,"backgroundColor");y=y.parentNode}catch(B){}}A=A.blend(v&&v!=="transparent"?v:"_default")}A=A.toRgbaString()}try{z.style[u]=A}catch(x){}}};s.fx.step[u]=function(v){if(!v.colorInit){v.start=i(v.elem,u);v.end=i(v.end);v.colorInit=true}s.cssHooks[u].set(v.elem,v.start.transition(v.end,v.pos))}});s.cssHooks.borderColor={expand:function(u){var t={};p(["Top","Right","Bottom","Left"],function(w,v){t["border"+v+"Color"]=u});return t}};e=s.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}})(jQuery);(function(){var f=["add","remove","toggle"],g={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};b.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(i,j){b.fx.step[j]=function(k){if(k.end!=="none"&&!k.setAttr||k.pos===1&&!k.setAttr){jQuery.style(k.elem,j,k.end);k.setAttr=true}}});function h(){var k=this.ownerDocument.defaultView?this.ownerDocument.defaultView.getComputedStyle(this,null):this.currentStyle,l={},j,i;if(k&&k.length&&k[0]&&k[k[0]]){i=k.length;while(i--){j=k[i];if(typeof k[j]==="string"){l[b.camelCase(j)]=k[j]}}}else{for(j in k){if(typeof k[j]==="string"){l[j]=k[j]}}}return l}function e(i,k){var m={},j,l;for(j in k){l=k[j];if(i[j]!==l){if(!g[j]){if(b.fx.step[j]||!isNaN(parseFloat(l))){m[j]=l}}}}return m}b.effects.animateClass=function(i,j,m,l){var k=b.speed(j,m,l);return this.queue(function(){var p=b(this),n=p.attr("class")||"",o,q=k.children?p.find("*").andSelf():p;q=q.map(function(){var r=b(this);return{el:r,start:h.call(this)}});o=function(){b.each(f,function(r,s){if(i[s]){p[s+"Class"](i[s])}})};o();q=q.map(function(){this.end=h.call(this.el[0]);this.diff=e(this.start,this.end);return this});p.attr("class",n);q=q.map(function(){var t=this,r=b.Deferred(),s=jQuery.extend({},k,{queue:false,complete:function(){r.resolve(t)}});this.el.animate(this.diff,s);return r.promise()});b.when.apply(b,q.get()).done(function(){o();b.each(arguments,function(){var r=this.el;b.each(this.diff,function(s){r.css(s,"")})});k.complete.call(p[0])})})};b.fn.extend({_addClass:b.fn.addClass,addClass:function(j,i,l,k){return i?b.effects.animateClass.call(this,{add:j},i,l,k):this._addClass(j)},_removeClass:b.fn.removeClass,removeClass:function(j,i,l,k){return i?b.effects.animateClass.call(this,{remove:j},i,l,k):this._removeClass(j)},_toggleClass:b.fn.toggleClass,toggleClass:function(k,j,i,m,l){if(typeof j==="boolean"||j===d){if(!i){return this._toggleClass(k,j)}else{return b.effects.animateClass.call(this,(j?{add:k}:{remove:k}),i,m,l)}}else{return b.effects.animateClass.call(this,{toggle:k},j,i,m)}},switchClass:function(i,k,j,m,l){return b.effects.animateClass.call(this,{add:k,remove:i},j,m,l)}})})();(function(){b.extend(b.effects,{version:"1.9.2",save:function(h,j){for(var g=0;g

      ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),g={width:h.width(),height:h.height()},k=document.activeElement;try{k.id}catch(j){k=document.body}h.wrap(l);if(h[0]===k||b.contains(h[0],k)){b(k).focus()}l=h.parent();if(h.css("position")==="static"){l.css({position:"relative"});h.css({position:"relative"})}else{b.extend(i,{position:h.css("position"),zIndex:h.css("z-index")});b.each(["top","left","bottom","right"],function(m,n){i[n]=h.css(n);if(isNaN(parseInt(i[n],10))){i[n]="auto"}});h.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}h.css(g);return l.css(i).show()},removeWrapper:function(g){var h=document.activeElement;if(g.parent().is(".ui-effects-wrapper")){g.parent().replaceWith(g);if(g[0]===h||b.contains(g[0],h)){b(h).focus()}}return g},setTransition:function(h,j,g,i){i=i||{};b.each(j,function(l,k){var m=h.cssUnit(k);if(m[0]>0){i[k]=m[0]*g+m[1]}});return i}});function e(h,g,i,j){if(b.isPlainObject(h)){g=h;h=h.effect}h={effect:h};if(g==null){g={}}if(b.isFunction(g)){j=g;i=null;g={}}if(typeof g==="number"||b.fx.speeds[g]){j=i;i=g;g={}}if(b.isFunction(i)){j=i;i=null}if(g){b.extend(h,g)}i=i||g.duration;h.duration=b.fx.off?0:typeof i==="number"?i:i in b.fx.speeds?b.fx.speeds[i]:b.fx.speeds._default;h.complete=j||g.complete;return h}function f(g){if(!g||typeof g==="number"||b.fx.speeds[g]){return true}if(typeof g==="string"&&!b.effects.effect[g]){if(a&&b.effects[g]){return false}return true}return false}b.fn.extend({effect:function(){var i=e.apply(this,arguments),l=i.mode,g=i.queue,h=b.effects.effect[i.effect],j=!h&&a&&b.effects[i.effect];if(b.fx.off||!(h||j)){if(l){return this[l](i.duration,i.complete)}else{return this.each(function(){if(i.complete){i.complete.call(this)}})}}function k(o){var p=b(this),n=i.complete,q=i.mode;function m(){if(b.isFunction(n)){n.call(p[0])}if(b.isFunction(o)){o()}}if(p.is(":hidden")?q==="hide":q==="show"){m()}else{h.call(p[0],i,m)}}if(h){return g===false?this.each(k):this.queue(g||"fx",k)}else{return j.call(this,{options:i,duration:i.duration,callback:i.complete,mode:i.mode})}},_show:b.fn.show,show:function(h){if(f(h)){return this._show.apply(this,arguments)}else{var g=e.apply(this,arguments);g.mode="show";return this.effect.call(this,g)}},_hide:b.fn.hide,hide:function(h){if(f(h)){return this._hide.apply(this,arguments)}else{var g=e.apply(this,arguments);g.mode="hide";return this.effect.call(this,g)}},__toggle:b.fn.toggle,toggle:function(h){if(f(h)||typeof h==="boolean"||b.isFunction(h)){return this.__toggle.apply(this,arguments)}else{var g=e.apply(this,arguments);g.mode="toggle";return this.effect.call(this,g)}},cssUnit:function(g){var h=this.css(g),i=[];b.each(["em","px","%","pt"],function(j,k){if(h.indexOf(k)>0){i=[parseFloat(h),k]}});return i}})})();(function(){var e={};b.each(["Quad","Cubic","Quart","Quint","Expo"],function(g,f){e[f]=function(h){return Math.pow(h,g+2)}});b.extend(e,{Sine:function(f){return 1-Math.cos(f*Math.PI/2)},Circ:function(f){return 1-Math.sqrt(1-f*f)},Elastic:function(f){return f===0||f===1?f:-Math.pow(2,8*(f-1))*Math.sin(((f-1)*80-7.5)*Math.PI/15)},Back:function(f){return f*f*(3*f-2)},Bounce:function(h){var f,g=4;while(h<((f=Math.pow(2,--g))-1)/11){}return 1/Math.pow(4,3-g)-7.5625*Math.pow((f*3-2)/22-h,2)}});b.each(e,function(g,f){b.easing["easeIn"+g]=f;b.easing["easeOut"+g]=function(h){return 1-f(1-h)};b.easing["easeInOut"+g]=function(h){return h<0.5?f(h*2)/2:1-f(h*-2+2)/2}})})()})(jQuery));(function(b,d){var a=/up|down|vertical/,c=/up|left|vertical|horizontal/;b.effects.effect.blind=function(g,m){var h=b(this),q=["position","top","bottom","left","right","height","width"],n=b.effects.setMode(h,g.mode||"hide"),r=g.direction||"up",j=a.test(r),i=j?"height":"width",p=j?"top":"left",t=c.test(r),l={},s=n==="show",f,e,k;if(h.parent().is(".ui-effects-wrapper")){b.effects.save(h.parent(),q)}else{b.effects.save(h,q)}h.show();f=b.effects.createWrapper(h).css({overflow:"hidden"});e=f[i]();k=parseFloat(f.css(p))||0;l[i]=s?e:0;if(!t){h.css(j?"bottom":"right",0).css(j?"top":"left","auto").css({position:"absolute"});l[p]=s?k:e+k}if(s){f.css(i,0);if(!t){f.css(p,k+e)}}f.animate(l,{duration:g.duration,easing:g.easing,queue:false,complete:function(){if(n==="hide"){h.hide()}b.effects.restore(h,q);b.effects.removeWrapper(h);m()}})}})(jQuery);(function(a,b){a.effects.effect.bounce=function(m,l){var c=a(this),d=["position","top","bottom","left","right","height","width"],k=a.effects.setMode(c,m.mode||"effect"),j=k==="hide",v=k==="show",w=m.direction||"up",e=m.distance,h=m.times||5,x=h*2+(v||j?1:0),u=m.duration/x,p=m.easing,f=(w==="up"||w==="down")?"top":"left",n=(w==="up"||w==="left"),t,g,s,q=c.queue(),r=q.length;if(v||j){d.push("opacity")}a.effects.save(c,d);c.show();a.effects.createWrapper(c);if(!e){e=c[f==="top"?"outerHeight":"outerWidth"]()/3}if(v){s={opacity:1};s[f]=0;c.css("opacity",0).css(f,n?-e*2:e*2).animate(s,u,p)}if(j){e=e/Math.pow(2,h-1)}s={};s[f]=0;for(t=0;t1){q.splice.apply(q,[1,0].concat(q.splice(r,x+1)))}c.dequeue()}})(jQuery);(function(a,b){a.effects.effect.clip=function(f,i){var g=a(this),m=["position","top","bottom","left","right","height","width"],l=a.effects.setMode(g,f.mode||"hide"),p=l==="show",n=f.direction||"vertical",k=n==="vertical",q=k?"height":"width",j=k?"top":"left",h={},d,e,c;a.effects.save(g,m);g.show();d=a.effects.createWrapper(g).css({overflow:"hidden"});e=(g[0].tagName==="IMG")?d:g;c=e[q]();if(p){e.css(q,0);e.css(j,c/2)}h[q]=p?c:0;h[j]=p?0:c/2;e.animate(h,{queue:false,duration:f.duration,easing:f.easing,complete:function(){if(!p){g.hide()}a.effects.restore(g,m);a.effects.removeWrapper(g);i()}})}})(jQuery);(function(a,b){a.effects.effect.drop=function(d,h){var e=a(this),j=["position","top","bottom","left","right","opacity","height","width"],i=a.effects.setMode(e,d.mode||"hide"),l=i==="show",k=d.direction||"left",f=(k==="up"||k==="down")?"top":"left",m=(k==="up"||k==="left")?"pos":"neg",g={opacity:l?1:0},c;a.effects.save(e,j);e.show();a.effects.createWrapper(e);c=d.distance||e[f==="top"?"outerHeight":"outerWidth"](true)/2;if(l){e.css("opacity",0).css(f,m==="pos"?-c:c)}g[f]=(l?(m==="pos"?"+=":"-="):(m==="pos"?"-=":"+="))+c;e.animate(g,{queue:false,duration:d.duration,easing:d.easing,complete:function(){if(i==="hide"){e.hide()}a.effects.restore(e,j);a.effects.removeWrapper(e);h()}})}})(jQuery);(function(a,b){a.effects.effect.explode=function(s,r){var k=s.pieces?Math.round(Math.sqrt(s.pieces)):3,d=k,c=a(this),m=a.effects.setMode(c,s.mode||"hide"),w=m==="show",g=c.show().css("visibility","hidden").offset(),t=Math.ceil(c.outerWidth()/d),q=Math.ceil(c.outerHeight()/k),h=[],v,u,e,p,n,l;function x(){h.push(this);if(h.length===k*d){f()}}for(v=0;v
      ").css({position:"absolute",visibility:"visible",left:-u*t,top:-v*q}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:t,height:q,left:e+(w?n*t:0),top:p+(w?l*q:0),opacity:w?0:1}).animate({left:e+(w?0:n*t),top:p+(w?0:l*q),opacity:w?1:0},s.duration||500,s.easing,x)}}function f(){c.css({visibility:"visible"});a(h).remove();if(!w){c.hide()}r()}}})(jQuery);(function(a,b){a.effects.effect.fade=function(f,c){var d=a(this),e=a.effects.setMode(d,f.mode||"toggle");d.animate({opacity:e},{queue:false,duration:f.duration,easing:f.easing,complete:c})}})(jQuery);(function(a,b){a.effects.effect.fold=function(e,i){var f=a(this),n=["position","top","bottom","left","right","height","width"],k=a.effects.setMode(f,e.mode||"hide"),r=k==="show",l=k==="hide",t=e.size||15,m=/([0-9]+)%/.exec(t),s=!!e.horizFirst,j=r!==s,g=j?["width","height"]:["height","width"],h=e.duration/2,d,c,q={},p={};a.effects.save(f,n);f.show();d=a.effects.createWrapper(f).css({overflow:"hidden"});c=j?[d.width(),d.height()]:[d.height(),d.width()];if(m){t=parseInt(m[1],10)/100*c[l?0:1]}if(r){d.css(s?{height:0,width:t}:{height:t,width:0})}q[g[0]]=r?c[0]:t;p[g[1]]=r?c[1]:0;d.animate(q,h,e.easing).animate(p,h,e.easing,function(){if(l){f.hide()}a.effects.restore(f,n);a.effects.removeWrapper(f);i()})}})(jQuery);(function(a,b){a.effects.effect.highlight=function(h,c){var e=a(this),d=["backgroundImage","backgroundColor","opacity"],g=a.effects.setMode(e,h.mode||"show"),f={backgroundColor:e.css("backgroundColor")};if(g==="hide"){f.opacity=0}a.effects.save(e,d);e.show().css({backgroundImage:"none",backgroundColor:h.color||"#ffff99"}).animate(f,{queue:false,duration:h.duration,easing:h.easing,complete:function(){if(g==="hide"){e.hide()}a.effects.restore(e,d);c()}})}})(jQuery);(function(a,b){a.effects.effect.pulsate=function(c,g){var e=a(this),k=a.effects.setMode(e,c.mode||"show"),p=k==="show",l=k==="hide",q=(p||k==="hide"),m=((c.times||5)*2)+(q?1:0),f=c.duration/m,n=0,j=e.queue(),d=j.length,h;if(p||!e.is(":visible")){e.css("opacity",0).show();n=1}for(h=1;h1){j.splice.apply(j,[1,0].concat(j.splice(d,m+1)))}e.dequeue()}})(jQuery);(function(a,b){a.effects.effect.puff=function(j,c){var h=a(this),i=a.effects.setMode(h,j.mode||"hide"),f=i==="hide",g=parseInt(j.percent,10)||150,e=g/100,d={height:h.height(),width:h.width(),outerHeight:h.outerHeight(),outerWidth:h.outerWidth()};a.extend(j,{effect:"scale",queue:false,fade:true,mode:i,complete:c,percent:f?g:100,from:f?d:{height:d.height*e,width:d.width*e,outerHeight:d.outerHeight*e,outerWidth:d.outerWidth*e}});h.effect(j)};a.effects.effect.scale=function(c,f){var d=a(this),l=a.extend(true,{},c),g=a.effects.setMode(d,c.mode||"effect"),h=parseInt(c.percent,10)||(parseInt(c.percent,10)===0?0:(g==="hide"?0:100)),j=c.direction||"both",k=c.origin,e={height:d.height(),width:d.width(),outerHeight:d.outerHeight(),outerWidth:d.outerWidth()},i={y:j!=="horizontal"?(h/100):1,x:j!=="vertical"?(h/100):1};l.effect="size";l.queue=false;l.complete=f;if(g!=="effect"){l.origin=k||["middle","center"];l.restore=true}l.from=c.from||(g==="show"?{height:0,width:0,outerHeight:0,outerWidth:0}:e);l.to={height:e.height*i.y,width:e.width*i.x,outerHeight:e.outerHeight*i.y,outerWidth:e.outerWidth*i.x};if(l.fade){if(g==="show"){l.from.opacity=0;l.to.opacity=1}if(g==="hide"){l.from.opacity=1;l.to.opacity=0}}d.effect(l)};a.effects.effect.size=function(l,k){var q,i,j,c=a(this),p=["position","top","bottom","left","right","width","height","overflow","opacity"],n=["position","top","bottom","left","right","overflow","opacity"],m=["width","height","overflow"],g=["fontSize"],s=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],d=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],h=a.effects.setMode(c,l.mode||"effect"),r=l.restore||h!=="effect",v=l.scale||"both",t=l.origin||["middle","center"],u=c.css("position"),e=r?p:n,f={height:0,width:0,outerHeight:0,outerWidth:0};if(h==="show"){c.show()}q={height:c.height(),width:c.width(),outerHeight:c.outerHeight(),outerWidth:c.outerWidth()};if(l.mode==="toggle"&&h==="show"){c.from=l.to||f;c.to=l.from||q}else{c.from=l.from||(h==="show"?f:q);c.to=l.to||(h==="hide"?f:q)}j={from:{y:c.from.height/q.height,x:c.from.width/q.width},to:{y:c.to.height/q.height,x:c.to.width/q.width}};if(v==="box"||v==="both"){if(j.from.y!==j.to.y){e=e.concat(s);c.from=a.effects.setTransition(c,s,j.from.y,c.from);c.to=a.effects.setTransition(c,s,j.to.y,c.to)}if(j.from.x!==j.to.x){e=e.concat(d);c.from=a.effects.setTransition(c,d,j.from.x,c.from);c.to=a.effects.setTransition(c,d,j.to.x,c.to)}}if(v==="content"||v==="both"){if(j.from.y!==j.to.y){e=e.concat(g).concat(m);c.from=a.effects.setTransition(c,g,j.from.y,c.from);c.to=a.effects.setTransition(c,g,j.to.y,c.to)}}a.effects.save(c,e);c.show();a.effects.createWrapper(c);c.css("overflow","hidden").css(c.from);if(t){i=a.effects.getBaseline(t,q);c.from.top=(q.outerHeight-c.outerHeight())*i.y;c.from.left=(q.outerWidth-c.outerWidth())*i.x;c.to.top=(q.outerHeight-c.to.outerHeight)*i.y;c.to.left=(q.outerWidth-c.to.outerWidth)*i.x}c.css(c.from);if(v==="content"||v==="both"){s=s.concat(["marginTop","marginBottom"]).concat(g);d=d.concat(["marginLeft","marginRight"]);m=p.concat(s).concat(d);c.find("*[width]").each(function(){var w=a(this),o={height:w.height(),width:w.width(),outerHeight:w.outerHeight(),outerWidth:w.outerWidth()};if(r){a.effects.save(w,m)}w.from={height:o.height*j.from.y,width:o.width*j.from.x,outerHeight:o.outerHeight*j.from.y,outerWidth:o.outerWidth*j.from.x};w.to={height:o.height*j.to.y,width:o.width*j.to.x,outerHeight:o.height*j.to.y,outerWidth:o.width*j.to.x};if(j.from.y!==j.to.y){w.from=a.effects.setTransition(w,s,j.from.y,w.from);w.to=a.effects.setTransition(w,s,j.to.y,w.to)}if(j.from.x!==j.to.x){w.from=a.effects.setTransition(w,d,j.from.x,w.from);w.to=a.effects.setTransition(w,d,j.to.x,w.to)}w.css(w.from);w.animate(w.to,l.duration,l.easing,function(){if(r){a.effects.restore(w,m)}})})}c.animate(c.to,{queue:false,duration:l.duration,easing:l.easing,complete:function(){if(c.to.opacity===0){c.css("opacity",c.from.opacity)}if(h==="hide"){c.hide()}a.effects.restore(c,e);if(!r){if(u==="static"){c.css({position:"relative",top:c.to.top,left:c.to.left})}else{a.each(["top","left"],function(o,w){c.css(w,function(y,A){var z=parseInt(A,10),x=o?c.to.left:c.to.top;if(A==="auto"){return x+"px"}return z+x+"px"})})}}a.effects.removeWrapper(c);k()}})}})(jQuery);(function(a,b){a.effects.effect.shake=function(l,k){var c=a(this),d=["position","top","bottom","left","right","height","width"],j=a.effects.setMode(c,l.mode||"effect"),u=l.direction||"left",e=l.distance||20,h=l.times||3,v=h*2+1,q=Math.round(l.duration/v),g=(u==="up"||u==="down")?"top":"left",f=(u==="up"||u==="left"),t={},s={},r={},p,m=c.queue(),n=m.length;a.effects.save(c,d);c.show();a.effects.createWrapper(c);t[g]=(f?"-=":"+=")+e;s[g]=(f?"+=":"-=")+e*2;r[g]=(f?"-=":"+=")+e*2;c.animate(t,q,l.easing);for(p=1;p1){m.splice.apply(m,[1,0].concat(m.splice(n,v+1)))}c.dequeue()}})(jQuery);(function(a,b){a.effects.effect.slide=function(e,i){var f=a(this),k=["position","top","bottom","left","right","width","height"],j=a.effects.setMode(f,e.mode||"show"),m=j==="show",l=e.direction||"left",g=(l==="up"||l==="down")?"top":"left",d=(l==="up"||l==="left"),c,h={};a.effects.save(f,k);f.show();c=e.distance||f[g==="top"?"outerHeight":"outerWidth"](true);a.effects.createWrapper(f).css({overflow:"hidden"});if(m){f.css(g,d?(isNaN(c)?"-"+c:-c):c)}h[g]=(m?(d?"+=":"-="):(d?"-=":"+="))+c;f.animate(h,{queue:false,duration:e.duration,easing:e.easing,complete:function(){if(j==="hide"){f.hide()}a.effects.restore(f,k);a.effects.removeWrapper(f);i()}})}})(jQuery);(function(a,b){a.effects.effect.transfer=function(d,h){var f=a(this),k=a(d.to),n=k.css("position")==="fixed",j=a("body"),l=n?j.scrollTop():0,m=n?j.scrollLeft():0,c=k.offset(),g={top:c.top-l,left:c.left-m,height:k.innerHeight(),width:k.innerWidth()},i=f.offset(),e=a('
      ').appendTo(document.body).addClass(d.className).css({top:i.top-l,left:i.left-m,height:f.innerHeight(),width:f.innerWidth(),position:n?"fixed":"absolute"}).animate(g,d.duration,d.easing,function(){e.remove();h()})}})(jQuery); \ No newline at end of file diff --git a/phpmyadmin/js/jquery/jquery-ui-timepicker-addon.js b/phpmyadmin/js/jquery/jquery-ui-timepicker-addon.js new file mode 100644 index 000000000..55f9dc859 --- /dev/null +++ b/phpmyadmin/js/jquery/jquery-ui-timepicker-addon.js @@ -0,0 +1 @@ +(function($){$.ui.timepicker=$.ui.timepicker||{};if($.ui.timepicker.version){return}$.extend($.ui,{timepicker:{version:"1.1.1"}});function Timepicker(){this.regional=[];this.regional[""]={currentText:"Now",closeText:"Done",amNames:["AM","A"],pmNames:["PM","P"],timeFormat:"HH:mm",timeSuffix:"",timeOnlyTitle:"Choose Time",timeText:"Time",hourText:"Hour",minuteText:"Minute",secondText:"Second",millisecText:"Millisecond",timezoneText:"Time Zone",isRTL:false};this._defaults={showButtonPanel:true,timeOnly:false,showHour:true,showMinute:true,showSecond:false,showMillisec:false,showTimezone:false,showTime:true,stepHour:1,stepMinute:1,stepSecond:1,stepMillisec:1,hour:0,minute:0,second:0,millisec:0,timezone:null,useLocalTimezone:false,defaultTimezone:"+0000",hourMin:0,minuteMin:0,secondMin:0,millisecMin:0,hourMax:23,minuteMax:59,secondMax:59,millisecMax:999,minDateTime:null,maxDateTime:null,onSelect:null,hourGrid:0,minuteGrid:0,secondGrid:0,millisecGrid:0,alwaysSetTime:true,separator:" ",altFieldTimeOnly:true,altTimeFormat:null,altSeparator:null,altTimeSuffix:null,pickerTimeFormat:null,pickerTimeSuffix:null,showTimepicker:true,timezoneIso8601:false,timezoneList:null,addSliderAccess:false,sliderAccessArgs:null,controlType:"slider",defaultValue:null,parse:"strict"};$.extend(this._defaults,this.regional[""])}$.extend(Timepicker.prototype,{$input:null,$altInput:null,$timeObj:null,inst:null,hour_slider:null,minute_slider:null,second_slider:null,millisec_slider:null,timezone_select:null,hour:0,minute:0,second:0,millisec:0,timezone:null,defaultTimezone:"+0000",hourMinOriginal:null,minuteMinOriginal:null,secondMinOriginal:null,millisecMinOriginal:null,hourMaxOriginal:null,minuteMaxOriginal:null,secondMaxOriginal:null,millisecMaxOriginal:null,ampm:"",formattedDate:"",formattedTime:"",formattedDateTime:"",timezoneList:null,units:["hour","minute","second","millisec"],control:null,setDefaults:function(settings){extendRemove(this._defaults,settings||{});return this},_newInst:function($input,o){var tp_inst=new Timepicker(),inlineSettings={},fns={},overrides,i;for(var attrName in this._defaults){if(this._defaults.hasOwnProperty(attrName)){var attrValue=$input.attr("time:"+attrName);if(attrValue){try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}}overrides={beforeShow:function(input,dp_inst){if($.isFunction(tp_inst._defaults.evnts.beforeShow)){return tp_inst._defaults.evnts.beforeShow.call($input[0],input,dp_inst,tp_inst)}},onChangeMonthYear:function(year,month,dp_inst){tp_inst._updateDateTime(dp_inst);if($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)){tp_inst._defaults.evnts.onChangeMonthYear.call($input[0],year,month,dp_inst,tp_inst)}},onClose:function(dateText,dp_inst){if(tp_inst.timeDefined===true&&$input.val()!==""){tp_inst._updateDateTime(dp_inst)}if($.isFunction(tp_inst._defaults.evnts.onClose)){tp_inst._defaults.evnts.onClose.call($input[0],dateText,dp_inst,tp_inst)}}};for(i in overrides){if(overrides.hasOwnProperty(i)){fns[i]=o[i]||null}}tp_inst._defaults=$.extend({},this._defaults,inlineSettings,o,overrides,{evnts:fns,timepicker:tp_inst});tp_inst.amNames=$.map(tp_inst._defaults.amNames,function(val){return val.toUpperCase()});tp_inst.pmNames=$.map(tp_inst._defaults.pmNames,function(val){return val.toUpperCase()});if(typeof(tp_inst._defaults.controlType)==="string"){if($.fn[tp_inst._defaults.controlType]===undefined){tp_inst._defaults.controlType="select"}tp_inst.control=tp_inst._controls[tp_inst._defaults.controlType]}else{tp_inst.control=tp_inst._defaults.controlType}if(tp_inst._defaults.timezoneList===null){var timezoneList=["-1200","-1100","-1000","-0930","-0900","-0800","-0700","-0600","-0500","-0430","-0400","-0330","-0300","-0200","-0100","+0000","+0100","+0200","+0300","+0330","+0400","+0430","+0500","+0530","+0545","+0600","+0630","+0700","+0800","+0845","+0900","+0930","+1000","+1030","+1100","+1130","+1200","+1245","+1300","+1400"];if(tp_inst._defaults.timezoneIso8601){timezoneList=$.map(timezoneList,function(val){return val=="+0000"?"Z":(val.substring(0,3)+":"+val.substring(3))})}tp_inst._defaults.timezoneList=timezoneList}tp_inst.timezone=tp_inst._defaults.timezone;tp_inst.hour=tp_inst._defaults.hour;tp_inst.minute=tp_inst._defaults.minute;tp_inst.second=tp_inst._defaults.second;tp_inst.millisec=tp_inst._defaults.millisec;tp_inst.ampm="";tp_inst.$input=$input;if(o.altField){tp_inst.$altInput=$(o.altField).css({cursor:"pointer"}).focus(function(){$input.trigger("focus")})}if(tp_inst._defaults.minDate===0||tp_inst._defaults.minDateTime===0){tp_inst._defaults.minDate=new Date()}if(tp_inst._defaults.maxDate===0||tp_inst._defaults.maxDateTime===0){tp_inst._defaults.maxDate=new Date()}if(tp_inst._defaults.minDate!==undefined&&tp_inst._defaults.minDate instanceof Date){tp_inst._defaults.minDateTime=new Date(tp_inst._defaults.minDate.getTime())}if(tp_inst._defaults.minDateTime!==undefined&&tp_inst._defaults.minDateTime instanceof Date){tp_inst._defaults.minDate=new Date(tp_inst._defaults.minDateTime.getTime())}if(tp_inst._defaults.maxDate!==undefined&&tp_inst._defaults.maxDate instanceof Date){tp_inst._defaults.maxDateTime=new Date(tp_inst._defaults.maxDate.getTime())}if(tp_inst._defaults.maxDateTime!==undefined&&tp_inst._defaults.maxDateTime instanceof Date){tp_inst._defaults.maxDate=new Date(tp_inst._defaults.maxDateTime.getTime())}tp_inst.$input.bind("focus",function(){tp_inst._onFocus()});return tp_inst},_addTimePicker:function(dp_inst){var currDT=(this.$altInput&&this._defaults.altFieldTimeOnly)?this.$input.val()+" "+this.$altInput.val():this.$input.val();this.timeDefined=this._parseTime(currDT);this._limitMinMaxDateTime(dp_inst,false);this._injectTimePicker()},_parseTime:function(timeString,withDate){if(!this.inst){this.inst=$.datepicker._getInst(this.$input[0])}if(withDate||!this._defaults.timeOnly){var dp_dateFormat=$.datepicker._get(this.inst,"dateFormat");try{var parseRes=parseDateTimeInternal(dp_dateFormat,this._defaults.timeFormat,timeString,$.datepicker._getFormatConfig(this.inst),this._defaults);if(!parseRes.timeObj){return false}$.extend(this,parseRes.timeObj)}catch(err){$.datepicker.log("Error parsing the date/time string: "+err+"\ndate/time string = "+timeString+"\ntimeFormat = "+this._defaults.timeFormat+"\ndateFormat = "+dp_dateFormat);return false}return true}else{var timeObj=$.datepicker.parseTime(this._defaults.timeFormat,timeString,this._defaults);if(!timeObj){return false}$.extend(this,timeObj);return true}},_injectTimePicker:function(){var $dp=this.inst.dpDiv,o=this.inst.settings,tp_inst=this,litem="",uitem="",max={},gridSize={},size=null;if($dp.find("div.ui-timepicker-div").length===0&&o.showTimepicker){var noDisplay=' style="display:none;"',html='
      "+o.timeText+'
      ";for(var i=0,l=this.units.length;i"+o[litem+"Text"]+'
      ";if(o["show"+uitem]&&o[litem+"Grid"]>0){html+='
      ';if(litem=="hour"){for(var h=o[litem+"Min"];h<=max[litem];h+=parseInt(o[litem+"Grid"],10)){gridSize[litem]++;var tmph=$.datepicker.formatTime(useAmpm(o.pickerTimeFormat||o.timeFormat)?"hht":"HH",{hour:h},o);html+='"}}else{for(var m=o[litem+"Min"];m<=max[litem];m+=parseInt(o[litem+"Grid"],10)){gridSize[litem]++;html+='"}}html+="
      '+tmph+"'+((m<10)?"0":"")+m+"
      "}html+="
      "}html+='
      "+o.timezoneText+"
      ";html+='
      ";html+="
      ";var $tp=$(html);if(o.timeOnly===true){$tp.prepend('
      '+o.timeOnlyTitle+"
      ");$dp.find(".ui-datepicker-header, .ui-datepicker-calendar").hide()}for(var i=0,l=tp_inst.units.length;i0){size=100*gridSize[litem]*o[litem+"Grid"]/(max[litem]-o[litem+"Min"]);$tp.find(".ui_tpicker_"+litem+" table").css({width:size+"%",marginLeft:o.isRTL?"0":((size/(-2*gridSize[litem]))+"%"),marginRight:o.isRTL?((size/(-2*gridSize[litem]))+"%"):"0",borderCollapse:"collapse"}).find("td").click(function(e){var $t=$(this),h=$t.html(),n=parseInt(h.replace(/[^0-9]/g),10),ap=h.replace(/[^apm]/ig),f=$t.data("for");if(f=="hour"){if(ap.indexOf("p")!==-1&&n<12){n+=12}else{if(ap.indexOf("a")!==-1&&n===12){n=0}}}tp_inst.control.value(tp_inst,tp_inst[f+"_slider"],litem,n);tp_inst._onTimeChange();tp_inst._onSelectHandler()}).css({cursor:"pointer",width:(100/gridSize[litem])+"%",textAlign:"center",overflow:"hidden"})}}this.timezone_select=$tp.find(".ui_tpicker_timezone").append("").find("select");$.fn.append.apply(this.timezone_select,$.map(o.timezoneList,function(val,idx){return $("
      ").css("padding","0.5em");for(var N in R.chart.series){S.append($("
      ").append($("
      ").css({width:"1em",height:"1em",background:R.chart.seriesColors[N]}).addClass("floatleft")).append($("
      ").text(R.chart.series[N].label).addClass("floatleft")).append($('
      ')).addClass("floatleft"))}$("#gridchart"+runtime.chartAI).css("overflow","hidden").parent().append(S);if(M!=true){runtime.charts["c"+runtime.chartAI]=R;z()}$("#gridchart"+runtime.chartAI).bind("jqplotMouseDown",function(U,T,X,W,V){i=true;G.push(X.xaxis);if($("#selection_box").length){$("#selection_box").remove()}selectionBox=$('
      ');$(document.body).append(selectionBox);d=U.pageX;c=U.pageY;selectionBox.attr({id:"selection_box"}).css({top:c-T.y,left:d}).fadeIn()});$("#gridchart"+runtime.chartAI).bind("jqplotMouseUp",function(W,U,Z,Y,X){if(!i||t){return}G.push(Z.xaxis);if(G[1]<=G[0]){G=[];return}var V=new Date(Math.ceil(G[0]));var T=new Date(Math.ceil(G[1]));x(V,T);G=[];i=false});$("#gridchart"+runtime.chartAI).bind("jqplotMouseMove",function(U,T,X,W,V){if(!i||t){return}if(d!=undefined){$("#selection_box").css({width:Math.ceil(U.pageX-d)}).fadeIn()}});$("#gridchart"+runtime.chartAI).bind("jqplotMouseLeave",function(U,T,X,W,V){i=false});$(document.body).mouseup(function(){if($("#selection_box").length){selectionBox.remove()}});$("#chartGrid div svg").find("*[zIndex=20], *[zIndex=21], *[zIndex=19]").toggle(t);runtime.chartAI++}function w(P){var R=P.options.chart.renderTo;if(!R){return}var O=null;var M=null;$.each(runtime.charts,function(S,T){if(T.chart.options.chart.renderTo==R){O=T;M=S;return false}});if(O==null){return}var Q="

      "+PMA_messages.strChartTitle+':
      ';Q+="

      "+PMA_messages.strSeries+":

        ";for(var N=0;N"+O.nodes[N].dataPoints[0].name+':
        '}dlgBtns={};dlgBtns[PMA_messages.strSave]=function(){runtime.charts[M].title=$('#emptyDialog input[name="chartTitle"]').val();runtime.charts[M].chart.setTitle({text:runtime.charts[M].title});$('#emptyDialog input[name*="chartSerie"]').each(function(){var T=$(this);var S=T.attr("name").split("-")[1];runtime.charts[M].nodes[S].name=T.val();runtime.charts[M].chart.series[S].name=T.val()});$(this).dialog("close");e()};dlgBtns[PMA_messages.strCancel]=function(){$(this).dialog("close")};$("#emptyDialog").html(Q+"
      ");$("#emptyDialog").dialog({title:PMA_messages.strChartEdit,width:"auto",height:"auto",buttons:dlgBtns})}function x(N,M){$('#logAnalyseDialog input[name="dateStart"]').val(formatDate(N,"yyyy-MM-dd HH:mm:ss"));$('#logAnalyseDialog input[name="dateEnd"]').val(formatDate(M,"yyyy-MM-dd HH:mm:ss"));var O={};O[PMA_messages.strFromSlowLog]=function(){H("slow",N,M);$(this).dialog("close")};O[PMA_messages.strFromGeneralLog]=function(){H("general",N,M);$(this).dialog("close")};$("#logAnalyseDialog").dialog({width:"auto",height:"auto",buttons:O})}function H(P,N,M){var Q=Date.parse($('#logAnalyseDialog input[name="dateStart"]').prop("value"))||N;var O=Date.parse($('#logAnalyseDialog input[name="dateEnd"]').prop("value"))||M;m({src:P,start:Q,end:O,removeVariables:$("#removeVariables").prop("checked"),limitTypes:$("#limitTypes").prop("checked")})}function L(M){var N=M.options.chart.renderTo;if(!N){return}$.each(runtime.charts,function(O,P){if(P.chart.options.chart.renderTo==N){delete runtime.charts[O];return false}});z();setTimeout(function(){M.destroy();$("#"+N).remove()},10);e()}function n(){runtime.refreshRequest=$.post("server_status_monitor.php?"+PMA_commonParams.get("common_query"),{ajax_request:true,chart_data:1,type:"chartgrid",requiredData:$.toJSON(runtime.dataList)},function(Q){var P;if(Q.success==true){P=Q.message}else{return serverResponseError()}var O,M=0;var R;var N;$.each(runtime.charts,function(W,V){var U=V.chartID;if(!P[U]){return}N=0;for(var T=0;TV.maxYLabel){V.maxYLabel=O}else{if(V.maxYLabel==0){V.maxYLabel=0.5}}if(V.chart.series[T].data.length>runtime.gridMaxPoints&&V.chart.series[T].data[0][0]N)?O[1]:N});return N}function p(N,R,P){switch(N){case"cpu-linux":if(P==null){return undefined}R=R[0];P=P[0];var Q=R.busy+R.idle-(P.busy+P.idle);var O=R.idle-P.idle;return 100*(Q-O)/Q;case"qce":if(P==null){return undefined}var M=R[0].value-P[0].value;if(R[1].value-P[1].value==0){return 0}return M/(R[1].value-P[1].value+M)*100;case"qcu":if(R[1].value==0){return 0}return 100-R[0].value/R[1].value*100}return undefined}function z(){runtime.dataList={};var M=0;$.each(runtime.charts,function(P,Q){runtime.dataList[M]=[];for(var O=0,N=Q.nodes.length;O');var N={};N[PMA_messages.strCancelRequest]=function(){if(Q!=null){Q.abort()}$(this).dialog("close")};$("#emptyDialog").dialog({width:"auto",height:"auto",buttons:N});Q=$.get("server_status_monitor.php?"+PMA_commonParams.get("common_query"),{ajax_request:true,log_data:1,type:O.src,time_start:Math.round(O.start/1000),time_end:Math.round(O.end/1000),removeVariables:O.removeVariables,limitTypes:O.limitTypes},function(T){var S;if(T.success==true){S=T.message}else{return serverResponseError()}if(S.rows.length!=0){runtime.logDataCols=g(S);$("#emptyDialog").dialog({title:PMA_messages.strLoadingLogs});$("#emptyDialog").html("

      "+PMA_messages.strLogDataLoaded+"

      ");$.each(S.sum,function(U,V){U=U.charAt(0).toUpperCase()+U.slice(1).toLowerCase();if(U=="Total"){U=""+U+""}$("#emptyDialog").append(U+": "+V+"
      ")});if(S.numRows>12){$("#logTable").prepend('
      '+PMA_messages.strFiltersForLogTable+'
      '+((S.numRows>250)?'
      ":"")+'
      ");$("#logTable #noWHEREData").change(function(){P(true)});if(S.numRows>250){$("#logTable #startFilterQueryText").click(P)}else{$("#logTable #filterQueryText").keyup(P)}}var R={};R[PMA_messages.strJumpToTable]=function(){$(this).dialog("close");$(document).scrollTop($("#logTable").offset().top)};$("#emptyDialog").dialog("option","buttons",R)}else{$("#emptyDialog").dialog({title:PMA_messages.strNoDataFoundTitle});$("#emptyDialog").html("

      "+PMA_messages.strNoDataFound+"

      ");var R={};R[PMA_messages.strClose]=function(){$(this).dialog("close")};$("#emptyDialog").dialog("option","buttons",R)}});function P(S){var U=false,R,ak;var ao=$("#logTable #filterQueryText").val();if(ao.length==0){ak=null}else{ak=new RegExp(ao,"i")}var af=0,X=0,ai=0,ad;var aj=$("#logTable #noWHEREData").prop("checked");var am=/([^=]+)=(\d+|((\'|"|).*?[^\\])\4((\s+)|$))/gi;var ae=/([a-z0-9_]+)\(.+?\)/gi;var V={},ag={};var ab=false,Y;var ac=runtime.logDataCols[runtime.logDataCols.length-2];var an=runtime.logDataCols[runtime.logDataCols.length-1];var T=O.src=="slow";var ah={};var al=function(aq,ar){var ap=ar.match(/(.*?)<\/td>/gi);if(!ah[aq]){ah[aq]=[0,0,0,0]}ah[aq][0]+=b(ap[2].replace(/(|<\/td>)/gi,""));ah[aq][1]+=b(ap[3].replace(/(|<\/td>)/gi,""));ah[aq][2]+=parseInt(ap[4].replace(/(|<\/td>)/gi,""));ah[aq][3]+=parseInt(ap[5].replace(/(|<\/td>)/gi,""))};$("#logTable table tbody tr td:nth-child("+(runtime.logDataCols.length-1)+")").each(function(){var ap=$(this);if(S&&ap.html().match(/^SELECT/i)){if(aj){ad=ap.text().replace(am,"$1=...$6").trim();ad=ad.replace(ae," $1(...)");if(V[ad]){V[ad]+=parseInt(ap.next().text());X+=parseInt(ap.next().text());ab=true}else{V[ad]=parseInt(ap.next().text());ag[ad]=ai;ap.text(ad)}if(T){al(ad,ap.parent().html())}}else{Y=ap.parent().data("query");ap.text(Y[ac]);ap.next().text(Y[an]);if(T){ap.parent().children("td:nth-child(3)").text(Y.query_time);ap.parent().children("td:nth-child(4)").text(Y.lock_time);ap.parent().children("td:nth-child(5)").text(Y.rows_sent);ap.parent().children("td:nth-child(6)").text(Y.rows_examined)}}}if(!ab&&(ak!=null&&!ak.exec(ap.text()))){ab=true}if(ab){ap.parent().css("display","none")}else{X+=parseInt(ap.next().text());af++;U=!U;ap.parent().css("display","");if(U){ap.parent().addClass("odd");ap.parent().removeClass("even")}else{ap.parent().addClass("even");ap.parent().removeClass("odd")}}ab=false;ai++});if(S){if(aj){var aa,W,Z=$("#logTable table tbody");$.each(ag,function(ap,aq){if(V[ap]<=1){return}W=Z.children("tr:nth-child("+(aq+1)+")");aa=W.children(":nth-child("+(runtime.logDataCols.length)+")");aa.text(V[ap]);if(T){W.children("td:nth-child(3)").text(A(ah[ap][0]));W.children("td:nth-child(4)").text(A(ah[ap][1]));W.children("td:nth-child(5)").text(ah[ap][2]);W.children("td:nth-child(6)").text(ah[ap][3])}})}$("#logTable table").trigger("update");setTimeout(function(){$("#logTable table").trigger("sorton",[[[runtime.logDataCols.length-1,1]]])},0)}$("#logTable table tfoot tr").html(''+PMA_messages.strSumRows+" "+af+''+PMA_messages.strTotal+''+X+"")}}function b(N){var M=N.split(":");return parseInt(M[0]*3600)+parseInt(M[1]*60)+parseInt(M[2])}function A(N){var M=Math.floor(N/3600);N-=M*3600;var O=Math.floor(N/60);N-=O*60;if(M<10){M="0"+M}if(O<10){O="0"+O}if(N<10){N="0"+N}return M+":"+O+":"+N}function g(Q){var Z=Q.rows;var U=[];var Y=$('
      ');var V,S,M;$("#logTable").html(Y);var R=function(aa,ab){switch(aa){case"user_host":return ab.replace(/(\[.*?\])+/g,"")}return ab};for(var P=0,N=Z.length;P'+U.join('')+"");Y.append(V=$(""))}V.append(S=$(''));var X="";for(var O=0,T=U.length;O'+R(U[O],Z[P][U[O]])+""));M.click(r)}else{S.append(""+R(U[O],Z[P][U[O]])+"")}S.data("query",Z[P])}}Y.append(''+PMA_messages.strSumRows+" "+Q.numRows+''+PMA_messages.strTotal+''+Q.sum.TOTAL+"");if($("#logTable th:last").html()=="#"){$("#logTable th:last").append(" "+PMA_getImage("b_docs.png","",{"class":"qroupedQueryInfoIcon"}));var W=PMA_messages.strCountColumnExplanation;if(groupInserts){W+="

      "+PMA_messages.strMoreCountColumnExplanation+"

      "}PMA_tooltip($("img.qroupedQueryInfoIcon"),"img",W)}$("#logTable table").tablesorter({sortList:[[U.length-1,1]],widgets:["fast-zebra"]});$("#logTable table thead th").append('');return U}function r(){var O=$(this).parent().data("query");var N=O.argument||O.sql_text;if(codemirror_editor){N=PMA_SQLPrettyPrint(N);codemirror_editor.setValue(N);setTimeout(function(){codemirror_editor.refresh()},50)}else{$("#sqlquery").val(N)}var P=null;var M={};M[PMA_messages.strAnalyzeQuery]=function(){F(O)};M[PMA_messages.strClose]=function(){$(this).dialog("close")};$("#queryAnalyzerDialog").dialog({width:"auto",height:"auto",resizable:false,buttons:M,close:function(){if(P!=null){P.destroy()}$("#queryAnalyzerDialog div.placeHolder").html("");if(codemirror_editor){codemirror_editor.setValue("")}else{$("#sqlquery").val("")}}})}function F(N){var M=N.db||"";$("#queryAnalyzerDialog div.placeHolder").html(PMA_messages.strAnalyzing+' ');$.post("server_status_monitor.php?"+PMA_commonParams.get("common_query"),{ajax_request:true,query_analyzer:true,query:codemirror_editor?codemirror_editor.getValue():$("#sqlquery").val(),database:M},function(U){if(U.success==true){U=U.message}else{$("#queryAnalyzerDialog div.placeHolder").html('
      '+U.error+"
      ");return}var O=0;$("#queryAnalyzerDialog div.placeHolder").html('
      ');var W=""+PMA_messages.strExplainOutput+" "+$("#explain_docu").html();if(U.explain.length>1){W+=" (";for(var V=0;V0){W+=", "}W+=''+V+""}W+=")"}W+="

      ";for(var V=0,P=U.explain.length;V0?'style="display:none;"':"")+">";$.each(U.explain[V],function(X,Y){Y=(Y==null)?"null":Y;if(X=="type"&&Y.toLowerCase()=="all"){Y=''+Y+""}if(X=="Extra"){Y=Y.replace(/(using (temporary|filesort))/gi,'$1')}W+=X+": "+Y+"
      "});W+="
      "}W+="

      "+PMA_messages.strAffectedRows+" "+U.affectedRows;$("#queryAnalyzerDialog div.placeHolder td.explain").append(W);$('#queryAnalyzerDialog div.placeHolder a[href*="#showExplain"]').click(function(){var X=$(this).attr("href").split("-")[1];$(this).parent().find('div[class*="explain"]').hide();$(this).parent().find('div[class*="explain-'+X+'"]').show()});if(U.profiling){var T=[];var S='";var Q;var R=0;for(var V=0,P=U.profiling.length;V"}for(var V=0,P=U.profiling.length;V0.02){T.push([PMA_prettyProfilingNum(Q,2)+" "+U.profiling[V].state,Q])}else{R+=Q}}if(R>0){T.push([PMA_prettyProfilingNum(R,2)+" "+PMA_messages.strOther,R])}S+="";S+="
      '+PMA_messages.strStatus+""+PMA_messages.strTime+"
      "+U.profiling[V].state+" "+PMA_prettyProfilingNum(Q,2)+"
      "+PMA_messages.strTotalTime+""+PMA_prettyProfilingNum(O,2)+"
      ";$("#queryAnalyzerDialog div.placeHolder td.chart").append(""+PMA_messages.strProfilingResults+" "+$("#profiling_docu").html()+' ('+PMA_messages.strTable+', '+PMA_messages.strChart+")
      "+S+'

      ');$('#queryAnalyzerDialog div.placeHolder a[href="#showNums"]').click(function(){$("#queryAnalyzerDialog #queryProfiling").hide();$("#queryAnalyzerDialog table.queryNums").show();return false});$('#queryAnalyzerDialog div.placeHolder a[href="#showChart"]').click(function(){$("#queryAnalyzerDialog #queryProfiling").show();$("#queryAnalyzerDialog table.queryNums").hide();return false});profilingChart=PMA_createProfilingChartJqplot("queryProfiling",T)}})}function e(){var M={};$.each(runtime.charts,function(N,O){M[N]={};M[N].nodes=O.nodes;M[N].settings=O.settings;M[N].title=O.title;M[N].series=O.series;M[N].maxYLabel=O.maxYLabel});if(window.localStorage){window.localStorage.monitorCharts=$.toJSON(M);window.localStorage.monitorSettings=$.toJSON(a);window.localStorage.monitorVersion=l}$('a[href="#clearMonitorConfig"]').show()}});AJAX.registerOnload("server_status_monitor.js",function(){$('a[href="#pauseCharts"]').trigger("click")});function serverResponseError(){var a={};a[PMA_messages.strReloadPage]=function(){window.location.reload()};$("#emptyDialog").dialog({title:PMA_messages.strRefreshFailed});$("#emptyDialog").html(PMA_getImage("s_attention.png")+PMA_messages.strInvalidResponseExplanation);$("#emptyDialog").dialog({buttons:a})}function destroyGrid(){if(runtime.charts){$.each(runtime.charts,function(b,d){try{d.chart.destroy()}catch(c){}})}try{runtime.refreshRequest.abort()}catch(a){}try{clearTimeout(runtime.refreshTimeout)}catch(a){}$("#chartGrid").html("");runtime.charts=null;runtime.chartAI=0;monitorSettings=null}; \ No newline at end of file diff --git a/phpmyadmin/js/server_status_queries.js b/phpmyadmin/js/server_status_queries.js new file mode 100644 index 000000000..b6b6f16f8 --- /dev/null +++ b/phpmyadmin/js/server_status_queries.js @@ -0,0 +1 @@ +AJAX.registerTeardown("server_status_queries.js",function(){var a=$("#serverstatusquerieschart").data("queryPieChart");if(a){a.destroy()}});AJAX.registerOnload("server_status_queries.js",function(){var b=[];try{$.each(jQuery.parseJSON($("#serverstatusquerieschart_data").text()),function(c,d){b.push([c,parseInt(d)])});$("#serverstatusquerieschart").data("queryPieChart",PMA_createProfilingChartJqplot("serverstatusquerieschart",b))}catch(a){}PMA_tooltip($("table.sortable>thead>tr:first").find("th"),"th",PMA_messages.strSortHint);initTableSorter("statustabs_queries")}); \ No newline at end of file diff --git a/phpmyadmin/js/server_status_sorter.js b/phpmyadmin/js/server_status_sorter.js new file mode 100644 index 000000000..813024023 --- /dev/null +++ b/phpmyadmin/js/server_status_sorter.js @@ -0,0 +1 @@ +function initTableSorter(a){var b,c;switch(a){case"statustabs_queries":b=$("#serverstatusqueriesdetails");c={sortList:[[3,1]],widgets:["fast-zebra"],headers:{1:{sorter:"fancyNumber"},2:{sorter:"fancyNumber"}}};break;case"statustabs_allvars":b=$("#serverstatusvariables");c={sortList:[[0,0]],widgets:["fast-zebra"],headers:{1:{sorter:"withinSpanNumber"}}};break}b.tablesorter(c);b.find("tr:first th").append('')}$(function(){$.tablesorter.addParser({id:"fancyNumber",is:function(a){return/^[0-9]?[0-9,\.]*\s?(k|M|G|T|%)?$/.test(a)},format:function(c){var a=jQuery.tablesorter.formatFloat(c.replace(PMA_messages.strThousandsSeparator,"").replace(PMA_messages.strDecimalSeparator,"."));var b=1;switch(c.charAt(c.length-1)){case"%":b=-2;break;case"k":b=3;break;case"M":b=6;break;case"G":b=9;break;case"T":b=12;break}return a*Math.pow(10,b)},type:"numeric"});$.tablesorter.addParser({id:"withinSpanNumber",is:function(a){return/(.*)?<\/span>/);return(a&&a.length>=3)?a[2]:0},type:"numeric"});$.tablesorter.addWidget({id:"fast-zebra",format:function(a){if(a.config.debug){var b=new Date()}$("tr:even",a.tBodies[0]).removeClass(a.config.widgetZebra.css[0]).addClass(a.config.widgetZebra.css[1]);$("tr:odd",a.tBodies[0]).removeClass(a.config.widgetZebra.css[1]).addClass(a.config.widgetZebra.css[0]);if(a.config.debug){$.tablesorter.benchmark("Applying Fast-Zebra widget",b)}}})}); \ No newline at end of file diff --git a/phpmyadmin/js/server_status_variables.js b/phpmyadmin/js/server_status_variables.js new file mode 100644 index 000000000..75bb7eee3 --- /dev/null +++ b/phpmyadmin/js/server_status_variables.js @@ -0,0 +1 @@ +AJAX.registerTeardown("server_status_variables.js",function(){$("#filterAlert").unbind("change");$("#filterText").unbind("keyup");$("#filterCategory").unbind("change");$("#dontFormat").unbind("change")});AJAX.registerOnload("server_status_variables.js",function(){PMA_tooltip($("table.sortable>thead>tr:first").find("th"),"th",PMA_messages.strSortHint);initTableSorter("statustabs_allvars");var d=null;var c=$("#filterAlert").prop("checked");var b=$("#filterCategory").find(":selected").val();var a=false;var f="";$("#filterAlert").change(function(){c=this.checked;e()});$("#filterCategory").change(function(){b=$(this).val();e()});$("#dontFormat").change(function(){$("#serverstatusvariables").hide();$("#serverstatusvariables td.value span.original").toggle(this.checked);$("#serverstatusvariables td.value span.formatted").toggle(!this.checked);$("#serverstatusvariables").show()}).trigger("change");$("#filterText").keyup(function(h){var g=$(this).val().replace(/_/g," ");if(g.length==0){d=null}else{d=new RegExp("(^| )"+g,"i")}f=g;e()}).trigger("keyup");function e(){var g=0;var h=f;if(b.length>0){h=b}if(h.length>1){$("#linkSuggestions span").each(function(){if($(this).attr("class").indexOf("status_"+h)!=-1){g++;$(this).css("display","")}else{$(this).css("display","none")}})}if(g>0){$("#linkSuggestions").css("display","")}else{$("#linkSuggestions").css("display","none")}a=false;$("#serverstatusvariables th.name").each(function(){if((d==null||d.exec($(this).text()))&&(!c||$(this).next().find("span.attention").length>0)&&(b.length==0||$(this).parent().hasClass("s_"+b))){a=!a;$(this).parent().css("display","");if(a){$(this).parent().addClass("odd");$(this).parent().removeClass("even")}else{$(this).parent().addClass("even");$(this).parent().removeClass("odd")}}else{$(this).parent().css("display","none")}})}}); \ No newline at end of file diff --git a/phpmyadmin/js/server_variables.js b/phpmyadmin/js/server_variables.js new file mode 100644 index 000000000..07ea3e9a4 --- /dev/null +++ b/phpmyadmin/js/server_variables.js @@ -0,0 +1 @@ +AJAX.registerTeardown("server_variables.js",function(){$("#serverVariables .var-row").unbind("hover");$("#filterText").unbind("keyup");$("a.editLink").die("click");$("#serverVariables").find(".var-name").find("a img").remove()});AJAX.registerOnload("server_variables.js",function(){var c=$("a.editLink");var e=$("a.saveLink");var b=$("a.cancelLink");var d=$("#filterText");$("#serverVariables").delegate(".var-row","hover",function(h){if(h.type==="mouseenter"){var g=$(this).find(".var-value");if(g.hasClass("editable")&&!g.hasClass("edit")){g.prepend(c.clone().show())}}else{$(this).find("a.editLink").remove()}}).find(".var-name").find("a").append($("#docImage").clone().show());c.live("click",function(g){g.preventDefault();a(this)});d.keyup(function(){var g=null,h=$(this).val();if(h.length!==0){g=new RegExp("(^| )"+h.replace(/_/g," "),"i")}f(g)});if(d.val()){d.trigger("keyup").select()}function f(i){var j=false,g,h=false;$("#serverVariables .var-row").not(".var-header").each(function(){g=$(this);if(j||i===null||i.exec(g.find(".var-name").text())){j=g.hasClass("diffSession")&&!j;h=!h;g.css("display","");if(h){g.addClass("odd").removeClass("even")}else{g.addClass("even").removeClass("odd")}}else{g.css("display","none")}})}function a(i){var j=$(i).parent();var l=j.parent().find(".var-name").text().replace(/ /g,"_");var h=e.clone().show();var g=b.clone().show();var k=PMA_ajaxShowMessage();j.addClass("edit").find("a.editLink").remove();h.click(function(){var m=PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);$.get($(this).attr("href"),{ajax_request:true,type:"setval",varName:l,varValue:j.find("input").val()},function(n){if(n.success){j.html(n.variable).data("content",n.variable);PMA_ajaxRemoveMessage(m)}else{PMA_ajaxShowMessage(n.error,false);j.html(j.data("content"))}j.removeClass("edit")});return false});g.click(function(){j.html(j.data("content")).removeClass("edit");return false});$.get(h.attr("href"),{ajax_request:true,type:"getval",varName:l},function(m){if(m.success===true){var n=$("
      ",{"class":"serverVariableEditor"}).append(g).append(" ").append(h).append(" ").append($("
      ").append($("",{type:"text"}).val(m.message)));j.data("content",j.html()).html(n).find("input").focus().keydown(function(o){if(o.keyCode===13){h.trigger("click")}else{if(o.keyCode===27){g.trigger("click")}}});PMA_ajaxRemoveMessage(k)}else{j.removeClass("edit");PMA_ajaxShowMessage(m.error)}})}}); \ No newline at end of file diff --git a/phpmyadmin/js/sql.js b/phpmyadmin/js/sql.js new file mode 100644 index 000000000..f03688ac1 --- /dev/null +++ b/phpmyadmin/js/sql.js @@ -0,0 +1 @@ +var $data_a;function PMA_urldecode(a){return decodeURIComponent(a.replace(/\+/g,"%20"))}function PMA_urlencode(a){return encodeURIComponent(a).replace(/\%20/g,"+")}function getFieldName(c){var b=c.index();var a=!$("#table_results").find("th:first").hasClass("draggable");var f=a?$("#table_results").find("th:first").attr("colspan")-1:0;var e=$("#table_results").find("thead").find("th:eq("+(b-f)+") a").text();if(""==e){var d=$("#table_results").find("thead").find("th:eq("+(b-f)+")").children("span");var g=d.children().detach();e=d.text();d.append(g)}e=$.trim(e);return e}AJAX.registerTeardown("sql.js",function(){$("a.delete_row.ajax").unbind("click");$("#bookmarkQueryForm").die("submit");$("input#bkm_label").unbind("keyup");$("#sqlqueryresults").die("makegrid");$("#togglequerybox").unbind("click");$("#button_submit_query").die("click");$("input[name=bookmark_variable]").unbind("keypress");$("#sqlqueryform.ajax").die("submit");$("input[name=navig].ajax").die("click");$("#pageselector").die("change");$("#table_results.ajax").find("a[title=Sort]").die("click");$("#displayOptionsForm.ajax").die("submit");$("#resultsForm.ajax .mult_submit[value=edit]").die("click");$("#insertForm .insertRowTable.ajax input[type=submit]").die("click");$("#buttonYes.ajax").die("click");$("a.browse_foreign").die("click");$("th.column_heading.pointer").die("hover");$("th.column_heading.marker").die("click")});AJAX.registerOnload("sql.js",function(){$("a.delete_row.ajax").click(function(c){c.preventDefault();var b=$.sprintf(PMA_messages.strDoYouReally,$(this).closest("td").find("div").text());var a=$(this);a.PMA_confirm(b,a.attr("href"),function(d){$msgbox=PMA_ajaxShowMessage();$.get(d,{ajax_request:true,is_js_confirmed:true},function(e){if(e.success){PMA_ajaxShowMessage(e.message);a.closest("tr").remove()}else{PMA_ajaxShowMessage(e.error,false)}})})});$("#bookmarkQueryForm").live("submit",function(a){a.preventDefault();PMA_ajaxShowMessage();$.post($(this).attr("action"),"ajax_request=1&"+$(this).serialize(),function(b){if(b.success){PMA_ajaxShowMessage(b.message)}else{PMA_ajaxShowMessage(b.error,false)}})});$("input#bkm_label").keyup(function(){$("input#id_bkm_all_users, input#id_bkm_replace").parent().toggle($(this).val().length>0)}).trigger("keyup");$("#sqlqueryresults").live("makegrid",function(){PMA_makegrid($("#table_results")[0])});if(!$("#sqlqueryform").find("a").is("#togglequerybox")){$('').html(PMA_messages.strHideQueryBox).appendTo("#sqlqueryform").hide();$("#togglequerybox").bind("click",function(){var a=$(this);a.siblings().slideToggle("fast");if(a.text()==PMA_messages.strHideQueryBox){a.text(PMA_messages.strShowQueryBox);$("#togglequerybox_spacer").remove();a.before('
      ')}else{a.text(PMA_messages.strHideQueryBox)}return false})}$("#button_submit_query").live("click",function(b){var a=$(this).closest("form");a.find("select[name=id_bookmark]").val("")});$("input[name=bookmark_variable]").bind("keypress",function(b){var a=(b.keyCode?b.keyCode:(b.which?b.which:b.charCode));if(a==13){$("#button_submit_bookmark").click();return false}else{return true}});$("#sqlqueryform.ajax").live("submit",function(c){c.preventDefault();var b=$(this);if(!checkSqlQuery(b[0])){return false}$("div.error").remove();var d=PMA_ajaxShowMessage();var a=$("#sqlqueryresults");PMA_prepareForAjaxRequest(b);$.post(b.attr("action"),b.serialize(),function(e){if(e.success==true){$("div.success, div.sqlquery_message").fadeOut();if($("#result_query").length){$("#result_query").remove()}if(typeof e.action_bookmark!="undefined"){if("1"==e.action_bookmark){$("#sqlquery").text(e.sql_query);setQuery(e.sql_query)}if("2"==e.action_bookmark){$("#id_bookmark option[value='"+e.id_bookmark+"']").remove()}a.show().html(e.message)}else{if(typeof e.sql_query!="undefined"){$('
      ').html(e.sql_query).insertBefore("#sqlqueryform");$("div.notice").remove()}else{a.show().html(e.message)}}if(typeof e.ajax_reload!="undefined"){if(e.ajax_reload.reload){if(e.ajax_reload.table_name){PMA_commonParams.set("table",e.ajax_reload.table_name);PMA_commonActions.refreshMain()}else{PMA_reloadNavigation()}}}else{if(typeof e.reload!="undefined"){PMA_commonActions.setDb(e.db);PMA_commonActions.refreshMain(false,function(){if($("#result_query").length){$("#result_query").remove()}if(e.sql_query){$('
      ').html(e.sql_query).prependTo("#page_content")}});PMA_reloadNavigation()}}a.show().trigger("makegrid");$("#togglequerybox").show();PMA_init_slider();if(typeof e.action_bookmark=="undefined"){if($('#sqlqueryform input[name="retain_query_box"]').is(":checked")!=true){if($("#togglequerybox").siblings(":visible").length>0){$("#togglequerybox").trigger("click")}}}}else{if(e.success==false){$("#sqlqueryform").before(e.error);a.hide()}}PMA_ajaxRemoveMessage(d)})});$("#pageselector").live("change",function(b){var a=$(this).parent("form");a.submit()});$("#displayOptionsForm.ajax").live("submit",function(a){a.preventDefault();$form=$(this);$.post($form.attr("action"),$form.serialize()+"&ajax_request=true",function(b){$("#sqlqueryresults").html(b.message).trigger("makegrid");PMA_init_slider()})});$("#resultsForm.ajax .mult_submit[value=edit]").live("click",function(d){d.preventDefault();if($("#table_results tbody tr, #table_results tbody tr td").hasClass("marked")){var a=$('
      ');var c={};c[PMA_messages.strCancel]=function(){$(this).dialog("close")};var e={};e[PMA_messages.strOK]=function(){$(this).dialog("close")};var b=$("#resultsForm");var f=PMA_ajaxShowMessage();$.get(b.attr("action"),b.serialize()+"&ajax_request=true&submit_mult=row_edit",function(g){if(g.success!=undefined&&g.success==false){a.append(g.error).dialog({title:PMA_messages.strChangeTbl,height:230,width:900,open:PMA_verifyColumnsProperties,close:function(h,i){$(this).remove()},buttons:e})}else{a.append(g.message).dialog({title:PMA_messages.strChangeTbl,height:600,width:900,open:PMA_verifyColumnsProperties,close:function(h,i){$(this).remove()},buttons:c}).find("#topmenucontainer").hide();$("table.insertRowTable").addClass("ajax");$("#buttonYes").addClass("ajax")}PMA_ajaxRemoveMessage(f)})}else{PMA_ajaxShowMessage(PMA_messages.strNoRowSelected)}});$("#insertForm .insertRowTable.ajax input[type=submit]").live("click",function(b){b.preventDefault();var a=$("#insertForm");PMA_prepareForAjaxRequest(a);$.post(a.attr("action"),a.serialize(),function(c){if(c.success==true){PMA_ajaxShowMessage(c.message);if($("#pageselector").length!=0){$("#pageselector").trigger("change")}else{$("input[name=navig].ajax").trigger("click")}}else{PMA_ajaxShowMessage(c.error,false);$("#table_results tbody tr.marked .multi_checkbox , #table_results tbody tr td.marked .multi_checkbox").prop("checked",false);$("#table_results tbody tr.marked .multi_checkbox , #table_results tbody tr td.marked .multi_checkbox").removeClass("last_clicked");$("#table_results tbody tr, #table_results tbody tr td").removeClass("marked")}if($("#change_row_dialog").length>0){$("#change_row_dialog").dialog("close").remove()}$("#result_query").remove();$("#sqlqueryresults").prepend(c.sql_query);$("#result_query .notice").remove();$("#result_query").prepend((c.message))})});$("#buttonYes.ajax").live("click",function(c){c.preventDefault();var a=$("#insertForm");var b=$("#insertForm").find("#actions_panel .control_at_footer option:selected").val();$("#result_query").remove();PMA_prepareForAjaxRequest(a);$.post(a.attr("action"),a.serialize(),function(d){if(d.success==true){PMA_ajaxShowMessage(d.message);if(b=="showinsert"){$("#sqlqueryresults").prepend(d.sql_query);$("#result_query .notice").remove();$("#result_query").prepend(d.message);$("#table_results tbody tr.marked .multi_checkbox , #table_results tbody tr td.marked .multi_checkbox").prop("checked",false);$("#table_results tbody tr.marked .multi_checkbox , #table_results tbody tr td.marked .multi_checkbox").removeClass("last_clicked");$("#table_results tbody tr, #table_results tbody tr td").removeClass("marked")}else{if($("#pageselector").length!=0){$("#pageselector").trigger("change")}else{$("input[name=navig].ajax").trigger("click")}$("#result_query").remove();$("#sqlqueryresults").prepend(d.sql_query);$("#result_query .notice").remove();$("#result_query").prepend((d.message))}}else{PMA_ajaxShowMessage(d.error,false);$("#table_results tbody tr.marked .multi_checkbox , #table_results tbody tr td.marked .multi_checkbox").prop("checked",false);$("#table_results tbody tr.marked .multi_checkbox , #table_results tbody tr td.marked .multi_checkbox").removeClass("last_clicked");$("#table_results tbody tr, #table_results tbody tr td").removeClass("marked")}if($("#change_row_dialog").length>0){$("#change_row_dialog").dialog("close").remove()}})})});function PMA_changeClassForColumn(b,a,d){var e=b.index();var c=!b.closest("tr").children(":first").hasClass("column_heading");if(c){e--}var f=b.closest("table").find("tbody tr").find("td.data:eq("+e+")");if(d==undefined){f.toggleClass(a)}else{f.toggleClass(a,d)}}AJAX.registerOnload("sql.js",function(){$("a.browse_foreign").live("click",function(a){a.preventDefault();window.open(this.href,"foreigners","width=640,height=240,scrollbars=yes,resizable=yes");$anchor=$(this);$anchor.addClass("browse_foreign_clicked")});$("th.column_heading.pointer").live("hover",function(a){PMA_changeClassForColumn($(this),"hover",a.type=="mouseenter")});$("th.column_heading.marker").live("click",function(){PMA_changeClassForColumn($(this),"marked")});$("#sqlqueryresults").trigger("makegrid")});function makeProfilingChart(){if($("#profilingchart").length==0||$("#profilingchart").html().length!=0){return}var a=[];$.each(jQuery.parseJSON($("#profilingChartData").html()),function(b,c){a.push([b,parseFloat(c)])});$("#profilingchart").html("").show();$("#profilingChartData").html("");PMA_createProfilingChartJqplot("profilingchart",a)}; \ No newline at end of file diff --git a/phpmyadmin/js/tbl_change.js b/phpmyadmin/js/tbl_change.js new file mode 100644 index 000000000..dcc8e46b9 --- /dev/null +++ b/phpmyadmin/js/tbl_change.js @@ -0,0 +1 @@ +function nullify(f,h,c,g){var d=document.forms.insertForm;if(typeof(d.elements["funcs"+g+"["+c+"]"])!="undefined"){d.elements["funcs"+g+"["+c+"]"].selectedIndex=-1}if(f==1){d.elements["fields"+g+"["+c+"]"][1].selectedIndex=-1}else{if(f==2){var e=d.elements["fields"+g+"["+c+"]"];if(e.checked){e.checked=false}else{var a=e.length;for(var b=0;b=1&&a<=9?"0"+a:"00"}function isDate(b,d){b=b.replace(/[.|*|^|+|//|@]/g,"-");var g=b.split("-");for(var j=0;jdaysInFebruary(f)){return false}if(b.substring(0,h+2).length==2){f=parseInt("20"+b.substring(0,h+2))}if(d==true){if(f<1978){return false}if(f>2038||(f>2037&&i>19&&e>=1)||(f>2037&&e>1)){return false}}}else{return false}return true}function isTime(f){var d=f.split(":");for(var c=0,b=d.length;c').insertBefore("table.insertRowTable:last").after('")}else{var i=$("#insertForm").children("input:checkbox:last");var j=i.attr("name");var b=parseInt(j.match(/\d+/));var c=j.replace(/\d+/,b+1);i.clone().attr({id:c,name:c}).prop("checked",true).add("label[for^=insert_ignore]:last").clone().attr("for",c).before("
      ").insertBefore("table.insertRowTable:last")}f++}var e=0;$(".textfield").each(function(){e++;$(this).attr("tabindex",e);$(this).attr("id","field_"+e+"_3")});$("select.control_at_footer").each(function(){e++;$(this).attr("tabindex",e)});$("input.datefield, input.datetimefield").each(function(){PMA_addDatepicker($(this))})}else{if(f>g){while(f>g){$("input[id^=insert_ignore]:last").nextUntil("fieldset").andSelf().remove();f--}}}})}); \ No newline at end of file diff --git a/phpmyadmin/js/tbl_chart.js b/phpmyadmin/js/tbl_chart.js new file mode 100644 index 000000000..6d6082a2e --- /dev/null +++ b/phpmyadmin/js/tbl_chart.js @@ -0,0 +1 @@ +var chart_data={};var temp_chart_title;var currentChart=null;var currentSettings=null;AJAX.registerTeardown("tbl_chart.js",function(){$('input[name="chartType"]').unbind("click");$('input[name="barStacked"]').unbind("click");$('input[name="chartTitle"]').unbind("focus").unbind("keyup").unbind("blur");$('select[name="chartXAxis"]').unbind("change");$('select[name="chartSeries"]').unbind("change");$('input[name="xaxis_label"]').unbind("keyup");$('input[name="yaxis_label"]').unbind("keyup");$("#resizer").unbind("resizestop")});AJAX.registerOnload("tbl_chart.js",function(){$("#resizer").resizable({minHeight:240,minWidth:300}).width($("#div_view_options").width()-50);$("#resizer").bind("resizestop",function(c,d){$("#querychart").height($("#resizer").height()*0.96);$("#querychart").width($("#resizer").width()*0.96);currentChart.redraw({resetAxes:true})});currentSettings={type:"line",width:$("#resizer").width()-20,height:$("#resizer").height()-20,xaxisLabel:$('input[name="xaxis_label"]').val(),yaxisLabel:$('input[name="yaxis_label"]').val(),title:$('input[name="chartTitle"]').val(),stackSeries:false,mainAxis:parseInt($('select[name="chartXAxis"]').val()),selectedSeries:getSelectedSeries()};$('input[name="chartType"]').click(function(){currentSettings.type=$(this).val();drawChart();if($(this).val()=="bar"||$(this).val()=="column"||$(this).val()=="line"||$(this).val()=="area"||$(this).val()=="timeline"||$(this).val()=="spline"){$("span.barStacked").show()}else{$("span.barStacked").hide()}});$('input[name="barStacked"]').click(function(){if(this.checked){$.extend(true,currentSettings,{stackSeries:true})}else{$.extend(true,currentSettings,{stackSeries:false})}drawChart()});$('input[name="chartTitle"]').focus(function(){temp_chart_title=$(this).val()}).keyup(function(){var c=$(this).val();if(c.length==0){c=" "}currentSettings.title=$('input[name="chartTitle"]').val();drawChart()}).blur(function(){if($(this).val()!=temp_chart_title){drawChart()}});var a=[];var b=$('input[name="dateTimeCols"]').val().split(" ");$.each(b,function(d,c){a.push(parseInt(c))});$('select[name="chartXAxis"]').change(function(){currentSettings.mainAxis=parseInt($(this).val());if(a.indexOf(currentSettings.mainAxis)!=-1){$("span.span_timeline").show()}else{$("span.span_timeline").hide();if(currentSettings.type=="timeline"){$("input#radio_line").prop("checked",true);currentSettings.type="line"}}var c=$(this).children("option:selected").text();$('input[name="xaxis_label"]').val(c);currentSettings.xaxisLabel=c;drawChart()});$('select[name="chartSeries"]').change(function(){currentSettings.selectedSeries=getSelectedSeries();var c;if(currentSettings.selectedSeries.length==1){$("span.span_pie").show();c=$(this).children("option:selected").text()}else{$("span.span_pie").hide();if(currentSettings.type=="pie"){$("input#radio_line").prop("checked",true);currentSettings.type="line"}c=PMA_messages.strYValues}$('input[name="yaxis_label"]').val(c);currentSettings.yaxisLabel=c;drawChart()});$('input[name="xaxis_label"]').keyup(function(){currentSettings.xaxisLabel=$(this).val();drawChart()});$('input[name="yaxis_label"]').keyup(function(){currentSettings.yaxisLabel=$(this).val();drawChart()});$("#tblchartform").submit()});$("#tblchartform").live("submit",function(b){if(!checkFormElementInRange(this,"session_max_rows",PMA_messages.strNotValidRowNumber,1)||!checkFormElementInRange(this,"pos",PMA_messages.strNotValidRowNumber,0-1)){return false}var a=$(this);if(!checkSqlQuery(a[0])){return false}$(".error").remove();var c=PMA_ajaxShowMessage();PMA_prepareForAjaxRequest(a);$.post(a.attr("action"),a.serialize(),function(d){if(d.success==true){$(".success").fadeOut();if(typeof d.chartData!="undefined"){chart_data=jQuery.parseJSON(d.chartData);drawChart();$("div#querychart").height($("div#resizer").height()*0.96);$("div#querychart").width($("div#resizer").width()*0.96);currentChart.redraw({resetAxes:true});$("#querychart").show()}}else{PMA_ajaxRemoveMessage(c);PMA_ajaxShowMessage(d.error,false);chart_data=null;drawChart()}PMA_ajaxRemoveMessage(c)},"json");return false});function drawChart(){currentSettings.width=$("#resizer").width()-20;currentSettings.height=$("#resizer").height()-20;if(currentChart!=null){currentChart.destroy()}var b=[];$('select[name="chartXAxis"] option').each(function(){b.push($(this).text())});try{currentChart=PMA_queryChart(chart_data,b,currentSettings)}catch(a){PMA_ajaxShowMessage(a.message,false)}}function getSelectedSeries(){var b=$('select[name="chartSeries"]').val()||[];var a=[];$.each(b,function(d,c){a.push(parseInt(c))});return a}function extractDate(d){var e,b;var a=/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/;var c=/[0-9]{4}-[0-9]{2}-[0-9]{2}/;e=a.exec(d);if(e!=null&&e.length>0){b=e[0];return new Date(b.substr(0,4),b.substr(5,2),b.substr(8,2),b.substr(11,2),b.substr(14,2),b.substr(17,2))}else{e=c.exec(d);if(e!=null&&e.length>0){b=e[0];return new Date(b.substr(0,4),b.substr(5,2),b.substr(8,2))}}return null}function PMA_queryChart(f,l,c){if($("#querychart").length==0){return}var m={title:{text:c.title,escapeHtml:true},grid:{drawBorder:false,shadow:false,background:"rgba(0,0,0,0)"},legend:{show:true,placement:"outsideGrid",location:"e"},axes:{xaxis:{label:c.xaxisLabel},yaxis:{label:c.yaxisLabel}},stackSeries:c.stackSeries,highlighter:{show:true,showTooltip:true,tooltipAxes:"xy"}};var g=new JQPlotChartFactory();var k=g.createChart(c.type,"querychart");var a=new DataTable();if(c.type=="timeline"){a.addColumn(ColumnType.DATE,l[c.mainAxis])}else{a.addColumn(ColumnType.STRING,l[c.mainAxis])}$.each(c.selectedSeries,function(i,j){a.addColumn(ColumnType.NUMBER,l[j])});var h=[c.mainAxis];$.each(c.selectedSeries,function(i,j){h.push(j)});var n=[],o,p,b;for(var e=0;e0){var a=$("#pmaThemeImage").val();$('').appendTo(b);$('').appendTo(b);$('').appendTo(b);$('').appendTo(b);$('').appendTo(b);$('').appendTo(b);$('').appendTo(b)}}function resizeGISVisualization(){var b=$("#placeholder");var a=b.width();var c=$("#div_view_options").width()-48;b.width(c);$("svg").attr("width",c);defaultX=(c-a)/2;x=defaultX;y=0;scale=1}function initGISVisualization(){selectVisualization();resizeGISVisualization();styleOSM();drawOpenLayers();loadSVG();addZoomPanControllers();zoomAndPan()}function getRelativeCoords(b){var a=$("#placeholder").offset();return{x:b.pageX-a.left,y:b.pageY-a.top}}AJAX.registerTeardown("tbl_gis_visualization.js",function(){$("#choice").die("click");$("#placeholder").die("mousewheel");$("svg").die("dragstart");$("svg").die("mouseup");$("svg").die("drag");$("#placeholder").die("dblclick");$("#zoom_in").die("click");$("#zoom_world").die("click");$("#zoom_out").die("click");$("#left_arrow").die("click");$("#right_arrow").die("click");$("#up_arrow").die("click");$("#down_arrow").die("click");$(".vector").unbind("mousemove").unbind("mouseout")});AJAX.registerOnload("tbl_gis_visualization.js",function(){if($("table.gis_table").length>0){initGISVisualization()}$("#choice").live("click",function(){if($(this).prop("checked")==false){$("#placeholder").show();$("#openlayersmap").hide()}else{$("#placeholder").hide();$("#openlayersmap").show()}});$("#placeholder").live("mousewheel",function(c,e){var d=getRelativeCoords(c);if(e>0){scale*=zoomFactor;x=d.x-(d.x-x)*zoomFactor;y=d.y-(d.y-y)*zoomFactor;zoomAndPan()}else{scale/=zoomFactor;x=d.x-(d.x-x)/zoomFactor;y=d.y-(d.y-y)/zoomFactor;zoomAndPan()}return true});var b=0;var a=0;$("svg").live("dragstart",function(d,c){$("#placeholder").addClass("placeholderDrag");b=Math.round(c.offsetX);a=Math.round(c.offsetY)});$("svg").live("mouseup",function(c){$("#placeholder").removeClass("placeholderDrag")});$("svg").live("drag",function(d,c){newX=Math.round(c.offsetX);x+=newX-b;b=newX;newY=Math.round(c.offsetY);y+=newY-a;a=newY;zoomAndPan()});$("#placeholder").live("dblclick",function(c){scale*=zoomFactor;var d=getRelativeCoords(c);x=d.x-(d.x-x)*zoomFactor;y=d.y-(d.y-y)*zoomFactor;zoomAndPan()});$("#zoom_in").live("click",function(c){c.preventDefault();scale*=zoomFactor;width=$("#placeholder svg").attr("width");height=$("#placeholder svg").attr("height");x=width/2-(width/2-x)*zoomFactor;y=height/2-(height/2-y)*zoomFactor;zoomAndPan()});$("#zoom_world").live("click",function(c){c.preventDefault();scale=1;x=defaultX;y=defaultY;zoomAndPan()});$("#zoom_out").live("click",function(c){c.preventDefault();scale/=zoomFactor;width=$("#placeholder svg").attr("width");height=$("#placeholder svg").attr("height");x=width/2-(width/2-x)/zoomFactor;y=height/2-(height/2-y)/zoomFactor;zoomAndPan()});$("#left_arrow").live("click",function(c){c.preventDefault();x+=100;zoomAndPan()});$("#right_arrow").live("click",function(c){c.preventDefault();x-=100;zoomAndPan()});$("#up_arrow").live("click",function(c){c.preventDefault();y+=100;zoomAndPan()});$("#down_arrow").live("click",function(c){c.preventDefault();y-=100;zoomAndPan()});$(".vector").bind("mousemove",function(d){var c=$.trim(escapeHtml($(this).attr("name")));$("#tooltip").remove();if(c!=""){$('
      '+c+"
      ").css({position:"absolute",top:d.pageY+10,left:d.pageX+10,border:"1px solid #fdd",padding:"2px","background-color":"#fee",opacity:0.9}).appendTo("body").fadeIn(200)}});$(".vector").bind("mouseout",function(c){$("#tooltip").remove()})}); \ No newline at end of file diff --git a/phpmyadmin/js/tbl_relation.js b/phpmyadmin/js/tbl_relation.js new file mode 100644 index 000000000..49b3d1773 --- /dev/null +++ b/phpmyadmin/js/tbl_relation.js @@ -0,0 +1 @@ +function show_hide_clauses(a){if(a.val()!=""){a.parent().nextAll("span").show()}else{a.parent().nextAll("span").hide()}}AJAX.registerTeardown("tbl_relation.js",function(){$("select.referenced_column_dropdown").unbind("change")});AJAX.registerOnload("tbl_relation.js",function(){$("select.referenced_column_dropdown").each(function(a,b){show_hide_clauses($(b))});$("select.referenced_column_dropdown").change(function(){show_hide_clauses($(this))})}); \ No newline at end of file diff --git a/phpmyadmin/js/tbl_select.js b/phpmyadmin/js/tbl_select.js new file mode 100644 index 000000000..5c93bd9c0 --- /dev/null +++ b/phpmyadmin/js/tbl_select.js @@ -0,0 +1 @@ +AJAX.registerTeardown("tbl_select.js",function(){$("#togglesearchformlink").unbind("click");$("#tbl_search_form.ajax").die("submit");$("select.geom_func").unbind("change");$("span.open_search_gis_editor").die("click")});AJAX.registerOnload("tbl_select.js",function(){$('
      ').insertAfter("#tbl_search_form").hide();$("#togglesearchformlink").html(PMA_messages.strShowSearchCriteria).bind("click",function(){var a=$(this);$("#tbl_search_form").slideToggle();if(a.text()==PMA_messages.strHideSearchCriteria){a.text(PMA_messages.strShowSearchCriteria)}else{a.text(PMA_messages.strHideSearchCriteria)}return false});$("#tbl_search_form.ajax").live("submit",function(d){var g=["IS NULL","IS NOT NULL","= ''","!= ''"];$search_form=$(this);d.preventDefault();$("#sqlqueryresults").empty();var f=PMA_ajaxShowMessage(PMA_messages.strSearching,false);PMA_prepareForAjaxRequest($search_form);var c={};$search_form.find(":input").each(function(){var a=$(this);if(a.attr("type")=="checkbox"||a.attr("type")=="radio"){if(a.is(":checked")){c[this.name]=a.val()}}else{c[this.name]=a.val()}});var e=$('select[name="columnsToDisplay[]"] option').length;for(var b=0;b=0){continue}if(c["criteriaValues["+b+"]"]==""||c["criteriaValues["+b+"]"]==null){delete c["criteriaValues["+b+"]"];delete c["criteriaColumnOperators["+b+"]"];delete c["criteriaColumnNames["+b+"]"];delete c["criteriaColumnTypes["+b+"]"];delete c["criteriaColumnCollations["+b+"]"]}}if(c["columnsToDisplay[]"]!=null){if(c["columnsToDisplay[]"].length==e){delete c["columnsToDisplay[]"];c.displayAllColumns=true}}else{c.displayAllColumns=true}$.post($search_form.attr("action"),c,function(a){PMA_ajaxRemoveMessage(f);if(a.success==true){if(a.sql_query!=null){$("#sqlqueryresults").html(a.sql_query)}else{$("#sqlqueryresults").html(a.message);$("#sqlqueryresults").trigger("makegrid")}$("#tbl_search_form").slideToggle().hide();$("#togglesearchformlink").text(PMA_messages.strShowSearchCriteria);$("#togglesearchformdiv").show();PMA_init_slider()}else{$("#sqlqueryresults").html(a.error)}})});$("span.open_search_gis_editor").hide();$("select.geom_func").bind("change",function(){var b=$(this);var c=["Contains","Crosses","Disjoint","Equals","Intersects","Overlaps","Touches","Within","MBRContains","MBRDisjoint","MBREquals","MBRIntersects","MBROverlaps","MBRTouches","MBRWithin","ST_Contains","ST_Crosses","ST_Disjoint","ST_Equals","ST_Intersects","ST_Overlaps","ST_Touches","ST_Within"];var e=["Envelope","EndPoint","StartPoint","ExteriorRing","Centroid","PointOnSurface"];var d=c.concat(e);var a=b.parents("tr").find("td:nth-child(5)").find("select");if($.inArray(b.val(),c)>=0){a.prop("readonly",true)}else{a.prop("readonly",false)}var f=b.parents("tr").find("span.open_search_gis_editor");if($.inArray(b.val(),d)>=0){f.show()}else{f.hide()}});$("span.open_search_gis_editor").live("click",function(e){e.preventDefault();var a=$(this);var f=a.parent("td").children("input[type='text']").val();var g="Parameter";var b=a.parents("tr").find(".geom_func").val();if(b=="Envelope"){var d="polygon"}else{if(b=="ExteriorRing"){var d="linestring"}else{var d="point"}}var h=a.parent("td").children("input[type='text']").attr("name");var c=$("input[name='token']").val();openGISEditor();if(!gisEditorLoaded){loadJSAndGISEditor(f,g,d,h,c)}else{loadGISEditor(f,g,d,h,c)}})}); \ No newline at end of file diff --git a/phpmyadmin/js/tbl_structure.js b/phpmyadmin/js/tbl_structure.js new file mode 100644 index 000000000..b7ba1636a --- /dev/null +++ b/phpmyadmin/js/tbl_structure.js @@ -0,0 +1 @@ +AJAX.registerTeardown("tbl_structure.js",function(){$("a.change_column_anchor.ajax").die("click");$("button.change_columns_anchor.ajax, input.change_columns_anchor.ajax").die("click");$("a.drop_column_anchor.ajax").die("click");$("a.add_primary_key_anchor.ajax").die("click");$("#move_columns_anchor").die("click");$(".append_fields_form.ajax").unbind("submit")});AJAX.registerOnload("tbl_structure.js",function(){$(".append_fields_form.ajax").die().live("submit",function(b){b.preventDefault();var a=$(this);if(checkTableEditForm(a[0],a.find("input[name=orig_num_fields]").val())){PMA_prepareForAjaxRequest(a);$msg=PMA_ajaxShowMessage();$.post(a.attr("action"),a.serialize()+"&do_save_data=1",function(c){if($("#sqlqueryresults").length!=0){$("#sqlqueryresults").remove()}else{if($(".error:not(.tab)").length!=0){$(".error:not(.tab)").remove()}}if(c.success==true){$("#page_content").empty().append(c.message).append(c.sql_query).show();$("#result_query .notice").remove();a.remove();PMA_ajaxRemoveMessage($msg);PMA_reloadNavigation()}else{PMA_ajaxShowMessage(c.error,false)}})}});$("a.change_column_anchor.ajax").live("click",function(b){b.preventDefault();var a=PMA_ajaxShowMessage();$("#page_content").hide();$.get($(this).attr("href"),{ajax_request:true},function(c){PMA_ajaxRemoveMessage(a);if(c.success){$('
      ').html(c.message).insertBefore("#page_content");PMA_verifyColumnsProperties()}else{PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest+" : "+c.error,false)}})});$("button.change_columns_anchor.ajax, input.change_columns_anchor.ajax").live("click",function(c){c.preventDefault();var a=PMA_ajaxShowMessage();$("#page_content").hide();var b=$(this).closest("form");var d=b.serialize()+"&ajax_request=true&submit_mult=change";$.post(b.prop("action"),d,function(e){PMA_ajaxRemoveMessage(a);if(e.success){$("#page_content").empty().append($('
      ').html(e.message)).show();PMA_verifyColumnsProperties()}else{$("#page_content").show();PMA_ajaxShowMessage(e.error)}})});$("a.drop_column_anchor.ajax").live("click",function(c){c.preventDefault();var f=$(this).closest("form").find("input[name=table]").val();var b=$(this).parents("tr");var d=b.children("th").children("label").text();var e=$("select[name='after_field'] option[value='"+d+"']");var a=$.sprintf(PMA_messages.strDoYouReally,"ALTER TABLE `"+escapeHtml(f)+"` DROP `"+escapeHtml(d)+"`;");$(this).PMA_confirm(a,$(this).attr("href"),function(h){var g=PMA_ajaxShowMessage(PMA_messages.strDroppingColumn,false);$.get(h,{is_js_confirmed:1,ajax_request:true,ajax_page_request:true},function(k){if(k.success==true){PMA_ajaxRemoveMessage(g);if($("#result_query").length){$("#result_query").remove()}if(k.sql_query){$('
      ').html(k.sql_query).prependTo("#page_content")}toggleRowColors(b.next());for(var j=b.next();j.length>0;j=j.next()){var i=parseInt(j.find("td:nth-child(2)").text())-1;j.find("td:nth-child(2)").text(i)}e.remove();b.hide("medium").remove();if(k.tableStat){$("#tablestatistics").html(k.tableStat)}$(".index_info").replaceWith(k.indexes_list);PMA_reloadNavigation()}else{PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest+" : "+k.error,false)}})})});$("a.add_primary_key_anchor.ajax").live("click",function(b){b.preventDefault();var d=$(this).closest("form").find("input[name=table]").val();var c=$(this).parents("tr").children("th").children("label").text();var a=$.sprintf(PMA_messages.strDoYouReally,"ALTER TABLE `"+escapeHtml(d)+"` ADD PRIMARY KEY(`"+escapeHtml(c)+"`);");$(this).PMA_confirm(a,$(this).attr("href"),function(f){var e=PMA_ajaxShowMessage(PMA_messages.strAddingPrimaryKey,false);$.get(f,{is_js_confirmed:1,ajax_request:true},function(g){if(g.success==true){PMA_ajaxRemoveMessage(e);$(this).remove();if(typeof g.reload!="undefined"){PMA_commonActions.refreshMain(false,function(){if($("#result_query").length){$("#result_query").remove()}if(g.sql_query){$('
      ').html(g.sql_query).prependTo("#page_content")}});PMA_reloadNavigation()}}else{PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest+" : "+g.error,false)}})})});$("#move_columns_anchor").live("click",function(g){g.preventDefault();if($(this).hasClass("move-active")){return}var b={};b[PMA_messages.strGo]=function(i){i.preventDefault();var l=PMA_ajaxShowMessage();var k=$(this);var e=k.find("form");var j=e.serialize();if(j==e.data("serialized-unmoved")){PMA_ajaxRemoveMessage(l);k.dialog("close");return}$.post(e.prop("action"),j+"&ajax_request=true",function(t){if(t.success==false){PMA_ajaxRemoveMessage(l);k.clone().html(t.error).dialog({title:$(this).prop("title"),height:230,width:900,modal:true,buttons:f})}else{$("#fieldsForm ul.table-structure-actions").menuResizer("destroy");var o=$("table#tablestructure tbody");var q=o.find("tr").remove();for(var r in t.columns){var s=t.columns[r];var p=q.find("input:checkbox[value="+s+"]").closest("tr");o.append(p)}var n=o.find("tr").eq(0);for(var m=n;m.length>0;m=m.next()){m.find("td:nth-child(2)").text(m.index()+1).end().removeClass("odd even").addClass(m.index()%2==0?"odd":"even")}PMA_ajaxShowMessage(t.message);k.dialog("close");$("#fieldsForm ul.table-structure-actions").menuResizer(PMA_tbl_structure_menu_resizer_callback)}})};b[PMA_messages.strCancel]=function(){$(this).dialog("close")};var f={};f[PMA_messages.strOK]=function(){$(this).dialog("close").remove()};var d=[];$("#tablestructure tbody tr").each(function(){var i=$(this).find("input:checkbox").eq(0).val();var e=$("").prop({name:"move_columns[]",type:"hidden"}).val(i);d[d.length]=$("
    • ").addClass("placeholderDrag").text(i).append(e)});var h=$("#move_columns_dialog ul").find("li").remove().end();for(var c in d){h.append(d[c])}h.sortable({axis:"y",containment:$("#move_columns_dialog div")}).disableSelection();var a=$("#move_columns_dialog form");a.data("serialized-unmoved",a.serialize());$("#move_columns_dialog").dialog({modal:true,buttons:b,beforeClose:function(){$("#move_columns_anchor").removeClass("move-active")}})})});function reloadFieldForm(a){$.post($("#fieldsForm").attr("action"),$("#fieldsForm").serialize()+"&ajax_request=true",function(c){var b=$("
      ").append(c.message);$("#fieldsForm").replaceWith(b.find("#fieldsForm"));$("#addColumns").replaceWith(b.find("#addColumns"));$("#move_columns_dialog ul").replaceWith(b.find("#move_columns_dialog ul"));$("#moveColumns").removeClass("move-active");$("#fieldsForm ul.table-structure-actions").menuResizer(PMA_tbl_structure_menu_resizer_callback);setTimeout(function(){PMA_ajaxShowMessage(a)},500)});$("#page_content").show()}function PMA_tbl_structure_menu_resizer_callback(){var c=$("body").width();var b=$("#page_content");c-=b.outerWidth(true)-b.outerWidth();var d=0;var a=$("#tablestructure").find("tr:eq(1)").find("td,th");a.not(":last").each(function(){d+=$(this).outerWidth(true)});var e=$("#tablestructure").width();a.each(function(){e-=$(this).outerWidth(true)});return c-d-e-15}AJAX.registerOnload("tbl_structure.js",function(){if($("#fieldsForm").hasClass("HideStructureActions")){$("#fieldsForm ul.table-structure-actions").menuResizer(PMA_tbl_structure_menu_resizer_callback)}});AJAX.registerTeardown("tbl_structure.js",function(){$("#fieldsForm ul.table-structure-actions").menuResizer("destroy")});$(function(){$(window).resize($.throttle(function(){var a=$("#fieldsForm ul.table-structure-actions");if(a.length){a.menuResizer("resize")}}))}); \ No newline at end of file diff --git a/phpmyadmin/js/tbl_zoom_plot_jqplot.js b/phpmyadmin/js/tbl_zoom_plot_jqplot.js new file mode 100644 index 000000000..dffee4621 --- /dev/null +++ b/phpmyadmin/js/tbl_zoom_plot_jqplot.js @@ -0,0 +1 @@ +function displayHelp(){PMA_ajaxShowMessage(PMA_messages.strDisplayHelp,10000)}Array.max=function(a){return Math.max.apply(Math,a)};Array.min=function(a){return Math.min.apply(Math,a)};function isNumeric(a){return !isNaN(parseFloat(a))&&isFinite(a)}function isEmpty(b){var a;for(a in b){return false}return true}function getTimeStamp(b,a){if(a.toString().search(/datetime/i)!=-1||a.toString().search(/timestamp/i)!=-1){return getDateFromFormat(b,"yyyy-MM-dd HH:mm:ss")}else{if(a.toString().search(/time/i)!=-1){return getDateFromFormat("1970-01-01 "+b,"yyyy-MM-dd HH:mm:ss")}else{if(a.toString().search(/date/i)!=-1){return getDateFromFormat(b,"yyyy-MM-dd")}}}}function getType(a){if(a.toString().search(/int/i)!=-1||a.toString().search(/decimal/i)!=-1||a.toString().search(/year/i)!=-1){return"numeric"}else{if(a.toString().search(/time/i)!=-1||a.toString().search(/date/i)!=-1){return"time"}else{return"text"}}}function getCord(b){var a=[];var c=$.extend(true,[],b);var b=jQuery.unique(b).sort();$.each(c,function(d,e){a.push(jQuery.inArray(e,b))});return[a,b,c]}function scrollToChart(){var a=$("#dataDisplay").offset().top-100;$("html,body").animate({scrollTop:a},500)}AJAX.registerTeardown("tbl_zoom_plot_jqplot.js",function(){$("#tableid_0").unbind("change");$("#tableid_1").unbind("change");$("#tableid_2").unbind("change");$("#tableid_3").unbind("change");$("#inputFormSubmitId").unbind("click");$("#togglesearchformlink").unbind("click");$("#dataDisplay").find(":input").die("keydown");$("button.button-reset").unbind("click");$("div#resizer").unbind("resizestop");$("div#querychart").unbind("jqplotDataClick")});AJAX.registerOnload("tbl_zoom_plot_jqplot.js",function(){var C=($("input[name='mode']:checked").val()=="edit")?"crosshair":"pointer";var m=null;var e=null;var p=$("#tableid_0").val();var s=$("#tableid_1").val();var r=$("#types_0").val();var d=$("#types_1").val();var b=$("#dataLabel").val();var n;var l;var A=1;var t=jQuery.parseJSON($("#querydata").html());$("#tableid_0").change(function(){$.post("tbl_zoom_select.php",{ajax_request:true,change_tbl_info:true,db:PMA_commonParams.get("db"),table:PMA_commonParams.get("table"),field:$("#tableid_0").val(),it:0,token:PMA_commonParams.get("token")},function(D){$("#tableFieldsId tr:eq(1) td:eq(0)").html(D.field_type);$("#tableFieldsId tr:eq(1) td:eq(1)").html(D.field_collation);$("#tableFieldsId tr:eq(1) td:eq(2)").html(D.field_operators);$("#tableFieldsId tr:eq(1) td:eq(3)").html(D.field_value);p=$("#tableid_0").val();$("#types_0").val(D.field_type);r=D.field_type;$("#collations_0").val(D.field_collations);addDateTimePicker()})});$("#tableid_1").change(function(){$.post("tbl_zoom_select.php",{ajax_request:true,change_tbl_info:true,db:PMA_commonParams.get("db"),table:PMA_commonParams.get("table"),field:$("#tableid_1").val(),it:1,token:PMA_commonParams.get("token")},function(D){$("#tableFieldsId tr:eq(3) td:eq(0)").html(D.field_type);$("#tableFieldsId tr:eq(3) td:eq(1)").html(D.field_collation);$("#tableFieldsId tr:eq(3) td:eq(2)").html(D.field_operators);$("#tableFieldsId tr:eq(3) td:eq(3)").html(D.field_value);s=$("#tableid_1").val();$("#types_1").val(D.field_type);d=D.field_type;$("#collations_1").val(D.field_collations);addDateTimePicker()})});$("#tableid_2").change(function(){$.post("tbl_zoom_select.php",{ajax_request:true,change_tbl_info:true,db:PMA_commonParams.get("db"),table:PMA_commonParams.get("table"),field:$("#tableid_2").val(),it:2,token:PMA_commonParams.get("token")},function(D){$("#tableFieldsId tr:eq(6) td:eq(0)").html(D.field_type);$("#tableFieldsId tr:eq(6) td:eq(1)").html(D.field_collation);$("#tableFieldsId tr:eq(6) td:eq(2)").html(D.field_operators);$("#tableFieldsId tr:eq(6) td:eq(3)").html(D.field_value);$("#types_2").val(D.field_type);$("#collations_2").val(D.field_collations);addDateTimePicker()})});$("#tableid_3").change(function(){$.post("tbl_zoom_select.php",{ajax_request:true,change_tbl_info:true,db:PMA_commonParams.get("db"),table:PMA_commonParams.get("table"),field:$("#tableid_3").val(),it:3,token:PMA_commonParams.get("token")},function(D){$("#tableFieldsId tr:eq(8) td:eq(0)").html(D.field_type);$("#tableFieldsId tr:eq(8) td:eq(1)").html(D.field_collation);$("#tableFieldsId tr:eq(8) td:eq(2)").html(D.field_operators);$("#tableFieldsId tr:eq(8) td:eq(3)").html(D.field_value);$("#types_3").val(D.field_type);$("#collations_3").val(D.field_collations);addDateTimePicker()})});$("#inputFormSubmitId").click(function(){if($("#tableid_0").get(0).selectedIndex==0||$("#tableid_1").get(0).selectedIndex==0){PMA_ajaxShowMessage(PMA_messages.strInputNull)}else{if(p==s){PMA_ajaxShowMessage(PMA_messages.strSameInputs)}}});$('
      ').insertAfter("#zoom_search_form").hide();$("#togglesearchformlink").html(PMA_messages.strShowSearchCriteria).bind("click",function(){var D=$(this);$("#zoom_search_form").slideToggle();if(D.text()==PMA_messages.strHideSearchCriteria){D.text(PMA_messages.strShowSearchCriteria)}else{D.text(PMA_messages.strHideSearchCriteria)}return false});var h={};h[PMA_messages.strSave]=function(){var N={};var D={};var G=0;var M=false;var F=false;var L;for(L in z){var K=z[L];var E=($("#edit_fields_null_id_"+G).prop("checked"))?null:$("#edit_fieldID_"+G).val();if(E instanceof Array){E=$("#edit_fieldID_"+G).map(function(){return $(this).val()}).get().join(",")}if(K!=E){z[L]=E;N[L]=E;if(L==p){M=true;t[e][p]=E}else{if(L==s){F=true;t[e][s]=E}}}var H=$("#edit_fieldID_"+G);if(H.hasClass("bit")){D[L]="bit"}G++}if(M||F){if(M){f[e]=z[p];if(r=="numeric"){q[0][e][0]=z[p]}else{if(r=="time"){q[0][e][0]=getTimeStamp(z[p],$("#types_0").val())}else{}}m.series[0].data=q[0];m.replot()}if(F){v[e]=z[s];if(d=="numeric"){q[0][e][1]=z[s]}else{if(d=="time"){q[0][e][1]=getTimeStamp(z[s],$("#types_1").val())}else{}}m.series[0].data=q[0];m.replot()}}if(!isEmpty(N)){var I="UPDATE `"+PMA_commonParams.get("table")+"` SET ";for(L in N){I+="`"+L+"`=";var J=N[L];if(J==null){I+="NULL, "}else{if($.trim(J)==""){I+="'', "}else{if(D[L]!=null){if(D[L]=="bit"){I+="b'"+J+"', "}}else{if(!isNumeric(J)){I+="'"+J+"', "}else{I+=J+", "}}}}}I=I.substring(0,I.length-2);I+=" WHERE "+PMA_urldecode(t[e]["where_clause"]);$.post("sql.php",{token:PMA_commonParams.get("token"),db:PMA_commonParams.get("db"),ajax_request:true,sql_query:I,inline_edit:false},function(O){if(O.success==true){$("#sqlqueryresults").html(O.sql_query);$("#sqlqueryresults").trigger("appendAnchor")}else{PMA_ajaxShowMessage(O.error,false)}})}$("#dataDisplay").dialog("close")};h[PMA_messages.strCancel]=function(){$(this).dialog("close")};$("#dataDisplay").dialog({autoOpen:false,title:PMA_messages.strDataPointContent,modal:true,buttons:h,width:$("#dataDisplay").width()+80,open:function(){$(this).find("input[type=checkbox]").css("margin","0.5em")}});$("#dataDisplay").find(":input").live("keydown",function(D){if(D.which===13){D.preventDefault();if(typeof h[PMA_messages.strSave]==="function"){h[PMA_messages.strSave].call()}}});if(t!=null){$("#zoom_search_form").slideToggle().hide();$("#togglesearchformlink").text(PMA_messages.strShowSearchCriteria);$("#togglesearchformdiv").show();var z;var x=["#FF0000","#00FFFF","#0000FF","#0000A0","#FF0080","#800080","#FFFF00","#00FF00","#FF00FF"];var q=[];var f=[];var v=[];var i,g;var k=0;var B;var y;var c;var a;var j={series:[{showLine:false}],grid:{drawBorder:false,shadow:false,background:"rgba(0,0,0,0)"},axes:{xaxis:{label:$("#tableid_0").val(),labelRenderer:$.jqplot.CanvasAxisLabelRenderer},yaxis:{label:$("#tableid_1").val(),labelRenderer:$.jqplot.CanvasAxisLabelRenderer}},highlighter:{show:true,tooltipAxes:"y",yvalues:2,formatString:'%s%s'},cursor:{show:true,zoom:true,showTooltip:false}};if(b==""){j.highlighter.show=false}r=getType(r);d=getType(d);q[0]=[];if(r=="time"){var u=$("#types_0").val();var w;if(u=="date"){w="%Y-%m-%d"}$.extend(j.axes.xaxis,{renderer:$.jqplot.DateAxisRenderer,tickOptions:{formatString:w}})}if(d=="time"){var o=$("#types_1").val();var w;if(o=="date"){w="%Y-%m-%d"}$.extend(j.axes.yaxis,{renderer:$.jqplot.DateAxisRenderer,tickOptions:{formatString:w}})}$.each(t,function(D,F){if(r=="numeric"){var G=parseFloat(F[p])}if(r=="time"){var G=getTimeStamp(F[p],u)}if(d=="numeric"){var E=parseFloat(F[s])}if(d=="time"){var E=getTimeStamp(F[s],o)}q[0].push([G,E,F[b],F.where_clause,D])});m=$.jqplot("querychart",q,j);m.resetZoom();$("button.button-reset").click(function(D){D.preventDefault();m.resetZoom()});$("div#resizer").resizable();$("div#resizer").bind("resizestop",function(D,E){$("div#querychart").height($("div#resizer").height()*0.96);$("div#querychart").width($("div#resizer").width()*0.96);m.replot({resetAxes:true})});$("div#querychart").bind("jqplotDataClick",function(H,D,G,I){e=I[4];var F=0;var E={ajax_request:true,get_data_row:true,db:PMA_commonParams.get("db"),table:PMA_commonParams.get("table"),where_clause:I[3],token:PMA_commonParams.get("token")};$.post("tbl_zoom_select.php",E,function(K){var J;for(J in K.row_info){$field=$("#edit_fieldID_"+F);$field_null=$("#edit_fields_null_id_"+F);if(K.row_info[J]==null){$field_null.prop("checked",true);$field.val("")}else{$field_null.prop("checked",false);if($field.attr("multiple")){$field.val(K.row_info[J].split(","))}else{$field.val(K.row_info[J])}}F++}z={};z=K.row_info});$("#dataDisplay").dialog("open")})}}); \ No newline at end of file diff --git a/phpmyadmin/libraries/.htaccess b/phpmyadmin/libraries/.htaccess new file mode 100644 index 000000000..56baee608 --- /dev/null +++ b/phpmyadmin/libraries/.htaccess @@ -0,0 +1,3 @@ +# This folder does not require access over HTTP +# (the following directive denies access by default) +Order allow,deny diff --git a/phpmyadmin/libraries/Advisor.class.php b/phpmyadmin/libraries/Advisor.class.php new file mode 100644 index 000000000..91c8bf2be --- /dev/null +++ b/phpmyadmin/libraries/Advisor.class.php @@ -0,0 +1,509 @@ +variables = array_merge( + PMA_DBI_fetch_result('SHOW GLOBAL STATUS', 0, 1), + PMA_DBI_fetch_result('SHOW GLOBAL VARIABLES', 0, 1) + ); + if (PMA_DRIZZLE) { + $this->variables = array_merge( + $this->variables, + PMA_DBI_fetch_result( + "SELECT concat('Com_', variable_name), variable_value + FROM data_dictionary.GLOBAL_STATEMENTS", 0, 1 + ) + ); + } + // Add total memory to variables as well + include_once 'libraries/sysinfo.lib.php'; + $sysinfo = PMA_getSysInfo(); + $memory = $sysinfo->memory(); + $this->variables['system_memory'] = $memory['MemTotal']; + + // Step 2: Read and parse the list of rules + $this->parseResult = $this->parseRulesFile(); + // Step 3: Feed the variables to the rules and let them fire. Sets + // $runResult + $this->runRules(); + + return array( + 'parse' => array('errors' => $this->parseResult['errors']), + 'run' => $this->runResult + ); + } + + /** + * Stores current error in run results. + * + * @param string $description description of an error. + * @param object $exception exception raised + * + * @return void + */ + function storeError($description, $exception) + { + $this->runResult['errors'][] = $description + . ' ' + . sprintf(__('PHP threw following error: %s'), $exception->getMessage()); + } + + /** + * Executes advisor rules + * + * @return void + */ + function runRules() + { + $this->runResult = array( + 'fired' => array(), + 'notfired' => array(), + 'unchecked'=> array(), + 'errors' => array() + ); + + foreach ($this->parseResult['rules'] as $rule) { + $this->variables['value'] = 0; + $precond = true; + + if (isset($rule['precondition'])) { + try { + $precond = $this->ruleExprEvaluate($rule['precondition']); + } catch (Exception $e) { + $this->storeError( + sprintf( + __('Failed evaluating precondition for rule \'%s\''), + $rule['name'] + ), + $e + ); + continue; + } + } + + if (! $precond) { + $this->addRule('unchecked', $rule); + } else { + try { + $value = $this->ruleExprEvaluate($rule['formula']); + } catch(Exception $e) { + $this->storeError( + sprintf( + __('Failed calculating value for rule \'%s\''), + $rule['name'] + ), + $e + ); + continue; + } + + $this->variables['value'] = $value; + + try { + if ($this->ruleExprEvaluate($rule['test'])) { + $this->addRule('fired', $rule); + } else { + $this->addRule('notfired', $rule); + } + } catch(Exception $e) { + $this->storeError( + sprintf( + __('Failed running test for rule \'%s\''), + $rule['name'] + ), + $e + ); + } + } + } + + return true; + } + + /** + * Escapes percent string to be used in format string. + * + * @param string $str string to escape + * + * @return string + */ + static function escapePercent($str) + { + return preg_replace('/%( |,|\.|$|\(|\)|<|>)/', '%%\1', $str); + } + + /** + * Wrapper function for translating. + * + * @param string $str the string + * @param mixed $param the parameters + * + * @return string + */ + function translate($str, $param = null) + { + if (is_null($param)) { + return sprintf(_gettext(Advisor::escapePercent($str))); + } else { + $printf = 'sprintf("' . _gettext(Advisor::escapePercent($str)) . '",'; + return $this->ruleExprEvaluate( + $printf . $param . ')', + strlen($printf) + ); + } + } + + /** + * Splits justification to text and formula. + * + * @param string $rule the rule + * + * @return array + */ + static function splitJustification($rule) + { + $jst = preg_split('/\s*\|\s*/', $rule['justification'], 2); + if (count($jst) > 1) { + return array($jst[0], $jst[1]); + } + return array($rule['justification']); + } + + /** + * Adds a rule to the result list + * + * @param string $type type of rule + * @param array $rule rule itslef + * + * @return void + */ + function addRule($type, $rule) + { + switch($type) { + case 'notfired': + case 'fired': + $jst = Advisor::splitJustification($rule); + if (count($jst) > 1) { + try { + /* Translate */ + $str = $this->translate($jst[0], $jst[1]); + } catch (Exception $e) { + $this->storeError( + sprintf( + __('Failed formatting string for rule \'%s\'.'), + $rule['name'] + ), + $e + ); + return; + } + + $rule['justification'] = $str; + } else { + $rule['justification'] = $this->translate($rule['justification']); + } + $rule['id'] = $rule['name']; + $rule['name'] = $this->translate($rule['name']); + $rule['issue'] = $this->translate($rule['issue']); + + // Replaces {server_variable} with 'server_variable' + // linking to server_variables.php + $rule['recommendation'] = preg_replace( + '/\{([a-z_0-9]+)\}/Ui', + '\1', + $this->translate($rule['recommendation']) + ); + + // Replaces external Links with PMA_linkURL() generated links + $rule['recommendation'] = preg_replace_callback( + '#href=("|\')(https?://[^\1]+)\1#i', + array($this, '_replaceLinkURL'), + $rule['recommendation'] + ); + break; + } + + $this->runResult[$type][] = $rule; + } + + /** + * Callback for wrapping links with PMA_linkURL + * + * @param array $matches List of matched elements form preg_replace_callback + * + * @return Replacement value + */ + private function _replaceLinkURL($matches) + { + return 'href="' . PMA_linkURL($matches[2]) . '"'; + } + + /** + * Callback for evaluating fired() condition. + * + * @param array $matches List of matched elements form preg_replace_callback + * + * @return Replacement value + */ + private function _ruleExprEvaluateFired($matches) + { + // No list of fired rules + if (!isset($this->runResult['fired'])) { + return '0'; + } + + // Did matching rule fire? + foreach ($this->runResult['fired'] as $rule) { + if ($rule['id'] == $matches[2]) { + return '1'; + } + } + + return '0'; + } + + /** + * Callback for evaluating variables in expression. + * + * @param array $matches List of matched elements form preg_replace_callback + * + * @return Replacement value + */ + private function _ruleExprEvaluateVariable($matches) + { + return isset($this->variables[$matches[1]]) + ? (is_numeric($this->variables[$matches[1]]) + ? $this->variables[$matches[1]] + : '"'.$this->variables[$matches[1]].'"') + : $matches[1]; + } + + /** + * Runs a code expression, replacing variable names with their respective + * values + * + * @param string $expr expression to evaluate + * @param int $ignoreUntil if > 0, it doesn't replace any variables until + * that string position, but still evaluates the + * whole expr + * + * @return result of evaluated expression + */ + function ruleExprEvaluate($expr, $ignoreUntil = 0) + { + if ($ignoreUntil > 0) { + $exprIgnore = substr($expr, 0, $ignoreUntil); + $expr = substr($expr, $ignoreUntil); + } + // Evaluate fired() conditions + $expr = preg_replace_callback( + '/fired\s*\(\s*(\'|")(.*)\1\s*\)/Ui', + array($this, '_ruleExprEvaluateFired'), + $expr + ); + // Evaluate variables + $expr = preg_replace_callback( + '/\b(\w+)\b/', + array($this, '_ruleExprEvaluateVariable'), + $expr + ); + if ($ignoreUntil > 0) { + $expr = $exprIgnore . $expr; + } + $value = 0; + $err = 0; + + // Actually evaluate the code + ob_start(); + eval('$value = ' . $expr . ';'); + $err = ob_get_contents(); + ob_end_clean(); + + // Error handling + if ($err) { + throw new Exception( + strip_tags($err) . '
      Executed code: $value = ' . htmlspecialchars($expr) . ';' + ); + } + return $value; + } + + /** + * Reads the rule file into an array, throwing errors messages on syntax + * errors. + * + * @return array with parsed data + */ + static function parseRulesFile() + { + $file = file('libraries/advisory_rules.txt', FILE_IGNORE_NEW_LINES); + $errors = array(); + $rules = array(); + $lines = array(); + $ruleSyntax = array( + 'name', 'formula', 'test', 'issue', 'recommendation', 'justification' + ); + $numRules = count($ruleSyntax); + $numLines = count($file); + $ruleNo = -1; + $ruleLine = -1; + + for ($i = 0; $i < $numLines; $i++) { + $line = $file[$i]; + if ($line == "" || $line[0] == '#') { + continue; + } + + // Reading new rule + if (substr($line, 0, 4) == 'rule') { + if ($ruleLine > 0) { + $errors[] = sprintf( + __('Invalid rule declaration on line %1$s, expected line %2$s of previous rule'), + $i + 1, + $ruleSyntax[$ruleLine++] + ); + continue; + } + if (preg_match("/rule\s'(.*)'( \[(.*)\])?$/", $line, $match)) { + $ruleLine = 1; + $ruleNo++; + $rules[$ruleNo] = array('name' => $match[1]); + $lines[$ruleNo] = array('name' => $i + 1); + if (isset($match[3])) { + $rules[$ruleNo]['precondition'] = $match[3]; + $lines[$ruleNo]['precondition'] = $i + 1; + } + } else { + $errors[] = sprintf( + __('Invalid rule declaration on line %s'), + $i + 1 + ); + } + continue; + } else { + if ($ruleLine == -1) { + $errors[] = sprintf( + __('Unexpected characters on line %s'), + $i + 1 + ); + } + } + + // Reading rule lines + if ($ruleLine > 0) { + if (!isset($line[0])) { + continue; // Empty lines are ok + } + // Non tabbed lines are not + if ($line[0] != "\t") { + $errors[] = sprintf( + __('Unexpected character on line %1$s. Expected tab, but found "%2$s"'), + $i + 1, + $line[0] + ); + continue; + } + $rules[$ruleNo][$ruleSyntax[$ruleLine]] = chop(substr($line, 1)); + $lines[$ruleNo][$ruleSyntax[$ruleLine]] = $i + 1; + $ruleLine += 1; + } + + // Rule complete + if ($ruleLine == $numRules) { + $ruleLine = -1; + } + } + + return array('rules' => $rules, 'lines' => $lines, 'errors' => $errors); + } +} + +/** + * Formats interval like 10 per hour + * + * @param integer $num number to format + * @param intefer $precision required precision + * + * @return formatted string + */ +function ADVISOR_bytime($num, $precision) +{ + $per = ''; + if ($num >= 1) { // per second + $per = __('per second'); + } elseif ($num * 60 >= 1) { // per minute + $num = $num * 60; + $per = __('per minute'); + } elseif ($num * 60 * 60 >= 1 ) { // per hour + $num = $num * 60 * 60; + $per = __('per hour'); + } else { + $num = $num * 60 * 60 * 24; + $per = __('per day'); + } + + $num = round($num, $precision); + + if ($num == 0) { + $num = '<' . PMA_Util::pow(10, -$precision); + } + + return "$num $per"; +} + +/** + * Wrapper for PMA_Util::timespanFormat + * + * @param int $seconds the timespan + * + * @return string the formatted value + */ +function ADVISOR_timespanFormat($seconds) +{ + return PMA_Util::timespanFormat($seconds); +} + +/** + * Wrapper around PMA_Util::formatByteDown + * + * @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 + */ +function ADVISOR_formatByteDown($value, $limes = 6, $comma = 0) +{ + return PMA_Util::formatByteDown($value, $limes, $comma); +} + +?> diff --git a/phpmyadmin/libraries/Config.class.php b/phpmyadmin/libraries/Config.class.php new file mode 100644 index 000000000..57b643ea3 --- /dev/null +++ b/phpmyadmin/libraries/Config.class.php @@ -0,0 +1,1829 @@ +settings = array(); + + // functions need to refresh in case of config file changed goes in + // PMA_Config::load() + $this->load($source); + + // other settings, independent from config file, comes in + $this->checkSystem(); + + $this->checkIsHttps(); + } + + /** + * sets system and application settings + * + * @return void + */ + function checkSystem() + { + $this->set('PMA_VERSION', '4.0.4'); + /** + * @deprecated + */ + $this->set('PMA_THEME_VERSION', 2); + /** + * @deprecated + */ + $this->set('PMA_THEME_GENERATION', 2); + + $this->checkPhpVersion(); + $this->checkWebServerOs(); + $this->checkWebServer(); + $this->checkGd2(); + $this->checkClient(); + $this->checkUpload(); + $this->checkUploadSize(); + $this->checkOutputCompression(); + } + + /** + * whether to use gzip output compression or not + * + * @return void + */ + function checkOutputCompression() + { + // If zlib output compression is set in the php configuration file, no + // output buffering should be run + if (@ini_get('zlib.output_compression')) { + $this->set('OBGzip', false); + } + + // disable output-buffering (if set to 'auto') for IE6, else enable it. + if (strtolower($this->get('OBGzip')) == 'auto') { + if ($this->get('PMA_USR_BROWSER_AGENT') == 'IE' + && $this->get('PMA_USR_BROWSER_VER') >= 6 + && $this->get('PMA_USR_BROWSER_VER') < 7 + ) { + $this->set('OBGzip', false); + } else { + $this->set('OBGzip', true); + } + } + } + + /** + * Determines platform (OS), browser and version of the user + * Based on a phpBuilder article: + * + * @see http://www.phpbuilder.net/columns/tim20000821.php + * + * @return void + */ + function checkClient() + { + if (PMA_getenv('HTTP_USER_AGENT')) { + $HTTP_USER_AGENT = PMA_getenv('HTTP_USER_AGENT'); + } else { + $HTTP_USER_AGENT = ''; + } + + // 1. Platform + if (strstr($HTTP_USER_AGENT, 'Win')) { + $this->set('PMA_USR_OS', 'Win'); + } elseif (strstr($HTTP_USER_AGENT, 'Mac')) { + $this->set('PMA_USR_OS', 'Mac'); + } elseif (strstr($HTTP_USER_AGENT, 'Linux')) { + $this->set('PMA_USR_OS', 'Linux'); + } elseif (strstr($HTTP_USER_AGENT, 'Unix')) { + $this->set('PMA_USR_OS', 'Unix'); + } elseif (strstr($HTTP_USER_AGENT, 'OS/2')) { + $this->set('PMA_USR_OS', 'OS/2'); + } else { + $this->set('PMA_USR_OS', 'Other'); + } + + // 2. browser and version + // (must check everything else before Mozilla) + + if (preg_match( + '@Opera(/| )([0-9].[0-9]{1,2})@', + $HTTP_USER_AGENT, + $log_version + )) { + $this->set('PMA_USR_BROWSER_VER', $log_version[2]); + $this->set('PMA_USR_BROWSER_AGENT', 'OPERA'); + } elseif (preg_match( + '@MSIE ([0-9].[0-9]{1,2})@', + $HTTP_USER_AGENT, + $log_version + )) { + $this->set('PMA_USR_BROWSER_VER', $log_version[1]); + $this->set('PMA_USR_BROWSER_AGENT', 'IE'); + } elseif (preg_match( + '@OmniWeb/([0-9].[0-9]{1,2})@', + $HTTP_USER_AGENT, + $log_version + )) { + $this->set('PMA_USR_BROWSER_VER', $log_version[1]); + $this->set('PMA_USR_BROWSER_AGENT', 'OMNIWEB'); + // Konqueror 2.2.2 says Konqueror/2.2.2 + // Konqueror 3.0.3 says Konqueror/3 + } elseif (preg_match( + '@(Konqueror/)(.*)(;)@', + $HTTP_USER_AGENT, + $log_version + )) { + $this->set('PMA_USR_BROWSER_VER', $log_version[2]); + $this->set('PMA_USR_BROWSER_AGENT', 'KONQUEROR'); + // must check Chrome before Safari + } elseif (preg_match( + '@Mozilla/([0-9].[0-9]{1,2})@', + $HTTP_USER_AGENT, + $log_version) + && preg_match('@Chrome/([0-9]*)@', $HTTP_USER_AGENT, $log_version2) + ) { + $this->set('PMA_USR_BROWSER_VER', $log_version[1] . '.' . $log_version2[1]); + $this->set('PMA_USR_BROWSER_AGENT', 'CHROME'); + // newer Safari + } elseif (preg_match( + '@Mozilla/([0-9].[0-9]{1,2})@', + $HTTP_USER_AGENT, + $log_version) + && preg_match('@Version/(.*) Safari@', $HTTP_USER_AGENT, $log_version2) + ) { + $this->set( + 'PMA_USR_BROWSER_VER', $log_version2[1] + ); + $this->set('PMA_USR_BROWSER_AGENT', 'SAFARI'); + // older Safari + } elseif (preg_match( + '@Mozilla/([0-9].[0-9]{1,2})@', + $HTTP_USER_AGENT, + $log_version) + && preg_match('@Safari/([0-9]*)@', $HTTP_USER_AGENT, $log_version2) + ) { + $this->set( + 'PMA_USR_BROWSER_VER', $log_version[1] . '.' . $log_version2[1] + ); + $this->set('PMA_USR_BROWSER_AGENT', 'SAFARI'); + } elseif (preg_match('@rv:1.9(.*)Gecko@', $HTTP_USER_AGENT)) { + $this->set('PMA_USR_BROWSER_VER', '1.9'); + $this->set('PMA_USR_BROWSER_AGENT', 'GECKO'); + } elseif (preg_match('@Mozilla/([0-9].[0-9]{1,2})@', $HTTP_USER_AGENT, $log_version)) { + $this->set('PMA_USR_BROWSER_VER', $log_version[1]); + $this->set('PMA_USR_BROWSER_AGENT', 'MOZILLA'); + } else { + $this->set('PMA_USR_BROWSER_VER', 0); + $this->set('PMA_USR_BROWSER_AGENT', 'OTHER'); + } + } + + /** + * Whether GD2 is present + * + * @return void + */ + function checkGd2() + { + if ($this->get('GD2Available') == 'yes') { + $this->set('PMA_IS_GD2', 1); + } elseif ($this->get('GD2Available') == 'no') { + $this->set('PMA_IS_GD2', 0); + } else { + if (!@function_exists('imagecreatetruecolor')) { + $this->set('PMA_IS_GD2', 0); + } else { + if (@function_exists('gd_info')) { + $gd_nfo = gd_info(); + if (strstr($gd_nfo["GD Version"], '2.')) { + $this->set('PMA_IS_GD2', 1); + } else { + $this->set('PMA_IS_GD2', 0); + } + } else { + $this->set('PMA_IS_GD2', 0); + } + } + } + } + + /** + * Whether the Web server php is running on is IIS + * + * @return void + */ + function checkWebServer() + { + // some versions return Microsoft-IIS, some Microsoft/IIS + // we could use a preg_match() but it's slower + if (PMA_getenv('SERVER_SOFTWARE') + && stristr(PMA_getenv('SERVER_SOFTWARE'), 'Microsoft') + && stristr(PMA_getenv('SERVER_SOFTWARE'), 'IIS') + ) { + $this->set('PMA_IS_IIS', 1); + } else { + $this->set('PMA_IS_IIS', 0); + } + } + + /** + * Whether the os php is running on is windows or not + * + * @return void + */ + function checkWebServerOs() + { + // Default to Unix or Equiv + $this->set('PMA_IS_WINDOWS', 0); + // If PHP_OS is defined then continue + if (defined('PHP_OS')) { + if (stristr(PHP_OS, 'win')) { + // Is it some version of Windows + $this->set('PMA_IS_WINDOWS', 1); + } elseif (stristr(PHP_OS, 'OS/2')) { + // Is it OS/2 (No file permissions like Windows) + $this->set('PMA_IS_WINDOWS', 1); + } + } + } + + /** + * detects PHP version + * + * @return void + */ + function checkPhpVersion() + { + $match = array(); + if (! preg_match( + '@([0-9]{1,2}).([0-9]{1,2}).([0-9]{1,2})@', + phpversion(), + $match + )) { + preg_match( + '@([0-9]{1,2}).([0-9]{1,2})@', + phpversion(), + $match + ); + } + if (isset($match) && ! empty($match[1])) { + if (! isset($match[2])) { + $match[2] = 0; + } + if (! isset($match[3])) { + $match[3] = 0; + } + $this->set( + 'PMA_PHP_INT_VERSION', + (int) sprintf('%d%02d%02d', $match[1], $match[2], $match[3]) + ); + } else { + $this->set('PMA_PHP_INT_VERSION', 0); + } + $this->set('PMA_PHP_STR_VERSION', phpversion()); + } + + /** + * detects if Git revision + * + * @return boolean + */ + function isGitRevision() + { + // caching + if (isset($_SESSION['is_git_revision'])) { + if ($_SESSION['is_git_revision']) { + $this->set('PMA_VERSION_GIT', 1); + } + return $_SESSION['is_git_revision']; + } + // find out if there is a .git folder + $git_folder = '.git'; + if (! @file_exists($git_folder) + || ! @file_exists($git_folder . '/config') + ) { + $_SESSION['is_git_revision'] = false; + return false; + } + $_SESSION['is_git_revision'] = true; + return true; + } + + /** + * detects Git revision, if running inside repo + * + * @return void + */ + function checkGitRevision() + { + // find out if there is a .git folder + $git_folder = '.git'; + if (! $this->isGitRevision()) { + return; + } + + if (! $ref_head = @file_get_contents($git_folder . '/HEAD')) { + return; + } + $branch = false; + // are we on any branch? + if (strstr($ref_head, '/')) { + $ref_head = substr(trim($ref_head), 5); + if (substr($ref_head, 0, 11) === 'refs/heads/') { + $branch = substr($ref_head, 11); + } else { + $branch = basename($ref_head); + } + + $ref_file = $git_folder . '/' . $ref_head; + if (@file_exists($ref_file)) { + if (! $hash = @file_get_contents($ref_file)) { + return; + } + $hash = trim($hash); + } else { + // deal with packed refs + if (! $packed_refs = @file_get_contents($git_folder . '/packed-refs')) { + return; + } + // split file to lines + $ref_lines = explode("\n", $packed_refs); + foreach ($ref_lines as $line) { + // skip comments + if ($line[0] == '#') { + continue; + } + // parse line + $parts = explode(' ', $line); + // care only about named refs + if (count($parts) != 2) { + continue; + } + // have found our ref? + if ($parts[1] == $ref_head) { + $hash = $parts[0]; + break; + } + } + if (! isset($hash)) { + // Could not find ref + return; + } + } + } else { + $hash = trim($ref_head); + } + + $commit = false; + if ( !isset($_SESSION['PMA_VERSION_COMMITDATA_' . $hash])) { + $git_file_name = $git_folder . '/objects/' . substr($hash, 0, 2) + . '/' . substr($hash, 2); + if (file_exists($git_file_name) ) { + if (! $commit = @file_get_contents($git_file_name)) { + return; + } + $commit = explode("\0", gzuncompress($commit), 2); + $commit = explode("\n", $commit[1]); + $_SESSION['PMA_VERSION_COMMITDATA_' . $hash] = $commit; + } else { + $pack_names = array(); + // work with packed data + if ($packs = @file_get_contents($git_folder . '/objects/info/packs')) { + // File exists. Read it, parse the file to get the names of the + // packs. (to look for them in .git/object/pack directory later) + foreach (explode("\n", $packs) as $line) { + // skip blank lines + if (strlen(trim($line)) == 0) { + continue; + } + // skip non pack lines + if ($line[0] != 'P') { + continue; + } + // parse names + $pack_names[] = substr($line, 2); + } + } else { + // '.git/objects/info/packs' file can be missing + // (atlease in mysGit) + // File missing. May be we can look in the .git/object/pack + // directory for all the .pack files and use that list of + // files instead + $it = new DirectoryIterator($git_folder . '/objects/pack'); + foreach ($it as $file_info) { + $file_name = $file_info->getFilename(); + // if this is a .pack file + if ($file_info->isFile() + && substr($file_name, -5) == '.pack' + ) { + $pack_names[] = $file_name; + } + } + } + $hash = strtolower($hash); + foreach ($pack_names as $pack_name) { + $index_name = str_replace('.pack', '.idx', $pack_name); + + // load index + if (! $index_data = @file_get_contents($git_folder . '/objects/pack/' . $index_name)) { + continue; + } + // check format + if (substr($index_data, 0, 4) != "\377tOc") { + continue; + } + // check version + $version = unpack('N', substr($index_data, 4, 4)); + if ($version[1] != 2) { + continue; + } + // parse fanout table + $fanout = unpack("N*", substr($index_data, 8, 256 * 4)); + + // find where we should search + $firstbyte = intval(substr($hash, 0, 2), 16); + // array is indexed from 1 and we need to get + // previous entry for start + if ($firstbyte == 0) { + $start = 0; + } else { + $start = $fanout[$firstbyte]; + } + $end = $fanout[$firstbyte + 1]; + + // stupid linear search for our sha + $position = $start; + $found = false; + $offset = 8 + (256 * 4); + for ($position = $start; $position < $end; $position++) { + $sha = strtolower( + bin2hex( + substr( + $index_data, $offset + ($position * 20), 20 + ) + ) + ); + if ($sha == $hash) { + $found = true; + break; + } + } + if (! $found) { + continue; + } + // read pack offset + $offset = 8 + (256 * 4) + (24 * $fanout[256]); + $pack_offset = unpack( + 'N', substr($index_data, $offset + ($position * 4), 4) + ); + $pack_offset = $pack_offset[1]; + + // open pack file + $pack_file = fopen( + $git_folder . '/objects/pack/' . $pack_name, 'rb' + ); + if ($pack_file === false) { + continue; + } + // seek to start + fseek($pack_file, $pack_offset); + + // parse header + $header = ord(fread($pack_file, 1)); + $type = ($header >> 4) & 7; + $hasnext = ($header & 128) >> 7; + $size = $header & 0xf; + $offset = 4; + + while ($hasnext) { + $byte = ord(fread($pack_file, 1)); + $size |= ($byte & 0x7f) << $offset; + $hasnext = ($byte & 128) >> 7; + $offset += 7; + } + + // we care only about commit objects + if ($type != 1) { + continue; + } + + // read data + $commit = fread($pack_file, $size); + $commit = gzuncompress($commit); + $commit = explode("\n", $commit); + $_SESSION['PMA_VERSION_COMMITDATA_' . $hash] = $commit; + fclose($pack_file); + } + } + } else { + $commit = $_SESSION['PMA_VERSION_COMMITDATA_' . $hash]; + } + + // check if commit exists in Github + $is_remote_commit = false; + if ($commit !== false + && isset($_SESSION['PMA_VERSION_REMOTECOMMIT_' . $hash]) + ) { + $is_remote_commit = $_SESSION['PMA_VERSION_REMOTECOMMIT_' . $hash]; + } else { + $link = 'https://api.github.com/repos/phpmyadmin/phpmyadmin/git/commits/' + . $hash; + $is_found = $this->checkHTTP($link, !$commit); + switch($is_found) { + case false: + $is_remote_commit = false; + $_SESSION['PMA_VERSION_REMOTECOMMIT_' . $hash] = false; + break; + case null: + // no remote link for now, but don't cache this as Github is down + $is_remote_commit = false; + break; + default: + $is_remote_commit = true; + $_SESSION['PMA_VERSION_REMOTECOMMIT_' . $hash] = true; + if ($commit === false) { + // if no local commit data, try loading from Github + $commit_json = json_decode($is_found); + } + break; + } + } + + $is_remote_branch = false; + if ($is_remote_commit && $branch !== false) { + // check if branch exists in Github + if (isset($_SESSION['PMA_VERSION_REMOTEBRANCH_' . $hash])) { + $is_remote_branch = $_SESSION['PMA_VERSION_REMOTEBRANCH_' . $hash]; + } else { + $link = 'https://api.github.com/repos/phpmyadmin/phpmyadmin' + . '/git/trees/' . $branch; + $is_found = $this->checkHTTP($link); + switch($is_found) { + case true: + $is_remote_branch = true; + $_SESSION['PMA_VERSION_REMOTEBRANCH_' . $hash] = true; + break; + case false: + $is_remote_branch = false; + $_SESSION['PMA_VERSION_REMOTEBRANCH_' . $hash] = false; + break; + case null: + // no remote link for now, but don't cache this as Github is down + $is_remote_branch = false; + break; + } + } + } + + if ($commit !== false) { + $author = array('name' => '', 'email' => '', 'date' => ''); + $committer = array('name' => '', 'email' => '', 'date' => ''); + + do { + $dataline = array_shift($commit); + $datalinearr = explode(' ', $dataline, 2); + $linetype = $datalinearr[0]; + if (in_array($linetype, array('author', 'committer'))) { + $user = $datalinearr[1]; + preg_match('/([^<]+)<([^>]+)> ([0-9]+)( [^ ]+)?/', $user, $user); + $user2 = array( + 'name' => trim($user[1]), + 'email' => trim($user[2]), + 'date' => date('Y-m-d H:i:s', $user[3])); + if (isset($user[4])) { + $user2['date'] .= $user[4]; + } + $$linetype = $user2; + } + } while ($dataline != ''); + $message = trim(implode(' ', $commit)); + + } elseif (isset($commit_json)) { + $author = array( + 'name' => $commit_json->author->name, + 'email' => $commit_json->author->email, + 'date' => $commit_json->author->date); + $committer = array( + 'name' => $commit_json->committer->name, + 'email' => $commit_json->committer->email, + 'date' => $commit_json->committer->date); + $message = trim($commit_json->message); + } else { + return; + } + + $this->set('PMA_VERSION_GIT', 1); + $this->set('PMA_VERSION_GIT_COMMITHASH', $hash); + $this->set('PMA_VERSION_GIT_BRANCH', $branch); + $this->set('PMA_VERSION_GIT_MESSAGE', $message); + $this->set('PMA_VERSION_GIT_AUTHOR', $author); + $this->set('PMA_VERSION_GIT_COMMITTER', $committer); + $this->set('PMA_VERSION_GIT_ISREMOTECOMMIT', $is_remote_commit); + $this->set('PMA_VERSION_GIT_ISREMOTEBRANCH', $is_remote_branch); + } + + /** + * Checks if given URL is 200 or 404, optionally returns data + * + * @param mixed $link curl link + * @param boolean $get_body whether to retrieve body of document + * + * @return test result or data + */ + function checkHTTP($link, $get_body = false) + { + if (! function_exists('curl_init')) { + return null; + } + $ch = curl_init($link); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); + curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); + curl_setopt($ch, CURLOPT_USERAGENT, 'phpMyAdmin/' . PMA_VERSION); + curl_setopt($ch, CURLOPT_TIMEOUT, 5); + $data = @curl_exec($ch); + if ($data === false) { + return null; + } + $ok = 'HTTP/1.1 200 OK'; + $notfound = 'HTTP/1.1 404 Not Found'; + if (substr($data, 0, strlen($ok)) === $ok) { + return $get_body ? substr($data, strpos($data, "\r\n\r\n") + 4) : true; + } elseif (substr($data, 0, strlen($notfound)) === $notfound) { + return false; + } + return null; + } + + /** + * loads default values from default source + * + * @return boolean success + */ + function loadDefaults() + { + $cfg = array(); + if (! file_exists($this->default_source)) { + $this->error_config_default_file = true; + return false; + } + include $this->default_source; + + $this->default_source_mtime = filemtime($this->default_source); + + $this->default_server = $cfg['Servers'][1]; + unset($cfg['Servers']); + + $this->default = $cfg; + $this->settings = PMA_arrayMergeRecursive($this->settings, $cfg); + + $this->error_config_default_file = false; + + return true; + } + + /** + * loads configuration from $source, usally the config file + * should be called on object creation + * + * @param string $source config file + * + * @return bool + */ + function load($source = null) + { + $this->loadDefaults(); + + if (null !== $source) { + $this->setSource($source); + } + + if (! $this->checkConfigSource()) { + return false; + } + + $cfg = array(); + + /** + * Parses the configuration file, the eval is used here to avoid + * problems with trailing whitespace, what is often a problem. + */ + $old_error_reporting = error_reporting(0); + $eval_result = eval('?' . '>' . trim(file_get_contents($this->getSource()))); + error_reporting($old_error_reporting); + + if ($eval_result === false) { + $this->error_config_file = true; + } else { + $this->error_config_file = false; + $this->source_mtime = filemtime($this->getSource()); + } + + /** + * Backward compatibility code + */ + if (!empty($cfg['DefaultTabTable'])) { + $cfg['DefaultTabTable'] = str_replace( + '_properties', + '', + str_replace( + 'tbl_properties.php', + 'tbl_sql.php', + $cfg['DefaultTabTable'] + ) + ); + } + if (!empty($cfg['DefaultTabDatabase'])) { + $cfg['DefaultTabDatabase'] = str_replace( + '_details', + '', + str_replace( + 'db_details.php', + 'db_sql.php', + $cfg['DefaultTabDatabase'] + ) + ); + } + + $this->settings = PMA_arrayMergeRecursive($this->settings, $cfg); + $this->checkPmaAbsoluteUri(); + $this->checkFontsize(); + + // Handling of the collation must be done after merging of $cfg + // (from config.inc.php) so that $cfg['DefaultConnectionCollation'] + // can have an effect. Note that the presence of collation + // information in a cookie has priority over what is defined + // in the default or user's config files. + /** + * @todo check validity of $_COOKIE['pma_collation_connection'] + */ + if (! empty($_COOKIE['pma_collation_connection'])) { + $this->set( + 'collation_connection', + strip_tags($_COOKIE['pma_collation_connection']) + ); + } else { + $this->set( + 'collation_connection', + $this->get('DefaultConnectionCollation') + ); + } + // Now, a collation information could come from REQUEST + // (an example of this: the collation selector in index.php) + // so the following handles the setting of collation_connection + // and later, in common.inc.php, the cookie will be set + // according to this. + $this->checkCollationConnection(); + + return true; + } + + /** + * Loads user preferences and merges them with current config + * must be called after control connection has been estabilished + * + * @return boolean + */ + function loadUserPreferences() + { + // index.php should load these settings, so that phpmyadmin.css.php + // will have everything avaiable in session cache + $server = isset($GLOBALS['server']) + ? $GLOBALS['server'] + : (!empty($GLOBALS['cfg']['ServerDefault']) + ? $GLOBALS['cfg']['ServerDefault'] + : 0); + $cache_key = 'server_' . $server; + if ($server > 0 && !defined('PMA_MINIMUM_COMMON')) { + $config_mtime = max($this->default_source_mtime, $this->source_mtime); + // cache user preferences, use database only when needed + if (! isset($_SESSION['cache'][$cache_key]['userprefs']) + || $_SESSION['cache'][$cache_key]['config_mtime'] < $config_mtime + ) { + // load required libraries + include_once './libraries/user_preferences.lib.php'; + $prefs = PMA_loadUserprefs(); + $_SESSION['cache'][$cache_key]['userprefs'] + = PMA_applyUserprefs($prefs['config_data']); + $_SESSION['cache'][$cache_key]['userprefs_mtime'] = $prefs['mtime']; + $_SESSION['cache'][$cache_key]['userprefs_type'] = $prefs['type']; + $_SESSION['cache'][$cache_key]['config_mtime'] = $config_mtime; + } + } elseif ($server == 0 + || ! isset($_SESSION['cache'][$cache_key]['userprefs']) + ) { + $this->set('user_preferences', false); + return; + } + $config_data = $_SESSION['cache'][$cache_key]['userprefs']; + // type is 'db' or 'session' + $this->set( + 'user_preferences', + $_SESSION['cache'][$cache_key]['userprefs_type'] + ); + $this->set( + 'user_preferences_mtime', + $_SESSION['cache'][$cache_key]['userprefs_mtime'] + ); + + // backup some settings + $org_fontsize = ''; + if (isset($this->settings['fontsize'])) { + $org_fontsize = $this->settings['fontsize']; + } + // load config array + $this->settings = PMA_arrayMergeRecursive($this->settings, $config_data); + $GLOBALS['cfg'] = PMA_arrayMergeRecursive($GLOBALS['cfg'], $config_data); + if (defined('PMA_MINIMUM_COMMON')) { + return; + } + + // settings below start really working on next page load, but + // changes are made only in index.php so everything is set when + // in frames + + // save theme + $tmanager = $_SESSION['PMA_Theme_Manager']; + if ($tmanager->getThemeCookie() || isset($_REQUEST['set_theme'])) { + if ((! isset($config_data['ThemeDefault']) + && $tmanager->theme->getId() != 'original') + || isset($config_data['ThemeDefault']) + && $config_data['ThemeDefault'] != $tmanager->theme->getId() + ) { + // new theme was set in common.inc.php + $this->setUserValue( + null, + 'ThemeDefault', + $tmanager->theme->getId(), + 'original' + ); + } + } else { + // no cookie - read default from settings + if ($this->settings['ThemeDefault'] != $tmanager->theme->getId() + && $tmanager->checkTheme($this->settings['ThemeDefault']) + ) { + $tmanager->setActiveTheme($this->settings['ThemeDefault']); + $tmanager->setThemeCookie(); + } + } + + // save font size + if ((! isset($config_data['fontsize']) + && $org_fontsize != '82%') + || isset($config_data['fontsize']) + && $org_fontsize != $config_data['fontsize'] + ) { + $this->setUserValue(null, 'fontsize', $org_fontsize, '82%'); + } + + // save language + if (isset($_COOKIE['pma_lang']) || isset($_POST['lang'])) { + if ((! isset($config_data['lang']) + && $GLOBALS['lang'] != 'en') + || isset($config_data['lang']) + && $GLOBALS['lang'] != $config_data['lang'] + ) { + $this->setUserValue(null, 'lang', $GLOBALS['lang'], 'en'); + } + } else { + // read language from settings + if (isset($config_data['lang']) && PMA_langSet($config_data['lang'])) { + $this->setCookie('pma_lang', $GLOBALS['lang']); + } + } + + // save connection collation + if (isset($_COOKIE['pma_collation_connection']) + || isset($_POST['collation_connection']) + ) { + if ((! isset($config_data['collation_connection']) + && $GLOBALS['collation_connection'] != 'utf8_general_ci') + || isset($config_data['collation_connection']) + && $GLOBALS['collation_connection'] != $config_data['collation_connection'] + ) { + $this->setUserValue( + null, + 'collation_connection', + $GLOBALS['collation_connection'], + 'utf8_general_ci' + ); + } + } else { + // read collation from settings + if (isset($config_data['collation_connection'])) { + $GLOBALS['collation_connection'] + = $config_data['collation_connection']; + $this->setCookie( + 'pma_collation_connection', + $GLOBALS['collation_connection'] + ); + } + } + } + + /** + * Sets config value which is stored in user preferences (if available) + * or in a cookie. + * + * If user preferences are not yet initialized, option is applied to + * global config and added to a update queue, which is processed + * by {@link loadUserPreferences()} + * + * @param string $cookie_name can be null + * @param string $cfg_path configuration path + * @param mixed $new_cfg_value new value + * @param mixed $default_value default value + * + * @return void + */ + function setUserValue($cookie_name, $cfg_path, $new_cfg_value, + $default_value = null + ) { + // use permanent user preferences if possible + $prefs_type = $this->get('user_preferences'); + if ($prefs_type) { + include_once './libraries/user_preferences.lib.php'; + if ($default_value === null) { + $default_value = PMA_arrayRead($cfg_path, $this->default); + } + PMA_persistOption($cfg_path, $new_cfg_value, $default_value); + } + if ($prefs_type != 'db' && $cookie_name) { + // fall back to cookies + if ($default_value === null) { + $default_value = PMA_arrayRead($cfg_path, $this->settings); + } + $this->setCookie($cookie_name, $new_cfg_value, $default_value); + } + PMA_arrayWrite($cfg_path, $GLOBALS['cfg'], $new_cfg_value); + PMA_arrayWrite($cfg_path, $this->settings, $new_cfg_value); + } + + /** + * Reads value stored by {@link setUserValue()} + * + * @param string $cookie_name cookie name + * @param mixed $cfg_value config value + * + * @return mixed + */ + function getUserValue($cookie_name, $cfg_value) + { + $cookie_exists = isset($_COOKIE) && !empty($_COOKIE[$cookie_name]); + $prefs_type = $this->get('user_preferences'); + if ($prefs_type == 'db') { + // permanent user preferences value exists, remove cookie + if ($cookie_exists) { + $this->removeCookie($cookie_name); + } + } else if ($cookie_exists) { + return $_COOKIE[$cookie_name]; + } + // return value from $cfg array + return $cfg_value; + } + + /** + * set source + * + * @param string $source source + * + * @return void + */ + function setSource($source) + { + $this->source = trim($source); + } + + /** + * check config source + * + * @return boolean whether source is valid or not + */ + function checkConfigSource() + { + if (! $this->getSource()) { + // no configuration file set at all + return false; + } + + if (! file_exists($this->getSource())) { + $this->source_mtime = 0; + return false; + } + + if (! is_readable($this->getSource())) { + // manually check if file is readable + // might be bug #3059806 Supporting running from CIFS/Samba shares + + $contents = false; + $handle = @fopen($this->getSource(), 'r'); + if ($handle !== false) { + $contents = @fread($handle, 1); // reading 1 byte is enough to test + @fclose($handle); + } + if ($contents === false) { + $this->source_mtime = 0; + PMA_fatalError( + sprintf( + function_exists('__') + ? __('Existing configuration file (%s) is not readable.') + : 'Existing configuration file (%s) is not readable.', + $this->getSource() + ) + ); + return false; + } + } + + return true; + } + + /** + * verifies the permissions on config file (if asked by configuration) + * (must be called after config.inc.php has been merged) + * + * @return void + */ + function checkPermissions() + { + // Check for permissions (on platforms that support it): + if ($this->get('CheckConfigurationPermissions')) { + $perms = @fileperms($this->getSource()); + if (!($perms === false) && ($perms & 2)) { + // This check is normally done after loading configuration + $this->checkWebServerOs(); + if ($this->get('PMA_IS_WINDOWS') == 0) { + $this->source_mtime = 0; + /* Gettext is possibly still not loaded */ + if (function_exists('__')) { + $msg = __('Wrong permissions on configuration file, should not be world writable!'); + } else { + $msg = 'Wrong permissions on configuration file, should not be world writable!'; + } + PMA_fatalError($msg); + } + } + } + } + + /** + * returns specific config setting + * + * @param string $setting config setting + * + * @return mixed value + */ + function get($setting) + { + if (isset($this->settings[$setting])) { + return $this->settings[$setting]; + } + return null; + } + + /** + * sets configuration variable + * + * @param string $setting configuration option + * @param string $value new value for configuration option + * + * @return void + */ + function set($setting, $value) + { + if (! isset($this->settings[$setting]) + || $this->settings[$setting] != $value + ) { + $this->settings[$setting] = $value; + $this->set_mtime = time(); + } + } + + /** + * returns source for current config + * + * @return string config source + */ + function getSource() + { + return $this->source; + } + + /** + * returns a unique value to force a CSS reload if either the config + * or the theme changes + * must also check the pma_fontsize cookie in case there is no + * config file + * + * @return int Summary of unix timestamps and fontsize, + * to be unique on theme parameters change + */ + function getThemeUniqueValue() + { + if (null !== $this->get('fontsize')) { + $fontsize = intval($this->get('fontsize')); + } elseif (isset($_COOKIE['pma_fontsize'])) { + $fontsize = intval($_COOKIE['pma_fontsize']); + } else { + $fontsize = 0; + } + return ( + $fontsize + + $this->source_mtime + + $this->default_source_mtime + + $this->get('user_preferences_mtime') + + $_SESSION['PMA_Theme']->mtime_info + + $_SESSION['PMA_Theme']->filesize_info); + } + + /** + * $cfg['PmaAbsoluteUri'] is a required directive else cookies won't be + * set properly and, depending on browsers, inserting or updating a + * record might fail + * + * @return bool + */ + function checkPmaAbsoluteUri() + { + // Setup a default value to let the people and lazy sysadmins work anyway, + // they'll get an error if the autodetect code doesn't work + $pma_absolute_uri = $this->get('PmaAbsoluteUri'); + $is_https = $this->detectHttps(); + + if (strlen($pma_absolute_uri) < 5) { + $url = array(); + + // If we don't have scheme, we didn't have full URL so we need to + // dig deeper + if (empty($url['scheme'])) { + // Scheme + if ($is_https) { + $url['scheme'] = 'https'; + } else { + $url['scheme'] = 'http'; + } + + // Host and port + if (PMA_getenv('HTTP_HOST')) { + // Prepend the scheme before using parse_url() since this + // is not part of the RFC2616 Host request-header + $parsed_url = parse_url( + $url['scheme'] . '://' . PMA_getenv('HTTP_HOST') + ); + if (!empty($parsed_url['host'])) { + $url = $parsed_url; + } else { + $url['host'] = PMA_getenv('HTTP_HOST'); + } + } elseif (PMA_getenv('SERVER_NAME')) { + $url['host'] = PMA_getenv('SERVER_NAME'); + } else { + $this->error_pma_uri = true; + return false; + } + + // If we didn't set port yet... + if (empty($url['port']) && PMA_getenv('SERVER_PORT')) { + $url['port'] = PMA_getenv('SERVER_PORT'); + } + + // And finally the path could be already set from REQUEST_URI + if (empty($url['path'])) { + $path = parse_url($GLOBALS['PMA_PHP_SELF']); + $url['path'] = $path['path']; + } + } + + // Make url from parts we have + $pma_absolute_uri = $url['scheme'] . '://'; + // Was there user information? + if (!empty($url['user'])) { + $pma_absolute_uri .= $url['user']; + if (!empty($url['pass'])) { + $pma_absolute_uri .= ':' . $url['pass']; + } + $pma_absolute_uri .= '@'; + } + // Add hostname + $pma_absolute_uri .= $url['host']; + // Add port, if it not the default one + if (! empty($url['port']) + && (($url['scheme'] == 'http' && $url['port'] != 80) + || ($url['scheme'] == 'https' && $url['port'] != 443)) + ) { + $pma_absolute_uri .= ':' . $url['port']; + } + // And finally path, without script name, the 'a' is there not to + // strip our directory, when path is only /pmadir/ without filename. + // Backslashes returned by Windows have to be changed. + // Only replace backslashes by forward slashes if on Windows, + // as the backslash could be valid on a non-Windows system. + $this->checkWebServerOs(); + if ($this->get('PMA_IS_WINDOWS') == 1) { + $path = str_replace("\\", "/", dirname($url['path'] . 'a')); + } else { + $path = dirname($url['path'] . 'a'); + } + + // To work correctly within transformations overview: + if (defined('PMA_PATH_TO_BASEDIR') && PMA_PATH_TO_BASEDIR == '../../') { + if ($this->get('PMA_IS_WINDOWS') == 1) { + $path = str_replace("\\", "/", dirname(dirname($path))); + } else { + $path = dirname(dirname($path)); + } + } + + // PHP's dirname function would have returned a dot + // when $path contains no slash + if ($path == '.') { + $path = ''; + } + // in vhost situations, there could be already an ending slash + if (substr($path, -1) != '/') { + $path .= '/'; + } + $pma_absolute_uri .= $path; + + // We used to display a warning if PmaAbsoluteUri wasn't set, but now + // the autodetect code works well enough that we don't display the + // warning at all. The user can still set PmaAbsoluteUri manually. + + } else { + // The URI is specified, however users do often specify this + // wrongly, so we try to fix this. + + // Adds a trailing slash et the end of the phpMyAdmin uri if it + // does not exist. + if (substr($pma_absolute_uri, -1) != '/') { + $pma_absolute_uri .= '/'; + } + + // If URI doesn't start with http:// or https://, we will add + // this. + if (substr($pma_absolute_uri, 0, 7) != 'http://' + && substr($pma_absolute_uri, 0, 8) != 'https://' + ) { + $pma_absolute_uri + = ($is_https ? 'https' : 'http') + . ':' . (substr($pma_absolute_uri, 0, 2) == '//' ? '' : '//') + . $pma_absolute_uri; + } + } + $this->set('PmaAbsoluteUri', $pma_absolute_uri); + } + + /** + * Converts currently used PmaAbsoluteUri to SSL based variant. + * + * @return String witch adjusted URI + */ + function getSSLUri() + { + // grab current URL + $url = $this->get('PmaAbsoluteUri'); + // Parse current URL + $parsed = parse_url($url); + // In case parsing has failed do stupid string replacement + if ($parsed === false) { + // Replace http protocol + return preg_replace('@^http:@', 'https:', $url); + } + + // Reconstruct URL using parsed parts + if ($this->get('SSLPort')) { + $port_number = $this->get('SSLPort'); + } else { + $port_number = 443; + } + return 'https://' . $parsed['host'] . ':' . $port_number . $parsed['path']; + } + + /** + * check selected collation_connection + * + * @todo check validity of $_REQUEST['collation_connection'] + * + * @return void + */ + function checkCollationConnection() + { + if (! empty($_REQUEST['collation_connection'])) { + $this->set( + 'collation_connection', + strip_tags($_REQUEST['collation_connection']) + ); + } + } + + /** + * checks for font size configuration, and sets font size as requested by user + * + * @return void + */ + function checkFontsize() + { + $new_fontsize = ''; + + if (isset($_GET['set_fontsize'])) { + $new_fontsize = $_GET['set_fontsize']; + } elseif (isset($_POST['set_fontsize'])) { + $new_fontsize = $_POST['set_fontsize']; + } elseif (isset($_COOKIE['pma_fontsize'])) { + $new_fontsize = $_COOKIE['pma_fontsize']; + } + + if (preg_match('/^[0-9.]+(px|em|pt|\%)$/', $new_fontsize)) { + $this->set('fontsize', $new_fontsize); + } elseif (! $this->get('fontsize')) { + // 80% would correspond to the default browser font size + // of 16, but use 82% to help read the monoface font + $this->set('fontsize', '82%'); + } + + $this->setCookie('pma_fontsize', $this->get('fontsize'), '82%'); + } + + /** + * checks if upload is enabled + * + * @return void + */ + function checkUpload() + { + if (ini_get('file_uploads')) { + $this->set('enable_upload', true); + // if set "php_admin_value file_uploads Off" in httpd.conf + // ini_get() also returns the string "Off" in this case: + if ('off' == strtolower(ini_get('file_uploads'))) { + $this->set('enable_upload', false); + } + } else { + $this->set('enable_upload', false); + } + } + + /** + * Maximum upload size as limited by PHP + * Used with permission from Moodle (http://moodle.org) by Martin Dougiamas + * + * this section generates $max_upload_size in bytes + * + * @return void + */ + function checkUploadSize() + { + if (! $filesize = ini_get('upload_max_filesize')) { + $filesize = "5M"; + } + + if ($postsize = ini_get('post_max_size')) { + $this->set( + 'max_upload_size', + min(PMA_getRealSize($filesize), PMA_getRealSize($postsize)) + ); + } else { + $this->set('max_upload_size', PMA_getRealSize($filesize)); + } + } + + /** + * check for https + * + * @return void + */ + function checkIsHttps() + { + $this->set('is_https', $this->isHttps()); + } + + /** + * Checks if protocol is https + * + * This function checks if the https protocol is used in the PmaAbsoluteUri + * configuration setting, as opposed to detectHttps() which checks if the + * https protocol is used on the active connection. + * + * @return bool + */ + public function isHttps() + { + static $is_https = null; + + if (null !== $is_https) { + return $is_https; + } + + $url = parse_url($this->get('PmaAbsoluteUri')); + + if (isset($url['scheme']) && $url['scheme'] == 'https') { + $is_https = true; + } else { + $is_https = false; + } + + return $is_https; + } + + /** + * Detects whether https appears to be used. + * + * This function checks if the https protocol is used in the current connection + * with the webserver, based on environment variables. + * Please note that this just detects what we see, so + * it completely ignores things like reverse proxies. + * + * @return bool + */ + function detectHttps() + { + $is_https = false; + + $url = array(); + + // At first we try to parse REQUEST_URI, it might contain full URL, + if (PMA_getenv('REQUEST_URI')) { + // produces E_WARNING if it cannot get parsed, e.g. '/foobar:/' + $url = @parse_url(PMA_getenv('REQUEST_URI')); + if ($url === false) { + $url = array(); + } + } + + // If we don't have scheme, we didn't have full URL so we need to + // dig deeper + if (empty($url['scheme'])) { + // Scheme + if (PMA_getenv('HTTP_SCHEME')) { + $url['scheme'] = PMA_getenv('HTTP_SCHEME'); + } elseif (PMA_getenv('HTTPS') + && strtolower(PMA_getenv('HTTPS')) == 'on' + ) { + $url['scheme'] = 'https'; + } elseif (PMA_getenv('HTTP_X_FORWARDED_PROTO')) { + $url['scheme'] = strtolower(PMA_getenv('HTTP_X_FORWARDED_PROTO')); + } elseif (PMA_getenv('HTTP_FRONT_END_HTTPS') + && strtolower(PMA_getenv('HTTP_FRONT_END_HTTPS')) == 'on' + ) { + $url['scheme'] = 'https'; + } else { + $url['scheme'] = 'http'; + } + } + + if (isset($url['scheme']) && $url['scheme'] == 'https') { + $is_https = true; + } else { + $is_https = false; + } + + return $is_https; + } + + /** + * detect correct cookie path + * + * @return void + */ + function checkCookiePath() + { + $this->set('cookie_path', $this->getCookiePath()); + } + + /** + * Get cookie path + * + * @return string + */ + public function getCookiePath() + { + static $cookie_path = null; + + if (null !== $cookie_path && !defined('TESTSUITE')) { + return $cookie_path; + } + + $parsed_url = parse_url($this->get('PmaAbsoluteUri')); + + $cookie_path = $parsed_url['path']; + + return $cookie_path; + } + + /** + * enables backward compatibility + * + * @return void + */ + function enableBc() + { + $GLOBALS['cfg'] = $this->settings; + $GLOBALS['default_server'] = $this->default_server; + unset($this->default_server); + $GLOBALS['collation_connection'] = $this->get('collation_connection'); + $GLOBALS['is_upload'] = $this->get('enable_upload'); + $GLOBALS['max_upload_size'] = $this->get('max_upload_size'); + $GLOBALS['cookie_path'] = $this->get('cookie_path'); + $GLOBALS['is_https'] = $this->get('is_https'); + + $defines = array( + 'PMA_VERSION', + 'PMA_THEME_VERSION', + 'PMA_THEME_GENERATION', + 'PMA_PHP_STR_VERSION', + 'PMA_PHP_INT_VERSION', + 'PMA_IS_WINDOWS', + 'PMA_IS_IIS', + 'PMA_IS_GD2', + 'PMA_USR_OS', + 'PMA_USR_BROWSER_VER', + 'PMA_USR_BROWSER_AGENT' + ); + + foreach ($defines as $define) { + if (! defined($define)) { + define($define, $this->get($define)); + } + } + } + + /** + * returns options for font size selection + * + * @param string $current_size current selected font size with unit + * + * @return array selectable font sizes + * + * @static + */ + static protected function getFontsizeOptions($current_size = '82%') + { + $unit = preg_replace('/[0-9.]*/', '', $current_size); + $value = preg_replace('/[^0-9.]*/', '', $current_size); + + $factors = array(); + $options = array(); + $options["$value"] = $value . $unit; + + if ($unit === '%') { + $factors[] = 1; + $factors[] = 5; + $factors[] = 10; + } elseif ($unit === 'em') { + $factors[] = 0.05; + $factors[] = 0.2; + $factors[] = 1; + } elseif ($unit === 'pt') { + $factors[] = 0.5; + $factors[] = 2; + } elseif ($unit === 'px') { + $factors[] = 1; + $factors[] = 5; + $factors[] = 10; + } else { + //unknown font size unit + $factors[] = 0.05; + $factors[] = 0.2; + $factors[] = 1; + $factors[] = 5; + $factors[] = 10; + } + + foreach ($factors as $key => $factor) { + $option_inc = $value + $factor; + $option_dec = $value - $factor; + while (count($options) < 21) { + $options["$option_inc"] = $option_inc . $unit; + if ($option_dec > $factors[0]) { + $options["$option_dec"] = $option_dec . $unit; + } + $option_inc += $factor; + $option_dec -= $factor; + if (isset($factors[$key + 1]) + && $option_inc >= $value + $factors[$key + 1] + ) { + break; + } + } + } + ksort($options); + return $options; + } + + /** + * returns html selectbox for font sizes + * + * @static + * + * @return string html selectbox + */ + static protected function getFontsizeSelection() + { + $current_size = $GLOBALS['PMA_Config']->get('fontsize'); + // for the case when there is no config file (this is supported) + if (empty($current_size)) { + if (isset($_COOKIE['pma_fontsize'])) { + $current_size = $_COOKIE['pma_fontsize']; + } else { + $current_size = '82%'; + } + } + $options = PMA_Config::getFontsizeOptions($current_size); + + $return = '' . "\n" + . ''; + + return $return; + } + + /** + * return complete font size selection form + * + * @static + * + * @return string html selectbox + */ + static public function getFontsizeForm() + { + return '
      ' . "\n" + . PMA_generate_common_hidden_inputs() . "\n" + . PMA_Config::getFontsizeSelection() . "\n" + . '
      '; + } + + /** + * removes cookie + * + * @param string $cookie name of cookie to remove + * + * @return boolean result of setcookie() + */ + function removeCookie($cookie) + { + if (defined('TESTSUITE')) { + if (isset($_COOKIE[$cookie])) { + unset($_COOKIE[$cookie]); + } + return true; + } + return setcookie( + $cookie, + '', + time() - 3600, + $this->getCookiePath(), + '', + $this->isHttps() + ); + } + + /** + * sets cookie if value is different from current cookie value, + * or removes if value is equal to default + * + * @param string $cookie name of cookie to remove + * @param mixed $value new cookie value + * @param string $default default value + * @param int $validity validity of cookie in seconds (default is one month) + * @param bool $httponly whether cookie is only for HTTP (and not for scripts) + * + * @return boolean result of setcookie() + */ + function setCookie($cookie, $value, $default = null, $validity = null, + $httponly = true + ) { + if (strlen($value) && null !== $default && $value === $default) { + // default value is used + if (isset($_COOKIE[$cookie])) { + // remove cookie + return $this->removeCookie($cookie); + } + return false; + } + + if (! strlen($value) && isset($_COOKIE[$cookie])) { + // remove cookie, value is empty + return $this->removeCookie($cookie); + } + + if (! isset($_COOKIE[$cookie]) || $_COOKIE[$cookie] !== $value) { + // set cookie with new value + /* Calculate cookie validity */ + if ($validity === null) { + $validity = time() + 2592000; + } elseif ($validity == 0) { + $validity = 0; + } else { + $validity = time() + $validity; + } + if (defined('TESTSUITE')) { + $_COOKIE[$cookie] = $value; + return true; + } + return setcookie( + $cookie, + $value, + $validity, + $this->getCookiePath(), + '', + $this->isHttps(), + $httponly + ); + } + + // cookie has already $value as value + return true; + } +} +?> diff --git a/phpmyadmin/libraries/DBQbe.class.php b/phpmyadmin/libraries/DBQbe.class.php new file mode 100644 index 000000000..6213dd795 --- /dev/null +++ b/phpmyadmin/libraries/DBQbe.class.php @@ -0,0 +1,1343 @@ +_db = $db; + // Sets criteria parameters + $this->_setSearchParams(); + $this->_setCriteriaTablesAndColumns(); + } + + /** + * Sets search parameters + * + * @return void + */ + private function _setSearchParams() + { + // sets column count + $criteriaColumnCount = PMA_ifSetOr( + $_REQUEST['criteriaColumnCount'], + 3, + 'numeric' + ); + $criteriaColumnAdd = PMA_ifSetOr( + $_REQUEST['criteriaColumnAdd'], + 0, + 'numeric' + ); + $this->_criteria_column_count = max( + $criteriaColumnCount + $criteriaColumnAdd, + 0 + ); + + // sets row count + $rows = PMA_ifSetOr($_REQUEST['rows'], 0, 'numeric'); + $criteriaRowAdd = PMA_ifSetOr($_REQUEST['criteriaRowAdd'], 0, 'numeric'); + $this->_criteria_row_count = max($rows + $criteriaRowAdd, 0); + + $this->_criteriaColumnInsert = PMA_ifSetOr( + $_REQUEST['criteriaColumnInsert'], + null, + 'array' + ); + $this->_criteriaColumnDelete = PMA_ifSetOr( + $_REQUEST['criteriaColumnDelete'], + null, + 'array' + ); + + $this->_prev_criteria = isset($_REQUEST['prev_criteria']) + ? $_REQUEST['prev_criteria'] + : array(); + $this->_criteria = isset($_REQUEST['criteria']) + ? $_REQUEST['criteria'] + : array_fill(0, $criteriaColumnCount, ''); + + $this->_criteriaRowInsert = isset($_REQUEST['criteriaRowInsert']) + ? $_REQUEST['criteriaRowInsert'] + : array_fill(0, $criteriaColumnCount, ''); + $this->_criteriaRowDelete = isset($_REQUEST['criteriaRowDelete']) + ? $_REQUEST['criteriaRowDelete'] + : array_fill(0, $criteriaColumnCount, ''); + $this->_criteriaAndOrRow = isset($_REQUEST['criteriaAndOrRow']) + ? $_REQUEST['criteriaAndOrRow'] + : array_fill(0, $criteriaColumnCount, ''); + $this->_criteriaAndOrColumn = isset($_REQUEST['criteriaAndOrColumn']) + ? $_REQUEST['criteriaAndOrColumn'] + : array_fill(0, $criteriaColumnCount, ''); + // sets minimum width + $this->_form_column_width = 12; + $this->_curField = array(); + $this->_curSort = array(); + $this->_curShow = array(); + $this->_curCriteria = array(); + $this->_curAndOrRow = array(); + $this->_curAndOrCol = array(); + } + + /** + * Sets criteria tables and columns + * + * @return void + */ + private function _setCriteriaTablesAndColumns() + { + // The tables list sent by a previously submitted form + if (PMA_isValid($_REQUEST['TableList'], 'array')) { + foreach ($_REQUEST['TableList'] as $each_table) { + $this->_criteriaTables[$each_table] = ' selected="selected"'; + } + } // end if + $all_tables = PMA_DBI_query( + 'SHOW TABLES FROM ' . PMA_Util::backquote($this->_db) . ';', + null, + PMA_DBI_QUERY_STORE + ); + $all_tables_count = PMA_DBI_num_rows($all_tables); + if (0 == $all_tables_count) { + PMA_Message::error(__('No tables found in database.'))->display(); + exit; + } + // The tables list gets from MySQL + while (list($table) = PMA_DBI_fetch_row($all_tables)) { + $columns = PMA_DBI_get_columns($this->_db, $table); + + if (empty($this->_criteriaTables[$table]) + && ! empty($_REQUEST['TableList']) + ) { + $this->_criteriaTables[$table] = ''; + } else { + $this->_criteriaTables[$table] = ' selected="selected"'; + } // end if + + // The fields list per selected tables + if ($this->_criteriaTables[$table] == ' selected="selected"') { + $each_table = PMA_Util::backquote($table); + $this->_columnNames[] = $each_table . '.*'; + foreach ($columns as $each_column) { + $each_column = $each_table . '.' + . PMA_Util::backquote($each_column['Field']); + $this->_columnNames[] = $each_column; + // increase the width if necessary + $this->_form_column_width = max( + strlen($each_column), + $this->_form_column_width + ); + } // end foreach + } // end if + } // end while + PMA_DBI_free_result($all_tables); + + // sets the largest width found + $this->_realwidth = $this->_form_column_width . 'ex'; + } + /** + * Provides select options list containing column names + * + * @param integer $column_number Column Number (0,1,2) or more + * @param string $selected Selected criteria column name + * + * @return HTML for select options + */ + private function _showColumnSelectCell($column_number, $selected = '') + { + $html_output = ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + return $html_output; + } + + /** + * Provides select options list containing sort options (ASC/DESC) + * + * @param integer $column_number Column Number (0,1,2) or more + * @param string $asc_selected Selected criteria 'Ascending' + * @param string $desc_selected Selected criteria 'Descending' + * + * @return HTML for select options + */ + private function _getSortSelectCell($column_number, $asc_selected = '', + $desc_selected = '' + ) { + $html_output = ''; + $html_output .= ''; + $html_output .= ''; + return $html_output; + } + + /** + * Provides search form's row containing column select options + * + * @return HTML for search table's row + */ + private function _getColumnNamesRow() + { + $html_output = ''; + $html_output .= '' . __('Column') . ':'; + $new_column_count = 0; + for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) { + if (isset($this->_criteriaColumnInsert[$column_index]) + && $this->_criteriaColumnInsert[$column_index] == 'on' + ) { + $html_output .= $this->_showColumnSelectCell( + $new_column_count + ); + $new_column_count++; + } + if (! empty($this->_criteriaColumnDelete) + && isset($this->_criteriaColumnDelete[$column_index]) + && $this->_criteriaColumnDelete[$column_index] == 'on' + ) { + continue; + } + $selected = ''; + if (isset($_REQUEST['criteriaColumn'][$column_index])) { + $selected = $_REQUEST['criteriaColumn'][$column_index]; + $this->_curField[$new_column_count] + = $_REQUEST['criteriaColumn'][$column_index]; + } + $html_output .= $this->_showColumnSelectCell( + $new_column_count, + $selected + ); + $new_column_count++; + } // end for + $this->_new_column_count = $new_column_count; + $html_output .= ''; + return $html_output; + } + + /** + * Provides search form's row containing sort(ASC/DESC) select options + * + * @return HTML for search table's row + */ + private function _getSortRow() + { + $html_output = ''; + $html_output .= '' . __('Sort') . ':'; + $new_column_count = 0; + for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) { + if (! empty($this->_criteriaColumnInsert) + && isset($this->_criteriaColumnInsert[$column_index]) + && $this->_criteriaColumnInsert[$column_index] == 'on' + ) { + $html_output .= $this->_getSortSelectCell($new_column_count); + $new_column_count++; + } // end if + + if (! empty($this->_criteriaColumnDelete) + && isset($this->_criteriaColumnDelete[$column_index]) + && $this->_criteriaColumnDelete[$column_index] == 'on' + ) { + continue; + } + // If they have chosen all fields using the * selector, + // then sorting is not available, Fix for Bug #570698 + if (isset($_REQUEST['criteriaSort'][$column_index]) + && isset($_REQUEST['criteriaColumn'][$column_index]) + && substr($_REQUEST['criteriaColumn'][$column_index], -2) == '.*' + ) { + $_REQUEST['criteriaSort'][$column_index] = ''; + } //end if + // Set asc_selected + if (isset($_REQUEST['criteriaSort'][$column_index]) + && $_REQUEST['criteriaSort'][$column_index] == 'ASC' + ) { + $this->_curSort[$new_column_count] + = $_REQUEST['criteriaSort'][$column_index]; + $asc_selected = ' selected="selected"'; + } else { + $asc_selected = ''; + } // end if + // Set desc selected + if (isset($_REQUEST['criteriaSort'][$column_index]) + && $_REQUEST['criteriaSort'][$column_index] == 'DESC' + ) { + $this->_curSort[$new_column_count] + = $_REQUEST['criteriaSort'][$column_index]; + $desc_selected = ' selected="selected"'; + } else { + $desc_selected = ''; + } // end if + $html_output .= $this->_getSortSelectCell( + $new_column_count, $asc_selected, $desc_selected + ); + $new_column_count++; + } // end for + $html_output .= ''; + return $html_output; + } + + /** + * Provides search form's row containing SHOW checkboxes + * + * @return HTML for search table's row + */ + private function _getShowRow() + { + $html_output = ''; + $html_output .= '' . __('Show') . ':'; + $new_column_count = 0; + for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) { + if (! empty($this->_criteriaColumnInsert) + && isset($this->_criteriaColumnInsert[$column_index]) + && $this->_criteriaColumnInsert[$column_index] == 'on' + ) { + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $new_column_count++; + } // end if + if (! empty($this->_criteriaColumnDelete) + && isset($this->_criteriaColumnDelete[$column_index]) + && $this->_criteriaColumnDelete[$column_index] == 'on' + ) { + continue; + } + if (isset($_REQUEST['criteriaShow'][$column_index])) { + $checked_options = ' checked="checked"'; + $this->_curShow[$new_column_count] + = $_REQUEST['criteriaShow'][$column_index]; + } else { + $checked_options = ''; + } + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $new_column_count++; + } // end for + $html_output .= ''; + return $html_output; + } + + /** + * Provides search form's row containing criteria Inputboxes + * + * @return HTML for search table's row + */ + private function _getCriteriaInputboxRow() + { + $html_output = ''; + $html_output .= '' . __('Criteria') . ':'; + $new_column_count = 0; + for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) { + if (! empty($this->_criteriaColumnInsert) + && isset($this->_criteriaColumnInsert[$column_index]) + && $this->_criteriaColumnInsert[$column_index] == 'on' + ) { + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $new_column_count++; + } // end if + if (! empty($this->_criteriaColumnDelete) + && isset($this->_criteriaColumnDelete[$column_index]) + && $this->_criteriaColumnDelete[$column_index] == 'on' + ) { + continue; + } + if (isset($this->_criteria[$column_index])) { + $tmp_criteria = $this->_criteria[$column_index]; + } + if ((empty($this->_prev_criteria) + || ! isset($this->_prev_criteria[$column_index])) + || $this->_prev_criteria[$column_index] != htmlspecialchars($tmp_criteria) + ) { + $this->_curCriteria[$new_column_count] = $tmp_criteria; + } else { + $this->_curCriteria[$new_column_count] + = $this->_prev_criteria[$column_index]; + } + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $new_column_count++; + } // end for + $html_output .= ''; + return $html_output; + } + + /** + * Provides footer options for adding/deleting row/columns + * + * @param string $type Whether row or column + * + * @return HTML for footer options + */ + private function _getFootersOptions($type) + { + $html_output = '
      '; + $html_output .= (($type == 'row') + ? __('Add/Delete criteria rows') : __('Add/Delete columns')); + $html_output .= ':'; + $html_output .= '
      '; + return $html_output; + } + + /** + * Provides search form table's footer options + * + * @return HTML for table footer + */ + private function _getTableFooters() + { + $html_output = '
      '; + $html_output .= $this->_getFootersOptions("row"); + $html_output .= $this->_getFootersOptions("column"); + $html_output .= '
      '; + $html_output .= ''; + $html_output .= '
      '; + $html_output .= '
      '; + return $html_output; + } + + /** + * Provides a select list of database tables + * + * @return HTML for table select list + */ + private function _getTablesList() + { + $html_output = '
      '; + $html_output .= '
      '; + $html_output .= '' . __('Use Tables') . ''; + // Build the options list for each table name + $options = ''; + $numTableListOptions = 0; + foreach ($this->_criteriaTables as $key => $val) { + $options .= ''; + $numTableListOptions++; + } + $html_output .= ''; + $html_output .= '
      '; + $html_output .= '
      '; + $html_output .= ''; + $html_output .= '
      '; + $html_output .= '
      '; + return $html_output; + } + + /** + * Provides And/Or modification cell along with Insert/Delete options + * (For modifying search form's table columns) + * + * @param integer $column_number Column Number (0,1,2) or more + * @param array $selected Selected criteria column name + * + * @return HTML for modification cell + */ + private function _getAndOrColCell($column_number, $selected = null) + { + $html_output = ''; + $html_output .= '' . __('Or') . ':'; + $html_output .= ''; + $html_output .= '  ' . __('And') . ':'; + $html_output .= ''; + $html_output .= '
      ' . __('Ins'); + $html_output .= ''; + $html_output .= '  ' . __('Del'); + $html_output .= ''; + $html_output .= ''; + return $html_output; + } + + /** + * Provides search form's row containing column modifications options + * (For modifying search form's table columns) + * + * @return HTML for search table's row + */ + private function _getModifyColumnsRow() + { + $html_output = ''; + $html_output .= '' . __('Modify') . ':'; + $new_column_count = 0; + for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) { + if (! empty($this->_criteriaColumnInsert) + && isset($this->_criteriaColumnInsert[$column_index]) + && $this->_criteriaColumnInsert[$column_index] == 'on' + ) { + $html_output .= $this->_getAndOrColCell($new_column_count); + $new_column_count++; + } // end if + + if (! empty($this->_criteriaColumnDelete) + && isset($this->_criteriaColumnDelete[$column_index]) + && $this->_criteriaColumnDelete[$column_index] == 'on' + ) { + continue; + } + + if (isset($this->_criteriaAndOrColumn[$column_index])) { + $this->_curAndOrCol[$new_column_count] + = $this->_criteriaAndOrColumn[$column_index]; + } + if (isset($this->_criteriaAndOrColumn[$column_index]) + && $this->_criteriaAndOrColumn[$column_index] == 'or' + ) { + $checked_options['or'] = ' checked="checked"'; + $checked_options['and'] = ''; + } else { + $checked_options['and'] = ' checked="checked"'; + $checked_options['or'] = ''; + } + $html_output .= $this->_getAndOrColCell( + $new_column_count, + $checked_options + ); + $new_column_count++; + } // end for + $html_output .= ''; + return $html_output; + } + + /** + * Provides Insert/Delete options for criteria inputbox + * with AND/OR relationship modification options + * + * @param integer $row_index Number of criteria row + * @param string $checked_options If checked + * + * @return HTML + */ + private function _getInsDelAndOrCell($row_index, $checked_options) + { + $html_output = ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= '
      '; + $html_output .= '' . __('Ins') . ':'; + $html_output .= ''; + $html_output .= ''; + $html_output .= '' . __('And') . ':'; + $html_output .= ''; + $html_output .= ''; + $html_output .= '
      '; + $html_output .= '' . __('Del') . ':'; + $html_output .= ''; + $html_output .= ''; + $html_output .= '' . __('Or') . ':'; + $html_output .= ''; + $html_output .= ''; + $html_output .= '
      '; + $html_output .= ''; + return $html_output; + } + + /** + * Provides rows for criteria inputbox Insert/Delete options + * with AND/OR relationship modification options + * + * @param integer $new_row_index New row index if rows are added/deleted + * @param integer $row_index Row index + * + * @return HTML table rows + */ + private function _getInputboxRow($new_row_index, $row_index) + { + $html_output = ''; + $new_column_count = 0; + for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) { + if (! empty($this->_criteriaColumnInsert) + && isset($this->_criteriaColumnInsert[$column_index]) + && $this->_criteriaColumnInsert[$column_index] == 'on' + ) { + $or = 'Or' . $new_row_index . '[' . $new_column_count . ']'; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $new_column_count++; + } // end if + if (! empty($this->_criteriaColumnDelete) + && isset($this->_criteriaColumnDelete[$column_index]) + && $this->_criteriaColumnDelete[$column_index] == 'on' + ) { + continue; + } + $or = 'Or' . $new_row_index; + if (! empty($_POST[$or]) && isset($_POST[$or][$column_index])) { + $tmp_or = $_POST[$or][$column_index]; + } else { + $tmp_or = ''; + } + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + if (! empty(${$or}) && isset(${$or}[$column_index])) { + $GLOBALS[${'cur' . $or}][$new_column_count] = ${$or}[$column_index]; + } + $new_column_count++; + } // end for + return $html_output; + } + + /** + * Provides rows for criteria inputbox Insert/Delete options + * with AND/OR relationship modification options + * + * @return HTML table rows + */ + private function _getInsDelAndOrCriteriaRows() + { + $html_output = ''; + $new_row_count = 0; + $odd_row = true; + for ($row_index = 0; $row_index <= $this->_criteria_row_count; $row_index++) { + if (isset($this->_criteriaRowInsert[$row_index]) + && $this->_criteriaRowInsert[$row_index] == 'on' + ) { + $checked_options['or'] = ' checked="checked"'; + $checked_options['and'] = ''; + $html_output .= ''; + $html_output .= $this->_getInsDelAndOrCell( + $new_row_count, $checked_options + ); + $html_output .= $this->_getInputboxRow( + $new_row_count, $row_index + ); + $new_row_count++; + $html_output .= ''; + $odd_row =! $odd_row; + } // end if + if (isset($this->_criteriaRowDelete[$row_index]) + && $this->_criteriaRowDelete[$row_index] == 'on' + ) { + continue; + } + if (isset($this->_criteriaAndOrRow[$row_index])) { + $this->_curAndOrRow[$new_row_count] + = $this->_criteriaAndOrRow[$row_index]; + } + if (isset($this->_criteriaAndOrRow[$row_index]) + && $this->_criteriaAndOrRow[$row_index] == 'and' + ) { + $checked_options['and'] = ' checked="checked"'; + $checked_options['or'] = ''; + } else { + $checked_options['or'] = ' checked="checked"'; + $checked_options['and'] = ''; + } + $html_output .= ''; + $html_output .= $this->_getInsDelAndOrCell( + $new_row_count, $checked_options + ); + $html_output .= $this->_getInputboxRow( + $new_row_count, $row_index + ); + $new_row_count++; + $html_output .= ''; + $odd_row =! $odd_row; + } // end for + $this->_new_row_count = $new_row_count; + return $html_output; + } + + /** + * Provides SELECT clause for building SQL query + * + * @return Select clause + */ + private function _getSelectClause() + { + $select_clause = ''; + $select_clauses = array(); + for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) { + if (! empty($this->_curField[$column_index]) + && isset($this->_curShow[$column_index]) + && $this->_curShow[$column_index] == 'on' + ) { + $select_clauses[] = $this->_curField[$column_index]; + } + } // end for + if ($select_clauses) { + $select_clause = 'SELECT ' + . htmlspecialchars(implode(", ", $select_clauses)) . "\n"; + } + return $select_clause; + } + + /** + * Provides WHERE clause for building SQL query + * + * @return Where clause + */ + private function _getWhereClause() + { + $where_clause = ''; + $criteria_cnt = 0; + for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) { + if (! empty($this->_curField[$column_index]) + && ! empty($this->_curCriteria[$column_index]) + && $column_index + && isset($last_where) + && isset($this->_curAndOrCol) + ) { + $where_clause .= ' ' . strtoupper($this->_curAndOrCol[$last_where]) . ' '; + } + if (! empty($this->_curField[$column_index]) + && ! empty($this->_curCriteria[$column_index]) + ) { + $where_clause .= '(' . $this->_curField[$column_index] . ' ' + . $this->_curCriteria[$column_index] . ')'; + $last_where = $column_index; + $criteria_cnt++; + } + } // end for + if ($criteria_cnt > 1) { + $where_clause = '(' . $where_clause . ')'; + } + // OR rows ${'cur' . $or}[$column_index] + if (! isset($this->_curAndOrRow)) { + $this->_curAndOrRow = array(); + } + for ($row_index = 0; $row_index <= $this->_criteria_row_count; $row_index++) { + $criteria_cnt = 0; + $qry_orwhere = ''; + $last_orwhere = ''; + for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) { + if (! empty($this->_curField[$column_index]) + && ! empty(${'curOr' . $row_index}[$column_index]) + && $column_index + ) { + $qry_orwhere .= ' ' . strtoupper($this->_curAndOrCol[$last_orwhere]) . ' '; + } + if (! empty($this->_curField[$column_index]) + && ! empty(${'curOr' . $row_index}[$column_index]) + ) { + $qry_orwhere .= '(' . $this->_curField[$column_index] + . ' ' + . ${'curOr' . $row_index}[$column_index] + . ')'; + $last_orwhere = $column_index; + $criteria_cnt++; + } + } // end for + if ($criteria_cnt > 1) { + $qry_orwhere = '(' . $qry_orwhere . ')'; + } + if (! empty($qry_orwhere)) { + $where_clause .= "\n" + . strtoupper( + isset($this->_curAndOrRow[$row_index]) + ? $this->_curAndOrRow[$row_index] . ' ' + : '' + ) + . $qry_orwhere; + } // end if + } // end for + + if (! empty($where_clause) && $where_clause != '()') { + $where_clause = 'WHERE ' . htmlspecialchars($where_clause) . "\n"; + } // end if + return $where_clause; + } + + /** + * Provides ORDER BY clause for building SQL query + * + * @return Order By clause + */ + private function _getOrderByClause() + { + $orderby_clause = ''; + $orderby_clauses = array(); + for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) { + // if all columns are chosen with * selector, + // then sorting isn't available + // Fix for Bug #570698 + if (! empty($this->_curField[$column_index]) + && ! empty($this->_curSort[$column_index]) + ) { + if (substr($this->_curField[$column_index], -2) == '.*') { + continue; + } + $orderby_clauses[] = $this->_curField[$column_index] . ' ' + . $this->_curSort[$column_index]; + } + } // end for + if ($orderby_clauses) { + $orderby_clause = 'ORDER BY ' + . htmlspecialchars(implode(", ", $orderby_clauses)) . "\n"; + } + return $orderby_clause; + } + + /** + * Provides UNIQUE columns and INDEX columns present in criteria tables + * + * @param array $all_tables Tables involved in the search + * @param array $all_columns Columns involved in the search + * @param array $where_clause_columns Columns having criteria where clause + * + * @return array having UNIQUE and INDEX columns + */ + private function _getIndexes($all_tables, $all_columns, + $where_clause_columns + ) { + $unique_columns = array(); + $index_columns = array(); + + foreach ($all_tables as $table) { + $indexes = PMA_DBI_get_table_indexes($this->_db, $table); + foreach ($indexes as $index) { + $column = $table . '.' . $index['Column_name']; + if (isset($all_columns[$column])) { + if ($index['Non_unique'] == 0) { + if (isset($where_clause_columns[$column])) { + $unique_columns[$column] = 'Y'; + } else { + $unique_columns[$column] = 'N'; + } + } else { + if (isset($where_clause_columns[$column])) { + $index_columns[$column] = 'Y'; + } else { + $index_columns[$column] = 'N'; + } + } + } + } // end while (each index of a table) + } // end while (each table) + + return array( + 'unique' => $unique_columns, + 'index' => $index_columns + ); + } + + /** + * Provides UNIQUE columns and INDEX columns present in criteria tables + * + * @param array $all_tables Tables involved in the search + * @param array $all_columns Columns involved in the search + * @param array $where_clause_columns Columns having criteria where clause + * + * @return array having UNIQUE and INDEX columns + */ + private function _getLeftJoinColumnCandidates($all_tables, $all_columns, + $where_clause_columns + ) { + PMA_DBI_select_db($this->_db); + $candidate_columns = array(); + + // Get unique columns and index columns + $indexes = $this->_getIndexes( + $all_tables, $all_columns, $where_clause_columns + ); + $unique_columns = $indexes['unique']; + $index_columns = $indexes['index']; + + // now we want to find the best. + if (isset($unique_columns) && count($unique_columns) > 0) { + $candidate_columns = $unique_columns; + $needsort = 1; + } elseif (isset($index_columns) && count($index_columns) > 0) { + $candidate_columns = $index_columns; + $needsort = 1; + } elseif (isset($where_clause_columns) && count($where_clause_columns) > 0) { + $candidate_columns = $where_clause_columns; + $needsort = 0; + } else { + $candidate_columns = $all_tables; + $needsort = 0; + } + + // If we came up with $unique_columns (very good) or $index_columns (still + // good) as $candidate_columns we want to check if we have any 'Y' there + // (that would mean that they were also found in the whereclauses + // which would be great). if yes, we take only those + if ($needsort == 1) { + foreach ($candidate_columns as $column => $is_where) { + $table = explode('.', $column); + $table = $table[0]; + if ($is_where == 'Y') { + $vg[$column] = $table; + } else { + $sg[$column] = $table; + } + } + if (isset($vg)) { + $candidate_columns = $vg; + // Candidates restricted in index+where + } else { + $candidate_columns = $sg; + // None of the candidates where in a where-clause + } + } + + return $candidate_columns; + } + + /** + * Provides the main table to form the LEFT JOIN clause + * + * @param array $all_tables Tables involved in the search + * @param array $all_columns Columns involved in the search + * @param array $where_clause_columns Columns having criteria where clause + * @param array $where_clause_tables Tables having criteria where clause + * + * @return string table name + */ + private function _getMasterTable($all_tables, $all_columns, + $where_clause_columns, $where_clause_tables + ) { + $master = ''; + if (count($where_clause_tables) == 1) { + // If there is exactly one column that has a decent where-clause + // we will just use this + $master = key($where_clause_tables); + } else { + // Now let's find out which of the tables has an index + // (When the control user is the same as the normal user + // because he is using one of his databases as pmadb, + // the last db selected is not always the one where we need to work) + $candidate_columns = $this->_getLeftJoinColumnCandidates( + $all_tables, $all_columns, $where_clause_columns + ); + // If our array of candidates has more than one member we'll just + // find the smallest table. + // Of course the actual query would be faster if we check for + // the Criteria which gives the smallest result set in its table, + // but it would take too much time to check this + if (count($candidate_columns) > 1) { + // Of course we only want to check each table once + $checked_tables = $candidate_columns; + foreach ($candidate_columns as $table) { + if ($checked_tables[$table] != 1) { + $tsize[$table] = PMA_Table::countRecords( + $this->_db, + $table, + false + ); + $checked_tables[$table] = 1; + } + $csize[$table] = $tsize[$table]; + } + asort($csize); + reset($csize); + $master = key($csize); // Smallest + } else { + reset($candidate_columns); + $master = current($candidate_columns); // Only one single candidate + } + } // end if (exactly one where clause) + return $master; + } + + /** + * Provides columns and tables that have valid where clause criteria + * + * @return array + */ + private function _getWhereClauseTablesAndColumns() + { + $where_clause_columns = array(); + $where_clause_tables = array(); + // Now we need all tables that we have in the where clause + for ($column_index = 0; $column_index < count($this->_criteria); $column_index++) { + $current_table = explode('.', $_POST['criteriaColumn'][$column_index]); + if (empty($current_table[0]) || empty($current_table[1])) { + continue; + } // end if + $table = str_replace('`', '', $current_table[0]); + $column = str_replace('`', '', $current_table[1]); + $column = $table . '.' . $column; + // Now we know that our array has the same numbers as $criteria + // we can check which of our columns has a where clause + if (! empty($this->_criteria[$column_index])) { + if (substr($this->_criteria[$column_index], 0, 1) == '=' + || stristr($this->_criteria[$column_index], 'is') + ) { + $where_clause_columns[$column] = $column; + $where_clause_tables[$table] = $table; + } + } // end if + } // end for + return array( + 'where_clause_tables' => $where_clause_tables, + 'where_clause_columns' => $where_clause_columns + ); + } + + /** + * Provides FROM clause for building SQL query + * + * @param string $cfgRelation Relation Settings + * + * @return FROM clause + */ + private function _getFromClause($cfgRelation) + { + $from_clause = ''; + if (isset($_POST['criteriaColumn']) && count($_POST['criteriaColumn']) > 0) { + // Initialize some variables + $all_tables = $all_columns = $known_tables = $remaining_tables = array(); + $left_join = ''; + + // We only start this if we have fields, otherwise it would be dumb + foreach ($_POST['criteriaColumn'] as $value) { + $parts = explode('.', $value); + if (! empty($parts[0]) && ! empty($parts[1])) { + $table = str_replace('`', '', $parts[0]); + $all_tables[$table] = $table; + $all_columns[] = $table . '.' . str_replace('`', '', $parts[1]); + } + } // end while + + // Create LEFT JOINS out of Relations + if ($cfgRelation['relwork'] && count($all_tables) > 0) { + // Get tables and columns with valid where clauses + $valid_where_clauses = $this->_getWhereClauseTablesAndColumns(); + $where_clause_tables = $valid_where_clauses['where_clause_tables']; + $where_clause_columns = $valid_where_clauses['where_clause_columns']; + // Get master table + $master = $this->_getMasterTable( + $all_tables, $all_columns, + $where_clause_columns, $where_clause_tables + ); + $from_clause = PMA_Util::backquote($master) + . PMA_getRelatives($all_tables, $master); + + } // end if ($cfgRelation['relwork'] && count($all_tables) > 0) + } // end count($_POST['criteriaColumn']) > 0 + + // In case relations are not defined, just generate the FROM clause + // from the list of tables, however we don't generate any JOIN + if (empty($from_clause) && isset($all_tables)) { + $from_clause = implode(', ', $all_tables); + } + return $from_clause; + } + + /** + * Provides the generated SQL query + * + * @param string $cfgRelation Relation Settings + * + * @return string SQL query + */ + private function _getSQLQuery($cfgRelation) + { + $sql_query = ''; + // get SELECT clause + $sql_query .= $this->_getSelectClause(); + // get FROM clause + $from_clause = $this->_getFromClause($cfgRelation); + if (! empty($from_clause)) { + $sql_query .= 'FROM ' . htmlspecialchars($from_clause) . "\n"; + } + // get WHERE clause + $sql_query .= $this->_getWhereClause(); + // get ORDER BY clause + $sql_query .= $this->_getOrderByClause(); + return $sql_query; + } + + /** + * Provides the generated QBE form + * + * @param string $cfgRelation Relation Settings + * + * @return string QBE form + */ + public function getSelectionForm($cfgRelation) + { + $html_output = '
      '; + $html_output .= '
      '; + $html_output .= ''; + // Get table's elements + $html_output .= $this->_getColumnNamesRow(); + $html_output .= $this->_getSortRow(); + $html_output .= $this->_getShowRow(); + $html_output .= $this->_getCriteriaInputboxRow(); + $html_output .= $this->_getInsDelAndOrCriteriaRows(); + $html_output .= $this->_getModifyColumnsRow(); + $html_output .= '
      '; + $this->_new_row_count--; + $url_params['db'] = $this->_db; + $url_params['criteriaColumnCount'] = $this->_new_column_count; + $url_params['rows'] = $this->_new_row_count; + $html_output .= PMA_generate_common_hidden_inputs($url_params); + $html_output .= '
      '; + // get footers + $html_output .= $this->_getTableFooters(); + // get tables select list + $html_output .= $this->_getTablesList(); + $html_output .= '
      '; + $html_output .= '
      '; + $html_output .= PMA_generate_common_hidden_inputs(array('db' => $this->_db)); + // get SQL query + $html_output .= '
      '; + $html_output .= '
      '; + $html_output .= '' + . sprintf( + __('SQL query on database %s:'), + PMA_Util::getDbLink($this->_db) + ); + $html_output .= ''; + $text_dir = 'ltr'; + $html_output .= ''; + $html_output .= '
      '; + // displays form's footers + $html_output .= '
      '; + $html_output .= ''; + $html_output .= ''; + $html_output .= '
      '; + $html_output .= '
      '; + $html_output .= '
      '; + return $html_output; + } +} +?> diff --git a/phpmyadmin/libraries/DbSearch.class.php b/phpmyadmin/libraries/DbSearch.class.php new file mode 100644 index 000000000..9ffd1d802 --- /dev/null +++ b/phpmyadmin/libraries/DbSearch.class.php @@ -0,0 +1,489 @@ +_db = $db; + // Sets criteria parameters + $this->_setSearchParams(); + } + + /** + * Sets search parameters + * + * @return void + */ + private function _setSearchParams() + { + $this->_tables_names_only = PMA_DBI_get_tables($this->_db); + + $this->_searchTypes = array( + '1' => __('at least one of the words'), + '2' => __('all words'), + '3' => __('the exact phrase'), + '4' => __('as regular expression'), + ); + + if (empty($_REQUEST['criteriaSearchType']) + || ! is_string($_REQUEST['criteriaSearchType']) + || ! array_key_exists($_REQUEST['criteriaSearchType'], $this->_searchTypes) + ) { + $this->_criteriaSearchType = 1; + unset($_REQUEST['submit_search']); + } else { + $this->_criteriaSearchType = (int) $_REQUEST['criteriaSearchType']; + $this->_searchTypeDescription + = $this->_searchTypes[$_REQUEST['criteriaSearchType']]; + } + + if (empty($_REQUEST['criteriaSearchString']) + || ! is_string($_REQUEST['criteriaSearchString']) + ) { + $this->_criteriaSearchString = ''; + unset($_REQUEST['submit_search']); + } else { + $this->_criteriaSearchString = $_REQUEST['criteriaSearchString']; + } + + $this->_criteriaTables = array(); + if (empty($_REQUEST['criteriaTables']) + || ! is_array($_REQUEST['criteriaTables']) + ) { + unset($_REQUEST['submit_search']); + } else { + $this->_criteriaTables = array_intersect( + $_REQUEST['criteriaTables'], $this->_tables_names_only + ); + } + + if (empty($_REQUEST['criteriaColumnName']) + || ! is_string($_REQUEST['criteriaColumnName']) + ) { + unset($this->_criteriaColumnName); + } else { + $this->_criteriaColumnName = PMA_Util::sqlAddSlashes( + $_REQUEST['criteriaColumnName'], true + ); + } + } + + /** + * Builds the SQL search query + * + * @param string $table The table name + * + * @return array 3 SQL querys (for count, display and delete results) + * + * @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 + */ + private function _getSearchSqls($table) + { + // Statement types + $sqlstr_select = 'SELECT'; + $sqlstr_delete = 'DELETE'; + // Table to use + $sqlstr_from = ' FROM ' + . PMA_Util::backquote($GLOBALS['db']) . '.' + . PMA_Util::backquote($table); + // Gets where clause for the query + $where_clause = $this->_getWhereClause($table); + // Builds complete queries + $sql['select_columns'] = $sqlstr_select . ' * ' . $sqlstr_from . $where_clause; + // 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 . $where_clause; + $sql['delete'] = $sqlstr_delete . $sqlstr_from . $where_clause; + + return $sql; + } + + /** + * Provides where clause for bulding SQL query + * + * @param string $table The table name + * + * @return string The generated where clause + */ + private function _getWhereClause($table) + { + $where_clause = ''; + // Columns to select + $allColumns = PMA_DBI_get_columns($GLOBALS['db'], $table); + $likeClauses = array(); + // Based on search type, decide like/regex & '%'/'' + $like_or_regex = (($this->_criteriaSearchType == 4) ? 'REGEXP' : 'LIKE'); + $automatic_wildcard = (($this->_criteriaSearchType < 3) ? '%' : ''); + // For "as regular expression" (search option 4), LIKE won't be used + // Usage example: If user is seaching for a literal $ in a regexp search, + // he should enter \$ as the value. + $this->_criteriaSearchString = PMA_Util::sqlAddSlashes( + $this->_criteriaSearchString, + ($this->_criteriaSearchType == 4 ? false : true) + ); + // Extract search words or pattern + $search_words = (($this->_criteriaSearchType > 2) + ? array($this->_criteriaSearchString) + : explode(' ', $this->_criteriaSearchString)); + + foreach ($search_words as $search_word) { + // Eliminates empty values + if (strlen($search_word) === 0) { + continue; + } + $likeClausesPerColumn = array(); + // for each column in the table + foreach ($allColumns as $column) { + if (! isset($this->_criteriaColumnName) + || strlen($this->_criteriaColumnName) == 0 + || $column['Field'] == $this->_criteriaColumnName + ) { + // Drizzle has no CONVERT and all text columns are UTF-8 + $column = ((PMA_DRIZZLE) + ? PMA_Util::backquote($column['Field']) + : 'CONVERT(' . PMA_Util::backquote($column['Field']) + . ' USING utf8)'); + $likeClausesPerColumn[] = $column . ' ' . $like_or_regex . ' ' + . "'" + . $automatic_wildcard . $search_word . $automatic_wildcard + . "'"; + } + } // end for + if (count($likeClausesPerColumn) > 0) { + $likeClauses[] = implode(' OR ', $likeClausesPerColumn); + } + } // end for + // Use 'OR' if 'at least one word' is to be searched, else use 'AND' + $implode_str = ($this->_criteriaSearchType == 1 ? ' OR ' : ' AND '); + if ( empty($likeClauses)) { + // this could happen when the "inside column" does not exist + // in any selected tables + $where_clause = ' WHERE FALSE'; + } else { + $where_clause = ' WHERE (' + . implode(') ' . $implode_str . ' (', $likeClauses) + . ')'; + } + return $where_clause; + } + + /** + * Displays database search results + * + * @return string HTML for search results + */ + public function getSearchResults() + { + $html_output = ''; + // Displays search string + $html_output .= '
      ' + . '' + . ''; + + $num_search_result_total = 0; + $odd_row = true; + // For each table selected as search criteria + foreach ($this->_criteriaTables as $each_table) { + // Gets the SQL statements + $newsearchsqls = $this->_getSearchSqls($each_table); + // Executes the "COUNT" statement + $res_cnt = PMA_DBI_fetch_value($newsearchsqls['select_count']); + $num_search_result_total += $res_cnt; + // Gets the result row's HTML for a table + $html_output .= $this->_getResultsRow( + $each_table, $newsearchsqls, $odd_row, $res_cnt + ); + $odd_row = ! $odd_row; + } // end for + $html_output .= '
      ' + . sprintf( + __('Search results for "%s" %s:'), + htmlspecialchars($this->_criteriaSearchString), + $this->_searchTypeDescription + ) + . '
      '; + // Displays total number of matches + if (count($this->_criteriaTables) > 1) { + $html_output .= '

      '; + $html_output .= sprintf( + _ngettext( + 'Total: %s match', + 'Total: %s matches', + $num_search_result_total + ), + $num_search_result_total + ); + $html_output .= '

      '; + } + return $html_output; + } + + /** + * Provides search results row with browse/delete links. + * (for a table) + * + * @param string $each_table One of the tables on which search was performed + * @param array $newsearchsqls Contains SQL queries + * @param bool $odd_row For displaying contrasting table rows + * @param integer $res_cnt Number of results found + * + * @return string HTML row + */ + private function _getResultsRow($each_table, $newsearchsqls, $odd_row, $res_cnt) + { + $this_url_params = array( + 'db' => $GLOBALS['db'], + 'table' => $each_table, + 'goto' => 'db_sql.php', + 'pos' => 0, + 'is_js_confirmed' => 0, + ); + // Start forming search results row + $html_output = ''; + // Displays results count for a table + $html_output .= ''; + $html_output .= sprintf( + _ngettext( + '%1$s match in %2$s', + '%1$s matches in %2$s', $res_cnt + ), + $res_cnt, htmlspecialchars($each_table) + ); + $html_output .= ''; + // Displays browse/delete link if result count > 0 + if ($res_cnt > 0) { + $this_url_params['sql_query'] = $newsearchsqls['select_columns']; + $browse_result_path = 'sql.php' . PMA_generate_common_url($this_url_params); + $html_output .= '' + . __('Browse') . ''; + $this_url_params['sql_query'] = $newsearchsqls['delete']; + $delete_result_path = 'sql.php' . PMA_generate_common_url($this_url_params); + $html_output .= '' + . __('Delete') . ''; + } else { + $html_output .= ' ' + .' '; + }// end if else + $html_output .= ''; + return $html_output; + } + + /** + * Provides the main search form's html + * + * @param array $url_params URL parameters + * + * @return string HTML for selection form + */ + public function getSelectionForm($url_params) + { + $html_output = ''; + $html_output .= '
      '; + $html_output .= PMA_generate_common_hidden_inputs($GLOBALS['db']); + $html_output .= '
      '; + // set legend caption + $html_output .= '' . __('Search in database') . ''; + $html_output .= ''; + // inputbox for search phrase + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + // choices for types of search + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + // displays table names as select options + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + // Displays 'select all' and 'unselect all' links + $alter_select = '' + . __('Select All') . '  / '; + $alter_select .= '' + . __('Unselect All') . ''; + $html_output .= ''; + // Inputbox for column name entry + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= '
      ' . __('Words or values to search for (wildcard: "%"):') + . ''; + $html_output .= '
      ' . __('Find:') . ''; + $choices = array( + '1' => __('at least one of the words') + . PMA_Util::showHint( + __('Words are separated by a space character (" ").') + ), + '2' => __('all words') + . PMA_Util::showHint( + __('Words are separated by a space character (" ").') + ), + '3' => __('the exact phrase'), + '4' => __('as regular expression') . ' ' + . PMA_Util::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 + $html_output .= PMA_Util::getRadioFields( + 'criteriaSearchType', $choices, $this->_criteriaSearchType, true, false + ); + $html_output .= '
      ' . __('Inside tables:') . ''; + $html_output .= ''; + $html_output .= '
      ' . $alter_select . '
      ' . __('Inside column:') . '
      '; + $html_output .= '
      '; + $html_output .= '
      '; + $html_output .= ''; + $html_output .= '
      '; + $html_output .= '
      '; + $html_output .= $this->_getResultDivs(); + + return $html_output; + } + + /** + * Provides div tags for browsing search results and sql query form. + * + * @return string div tags + */ + private function _getResultDivs() + { + $html_output = ''; + $html_output .= '
      '; + $html_output .= ''; + $html_output .= '
      '; + // div for browsing results + $html_output .= '
      '; + $html_output .= ''; + $html_output .= '
      '; + $html_output .= '
      '; + $html_output .= '
      '; + $html_output .= ''; + $html_output .= '
      '; + $html_output .= ''; + $html_output .= ''; + return $html_output; + } +} diff --git a/phpmyadmin/libraries/DisplayResults.class.php b/phpmyadmin/libraries/DisplayResults.class.php new file mode 100644 index 000000000..35dd112ea --- /dev/null +++ b/phpmyadmin/libraries/DisplayResults.class.php @@ -0,0 +1,5967 @@ + null, + + /** string Table name */ + 'table' => null, + + /** string the URL to go back in case of errors */ + 'goto' => null, + + /** string the SQL query */ + 'sql_query' => null, + + /** + * integer the total number of rows returned by the SQL query without any + * appended "LIMIT" clause programmatically + */ + 'unlim_num_rows' => null, + + /** array meta information about fields */ + 'fields_meta' => null, + + /** boolean */ + 'is_count' => null, + + /** integer */ + 'is_export' => null, + + /** boolean */ + 'is_func' => null, + + /** integer */ + 'is_analyse' => null, + + /** integer the total number of rows returned by the SQL query */ + 'num_rows' => null, + + /** integer the total number of fields returned by the SQL query */ + 'fields_cnt' => null, + + /** double time taken for execute the SQL query */ + 'querytime' => null, + + /** string path for theme images directory */ + 'pma_theme_image' => null, + + /** string */ + 'text_dir' => null, + + /** boolean */ + 'is_maint' => null, + + /** boolean */ + 'is_explain' => null, + + /** boolean */ + 'is_show' => null, + + /** array table definitions */ + 'showtable' => null, + + /** string */ + 'printview' => null, + + /** string URL query */ + 'url_query' => null, + + /** array column names to highlight */ + 'highlight_columns' => null, + + /** array informations used with vertical display mode */ + 'vertical_display' => null, + + /** array mime types information of fields */ + 'mime_map' => null, + + /** boolean */ + 'editable' => null + ); + + /** + * This global variable represent the columns which needs to be syntax + * highlighted in each database tables + * One element of this array represent all relavant columns in all tables in + * one specific database + */ + public $syntax_highlighting_column_info; + + + /** + * Get any property of this class + * + * @param string $property name of the property + * + * @return if property exist, value of the relavant property + */ + public function __get($property) + { + if (array_key_exists($property, $this->_property_array)) { + return $this->_property_array[$property]; + } + } + + + /** + * Set values for any property of this class + * + * @param string $property name of the property + * @param any $value value to set + * + * @return void + */ + public function __set($property, $value) + { + if (array_key_exists($property, $this->_property_array)) { + $this->_property_array[$property] = $value; + } + } + + + /** + * Constructor for PMA_DisplayResults class + * + * @param string $db the database name + * @param string $table the table name + * @param string $goto the URL to go back in case of errors + * @param string $sql_query the SQL query + * + * @access public + */ + public function __construct($db, $table, $goto, $sql_query) + { + $this->syntax_highlighting_column_info = array( + 'information_schema' => array( + 'processlist' => array( + 'info' => array( + 'libraries/plugins/transformations/' + . 'Text_Plain_Formatted.class.php', + 'Text_Plain_Formatted', + 'Text_Plain' + ) + ) + ) + ); + + $this->__set('db', $db); + $this->__set('table', $table); + $this->__set('goto', $goto); + $this->__set('sql_query', $sql_query); + } + + + /** + * Set properties which were not initialized at the constructor + * + * @param type $unlim_num_rows integer the total number of rows returned by + * the SQL query without any appended + * "LIMIT" clause programmatically + * @param type $fields_meta array meta information about fields + * @param type $is_count boolean + * @param type $is_export integer + * @param type $is_func boolean + * @param type $is_analyse integer + * @param type $num_rows integer total no. of rows returned by SQL query + * @param type $fields_cnt integer total no.of fields returned by SQL query + * @param type $querytime double time taken for execute the SQL query + * @param type $pmaThemeImage string path for theme images directory + * @param type $text_dir string + * @param type $is_maint boolean + * @param type $is_explain boolean + * @param type $is_show boolean + * @param type $showtable array table definitions + * @param type $printview string + * @param type $url_query string URL query + * @param type $editable boolean whether the resutls set is editable + * + * @return void + * + * @see sql.php + */ + public function setProperties( + $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func, + $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir, + $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query, + $editable + ) { + + $this->__set('unlim_num_rows', $unlim_num_rows); + $this->__set('fields_meta', $fields_meta); + $this->__set('is_count', $is_count); + $this->__set('is_export', $is_export); + $this->__set('is_func', $is_func); + $this->__set('is_analyse', $is_analyse); + $this->__set('num_rows', $num_rows); + $this->__set('fields_cnt', $fields_cnt); + $this->__set('querytime', $querytime); + $this->__set('pma_theme_image', $pmaThemeImage); + $this->__set('text_dir', $text_dir); + $this->__set('is_maint', $is_maint); + $this->__set('is_explain', $is_explain); + $this->__set('is_show', $is_show); + $this->__set('showtable', $showtable); + $this->__set('printview', $printview); + $this->__set('url_query', $url_query); + $this->__set('editable', $editable); + + } // end of the 'setProperties()' function + + + /** + * Defines the display mode to use for the results of a SQL query + * + * It uses a synthetic string that contains all the required informations. + * In this string: + * - the first two characters stand for the action to do while + * clicking on the "edit" link (e.g. 'ur' for update a row, 'nn' for no + * edit link...); + * - the next two characters stand for the action to do while + * clicking on the "delete" link (e.g. 'kp' for kill a process, 'nn' for + * no delete link...); + * - the next characters are boolean values (1/0) and respectively stand + * for sorting links, navigation bar, "insert a new row" link, the + * bookmark feature, the expand/collapse text/blob fields button and + * the "display printable view" option. + * Of course '0'/'1' means the feature won't/will be enabled. + * + * @param string &$the_disp_mode the synthetic value for display_mode (see a few + * lines above for explanations) + * @param integer &$the_total the total number of rows returned by the SQL + * query without any programmatically appended + * LIMIT clause + * (just a copy of $unlim_num_rows if it exists, + * elsecomputed inside this function) + * + * @return array an array with explicit indexes for all the display + * elements + * + * @access private + * + * @see getTable() + */ + private function _setDisplayMode(&$the_disp_mode, &$the_total) + { + + // Following variables are needed for use in isset/empty or + // use with array indexes or safe use in foreach + $db = $this->__get('db'); + $table = $this->__get('table'); + $unlim_num_rows = $this->__get('unlim_num_rows'); + $fields_meta = $this->__get('fields_meta'); + $printview = $this->__get('printview'); + + // 1. Initializes the $do_display array + $do_display = array(); + $do_display['edit_lnk'] = $the_disp_mode[0] . $the_disp_mode[1]; + $do_display['del_lnk'] = $the_disp_mode[2] . $the_disp_mode[3]; + $do_display['sort_lnk'] = (string) $the_disp_mode[4]; + $do_display['nav_bar'] = (string) $the_disp_mode[5]; + $do_display['ins_row'] = (string) $the_disp_mode[6]; + $do_display['bkm_form'] = (string) $the_disp_mode[7]; + $do_display['text_btn'] = (string) $the_disp_mode[8]; + $do_display['pview_lnk'] = (string) $the_disp_mode[9]; + + // 2. Display mode is not "false for all elements" -> updates the + // display mode + if ($the_disp_mode != 'nnnn000000') { + + if (isset($printview) && ($printview == '1')) { + // 2.0 Print view -> set all elements to false! + $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link + $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link + $do_display['sort_lnk'] = (string) '0'; + $do_display['nav_bar'] = (string) '0'; + $do_display['ins_row'] = (string) '0'; + $do_display['bkm_form'] = (string) '0'; + $do_display['text_btn'] = (string) '0'; + $do_display['pview_lnk'] = (string) '0'; + + } elseif ($this->__get('is_count') || $this->__get('is_analyse') + || $this->__get('is_maint') || $this->__get('is_explain') + ) { + // 2.1 Statement is a "SELECT COUNT", a + // "CHECK/ANALYZE/REPAIR/OPTIMIZE", an "EXPLAIN" one or + // contains a "PROC ANALYSE" part + $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link + $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link + $do_display['sort_lnk'] = (string) '0'; + $do_display['nav_bar'] = (string) '0'; + $do_display['ins_row'] = (string) '0'; + $do_display['bkm_form'] = (string) '1'; + + if ($this->__get('is_maint')) { + $do_display['text_btn'] = (string) '1'; + } else { + $do_display['text_btn'] = (string) '0'; + } + $do_display['pview_lnk'] = (string) '1'; + + } elseif ($this->__get('is_show')) { + // 2.2 Statement is a "SHOW..." + /** + * 2.2.1 + * @todo defines edit/delete links depending on show statement + */ + $tmp = preg_match( + '@^SHOW[[:space:]]+(VARIABLES|(FULL[[:space:]]+)?' + . 'PROCESSLIST|STATUS|TABLE|GRANTS|CREATE|LOGS|DATABASES|FIELDS' + . ')@i', + $this->__get('sql_query'), $which + ); + if (isset($which[1]) + && (strpos(' ' . strtoupper($which[1]), 'PROCESSLIST') > 0) + ) { + // no edit link + $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; + // "kill process" type edit link + $do_display['del_lnk'] = self::KILL_PROCESS; + } else { + // Default case -> no links + // no edit link + $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; + // no delete link + $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE; + } + // 2.2.2 Other settings + $do_display['sort_lnk'] = (string) '0'; + $do_display['nav_bar'] = (string) '0'; + $do_display['ins_row'] = (string) '0'; + $do_display['bkm_form'] = (string) '1'; + $do_display['text_btn'] = (string) '1'; + $do_display['pview_lnk'] = (string) '1'; + + } else { + // 2.3 Other statements (ie "SELECT" ones) -> updates + // $do_display['edit_lnk'], $do_display['del_lnk'] and + // $do_display['text_btn'] (keeps other default values) + $prev_table = $fields_meta[0]->table; + $do_display['text_btn'] = (string) '1'; + + for ($i = 0; $i < $this->__get('fields_cnt'); $i++) { + + $is_link = ($do_display['edit_lnk'] != self::NO_EDIT_OR_DELETE) + || ($do_display['del_lnk'] != self::NO_EDIT_OR_DELETE) + || ($do_display['sort_lnk'] != '0') + || ($do_display['ins_row'] != '0'); + + // 2.3.2 Displays edit/delete/sort/insert links? + if ($is_link + && (($fields_meta[$i]->table == '') + || ($fields_meta[$i]->table != $prev_table)) + ) { + // don't display links + $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; + $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE; + /** + * @todo May be problematic with same field names + * in two joined table. + */ + // $do_display['sort_lnk'] = (string) '0'; + $do_display['ins_row'] = (string) '0'; + if ($do_display['text_btn'] == '1') { + break; + } + } // end if (2.3.2) + + // 2.3.3 Always display print view link + $do_display['pview_lnk'] = (string) '1'; + $prev_table = $fields_meta[$i]->table; + + } // end for + } // end if..elseif...else (2.1 -> 2.3) + } // end if (2) + + // 3. Gets the total number of rows if it is unknown + if (isset($unlim_num_rows) && $unlim_num_rows != '') { + $the_total = $unlim_num_rows; + } elseif ((($do_display['nav_bar'] == '1') + || ($do_display['sort_lnk'] == '1')) + && (strlen($db) && !empty($table)) + ) { + $the_total = PMA_Table::countRecords($db, $table); + } + + // 4. If navigation bar or sorting fields names URLs should be + // displayed but there is only one row, change these settings to + // false + if ($do_display['nav_bar'] == '1' || $do_display['sort_lnk'] == '1') { + + // - Do not display sort links if less than 2 rows. + // - For a VIEW we (probably) did not count the number of rows + // so don't test this number here, it would remove the possibility + // of sorting VIEW results. + if (isset($unlim_num_rows) + && ($unlim_num_rows < 2) + && ! PMA_Table::isView($db, $table) + ) { + // force display of navbar for vertical/horizontal display-choice. + // $do_display['nav_bar'] = (string) '0'; + $do_display['sort_lnk'] = (string) '0'; + } + } // end if (3) + + // 5. Updates the synthetic var + $the_disp_mode = join('', $do_display); + + return $do_display; + + } // end of the 'setDisplayMode()' function + + + /** + * Return true if we are executing a query in the form of + * "SELECT * FROM ..." + * + * @param array $analyzed_sql the analyzed query + * + * @return boolean + * + * @access private + * + * @see _getTableHeaders(), _getColumnParams() + */ + private function _isSelect($analyzed_sql) + { + if (!isset($analyzed_sql[0]['select_expr'])) { + $analyzed_sql[0]['select_expr'] = 0; + } + + return ! ($this->__get('is_count') || $this->__get('is_export') + || $this->__get('is_func') || $this->__get('is_analyse')) + && (count($analyzed_sql[0]['select_expr']) == 0) + && isset($analyzed_sql[0]['queryflags']['select_from']) + && (count($analyzed_sql[0]['table_ref']) == 1); + } + + + /** + * Get a navigation button + * + * @param string $caption iconic caption for button + * @param string $title text for button + * @param integer $pos position for next query + * @param string $html_sql_query query ready for display + * @param string $onsubmit optional onsubmit clause + * @param string $input_for_real_end optional hidden field for special treatment + * @param string $onclick optional onclick clause + * + * @return string html content + * + * @access private + * + * @see _getMoveBackwardButtonsForTableNavigation(), + * _getMoveForwardButtonsForTableNavigation() + */ + private function _getTableNavigationButton( + $caption, $title, $pos, $html_sql_query, $onsubmit = '', + $input_for_real_end = '', $onclick = '' + ) { + + $caption_output = ''; + // for true or 'both' + if ($GLOBALS['cfg']['NavigationBarIconic']) { + $caption_output .= $caption; + } + + // for false or 'both' + if (($GLOBALS['cfg']['NavigationBarIconic'] === false) + || ($GLOBALS['cfg']['NavigationBarIconic'] === self::POSITION_BOTH) + ) { + $caption_output .= ' ' . $title; + } + $title_output = ' title="' . $title . '"'; + + return '' + . '
      ' + . PMA_generate_common_hidden_inputs( + $this->__get('db'), $this->__get('table') + ) + . '' + . '' + . '' + . $input_for_real_end + . '' + . '
      ' + . ''; + + } // end function _getTableNavigationButton() + + + /** + * Get a navigation bar to browse among the results of a SQL query + * + * @param integer $pos_next the offset for the "next" page + * @param integer $pos_prev the offset for the "previous" page + * @param string $id_for_direction_dropdown the id for the direction dropdown + * @param boolean $is_innodb whether its InnoDB or not + * + * @return string html content + * + * @access private + * + * @see _getTable() + */ + private function _getTableNavigation( + $pos_next, $pos_prev, $id_for_direction_dropdown, $is_innodb + ) { + + $table_navigation_html = ''; + $showtable = $this->__get('showtable'); // To use in isset + + // here, using htmlentities() would cause problems if the query + // contains accented characters + $html_sql_query = htmlspecialchars($this->__get('sql_query')); + + /** + * @todo move this to a central place + * @todo for other future table types + */ + $is_innodb = (isset($showtable['Type']) + && $showtable['Type'] == self::TABLE_TYPE_INNO_DB); + + // Navigation bar + $table_navigation_html .= '' + . '' + . ''; + + // Move to the beginning or to the previous page + if ($_SESSION['tmp_user_values']['pos'] + && ($_SESSION['tmp_user_values']['max_rows'] != self::ALL_ROWS) + ) { + + $table_navigation_html + .= $this->_getMoveBackwardButtonsForTableNavigation( + $html_sql_query, $pos_prev + ); + + } // end move back + + $nbTotalPage = 1; + //page redirection + // (unless we are showing all records) + if ($_SESSION['tmp_user_values']['max_rows'] != self::ALL_ROWS) { //if1 + + $pageNow = @floor( + $_SESSION['tmp_user_values']['pos'] + / $_SESSION['tmp_user_values']['max_rows'] + ) + 1; + + $nbTotalPage = @ceil( + $this->__get('unlim_num_rows') + / $_SESSION['tmp_user_values']['max_rows'] + ); + + if ($nbTotalPage > 1) { //if2 + + $table_navigation_html .= ''; + } //_if2 + } //_if1 + + // Display the "Show all" button if allowed + if (($this->__get('num_rows') < $this->__get('unlim_num_rows')) + && ($GLOBALS['cfg']['ShowAll'] + || ($GLOBALS['cfg']['MaxRows'] * 5 >= $this->__get('unlim_num_rows'))) + ) { + + $table_navigation_html .= $this->_getShowAllButtonForTableNavigation( + $html_sql_query + ); + + } // end show all + + // Move to the next page or to the last one + $endpos = $_SESSION['tmp_user_values']['pos'] + + $_SESSION['tmp_user_values']['max_rows']; + + if (($endpos < $this->__get('unlim_num_rows')) + && ($this->__get('num_rows') >= $_SESSION['tmp_user_values']['max_rows']) + && ($_SESSION['tmp_user_values']['max_rows'] != self::ALL_ROWS) + ) { + + $table_navigation_html + .= $this->_getMoveForwardButtonsForTableNavigation( + $html_sql_query, $pos_next, $is_innodb + ); + + } // end move toward + + // show separator if pagination happen + if ($nbTotalPage > 1) { + $table_navigation_html + .= ''; + } + + $table_navigation_html .= '' + . ''; + + // if displaying a VIEW, $unlim_num_rows could be zero because + // of $cfg['MaxExactCountViews']; in this case, avoid passing + // the 5th parameter to checkFormElementInRange() + // (this means we can't validate the upper limit + $table_navigation_html .= '' + . '' + . '' + . ''; + + return $table_navigation_html; + + } // end of the '_getTableNavigation()' function + + + /** + * Prepare move backward buttons - previous and first + * + * @param string $html_sql_query the sql encoded by html special characters + * @param integer $pos_prev the offset for the "previous" page + * + * @return string html content + * + * @access private + * + * @see _getTableNavigation() + */ + private function _getMoveBackwardButtonsForTableNavigation( + $html_sql_query, $pos_prev + ) { + return $this->_getTableNavigationButton( + '<<', _pgettext('First page', 'Begin'), 0, $html_sql_query + ) + . $this->_getTableNavigationButton( + '<', _pgettext('Previous page', 'Previous'), $pos_prev, + $html_sql_query + ); + } // end of the '_getMoveBackwardButtonsForTableNavigation()' function + + + /** + * Prepare Show All button for table navigation + * + * @param string $html_sql_query the sql encoded by html special characters + * + * @return string html content + * + * @access private + * + * @see _getTableNavigation() + */ + private function _getShowAllButtonForTableNavigation($html_sql_query) + { + return "\n" + . '' + . '
      ' + . PMA_generate_common_hidden_inputs( + $this->__get('db'), $this->__get('table') + ) + . '' + . '' + . '' + . '' + . '' + . '
      ' + . ''; + } // end of the '_getShowAllButtonForTableNavigation()' function + + + /** + * Prepare move farward buttons - next and last + * + * @param string $html_sql_query the sql encoded by html special characters + * @param integer $pos_next the offset for the "next" page + * @param boolean $is_innodb whether its InnoDB or not + * + * @return string $buttons_html html content + * + * @access private + * + * @see _getTableNavigation() + */ + private function _getMoveForwardButtonsForTableNavigation( + $html_sql_query, $pos_next, $is_innodb + ) { + + // display the Next button + $buttons_html = $this->_getTableNavigationButton( + '>', + _pgettext('Next page', 'Next'), + $pos_next, + $html_sql_query + ); + + // prepare some options for the End button + if ($is_innodb + && $this->__get('unlim_num_rows') > $GLOBALS['cfg']['MaxExactCount'] + ) { + $input_for_real_end = ''; + // no backquote around this message + $onclick = ''; + } else { + $input_for_real_end = $onclick = ''; + } + + $onsubmit = 'onsubmit="return ' + . ($_SESSION['tmp_user_values']['pos'] + + $_SESSION['tmp_user_values']['max_rows'] + < $this->__get('unlim_num_rows') + && $this->__get('num_rows') >= $_SESSION['tmp_user_values']['max_rows']) + ? 'true' + : 'false' . '"'; + + // display the End button + $buttons_html .= $this->_getTableNavigationButton( + '>>', + _pgettext('Last page', 'End'), + @((ceil( + $this->__get('unlim_num_rows') + / $_SESSION['tmp_user_values']['max_rows'] + )- 1) * $_SESSION['tmp_user_values']['max_rows']), + $html_sql_query, $onsubmit, $input_for_real_end, $onclick + ); + + return $buttons_html; + + } // end of the '_getMoveForwardButtonsForTableNavigation()' function + + + /** + * Prepare feilds followed by Show button for table navigation + * Start row, Number of rows, Headers every + * + * @param string $html_sql_query the sql encoded by html special + * characters + * @param integer $pos_next the offset for the "next" page + * @param string $id_for_direction_dropdown the id for the direction dropdown + * + * @return string $additional_fields_html html content + * + * @access private + * + * @see _getTableNavigation() + */ + private function _getAdditionalFieldsForTableNavigation( + $html_sql_query, $pos_next, $id_for_direction_dropdown + ) { + + $additional_fields_html = ''; + + $additional_fields_html .= '' + . '' + . '' + . __('Start row') . ': ' . "\n" + . '' + . __('Number of rows') . ': ' . "\n" + . ''; + + if ($GLOBALS['cfg']['ShowDisplayDirection']) { + // Display mode (horizontal/vertical and repeat headers) + $additional_fields_html .= __('Mode') . ': ' . "\n"; + $choices = array( + 'horizontal' => __('horizontal'), + 'horizontalflipped' => __('horizontal (rotated headers)'), + 'vertical' => __('vertical') + ); + + $additional_fields_html .= PMA_Util::getDropdown( + 'disp_direction', $choices, + $_SESSION['tmp_user_values']['disp_direction'], + $id_for_direction_dropdown + ); + unset($choices); + } + + $additional_fields_html .= sprintf( + __('Headers every %s rows'), + ' ' + ); + + return $additional_fields_html; + + } // end of the '_getAdditionalFieldsForTableNavigation()' function + + + /** + * Get the headers of the results table + * + * @param array &$is_display which elements to display + * @param array $analyzed_sql the analyzed query + * @param string $sort_expression sort expression + * @param string $sort_expression_nodirection sort expression without direction + * @param string $sort_direction sort direction + * @param boolean $is_limited_display with limited operations or not + * + * @return string html content + * + * @access private + * + * @see getTable() + */ + private function _getTableHeaders( + &$is_display, $analyzed_sql = '', + $sort_expression = '', $sort_expression_nodirection = '', + $sort_direction = '', $is_limited_display = false + ) { + + $table_headers_html = ''; + // Following variable are needed for use in isset/empty or + // use with array indexes/safe use in foreach + $fields_meta = $this->__get('fields_meta'); + $highlight_columns = $this->__get('highlight_columns'); + $printview = $this->__get('printview'); + $vertical_display = $this->__get('vertical_display'); + + // required to generate sort links that will remember whether the + // "Show all" button has been clicked + $sql_md5 = md5($this->__get('sql_query')); + $session_max_rows = $is_limited_display + ? 0 + : $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows']; + + $direction = isset($_SESSION['tmp_user_values']['disp_direction']) + ? $_SESSION['tmp_user_values']['disp_direction'] + : ''; + + if ($analyzed_sql == '') { + $analyzed_sql = array(); + } + + $directionCondition = ($direction == self::DISP_DIR_HORIZONTAL) + || ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED); + + // can the result be sorted? + if ($is_display['sort_lnk'] == '1') { + + list($unsorted_sql_query, $drop_down_html) + = $this->_getUnsortedSqlAndSortByKeyDropDown( + $analyzed_sql, $sort_expression + ); + + $table_headers_html .= $drop_down_html; + + } + + // Output data needed for grid editing + $table_headers_html .= '' + . '
      ' + . PMA_generate_common_hidden_inputs( + $this->__get('db'), $this->__get('table') + ) + . '
      '; + + // Output data needed for column reordering and show/hide column + if ($this->_isSelect($analyzed_sql)) { + $table_headers_html .= $this->_getDataForResettingColumnOrder(); + } + + $vertical_display['emptypre'] = 0; + $vertical_display['emptyafter'] = 0; + $vertical_display['textbtn'] = ''; + $full_or_partial_text_link = null; + + $this->__set('vertical_display', $vertical_display); + + // Display options (if we are not in print view) + if (! (isset($printview) && ($printview == '1')) && ! $is_limited_display) { + + $table_headers_html .= $this->_getOptionsBlock(); + + // prepare full/partial text button or link + $full_or_partial_text_link = $this->_getFullOrPartialTextButtonOrLink(); + } + + // Start of form for multi-rows edit/delete/export + $table_headers_html .= $this->_getFormForMultiRowOperations( + $is_display['del_lnk'] + ); + + // 1. Set $colspan or $rowspan and generate html with full/partial + // text button or link + list($colspan, $rowspan, $button_html) + = $this->_getFieldVisibilityParams( + $directionCondition, $is_display, $full_or_partial_text_link + ); + + $table_headers_html .= $button_html; + + // 2. Displays the fields' name + // 2.0 If sorting links should be used, checks if the query is a "JOIN" + // statement (see 2.1.3) + + // 2.0.1 Prepare Display column comments if enabled + // ($GLOBALS['cfg']['ShowBrowseComments']). + // Do not show comments, if using horizontalflipped mode, + // because of space usage + $comments_map = $this->_getTableCommentsArray($direction, $analyzed_sql); + + if ($GLOBALS['cfgRelation']['commwork'] + && $GLOBALS['cfgRelation']['mimework'] + && $GLOBALS['cfg']['BrowseMIME'] + && ! $_SESSION['tmp_user_values']['hide_transformation'] + ) { + include_once './libraries/transformations.lib.php'; + $this->__set( + 'mime_map', + PMA_getMIME($this->__get('db'), $this->__get('table')) + ); + } + + // See if we have to highlight any header fields of a WHERE query. + // Uses SQL-Parser results. + $this->_setHighlightedColumnGlobalField($analyzed_sql); + + list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql); + + for ($j = 0; $j < $this->__get('fields_cnt'); $j++) { + + // assign $i with appropriate column order + $i = $col_order ? $col_order[$j] : $j; + + // See if this column should get highlight because it's used in the + // where-query. + $condition_field = (isset($highlight_columns[$fields_meta[$i]->name]) + || isset($highlight_columns[PMA_Util::backquote($fields_meta[$i]->name)])) + ? true + : false; + + // 2.0 Prepare comment-HTML-wrappers for each row, if defined/enabled. + $comments = $this->_getCommentForRow($comments_map, $fields_meta[$i]); + + $vertical_display = $this->__get('vertical_display'); + + if (($is_display['sort_lnk'] == '1') && ! $is_limited_display) { + + list($order_link, $sorted_headrer_html) + = $this->_getOrderLinkAndSortedHeaderHtml( + $fields_meta[$i], $sort_expression, + $sort_expression_nodirection, $i, $unsorted_sql_query, + $session_max_rows, $direction, $comments, + $sort_direction, $directionCondition, $col_visib, + $col_visib[$j], $condition_field + ); + + $table_headers_html .= $sorted_headrer_html; + + $vertical_display['desc'][] = ' ' . "\n" . $order_link . $comments . ' ' . "\n"; + } else { + // 2.2 Results can't be sorted + + if ($directionCondition) { + $table_headers_html + .= $this->_getDraggableClassForNonSortableColumns( + $col_visib, $col_visib[$j], $condition_field, + $direction, $fields_meta[$i], $comments + ); + } + + $vertical_display['desc'][] = ' ' . "\n" . ' ' + . htmlspecialchars($fields_meta[$i]->name) + . "\n" . $comments . ' '; + } // end else (2.2) + + $this->__set('vertical_display', $vertical_display); + + } // end for + + // Display column at rightside - checkboxes or empty column + $table_headers_html .= $this->_getColumnAtRightSide( + $is_display, $directionCondition, $full_or_partial_text_link, + $colspan, $rowspan + ); + + if ($directionCondition) { + $table_headers_html .= '' + . ''; + } + + return $table_headers_html; + + } // end of the '_getTableHeaders()' function + + + /** + * Prepare unsorted sql query and sort by key drop down + * + * @param array $analyzed_sql the analyzed query + * @param string $sort_expression sort expression + * + * @return array two element array - $unsorted_sql_query, $drop_down_html + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getUnsortedSqlAndSortByKeyDropDown( + $analyzed_sql, $sort_expression + ) { + + $drop_down_html = ''; + + // Just as fallback + $unsorted_sql_query = $this->__get('sql_query'); + if (isset($analyzed_sql[0]['unsorted_query'])) { + $unsorted_sql_query = $analyzed_sql[0]['unsorted_query']; + } + // Handles the case of multiple clicks on a column's header + // which would add many spaces before "ORDER BY" in the + // generated query. + $unsorted_sql_query = trim($unsorted_sql_query); + + // sorting by indexes, only if it makes sense (only one table ref) + if (isset($analyzed_sql) + && isset($analyzed_sql[0]) + && isset($analyzed_sql[0]['querytype']) + && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT) + && isset($analyzed_sql[0]['table_ref']) + && (count($analyzed_sql[0]['table_ref']) == 1) + ) { + // grab indexes data: + $indexes = PMA_Index::getFromTable( + $this->__get('table'), + $this->__get('db') + ); + + // do we have any index? + if ($indexes) { + $drop_down_html = $this->_getSortByKeyDropDown( + $indexes, $sort_expression, + $unsorted_sql_query + ); + } + } + + return array($unsorted_sql_query, $drop_down_html); + + } // end of the '_getUnsortedSqlAndSortByKeyDropDown()' function + + + /** + * Prepare sort by key dropdown - html code segment + * + * @param array $indexes the indexes of the table for sort criteria + * @param string $sort_expression the sort expression + * @param string $unsorted_sql_query the unsorted sql query + * + * @return string $drop_down_html html content + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getSortByKeyDropDown( + $indexes, $sort_expression, $unsorted_sql_query + ) { + + $drop_down_html = ''; + + $drop_down_html .= '
      ' . "\n" + . PMA_generate_common_hidden_inputs( + $this->__get('db'), $this->__get('table') + ) + . __('Sort by key') + . ': ' . "\n" + . '
      ' . "\n"; + + return $drop_down_html; + + } // end of the '_getSortByKeyDropDown()' function + + + /** + * Set column span, row span and prepare html with full/partial + * text button or link + * + * @param boolean $directionCondition display direction horizontal or + * horizontalflipped + * @param array &$is_display which elements to display + * @param string $full_or_partial_text_link full/partial link or text button + * + * @return array 3 element array - $colspan, $rowspan, $button_html + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getFieldVisibilityParams( + $directionCondition, &$is_display, $full_or_partial_text_link + ) { + + $button_html = ''; + $colspan = $rowspan = null; + $vertical_display = $this->__get('vertical_display'); + + // 1. Displays the full/partial text button (part 1)... + if ($directionCondition) { + + $button_html .= '' . "\n"; + + $colspan = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE) + && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) + ? ' colspan="4"' + : ''; + + } else { + $rowspan = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE) + && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) + ? ' rowspan="4"' + : ''; + } + + // ... before the result table + if ((($is_display['edit_lnk'] == self::NO_EDIT_OR_DELETE) + && ($is_display['del_lnk'] == self::NO_EDIT_OR_DELETE)) + && ($is_display['text_btn'] == '1') + ) { + + $vertical_display['emptypre'] + = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE) + && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0; + + if ($directionCondition) { + + $button_html .= '' + . '' + . '' + . ''; + + // end horizontal/horizontalflipped mode + } else { + + $span = $this->__get('num_rows') + 1 + floor( + $this->__get('num_rows') + / $_SESSION['tmp_user_values']['repeat_cells'] + ); + $button_html .= ''; + + } // end vertical mode + + } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && ($is_display['text_btn'] == '1') + ) { + // ... at the left column of the result table header if possible + // and required + + $vertical_display['emptypre'] + = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE) + && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0; + + if ($directionCondition) { + + $button_html .= '' + . $full_or_partial_text_link . ''; + // end horizontal/horizontalflipped mode + + } else { + + $vertical_display['textbtn'] + = ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n"; + } // end vertical mode + + } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE) + || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) + ) { + // ... elseif no button, displays empty(ies) col(s) if required + + $vertical_display['emptypre'] + = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE) + && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0; + + if ($directionCondition) { + + $button_html .= ''; + + // end horizontal/horizontalfipped mode + } else { + $vertical_display['textbtn'] = ' ' . "\n"; + } // end vertical mode + + } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) + && ($directionCondition) + ) { + // ... elseif display an empty column if the actions links are + // disabled to match the rest of the table + $button_html .= ''; + } + + $this->__set('vertical_display', $vertical_display); + + return array($colspan, $rowspan, $button_html); + + } // end of the '_getFieldVisibilityParams()' function + + + /** + * Get table comments as array + * + * @param boolean $direction display direction, horizontal + * or horizontalflipped + * @param array $analyzed_sql the analyzed query + * + * @return array $comments_map table comments when condition true + * null when condition falls + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getTableCommentsArray($direction, $analyzed_sql) + { + + $comments_map = null; + + if ($GLOBALS['cfg']['ShowBrowseComments'] + && ($direction != self::DISP_DIR_HORIZONTAL_FLIPPED) + ) { + $comments_map = array(); + if (isset($analyzed_sql[0]) + && is_array($analyzed_sql[0]) + && isset($analyzed_sql[0]['table_ref']) + ) { + foreach ($analyzed_sql[0]['table_ref'] as $tbl) { + $tb = $tbl['table_true_name']; + $comments_map[$tb] = PMA_getComments($this->__get('db'), $tb); + unset($tb); + } + } + } + + return $comments_map; + + } // end of the '_getTableCommentsArray()' function + + + /** + * Set global array for store highlighted header fields + * + * @param array $analyzed_sql the analyzed query + * + * @return void + * + * @access private + * + * @see _getTableHeaders() + */ + private function _setHighlightedColumnGlobalField($analyzed_sql) + { + + $highlight_columns = array(); + if (isset($analyzed_sql) && isset($analyzed_sql[0]) + && isset($analyzed_sql[0]['where_clause_identifiers']) + ) { + + $wi = 0; + if (isset($analyzed_sql[0]['where_clause_identifiers']) + && is_array($analyzed_sql[0]['where_clause_identifiers']) + ) { + foreach ($analyzed_sql[0]['where_clause_identifiers'] + as $wci_nr => $wci + ) { + $highlight_columns[$wci] = 'true'; + } + } + } + + $this->__set('highlight_columns', $highlight_columns); + + } // end of the '_setHighlightedColumnGlobalField()' function + + + /** + * Prepare data for column restoring and show/hide + * + * @return string $data_html html content + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getDataForResettingColumnOrder() + { + + $data_html = ''; + + // generate the column order, if it is set + $pmatable = new PMA_Table($this->__get('table'), $this->__get('db')); + $col_order = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_ORDER); + + if ($col_order) { + $data_html .= ''; + } + + $col_visib = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_VISIB); + + if ($col_visib) { + $data_html .= ''; + } + + // generate table create time + if (! PMA_Table::isView($this->__get('db'), $this->__get('table'))) { + $data_html .= ''; + } + + return $data_html; + + } // end of the '_getDataForResettingColumnOrder()' function + + + /** + * Prepare option fields block + * + * @return string $options_html html content + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getOptionsBlock() + { + + $options_html = ''; + + $options_html .= '
      $this->__get('db'), + 'table' => $this->__get('table'), + 'sql_query' => $this->__get('sql_query'), + 'goto' => $this->__get('goto'), + 'display_options_form' => 1 + ); + + $options_html .= PMA_generate_common_hidden_inputs($url_params) + . '
      ' + . PMA_Util::getDivForSliderEffect( + 'displayoptions', __('Options') + ) + . '
      '; + + $options_html .= '
      '; + $choices = array( + 'P' => __('Partial texts'), + 'F' => __('Full texts') + ); + + $options_html .= PMA_Util::getRadioFields( + 'display_text', $choices, + $_SESSION['tmp_user_values']['display_text'] + ) + . '
      '; + + if ($GLOBALS['cfgRelation']['relwork'] + && $GLOBALS['cfgRelation']['displaywork'] + ) { + $options_html .= '
      '; + $choices = array( + 'K' => __('Relational key'), + 'D' => __('Relational display column') + ); + + $options_html .= PMA_Util::getRadioFields( + 'relational_display', $choices, + $_SESSION['tmp_user_values']['relational_display'] + ) + . '
      '; + } + + $options_html .= '
      ' + . PMA_Util::getCheckbox( + 'display_binary', __('Show binary contents'), + ! empty($_SESSION['tmp_user_values']['display_binary']), false + ) + . '
      ' + . PMA_Util::getCheckbox( + 'display_blob', __('Show BLOB contents'), + ! empty($_SESSION['tmp_user_values']['display_blob']), false + ) + . '
      ' + . PMA_Util::getCheckbox( + 'display_binary_as_hex', __('Show binary contents as HEX'), + ! empty($_SESSION['tmp_user_values']['display_binary_as_hex']), false + ) + . '
      '; + + // I would have preferred to name this "display_transformation". + // This is the only way I found to be able to keep this setting sticky + // per SQL query, and at the same time have a default that displays + // the transformations. + $options_html .= '
      ' + . PMA_Util::getCheckbox( + 'hide_transformation', __('Hide browser transformation'), + ! empty($_SESSION['tmp_user_values']['hide_transformation']), false + ) + . '
      '; + + if (! PMA_DRIZZLE) { + $options_html .= '
      '; + $choices = array( + 'GEOM' => __('Geometry'), + 'WKT' => __('Well Known Text'), + 'WKB' => __('Well Known Binary') + ); + + $options_html .= PMA_Util::getRadioFields( + 'geometry_display', $choices, + $_SESSION['tmp_user_values']['geometry_display'] + ) + . '
      '; + } + + $options_html .= '
      ' + . '
      '; + + $options_html .= '
      ' + . '' + . '
      ' + . '
      ' + . ''; + + return $options_html; + + } // end of the '_getOptionsBlock()' function + + + /** + * Get full/partial text button or link + * + * @return string html content + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getFullOrPartialTextButtonOrLink() + { + + $url_params_full_text = array( + 'db' => $this->__get('db'), + 'table' => $this->__get('table'), + 'sql_query' => $this->__get('sql_query'), + 'goto' => $this->__get('goto'), + 'full_text_button' => 1 + ); + + if ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_FULL_TEXT) { + // currently in fulltext mode so show the opposite link + $tmp_image_file = $this->__get('pma_theme_image') . 's_partialtext.png'; + $tmp_txt = __('Partial texts'); + $url_params_full_text['display_text'] = self::DISPLAY_PARTIAL_TEXT; + } else { + $tmp_image_file = $this->__get('pma_theme_image') . 's_fulltext.png'; + $tmp_txt = __('Full texts'); + $url_params_full_text['display_text'] = self::DISPLAY_FULL_TEXT; + } + + $tmp_image = ''
+                     . $tmp_txt . ''; + $tmp_url = 'sql.php' . PMA_generate_common_url($url_params_full_text); + + return PMA_Util::linkOrButton( + $tmp_url, $tmp_image, array(), false + ); + + } // end of the '_getFullOrPartialTextButtonOrLink()' function + + + /** + * Prepare html form for multi row operations + * + * @param string $del_lnk the delete link of current row + * + * @return string $form_html html content + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getFormForMultiRowOperations($del_lnk) + { + + $form_html = ''; + + if (($del_lnk == self::DELETE_ROW) || ($del_lnk == self::KILL_PROCESS)) { + + $form_html .= '
      __get('db'), $this->__get('table'), 1 + ) + . ''; + } + + $form_html .= ''; + + return $form_html; + + } // end of the '_getFormForMultiRowOperations()' function + + + /** + * Get comment for row + * + * @param array $comments_map comments array + * @param array $fields_meta set of field properties + * + * @return string $comment html content + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getCommentForRow($comments_map, $fields_meta) + { + $comments = ''; + if (isset($comments_map) + && isset($comments_map[$fields_meta->table]) + && isset($comments_map[$fields_meta->table][$fields_meta->name]) + ) { + $comments = '' + . htmlspecialchars( + $comments_map[$fields_meta->table][$fields_meta->name] + ) + . ''; + } + return $comments; + } // end of the '_getCommentForRow()' function + + + /** + * Prepare parameters and html for sorted table header fields + * + * @param array $fields_meta set of field properties + * @param string $sort_expression sort expression + * @param string $sort_expression_nodirection sort expression without direction + * @param integer $column_index the index of the column + * @param string $unsorted_sql_query the unsorted sql query + * @param integer $session_max_rows maximum rows resulted by sql + * @param string $direction the display direction + * @param string $comments comment for row + * @param string $sort_direction sort direction + * @param boolean $directionCondition display direction horizontal + * or horizontalflipped + * @param boolean $col_visib column is visible(false) + * array column isn't visible(string array) + * @param string $col_visib_j element of $col_visib array + * @param boolean $condition_field whether the column is a part of + * the where clause + * + * @return array 2 element array - $order_link, $sorted_header_html + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getOrderLinkAndSortedHeaderHtml( + $fields_meta, $sort_expression, $sort_expression_nodirection, + $column_index, $unsorted_sql_query, $session_max_rows, $direction, + $comments, $sort_direction, $directionCondition, $col_visib, + $col_visib_j, $condition_field + ) { + + $sorted_header_html = ''; + + // Checks if the table name is required; it's the case + // for a query with a "JOIN" statement and if the column + // isn't aliased, or in queries like + // SELECT `1`.`master_field` , `2`.`master_field` + // FROM `PMA_relation` AS `1` , `PMA_relation` AS `2` + + $sort_tbl = (isset($fields_meta->table) + && strlen($fields_meta->table)) + ? PMA_Util::backquote( + $fields_meta->table + ) . '.' + : ''; + + // Checks if the current column is used to sort the + // results + // the orgname member does not exist for all MySQL versions + // but if found, it's the one on which to sort + $name_to_use_in_sort = $fields_meta->name; + $is_orgname = false; + if (isset($fields_meta->orgname) + && strlen($fields_meta->orgname) + ) { + $name_to_use_in_sort = $fields_meta->orgname; + $is_orgname = true; + } + + // $name_to_use_in_sort might contain a space due to + // formatting of function expressions like "COUNT(name )" + // so we remove the space in this situation + $name_to_use_in_sort = str_replace(' )', ')', $name_to_use_in_sort); + + $is_in_sort = $this->_isInSorted( + $sort_expression, $sort_expression_nodirection, + $sort_tbl, $name_to_use_in_sort + ); + + // Check the field name for a bracket. + // If it contains one, it's probably a function column + // like 'COUNT(`field`)' + // It still might be a column name of a view. See bug #3383711 + // Check is_orgname. + if ((strpos($name_to_use_in_sort, '(') !== false) && ! $is_orgname) { + $sort_order = "\n" . 'ORDER BY ' . $name_to_use_in_sort . ' '; + } else { + $sort_order = "\n" . 'ORDER BY ' . $sort_tbl + . PMA_Util::backquote( + $name_to_use_in_sort + ) . ' '; + } + unset($name_to_use_in_sort); + unset($is_orgname); + + // Do define the sorting URL + + list($sort_order, $order_img) = $this->_getSortingUrlParams( + $is_in_sort, $sort_direction, $fields_meta, + $sort_order, $column_index + ); + + if (preg_match( + '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|FOR UPDATE|' + . 'LOCK IN SHARE MODE))@is', + $unsorted_sql_query, $regs3 + )) { + $sorted_sql_query = $regs3[1] . $sort_order . $regs3[2]; + } else { + $sorted_sql_query = $unsorted_sql_query . $sort_order; + } + + $_url_params = array( + 'db' => $this->__get('db'), + 'table' => $this->__get('table'), + 'sql_query' => $sorted_sql_query, + 'session_max_rows' => $session_max_rows + ); + $order_url = 'sql.php' . PMA_generate_common_url($_url_params); + + // Displays the sorting URL + // enable sort order swapping for image + $order_link = $this->_getSortOrderLink( + $order_img, $column_index, $direction, + $fields_meta, $order_url + ); + + if ($directionCondition) { + $sorted_header_html .= $this->_getDraggableClassForSortableColumns( + $col_visib, $col_visib_j, $condition_field, $direction, + $fields_meta, $order_link, $comments + ); + } + + return array($order_link, $sorted_header_html); + + } // end of the '_getOrderLinkAndSortedHeaderHtml()' function + + + /** + * Check whether the column is sorted + * + * @param string $sort_expression sort expression + * @param string $sort_expression_nodirection sort expression without direction + * @param string $sort_tbl the table name + * @param string $name_to_use_in_sort the sorting column name + * + * @return boolean $is_in_sort the column sorted or not + * + * @access private + * + * @see _getTableHeaders() + */ + private function _isInSorted( + $sort_expression, $sort_expression_nodirection, $sort_tbl, + $name_to_use_in_sort + ) { + + if (empty($sort_expression)) { + $is_in_sort = false; + } else { + // Field name may be preceded by a space, or any number + // of characters followed by a dot (tablename.fieldname) + // so do a direct comparison for the sort expression; + // this avoids problems with queries like + // "SELECT id, count(id)..." and clicking to sort + // on id or on count(id). + // Another query to test this: + // SELECT p.*, FROM_UNIXTIME(p.temps) FROM mytable AS p + // (and try clicking on each column's header twice) + if (! empty($sort_tbl) + && strpos($sort_expression_nodirection, $sort_tbl) === false + && strpos($sort_expression_nodirection, '(') === false + ) { + $new_sort_expression_nodirection = $sort_tbl + . $sort_expression_nodirection; + } else { + $new_sort_expression_nodirection = $sort_expression_nodirection; + } + + $is_in_sort = false; + $sort_name = str_replace('`', '', $sort_tbl) . $name_to_use_in_sort; + + if ($sort_name == str_replace('`', '', $new_sort_expression_nodirection) + || $sort_name == str_replace('`', '', $sort_expression_nodirection) + ) { + $is_in_sort = true; + } + } + + return $is_in_sort; + + } // end of the '_isInSorted()' function + + + /** + * Get sort url paramaeters - sort order and order image + * + * @param boolean $is_in_sort the column sorted or not + * @param string $sort_direction the sort direction + * @param array $fields_meta set of field properties + * @param string $sort_order the sorting order + * @param integer $column_index the index of the column + * + * @return array 2 element array - $sort_order, $order_img + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getSortingUrlParams( + $is_in_sort, $sort_direction, $fields_meta, $sort_order, $column_index + ) { + + if (! $is_in_sort) { + + // patch #455484 ("Smart" order) + $GLOBALS['cfg']['Order'] = strtoupper($GLOBALS['cfg']['Order']); + + if ($GLOBALS['cfg']['Order'] === self::SMART_SORT_ORDER) { + $sort_order .= (preg_match( + '@time|date@i', + $fields_meta->type + )) ? self::DESCENDING_SORT_DIR : self::ASCENDING_SORT_DIR; + } else { + $sort_order .= $GLOBALS['cfg']['Order']; + } + $order_img = ''; + + } elseif ($sort_direction == self::DESCENDING_SORT_DIR) { + + $sort_order .= ' ASC'; + $order_img = ' ' . PMA_Util::getImage( + 's_desc.png', __('Descending'), + array('class' => "soimg$column_index", 'title' => '') + ); + + $order_img .= ' ' . PMA_Util::getImage( + 's_asc.png', __('Ascending'), + array('class' => "soimg$column_index hide", 'title' => '') + ); + + } else { + + $sort_order .= ' DESC'; + $order_img = ' ' . PMA_Util::getImage( + 's_asc.png', __('Ascending'), + array('class' => "soimg$column_index", 'title' => '') + ); + + $order_img .= ' ' . PMA_Util::getImage( + 's_desc.png', __('Descending'), + array('class' => "soimg$column_index hide", 'title' => '') + ); + } + + return array($sort_order, $order_img); + + } // end of the '_getSortingUrlParams()' function + + + /** + * Get sort order link + * + * @param string $order_img the sort order image + * @param integer $col_index the index of the column + * @param string $direction the display direction + * @param array $fields_meta set of field properties + * @param string $order_url the url for sort + * + * @return string the sort order link + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getSortOrderLink( + $order_img, $col_index, $direction, $fields_meta, $order_url + ) { + + $order_link_params = array(); + + if (isset($order_img) && ($order_img != '')) { + if (strstr($order_img, 'asc')) { + $order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()"; + $order_link_params['onmouseout'] = "$('.soimg$col_index').toggle()"; + } elseif (strstr($order_img, 'desc')) { + $order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()"; + $order_link_params['onmouseout'] = "$('.soimg$col_index').toggle()"; + } + } + + if ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_AUTO) { + + $GLOBALS['cfg']['HeaderFlipType'] + = (PMA_USR_BROWSER_AGENT == 'IE') + ? self::HEADER_FLIP_TYPE_CSS + : self::HEADER_FLIP_TYPE_FAKE; + } + + if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED + && $GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_CSS + ) { + $order_link_params['style'] = 'direction: ltr; writing-mode: tb-rl;'; + } + + $order_link_content = (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED) + && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_FAKE)) + ? PMA_Util::flipstring( + htmlspecialchars($fields_meta->name), + "
      \n" + ) + : htmlspecialchars($fields_meta->name); + + return PMA_Util::linkOrButton( + $order_url, $order_link_content . $order_img, + $order_link_params, false, true + ); + + } // end of the '_getSortOrderLink()' function + + + /** + * Prepare columns to draggable effect for sortable columns + * + * @param boolean $col_visib the column is visible (false) + * array the column is not visible (string array) + * @param string $col_visib_j element of $col_visib array + * @param boolean $condition_field whether to add CSS class condition + * @param string $direction the display direction + * @param array $fields_meta set of field properties + * @param string $order_link the order link + * @param string $comments the comment for the column + * + * @return string $draggable_html html content + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getDraggableClassForSortableColumns( + $col_visib, $col_visib_j, $condition_field, $direction, $fields_meta, + $order_link, $comments + ) { + + $draggable_html = 'name) + . '">' . $order_link . $comments . ''; + + return $draggable_html; + + } // end of the '_getDraggableClassForSortableColumns()' function + + + /** + * Prepare columns to draggable effect for non sortable columns + * + * @param boolean $col_visib the column is visible (false) + * array the column is not visible (string array) + * @param string $col_visib_j element of $col_visib array + * @param boolean $condition_field whether to add CSS class condition + * @param string $direction the display direction + * @param array $fields_meta set of field properties + * @param string $comments the comment for the column + * + * @return string $draggable_html html content + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getDraggableClassForNonSortableColumns( + $col_visib, $col_visib_j, $condition_field, + $direction, $fields_meta, $comments + ) { + + $draggable_html = 'name) . '">'; + + if (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED) + && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_FAKE) + ) { + + $draggable_html .= PMA_Util::flipstring( + htmlspecialchars($fields_meta->name), '
      ' + ); + + } else { + $draggable_html .= htmlspecialchars($fields_meta->name); + } + + $draggable_html .= "\n" . $comments . ''; + + return $draggable_html; + + } // end of the '_getDraggableClassForNonSortableColumns()' function + + + /** + * Prepare column to show at right side - check boxes or empty column + * + * @param array &$is_display which elements to display + * @param boolean $directionCondition display direction horizontal + * or horizontalflipped + * @param string $full_or_partial_text_link full/partial link or text button + * @param string $colspan column span of table header + * @param string $rowspan row span of table header + * + * @return string html content + * + * @access private + * + * @see _getTableHeaders() + */ + private function _getColumnAtRightSide( + &$is_display, $directionCondition, $full_or_partial_text_link, + $colspan, $rowspan + ) { + + $right_column_html = ''; + $vertical_display = $this->__get('vertical_display'); + + // Displays the needed checkboxes at the right + // column of the result table header if possible and required... + if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE) + || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) + && ($is_display['text_btn'] == '1') + ) { + + $vertical_display['emptyafter'] + = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE) + && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1; + + if ($directionCondition) { + $right_column_html .= "\n" + . '
      '; + + // end horizontal/horizontalflipped mode + } else { + $vertical_display['textbtn'] = ' ' . "\n"; + } // end vertical mode + } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && (($is_display['edit_lnk'] == self::NO_EDIT_OR_DELETE) + && ($is_display['del_lnk'] == self::NO_EDIT_OR_DELETE)) + && (! isset($GLOBALS['is_header_sent']) || ! $GLOBALS['is_header_sent']) + ) { + // ... elseif no button, displays empty columns if required + // (unless coming from Browse mode print view) + + $vertical_display['emptyafter'] + = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE) + && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1; + + if ($directionCondition) { + $right_column_html .= "\n" + . ''; + + // end horizontal/horizontalflipped mode + } else { + $vertical_display['textbtn'] = ' ' . "\n"; + } // end vertical mode + } + + $this->__set('vertical_display', $vertical_display); + + return $right_column_html; + + } // end of the '_getColumnAtRightSide()' function + + + /** + * Prepares the display for a value + * + * @param string $class class of table cell + * @param bool $condition_field whether to add CSS class condition + * @param string $value value to display + * + * @return string the td + * + * @access private + * + * @see _getDataCellForBlobColumns(), _getDataCellForGeometryColumns(), + * _getDataCellForNonNumericAndNonBlobColumns() + */ + private function _buildValueDisplay($class, $condition_field, $value) + { + return ''; + } // end of the '_buildValueDisplay()' function + + + /** + * Prepares the display for a null value + * + * @param string $class class of table cell + * @param bool $condition_field whether to add CSS class condition + * @param object $meta the meta-information about this field + * @param string $align cell allignment + * + * @return string the td + * + * @access private + * + * @see _getDataCellForNumericColumns(), _getDataCellForBlobColumns(), + * _getDataCellForGeometryColumns(), + * _getDataCellForNonNumericAndNonBlobColumns() + */ + private function _buildNullDisplay($class, $condition_field, $meta, $align = '') + { + // the null class is needed for grid editing + return ''; + } // end of the '_buildNullDisplay()' function + + + /** + * Prepares the display for an empty value + * + * @param string $class class of table cell + * @param bool $condition_field whether to add CSS class condition + * @param object $meta the meta-information about this field + * @param string $align cell allignment + * + * @return string the td + * + * @access private + * + * @see _getDataCellForNumericColumns(), _getDataCellForBlobColumns(), + * _getDataCellForGeometryColumns(), + * _getDataCellForNonNumericAndNonBlobColumns() + */ + private function _buildEmptyDisplay($class, $condition_field, $meta, $align = '') + { + return ''; + } // end of the '_buildEmptyDisplay()' function + + + /** + * Adds the relavant classes. + * + * @param string $class class of table cell + * @param bool $condition_field whether to add CSS class condition + * @param object $meta the meta-information about the field + * @param string $nowrap avoid wrapping + * @param bool $is_field_truncated is field truncated (display ...) + * @param string $transformation_plugin transformation plugin. + * Can also be the default function: + * PMA_mimeDefaultFunction + * @param string $default_function default transformation function + * + * @return string the list of classes + * + * @access private + * + * @see _buildNullDisplay(), _getRowData() + */ + private function _addClass( + $class, $condition_field, $meta, $nowrap, $is_field_truncated = false, + $transformation_plugin = '', $default_function = '' + ) { + + // Define classes to be added to this data field based on the type of data + $enum_class = ''; + if (strpos($meta->flags, 'enum') !== false) { + $enum_class = ' enum'; + } + + $set_class = ''; + if (strpos($meta->flags, 'set') !== false) { + $set_class = ' set'; + } + + $bit_class = ''; + if (strpos($meta->type, 'bit') !== false) { + $bit_class = ' bit'; + } + + $mime_type_class = ''; + if (isset($meta->mimetype)) { + $mime_type_class = ' ' . preg_replace('/\//', '_', $meta->mimetype); + } + + return $class . ($condition_field ? ' condition' : '') . $nowrap + . ' ' . ($is_field_truncated ? ' truncated' : '') + . ($transformation_plugin != $default_function ? ' transformed' : '') + . $enum_class . $set_class . $bit_class . $mime_type_class; + + } // end of the '_addClass()' function + + + /** + * Prepare the body of the results table + * + * @param integer &$dt_result the link id associated to the query + * which results have to be displayed + * @param array &$is_display which elements to display + * @param array $map the list of relations + * @param array $analyzed_sql the analyzed query + * @param boolean $is_limited_display with limited operations or not + * + * @return string $table_body_html html content + * + * @global array $row current row data + * + * @access private + * + * @see getTable() + */ + private function _getTableBody( + &$dt_result, &$is_display, $map, $analyzed_sql, $is_limited_display = false + ) { + + global $row; // mostly because of browser transformations, + // to make the row-data accessible in a plugin + + $table_body_html = ''; + + // query without conditions to shorten URLs when needed, 200 is just + // guess, it should depend on remaining URL length + $url_sql_query = $this->_getUrlSqlQuery($analyzed_sql); + + $vertical_display = $this->__get('vertical_display'); + + if (! is_array($map)) { + $map = array(); + } + + $row_no = 0; + $vertical_display['edit'] = array(); + $vertical_display['copy'] = array(); + $vertical_display['delete'] = array(); + $vertical_display['data'] = array(); + $vertical_display['row_delete'] = array(); + $this->__set('vertical_display', $vertical_display); + + // name of the class added to all grid editable elements; + // if we don't have all the columns of a unique key in the result set, + // do not permit grid editing + if ($is_limited_display || ! $this->__get('editable')) { + $grid_edit_class = ''; + } else { + switch ($GLOBALS['cfg']['GridEditing']) { + case 'double-click': + // trying to reduce generated HTML by using shorter + // classes like click1 and click2 + $grid_edit_class = 'grid_edit click2'; + break; + case 'click': + $grid_edit_class = 'grid_edit click1'; + break; + case 'disabled': + $grid_edit_class = ''; + break; + } + } + + // prepare to get the column order, if available + list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql); + + // Correction University of Virginia 19991216 in the while below + // Previous code assumed that all tables have keys, specifically that + // the phpMyAdmin GUI should support row delete/edit only for such + // tables. + // Although always using keys is arguably the prescribed way of + // defining a relational table, it is not required. This will in + // particular be violated by the novice. + // We want to encourage phpMyAdmin usage by such novices. So the code + // below has been changed to conditionally work as before when the + // table being displayed has one or more keys; but to display + // delete/edit options correctly for tables without keys. + + $odd_row = true; + $directionCondition + = ($_SESSION['tmp_user_values']['disp_direction'] + == self::DISP_DIR_HORIZONTAL) + || ($_SESSION['tmp_user_values']['disp_direction'] + == self::DISP_DIR_HORIZONTAL_FLIPPED); + + while ($row = PMA_DBI_fetch_row($dt_result)) { + + // "vertical display" mode stuff + $table_body_html .= $this->_getVerticalDisplaySupportSegments( + $vertical_display, $row_no, $directionCondition + ); + + $alternating_color_class = ($odd_row ? 'odd' : 'even'); + $odd_row = ! $odd_row; + + if ($directionCondition) { + // pointer code part + $table_body_html .= ''; + } + + // 1. Prepares the row + // 1.1 Results from a "SELECT" statement -> builds the + // WHERE clause to use in links (a unique key if possible) + /** + * @todo $where_clause could be empty, for example a table + * with only one field and it's a BLOB; in this case, + * avoid to display the delete and edit links + */ + list($where_clause, $clause_is_unique, $condition_array) + = PMA_Util::getUniqueCondition( + $dt_result, + $this->__get('fields_cnt'), + $this->__get('fields_meta'), + $row + ); + $where_clause_html = urlencode($where_clause); + + // In print view these variable needs toinitialized + $del_url = $del_query = $del_str = $edit_anchor_class + = $edit_str = $js_conf = $copy_url = $copy_str = $edit_url = null; + + // 1.2 Defines the URLs for the modify/delete link(s) + + if (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE) + || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE) + ) { + // We need to copy the value + // or else the == 'both' check will always return true + + if ($GLOBALS['cfg']['PropertiesIconic'] === self::POSITION_BOTH) { + $iconic_spacer = '
      '; + } else { + $iconic_spacer = ''; + } + + // 1.2.1 Modify link(s) - update row case + if ($is_display['edit_lnk'] == self::UPDATE_ROW) { + + list($edit_url, $copy_url, $edit_str, $copy_str, + $edit_anchor_class) + = $this->_getModifiedLinks( + $where_clause, + $clause_is_unique, $url_sql_query + ); + + } // end if (1.2.1) + + // 1.2.2 Delete/Kill link(s) + if (($is_display['del_lnk'] == self::DELETE_ROW) + || ($is_display['del_lnk'] == self::KILL_PROCESS) + ) { + + list($del_query, $del_url, $del_str, $js_conf) + = $this->_getDeleteAndKillLinks( + $where_clause, $clause_is_unique, + $url_sql_query, $is_display['del_lnk'], + $row + ); + + } // end if (1.2.2) + + // 1.3 Displays the links at left if required + if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && $directionCondition + ) { + + $table_body_html .= $this->_getPlacedLinks( + self::POSITION_LEFT, $del_url, $is_display, $row_no, + $where_clause, $where_clause_html, $condition_array, + $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class, + $edit_str, $copy_str, $del_str, $js_conf + ); + + } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) + && $directionCondition + ) { + + $table_body_html .= $this->_getPlacedLinks( + self::POSITION_NONE, $del_url, $is_display, $row_no, + $where_clause, $where_clause_html, $condition_array, + $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class, + $edit_str, $copy_str, $del_str, $js_conf + ); + + } // end if (1.3) + } // end if (1) + + // 2. Displays the rows' values + $table_body_html .= $this->_getRowValues( + $dt_result, $row, $row_no, $col_order, $map, + $grid_edit_class, $col_visib, $where_clause, + $url_sql_query, $analyzed_sql, $directionCondition + ); + + // 3. Displays the modify/delete links on the right if required + if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && $directionCondition + ) { + + $table_body_html .= $this->_getPlacedLinks( + self::POSITION_RIGHT, $del_url, $is_display, $row_no, + $where_clause, $where_clause_html, $condition_array, + $del_query, 'r', $edit_url, $copy_url, $edit_anchor_class, + $edit_str, $copy_str, $del_str, $js_conf + ); + + } // end if (3) + + if ($directionCondition) { + $table_body_html .= '
      '; + } // end if + + // 4. Gather links of del_urls and edit_urls in an array for later + // output + $this->_gatherLinksForLaterOutputs( + $row_no, $is_display, $where_clause, $where_clause_html, $js_conf, + $del_url, $del_query, $del_str, $edit_anchor_class, $edit_url, + $edit_str, $copy_url, $copy_str, $alternating_color_class, + $condition_array + ); + + $table_body_html .= $directionCondition ? "\n" : ''; + $row_no++; + + } // end while + + return $table_body_html; + + } // end of the '_getTableBody()' function + + + /** + * Get the values for one data row + * + * @param integer &$dt_result the link id associated to the query + * which results have to be displayed + * @param array $row current row data + * @param integer $row_no the index of current row + * @param array $col_order the column order + * false when a property not found + * @param array $map the list of relations + * @param string $grid_edit_class the class for all editable columns + * @param boolean $col_visib column is visible(false) + * array column isn't visible(string array) + * @param string $where_clause where clause + * @param string $url_sql_query the analyzed sql query + * @param array $analyzed_sql the analyzed query + * @param boolean $directionCondition the directional condition + * + * @return string $row_values_html html content + * + * @access private + * + * @see _getTableBody() + */ + private function _getRowValues( + &$dt_result, $row, $row_no, $col_order, $map, + $grid_edit_class, $col_visib, $where_clause, + $url_sql_query, $analyzed_sql, $directionCondition + ) { + + $row_values_html = ''; + + // Following variable are needed for use in isset/empty or + // use with array indexes/safe use in foreach + $sql_query = $this->__get('sql_query'); + $fields_meta = $this->__get('fields_meta'); + $highlight_columns = $this->__get('highlight_columns'); + $mime_map = $this->__get('mime_map'); + + $row_info = $this->_getRowInfoForSpecialLinks($row, $col_order); + + for ($currentColumn = 0; + $currentColumn < $this->__get('fields_cnt'); + ++$currentColumn) { + + // assign $i with appropriate column order + $i = $col_order ? $col_order[$currentColumn] : $currentColumn; + + $meta = $fields_meta[$i]; + $not_null_class = $meta->not_null ? 'not_null' : ''; + $relation_class = isset($map[$meta->name]) ? 'relation' : ''; + $hide_class = ($col_visib && ! $col_visib[$currentColumn] + // hide per ' . "\n"; + + if ($vertical_display['emptypre'] > 0) { + + $support_html .= ' ' . "\n"; + + } else if ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) { + $support_html .= ' ' . "\n"; + } + + foreach ($vertical_display['desc'] as $val) { + $support_html .= $val; + } + + if ($vertical_display['emptyafter'] > 0) { + $support_html + .= ' ' . "\n"; + } + $support_html .= '' . "\n"; + } // end if + + return $support_html; + + } // end of the '_getVerticalDisplaySupportSegments()' function + + + /** + * Get modified links + * + * @param string $where_clause the where clause of the sql + * @param boolean $clause_is_unique the unique condition of clause + * @param string $url_sql_query the analyzed sql query + * + * @return array 5 element array - $edit_url, $copy_url, + * $edit_str, $copy_str, $edit_anchor_class + * + * @access private + * + * @see _getTableBody() + */ + private function _getModifiedLinks( + $where_clause, $clause_is_unique, $url_sql_query + ) { + + $_url_params = array( + 'db' => $this->__get('db'), + 'table' => $this->__get('table'), + 'where_clause' => $where_clause, + 'clause_is_unique' => $clause_is_unique, + 'sql_query' => $url_sql_query, + 'goto' => 'sql.php', + ); + + $edit_url = 'tbl_change.php' + . PMA_generate_common_url( + $_url_params + array('default_action' => 'update') + ); + + $copy_url = 'tbl_change.php' + . PMA_generate_common_url( + $_url_params + array('default_action' => 'insert') + ); + + $edit_str = PMA_Util::getIcon( + 'b_edit.png', __('Edit') + ); + $copy_str = PMA_Util::getIcon( + 'b_insrow.png', __('Copy') + ); + + // Class definitions required for grid editing jQuery scripts + $edit_anchor_class = "edit_row_anchor"; + if ( $clause_is_unique == 0) { + $edit_anchor_class .= ' nonunique'; + } + + return array($edit_url, $copy_url, $edit_str, $copy_str, $edit_anchor_class); + + } // end of the '_getModifiedLinks()' function + + + /** + * Get delete and kill links + * + * @param string $where_clause the where clause of the sql + * @param boolean $clause_is_unique the unique condition of clause + * @param string $url_sql_query the analyzed sql query + * @param string $del_lnk the delete link of current row + * @param array $row the current row + * + * @return array 4 element array - $del_query, + * $del_url, $del_str, $js_conf + * + * @access private + * + * @see _getTableBody() + */ + private function _getDeleteAndKillLinks( + $where_clause, $clause_is_unique, $url_sql_query, $del_lnk, $row + ) { + + $goto = $this->__get('goto'); + + if ($del_lnk == self::DELETE_ROW) { // delete row case + + $_url_params = array( + 'db' => $this->__get('db'), + 'table' => $this->__get('table'), + 'sql_query' => $url_sql_query, + 'message_to_show' => __('The row has been deleted'), + 'goto' => (empty($goto) ? 'tbl_sql.php' : $goto), + ); + + $lnk_goto = 'sql.php' . PMA_generate_common_url($_url_params, 'text'); + + $del_query = 'DELETE FROM ' + . PMA_Util::backquote($this->__get('db')) . '.' + . PMA_Util::backquote($this->__get('table')) + . ' WHERE ' . $where_clause . + ($clause_is_unique ? '' : ' LIMIT 1'); + + $_url_params = array( + 'db' => $this->__get('db'), + 'table' => $this->__get('table'), + 'sql_query' => $del_query, + 'message_to_show' => __('The row has been deleted'), + 'goto' => $lnk_goto, + ); + $del_url = 'sql.php' . PMA_generate_common_url($_url_params); + + $js_conf = 'DELETE FROM ' . PMA_jsFormat($this->__get('db')) . '.' + . PMA_jsFormat($this->__get('table')) + . ' WHERE ' . PMA_jsFormat($where_clause, false) + . ($clause_is_unique ? '' : ' LIMIT 1'); + + $del_str = PMA_Util::getIcon( + 'b_drop.png', __('Delete') + ); + + } elseif ($del_lnk == self::KILL_PROCESS) { // kill process case + + $_url_params = array( + 'db' => $this->__get('db'), + 'table' => $this->__get('table'), + 'sql_query' => $url_sql_query, + 'goto' => 'index.php', + ); + + $lnk_goto = 'sql.php' + . PMA_generate_common_url( + $_url_params, 'text' + ); + + $_url_params = array( + 'db' => 'mysql', + 'sql_query' => 'KILL ' . $row[0], + 'goto' => $lnk_goto, + ); + + $del_url = 'sql.php' . PMA_generate_common_url($_url_params); + $del_query = 'KILL ' . $row[0]; + $js_conf = 'KILL ' . $row[0]; + $del_str = PMA_Util::getIcon( + 'b_drop.png', __('Kill') + ); + } + + return array($del_query, $del_url, $del_str, $js_conf); + + } // end of the '_getDeleteAndKillLinks()' function + + + /** + * Prepare placed links + * + * @param string $dir the direction of links should place + * @param string $del_url the url for delete row + * @param array $is_display which elements to display + * @param integer $row_no the index of current row + * @param string $where_clause the where clause of the sql + * @param string $where_clause_html the html encoded where clause + * @param array $condition_array array of keys (primary, unique, condition) + * @param string $del_query the query for delete row + * @param string $dir_letter the letter denoted the direction + * @param string $edit_url the url for edit row + * @param string $copy_url the url for copy row + * @param string $edit_anchor_class the class for html element for edit + * @param string $edit_str the label for edit row + * @param string $copy_str the label for copy row + * @param string $del_str the label for delete row + * @param string $js_conf text for the JS confirmation + * + * @return string html content + * + * @access private + * + * @see _getTableBody() + */ + private function _getPlacedLinks( + $dir, $del_url, $is_display, $row_no, $where_clause, $where_clause_html, + $condition_array, $del_query, $dir_letter, $edit_url, $copy_url, + $edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf + ) { + + if (! isset($js_conf)) { + $js_conf = ''; + } + + return $this->_getCheckboxAndLinks( + $dir, $del_url, $is_display, + $row_no, $where_clause, $where_clause_html, $condition_array, + $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class, + $edit_str, $copy_str, $del_str, $js_conf + ); + + } // end of the '_getPlacedLinks()' function + + + /** + * Get the combined classes for a column + * + * @param string $grid_edit_class the class for all editable columns + * @param string $not_null_class the class for not null columns + * @param string $relation_class the class for relations in a column + * @param string $hide_class the class for visibility of a column + * @param string $field_type_class the class related to type of the field + * @param integer $row_no the row index + * + * @return string $class the combined classes + * + * @access private + * + * @see _getTableBody() + */ + private function _getClassesForColumn( + $grid_edit_class, $not_null_class, $relation_class, + $hide_class, $field_type_class, $row_no + ) { + + $printview = $this->__get('printview'); + + $class = 'data ' . $grid_edit_class . ' ' . $not_null_class . ' ' + . $relation_class . ' ' . $hide_class . ' ' . $field_type_class; + + if (($_SESSION['tmp_user_values']['disp_direction'] == self::DISP_DIR_VERTICAL) + && (! isset($printview) || ($printview != '1')) + ) { + // the row number corresponds to a data row, not HTML table row + $class .= ' row_' . $row_no; + if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) { + $class .= ' vpointer'; + } + + if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) { + $class .= ' vmarker'; + } + } + + return $class; + + } // end of the '_getClassesForColumn()' function + + + /** + * Get class for datetime related fields + * + * @param string $type the type of the column field + * + * @return string $field_type_class the class for the column + * + * @access private + * + * @see _getTableBody() + */ + private function _getClassForDateTimeRelatedFields($type) + { + if ((substr($type, 0, 9) == self::TIMESTAMP_FIELD) + || ($type == self::DATETIME_FIELD) + ) { + $field_type_class = 'datetimefield'; + } else if ($type == self::DATE_FIELD) { + $field_type_class = 'datefield'; + } else { + $field_type_class = ''; + } + return $field_type_class; + } // end of the '_getClassForDateTimeRelatedFields()' function + + + /** + * Prepare data cell for numeric type fields + * + * @param string $column the relavent column in data row + * @param string $class the html class for column + * @param boolean $condition_field the column should highlighted + * or not + * @param object $meta the meta-information about this + * field + * @param array $map the list of relations + * @param boolean $is_field_truncated the condition for blob data + * replacements + * @param array $analyzed_sql the analyzed query + * @param string $transformation_plugin the name of transformation plugin + * @param string $default_function the default transformation function + * @param string $transform_options the transformation parameters + * + * @return string $cell the prepared cell, html content + * + * @access private + * + * @see _getTableBody() + */ + private function _getDataCellForNumericColumns( + $column, $class, $condition_field, $meta, $map, $is_field_truncated, + $analyzed_sql, $transformation_plugin, $default_function, + $transform_options + ) { + + if (! isset($column) || is_null($column)) { + + $cell = $this->_buildNullDisplay( + 'right '.$class, $condition_field, $meta, '' + ); + + } elseif ($column != '') { + + $nowrap = ' nowrap'; + $where_comparison = ' = ' . $column; + + $cell = $this->_getRowData( + 'right '.$class, $condition_field, + $analyzed_sql, $meta, $map, $column, + $transformation_plugin, $default_function, $nowrap, + $where_comparison, $transform_options, + $is_field_truncated + ); + } else { + + $cell = $this->_buildEmptyDisplay( + 'right '.$class, $condition_field, $meta, '' + ); + } + + return $cell; + + } // end of the '_getDataCellForNumericColumns()' function + + + /** + * Get data cell for blob type fields + * + * @param string $column the relavent column in data row + * @param string $class the html class for column + * @param object $meta the meta-information about this + * field + * @param array $_url_params the parameters for generate url + * @param string $field_flags field flags for column(blob, + * primary etc) + * @param string $transformation_plugin the name of transformation function + * @param string $default_function the default transformation function + * @param string $transform_options the transformation parameters + * @param boolean $condition_field the column should highlighted + * or not + * @param boolean $is_field_truncated the condition for blob data + * replacements + * + * @return string $cell the prepared cell, html content + * + * @access private + * + * @see _getTableBody() + */ + private function _getDataCellForBlobColumns( + $column, $class, $meta, $_url_params, $field_flags, $transformation_plugin, + $default_function, $transform_options, $condition_field, $is_field_truncated + ) { + + if (stristr($field_flags, self::BINARY_FIELD)) { + + // remove 'grid_edit' from $class as we can't edit binary data. + $class = str_replace('grid_edit', '', $class); + + if (! isset($column) || is_null($column)) { + + $cell = $this->_buildNullDisplay($class, $condition_field, $meta); + + } else { + + $blobtext = $this->_handleNonPrintableContents( + self::BLOB_FIELD, (isset($column) ? $column : ''), + $transformation_plugin, $transform_options, + $default_function, $meta, $_url_params + ); + + $cell = $this->_buildValueDisplay( + $class, $condition_field, $blobtext + ); + unset($blobtext); + } + } else { + // not binary: + + if (! isset($column) || is_null($column)) { + + $cell = $this->_buildNullDisplay($class, $condition_field, $meta); + + } elseif ($column != '') { + + // if a transform function for blob is set, none of these + // replacements will be made + if ((PMA_strlen($column) > $GLOBALS['cfg']['LimitChars']) + && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT) + && ! $this->_isNeedToSyntaxHighlight(strtolower($meta->name)) + ) { + $column = PMA_substr($column, 0, $GLOBALS['cfg']['LimitChars']) + . '...'; + $is_field_truncated = true; + } + + // displays all space characters, 4 space + // characters for tabulations and / + $column = ($default_function != $transformation_plugin) + ? $transformation_plugin->applyTransformation( + $column, + $transform_options, + $meta + ) + : $this->$default_function($column, array(), $meta); + + if ($is_field_truncated) { + $class .= ' truncated'; + } + + $cell = $this->_buildValueDisplay($class, $condition_field, $column); + + } else { + $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta); + } + } + + return $cell; + + } // end of the '_getDataCellForBlobColumns()' function + + + /** + * Get data cell for geometry type fields + * + * @param string $column the relavent column in data row + * @param string $class the html class for column + * @param object $meta the meta-information about this field + * @param array $map the list of relations + * @param array $_url_params the parameters for generate url + * @param boolean $condition_field the column should highlighted or not + * @param string $transformation_plugin the name of transformation function + * @param string $default_function the default transformation function + * @param string $transform_options the transformation parameters + * @param boolean $is_field_truncated the condition for blob data replacements + * @param array $analyzed_sql the analyzed query + * + * @return string $cell the prepared data cell, html content + * + * @access private + * + * @see _getTableBody() + */ + private function _getDataCellForGeometryColumns( + $column, $class, $meta, $map, $_url_params, $condition_field, + $transformation_plugin, $default_function, $transform_options, + $is_field_truncated, $analyzed_sql + ) { + + if (! isset($column) || is_null($column)) { + + $cell = $this->_buildNullDisplay($class, $condition_field, $meta); + + } elseif ($column != '') { + + // Display as [GEOMETRY - (size)] + if ($_SESSION['tmp_user_values']['geometry_display'] == self::GEOMETRY_DISP_GEOM) { + + $geometry_text = $this->_handleNonPrintableContents( + strtoupper(self::GEOMETRY_FIELD), + (isset($column) ? $column : ''), $transformation_plugin, + $transform_options, $default_function, $meta + ); + + $cell = $this->_buildValueDisplay( + $class, $condition_field, $geometry_text + ); + + } elseif ($_SESSION['tmp_user_values']['geometry_display'] + == self::GEOMETRY_DISP_WKT + ) { + // Prepare in Well Known Text(WKT) format. + + $where_comparison = ' = ' . $column; + + // Convert to WKT format + $wktval = PMA_Util::asWKT($column); + + if ((PMA_strlen($wktval) > $GLOBALS['cfg']['LimitChars']) + && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT) + ) { + $wktval = PMA_substr($wktval, 0, $GLOBALS['cfg']['LimitChars']) + . '...'; + $is_field_truncated = true; + } + + $cell = $this->_getRowData( + $class, $condition_field, $analyzed_sql, $meta, $map, + $wktval, $transformation_plugin, $default_function, '', + $where_comparison, $transform_options, + $is_field_truncated + ); + + } else { + // Prepare in Well Known Binary (WKB) format. + + if ($_SESSION['tmp_user_values']['display_binary']) { + + $where_comparison = ' = ' . $column; + + $wkbval = $this->_displayBinaryAsPrintable($column, 'binary', 8); + + if ((PMA_strlen($wkbval) > $GLOBALS['cfg']['LimitChars']) + && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT) + ) { + $wkbval + = PMA_substr($wkbval, 0, $GLOBALS['cfg']['LimitChars']) + . '...'; + $is_field_truncated = true; + } + + $cell = $this->_getRowData( + $class, $condition_field, + $analyzed_sql, $meta, $map, $wkbval, + $transformation_plugin, $default_function, '', + $where_comparison, $transform_options, + $is_field_truncated + ); + + } else { + $wkbval = $this->_handleNonPrintableContents( + self::BINARY_FIELD, $column, $transformation_plugin, + $transform_options, $default_function, $meta, + $_url_params + ); + + $cell = $this->_buildValueDisplay( + $class, $condition_field, $wkbval + ); + } + } + } else { + $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta); + } + + return $cell; + + } // end of the '_getDataCellForGeometryColumns()' function + + + /** + * Get data cell for non numeric and non blob type fields + * + * @param string $column the relavent column in data row + * @param string $class the html class for column + * @param object $meta the meta-information about the field + * @param array $map the list of relations + * @param array $_url_params the parameters for generate url + * @param boolean $condition_field the column should highlighted + * or not + * @param string $transformation_plugin the name of transformation function + * @param string $default_function the default transformation function + * @param string $transform_options the transformation parameters + * @param boolean $is_field_truncated the condition for blob data + * replacements + * @param array $analyzed_sql the analyzed query + * @param integer &$dt_result the link id associated to the query + * which results have to be displayed + * @param integer $col_index the column index + * + * @return string $cell the prepared data cell, html content + * + * @access private + * + * @see _getTableBody() + */ + private function _getDataCellForNonNumericAndNonBlobColumns( + $column, $class, $meta, $map, $_url_params, $condition_field, + $transformation_plugin, $default_function, $transform_options, + $is_field_truncated, $analyzed_sql, &$dt_result, $col_index + ) { + + $is_analyse = $this->__get('is_analyse'); + $field_flags = PMA_DBI_field_flags($dt_result, $col_index); + if (stristr($field_flags, self::BINARY_FIELD) + && ($GLOBALS['cfg']['ProtectBinary'] == 'all' + || $GLOBALS['cfg']['ProtectBinary'] == 'noblob') + ) { + $class = str_replace('grid_edit', '', $class); + } + + if (! isset($column) || is_null($column)) { + + $cell = $this->_buildNullDisplay($class, $condition_field, $meta); + + } elseif ($column != '') { + + // Cut all fields to $GLOBALS['cfg']['LimitChars'] + // (unless it's a link-type transformation) + if (PMA_strlen($column) > $GLOBALS['cfg']['LimitChars'] + && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT) + && gettype($transformation_plugin) == "object" + && ! strpos($transformation_plugin->getName(), 'Link') === true + ) { + $column = PMA_substr($column, 0, $GLOBALS['cfg']['LimitChars']) + . '...'; + $is_field_truncated = true; + } + + $formatted = false; + if (isset($meta->_type) && $meta->_type === MYSQLI_TYPE_BIT) { + + $column = PMA_Util::printableBitValue( + $column, $meta->length + ); + + // some results of PROCEDURE ANALYSE() are reported as + // being BINARY but they are quite readable, + // so don't treat them as BINARY + } elseif (stristr($field_flags, self::BINARY_FIELD) + && ($meta->type == self::STRING_FIELD) + && !(isset($is_analyse) && $is_analyse) + ) { + + if ($_SESSION['tmp_user_values']['display_binary']) { + + // user asked to see the real contents of BINARY + // fields + $column = $this->_displayBinaryAsPrintable($column, 'binary'); + + } else { + // we show the BINARY message and field's size + // (or maybe use a transformation) + $column = $this->_handleNonPrintableContents( + self::BINARY_FIELD, $column, $transformation_plugin, + $transform_options, $default_function, + $meta, $_url_params + ); + $formatted = true; + } + } + + if ($formatted) { + + $cell = $this->_buildValueDisplay( + $class, $condition_field, $column + ); + + } else { + + // transform functions may enable no-wrapping: + $function_nowrap = 'applyTransformationNoWrap'; + + $bool_nowrap = (($default_function != $transformation_plugin) + && function_exists($transformation_plugin->$function_nowrap())) + ? $transformation_plugin->$function_nowrap($transform_options) + : false; + + // do not wrap if date field type + $nowrap = (preg_match('@DATE|TIME@i', $meta->type) + || $bool_nowrap) ? ' nowrap' : ''; + + $where_comparison = ' = \'' + . PMA_Util::sqlAddSlashes($column) + . '\''; + + $cell = $this->_getRowData( + $class, $condition_field, + $analyzed_sql, $meta, $map, $column, + $transformation_plugin, $default_function, $nowrap, + $where_comparison, $transform_options, + $is_field_truncated + ); + } + + } else { + $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta); + } + + return $cell; + + } // end of the '_getDataCellForNonNumericAndNonBlobColumns()' function + + + /** + * Get the resulted table with the vertical direction mode. + * + * @param array $analyzed_sql the analyzed query + * @param array $is_display display mode + * + * @return string html content + * + * @access private + * + * @see _getTable() + */ + private function _getVerticalTable($analyzed_sql, $is_display) + { + + $vertical_table_html = ''; + $vertical_display = $this->__get('vertical_display'); + + // Prepares "multi row delete" link at top if required + if (($GLOBALS['cfg']['RowActionLinks'] != self::POSITION_RIGHT) + && is_array($vertical_display['row_delete']) + && ((count($vertical_display['row_delete']) > 0) + || !empty($vertical_display['textbtn'])) + ) { + + $vertical_table_html .= '' . "\n"; + if ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) { + // if we are not showing the RowActionLinks, then we need to show + // the Multi-Row-Action checkboxes + $vertical_table_html .= '' . "\n"; + } + + $vertical_table_html .= $vertical_display['textbtn'] + . $this->_getCheckBoxesForMultipleRowOperations('_left', $is_display) + . '' . "\n"; + } // end if + + // Prepares "edit" link at top if required + if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && is_array($vertical_display['edit']) + && ((count($vertical_display['edit']) > 0) + || !empty($vertical_display['textbtn'])) + ) { + $vertical_table_html .= $this->_getOperationLinksForVerticleTable( + 'edit' + ); + } // end if + + // Prepares "copy" link at top if required + if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && is_array($vertical_display['copy']) + && ((count($vertical_display['copy']) > 0) + || !empty($vertical_display['textbtn'])) + ) { + $vertical_table_html .= $this->_getOperationLinksForVerticleTable( + 'copy' + ); + } // end if + + // Prepares "delete" link at top if required + if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && is_array($vertical_display['delete']) + && ((count($vertical_display['delete']) > 0) + || !empty($vertical_display['textbtn'])) + ) { + $vertical_table_html .= $this->_getOperationLinksForVerticleTable( + 'delete' + ); + } // end if + + list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql); + + // Prepares data + foreach ($vertical_display['desc'] AS $j => $val) { + + // assign appropriate key with current column order + $key = $col_order ? $col_order[$j] : $j; + + $vertical_table_html .= '' . "\n" + . $val; + + $cell_displayed = 0; + foreach ($vertical_display['rowdata'][$key] as $subval) { + + if (($cell_displayed != 0) + && ($_SESSION['tmp_user_values']['repeat_cells'] != 0) + && ! ($cell_displayed % $_SESSION['tmp_user_values']['repeat_cells']) + ) { + $vertical_table_html .= $val; + } + + $vertical_table_html .= $subval; + $cell_displayed++; + + } // end while + + $vertical_table_html .= '' . "\n"; + } // end while + + // Prepares "multi row delete" link at bottom if required + if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && is_array($vertical_display['row_delete']) + && ((count($vertical_display['row_delete']) > 0) + || !empty($vertical_display['textbtn'])) + ) { + + $vertical_table_html .= '' . "\n" + . $vertical_display['textbtn'] + . $this->_getCheckBoxesForMultipleRowOperations('_right', $is_display) + . '' . "\n"; + } // end if + + // Prepares "edit" link at bottom if required + if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && is_array($vertical_display['edit']) + && ((count($vertical_display['edit']) > 0) + || !empty($vertical_display['textbtn'])) + ) { + $vertical_table_html .= $this->_getOperationLinksForVerticleTable( + 'edit' + ); + } // end if + + // Prepares "copy" link at bottom if required + if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && is_array($vertical_display['copy']) + && ((count($vertical_display['copy']) > 0) + || !empty($vertical_display['textbtn'])) + ) { + $vertical_table_html .= $this->_getOperationLinksForVerticleTable( + 'copy' + ); + } // end if + + // Prepares "delete" link at bottom if required + if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT) + || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) + && is_array($vertical_display['delete']) + && ((count($vertical_display['delete']) > 0) + || !empty($vertical_display['textbtn'])) + ) { + $vertical_table_html .= $this->_getOperationLinksForVerticleTable( + 'delete' + ); + } + + return $vertical_table_html; + + } // end of the '_getVerticalTable' function + + + /** + * Prepare edit, copy and delete links for verticle table + * + * @param string $operation edit/copy/delete + * + * @return string $links_html html content + * + * @access private + * + * @see _getVerticalTable() + */ + private function _getOperationLinksForVerticleTable($operation) + { + + $link_html = '' . "\n"; + $vertical_display = $this->__get('vertical_display'); + + if (! is_array($vertical_display['row_delete'])) { + + if (($operation == 'edit') || ($operation == 'copy')) { + $link_html .= $vertical_display['textbtn']; + + } elseif ($operation == 'delete') { + + if (! is_array($vertical_display['edit'])) { + $link_html .= $vertical_display['textbtn']; + } + } + } + + foreach ($vertical_display[$operation] as $val) { + $link_html .= $val; + } // end while + + $link_html .= '' . "\n"; + + return $link_html; + + } // end of the '_getOperationLinksForVerticleTable' function + + + /** + * Get checkboxes for multiple row data operations + * + * @param string $dir _left / _right + * @param array $is_display display mode + * + * @return $checkBoxes_html html content + * + * @access private + * + * @see _getVerticalTable() + */ + private function _getCheckBoxesForMultipleRowOperations($dir, $is_display) + { + + $checkBoxes_html = ''; + $cell_displayed = 0; + $vertical_display = $this->__get('vertical_display'); + + foreach ($vertical_display['row_delete'] as $val) { + + if (($cell_displayed != 0) + && ($_SESSION['tmp_user_values']['repeat_cells'] != 0) + && !($cell_displayed % $_SESSION['tmp_user_values']['repeat_cells']) + ) { + + $checkBoxes_html .= '' . "\n"; + + } + + $checkBoxes_html .= str_replace('[%_PMA_CHECKBOX_DIR_%]', $dir, $val); + $cell_displayed++; + } // end while + + return $checkBoxes_html; + + } // end of the '_getCheckBoxesForMultipleRowOperations' function + + + /** + * Checks the posted options for viewing query resutls + * and sets appropriate values in the session. + * + * @todo make maximum remembered queries configurable + * @todo move/split into SQL class!? + * @todo currently this is called twice unnecessary + * @todo ignore LIMIT and ORDER in query!? + * + * @return void + * + * @access public + * + * @see sql.php file + */ + public function setConfigParamsForDisplayTable() + { + + $sql_md5 = md5($this->__get('sql_query')); + + $_SESSION['tmp_user_values']['query'][$sql_md5]['sql'] + = $this->__get('sql_query'); + + $valid_disp_dir = PMA_isValid( + $_REQUEST['disp_direction'], + array(self::DISP_DIR_HORIZONTAL, self::DISP_DIR_VERTICAL, + self::DISP_DIR_HORIZONTAL_FLIPPED + ) + ); + + if ($valid_disp_dir) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['disp_direction'] + = $_REQUEST['disp_direction']; + unset($_REQUEST['disp_direction']); + } elseif ( + empty($_SESSION['tmp_user_values']['query'][$sql_md5]['disp_direction']) + ) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['disp_direction'] + = $GLOBALS['cfg']['DefaultDisplay']; + } + + if (PMA_isValid($_REQUEST['repeat_cells'], 'numeric')) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['repeat_cells'] + = $_REQUEST['repeat_cells']; + unset($_REQUEST['repeat_cells']); + } elseif ( + empty($_SESSION['tmp_user_values']['query'][$sql_md5]['repeat_cells']) + ) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['repeat_cells'] + = $GLOBALS['cfg']['RepeatCells']; + } + + // as this is a form value, the type is always string so we cannot + // use PMA_isValid($_REQUEST['session_max_rows'], 'integer') + if ((PMA_isValid($_REQUEST['session_max_rows'], 'numeric') + && ((int) $_REQUEST['session_max_rows'] == $_REQUEST['session_max_rows'])) + || ($_REQUEST['session_max_rows'] == self::ALL_ROWS) + ) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows'] + = $_REQUEST['session_max_rows']; + unset($_REQUEST['session_max_rows']); + } elseif (empty($_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows'])) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows'] + = $GLOBALS['cfg']['MaxRows']; + } + + if (PMA_isValid($_REQUEST['pos'], 'numeric')) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['pos'] + = $_REQUEST['pos']; + unset($_REQUEST['pos']); + } elseif (empty($_SESSION['tmp_user_values']['query'][$sql_md5]['pos'])) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['pos'] = 0; + } + + if (PMA_isValid( + $_REQUEST['display_text'], + array( + self::DISPLAY_PARTIAL_TEXT, self::DISPLAY_FULL_TEXT + ) + ) + ) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['display_text'] + = $_REQUEST['display_text']; + unset($_REQUEST['display_text']); + } elseif ( + empty($_SESSION['tmp_user_values']['query'][$sql_md5]['display_text']) + ) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['display_text'] + = self::DISPLAY_PARTIAL_TEXT; + } + + if (PMA_isValid( + $_REQUEST['relational_display'], + array( + self::RELATIONAL_KEY, self::RELATIONAL_DISPLAY_COLUMN + ) + ) + ) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['relational_display'] + = $_REQUEST['relational_display']; + unset($_REQUEST['relational_display']); + } elseif ( + empty( + $_SESSION['tmp_user_values']['query'][$sql_md5]['relational_display'] + ) + ) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['relational_display'] + = self::RELATIONAL_KEY; + } + + if (PMA_isValid( + $_REQUEST['geometry_display'], + array( + self::GEOMETRY_DISP_WKT, self::GEOMETRY_DISP_WKB, + self::GEOMETRY_DISP_GEOM + ) + ) + ) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['geometry_display'] + = $_REQUEST['geometry_display']; + unset($_REQUEST['geometry_display']); + } elseif ( + empty( + $_SESSION['tmp_user_values']['query'][$sql_md5]['geometry_display'] + ) + ) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['geometry_display'] + = self::GEOMETRY_DISP_GEOM; + } + + if (isset($_REQUEST['display_binary'])) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['display_binary'] = true; + unset($_REQUEST['display_binary']); + } elseif (isset($_REQUEST['display_options_form'])) { + // we know that the checkbox was unchecked + unset($_SESSION['tmp_user_values']['query'][$sql_md5]['display_binary']); + } elseif (isset($_REQUEST['full_text_button'])) { + // do nothing to keep the value that is there in the session + } else { + // selected by default because some operations like OPTIMIZE TABLE + // and all queries involving functions return "binary" contents, + // according to low-level field flags + $_SESSION['tmp_user_values']['query'][$sql_md5]['display_binary'] = true; + } + + if (isset($_REQUEST['display_binary_as_hex'])) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['display_binary_as_hex'] + = true; + unset($_REQUEST['display_binary_as_hex']); + } elseif (isset($_REQUEST['display_options_form'])) { + // we know that the checkbox was unchecked + unset($_SESSION['tmp_user_values']['query'][$sql_md5] + ['display_binary_as_hex'] + ); + } elseif (isset($_REQUEST['full_text_button'])) { + // do nothing to keep the value that is there in the session + } else { + // display_binary_as_hex config option + if (isset($GLOBALS['cfg']['DisplayBinaryAsHex']) + && ($GLOBALS['cfg']['DisplayBinaryAsHex'] === true) + ) { + $_SESSION['tmp_user_values']['query'][$sql_md5] + ['display_binary_as_hex'] = true; + } + } + + if (isset($_REQUEST['display_blob'])) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['display_blob'] = true; + unset($_REQUEST['display_blob']); + } elseif (isset($_REQUEST['display_options_form'])) { + // we know that the checkbox was unchecked + unset($_SESSION['tmp_user_values']['query'][$sql_md5]['display_blob']); + } + + if (isset($_REQUEST['hide_transformation'])) { + $_SESSION['tmp_user_values']['query'][$sql_md5]['hide_transformation'] + = true; + unset($_REQUEST['hide_transformation']); + } elseif (isset($_REQUEST['display_options_form'])) { + // we know that the checkbox was unchecked + unset($_SESSION['tmp_user_values']['query'][$sql_md5] + ['hide_transformation'] + ); + } + + // move current query to the last position, to be removed last + // so only least executed query will be removed if maximum remembered queries + // limit is reached + $tmp = $_SESSION['tmp_user_values']['query'][$sql_md5]; + unset($_SESSION['tmp_user_values']['query'][$sql_md5]); + $_SESSION['tmp_user_values']['query'][$sql_md5] = $tmp; + + // do not exceed a maximum number of queries to remember + if (count($_SESSION['tmp_user_values']['query']) > 10) { + array_shift($_SESSION['tmp_user_values']['query']); + //echo 'deleting one element ...'; + } + + // populate query configuration + $_SESSION['tmp_user_values']['display_text'] + = $_SESSION['tmp_user_values']['query'][$sql_md5]['display_text']; + $_SESSION['tmp_user_values']['relational_display'] + = $_SESSION['tmp_user_values']['query'][$sql_md5]['relational_display']; + $_SESSION['tmp_user_values']['geometry_display'] + = $_SESSION['tmp_user_values']['query'][$sql_md5]['geometry_display']; + $_SESSION['tmp_user_values']['display_binary'] + = isset($_SESSION['tmp_user_values']['query'][$sql_md5] + ['display_binary'] + ) + ? true + : false; + $_SESSION['tmp_user_values']['display_binary_as_hex'] + = isset($_SESSION['tmp_user_values']['query'][$sql_md5] + ['display_binary_as_hex'] + ) + ? true + : false; + $_SESSION['tmp_user_values']['display_blob'] + = isset($_SESSION['tmp_user_values']['query'][$sql_md5]['display_blob']) + ? true + : false; + $_SESSION['tmp_user_values']['hide_transformation'] + = isset($_SESSION['tmp_user_values']['query'][$sql_md5] + ['hide_transformation'] + ) + ? true + : false; + $_SESSION['tmp_user_values']['pos'] + = $_SESSION['tmp_user_values']['query'][$sql_md5]['pos']; + $_SESSION['tmp_user_values']['max_rows'] + = $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows']; + $_SESSION['tmp_user_values']['repeat_cells'] + = $_SESSION['tmp_user_values']['query'][$sql_md5]['repeat_cells']; + $_SESSION['tmp_user_values']['disp_direction'] + = $_SESSION['tmp_user_values']['query'][$sql_md5]['disp_direction']; + + } + + + /** + * Prepare a table of results returned by a SQL query. + * This function is called by the "sql.php" script. + * + * @param integer &$dt_result the link id associated to the query + * which results have to be displayed + * @param array &$the_disp_mode the display mode + * @param array $analyzed_sql the analyzed query + * @param boolean $is_limited_display With limited operations or not + * + * @return string $table_html Generated HTML content for resulted table + * + * @access public + * + * @see sql.php file + */ + public function getTable( + &$dt_result, &$the_disp_mode, $analyzed_sql, $is_limited_display = false + ) { + + $table_html = ''; + // Following variable are needed for use in isset/empty or + // use with array indexes/safe use in foreach + $fields_meta = $this->__get('fields_meta'); + $showtable = $this->__get('showtable'); + $printview = $this->__get('printview'); + + // why was this called here? (already called from sql.php) + //$this->setConfigParamsForDisplayTable(); + + /** + * @todo move this to a central place + * @todo for other future table types + */ + $is_innodb = (isset($showtable['Type']) + && $showtable['Type'] == self::TABLE_TYPE_INNO_DB); + + if ($is_innodb + && ! isset($analyzed_sql[0]['queryflags']['union']) + && ! isset($analyzed_sql[0]['table_ref'][1]['table_name']) + && (empty($analyzed_sql[0]['where_clause']) + || ($analyzed_sql[0]['where_clause'] == '1 ')) + ) { + // "j u s t b r o w s i n g" + $pre_count = '~'; + $after_count = PMA_Util::showHint( + PMA_sanitize( + __('May be approximate. See [doc@faq3-11]FAQ 3.11[/doc]') + ) + ); + } else { + $pre_count = ''; + $after_count = ''; + } + + // 1. ----- Prepares the work ----- + + // 1.1 Gets the informations about which functionalities should be + // displayed + $total = ''; + $is_display = $this->_setDisplayMode($the_disp_mode, $total); + + // 1.2 Defines offsets for the next and previous pages + if ($is_display['nav_bar'] == '1') { + list($pos_next, $pos_prev) = $this->_getOffsets(); + } // end if + if (!isset($analyzed_sql[0]['order_by_clause'])) { + $analyzed_sql[0]['order_by_clause'] = ""; + } + + // 1.3 Find the sort expression + // we need $sort_expression and $sort_expression_nodirection + // even if there are many table references + list($sort_expression, $sort_expression_nodirection, $sort_direction) + = $this->_getSortParams($analyzed_sql[0]['order_by_clause']); + + + // 1.4 Prepares display of first and last value of the sorted column + + $sorted_column_message = $this->_getSortedColumnMessage( + $dt_result, $sort_expression_nodirection + ); + + + // 2. ----- Prepare to display the top of the page ----- + + // 2.1 Prepares a messages with position informations + if (($is_display['nav_bar'] == '1') && isset($pos_next)) { + + $message = $this->_setMessageInformation( + $sorted_column_message, $analyzed_sql[0]['limit_clause'], + $total, $pos_next, $pre_count, $after_count + ); + + $table_html .= PMA_Util::getMessage( + $message, $this->__get('sql_query'), 'success' + ); + + } elseif (! isset($printview) || ($printview != '1')) { + + $table_html .= PMA_Util::getMessage( + __('Your SQL query has been executed successfully'), + $this->__get('sql_query'), 'success' + ); + } + + // 2.3 Prepare the navigation bars + if (! strlen($this->__get('table'))) { + + if (isset($analyzed_sql[0]['query_type']) + && ($analyzed_sql[0]['query_type'] == self::QUERY_TYPE_SELECT) + ) { + // table does not always contain a real table name, + // for example in MySQL 5.0.x, the query SHOW STATUS + // returns STATUS as a table name + $this->__set('table', $fields_meta[0]->table); + } else { + $this->__set('table', ''); + } + + } + + if (($is_display['nav_bar'] == '1') + && empty($analyzed_sql[0]['limit_clause']) + ) { + + $table_html .= $this->_getPlacedTableNavigatoins( + $pos_next, $pos_prev, self::PLACE_TOP_DIRECTION_DROPDOWN, + "\n", $is_innodb + ); + + } elseif (! isset($printview) || ($printview != '1')) { + $table_html .= "\n" . '

      ' . "\n"; + } + + // 2b ----- Get field references from Database ----- + // (see the 'relation' configuration variable) + + // initialize map + $map = array(); + + // find tables + $target=array(); + if (isset($analyzed_sql[0]['table_ref']) + && is_array($analyzed_sql[0]['table_ref']) + ) { + + foreach ($analyzed_sql[0]['table_ref'] + as $table_ref_position => $table_ref) { + $target[] = $analyzed_sql[0]['table_ref'] + [$table_ref_position]['table_true_name']; + } + + } + + $tabs = '(\'' . join('\',\'', $target) . '\')'; + + if (! strlen($this->__get('table'))) { + $exist_rel = false; + } else { + // This method set the values for $map array + $this->_setParamForLinkForeignKeyRelatedTables($map); + } // end if + // end 2b + + // 3. ----- Prepare the results table ----- + $table_html .= $this->_getTableHeaders( + $is_display, $analyzed_sql, $sort_expression, + $sort_expression_nodirection, $sort_direction, $is_limited_display + ) + . '
      ' . "\n"; + + $url_query = ''; + $table_html .= $this->_getTableBody( + $dt_result, $is_display, $map, $analyzed_sql, $is_limited_display + ); + + // vertical output case + if ($_SESSION['tmp_user_values']['disp_direction'] == self::DISP_DIR_VERTICAL) { + $table_html .= $this->_getVerticalTable($analyzed_sql, $is_display); + } // end if + + $this->__set('vertical_display', null); + + $table_html .= '' . "\n" + . '
      ' . $full_or_partial_text_link + . '' . "\n" + . ' ' . "\n" + . ' ' . $value . 'NULL
      only if the display dir is not vertical + && ($_SESSION['tmp_user_values']['disp_direction'] + != self::DISP_DIR_VERTICAL)) + ? 'hide' + : ''; + + // handle datetime-related class, for grid editing + $field_type_class + = $this->_getClassForDateTimeRelatedFields($meta->type); + + $is_field_truncated = false; + // combine all the classes applicable to this column's value + $class = $this->_getClassesForColumn( + $grid_edit_class, $not_null_class, $relation_class, + $hide_class, $field_type_class, $row_no + ); + + // See if this column should get highlight because it's used in the + // where-query. + $condition_field = (isset($highlight_columns) + && (isset($highlight_columns[$meta->name]) + || isset($highlight_columns[PMA_Util::backquote($meta->name)]))) + ? true + : false; + + // Wrap MIME-transformations. [MIME] + $default_function = '_mimeDefaultFunction'; // default_function + $transformation_plugin = $default_function; + $transform_options = array(); + + if ($GLOBALS['cfgRelation']['mimework'] + && $GLOBALS['cfg']['BrowseMIME'] + ) { + + if (isset($mime_map[$meta->name]['mimetype']) + && isset($mime_map[$meta->name]['transformation']) + && !empty($mime_map[$meta->name]['transformation']) + ) { + + $file = $mime_map[$meta->name]['transformation']; + $include_file = 'libraries/plugins/transformations/' . $file; + + if (file_exists($include_file)) { + + include_once $include_file; + $class_name = str_replace('.class.php', '', $file); + // todo add $plugin_manager + $plugin_manager = null; + $transformation_plugin = new $class_name( + $plugin_manager + ); + + $transform_options = PMA_transformation_getOptions( + isset($mime_map[$meta->name] + ['transformation_options'] + ) + ? $mime_map[$meta->name] + ['transformation_options'] + : '' + ); + + $meta->mimetype = str_replace( + '_', '/', + $mime_map[$meta->name]['mimetype'] + ); + + } // end if file_exists + } // end if transformation is set + } // end if mime/transformation works. + + $_url_params = array( + 'db' => $this->__get('db'), + 'table' => $this->__get('table'), + 'where_clause' => $where_clause, + 'transform_key' => $meta->name, + ); + + if (! empty($sql_query)) { + $_url_params['sql_query'] = $url_sql_query; + } + + $transform_options['wrapper_link'] + = PMA_generate_common_url($_url_params); + + $vertical_display = $this->__get('vertical_display'); + + // Check whether the field needs to display with syntax highlighting + + if ($this->_isNeedToSyntaxHighlight($meta->name) + && (trim($row[$i]) != '') + ) { + + $parsed_sql = PMA_SQP_parse($row[$i]); + $row[$i] = PMA_Util::formatSql( + $parsed_sql, $row[$i] + ); + include_once $this->syntax_highlighting_column_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)][0]; + $transformation_plugin = new $this->syntax_highlighting_column_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)][1](null); + + $transform_options = PMA_transformation_getOptions( + isset($mime_map[$meta->name]['transformation_options']) + ? $mime_map[$meta->name]['transformation_options'] + : '' + ); + + $meta->mimetype = str_replace( + '_', '/', + $this->syntax_highlighting_column_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)][2] + ); + + } + + // Check for the predefined fields need to show as link in schemas + include_once 'libraries/special_schema_links.lib.php'; + + if (isset($GLOBALS['special_schema_links']) + && ($this->_isFieldNeedToLink(strtolower($meta->name))) + ) { + + $linking_url = $this->_getSpecialLinkUrl( + $row[$i], $row_info, strtolower($meta->name) + ); + include_once "libraries/plugins/transformations/Text_Plain_Link.class.php"; + $transformation_plugin = new Text_Plain_Link(null); + + $transform_options = array( + 0 => $linking_url, + 2 => true + ); + + $meta->mimetype = str_replace( + '_', '/', + 'Text/Plain' + ); + + } + + if ($meta->numeric == 1) { + // n u m e r i c + + $vertical_display['data'][$row_no][$i] + = $this->_getDataCellForNumericColumns( + $row[$i], $class, $condition_field, $meta, $map, + $is_field_truncated, $analyzed_sql, + $transformation_plugin, $default_function, + $transform_options + ); + + } elseif (stristr($meta->type, self::BLOB_FIELD)) { + // b l o b + + // PMA_mysql_fetch_fields returns BLOB in place of + // TEXT fields type so we have to ensure it's really a BLOB + $field_flags = PMA_DBI_field_flags($dt_result, $i); + + $vertical_display['data'][$row_no][$i] + = $this->_getDataCellForBlobColumns( + $row[$i], $class, $meta, $_url_params, $field_flags, + $transformation_plugin, $default_function, + $transform_options, $condition_field, $is_field_truncated + ); + + } elseif ($meta->type == self::GEOMETRY_FIELD) { + // g e o m e t r y + + // Remove 'grid_edit' from $class as we do not allow to + // inline-edit geometry data. + $class = str_replace('grid_edit', '', $class); + + $vertical_display['data'][$row_no][$i] + = $this->_getDataCellForGeometryColumns( + $row[$i], $class, $meta, $map, $_url_params, + $condition_field, $transformation_plugin, + $default_function, $transform_options, + $is_field_truncated, $analyzed_sql + ); + + } else { + // n o t n u m e r i c a n d n o t B L O B + + $vertical_display['data'][$row_no][$i] + = $this->_getDataCellForNonNumericAndNonBlobColumns( + $row[$i], $class, $meta, $map, $_url_params, + $condition_field, $transformation_plugin, + $default_function, $transform_options, + $is_field_truncated, $analyzed_sql, $dt_result, $i + ); + + } + + // output stored cell + if ($directionCondition) { + $row_values_html + .= $vertical_display['data'][$row_no][$i]; + } + + if (isset($vertical_display['rowdata'][$i][$row_no])) { + $vertical_display['rowdata'][$i][$row_no] + .= $vertical_display['data'][$row_no][$i]; + } else { + $vertical_display['rowdata'][$i][$row_no] + = $vertical_display['data'][$row_no][$i]; + } + + $this->__set('vertical_display', $vertical_display); + + } // end for + + return $row_values_html; + + } // end of the '_getRowValues()' function + + + /** + * Gather delete/edit url links for further outputs + * + * @param integer $row_no the index of current row + * @param array $is_display which elements to display + * @param string $where_clause where clause + * @param string $where_clause_html the html encoded where clause + * @param string $js_conf text for the JS confirmation + * @param string $del_url the url for delete row + * @param string $del_query the query for delete row + * @param string $del_str the label for delete row + * @param string $edit_anchor_class the class for html element for edit + * @param string $edit_url the url for edit row + * @param string $edit_str the label for edit row + * @param string $copy_url the url for copy row + * @param string $copy_str the label for copy row + * @param string $alternating_color_class class for display two colors in rows + * @param array $condition_array array of keys + * (primary,unique,condition) + * + * @return void + * + * @access private + * + * @see _getTableBody() + */ + private function _gatherLinksForLaterOutputs( + $row_no, $is_display, $where_clause, $where_clause_html, $js_conf, + $del_url, $del_query, $del_str, $edit_anchor_class, $edit_url, $edit_str, + $copy_url, $copy_str, $alternating_color_class, $condition_array + ) { + + $vertical_display = $this->__get('vertical_display'); + + if (! isset($vertical_display['edit'][$row_no])) { + $vertical_display['edit'][$row_no] = ''; + $vertical_display['copy'][$row_no] = ''; + $vertical_display['delete'][$row_no] = ''; + $vertical_display['row_delete'][$row_no] = ''; + } + + $vertical_class = ' row_' . $row_no; + if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) { + $vertical_class .= ' vpointer'; + } + + if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) { + $vertical_class .= ' vmarker'; + } + + if (!empty($del_url) + && ($is_display['del_lnk'] != self::KILL_PROCESS) + ) { + + $vertical_display['row_delete'][$row_no] + .= $this->_getCheckboxForMultiRowSubmissions( + $del_url, $is_display, $row_no, $where_clause_html, + $condition_array, $del_query, '[%_PMA_CHECKBOX_DIR_%]', + $alternating_color_class . $vertical_class + ); + + } else { + unset($vertical_display['row_delete'][$row_no]); + } + + if (isset($edit_url)) { + + $vertical_display['edit'][$row_no] .= $this->_getEditLink( + $edit_url, + $alternating_color_class . ' ' . $edit_anchor_class + . $vertical_class, $edit_str, + $where_clause, + $where_clause_html + ); + + } else { + unset($vertical_display['edit'][$row_no]); + } + + if (isset($copy_url)) { + + $vertical_display['copy'][$row_no] .= $this->_getCopyLink( + $copy_url, $copy_str, $where_clause, $where_clause_html, + $alternating_color_class . $vertical_class + ); + + } else { + unset($vertical_display['copy'][$row_no]); + } + + if (isset($del_url)) { + + if (! isset($js_conf)) { + $js_conf = ''; + } + + $vertical_display['delete'][$row_no] + .= $this->_getDeleteLink( + $del_url, $del_str, $js_conf, + $alternating_color_class . $vertical_class + ); + + } else { + unset($vertical_display['delete'][$row_no]); + } + + $this->__set('vertical_display', $vertical_display); + + } // end of the '_gatherLinksForLaterOutputs()' function + + + /** + * Check whether any field is marked as need to syntax highlight + * + * @param string $field field to check + * + * @return boolean + */ + private function _isNeedToSyntaxHighlight($field) + { + if (! empty($this->syntax_highlighting_column_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($field)])) { + return true; + } + return false; + } + + /** + * Check whether the field needs to be link + * + * @param string $field field to check + * + * @return boolean + */ + private function _isFieldNeedToLink($field) + { + if (! empty($GLOBALS['special_schema_links'][strtolower($this->__get('db'))][strtolower($this->__get('table'))][$field])) { + return true; + } + return false; + } + + + /** + * Get link for display special schema links + * + * @param string $column_value column value + * @param array $row_info information about row + * @param string $field_name column name + * + * @return string generated link + */ + private function _getSpecialLinkUrl($column_value, $row_info, $field_name) + { + + $linking_url_params = array(); + $link_relations = $GLOBALS['special_schema_links'] + [strtolower($this->__get('db'))] + [strtolower($this->__get('table'))] + [$field_name]; + + if (! is_array($link_relations['link_param'])) { + $linking_url_params[$link_relations['link_param']] = $column_value; + } else { + // Consider only the case of creating link for column field + // sql query need to be pass as url param + $sql = 'SELECT `'.$column_value.'` FROM `' + . $row_info[$link_relations['link_param'][1]] .'`.`' + . $row_info[$link_relations['link_param'][2]] .'`'; + $linking_url_params[$link_relations['link_param'][0]] = $sql; + } + + + if (! empty($link_relations['link_dependancy_params'])) { + + foreach ($link_relations['link_dependancy_params'] as $new_param) { + + // If param_info is an array, set the key and value + // from that array + if (is_array($new_param['param_info'])) { + $linking_url_params[$new_param['param_info'][0]] + = $new_param['param_info'][1]; + } else { + + $linking_url_params[$new_param['param_info']] + = $row_info[strtolower($new_param['column_name'])]; + + // Special case 1 - when executing routines, according + // to the type of the routine, url param changes + if (!empty($row_info['routine_type'])) { + if (strtolower($row_info['routine_type']) == self::ROUTINE_PROCEDURE) { + $linking_url_params['execute_routine'] = 1; + } else if (strtolower($row_info['routine_type']) == self::ROUTINE_FUNCTION) { + $linking_url_params['execute_dialog'] = 1; + } + } + } + + } + + } + + return $link_relations['default_page'] + . PMA_generate_common_url($linking_url_params); + + } + + + /** + * Prepare row information for display special links + * + * @param array $row current row data + * @param array $col_order the column order + * + * @return array $row_info associative array with column nama -> value + */ + private function _getRowInfoForSpecialLinks($row, $col_order) + { + + $row_info = array(); + $fields_meta = $this->__get('fields_meta'); + + for ($n = 0; $n < $this->__get('fields_cnt'); ++$n) { + $m = $col_order ? $col_order[$n] : $n; + $row_info[strtolower($fields_meta[$m]->name)] = $row[$m]; + } + + return $row_info; + + } + + + /** + * Get url sql query without conditions to shorten URLs + * + * @param array $analyzed_sql analyzed query + * + * @return string $url_sql analyzed sql query + * + * @access private + * + * @see _getTableBody() + */ + private function _getUrlSqlQuery($analyzed_sql) + { + + if (isset($analyzed_sql) + && isset($analyzed_sql[0]) + && isset($analyzed_sql[0]['querytype']) + && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT) + && (strlen($this->__get('sql_query')) > 200) + ) { + + $url_sql_query = 'SELECT '; + if (isset($analyzed_sql[0]['queryflags']['distinct'])) { + $url_sql_query .= ' DISTINCT '; + } + + $url_sql_query .= $analyzed_sql[0]['select_expr_clause']; + if (!empty($analyzed_sql[0]['from_clause'])) { + $url_sql_query .= ' FROM ' . $analyzed_sql[0]['from_clause']; + } + + return $url_sql_query; + } + + return $this->__get('sql_query'); + + } // end of the '_getUrlSqlQuery()' function + + + /** + * Get column order and column visibility + * + * @param array $analyzed_sql the analyzed query + * + * @return array 2 element array - $col_order, $col_visib + * + * @access private + * + * @see _getTableBody() + */ + private function _getColumnParams($analyzed_sql) + { + if ($this->_isSelect($analyzed_sql)) { + $pmatable = new PMA_Table($this->__get('table'), $this->__get('db')); + $col_order = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_ORDER); + $col_visib = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_VISIB); + } else { + $col_order = false; + $col_visib = false; + } + + return array($col_order, $col_visib); + } // end of the '_getColumnParams()' function + + + /** + * Prepare vertical display mode necessay HTML stuff + * + * @param array $vertical_display informations used with vertical + * display mode + * @param integer $row_no the index of current row + * @param boolean $directionCondition the directional condition + * + * @return string $vertical_disp_html html content + * + * @access private + * + * @see _getTableBody() + */ + private function _getVerticalDisplaySupportSegments( + $vertical_display, $row_no, $directionCondition + ) { + + $support_html = ''; + + if ((($row_no != 0) && ($_SESSION['tmp_user_values']['repeat_cells'] != 0)) + && !($row_no % $_SESSION['tmp_user_values']['repeat_cells']) + && $directionCondition + ) { + + $support_html .= '
      ' + . "\n".'  ' + . "\n" . '  
      '; + + // 4. ----- Prepares the link for multi-fields edit and delete + + if ($is_display['del_lnk'] == self::DELETE_ROW + && $is_display['del_lnk'] != self::KILL_PROCESS + ) { + + $table_html .= $this->_getMultiRowOperationLinks( + $dt_result, $analyzed_sql, $is_display['del_lnk'] + ); + + } + + // 5. ----- Get the navigation bar at the bottom if required ----- + if (($is_display['nav_bar'] == '1') + && empty($analyzed_sql[0]['limit_clause']) + ) { + $table_html .= $this->_getPlacedTableNavigatoins( + $pos_next, $pos_prev, self::PLACE_BOTTOM_DIRECTION_DROPDOWN, + '
      ' . "\n", $is_innodb + ); + } elseif (! isset($printview) || ($printview != '1')) { + $table_html .= "\n" . '

      ' . "\n"; + } + + + // 6. ----- Prepare "Query results operations" + if ((! isset($printview) || ($printview != '1')) && ! $is_limited_display) { + $table_html .= $this->_getResultsOperations( + $the_disp_mode, $analyzed_sql + ); + } + + return $table_html; + + } // end of the 'getTable()' function + + + /** + * Get offsets for next page and previous page + * + * @return array array with two elements - $pos_next, $pos_prev + * + * @access private + * + * @see getTable() + */ + private function _getOffsets() + { + + if ($_SESSION['tmp_user_values']['max_rows'] == self::ALL_ROWS) { + $pos_next = 0; + $pos_prev = 0; + } else { + + $pos_next = $_SESSION['tmp_user_values']['pos'] + + $_SESSION['tmp_user_values']['max_rows']; + + $pos_prev = $_SESSION['tmp_user_values']['pos'] + - $_SESSION['tmp_user_values']['max_rows']; + + if ($pos_prev < 0) { + $pos_prev = 0; + } + } + + return array($pos_next, $pos_prev); + + } // end of the '_getOffsets()' function + + + /** + * Get sort parameters + * + * @param string $order_by_clause the order by clause of the sql query + * + * @return array 3 element array: $sort_expression, + * $sort_expression_nodirection, $sort_direction + * + * @access private + * + * @see getTable() + */ + private function _getSortParams($order_by_clause) + { + + if (! empty($order_by_clause)) { + + $sort_expression = trim( + str_replace(' ', ' ', $order_by_clause) + ); + /** + * Get rid of ASC|DESC + */ + preg_match( + '@(.*)([[:space:]]*(ASC|DESC))@si', $sort_expression, $matches + ); + + $sort_expression_nodirection = isset($matches[1]) + ? trim($matches[1]) + : $sort_expression; + + $sort_direction = isset($matches[2]) ? trim($matches[2]) : ''; + unset($matches); + + } else { + $sort_expression = $sort_expression_nodirection = $sort_direction = ''; + } + + return array($sort_expression, $sort_expression_nodirection, + $sort_direction + ); + + } // end of the '_getSortParams()' function + + + /** + * Prepare sorted column message + * + * @param integer &$dt_result the link id associated to the + * query which results have to + * be displayed + * @param string $sort_expression_nodirection sort expression without direction + * + * @return string html content + * null if not found sorted column + * + * @access private + * + * @see getTable() + */ + private function _getSortedColumnMessage( + &$dt_result, $sort_expression_nodirection + ) { + + $fields_meta = $this->__get('fields_meta'); // To use array indexes + + if (! empty($sort_expression_nodirection)) { + + if (strpos($sort_expression_nodirection, '.') === false) { + $sort_table = $this->__get('table'); + $sort_column = $sort_expression_nodirection; + } else { + list($sort_table, $sort_column) + = explode('.', $sort_expression_nodirection); + } + + $sort_table = PMA_Util::unQuote($sort_table); + $sort_column = PMA_Util::unQuote($sort_column); + + // find the sorted column index in row result + // (this might be a multi-table query) + $sorted_column_index = false; + + foreach ($fields_meta as $key => $meta) { + if (($meta->table == $sort_table) && ($meta->name == $sort_column)) { + $sorted_column_index = $key; + break; + } + } + + if ($sorted_column_index !== false) { + + // fetch first row of the result set + $row = PMA_DBI_fetch_row($dt_result); + + // initializing default arguments + $default_function = '_mimeDefaultFunction'; + $transformation_plugin = $default_function; + $transform_options = array(); + + // check for non printable sorted row data + $meta = $fields_meta[$sorted_column_index]; + + if (stristr($meta->type, self::BLOB_FIELD) + || ($meta->type == self::GEOMETRY_FIELD) + ) { + + $column_for_first_row = $this->_handleNonPrintableContents( + $meta->type, $row[$sorted_column_index], + $transformation_plugin, $transform_options, + $default_function, $meta, null + ); + + } else { + $column_for_first_row = $row[$sorted_column_index]; + } + + $column_for_first_row = strtoupper( + substr($column_for_first_row, 0, $GLOBALS['cfg']['LimitChars']) + ); + + // fetch last row of the result set + PMA_DBI_data_seek($dt_result, $this->__get('num_rows') - 1); + $row = PMA_DBI_fetch_row($dt_result); + + // check for non printable sorted row data + $meta = $fields_meta[$sorted_column_index]; + if (stristr($meta->type, self::BLOB_FIELD) + || ($meta->type == self::GEOMETRY_FIELD) + ) { + + $column_for_last_row = $this->_handleNonPrintableContents( + $meta->type, $row[$sorted_column_index], + $transformation_plugin, $transform_options, + $default_function, $meta, null + ); + + } else { + $column_for_last_row = $row[$sorted_column_index]; + } + + $column_for_last_row = strtoupper( + substr($column_for_last_row, 0, $GLOBALS['cfg']['LimitChars']) + ); + + // reset to first row for the loop in _getTableBody() + PMA_DBI_data_seek($dt_result, 0); + + // we could also use here $sort_expression_nodirection + return ' [' . htmlspecialchars($sort_column) + . ': ' . htmlspecialchars($column_for_first_row) . ' - ' + . htmlspecialchars($column_for_last_row) . ']'; + } + } + + return null; + + } // end of the '_getSortedColumnMessage()' function + + + /** + * Set the content need to be show in message + * + * @param string $sorted_column_message the message for sorted column + * @param string $limit_clause the limit clause of analyzed query + * @param integer $total the total number of rows returned by + * the SQL query without any + * programmatically appended LIMIT clause + * @param integer $pos_next the offset for next page + * @param string $pre_count the string renders before row count + * @param string $after_count the string renders after row count + * + * @return PMA_Message $message an object of PMA_Message + * + * @access private + * + * @see getTable() + */ + private function _setMessageInformation( + $sorted_column_message, $limit_clause, $total, + $pos_next, $pre_count, $after_count + ) { + + $unlim_num_rows = $this->__get('unlim_num_rows'); // To use in isset() + + if (isset($unlim_num_rows) && ($unlim_num_rows != $total)) { + $selectstring = ', ' . $unlim_num_rows . ' ' . __('in query'); + } else { + $selectstring = ''; + } + + if (! empty($limit_clause)) { + + $limit_data + = PMA_Util::analyzeLimitClause($limit_clause); + $first_shown_rec = $limit_data['start']; + + if ($limit_data['length'] < $total) { + $last_shown_rec = $limit_data['start'] + $limit_data['length'] - 1; + } else { + $last_shown_rec = $limit_data['start'] + $total - 1; + } + + } elseif (($_SESSION['tmp_user_values']['max_rows'] == self::ALL_ROWS) + || ($pos_next > $total) + ) { + + $first_shown_rec = $_SESSION['tmp_user_values']['pos']; + $last_shown_rec = $total - 1; + + } else { + + $first_shown_rec = $_SESSION['tmp_user_values']['pos']; + $last_shown_rec = $pos_next - 1; + + } + + if (PMA_Table::isView($this->__get('db'), $this->__get('table')) + && ($total == $GLOBALS['cfg']['MaxExactCountViews']) + ) { + + $message = PMA_Message::notice( + __( + 'This view has at least this number of rows. ' + . 'Please refer to %sdocumentation%s.' + ) + ); + + $message->addParam('[doc@cfg_MaxExactCount]'); + $message->addParam('[/doc]'); + $message_view_warning = PMA_Util::showHint($message); + + } else { + $message_view_warning = false; + } + + $message = PMA_Message::success(__('Showing rows')); + $message->addMessage($first_shown_rec); + + if ($message_view_warning) { + + $message->addMessage('...', ' - '); + $message->addMessage($message_view_warning); + $message->addMessage('('); + + } else { + + $message->addMessage($last_shown_rec, ' - '); + $message->addMessage(' ('); + $message->addMessage( + $pre_count . PMA_Util::formatNumber($total, 0) + ); + $message->addString(__('total')); + + if (!empty($after_count)) { + $message->addMessage($after_count); + } + + $message->addMessage($selectstring, ''); + $message->addMessage(', ', ''); + + } + + $messagge_qt = PMA_Message::notice(__('Query took %01.4f sec') . ')'); + $messagge_qt->addParam($this->__get('querytime')); + + $message->addMessage($messagge_qt, ''); + if (! is_null($sorted_column_message)) { + $message->addMessage($sorted_column_message, ''); + } + + return $message; + + } // end of the '_setMessageInformation()' function + + + /** + * Set the value of $map array for linking foreign key related tables + * + * @param array &$map the list of relations + * + * @return void + * + * @access private + * + * @see getTable() + */ + private function _setParamForLinkForeignKeyRelatedTables(&$map) + { + + // To be able to later display a link to the related table, + // we verify both types of relations: either those that are + // native foreign keys or those defined in the phpMyAdmin + // configuration storage. If no PMA storage, we won't be able + // to use the "column to display" notion (for example show + // the name related to a numeric id). + $exist_rel = PMA_getForeigners( + $this->__get('db'), $this->__get('table'), '', self::POSITION_BOTH + ); + + if ($exist_rel) { + + foreach ($exist_rel as $master_field => $rel) { + + $display_field = PMA_getDisplayField( + $rel['foreign_db'], $rel['foreign_table'] + ); + + $map[$master_field] = array( + $rel['foreign_table'], + $rel['foreign_field'], + $display_field, + $rel['foreign_db'] + ); + } // end while + } // end if + + } // end of the '_setParamForLinkForeignKeyRelatedTables()' function + + + /** + * Prepare multi field edit/delete links + * + * @param integer &$dt_result the link id associated to the query + * which results have to be displayed + * @param array $analyzed_sql the analyzed query + * @param string $del_link the display element - 'del_link' + * + * @return string $links_html html content + * + * @access private + * + * @see getTable() + */ + private function _getMultiRowOperationLinks( + &$dt_result, $analyzed_sql, $del_link + ) { + + $links_html = ''; + $url_query = $this->__get('url_query'); + $delete_text = ($del_link == self::DELETE_ROW) ? __('Delete') : __('Kill'); + + $_url_params = array( + 'db' => $this->__get('db'), + 'table' => $this->__get('table'), + 'sql_query' => $this->__get('sql_query'), + 'goto' => $this->__get('goto'), + ); + + if ($_SESSION['tmp_user_values']['disp_direction'] != self::DISP_DIR_VERTICAL) { + + $links_html .= '' . __('With selected:') . ''; + } + + $links_html .= ' ' + . ' ' + . '' . __('With selected:') . '' . "\n"; + + $links_html .= PMA_Util::getButtonOrImage( + 'submit_mult', 'mult_submit', 'submit_mult_change', + __('Change'), 'b_edit.png', 'edit' + ); + + $links_html .= PMA_Util::getButtonOrImage( + 'submit_mult', 'mult_submit', 'submit_mult_delete', + $delete_text, 'b_drop.png', 'delete' + ); + + if (isset($analyzed_sql[0]) + && $analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT + ) { + $links_html .= PMA_Util::getButtonOrImage( + 'submit_mult', 'mult_submit', 'submit_mult_export', + __('Export'), 'b_tblexport.png', 'export' + ); + } + + $links_html .= "\n"; + + $links_html .= '' + . "\n"; + + if (! empty($url_query)) { + $links_html .= '' . "\n"; + } + + // fetch last row of the result set + PMA_DBI_data_seek($dt_result, $this->__get('num_rows') - 1); + $row = PMA_DBI_fetch_row($dt_result); + + // $clause_is_unique is needed by getTable() to generate the proper param + // in the multi-edit and multi-delete form + list($where_clause, $clause_is_unique, $condition_array) + = PMA_Util::getUniqueCondition( + $dt_result, + $this->__get('fields_cnt'), + $this->__get('fields_meta'), + $row + ); + + // reset to first row for the loop in _getTableBody() + PMA_DBI_data_seek($dt_result, 0); + + $links_html .= '' . "\n"; + + $links_html .= '
      ' . "\n"; + + return $links_html; + + } // end of the '_getMultiRowOperationLinks()' function + + + /** + * Prepare table navigation bar at the top or bottom + * + * @param integer $pos_next the offset for the "next" page + * @param integer $pos_prev the offset for the "previous" page + * @param string $place the place to show navigation + * @param string $empty_line empty line depend on the $place + * @param boolean $is_innodb whether its InnoDB or not + * + * @return string html content of navigation bar + * + * @access private + * + * @see _getTable() + */ + private function _getPlacedTableNavigatoins( + $pos_next, $pos_prev, $place, $empty_line, $is_innodb + ) { + + $navigation_html = ''; + + if ($place == self::PLACE_BOTTOM_DIRECTION_DROPDOWN) { + $navigation_html .= '
      ' . "\n"; + } + + $navigation_html .= $this->_getTableNavigation( + $pos_next, $pos_prev, 'top_direction_dropdown', $is_innodb + ); + + if ($place == self::PLACE_TOP_DIRECTION_DROPDOWN) { + $navigation_html .= "\n"; + } + + return $navigation_html; + + } // end of the '_getPlacedTableNavigatoins()' function + + + /** + * Get operations that are available on results. + * + * @param array $the_disp_mode the display mode + * @param array $analyzed_sql the analyzed query + * + * @return string $results_operations_html html content + * + * @access private + * + * @see getTable() + */ + private function _getResultsOperations($the_disp_mode, $analyzed_sql) + { + global $printview; + + $results_operations_html = ''; + $fields_meta = $this->__get('fields_meta'); // To safe use in foreach + $header_shown = false; + $header = '
      ' . __('Query results operations') + . ''; + + if (($the_disp_mode[6] == '1') || ($the_disp_mode[9] == '1')) { + // Displays "printable view" link if required + if ($the_disp_mode[9] == '1') { + + if (!$header_shown) { + $results_operations_html .= $header; + $header_shown = true; + } + + $_url_params = array( + 'db' => $this->__get('db'), + 'table' => $this->__get('table'), + 'printview' => '1', + 'sql_query' => $this->__get('sql_query'), + ); + $url_query = PMA_generate_common_url($_url_params); + + $results_operations_html + .= PMA_Util::linkOrButton( + 'sql.php' . $url_query, + PMA_Util::getIcon( + 'b_print.png', __('Print view'), true + ), + array('target' => 'print_view'), + true, + true, + 'print_view' + ) + . "\n"; + + if ($_SESSION['tmp_user_values']['display_text']) { + + $_url_params['display_text'] = self::DISPLAY_FULL_TEXT; + + $results_operations_html + .= PMA_Util::linkOrButton( + 'sql.php' . PMA_generate_common_url($_url_params), + PMA_Util::getIcon( + 'b_print.png', + __('Print view (with full texts)'), true + ), + array('target' => 'print_view'), + true, + true, + 'print_view' + ) + . "\n"; + unset($_url_params['display_text']); + } + } // end displays "printable view" + } + + // Export link + // (the url_query has extra parameters that won't be used to export) + // (the single_table parameter is used in display_export.lib.php + // to hide the SQL and the structure export dialogs) + // If the parser found a PROCEDURE clause + // (most probably PROCEDURE ANALYSE()) it makes no sense to + // display the Export link). + if (isset($analyzed_sql[0]) + && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT) + && ! isset($printview) + && ! isset($analyzed_sql[0]['queryflags']['procedure']) + ) { + + if (isset($analyzed_sql[0]['table_ref'][0]['table_true_name']) + && ! isset($analyzed_sql[0]['table_ref'][1]['table_true_name']) + ) { + $_url_params['single_table'] = 'true'; + } + + if (! $header_shown) { + $results_operations_html .= $header; + $header_shown = true; + } + + $_url_params['unlim_num_rows'] = $this->__get('unlim_num_rows'); + + /** + * At this point we don't know the table name; this can happen + * for example with a query like + * SELECT bike_code FROM (SELECT bike_code FROM bikes) tmp + * As a workaround we set in the table parameter the name of the + * first table of this database, so that tbl_export.php and + * the script it calls do not fail + */ + if (empty($_url_params['table']) && ! empty($_url_params['db'])) { + $_url_params['table'] = PMA_DBI_fetch_value("SHOW TABLES"); + /* No result (probably no database selected) */ + if ($_url_params['table'] === false) { + unset($_url_params['table']); + } + } + + $results_operations_html .= PMA_Util::linkOrButton( + 'tbl_export.php' . PMA_generate_common_url($_url_params), + PMA_Util::getIcon( + 'b_tblexport.png', __('Export'), true + ), + '', + true, + true, + '' + ) + . "\n"; + + // prepare chart + $results_operations_html .= PMA_Util::linkOrButton( + 'tbl_chart.php' . PMA_generate_common_url($_url_params), + PMA_Util::getIcon( + 'b_chart.png', __('Display chart'), true + ), + '', + true, + true, + '' + ) + . "\n"; + + // prepare GIS chart + $geometry_found = false; + // If atleast one geometry field is found + foreach ($fields_meta as $meta) { + if ($meta->type == self::GEOMETRY_FIELD) { + $geometry_found = true; + break; + } + } + + if ($geometry_found) { + $results_operations_html + .= PMA_Util::linkOrButton( + 'tbl_gis_visualization.php' + . PMA_generate_common_url($_url_params), + PMA_Util::getIcon( + 'b_globe.gif', __('Visualize GIS data'), true + ), + '', + true, + true, + '' + ) + . "\n"; + } + } + + // CREATE VIEW + /** + * + * @todo detect privileges to create a view + * (but see 2006-01-19 note in display_create_table.lib.php, + * I think we cannot detect db-specific privileges reliably) + * Note: we don't display a Create view link if we found a PROCEDURE clause + */ + if (!$header_shown) { + $results_operations_html .= $header; + $header_shown = true; + } + + if (!PMA_DRIZZLE && !isset($analyzed_sql[0]['queryflags']['procedure'])) { + + $ajax_class = ' ajax'; + + $results_operations_html .= '' + . PMA_Util::linkOrButton( + 'view_create.php' . $url_query, + PMA_Util::getIcon( + 'b_views.png', __('Create view'), true + ), + array('class' => 'create_view' . $ajax_class), true, true, '' + ) + . '' . "\n"; + } + + if ($header_shown) { + $results_operations_html .= '

      '; + } + + return $results_operations_html; + + } // end of the '_getResultsOperations()' function + + + /** + * Verifies what to do with non-printable contents (binary or BLOB) + * in Browse mode. + * + * @param string $category BLOB|BINARY|GEOMETRY + * @param string $content the binary content + * @param string $transformation_plugin transformation plugin. + * Can also be the default function: + * PMA_mimeDefaultFunction + * @param string $transform_options transformation parameters + * @param string $default_function default transformation function + * @param object $meta the meta-information about the field + * @param array $url_params parameters that should go to the + * download link + * + * @return mixed string or float + * + * @access private + * + * @see _getDataCellForBlobColumns(), + * _getDataCellForGeometryColumns(), + * _getDataCellForNonNumericAndNonBlobColumns(), + * _getSortedColumnMessage() + */ + private function _handleNonPrintableContents( + $category, $content, $transformation_plugin, $transform_options, + $default_function, $meta, $url_params = array() + ) { + + $result = '[' . $category; + + if (is_null($content)) { + + $result .= ' - NULL'; + $size = 0; + + } elseif (isset($content)) { + + $size = strlen($content); + $display_size + = PMA_Util::formatByteDown($size, 3, 1); + $result .= ' - '. $display_size[0] . ' ' . $display_size[1]; + + } + + $result .= ']'; + + if (gettype($transformation_plugin) == "object" + && strpos($transformation_plugin->getMIMESubtype(), 'Octetstream') + ) { + $result = $content; + } + + if ($size > 0) { + + if ($default_function != $transformation_plugin) { + $result = $transformation_plugin->applyTransformation( + $result, + $transform_options, + $meta + ); + } else { + + $result = $this->$default_function($result, array(), $meta); + if (stristr($meta->type, self::BLOB_FIELD) + && $_SESSION['tmp_user_values']['display_blob'] + ) { + // in this case, restart from the original $content + $result = $this->_displayBinaryAsPrintable($content, 'blob'); + } + + /* Create link to download */ + if (count($url_params) > 0) { + $result = '
      ' + . $result . ''; + } + } + } + + return($result); + + } // end of the '_handleNonPrintableContents()' function + + + /** + * Prepares the displayable content of a data cell in Browse mode, + * taking into account foreign key description field and transformations + * + * @param string $class css classes for the td element + * @param bool $condition_field whether the column is a part of the + * where clause + * @param string $analyzed_sql the analyzed query + * @param object $meta the meta-information about the field + * @param array $map the list of relations + * @param string $data data + * @param string $transformation_plugin transformation plugin. + * Can also be the default function: + * PMA_mimeDefaultFunction + * @param string $default_function default function + * @param string $nowrap 'nowrap' if the content should not + * be wrapped + * @param string $where_comparison data for the where clause + * @param array $transform_options array of options for transformation + * @param bool $is_field_truncated whether the field is truncated + * + * @return string formatted data + * + * @access private + * + * @see _getDataCellForNumericColumns(), _getDataCellForGeometryColumns(), + * _getDataCellForNonNumericAndNonBlobColumns(), + * + */ + private function _getRowData( + $class, $condition_field, $analyzed_sql, $meta, $map, $data, + $transformation_plugin, $default_function, $nowrap, $where_comparison, + $transform_options, $is_field_truncated + ) { + + $printview = $this->__get('printview'); + $result = ''; + + if (isset($analyzed_sql[0]['select_expr']) + && is_array($analyzed_sql[0]['select_expr']) + ) { + + foreach ($analyzed_sql[0]['select_expr'] + as $select_expr_position => $select_expr + ) { + + $alias = $analyzed_sql[0]['select_expr'] + [$select_expr_position]['alias']; + + if (isset($alias) && strlen($alias)) { + $true_column = $analyzed_sql[0]['select_expr'] + [$select_expr_position]['column']; + + if ($alias == $meta->name) { + // this change in the parameter does not matter + // outside of the function + $meta->name = $true_column; + } // end if + + } // end if + } // end foreach + } // end if + + if (isset($map[$meta->name])) { + + // Field to display from the foreign table? + if (isset($map[$meta->name][2]) && strlen($map[$meta->name][2])) { + + $dispsql = 'SELECT ' + . PMA_Util::backquote($map[$meta->name][2]) + . ' FROM ' + . PMA_Util::backquote($map[$meta->name][3]) + . '.' + . PMA_Util::backquote($map[$meta->name][0]) + . ' WHERE ' + . PMA_Util::backquote($map[$meta->name][1]) + . $where_comparison; + + $dispresult = PMA_DBI_try_query($dispsql, null, PMA_DBI_QUERY_STORE); + + if ($dispresult && PMA_DBI_num_rows($dispresult) > 0) { + list($dispval) = PMA_DBI_fetch_row($dispresult, 0); + } else { + $dispval = __('Link not found'); + } + + @PMA_DBI_free_result($dispresult); + + } else { + $dispval = ''; + } // end if... else... + + if (isset($printview) && ($printview == '1')) { + + $result .= ($transformation_plugin != $default_function + ? $transformation_plugin->applyTransformation( + $data, + $transform_options, + $meta + ) + : $this->$default_function($data) + ) + . ' [->' . $dispval . ']'; + + } else { + + if ($_SESSION['tmp_user_values']['relational_display'] == self::RELATIONAL_KEY) { + + // 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($data) . '"'; + } + + $_url_params = array( + 'db' => $map[$meta->name][3], + 'table' => $map[$meta->name][0], + 'pos' => '0', + 'sql_query' => 'SELECT * FROM ' + . PMA_Util::backquote( + $map[$meta->name][3] + ) . '.' + . PMA_Util::backquote( + $map[$meta->name][0] + ) + . ' WHERE ' + . PMA_Util::backquote( + $map[$meta->name][1] + ) + . $where_comparison, + ); + + $result .= ''; + + if ($transformation_plugin != $default_function) { + // always apply a transformation on the real data, + // not on the display field + $result .= $transformation_plugin->applyTransformation( + $data, + $transform_options, + $meta + ); + } else { + + if ($_SESSION['tmp_user_values']['relational_display'] == self::RELATIONAL_DISPLAY_COLUMN) { + // user chose "relational display field" in the + // display options, so show display field in the cell + $result .= $this->$default_function($dispval); + } else { + // otherwise display data in the cell + $result .= $this->$default_function($data); + } + + } + $result .= ''; + } + + } else { + $result .= ($transformation_plugin != $default_function + ? $transformation_plugin->applyTransformation( + $data, + $transform_options, + $meta + ) + : $this->$default_function($data) + ); + } + + // create hidden field if results from structure table + if (isset($_GET['browse_distinct']) && ($_GET['browse_distinct'] == 1)) { + + $where_comparison = " = '" . $data . "'"; + + $_url_params_for_show_data_row = array( + 'db' => $this->__get('db'), + 'table' => $meta->orgtable, + 'pos' => '0', + 'sql_query' => 'SELECT * FROM ' + . PMA_Util::backquote($this->__get('db')) + . '.' . PMA_Util::backquote($meta->orgtable) + . ' WHERE ' + . PMA_Util::backquote($meta->orgname) + . $where_comparison, + ); + + $result .= ''; + + } + + $result .= '' . "\n"; + + return $result; + + } // end of the '_getRowData()' function + + + /** + * Prepares a checkbox for multi-row submits + * + * @param string $del_url delete url + * @param array $is_display array with explicit indexes for all + * the display elements + * @param string $row_no the row number + * @param string $where_clause_html url encoded where clause + * @param array $condition_array array of conditions in the where clause + * @param string $del_query delete query + * @param string $id_suffix suffix for the id + * @param string $class css classes for the td element + * + * @return string the generated HTML + * + * @access private + * + * @see _getTableBody(), _getCheckboxAndLinks() + */ + private function _getCheckboxForMultiRowSubmissions( + $del_url, $is_display, $row_no, $where_clause_html, $condition_array, + $del_query, $id_suffix, $class + ) { + + $ret = ''; + + if (! empty($del_url) && $is_display['del_lnk'] != self::KILL_PROCESS) { + + $ret .= '' + . '' + . ' '; + } + + return $ret; + + } // end of the '_getCheckboxForMultiRowSubmissions()' function + + + /** + * Prepares an Edit link + * + * @param string $edit_url edit url + * @param string $class css classes for td element + * @param string $edit_str text for the edit link + * @param string $where_clause where clause + * @param string $where_clause_html url encoded where clause + * + * @return string the generated HTML + * + * @access private + * + * @see _getTableBody(), _getCheckboxAndLinks() + */ + private function _getEditLink( + $edit_url, $class, $edit_str, $where_clause, $where_clause_html + ) { + + $ret = ''; + if (! empty($edit_url)) { + + $ret .= '' + . PMA_Util::linkOrButton( + $edit_url, $edit_str, array(), false + ); + /* + * Where clause for selecting this row uniquely is provided as + * a hidden input. Used by jQuery scripts for handling grid editing + */ + if (! empty($where_clause)) { + $ret .= ''; + } + $ret .= ''; + } + + return $ret; + + } // end of the '_getEditLink()' function + + + /** + * Prepares an Copy link + * + * @param string $copy_url copy url + * @param string $copy_str text for the copy link + * @param string $where_clause where clause + * @param string $where_clause_html url encoded where clause + * @param string $class css classes for the td element + * + * @return string the generated HTML + * + * @access private + * + * @see _getTableBody(), _getCheckboxAndLinks() + */ + private function _getCopyLink( + $copy_url, $copy_str, $where_clause, $where_clause_html, $class + ) { + + $ret = ''; + if (! empty($copy_url)) { + + $ret .= '' + . PMA_Util::linkOrButton( + $copy_url, $copy_str, array(), false + ); + + /* + * Where clause for selecting this row uniquely is provided as + * a hidden input. Used by jQuery scripts for handling grid editing + */ + if (! empty($where_clause)) { + $ret .= ''; + } + $ret .= ''; + } + + return $ret; + + } // end of the '_getCopyLink()' function + + + /** + * Prepares a Delete link + * + * @param string $del_url delete url + * @param string $del_str text for the delete link + * @param string $js_conf text for the JS confirmation + * @param string $class css classes for the td element + * + * @return string the generated HTML + * + * @access private + * + * @see _getTableBody(), _getCheckboxAndLinks() + */ + private function _getDeleteLink($del_url, $del_str, $js_conf, $class) + { + + $ret = ''; + if (! empty($del_url)) { + + $ret .= '' + . PMA_Util::linkOrButton( + $del_url, $del_str, array('class' => 'delete_row' . $ajax), false + ) + . '
      ' . $js_conf . '
      ' + . ''; + } + + return $ret; + + } // end of the '_getDeleteLink()' function + + + /** + * Prepare checkbox and links at some position (left or right) + * (only called for horizontal mode) + * + * @param string $position the position of the checkbox and links + * @param string $del_url delete url + * @param array $is_display array with explicit indexes for all the + * display elements + * @param string $row_no row number + * @param string $where_clause where clause + * @param string $where_clause_html url encoded where clause + * @param array $condition_array array of conditions in the where clause + * @param string $del_query delete query + * @param string $id_suffix suffix for the id + * @param string $edit_url edit url + * @param string $copy_url copy url + * @param string $class css classes for the td elements + * @param string $edit_str text for the edit link + * @param string $copy_str text for the copy link + * @param string $del_str text for the delete link + * @param string $js_conf text for the JS confirmation + * + * @return string the generated HTML + * + * @access private + * + * @see _getPlacedLinks() + */ + private function _getCheckboxAndLinks( + $position, $del_url, $is_display, $row_no, $where_clause, + $where_clause_html, $condition_array, $del_query, $id_suffix, + $edit_url, $copy_url, $class, $edit_str, $copy_str, $del_str, $js_conf + ) { + + $ret = ''; + + if ($position == self::POSITION_LEFT) { + + $ret .= $this->_getCheckboxForMultiRowSubmissions( + $del_url, $is_display, $row_no, $where_clause_html, $condition_array, + $del_query, $id_suffix = '_left', '' + ); + + $ret .= $this->_getEditLink( + $edit_url, $class, $edit_str, $where_clause, $where_clause_html + ); + + $ret .= $this->_getCopyLink( + $copy_url, $copy_str, $where_clause, $where_clause_html, '' + ); + + $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, ''); + + } elseif ($position == self::POSITION_RIGHT) { + + $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, ''); + + $ret .= $this->_getCopyLink( + $copy_url, $copy_str, $where_clause, $where_clause_html, '' + ); + + $ret .= $this->_getEditLink( + $edit_url, $class, $edit_str, $where_clause, $where_clause_html + ); + + $ret .= $this->_getCheckboxForMultiRowSubmissions( + $del_url, $is_display, $row_no, $where_clause_html, $condition_array, + $del_query, $id_suffix = '_right', '' + ); + + } else { // $position == self::POSITION_NONE + + $ret .= $this->_getCheckboxForMultiRowSubmissions( + $del_url, $is_display, $row_no, $where_clause_html, $condition_array, + $del_query, $id_suffix = '_left', '' + ); + } + + return $ret; + + } // end of the '_getCheckboxAndLinks()' function + + + /** + * Replace some html-unfriendly stuff + * + * @param string $buffer String to process + * + * @return Escaped and cleaned up text suitable for html. + * + * @access private + * + * @see _getDataCellForBlobField(), _getRowData(), + * _handleNonPrintableContents() + */ + private function _mimeDefaultFunction($buffer) + { + $buffer = htmlspecialchars($buffer); + $buffer = str_replace( + "\011", + '    ', + str_replace(' ', '  ', $buffer) + ); + $buffer = preg_replace("@((\015\012)|(\015)|(\012))@", '
      ', $buffer); + + return $buffer; + } + + /** + * Display binary fields as hex string for PHP <5.4, + * otherwise escape the contents if it may be displayed as hex + * + * @param string $content String to parse + * @param string $binary_or_blob 'binary' or 'blob' + * @param int $hexlength optional, get substring + * + * @return Displayable version of the binary string + * + * @access private + * + * @see _getDataCellForGeometryColumns + * _getDataCellForNonNumericAndNonBlobColumns + * _handleNonPrintableContents + */ + private function _displayBinaryAsPrintable( + $content, $binary_or_blob, $hexlength = null + ) { + if (PMA_PHP_INT_VERSION < 50400 + || ($binary_or_blob === 'binary' + && $_SESSION['tmp_user_values']['display_binary_as_hex'] + && PMA_Util::containsNonPrintableAscii($content) + ) + ) { + $content = bin2hex($content); + if ($hexlength !== null) { + $content = PMA_substr($content, $hexlength); + } + } else { + $content = htmlspecialchars( + PMA_Util::replaceBinaryContents( + $content + ), + ENT_SUBSTITUTE + ); + } + return $content; + } +} +?> diff --git a/phpmyadmin/libraries/Error.class.php b/phpmyadmin/libraries/Error.class.php new file mode 100644 index 000000000..e2c013328 --- /dev/null +++ b/phpmyadmin/libraries/Error.class.php @@ -0,0 +1,409 @@ + 'Error', + E_WARNING => 'Warning', + E_PARSE => 'Parsing Error', + E_NOTICE => 'Notice', + E_CORE_ERROR => 'Core Error', + E_CORE_WARNING => 'Core Warning', + E_COMPILE_ERROR => 'Compile Error', + E_COMPILE_WARNING => 'Compile Warning', + E_USER_ERROR => 'User Error', + E_USER_WARNING => 'User Warning', + E_USER_NOTICE => 'User Notice', + E_STRICT => 'Runtime Notice', + E_DEPRECATED => 'Deprecation Notice', + E_RECOVERABLE_ERROR => 'Catchable Fatal Error', + ); + + /** + * Error levels + * + * @var array + */ + static public $errorlevel = array ( + E_ERROR => 'error', + E_WARNING => 'error', + E_PARSE => 'error', + E_NOTICE => 'notice', + E_CORE_ERROR => 'error', + E_CORE_WARNING => 'error', + E_COMPILE_ERROR => 'error', + E_COMPILE_WARNING => 'error', + E_USER_ERROR => 'error', + E_USER_WARNING => 'error', + E_USER_NOTICE => 'notice', + E_STRICT => 'notice', + E_DEPRECATED => 'notice', + E_RECOVERABLE_ERROR => 'error', + ); + + /** + * The file in which the error occured + * + * @var string + */ + protected $file = ''; + + /** + * The line in which the error occured + * + * @var integer + */ + protected $line = 0; + + /** + * Holds the backtrace for this error + * + * @var array + */ + protected $backtrace = array(); + + /** + * Unique id + * + * @var string + */ + protected $hash = null; + + /** + * Constructor + * + * @param integer $errno error number + * @param string $errstr error message + * @param string $errfile file + * @param integer $errline line + */ + public function __construct($errno, $errstr, $errfile, $errline) + { + $this->setNumber($errno); + $this->setMessage($errstr, false); + $this->setFile($errfile); + $this->setLine($errline); + + $backtrace = debug_backtrace(); + // remove last three calls: + // debug_backtrace(), handleError() and addError() + $backtrace = array_slice($backtrace, 3); + + $this->setBacktrace($backtrace); + } + + /** + * sets PMA_Error::$_backtrace + * + * @param array $backtrace backtrace + * + * @return void + */ + public function setBacktrace($backtrace) + { + $this->backtrace = $backtrace; + } + + /** + * sets PMA_Error::$_line + * + * @param integer $line the line + * + * @return void + */ + public function setLine($line) + { + $this->line = $line; + } + + /** + * sets PMA_Error::$_file + * + * @param string $file the file + * + * @return void + */ + public function setFile($file) + { + $this->file = PMA_Error::relPath($file); + } + + + /** + * returns unique PMA_Error::$hash, if not exists it will be created + * + * @return string PMA_Error::$hash + */ + public function getHash() + { + try { + $backtrace = serialize($this->getBacktrace()); + } catch(Exception $e) { + $backtrace = ''; + } + if ($this->hash === null) { + $this->hash = md5( + $this->getNumber() . + $this->getMessage() . + $this->getFile() . + $this->getLine() . + $backtrace + ); + } + + return $this->hash; + } + + /** + * returns PMA_Error::$_backtrace + * + * @return array PMA_Error::$_backtrace + */ + public function getBacktrace() + { + return $this->backtrace; + } + + /** + * returns PMA_Error::$file + * + * @return string PMA_Error::$file + */ + public function getFile() + { + return $this->file; + } + + /** + * returns PMA_Error::$line + * + * @return integer PMA_Error::$line + */ + public function getLine() + { + return $this->line; + } + + /** + * returns type of error + * + * @return string type of error + */ + public function getType() + { + return PMA_Error::$errortype[$this->getNumber()]; + } + + /** + * returns level of error + * + * @return string level of error + */ + public function getLevel() + { + return PMA_Error::$errorlevel[$this->getNumber()]; + } + + /** + * returns title prepared for HTML Title-Tag + * + * @return string HTML escaped and truncated title + */ + public function getHtmlTitle() + { + return htmlspecialchars(substr($this->getTitle(), 0, 100)); + } + + /** + * returns title for error + * + * @return string + */ + public function getTitle() + { + return $this->getType() . ': ' . $this->getMessage(); + } + + /** + * Get HTML backtrace + * + * @return void + */ + public function getBacktraceDisplay() + { + $retval = ''; + + foreach ($this->getBacktrace() as $step) { + if (isset($step['file']) && isset($step['line'])) { + $retval .= PMA_Error::relPath($step['file']) . '#' . $step['line'] . ': '; + } + if (isset($step['class'])) { + $retval .= $step['class'] . $step['type']; + } + $retval .= $step['function'] . '('; + if (isset($step['args']) && (count($step['args']) > 1)) { + $retval .= "
      \n"; + foreach ($step['args'] as $arg) { + $retval .= "\t"; + $retval .= $this->getArg($arg, $step['function']); + $retval .= ',' . "
      \n"; + } + } elseif (isset($step['args']) && (count($step['args']) > 0)) { + foreach ($step['args'] as $arg) { + $retval .= $this->getArg($arg, $step['function']); + } + } + $retval .= ')' . "
      \n"; + } + + return $retval; + } + + /** + * Get a single function argument + * + * if $function is one of include/require + * the $arg is converted to a relative path + * + * @param string $arg + * @param string $function + * + * @return string + */ + protected function getArg($arg, $function) + { + $retval = ''; + $include_functions = array( + 'include', + 'include_once', + 'require', + 'require_once', + ); + $connect_functions = array( + 'mysql_connect', + 'mysql_pconnect', + 'mysqli_connect', + 'mysqli_real_connect', + 'PMA_DBI_connect', + 'PMA_DBI_real_connect', + ); + + if (in_array($function, $include_functions)) { + $retval .= PMA_Error::relPath($arg); + } elseif (in_array($function, $connect_functions) + && getType($arg) === 'string' + ) { + $retval .= getType($arg) . ' ********'; + } elseif (is_scalar($arg)) { + $retval .= getType($arg) . ' ' . htmlspecialchars($arg); + } else { + $retval .= getType($arg); + } + + return $retval; + } + + /** + * Gets the error as string of HTML + * + * @return string + */ + public function getDisplay() + { + $this->isDisplayed(true); + $retval = '
      '; + if (! $this->isUserError()) { + $retval .= '' . $this->getType() . ''; + $retval .= ' in ' . $this->getFile() . '#' . $this->getLine(); + $retval .= "
      \n"; + } + $retval .= $this->getMessage(); + if (! $this->isUserError()) { + $retval .= "
      \n"; + $retval .= "
      \n"; + $retval .= "Backtrace
      \n"; + $retval .= "
      \n"; + $retval .= $this->getBacktraceDisplay(); + } + $retval .= '
      '; + + return $retval; + } + + /** + * whether this error is a user error + * + * @return boolean + */ + public function isUserError() + { + return $this->getNumber() & (E_USER_WARNING | E_USER_ERROR | E_USER_NOTICE); + } + + /** + * return short relative path to phpMyAdmin basedir + * + * prevent path disclusore in error message, + * and make users feel save to submit error reports + * + * @param string $dest path to be shorten + * + * @return string shortened path + * @static + */ + static function relPath($dest) + { + $dest = realpath($dest); + + if (substr(PHP_OS, 0, 3) == 'WIN') { + $path_separator = '\\'; + } else { + $path_separator = '/'; + } + + $Ahere = explode( + $path_separator, + realpath(dirname(__FILE__) . $path_separator . '..') + ); + $Adest = explode($path_separator, $dest); + + $result = '.'; + // && count ($Adest)>0 && count($Ahere)>0 ) + while (implode($path_separator, $Adest) != implode($path_separator, $Ahere)) { + if (count($Ahere) > count($Adest)) { + array_pop($Ahere); + $result .= $path_separator . '..'; + } else { + array_pop($Adest); + } + } + $path = $result . str_replace(implode($path_separator, $Adest), '', $dest); + return str_replace( + $path_separator . $path_separator, + $path_separator, + $path + ); + } +} +?> diff --git a/phpmyadmin/libraries/Error_Handler.class.php b/phpmyadmin/libraries/Error_Handler.class.php new file mode 100644 index 000000000..799c3fef3 --- /dev/null +++ b/phpmyadmin/libraries/Error_Handler.class.php @@ -0,0 +1,446 @@ +errors + ); + } else { + // remember only not displayed errors + foreach ($this->errors as $key => $error) { + /** + * We don't want to store all errors here as it would + * explode user session. In case you want them all set + * $GLOBALS['cfg']['Error_Handler']['gather'] to true + */ + if (count($_SESSION['errors']) >= 20) { + $error = new PMA_Error( + 0, + __('Too many error messages, some are not displayed.'), + __FILE__, + __LINE__ + ); + $_SESSION['errors'][$error->getHash()] = $error; + break; + } else if (($error instanceof PMA_Error) + && ! $error->isDisplayed() + ) { + $_SESSION['errors'][$key] = $error; + } + } + } + } + } + + /** + * returns array with all errors + * + * @return array PMA_Error_Handler::$_errors + */ + protected function getErrors() + { + $this->checkSavedErrors(); + return $this->errors; + } + + /** + * Error handler - called when errors are triggered/occured + * + * This calls the addError() function, escaping the error string + * + * @param integer $errno error number + * @param string $errstr error string + * @param string $errfile error file + * @param integer $errline error line + * + * @return void + */ + public function handleError($errno, $errstr, $errfile, $errline) + { + $this->addError($errstr, $errno, $errfile, $errline, true); + } + + /** + * Add an error; can also be called directly (with or without escaping) + * + * The following error types cannot be handled with a user defined function: + * E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, + * E_COMPILE_WARNING, + * and most of E_STRICT raised in the file where set_error_handler() is called. + * + * Do not use the context parameter as we want to avoid storing the + * complete $GLOBALS inside $_SESSION['errors'] + * + * @param string $errstr error string + * @param integer $errno error number + * @param string $errfile error file + * @param integer $errline error line + * @param boolean $escape whether to escape the error string + * + * @return void + */ + public function addError($errstr, $errno, $errfile, $errline, $escape = true) + { + if ($escape) { + $errstr = htmlspecialchars($errstr); + } + // create error object + $error = new PMA_Error( + $errno, + $errstr, + $errfile, + $errline + ); + + // do not repeat errors + $this->errors[$error->getHash()] = $error; + + switch ($error->getNumber()) { + case E_USER_NOTICE: + case E_USER_WARNING: + case E_STRICT: + case E_DEPRECATED: + case E_NOTICE: + case E_WARNING: + case E_CORE_WARNING: + case E_COMPILE_WARNING: + case E_USER_ERROR: + case E_RECOVERABLE_ERROR: + // just collect the error + // display is called from outside + break; + case E_ERROR: + case E_PARSE: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + default: + // FATAL error, dislay it and exit + $this->dispFatalError($error); + exit; + break; + } + } + + + /** + * log error to configured log facility + * + * @param PMA_Error $error the error + * + * @return bool + * + * @todo finish! + */ + protected function logError($error) + { + return error_log($error->getMessage()); + } + + /** + * trigger a custom error + * + * @param string $errorInfo error message + * @param integer $errorNumber error number + * @param string $file file name + * @param integer $line line number + * + * @return void + */ + public function triggerError($errorInfo, $errorNumber = null, + $file = null, $line = null + ) { + // we could also extract file and line from backtrace + // and call handleError() directly + trigger_error($errorInfo, $errorNumber); + } + + /** + * display fatal error and exit + * + * @param PMA_Error $error the error + * + * @return void + */ + protected function dispFatalError($error) + { + if (! headers_sent()) { + $this->dispPageStart($error); + } + $error->display(); + $this->dispPageEnd(); + exit; + } + + /** + * display the whole error page with all errors + * + * @return void + */ + public function dispErrorPage() + { + if (! headers_sent()) { + $this->dispPageStart(); + } + $this->dispAllErrors(); + $this->dispPageEnd(); + } + + /** + * Displays user errors not displayed + * + * @return void + */ + public function dispUserErrors() + { + echo $this->getDispUserErrors(); + } + + /** + * Renders user errors not displayed + * + * @return string + */ + public function getDispUserErrors() + { + $retval = ''; + foreach ($this->getErrors() as $error) { + if ($error->isUserError() && ! $error->isDisplayed()) { + $retval .= $error->getDisplay(); + } + } + return $retval; + } + + /** + * display HTML header + * + * @param PMA_error $error the error + * + * @return void + */ + protected function dispPageStart($error = null) + { + PMA_Response::getInstance()->disable(); + echo ''; + if ($error) { + echo $error->getTitle(); + } else { + echo 'phpMyAdmin error reporting page'; + } + echo ''; + } + + /** + * display HTML footer + * + * @return void + */ + protected function dispPageEnd() + { + echo ''; + } + + /** + * display all errors regardless already displayed or user errors + * + * @return void + */ + public function dispAllErrors() + { + foreach ($this->getErrors() as $error) { + $error->display(); + } + } + + /** + * renders errors not displayed + * + * @return void + */ + public function getDispErrors() + { + $retval = ''; + if ($GLOBALS['cfg']['Error_Handler']['display']) { + foreach ($this->getErrors() as $error) { + if ($error instanceof PMA_Error) { + if (! $error->isDisplayed()) { + $retval .= $error->getDisplay(); + } + } else { + ob_start(); + var_dump($error); + $retval .= ob_get_contents(); + ob_end_clean(); + } + } + } else { + $retval .= $this->getDispUserErrors(); + } + return $retval; + } + + /** + * displays errors not displayed + * + * @return void + */ + public function dispErrors() + { + echo $this->getDispErrors(); + } + + /** + * look in session for saved errors + * + * @return void + */ + protected function checkSavedErrors() + { + if (isset($_SESSION['errors'])) { + + // restore saved errors + foreach ($_SESSION['errors'] as $hash => $error) { + if ($error instanceof PMA_Error && ! isset($this->errors[$hash])) { + $this->errors[$hash] = $error; + } + } + //$this->errors = array_merge($_SESSION['errors'], $this->errors); + + // delete stored errors + $_SESSION['errors'] = array(); + unset($_SESSION['errors']); + } + } + + /** + * return count of errors + * + * @return integer number of errors occoured + */ + public function countErrors() + { + return count($this->getErrors()); + } + + /** + * return count of user errors + * + * @return integer number of user errors occoured + */ + public function countUserErrors() + { + $count = 0; + if ($this->countErrors()) { + foreach ($this->getErrors() as $error) { + if ($error->isUserError()) { + $count++; + } + } + } + + return $count; + } + + /** + * whether use errors occured or not + * + * @return boolean + */ + public function hasUserErrors() + { + return (bool) $this->countUserErrors(); + } + + /** + * whether errors occured or not + * + * @return boolean + */ + public function hasErrors() + { + return (bool) $this->countErrors(); + } + + /** + * number of errors to be displayed + * + * @return integer number of errors to be displayed + */ + public function countDisplayErrors() + { + if ($GLOBALS['cfg']['Error_Handler']['display']) { + return $this->countErrors(); + } else { + return $this->countUserErrors(); + } + } + + /** + * whether there are errors to display or not + * + * @return boolean + */ + public function hasDisplayErrors() + { + return (bool) $this->countDisplayErrors(); + } +} +?> diff --git a/phpmyadmin/libraries/File.class.php b/phpmyadmin/libraries/File.class.php new file mode 100644 index 000000000..62b87637c --- /dev/null +++ b/phpmyadmin/libraries/File.class.php @@ -0,0 +1,863 @@ +setName($name); + } + } + + /** + * destructor + * + * @see PMA_File::cleanUp() + * @access public + */ + public function __destruct() + { + $this->cleanUp(); + } + + /** + * deletes file if it is temporary, usally from a moved upload file + * + * @access public + * @return boolean success + */ + public function cleanUp() + { + if ($this->isTemp()) { + return $this->delete(); + } + + return true; + } + + /** + * deletes the file + * + * @access public + * @return boolean success + */ + public function delete() + { + return unlink($this->getName()); + } + + /** + * checks or sets the temp flag for this file + * file objects with temp flags are deleted with object destruction + * + * @param boolean $is_temp sets the temp flag + * + * @return boolean PMA_File::$_is_temp + * @access public + */ + public function isTemp($is_temp = null) + { + if (null !== $is_temp) { + $this->_is_temp = (bool) $is_temp; + } + + return $this->_is_temp; + } + + /** + * accessor + * + * @param string $name file name + * + * @return void + * @access public + */ + public function setName($name) + { + $this->_name = trim($name); + } + + /** + * Gets file content + * + * @param boolean $as_binary whether to return content as binary + * @param integer $offset starting offset + * @param integer $length length + * + * @return mixed the binary file content as a string, + * or false if no content + * + * @access public + */ + public function getContent($as_binary = true, $offset = 0, $length = null) + { + if (null === $this->_content) { + if ($this->isUploaded() && ! $this->checkUploadedFile()) { + return false; + } + + if (! $this->isReadable()) { + return false; + } + + if (function_exists('file_get_contents')) { + $this->_content = file_get_contents($this->getName()); + } elseif ($size = filesize($this->getName())) { + $this->_content = fread(fopen($this->getName(), 'rb'), $size); + } + } + + if (! empty($this->_content) && $as_binary) { + return '0x' . bin2hex($this->_content); + } + + if (null !== $length) { + return substr($this->_content, $offset, $length); + } elseif ($offset > 0) { + return substr($this->_content, $offset); + } + + return $this->_content; + } + + /** + * Whether file is uploaded. + * + * @access public + * + * @return bool + */ + public function isUploaded() + { + return is_uploaded_file($this->getName()); + } + + /** + * accessor + * + * @access public + * @return string PMA_File::$_name + */ + public function getName() + { + return $this->_name; + } + + /** + * Initializes object from uploaded file. + * + * @param string $name name of file uploaded + * + * @return boolean success + * @access public + */ + public function setUploadedFile($name) + { + $this->setName($name); + + if (! $this->isUploaded()) { + $this->setName(null); + $this->_error_message = __('File was not an uploaded file.'); + return false; + } + + return true; + } + + /** + * Loads uploaded file from table change request. + * + * @param string $key the md5 hash of the column name + * @param string $rownumber + * + * @return boolean success + * @access public + */ + public function setUploadedFromTblChangeRequest($key, $rownumber) + { + if (! isset($_FILES['fields_upload']) + || empty($_FILES['fields_upload']['name']['multi_edit'][$rownumber][$key]) + ) { + return false; + } + $file = PMA_File::fetchUploadedFromTblChangeRequestMultiple( + $_FILES['fields_upload'], + $rownumber, + $key + ); + + // check for file upload errors + switch ($file['error']) { + // we do not use the PHP constants here cause not all constants + // are defined in all versions of PHP - but the correct constants names + // are given as comment + case 0: //UPLOAD_ERR_OK: + return $this->setUploadedFile($file['tmp_name']); + break; + case 4: //UPLOAD_ERR_NO_FILE: + break; + case 1: //UPLOAD_ERR_INI_SIZE: + $this->_error_message = __('The uploaded file exceeds the upload_max_filesize directive in php.ini.'); + break; + case 2: //UPLOAD_ERR_FORM_SIZE: + $this->_error_message = __('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.'); + break; + case 3: //UPLOAD_ERR_PARTIAL: + $this->_error_message = __('The uploaded file was only partially uploaded.'); + break; + case 6: //UPLOAD_ERR_NO_TMP_DIR: + $this->_error_message = __('Missing a temporary folder.'); + break; + case 7: //UPLOAD_ERR_CANT_WRITE: + $this->_error_message = __('Failed to write file to disk.'); + break; + case 8: //UPLOAD_ERR_EXTENSION: + $this->_error_message = __('File upload stopped by extension.'); + break; + default: + $this->_error_message = __('Unknown error in file upload.'); + } // end switch + + return false; + } + + /** + * strips some dimension from the multi-dimensional array from $_FILES + * + * + * $file['name']['multi_edit'][$rownumber][$key] = [value] + * $file['type']['multi_edit'][$rownumber][$key] = [value] + * $file['size']['multi_edit'][$rownumber][$key] = [value] + * $file['tmp_name']['multi_edit'][$rownumber][$key] = [value] + * $file['error']['multi_edit'][$rownumber][$key] = [value] + * + * // becomes: + * + * $file['name'] = [value] + * $file['type'] = [value] + * $file['size'] = [value] + * $file['tmp_name'] = [value] + * $file['error'] = [value] + * + * + * @param array $file the array + * @param string $rownumber + * @param string $key + * + * @return array + * @access public + * @static + */ + public function fetchUploadedFromTblChangeRequestMultiple($file, $rownumber, $key) + { + $new_file = array( + 'name' => $file['name']['multi_edit'][$rownumber][$key], + 'type' => $file['type']['multi_edit'][$rownumber][$key], + 'size' => $file['size']['multi_edit'][$rownumber][$key], + 'tmp_name' => $file['tmp_name']['multi_edit'][$rownumber][$key], + 'error' => $file['error']['multi_edit'][$rownumber][$key], + ); + + return $new_file; + } + + /** + * sets the name if the file to the one selected in the tbl_change form + * + * @param string $key the md5 hash of the column name + * @param string $rownumber + * + * @return boolean success + * @access public + */ + public function setSelectedFromTblChangeRequest($key, $rownumber = null) + { + if (! empty($_REQUEST['fields_uploadlocal']['multi_edit'][$rownumber][$key]) + && is_string($_REQUEST['fields_uploadlocal']['multi_edit'][$rownumber][$key]) + ) { + // ... whether with multiple rows ... + return $this->setLocalSelectedFile( + $_REQUEST['fields_uploadlocal']['multi_edit'][$rownumber][$key] + ); + } else { + return false; + } + } + + /** + * Returns possible error message. + * + * @access public + * @return string error message + */ + public function getError() + { + return $this->_error_message; + } + + /** + * Checks whether there was any error. + * + * @access public + * @return boolean whether an error occured or not + */ + public function isError() + { + return ! empty($this->_error_message); + } + + /** + * checks the superglobals provided if the tbl_change form is submitted + * and uses the submitted/selected file + * + * @param string $key the md5 hash of the column name + * @param string $rownumber + * + * @return boolean success + * @access public + */ + public function checkTblChangeForm($key, $rownumber) + { + if ($this->setUploadedFromTblChangeRequest($key, $rownumber)) { + // well done ... + $this->_error_message = ''; + return true; + } elseif ($this->setSelectedFromTblChangeRequest($key, $rownumber)) { + // well done ... + $this->_error_message = ''; + return true; + } + // all failed, whether just no file uploaded/selected or an error + + return false; + } + + /** + * Sets named file to be read from UploadDir. + * + * @param string $name file name + * + * @return boolean success + * @access public + */ + public function setLocalSelectedFile($name) + { + if (empty($GLOBALS['cfg']['UploadDir'])) { + return false; + } + + $this->setName( + PMA_Util::userDir($GLOBALS['cfg']['UploadDir']) . PMA_securePath($name) + ); + if (! $this->isReadable()) { + $this->_error_message = __('File could not be read'); + $this->setName(null); + return false; + } + + return true; + } + + /** + * Checks whether file can be read. + * + * @access public + * @return boolean whether the file is readable or not + */ + public function isReadable() + { + // suppress warnings from being displayed, but not from being logged + // any file access outside of open_basedir will issue a warning + ob_start(); + $is_readable = is_readable($this->getName()); + ob_end_clean(); + return $is_readable; + } + + /** + * If we are on a server with open_basedir, we must move the file + * before opening it. The FAQ 1.11 explains how to create the "./tmp" + * directory - if needed + * + * @todo move check of $cfg['TempDir'] into PMA_Config? + * @access public + * @return boolean whether uploaded fiel is fine or not + */ + public function checkUploadedFile() + { + if ($this->isReadable()) { + return true; + } + + if (empty($GLOBALS['cfg']['TempDir']) + || ! is_writable($GLOBALS['cfg']['TempDir']) + ) { + // cannot create directory or access, point user to FAQ 1.11 + $this->_error_message = __('Error moving the uploaded file, see [doc@faq1-11]FAQ 1.11[/doc]'); + return false; + } + + $new_file_to_upload = tempnam( + realpath($GLOBALS['cfg']['TempDir']), + basename($this->getName()) + ); + + // suppress warnings from being displayed, but not from being logged + // any file access outside of open_basedir will issue a warning + ob_start(); + $move_uploaded_file_result = move_uploaded_file( + $this->getName(), + $new_file_to_upload + ); + ob_end_clean(); + if (! $move_uploaded_file_result) { + $this->_error_message = __('Error while moving uploaded file.'); + return false; + } + + $this->setName($new_file_to_upload); + $this->isTemp(true); + + if (! $this->isReadable()) { + $this->_error_message = __('Cannot read (moved) upload file.'); + return false; + } + + return true; + } + + /** + * Detects what compression filse uses + * + * @todo move file read part into readChunk() or getChunk() + * @todo add support for compression plugins + * @access protected + * @return string MIME type of compression, none for none + */ + protected function detectCompression() + { + // suppress warnings from being displayed, but not from being logged + // f.e. any file access outside of open_basedir will issue a warning + ob_start(); + $file = fopen($this->getName(), 'rb'); + ob_end_clean(); + + if (! $file) { + $this->_error_message = __('File could not be read'); + return false; + } + + /** + * @todo + * get registered plugins for file compression + + foreach (PMA_getPlugins($type = 'compression') as $plugin) { + if (call_user_func_array(array($plugin['classname'], 'canHandle'), array($this->getName()))) { + $this->setCompressionPlugin($plugin); + break; + } + } + */ + + $test = fread($file, 4); + $len = strlen($test); + fclose($file); + + if ($len >= 2 && $test[0] == chr(31) && $test[1] == chr(139)) { + $this->_compression = 'application/gzip'; + } elseif ($len >= 3 && substr($test, 0, 3) == 'BZh') { + $this->_compression = 'application/bzip2'; + } elseif ($len >= 4 && $test == "PK\003\004") { + $this->_compression = 'application/zip'; + } else { + $this->_compression = 'none'; + } + + return $this->_compression; + } + + /** + * Sets whether the content should be decompressed before returned + * + * @param boolean $decompress whether to decompres + * + * @return void + */ + public function setDecompressContent($decompress) + { + $this->_decompress = (bool) $decompress; + } + + /** + * Returns the file handle + * + * @return object file handle + */ + public function getHandle() + { + if (null === $this->_handle) { + $this->open(); + } + return $this->_handle; + } + + /** + * Sets the file handle + * + * @param object $handle file handle + * + * @return void + */ + public function setHandle($handle) + { + $this->_handle = $handle; + } + + + /** + * Sets error message for unsupported compression. + * + * @return void + */ + public function errorUnsupported() + { + $this->_error_message = sprintf( + __('You attempted to load file with unsupported compression (%s). Either support for it is not implemented or disabled by your configuration.'), + $this->getCompression() + ); + } + + /** + * Attempts to open the file. + * + * @return bool + */ + public function open() + { + if (! $this->_decompress) { + $this->_handle = @fopen($this->getName(), 'r'); + } + + switch ($this->getCompression()) { + case false: + return false; + case 'application/bzip2': + if ($GLOBALS['cfg']['BZipDump'] && @function_exists('bzopen')) { + $this->_handle = @bzopen($this->getName(), 'r'); + } else { + $this->errorUnsupported(); + return false; + } + break; + case 'application/gzip': + if ($GLOBALS['cfg']['GZipDump'] && @function_exists('gzopen')) { + $this->_handle = @gzopen($this->getName(), 'r'); + } else { + $this->errorUnsupported(); + return false; + } + break; + case 'application/zip': + if ($GLOBALS['cfg']['ZipDump'] && @function_exists('zip_open')) { + include_once './libraries/zip_extension.lib.php'; + $result = PMA_getZipContents($this->getName()); + if (! empty($result['error'])) { + $this->_error_message = PMA_Message::rawError($result['error']); + return false; + } else { + $this->content_uncompressed = $result['data']; + } + unset($result); + } else { + $this->errorUnsupported(); + return false; + } + break; + case 'none': + $this->_handle = @fopen($this->getName(), 'r'); + break; + default: + $this->errorUnsupported(); + return false; + break; + } + + return true; + } + + /** + * Returns the character set of the file + * + * @return string character set of the file + */ + public function getCharset() + { + return $this->_charset; + } + + /** + * Sets the character set of the file + * + * @param string $charset character set of the file + * + * @return void + */ + public function setCharset($charset) + { + $this->_charset = $charset; + } + + /** + * Returns compression used by file. + * + * @return string MIME type of compression, none for none + * @access public + */ + public function getCompression() + { + if (null === $this->_compression) { + return $this->detectCompression(); + } + + return $this->_compression; + } + + /** + * advances the file pointer in the file handle by $length bytes/chars + * + * @param integer $length numbers of chars/bytes to skip + * + * @return boolean + * @todo this function is unused + */ + public function advanceFilePointer($length) + { + while ($length > 0) { + $this->getNextChunk($length); + $length -= $this->getChunkSize(); + } + } + + /** + * http://bugs.php.net/bug.php?id=29532 + * bzip reads a maximum of 8192 bytes on windows systems + * + * @param int $max_size maximum size of the next chunk to be returned + * + * @return bool|string + * @todo this function is unused + */ + public function getNextChunk($max_size = null) + { + if (null !== $max_size) { + $size = min($max_size, $this->getChunkSize()); + } else { + $size = $this->getChunkSize(); + } + + // $result = $this->handler->getNextChunk($size); + $result = ''; + switch ($this->getCompression()) { + case 'application/bzip2': + $result = ''; + while (strlen($result) < $size - 8192 && ! feof($this->getHandle())) { + $result .= bzread($this->getHandle(), $size); + } + break; + case 'application/gzip': + $result = gzread($this->getHandle(), $size); + break; + case 'application/zip': + /* + * if getNextChunk() is used some day, + * replace this code by code similar to the one + * in open() + * + include_once './libraries/unzip.lib.php'; + $import_handle = new SimpleUnzip(); + $import_handle->ReadFile($this->getName()); + if ($import_handle->Count() == 0) { + $this->_error_message = __('No files found inside ZIP archive!'); + return false; + } elseif ($import_handle->GetError(0) != 0) { + $this->_error_message = __('Error in ZIP archive:') + . ' ' . $import_handle->GetErrorMsg(0); + return false; + } else { + $result = $import_handle->GetData(0); + } + */ + break; + case 'none': + $result = fread($this->getHandle(), $size); + break; + default: + return false; + } + + if ($GLOBALS['charset_conversion']) { + $result = PMA_convert_string($this->getCharset(), 'utf-8', $result); + } else { + /** + * Skip possible byte order marks (I do not think we need more + * charsets, but feel free to add more, you can use wikipedia for + * reference: ) + * + * @todo BOM could be used for charset autodetection + */ + if ($this->getOffset() === 0) { + // UTF-8 + if (strncmp($result, "\xEF\xBB\xBF", 3) == 0) { + $result = substr($result, 3); + // UTF-16 BE, LE + } elseif (strncmp($result, "\xFE\xFF", 2) == 0 + || strncmp($result, "\xFF\xFE", 2) == 0) { + $result = substr($result, 2); + } + } + } + + $this->_offset += $size; + if (0 === $result) { + return true; + } + return $result; + } + + /** + * Returns the offset + * + * @return integer the offset + */ + public function getOffset() + { + return $this->_offset; + } + + /** + * Returns the chunk size + * + * @return integer the chunk size + */ + public function getChunkSize() + { + return $this->_chunk_size; + } + + /** + * Sets the chunk size + * + * @param integer $chunk_size the chunk size + * + * @return void + */ + public function setChunkSize($chunk_size) + { + $this->_chunk_size = (int) $chunk_size; + } + + /** + * Returns the length of the content in the file + * + * @return integer the length of the file content + */ + public function getContentLength() + { + return strlen($this->_content); + } + + /** + * Returns whether the end of the file has been reached + * + * @return boolean whether the end of the file has been reached + */ + public function eof() + { + if ($this->getHandle()) { + return feof($this->getHandle()); + } else { + return ($this->getOffset() >= $this->getContentLength()); + } + + } +} +?> diff --git a/phpmyadmin/libraries/Footer.class.php b/phpmyadmin/libraries/Footer.class.php new file mode 100644 index 000000000..a0d14ad52 --- /dev/null +++ b/phpmyadmin/libraries/Footer.class.php @@ -0,0 +1,283 @@ +_isEnabled = true; + $this->_scripts = new PMA_Scripts(); + $this->_isMinimal = false; + } + + /** + * Renders the debug messages + * + * @return string + */ + private function _getDebugMessage() + { + $retval = ''; + if (! empty($_SESSION['debug'])) { + $sum_time = 0; + $sum_exec = 0; + foreach ($_SESSION['debug']['queries'] as $query) { + $sum_time += $query['count'] * $query['time']; + $sum_exec += $query['count']; + } + + $retval .= '
      '; + $retval .= count($_SESSION['debug']['queries']) . ' queries executed '; + $retval .= $sum_exec . ' times in ' . $sum_time . ' seconds'; + $retval .= '
      ';
      +
      +            ob_start();
      +            print_r($_SESSION['debug']);
      +            $retval .= ob_get_contents();
      +            ob_end_clean();
      +
      +            $retval .= '
      '; + $retval .= '
      '; + $_SESSION['debug'] = array(); + } + return $retval; + } + + /** + * Returns the url of the current page + * + * @param mixed $encoding See PMA_generate_common_url() + * + * @return string + */ + public function getSelfUrl($encoding = null) + { + $db = ! empty($GLOBALS['db']) ? $GLOBALS['db'] : ''; + $table = ! empty($GLOBALS['table']) ? $GLOBALS['table'] : ''; + $target = ! empty($_REQUEST['target']) ? $_REQUEST['target'] : ''; + return basename(PMA_getenv('SCRIPT_NAME')) . PMA_generate_common_url( + array( + 'db' => $db, + 'table' => $table, + 'server' => $GLOBALS['server'], + 'target' => $target + ), + $encoding + ); + } + + /** + * Renders the link to open a new page + * + * @param string $url The url of the page + * + * @return string + */ + private function _getSelfLink($url) + { + $retval = ''; + $retval .= ''; + return $retval; + } + + /** + * Renders the link to open a new page + * + * @return string + */ + public function getErrorMessages() + { + $retval = ''; + if ($GLOBALS['error_handler']->hasDisplayErrors()) { + $retval .= '
      '; + $retval .= $GLOBALS['error_handler']->getDispErrors(); + $retval .= '
      '; + } + return $retval; + } + + /** + * Saves query in history + * + * @return void + */ + private function _setHistory() + { + if (! PMA_isValid($_REQUEST['no_history']) + && empty($GLOBALS['error_message']) + && ! empty($GLOBALS['sql_query']) + ) { + PMA_setHistory( + PMA_ifSetOr($GLOBALS['db'], ''), + PMA_ifSetOr($GLOBALS['table'], ''), + $GLOBALS['cfg']['Server']['user'], + $GLOBALS['sql_query'] + ); + } + } + + /** + * Disables the rendering of the footer + * + * @return void + */ + public function disable() + { + $this->_isEnabled = false; + } + + /** + * Set the ajax flag to indicate whether + * we are sevicing an ajax request + * + * @param bool $isAjax Whether we are sevicing an ajax request + * + * @return void + */ + public function setAjax($isAjax) + { + $this->_isAjax = ($isAjax == true); + } + + /** + * Turn on minimal display mode + * + * @return void + */ + public function setMinimal() + { + $this->_isMinimal = true; + } + + /** + * Returns the PMA_Scripts object + * + * @return PMA_Scripts object + */ + public function getScripts() + { + return $this->_scripts; + } + + /** + * Renders the footer + * + * @return string + */ + public function getDisplay() + { + $retval = ''; + $this->_setHistory(); + if ($this->_isEnabled) { + if (! $this->_isAjax) { + $retval .= "
      "; + } + if (! $this->_isAjax && ! $this->_isMinimal) { + if (PMA_getenv('SCRIPT_NAME') + && empty($_POST) + && empty($GLOBALS['checked_special']) + && ! $this->_isAjax + ) { + $url = $this->getSelfUrl('unencoded'); + $header = PMA_Response::getInstance()->getHeader(); + $scripts = $header->getScripts()->getFiles(); + $menuHash = $header->getMenu()->getHash(); + // prime the client-side cache + $this->_scripts->addCode( + sprintf( + 'AJAX.cache.primer = {' + . ' url: "%s",' + . ' scripts: %s,' + . ' menuHash: "%s"' + . '};', + PMA_escapeJsString($url), + json_encode($scripts), + PMA_escapeJsString($menuHash) + ) + ); + $url = $this->getSelfUrl(); + $retval .= $this->_getSelfLink($url); + } + $retval .= $this->_getDebugMessage(); + $retval .= $this->getErrorMessages(); + $retval .= $this->_scripts->getDisplay(); + // Include possible custom footers + if (file_exists(CUSTOM_FOOTER_FILE)) { + ob_start(); + include CUSTOM_FOOTER_FILE; + $retval .= ob_get_contents(); + ob_end_clean(); + } + } + if (! $this->_isAjax) { + $retval .= ""; + } + } + + return $retval; + } +} diff --git a/phpmyadmin/libraries/Header.class.php b/phpmyadmin/libraries/Header.class.php new file mode 100644 index 000000000..1a934c6c4 --- /dev/null +++ b/phpmyadmin/libraries/Header.class.php @@ -0,0 +1,660 @@ +_isEnabled = true; + $this->_isAjax = false; + $this->_bodyId = ''; + $this->_title = ''; + $db = ! empty($GLOBALS['db']) ? $GLOBALS['db'] : ''; + $table = ! empty($GLOBALS['table']) ? $GLOBALS['table'] : ''; + $this->_menu = new PMA_Menu( + $GLOBALS['server'], + $db, + $table + ); + $this->_menuEnabled = true; + $this->_warningsEnabled = true; + $this->_isPrintView = false; + $this->_scripts = new PMA_Scripts(); + $this->_addDefaultScripts(); + $this->_headerIsSent = false; + // if database storage for user preferences is transient, + // offer to load exported settings from localStorage + // (detection will be done in JavaScript) + $this->_userprefsOfferImport = false; + if ($GLOBALS['PMA_Config']->get('user_preferences') == 'session' + && ! isset($_SESSION['userprefs_autoload']) + ) { + $this->_userprefsOfferImport = true; + } + } + + /** + * Loads common scripts + * + * @return void + */ + private function _addDefaultScripts() + { + $this->_scripts->addFile('jquery/jquery-1.8.3.js'); + $this->_scripts->addFile('ajax.js'); + $this->_scripts->addFile('keyhandler.js'); + $this->_scripts->addFile('jquery/jquery-ui-1.9.2.custom.js'); + $this->_scripts->addFile('jquery/jquery.sprintf.js'); + $this->_scripts->addFile('jquery/jquery.cookie.js'); + $this->_scripts->addFile('jquery/jquery.mousewheel.js'); + $this->_scripts->addFile('jquery/jquery.event.drag-2.2.js'); + $this->_scripts->addFile('jquery/jquery-ui-timepicker-addon.js'); + $this->_scripts->addFile('jquery/jquery.ba-hashchange-1.3.js'); + $this->_scripts->addFile('jquery/jquery.debounce-1.0.5.js'); + $this->_scripts->addFile('jquery/jquery.menuResizer-1.0.js'); + $this->_scripts->addFile('rte.js'); + + // Here would not be a good place to add CodeMirror because + // the user preferences have not been merged at this point + + // Localised strings + $params = array('lang' => $GLOBALS['lang']); + if (isset($GLOBALS['db'])) { + $params['db'] = $GLOBALS['db']; + } + $this->_scripts->addFile('messages.php' . PMA_generate_common_url($params)); + // Append the theme id to this url to invalidate + // the cache on a theme change. Though this might be + // unavailable for fatal errors. + if (isset($_SESSION['PMA_Theme'])) { + $theme_id = urlencode($_SESSION['PMA_Theme']->getId()); + } else { + $theme_id = 'default'; + } + $this->_scripts->addFile( + 'get_image.js.php?theme=' . $theme_id + ); + $this->_scripts->addFile('functions.js'); + $this->_scripts->addFile('navigation.js'); + $this->_scripts->addFile('indexes.js'); + $this->_scripts->addFile('common.js'); + $this->_scripts->addCode($this->getJsParamsCode()); + } + + /** + * Returns, as an array, a list of parameters + * used on the client side + * + * @return array + */ + public function getJsParams() + { + $db = ! empty($GLOBALS['db']) ? $GLOBALS['db'] : ''; + $table = ! empty($GLOBALS['table']) ? $GLOBALS['table'] : ''; + return array( + 'common_query' => PMA_generate_common_url('', '', '&'), + 'opendb_url' => $GLOBALS['cfg']['DefaultTabDatabase'], + 'safari_browser' => PMA_USR_BROWSER_AGENT == 'SAFARI' ? 1 : 0, + 'querywindow_height' => $GLOBALS['cfg']['QueryWindowHeight'], + 'querywindow_width' => $GLOBALS['cfg']['QueryWindowWidth'], + 'collation_connection' => $GLOBALS['collation_connection'], + 'lang' => $GLOBALS['lang'], + 'server' => $GLOBALS['server'], + 'table' => $table, + 'db' => $db, + 'token' => $_SESSION[' PMA_token '], + 'text_dir' => $GLOBALS['text_dir'], + 'pma_absolute_uri' => $GLOBALS['cfg']['PmaAbsoluteUri'], + 'pma_text_default_tab' => PMA_Util::getTitleForTarget( + $GLOBALS['cfg']['DefaultTabTable'] + ), + 'pma_text_left_default_tab' => PMA_Util::getTitleForTarget( + $GLOBALS['cfg']['NavigationTreeDefaultTabTable'] + ), + 'confirm' => $GLOBALS['cfg']['Confirm'] + ); + } + + /** + * Returns, as a string, a list of parameters + * used on the client side + * + * @return string + */ + public function getJsParamsCode() + { + $params = $this->getJsParams(); + foreach ($params as $key => $value) { + $params[$key] = $key . ':"' . PMA_escapeJsString($value) . '"'; + } + return 'PMA_commonParams.setAll({' . implode(',', $params) . '});'; + } + + /** + * Disables the rendering of the header + * + * @return void + */ + public function disable() + { + $this->_isEnabled = false; + } + + /** + * Set the ajax flag to indicate whether + * we are sevicing an ajax request + * + * @param bool $isAjax Whether we are sevicing an ajax request + * + * @return void + */ + public function setAjax($isAjax) + { + $this->_isAjax = ($isAjax == true); + } + + /** + * Returns the PMA_Scripts object + * + * @return PMA_Scripts object + */ + public function getScripts() + { + return $this->_scripts; + } + + /** + * Returns the PMA_Menu object + * + * @return PMA_Menu object + */ + public function getMenu() + { + return $this->_menu; + } + + /** + * Setter for the ID attribute in the BODY tag + * + * @param string $id Value for the ID attribute + * + * @return void + */ + public function setBodyId($id) + { + $this->_bodyId = htmlspecialchars($id); + } + + /** + * Setter for the title of the page + * + * @param string $title New title + * + * @return void + */ + public function setTitle($title) + { + $this->_title = htmlspecialchars($title); + } + + /** + * Disables the display of the top menu + * + * @return void + */ + public function disableMenu() + { + $this->_menuEnabled = false; + } + + /** + * Disables the display of the top menu + * + * @return void + */ + public function disableWarnings() + { + $this->_warningsEnabled = false; + } + + /** + * Turns on 'print view' mode + * + * @return void + */ + public function enablePrintView() + { + $this->disableMenu(); + $this->setTitle(__('Print view') . ' - phpMyAdmin ' . PMA_VERSION); + $this->_isPrintView = true; + } + + /** + * Generates the header + * + * @return string The header + */ + public function getDisplay() + { + $retval = ''; + if (! $this->_headerIsSent) { + if (! $this->_isAjax && $this->_isEnabled) { + $this->sendHttpHeaders(); + $retval .= $this->_getHtmlStart(); + $retval .= $this->_getMetaTags(); + $retval .= $this->_getLinkTags(); + $retval .= $this->getTitleTag(); + + // The user preferences have been merged at this point + // so we can conditionally add CodeMirror + if ($GLOBALS['cfg']['CodemirrorEnable']) { + $this->_scripts->addFile('codemirror/lib/codemirror.js'); + $this->_scripts->addFile('codemirror/mode/mysql/mysql.js'); + } + if ($this->_userprefsOfferImport) { + $this->_scripts->addFile('config.js'); + } + $retval .= $this->_scripts->getDisplay(); + $retval .= $this->_getBodyStart(); + if ($this->_menuEnabled && $GLOBALS['server'] > 0) { + $nav = new PMA_Navigation(); + $retval .= $nav->getDisplay(); + } + // Include possible custom headers + if (file_exists(CUSTOM_HEADER_FILE)) { + ob_start(); + include CUSTOM_HEADER_FILE; + $retval .= ob_get_contents(); + ob_end_clean(); + } + // offer to load user preferences from localStorage + if ($this->_userprefsOfferImport) { + include_once './libraries/user_preferences.lib.php'; + $retval .= PMA_userprefsAutoloadGetHeader(); + } + // pass configuration for hint tooltip display + // (to be used by PMA_tooltip() in js/functions.js) + if (! $GLOBALS['cfg']['ShowHint']) { + $retval .= ''; + } + $retval .= $this->_getWarnings(); + if ($this->_menuEnabled && $GLOBALS['server'] > 0) { + $retval .= $this->_menu->getDisplay(); + $pagetop_link = '%s'; + $retval .= sprintf( + $pagetop_link, + __('Click on the bar to scroll to top of page'), + PMA_Util::getImage('s_top.png') + ); + } + $retval .= '
      '; + $retval .= $this->getMessage(); + } + if ($this->_isEnabled && empty($_REQUEST['recent_table'])) { + $retval .= $this->_addRecentTable( + $GLOBALS['db'], + $GLOBALS['table'] + ); + } + } + return $retval; + } + + /** + * Returns the message to be displayed at the top of + * the page, including the executed SQL query, if any. + * + * @return string + */ + public function getMessage() + { + $retval = ''; + $message = ''; + if (! empty($GLOBALS['message'])) { + $message = $GLOBALS['message']; + unset($GLOBALS['message']); + } else if (! empty($_REQUEST['message'])) { + $message = $_REQUEST['message']; + } + if (! empty($message)) { + if (isset($GLOBALS['buffer_message'])) { + $buffer_message = $GLOBALS['buffer_message']; + } + $retval .= PMA_Util::getMessage($message); + if (isset($buffer_message)) { + $GLOBALS['buffer_message'] = $buffer_message; + } + } + return $retval; + } + + /** + * Sends out the HTTP headers + * + * @return void + */ + public function sendHttpHeaders() + { + $https = $GLOBALS['PMA_Config']->isHttps(); + $mapTilesUrls = ' *.tile.openstreetmap.org *.tile.opencyclemap.org'; + + /** + * Sends http headers + */ + $GLOBALS['now'] = gmdate('D, d M Y H:i:s') . ' GMT'; + if (! defined('TESTSUITE')) { + header( + "X-Content-Security-Policy: default-src 'self' " + . $GLOBALS['cfg']['CSPAllow'] . ';' + . "options inline-script eval-script;" + . "img-src 'self' data: " + . $GLOBALS['cfg']['CSPAllow'] + . ($https ? "" : $mapTilesUrls) + . ";" + ); + if (PMA_USR_BROWSER_AGENT == 'SAFARI' + && PMA_USR_BROWSER_VER < '6.0.0' + ) { + header( + "X-WebKit-CSP: allow 'self' " + . $GLOBALS['cfg']['CSPAllow'] . ';' + . "options inline-script eval-script;" + . "img-src 'self' data: " + . $GLOBALS['cfg']['CSPAllow'] + . ($https ? "" : $mapTilesUrls) + . ";" + ); + } else { + header( + "X-WebKit-CSP: default-src 'self' " + . $GLOBALS['cfg']['CSPAllow'] . ';' + . "script-src 'self' " + . $GLOBALS['cfg']['CSPAllow'] + . " 'unsafe-inline' 'unsafe-eval';" + . "style-src 'self' 'unsafe-inline';" + . "img-src 'self' data: " + . $GLOBALS['cfg']['CSPAllow'] + . ($https ? "" : $mapTilesUrls) + . ";" + ); + } + } + PMA_noCacheHeader(); + if (! defined('IS_TRANSFORMATION_WRAPPER') && ! defined('TESTSUITE')) { + // Define the charset to be used + header('Content-Type: text/html; charset=utf-8'); + } + $this->_headerIsSent = true; + } + + /** + * Returns the DOCTYPE and the start HTML tag + * + * @return string DOCTYPE and HTML tags + */ + private function _getHtmlStart() + { + $lang = $GLOBALS['available_languages'][$GLOBALS['lang']][1]; + $dir = $GLOBALS['text_dir']; + + $retval = ""; + $retval .= ""; + + return $retval; + } + + /** + * Returns the META tags + * + * @return string the META tags + */ + private function _getMetaTags() + { + $retval = ''; + $retval .= ''; + $retval .= ''; + return $retval; + } + + /** + * Returns the LINK tags for the favicon and the stylesheets + * + * @return string the LINK tags + */ + private function _getLinkTags() + { + $retval = '' + . ''; + // stylesheets + $basedir = defined('PMA_PATH_TO_BASEDIR') ? PMA_PATH_TO_BASEDIR : ''; + $common_url = PMA_generate_common_url(array('server' => $GLOBALS['server'])); + $theme_id = $GLOBALS['PMA_Config']->getThemeUniqueValue(); + $theme_path = $GLOBALS['pmaThemePath']; + + if ($this->_isPrintView) { + $retval .= ''; + } else { + $retval .= ''; + $retval .= ''; + } + + return $retval; + } + + /** + * Returns the TITLE tag + * + * @return string the TITLE tag + */ + public function getTitleTag() + { + $retval = ""; + $retval .= $this->_getPageTitle(); + $retval .= ""; + return $retval; + } + + /** + * If the page is missing the title, this function + * will set it to something reasonable + * + * @return string + */ + private function _getPageTitle() + { + if (empty($this->_title)) { + if ($GLOBALS['server'] > 0) { + if (! empty($GLOBALS['table'])) { + $temp_title = $GLOBALS['cfg']['TitleTable']; + } else if (! empty($GLOBALS['db'])) { + $temp_title = $GLOBALS['cfg']['TitleDatabase']; + } elseif (! empty($GLOBALS['cfg']['Server']['host'])) { + $temp_title = $GLOBALS['cfg']['TitleServer']; + } else { + $temp_title = $GLOBALS['cfg']['TitleDefault']; + } + $this->_title = htmlspecialchars( + PMA_Util::expandUserString($temp_title) + ); + } else { + $this->_title = 'phpMyAdmin'; + } + } + return $this->_title; + } + + /** + * Returns the close tag to the HEAD + * and the start tag for the BODY + * + * @return string HEAD and BODY tags + */ + private function _getBodyStart() + { + $retval = "_bodyId)) { + $retval .= " id='" . $this->_bodyId . "'"; + } + $retval .= ">"; + return $retval; + } + + /** + * Returns some warnings to be displayed at the top of the page + * + * @return string The warnings + */ + private function _getWarnings() + { + $retval = ''; + if ($this->_warningsEnabled) { + $retval .= ""; + } + return $retval; + } + + /** + * Add recently used table and reload the navigation. + * + * @param string $db Database name where the table is located. + * @param string $table The table name + * + * @return string + */ + private function _addRecentTable($db, $table) + { + $retval = ''; + if ($this->_menuEnabled && strlen($table) && $GLOBALS['cfg']['NumRecentTables'] > 0) { + $tmp_result = PMA_RecentTable::getInstance()->add($db, $table); + if ($tmp_result === true) { + $params = array('ajax_request' => true, 'recent_table' => true); + $url = 'index.php' . PMA_generate_common_url($params); + $retval = ''; + } else { + $error = $tmp_result; + $retval = $error->getDisplay(); + } + } + return $retval; + } +} + +?> diff --git a/phpmyadmin/libraries/Index.class.php b/phpmyadmin/libraries/Index.class.php new file mode 100644 index 000000000..c349ea4d5 --- /dev/null +++ b/phpmyadmin/libraries/Index.class.php @@ -0,0 +1,863 @@ +set($params); + } + + /** + * Creates(if not already created) and returns the corresponding Index object + * + * @param string $schema database name + * @param string $table table name + * @param string $index_name index name + * + * @return object corresponding Index object + */ + static public function singleton($schema, $table, $index_name = '') + { + PMA_Index::_loadIndexes($table, $schema); + if (! isset(PMA_Index::$_registry[$schema][$table][$index_name])) { + $index = new PMA_Index; + if (strlen($index_name)) { + $index->setName($index_name); + PMA_Index::$_registry[$schema][$table][$index->getName()] = $index; + } + return $index; + } else { + return PMA_Index::$_registry[$schema][$table][$index_name]; + } + } + + /** + * returns an array with all indexes from the given table + * + * @param string $table table + * @param string $schema schema + * + * @return array array of indexes + */ + static public function getFromTable($table, $schema) + { + PMA_Index::_loadIndexes($table, $schema); + + if (isset(PMA_Index::$_registry[$schema][$table])) { + return PMA_Index::$_registry[$schema][$table]; + } else { + return array(); + } + } + + /** + * return primary if set, false otherwise + * + * @param string $table table + * @param string $schema schema + * + * @return mixed primary index or false if no one exists + */ + static public function getPrimary($table, $schema) + { + PMA_Index::_loadIndexes($table, $schema); + + if (isset(PMA_Index::$_registry[$schema][$table]['PRIMARY'])) { + return PMA_Index::$_registry[$schema][$table]['PRIMARY']; + } else { + return false; + } + } + + /** + * Load index data for table + * + * @param string $table table + * @param string $schema schema + * + * @return boolean whether loading was successful + */ + static private function _loadIndexes($table, $schema) + { + if (isset(PMA_Index::$_registry[$schema][$table])) { + return true; + } + + $_raw_indexes = PMA_DBI_get_table_indexes($schema, $table); + foreach ($_raw_indexes as $_each_index) { + $_each_index['Schema'] = $schema; + if (! isset(PMA_Index::$_registry[$schema][$table][$_each_index['Key_name']])) { + $key = new PMA_Index($_each_index); + PMA_Index::$_registry[$schema][$table][$_each_index['Key_name']] = $key; + } else { + $key = PMA_Index::$_registry[$schema][$table][$_each_index['Key_name']]; + } + + $key->addColumn($_each_index); + } + + return true; + } + + /** + * Add column to index + * + * @param array $params column params + * + * @return void + */ + public function addColumn($params) + { + if (strlen($params['Column_name'])) { + $this->_columns[$params['Column_name']] = new PMA_Index_Column($params); + } + } + + /** + * Adds a list of columns to the index + * + * @param array $columns array containing details about the columns + * + * @return void + */ + public function addColumns($columns) + { + $_columns = array(); + + if (isset($columns['names'])) { + // coming from form + // $columns[names][] + // $columns[sub_parts][] + foreach ($columns['names'] as $key => $name) { + $sub_part = isset($columns['sub_parts'][$key]) + ? $columns['sub_parts'][$key] : ''; + $_columns[] = array( + 'Column_name' => $name, + 'Sub_part' => $sub_part, + ); + } + } else { + // coming from SHOW INDEXES + // $columns[][name] + // $columns[][sub_part] + // ... + $_columns = $columns; + } + + foreach ($_columns as $column) { + $this->addColumn($column); + } + } + + /** + * Returns true if $column indexed in this index + * + * @param string $column the column + * + * @return boolean true if $column indexed in this index + */ + public function hasColumn($column) + { + return isset($this->_columns[$column]); + } + + /** + * Sets index details + * + * @param array $params index details + * + * @return void + */ + public function set($params) + { + if (isset($params['columns'])) { + $this->addColumns($params['columns']); + } + if (isset($params['Schema'])) { + $this->_schema = $params['Schema']; + } + if (isset($params['Table'])) { + $this->_table = $params['Table']; + } + if (isset($params['Key_name'])) { + $this->_name = $params['Key_name']; + } + if (isset($params['Index_type'])) { + $this->_type = $params['Index_type']; + } + if (isset($params['Comment'])) { + $this->_remarks = $params['Comment']; + } + if (isset($params['Index_comment'])) { + $this->_comment = $params['Index_comment']; + } + if (isset($params['Non_unique'])) { + $this->_non_unique = $params['Non_unique']; + } + if (isset($params['Packed'])) { + $this->_packed = $params['Packed']; + } + if ('PRIMARY' == $this->_name) { + $this->_choice = 'PRIMARY'; + } elseif ('FULLTEXT' == $this->_type) { + $this->_choice = 'FULLTEXT'; + } elseif ('SPATIAL' == $this->_type) { + $this->_choice = 'SPATIAL'; + } elseif ('0' == $this->_non_unique) { + $this->_choice = 'UNIQUE'; + } else { + $this->_choice = 'INDEX'; + } + } + + /** + * Returns the number of columns of the index + * + * @return integer the number of the columns + */ + public function getColumnCount() + { + return count($this->_columns); + } + + /** + * Returns the index comment + * + * @return string index comment + */ + public function getComment() + { + return $this->_comment; + } + + /** + * Returns index remarks + * + * @return string index remarks + */ + public function getRemarks() + { + return $this->_remarks; + } + + /** + * Returns concatenated remarks and comment + * + * @return string concatenated remarks and comment + */ + public function getComments() + { + $comments = $this->getRemarks(); + if (strlen($comments)) { + $comments .= "\n"; + } + $comments .= $this->getComment(); + + return $comments; + } + + /** + * Returns index type ((BTREE, SPATIAL, FULLTEXT, HASH, RTREE) + * + * @return string index type + */ + public function getType() + { + return $this->_type; + } + + /** + * Returns index choice (PRIMARY, UNIQUE, INDEX, SPATIAL, FULLTEXT) + * + * @return index choice + */ + public function getChoice() + { + return $this->_choice; + } + + /** + * Return a list of all index choices + * + * @return array index choices + */ + static public function getIndexChoices() + { + return array( + 'PRIMARY', + 'INDEX', + 'UNIQUE', + 'SPATIAL', + 'FULLTEXT', + ); + } + + /** + * Returns HTML for the index choice selector + * + * @return string HTML for the index choice selector + */ + public function generateIndexSelector() + { + $html_options = ''; + + foreach (PMA_Index::getIndexChoices() as $each_index_choice) { + if ($each_index_choice === 'PRIMARY' + && $this->_choice !== 'PRIMARY' + && PMA_Index::getPrimary($this->_table, $this->_schema) + ) { + // skip PRIMARY if there is already one in the table + continue; + } + $html_options .= '' . "\n"; + } + + return $html_options; + } + + /** + * Returns how the index is packed + * + * @return string how the index is packed + */ + public function getPacked() + { + return $this->_packed; + } + + /** + * Returns 'No'/false if the index is not packed, + * how the index is packed if packed + * + * @param boolean $as_text whether to output should be in text + * + * @return mixed how index is paked + */ + public function isPacked($as_text = false) + { + if ($as_text) { + $r = array( + '0' => __('No'), + '1' => __('Yes'), + ); + } else { + $r = array( + '0' => false, + '1' => true, + ); + } + + if (null === $this->_packed) { + return $r[0]; + } + + return $this->_packed; + } + + /** + * Returns integer 0 if the index cannot contain duplicates, 1 if it can + * + * @return integer 0 if the index cannot contain duplicates, 1 if it can + */ + public function getNonUnique() + { + return $this->_non_unique; + } + + /** + * Returns whether the index is a 'Unique' index + * + * @param boolean $as_text whether to output should be in text + * + * @return mixed whether the index is a 'Unique' index + */ + public function isUnique($as_text = false) + { + if ($as_text) { + $r = array( + '0' => __('Yes'), + '1' => __('No'), + ); + } else { + $r = array( + '0' => true, + '1' => false, + ); + } + + return $r[$this->_non_unique]; + } + + /** + * Returns the name of the index + * + * @return string the name of the index + */ + public function getName() + { + return $this->_name; + } + + /** + * Sets the name of the index + * + * @param string $name index name + * + * @return void + */ + public function setName($name) + { + $this->_name = (string) $name; + } + + /** + * Returns the columns of the index + * + * @return array the columns of the index + */ + public function getColumns() + { + return $this->_columns; + } + + /** + * Show index data + * + * @param string $table The table name + * @param string $schema The schema name + * @param boolean $print_mode Whether the output is for the print mode + * + * @return array Index collection array + * + * @access public + */ + static public function getView($table, $schema, $print_mode = false) + { + $indexes = PMA_Index::getFromTable($table, $schema); + + $no_indexes_class = count($indexes) > 0 ? ' hide' : ''; + $no_indexes = "
      "; + $no_indexes .= PMA_Message::notice(__('No index defined!'))->getDisplay(); + $no_indexes .= '
      '; + + if (! $print_mode) { + $r = '
      '; + $r .= '' . __('Indexes'); + $r .= PMA_Util::showMySQLDocu( + 'optimization', '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 .= ''; + $r .= ''; + if (! $print_mode) { + $r .= ''; + } + $r .= ''; + $r .= ''; + $r .= ''; + $r .= ''; + $r .= ''; + $r .= ''; + $r .= ''; + $r .= ''; + if (PMA_MYSQL_INT_VERSION > 50500) { + $r .= ''; + } + $r .= ''; + $r .= ''; + $r .= ''; + + $odd_row = true; + foreach ($indexes as $index) { + $row_span = ' rowspan="' . $index->getColumnCount() . '" '; + + $r .= ''; + + 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_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_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"; + } + + if (! $print_mode) { + $r .= ''; + } else { + $r .= ''; + } + $r .= ''; + $r .= ''; + $r .= ''; + + foreach ($index->getColumns() as $column) { + if ($column->getSeqInIndex() > 1) { + $r .= ''; + } + $r .= ''; + $r .= ''; + $r .= ''; + $r .= ''; + + if (PMA_MYSQL_INT_VERSION > 50500 + && $column->getSeqInIndex() == 1) { + $r .= ''; + } + $r .= ''; + } // end foreach $index['Sequences'] + + $odd_row = ! $odd_row; + } // end while + $r .= ''; + $r .= '
      ' . __('Action') . '' . __('Keyname') . '' . __('Type') . '' . __('Unique') . '' . __('Packed') . '' . __('Column') . '' . __('Cardinality') . '' . __('Collation') . '' . __('Null') . '' . __('Comment') . '
      ' + . ' ' . PMA_Util::getIcon('b_edit.png', __('Edit')) . '' + . ''; + $r .= ''; + $r .= ' ' + . PMA_Util::getIcon('b_drop.png', __('Drop')) . '' + . '' + . htmlspecialchars($index->getName()) + . '' + . htmlspecialchars($index->getName()) + . '' + . htmlspecialchars($index->getType()) + . '' . $index->isUnique(true) . '' . $index->isPacked(true) . '
      ' . htmlspecialchars($column->getName()); + if ($column->getSubPart()) { + $r .= ' (' . $column->getSubPart() . ')'; + } + $r .= '' + . htmlspecialchars($column->getCardinality()) + . '' + . htmlspecialchars($column->getCollation()) + . '' + . htmlspecialchars($column->getNull(true)) + . '' + . htmlspecialchars($index->getComments()) . '
      '; + if (! $print_mode) { + $r .= '
    • '; + } + + return $r; + } + + public function getCompareData() + { + $data = array( + // 'Non_unique' => $this->_non_unique, + 'Packed' => $this->_packed, + 'Index_type' => $this->_type, + ); + + foreach ($this->_columns as $column) { + $data['columns'][] = $column->getCompareData(); + } + + return $data; + } + + /** + * 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 + */ + static public function findDuplicates($table, $schema) + { + $indexes = PMA_Index::getFromTable($table, $schema); + + $output = ''; + + // count($indexes) < 2: + // there is no need to check if there less than two indexes + if (count($indexes) < 2) { + return $output; + } + + // remove last index from stack and ... + while ($while_index = array_pop($indexes)) { + // ... compare with every remaining index in stack + foreach ($indexes as $each_index) { + if ($each_index->getCompareData() !== $while_index->getCompareData()) { + continue; + } + + // 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->addParam($each_index->getName()); + $message->addParam($while_index->getName()); + $output .= $message->getDisplay(); + + // there is no need to check any further indexes if we have already + // found that this one has a duplicate + continue 2; + } + } + return $output; + } +} + +/** + * @package PhpMyAdmin + */ +class PMA_Index_Column +{ + /** + * @var string The column name + */ + private $_name = ''; + + /** + * @var integer The column sequence number in the index, starting with 1. + */ + private $_seq_in_index = 1; + + /** + * @var string How the column is sorted in the index. “A” (Ascending) or + * NULL (Not sorted) + */ + private $_collation = null; + + /** + * The number of indexed characters if the column is only partly indexed, + * NULL if the entire column is indexed. + * + * @var integer + */ + private $_sub_part = null; + + /** + * Contains YES if the column may contain NULL. + * If not, the column contains NO. + * + * @var string + */ + private $_null = ''; + + /** + * An estimate of the number of unique values in the index. This is updated + * by running ANALYZE TABLE or myisamchk -a. Cardinality is counted based on + * statistics stored as integers, so the value is not necessarily exact even + * for small tables. The higher the cardinality, the greater the chance that + * MySQL uses the index when doing joins. + * + * @var integer + */ + private $_cardinality = null; + + public function __construct($params = array()) + { + $this->set($params); + } + + public function set($params) + { + if (isset($params['Column_name'])) { + $this->_name = $params['Column_name']; + } + if (isset($params['Seq_in_index'])) { + $this->_seq_in_index = $params['Seq_in_index']; + } + if (isset($params['Collation'])) { + $this->_collation = $params['Collation']; + } + if (isset($params['Cardinality'])) { + $this->_cardinality = $params['Cardinality']; + } + if (isset($params['Sub_part'])) { + $this->_sub_part = $params['Sub_part']; + } + if (isset($params['Null'])) { + $this->_null = $params['Null']; + } + } + + public function getName() + { + return $this->_name; + } + + public function getCollation() + { + return $this->_collation; + } + + public function getCardinality() + { + return $this->_cardinality; + } + + public function getNull($as_text = false) + { + return $as_text + ? (!$this->_null || $this->_null == 'NO' ? __('No') : __('Yes')) + : $this->_null; + } + + public function getSeqInIndex() + { + return $this->_seq_in_index; + } + + public function getSubPart() + { + return $this->_sub_part; + } + + public function getCompareData() + { + return array( + 'Column_name' => $this->_name, + 'Seq_in_index' => $this->_seq_in_index, + 'Collation' => $this->_collation, + 'Sub_part' => $this->_sub_part, + 'Null' => $this->_null, + ); + } +} +?> diff --git a/phpmyadmin/libraries/List.class.php b/phpmyadmin/libraries/List.class.php new file mode 100644 index 000000000..f87c89dff --- /dev/null +++ b/phpmyadmin/libraries/List.class.php @@ -0,0 +1,121 @@ +getEmpty(); + } + + /** + * defines what is an empty item (0, '', false or null) + * + * @return mixed an empty item + */ + public function getEmpty() + { + return $this->item_empty; + } + + /** + * checks if the given db names exists in the current list, if there is + * missing at least one item it returns false otherwise true + * + * @return boolean true if all items exists, otheriwse false + */ + public function exists() + { + $this_elements = $this->getArrayCopy(); + foreach (func_get_args() as $result) { + if (! in_array($result, $this_elements)) { + return false; + } + } + + return true; + } + + /** + * returns HTML '; + if (count($this->tables)) { + foreach ($this->tables as $table) { + $html .= ''; + } + } else { + $html .= ''; + } + return $html; + } + + /** + * Return HTML select. + * + * @return string + */ + public function getHtmlSelect() + { + $html = ''; + + return $html; + } + + /** + * Add recently used tables. + * + * @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 + */ + public function add($db, $table) + { + $table_arr = array(); + $table_arr['db'] = $db; + $table_arr['table'] = $table; + + // add only if this is new table + if (! isset($this->tables[0]) || $this->tables[0] != $table_arr) { + array_unshift($this->tables, $table_arr); + $this->tables = array_merge(array_unique($this->tables, SORT_REGULAR)); + $this->trim(); + if (isset($this->_pmaTable)) { + return $this->saveToDb(); + } + } + return true; + } + +} +?> diff --git a/phpmyadmin/libraries/Response.class.php b/phpmyadmin/libraries/Response.class.php new file mode 100644 index 000000000..1bc183293 --- /dev/null +++ b/phpmyadmin/libraries/Response.class.php @@ -0,0 +1,377 @@ +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 object + */ + public function getHeader() + { + return $this->_header; + } + + /** + * Returns a PMA_Footer object + * + * @return object + */ + 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 ($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 = ''; + if (isset($GLOBALS['sql_query']) + && strlen($GLOBALS['sql_query']) < $GLOBALS['cfg']['MaxCharactersInDisplayedSQL'] + ) { + $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 000000000..c0d64d8ab --- /dev/null +++ b/phpmyadmin/libraries/Scripts.class.php @@ -0,0 +1,243 @@ +"; + } + } + $static_scripts = sprintf( + "", + implode("&", $params) + ); + 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 + ) { + 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 000000000..de23d47e8 --- /dev/null +++ b/phpmyadmin/libraries/ServerStatusData.class.php @@ -0,0 +1,380 @@ +selfUrl = basename($GLOBALS['PMA_PHP_SELF']); + /** + * get status from server + */ + $server_status = PMA_DBI_fetch_result('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 = PMA_DBI_fetch_result($sql, 0, 1); + $server_status = array_merge($server_status, $statements); + } + + /** + * for some calculations we require also some server settings + */ + $server_variables = PMA_DBI_fetch_result('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 + ) { + $server_status['Key_write_ratio_%'] + = 100 * $server_status['Key_writes'] / $server_status['Key_write_requests']; + } + + if (isset($server_status['Key_reads']) + && isset($server_status['Key_read_requests']) + && $server_status['Key_read_requests'] > 0 + ) { + $server_status['Key_read_ratio_%'] + = 100 * $server_status['Key_reads'] / $server_status['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 . '?flush=TABLES&' . PMA_generate_common_url(); + $links['table'][__('Show open tables')] + = 'sql.php?sql_query=' . urlencode('SHOW OPEN TABLES') . + '&goto=' . $this->selfUrl . '&' . PMA_generate_common_url(); + + if ($GLOBALS['server_master_status']) { + $links['repl'][__('Show slave hosts')] + = 'sql.php?sql_query=' . urlencode('SHOW SLAVE HOSTS') + . '&goto=' . $this->selfUrl . '&' + . PMA_generate_common_url(); + $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 . '?flush=' . urlencode('QUERY CACHE') . '&' . + PMA_generate_common_url(); + $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_generate_common_url(); + $links['innodb'][__('InnoDB Status')] + = 'server_engines.php?engine=InnoDB&page=Status&' . + PMA_generate_common_url(); + $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 = PMA_DBI_fetch_result( + '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_generate_common_url(); + $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 new file mode 100644 index 000000000..2dfe7f7ef --- /dev/null +++ b/phpmyadmin/libraries/StorageEngine.class.php @@ -0,0 +1,434 @@ +' . "\n"; + + foreach (PMA_StorageEngine::getStorageEngines() as $key => $details) { + // Don't show PERFORMANCE_SCHEMA engine (MySQL 5.5) + // Don't show MyISAM for Drizzle (allowed only for temporary tables) + if (! $offerUnavailableEngines + && ($details['Support'] == 'NO' + || $details['Support'] == 'DISABLED' + || $details['Engine'] == 'PERFORMANCE_SCHEMA') + || (PMA_DRIZZLE && $details['Engine'] == 'MyISAM') + ) { + continue; + } + + $output .= ' ' . "\n"; + } + $output .= '' . "\n"; + return $output; + } + + /** + * public static final PMA_StorageEngine getEngine() + * + * Loads the corresponding engine plugin, if available. + * + * @param string $engine The engine ID + * + * @return object The engine plugin + */ + static public function getEngine($engine) + { + $engine = str_replace('/', '', str_replace('.', '', $engine)); + $filename = './libraries/engines/' . strtolower($engine) . '.lib.php'; + if (file_exists($filename) && include_once $filename) { + $class_name = 'PMA_StorageEngine_' . $engine; + $engine_object = new $class_name($engine); + } else { + $engine_object = new PMA_StorageEngine($engine); + } + return $engine_object; + } + + /** + * return true if given engine name is supported/valid, otherwise false + * + * @param string $engine name of engine + * + * @static + * @return boolean whether $engine is valid or not + */ + static public function isValid($engine) + { + if ($engine == "PBMS") { + return true; + } + $storage_engines = PMA_StorageEngine::getStorageEngines(); + return isset($storage_engines[$engine]); + } + + /** + * returns as HTML table of the engine's server variables + * + * @return string The table that was generated based on the retrieved + * information + */ + function getHtmlVariables() + { + $odd_row = false; + $ret = ''; + + foreach ($this->getVariablesStatus() as $details) { + $ret .= '' . "\n" + . ' ' . "\n"; + if (! empty($details['desc'])) { + $ret .= ' ' + . PMA_Util::showHint($details['desc']) + . "\n"; + } + $ret .= ' ' . "\n" + . ' ' . htmlspecialchars($details['title']) . '' + . "\n" + . ' '; + switch ($details['type']) { + case PMA_ENGINE_DETAILS_TYPE_SIZE: + $parsed_size = $this->resolveTypeSize($details['value']); + $ret .= $parsed_size[0] . ' ' . $parsed_size[1]; + unset($parsed_size); + break; + case PMA_ENGINE_DETAILS_TYPE_NUMERIC: + $ret .= PMA_Util::formatNumber($details['value']) . ' '; + break; + default: + $ret .= htmlspecialchars($details['value']) . ' '; + } + $ret .= '' . "\n" + . '' . "\n"; + $odd_row = ! $odd_row; + } + + if (! $ret) { + $ret = '

      ' . "\n" + . ' ' + . __('There is no detailed status information available for this storage engine.') + . "\n" + . '

      ' . "\n"; + } else { + $ret = '' . "\n" . $ret . '
      ' . "\n"; + } + + return $ret; + } + + /** + * Returns the engine specific handling for + * PMA_ENGINE_DETAILS_TYPE_SIZE type variables. + * + * This function should be overridden when + * PMA_ENGINE_DETAILS_TYPE_SIZE type needs to be + * handled differently for a particular engine. + * + * @param integer $value Value to format + * + * @return string the formatted value and its unit + */ + function resolveTypeSize($value) + { + return PMA_Util::formatByteDown($value); + } + + /** + * returns array with detailed info about engine specific server variables + * + * @return array with detailed info about specific engine server variables + */ + function getVariablesStatus() + { + $variables = $this->getVariables(); + $like = $this->getVariablesLikePattern(); + + if ($like) { + $like = " LIKE '" . $like . "' "; + } else { + $like = ''; + } + + $mysql_vars = array(); + + $sql_query = 'SHOW GLOBAL VARIABLES ' . $like . ';'; + $res = PMA_DBI_query($sql_query); + while ($row = PMA_DBI_fetch_assoc($res)) { + if (isset($variables[$row['Variable_name']])) { + $mysql_vars[$row['Variable_name']] = $variables[$row['Variable_name']]; + } elseif (! $like + && strpos(strtolower($row['Variable_name']), strtolower($this->engine)) !== 0 + ) { + continue; + } + $mysql_vars[$row['Variable_name']]['value'] = $row['Value']; + + if (empty($mysql_vars[$row['Variable_name']]['title'])) { + $mysql_vars[$row['Variable_name']]['title'] = $row['Variable_name']; + } + + if (! isset($mysql_vars[$row['Variable_name']]['type'])) { + $mysql_vars[$row['Variable_name']]['type'] + = PMA_ENGINE_DETAILS_TYPE_PLAINTEXT; + } + } + PMA_DBI_free_result($res); + + return $mysql_vars; + } + + /** + * Constructor + * + * @param string $engine The engine ID + */ + function __construct($engine) + { + $storage_engines = PMA_StorageEngine::getStorageEngines(); + if (! empty($storage_engines[$engine])) { + $this->engine = $engine; + $this->title = $storage_engines[$engine]['Engine']; + $this->comment + = (isset($storage_engines[$engine]['Comment']) + ? $storage_engines[$engine]['Comment'] + : ''); + switch ($storage_engines[$engine]['Support']) { + case 'DEFAULT': + $this->support = PMA_ENGINE_SUPPORT_DEFAULT; + break; + case 'YES': + $this->support = PMA_ENGINE_SUPPORT_YES; + break; + case 'DISABLED': + $this->support = PMA_ENGINE_SUPPORT_DISABLED; + break; + case 'NO': + default: + $this->support = PMA_ENGINE_SUPPORT_NO; + } + } + } + + /** + * public String getTitle() + * + * Reveals the engine's title + * + * @return string The title + */ + function getTitle() + { + return $this->title; + } + + /** + * public String getComment() + * + * Fetches the server's comment about this engine + * + * @return string The comment + */ + function getComment() + { + return $this->comment; + } + + /** + * public String getSupportInformationMessage() + * + * @return string The localized message. + */ + function getSupportInformationMessage() + { + switch ($this->support) { + case PMA_ENGINE_SUPPORT_DEFAULT: + $message = __('%s is the default storage engine on this MySQL server.'); + break; + case PMA_ENGINE_SUPPORT_YES: + $message = __('%s is available on this MySQL server.'); + break; + case PMA_ENGINE_SUPPORT_DISABLED: + $message = __('%s has been disabled for this MySQL server.'); + break; + case PMA_ENGINE_SUPPORT_NO: + default: + $message = __('This MySQL server does not support the %s storage engine.'); + } + return sprintf($message, htmlspecialchars($this->title)); + } + + /** + * public string[][] getVariables() + * + * Generates a list of MySQL variables that provide information about this + * engine. This function should be overridden when extending this class + * for a particular engine. + * + * @abstract + * @return Array The list of variables. + */ + function getVariables() + { + return array(); + } + + /** + * returns string with filename for the MySQL helppage + * about this storage engine + * + * @return string mysql helppage filename + */ + function getMysqlHelpPage() + { + return $this->engine . '-storage-engine'; + } + + /** + * public string getVariablesLikePattern() + * + * @abstract + * @return string SQL query LIKE pattern + */ + function getVariablesLikePattern() + { + return false; + } + + /** + * public String[] getInfoPages() + * + * Returns a list of available information pages with labels + * + * @abstract + * @return array The list + */ + function getInfoPages() + { + return array(); + } + + /** + * public String getPage() + * + * Generates the requested information page + * + * @param string $id The page ID + * + * @abstract + * @return string The page + * boolean or false on error. + */ + function getPage($id) + { + return false; + } +} + +?> diff --git a/phpmyadmin/libraries/Table.class.php b/phpmyadmin/libraries/Table.class.php new file mode 100644 index 000000000..49ea68e79 --- /dev/null +++ b/phpmyadmin/libraries/Table.class.php @@ -0,0 +1,1664 @@ +setName($table_name); + $this->setDbName($db_name); + } + + /** + * returns table name + * + * @see PMA_Table::getName() + * @return string table name + */ + function __toString() + { + return $this->getName(); + } + + /** + * return the last error + * + * @return the last error + */ + function getLastError() + { + return end($this->errors); + } + + /** + * return the last message + * + * @return the last message + */ + function getLastMessage() + { + return end($this->messages); + } + + /** + * sets table name + * + * @param string $table_name new table name + * + * @return void + */ + function setName($table_name) + { + $this->name = $table_name; + } + + /** + * returns table name + * + * @param boolean $backquoted whether to quote name with backticks `` + * + * @return string table name + */ + function getName($backquoted = false) + { + if ($backquoted) { + return PMA_Util::backquote($this->name); + } + return $this->name; + } + + /** + * sets database name for this table + * + * @param string $db_name database name + * + * @return void + */ + function setDbName($db_name) + { + $this->db_name = $db_name; + } + + /** + * returns database name for this table + * + * @param boolean $backquoted whether to quote name with backticks `` + * + * @return string database name for this table + */ + function getDbName($backquoted = false) + { + if ($backquoted) { + return PMA_Util::backquote($this->db_name); + } + return $this->db_name; + } + + /** + * returns full name for table, including database name + * + * @param boolean $backquoted whether to quote name with backticks `` + * + * @return string + */ + function getFullName($backquoted = false) + { + return $this->getDbName($backquoted) . '.' + . $this->getName($backquoted); + } + + /** + * returns whether the table is actually a view + * + * @param string $db database + * @param string $table table + * + * @return whether the given is a view + */ + static public function isView($db = null, $table = null) + { + if (empty($db) || empty($table)) { + return false; + } + + // use cached data or load information with SHOW command + if (isset(PMA_Table::$cache[$db][$table]) + || $GLOBALS['cfg']['Server']['DisableIS'] + ) { + $type = PMA_Table::sGetStatusInfo($db, $table, 'TABLE_TYPE'); + return $type == 'VIEW'; + } + + // query information_schema + $result = PMA_DBI_fetch_result( + "SELECT TABLE_NAME + FROM information_schema.VIEWS + WHERE TABLE_SCHEMA = '" . PMA_Util::sqlAddSlashes($db) . "' + AND TABLE_NAME = '" . PMA_Util::sqlAddSlashes($table) . "'" + ); + return $result ? true : false; + } + + /** + * Returns whether the table is actually an updatable view + * + * @param string $db database + * @param string $table table + * + * @return boolean whether the given is an updatable view + */ + static public function isUpdatableView($db = null, $table = null) + { + if (empty($db) || empty($table)) { + return false; + } + + $result = PMA_DBI_fetch_result( + "SELECT TABLE_NAME + FROM information_schema.VIEWS + WHERE TABLE_SCHEMA = '" . PMA_Util::sqlAddSlashes($db) . "' + AND TABLE_NAME = '" . PMA_Util::sqlAddSlashes($table) . "' + AND IS_UPDATABLE = 'YES'" + ); + return $result ? true : false; + } + + /** + * Returns the analysis of 'SHOW CREATE TABLE' query for the table. + * In case of a view, the values are taken from the information_schema. + * + * @param string $db database + * @param string $table table + * + * @return array analysis of 'SHOW CREATE TABLE' query for the table + */ + static public function analyzeStructure($db = null, $table = null) + { + if (empty($db) || empty($table)) { + return false; + } + + $analyzed_sql = array(); + if (self::isView($db, $table)) { + // For a view, 'SHOW CREATE TABLE' returns the definition, + // but the structure of the view. So, we try to mock + // the result of analyzing 'SHOW CREATE TABLE' query. + $analyzed_sql[0] = array(); + $analyzed_sql[0]['create_table_fields'] = array(); + + $results = PMA_DBI_fetch_result( + "SELECT COLUMN_NAME, DATA_TYPE + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = '" . PMA_Util::sqlAddSlashes($db) . "' + AND TABLE_NAME = '" . PMA_Util::sqlAddSlashes($table) . "'" + ); + foreach ($results as $result) { + $analyzed_sql[0]['create_table_fields'][$result['COLUMN_NAME']] + = array('type' => strtoupper($result['DATA_TYPE'])); + } + } else { + $show_create_table = PMA_DBI_fetch_value( + 'SHOW CREATE TABLE ' . PMA_Util::backquote($db) . '.' . PMA_Util::backquote($table), + 0, + 1 + ); + $analyzed_sql = PMA_SQP_analyze(PMA_SQP_parse($show_create_table)); + } + return $analyzed_sql; + } + + /** + * sets given $value for given $param + * + * @param string $param name + * @param mixed $value value + * + * @return void + */ + function set($param, $value) + { + $this->settings[$param] = $value; + } + + /** + * returns value for given setting/param + * + * @param string $param name for value to return + * + * @return mixed value for $param + */ + function get($param) + { + if (isset($this->settings[$param])) { + return $this->settings[$param]; + } + + return null; + } + + /** + * Checks if this is a merge table + * + * If the ENGINE of the table is MERGE or MRG_MYISAM (alias), + * this is a merge table. + * + * @param string $db the database name + * @param string $table the table name + * + * @return boolean true if it is a merge table + */ + static public function isMerge($db = null, $table = null) + { + $engine = null; + // if called static, with parameters + if (! empty($db) && ! empty($table)) { + $engine = PMA_Table::sGetStatusInfo( + $db, $table, 'ENGINE', null, true + ); + } + + // did we get engine? + if (empty($engine)) { + return false; + } + + // any of known merge engines? + return in_array(strtoupper($engine), array('MERGE', 'MRG_MYISAM')); + } + + /** + * Returns tooltip for the table + * Format : () + * + * @param string $db database name + * @param string $table table name + * + * @return string tooltip fot the table + */ + static public function sGetToolTip($db, $table) + { + return PMA_Table::sGetStatusInfo($db, $table, 'Comment') + . ' (' . PMA_Table::countRecords($db, $table) + . ' ' . __('Rows') . ')'; + } + + /** + * Returns full table status info, or specific if $info provided + * this info is collected from information_schema + * + * @param string $db database name + * @param string $table table name + * @param string $info specific information to be fetched + * @param boolean $force_read read new rather than serving from cache + * @param boolean $disable_error if true, disables error message + * + * @todo PMA_DBI_get_tables_full needs to be merged somehow into this class + * or at least better documented + * + * @return mixed + */ + static public function sGetStatusInfo($db, $table, $info = null, + $force_read = false, $disable_error = false + ) { + if (! empty($_SESSION['is_multi_query'])) { + $disable_error = true; + } + + if (! isset(PMA_Table::$cache[$db][$table]) || $force_read) { + PMA_DBI_get_tables_full($db, $table); + } + + if (! isset(PMA_Table::$cache[$db][$table])) { + // happens when we enter the table creation dialog + // or when we really did not get any status info, for example + // when $table == 'TABLE_NAMES' after the user tried SHOW TABLES + return ''; + } + + if (null === $info) { + return PMA_Table::$cache[$db][$table]; + } + + // array_key_exists allows for null values + if (!array_key_exists($info, PMA_Table::$cache[$db][$table])) { + if (! $disable_error) { + trigger_error( + __('unknown table status: ') . $info, + E_USER_WARNING + ); + } + return false; + } + + return PMA_Table::$cache[$db][$table][$info]; + } + + /** + * generates column specification for ALTER or CREATE TABLE syntax + * + * @param string $name name + * @param string $type type ('INT', 'VARCHAR', 'BIT', ...) + * @param string $index index + * @param string $length length ('2', '5,2', '', ...) + * @param string $attribute attribute + * @param string $collation collation + * @param bool|string $null with 'NULL' or 'NOT NULL' + * @param string $default_type whether default is CURRENT_TIMESTAMP, + * NULL, NONE, USER_DEFINED + * @param string $default_value default value for USER_DEFINED + * default type + * @param string $extra 'AUTO_INCREMENT' + * @param string $comment field comment + * @param array &$field_primary list of fields for PRIMARY KEY + * @param string $move_to new position for column + * + * @todo move into class PMA_Column + * @todo on the interface, some js to clear the default value when the + * default current_timestamp is checked + * + * @return string field specification + */ + static function generateFieldSpec($name, $type, $index, $length = '', + $attribute = '', $collation = '', $null = false, + $default_type = 'USER_DEFINED', $default_value = '', $extra = '', + $comment = '', &$field_primary = null, $move_to = '' + ) { + $is_timestamp = strpos(strtoupper($type), 'TIMESTAMP') !== false; + + $query = PMA_Util::backquote($name) . ' ' . $type; + + if ($length != '' + && ! preg_match( + '@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|' + . 'MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|SERIAL|BOOLEAN|UUID)$@i', + $type + ) + ) { + $query .= '(' . $length . ')'; + } + + if ($attribute != '') { + $query .= ' ' . $attribute; + } + + $matches = preg_match( + '@^(TINYTEXT|TEXT|MEDIUMTEXT|LONGTEXT|VARCHAR|CHAR|ENUM|SET)$@i', + $type + ); + if (! empty($collation) && $collation != 'NULL' && $matches) { + $query .= PMA_generateCharsetQueryPart($collation); + } + + if ($null !== false) { + if ($null == 'NULL') { + $query .= ' NULL'; + } else { + $query .= ' NOT NULL'; + } + } + + switch ($default_type) { + case 'USER_DEFINED' : + if ($is_timestamp && $default_value === '0') { + // a TIMESTAMP does not accept DEFAULT '0' + // but DEFAULT 0 works + $query .= ' DEFAULT 0'; + } elseif ($type == 'BIT') { + $query .= ' DEFAULT b\'' + . preg_replace('/[^01]/', '0', $default_value) + . '\''; + } elseif ($type == 'BOOLEAN') { + if (preg_match('/^1|T|TRUE|YES$/i', $default_value)) { + $query .= ' DEFAULT TRUE'; + } elseif (preg_match('/^0|F|FALSE|NO$/i', $default_value)) { + $query .= ' DEFAULT FALSE'; + } else { + // Invalid BOOLEAN value + $query .= ' DEFAULT \'' + . PMA_Util::sqlAddSlashes($default_value) . '\''; + } + } else { + $query .= ' DEFAULT \'' . PMA_Util::sqlAddSlashes($default_value) . '\''; + } + break; + case 'NULL' : + //If user uncheck null checkbox and not change default value null, + //default value will be ignored. + if ($null !== false && $null != 'NULL') { + break; + } + case 'CURRENT_TIMESTAMP' : + $query .= ' DEFAULT ' . $default_type; + break; + case 'NONE' : + default : + break; + } + + if (!empty($extra)) { + $query .= ' ' . $extra; + // Force an auto_increment field to be part of the primary key + // even if user did not tick the PK box; + if ($extra == 'AUTO_INCREMENT') { + $primary_cnt = count($field_primary); + if (1 == $primary_cnt) { + for ($j = 0; $j < $primary_cnt; $j++) { + if ($field_primary[$j] == $index) { + break; + } + } + if (isset($field_primary[$j]) && $field_primary[$j] == $index) { + $query .= ' PRIMARY KEY'; + unset($field_primary[$j]); + } + } else { + // but the PK could contain other columns so do not append + // a PRIMARY KEY clause, just add a member to $field_primary + $found_in_pk = false; + for ($j = 0; $j < $primary_cnt; $j++) { + if ($field_primary[$j] == $index) { + $found_in_pk = true; + break; + } + } // end for + if (! $found_in_pk) { + $field_primary[] = $index; + } + } + } // end if (auto_increment) + } + if (!empty($comment)) { + $query .= " COMMENT '" . PMA_Util::sqlAddSlashes($comment) . "'"; + } + + // move column + if ($move_to == '-first') { // dash can't appear as part of column name + $query .= ' FIRST'; + } elseif ($move_to != '') { + $query .= ' AFTER ' . PMA_Util::backquote($move_to); + } + return $query; + } // end function + + /** + * Counts and returns (or displays) the number of records in a table + * + * @param string $db the current database name + * @param string $table the current table name + * @param bool $force_exact whether to force an exact count + * @param bool $is_view whether the table is a view + * + * @return mixed the number of records if "retain" param is true, + * otherwise true + */ + static public function countRecords($db, $table, $force_exact = false, + $is_view = null + ) { + if (isset(PMA_Table::$cache[$db][$table]['ExactRows'])) { + $row_count = PMA_Table::$cache[$db][$table]['ExactRows']; + } else { + $row_count = false; + + if (null === $is_view) { + $is_view = PMA_Table::isView($db, $table); + } + + if (! $force_exact) { + if (! isset(PMA_Table::$cache[$db][$table]['Rows']) && ! $is_view) { + $tmp_tables = PMA_DBI_get_tables_full($db, $table); + if (isset($tmp_tables[$table])) { + PMA_Table::$cache[$db][$table] = $tmp_tables[$table]; + } + } + if (isset(PMA_Table::$cache[$db][$table]['Rows'])) { + $row_count = PMA_Table::$cache[$db][$table]['Rows']; + } else { + $row_count = false; + } + } + + // for a VIEW, $row_count is always false at this point + if (false === $row_count + || $row_count < $GLOBALS['cfg']['MaxExactCount'] + ) { + // Make an exception for views in I_S and D_D schema in + // Drizzle, as these map to in-memory data and should execute + // fast enough + if (! $is_view || (PMA_DRIZZLE && PMA_is_system_schema($db))) { + $row_count = PMA_DBI_fetch_value( + 'SELECT COUNT(*) FROM ' . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table) + ); + } else { + // For complex views, even trying to get a partial record + // count could bring down a server, so we offer an + // alternative: setting MaxExactCountViews to 0 will bypass + // completely the record counting for views + + if ($GLOBALS['cfg']['MaxExactCountViews'] == 0) { + $row_count = 0; + } else { + // Counting all rows of a VIEW could be too long, + // so use a LIMIT clause. + // Use try_query because it can fail (when a VIEW is + // based on a table that no longer exists) + $result = PMA_DBI_try_query( + 'SELECT 1 FROM ' . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table) . ' LIMIT ' + . $GLOBALS['cfg']['MaxExactCountViews'], + null, + PMA_DBI_QUERY_STORE + ); + if (!PMA_DBI_getError()) { + $row_count = PMA_DBI_num_rows($result); + PMA_DBI_free_result($result); + } + } + } + if ($row_count) { + PMA_Table::$cache[$db][$table]['ExactRows'] = $row_count; + } + } + } + + return $row_count; + } // end of the 'PMA_Table::countRecords()' function + + /** + * Generates column specification for ALTER syntax + * + * @param string $oldcol old column name + * @param string $newcol new column name + * @param string $type type ('INT', 'VARCHAR', 'BIT', ...) + * @param string $length length ('2', '5,2', '', ...) + * @param string $attribute attribute + * @param string $collation collation + * @param bool|string $null with 'NULL' or 'NOT NULL' + * @param string $default_type whether default is CURRENT_TIMESTAMP, + * NULL, NONE, USER_DEFINED + * @param string $default_value default value for USER_DEFINED default + * type + * @param string $extra 'AUTO_INCREMENT' + * @param string $comment field comment + * @param array &$field_primary list of fields for PRIMARY KEY + * @param string $index index + * @param string $move_to new position for column + * + * @see PMA_Table::generateFieldSpec() + * + * @return string field specification + */ + static public function generateAlter($oldcol, $newcol, $type, $length, + $attribute, $collation, $null, $default_type, $default_value, + $extra, $comment, &$field_primary, $index, $move_to + ) { + return PMA_Util::backquote($oldcol) . ' ' + . PMA_Table::generateFieldSpec( + $newcol, $type, $index, $length, $attribute, + $collation, $null, $default_type, $default_value, $extra, + $comment, $field_primary, $move_to + ); + } // end function + + /** + * Inserts existing entries in a PMA_* table by reading a value from an old + * entry + * + * @param string $work The array index, which Relation feature to + * check ('relwork', 'commwork', ...) + * @param string $pma_table The array index, which PMA-table to update + * ('bookmark', 'relation', ...) + * @param array $get_fields Which fields will be SELECT'ed from the old entry + * @param array $where_fields Which fields will be used for the WHERE query + * (array('FIELDNAME' => 'FIELDVALUE')) + * @param array $new_fields Which fields will be used as new VALUES. + * These are the important keys which differ + * from the old entry + * (array('FIELDNAME' => 'NEW FIELDVALUE')) + * + * @global relation variable + * + * @return int|true + */ + static public function duplicateInfo($work, $pma_table, $get_fields, + $where_fields, $new_fields + ) { + $last_id = -1; + + if (isset($GLOBALS['cfgRelation']) && $GLOBALS['cfgRelation'][$work]) { + $select_parts = array(); + $row_fields = array(); + foreach ($get_fields as $get_field) { + $select_parts[] = PMA_Util::backquote($get_field); + $row_fields[$get_field] = 'cc'; + } + + $where_parts = array(); + foreach ($where_fields as $_where => $_value) { + $where_parts[] = PMA_Util::backquote($_where) . ' = \'' + . PMA_Util::sqlAddSlashes($_value) . '\''; + } + + $new_parts = array(); + $new_value_parts = array(); + foreach ($new_fields as $_where => $_value) { + $new_parts[] = PMA_Util::backquote($_where); + $new_value_parts[] = PMA_Util::sqlAddSlashes($_value); + } + + $table_copy_query = ' + SELECT ' . implode(', ', $select_parts) . ' + FROM ' . PMA_Util::backquote($GLOBALS['cfgRelation']['db']) . '.' + . PMA_Util::backquote($GLOBALS['cfgRelation'][$pma_table]) . ' + WHERE ' . implode(' AND ', $where_parts); + + // must use PMA_DBI_QUERY_STORE here, since we execute another + // query inside the loop + $table_copy_rs = PMA_queryAsControlUser( + $table_copy_query, true, PMA_DBI_QUERY_STORE + ); + + while ($table_copy_row = @PMA_DBI_fetch_assoc($table_copy_rs)) { + $value_parts = array(); + foreach ($table_copy_row as $_key => $_val) { + if (isset($row_fields[$_key]) && $row_fields[$_key] == 'cc') { + $value_parts[] = PMA_Util::sqlAddSlashes($_val); + } + } + + $new_table_query = 'INSERT IGNORE INTO ' + . PMA_Util::backquote($GLOBALS['cfgRelation']['db']) + . '.' . PMA_Util::backquote($GLOBALS['cfgRelation'][$pma_table]) . ' + (' . implode(', ', $select_parts) . ', + ' . implode(', ', $new_parts) . ') + VALUES + (\'' . implode('\', \'', $value_parts) . '\', + \'' . implode('\', \'', $new_value_parts) . '\')'; + + PMA_queryAsControlUser($new_table_query); + $last_id = PMA_DBI_insert_id(); + } // end while + + PMA_DBI_free_result($table_copy_rs); + + return $last_id; + } + + return true; + } // end of 'PMA_Table::duplicateInfo()' function + + /** + * Copies or renames table + * + * @param string $source_db source database + * @param string $source_table source table + * @param string $target_db target database + * @param string $target_table target table + * @param string $what what to be moved or copied (data, dataonly) + * @param bool $move whether to move + * @param string $mode mode + * + * @return bool true if success, false otherwise + */ + static public function moveCopy($source_db, $source_table, $target_db, + $target_table, $what, $move, $mode + ) { + global $err_url; + + /* Try moving table directly */ + if ($move && $what == 'data') { + $tbl = new PMA_Table($source_table, $source_db); + $result = $tbl->rename($target_table, $target_db); + if ($result) { + $GLOBALS['message'] = $tbl->getLastMessage(); + return true; + } + } + + // set export settings we need + $GLOBALS['sql_backquotes'] = 1; + $GLOBALS['asfile'] = 1; + + // Ensure the target is valid + if (! $GLOBALS['pma']->databases->exists($source_db, $target_db)) { + if (! $GLOBALS['pma']->databases->exists($source_db)) { + $GLOBALS['message'] = PMA_Message::rawError( + sprintf( + __('Source database `%s` was not found!'), + htmlspecialchars($source_db) + ) + ); + } + if (! $GLOBALS['pma']->databases->exists($target_db)) { + $GLOBALS['message'] = PMA_Message::rawError( + sprintf( + __('Target database `%s` was not found!'), + htmlspecialchars($target_db) + ) + ); + } + return false; + } + + $source = PMA_Util::backquote($source_db) . '.' . PMA_Util::backquote($source_table); + if (! isset($target_db) || ! strlen($target_db)) { + $target_db = $source_db; + } + + // Doing a select_db could avoid some problems with replicated databases, + // when moving table from replicated one to not replicated one + PMA_DBI_select_db($target_db); + + $target = PMA_Util::backquote($target_db) . '.' . PMA_Util::backquote($target_table); + + // do not create the table if dataonly + if ($what != 'dataonly') { + include_once "libraries/plugin_interface.lib.php"; + // get Export SQL instance + $export_sql_plugin = PMA_getPlugin( + "export", + "sql", + 'libraries/plugins/export/', + array( + 'export_type' => 'table', + 'single_table' => isset($single_table) + ) + ); + + $no_constraints_comments = true; + $GLOBALS['sql_constraints_query'] = ''; + + $sql_structure = $export_sql_plugin->getTableDef( + $source_db, $source_table, "\n", $err_url, false, false + ); + unset($no_constraints_comments); + $parsed_sql = PMA_SQP_parse($sql_structure); + $analyzed_sql = PMA_SQP_analyze($parsed_sql); + $i = 0; + if (empty($analyzed_sql[0]['create_table_fields'])) { + // this is not a CREATE TABLE, so find the first VIEW + $target_for_view = PMA_Util::backquote($target_db); + while (true) { + if ($parsed_sql[$i]['type'] == 'alpha_reservedWord' + && $parsed_sql[$i]['data'] == 'VIEW' + ) { + break; + } + $i++; + } + } + unset($analyzed_sql); + if (PMA_DRIZZLE) { + $table_delimiter = 'quote_backtick'; + } else { + $server_sql_mode = PMA_DBI_fetch_value( + "SHOW VARIABLES LIKE 'sql_mode'", + 0, + 1 + ); + // ANSI_QUOTES might be a subset of sql_mode, for example + // REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI + if (false !== strpos($server_sql_mode, 'ANSI_QUOTES')) { + $table_delimiter = 'quote_double'; + } else { + $table_delimiter = 'quote_backtick'; + } + unset($server_sql_mode); + } + + /* Find table name in query and replace it */ + while ($parsed_sql[$i]['type'] != $table_delimiter) { + $i++; + } + + /* no need to backquote() */ + if (isset($target_for_view)) { + // this a view definition; we just found the first db name + // that follows DEFINER VIEW + // so change it for the new db name + $parsed_sql[$i]['data'] = $target_for_view; + // then we have to find all references to the source db + // and change them to the target db, ensuring we stay into + // the $parsed_sql limits + $last = $parsed_sql['len'] - 1; + $backquoted_source_db = PMA_Util::backquote($source_db); + for (++$i; $i <= $last; $i++) { + if ($parsed_sql[$i]['type'] == $table_delimiter + && $parsed_sql[$i]['data'] == $backquoted_source_db + && $parsed_sql[$i - 1]['type'] != 'punct_qualifier' + ) { + $parsed_sql[$i]['data'] = $target_for_view; + } + } + unset($last,$backquoted_source_db); + } else { + $parsed_sql[$i]['data'] = $target; + } + + /* Generate query back */ + $sql_structure = PMA_SQP_formatHtml($parsed_sql, 'query_only'); + // If table exists, and 'add drop table' is selected: Drop it! + $drop_query = ''; + if (isset($_REQUEST['drop_if_exists']) + && $_REQUEST['drop_if_exists'] == 'true' + ) { + if (PMA_Table::isView($target_db, $target_table)) { + $drop_query = 'DROP VIEW'; + } else { + $drop_query = 'DROP TABLE'; + } + $drop_query .= ' IF EXISTS ' + . PMA_Util::backquote($target_db) . '.' + . PMA_Util::backquote($target_table); + PMA_DBI_query($drop_query); + + $GLOBALS['sql_query'] .= "\n" . $drop_query . ';'; + + // If an existing table gets deleted, maintain any + // entries for the PMA_* tables + $maintain_relations = true; + } + + @PMA_DBI_query($sql_structure); + $GLOBALS['sql_query'] .= "\n" . $sql_structure . ';'; + + if (($move || isset($GLOBALS['add_constraints'])) + && !empty($GLOBALS['sql_constraints_query']) + ) { + $parsed_sql = PMA_SQP_parse($GLOBALS['sql_constraints_query']); + $i = 0; + + // find the first $table_delimiter, it must be the source + // table name + while ($parsed_sql[$i]['type'] != $table_delimiter) { + $i++; + // maybe someday we should guard against going over limit + //if ($i == $parsed_sql['len']) { + // break; + //} + } + + // replace it by the target table name, no need + // to backquote() + $parsed_sql[$i]['data'] = $target; + + // now we must remove all $table_delimiter that follow a + // CONSTRAINT keyword, because a constraint name must be + // unique in a db + + $cnt = $parsed_sql['len'] - 1; + + for ($j = $i; $j < $cnt; $j++) { + if ($parsed_sql[$j]['type'] == 'alpha_reservedWord' + && strtoupper($parsed_sql[$j]['data']) == 'CONSTRAINT' + ) { + if ($parsed_sql[$j+1]['type'] == $table_delimiter) { + $parsed_sql[$j+1]['data'] = ''; + } + } + } + + // Generate query back + $GLOBALS['sql_constraints_query'] = PMA_SQP_formatHtml( + $parsed_sql, 'query_only' + ); + if ($mode == 'one_table') { + PMA_DBI_query($GLOBALS['sql_constraints_query']); + } + $GLOBALS['sql_query'] .= "\n" . $GLOBALS['sql_constraints_query']; + if ($mode == 'one_table') { + unset($GLOBALS['sql_constraints_query']); + } + } + } else { + $GLOBALS['sql_query'] = ''; + } + + // Copy the data unless this is a VIEW + if (($what == 'data' || $what == 'dataonly') + && ! PMA_Table::isView($target_db, $target_table) + ) { + $sql_set_mode = "SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO'"; + PMA_DBI_query($sql_set_mode); + $GLOBALS['sql_query'] .= "\n\n" . $sql_set_mode . ';'; + + $sql_insert_data = 'INSERT INTO ' . $target + . ' SELECT * FROM ' . $source; + PMA_DBI_query($sql_insert_data); + $GLOBALS['sql_query'] .= "\n\n" . $sql_insert_data . ';'; + } + + $GLOBALS['cfgRelation'] = PMA_getRelationsParam(); + + // Drops old table if the user has requested to move it + if ($move) { + + // This could avoid some problems with replicated databases, when + // moving table from replicated one to not replicated one + PMA_DBI_select_db($source_db); + + if (PMA_Table::isView($source_db, $source_table)) { + $sql_drop_query = 'DROP VIEW'; + } else { + $sql_drop_query = 'DROP TABLE'; + } + $sql_drop_query .= ' ' . $source; + PMA_DBI_query($sql_drop_query); + + // Renable table in configuration storage + PMA_REL_renameTable( + $source_db, $target_db, + $source_table, $target_table + ); + + $GLOBALS['sql_query'] .= "\n\n" . $sql_drop_query . ';'; + // end if ($move) + } else { + // we are copying + // Create new entries as duplicates from old PMA DBs + if ($what != 'dataonly' && ! isset($maintain_relations)) { + if ($GLOBALS['cfgRelation']['commwork']) { + // Get all comments and MIME-Types for current table + $comments_copy_query = 'SELECT + column_name, comment' . ($GLOBALS['cfgRelation']['mimework'] ? ', mimetype, transformation, transformation_options' : '') . ' + FROM ' . PMA_Util::backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_Util::backquote($GLOBALS['cfgRelation']['column_info']) . ' + WHERE + db_name = \'' . PMA_Util::sqlAddSlashes($source_db) . '\' AND + table_name = \'' . PMA_Util::sqlAddSlashes($source_table) . '\''; + $comments_copy_rs = PMA_queryAsControlUser($comments_copy_query); + + // Write every comment as new copied entry. [MIME] + while ($comments_copy_row = PMA_DBI_fetch_assoc($comments_copy_rs)) { + $new_comment_query = 'REPLACE INTO ' . PMA_Util::backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_Util::backquote($GLOBALS['cfgRelation']['column_info']) + . ' (db_name, table_name, column_name, comment' . ($GLOBALS['cfgRelation']['mimework'] ? ', mimetype, transformation, transformation_options' : '') . ') ' + . ' VALUES(' + . '\'' . PMA_Util::sqlAddSlashes($target_db) . '\',' + . '\'' . PMA_Util::sqlAddSlashes($target_table) . '\',' + . '\'' . PMA_Util::sqlAddSlashes($comments_copy_row['column_name']) . '\'' + . ($GLOBALS['cfgRelation']['mimework'] ? ',\'' . PMA_Util::sqlAddSlashes($comments_copy_row['comment']) . '\',' + . '\'' . PMA_Util::sqlAddSlashes($comments_copy_row['mimetype']) . '\',' + . '\'' . PMA_Util::sqlAddSlashes($comments_copy_row['transformation']) . '\',' + . '\'' . PMA_Util::sqlAddSlashes($comments_copy_row['transformation_options']) . '\'' : '') + . ')'; + PMA_queryAsControlUser($new_comment_query); + } // end while + PMA_DBI_free_result($comments_copy_rs); + unset($comments_copy_rs); + } + + // duplicating the bookmarks must not be done here, but + // just once per db + + $get_fields = array('display_field'); + $where_fields = array( + 'db_name' => $source_db, + 'table_name' => $source_table + ); + $new_fields = array( + 'db_name' => $target_db, + 'table_name' => $target_table + ); + PMA_Table::duplicateInfo( + 'displaywork', + 'table_info', + $get_fields, + $where_fields, + $new_fields + ); + + + /** + * @todo revise this code when we support cross-db relations + */ + $get_fields = array( + 'master_field', + 'foreign_table', + 'foreign_field' + ); + $where_fields = array( + 'master_db' => $source_db, + 'master_table' => $source_table + ); + $new_fields = array( + 'master_db' => $target_db, + 'foreign_db' => $target_db, + 'master_table' => $target_table + ); + PMA_Table::duplicateInfo( + 'relwork', + 'relation', + $get_fields, + $where_fields, + $new_fields + ); + + + $get_fields = array( + 'foreign_field', + 'master_table', + 'master_field' + ); + $where_fields = array( + 'foreign_db' => $source_db, + 'foreign_table' => $source_table + ); + $new_fields = array( + 'master_db' => $target_db, + 'foreign_db' => $target_db, + 'foreign_table' => $target_table + ); + PMA_Table::duplicateInfo( + 'relwork', + 'relation', + $get_fields, + $where_fields, + $new_fields + ); + + + $get_fields = array('x', 'y', 'v', 'h'); + $where_fields = array( + 'db_name' => $source_db, + 'table_name' => $source_table + ); + $new_fields = array( + 'db_name' => $target_db, + 'table_name' => $target_table + ); + PMA_Table::duplicateInfo( + 'designerwork', + 'designer_coords', + $get_fields, + $where_fields, + $new_fields + ); + + /** + * @todo Can't get duplicating PDFs the right way. The + * page numbers always get screwed up independently from + * duplication because the numbers do not seem to be stored on a + * per-database basis. Would the author of pdf support please + * have a look at it? + * + $get_fields = array('page_descr'); + $where_fields = array('db_name' => $source_db); + $new_fields = array('db_name' => $target_db); + $last_id = PMA_Table::duplicateInfo( + 'pdfwork', + 'pdf_pages', + $get_fields, + $where_fields, + $new_fields + ); + + if (isset($last_id) && $last_id >= 0) { + $get_fields = array('x', 'y'); + $where_fields = array( + 'db_name' => $source_db, + 'table_name' => $source_table + ); + $new_fields = array( + 'db_name' => $target_db, + 'table_name' => $target_table, + 'pdf_page_number' => $last_id + ); + PMA_Table::duplicateInfo( + 'pdfwork', + 'table_coords', + $get_fields, + $where_fields, + $new_fields + ); + } + */ + } + } + return true; + } + + /** + * checks if given name is a valid table name, + * currently if not empty, trailing spaces, '.', '/' and '\' + * + * @param string $table_name name to check + * + * @todo add check for valid chars in filename on current system/os + * @see http://dev.mysql.com/doc/refman/5.0/en/legal-names.html + * + * @return boolean whether the string is valid or not + */ + static function isValidName($table_name) + { + if ($table_name !== trim($table_name)) { + // trailing spaces + return false; + } + + if (! strlen($table_name)) { + // zero length + return false; + } + + if (preg_match('/[.\/\\\\]+/i', $table_name)) { + // illegal char . / \ + return false; + } + + return true; + } + + /** + * renames table + * + * @param string $new_name new table name + * @param string $new_db new database name + * + * @return bool success + */ + function rename($new_name, $new_db = null) + { + if (null !== $new_db && $new_db !== $this->getDbName()) { + // Ensure the target is valid + if (! $GLOBALS['pma']->databases->exists($new_db)) { + $this->errors[] = __('Invalid database') . ': ' . $new_db; + return false; + } + } else { + $new_db = $this->getDbName(); + } + + $new_table = new PMA_Table($new_name, $new_db); + + if ($this->getFullName() === $new_table->getFullName()) { + return true; + } + + if (! PMA_Table::isValidName($new_name)) { + $this->errors[] = __('Invalid table name') . ': ' + . $new_table->getFullName(); + return false; + } + + // If the table is moved to a different database drop its triggers first + $triggers = PMA_DBI_get_triggers($this->getDbName(), $this->getName(), ''); + $handle_triggers = $this->getDbName() != $new_db && $triggers; + if ($handle_triggers) { + foreach ($triggers as $trigger) { + $sql = 'DROP TRIGGER IF EXISTS ' . PMA_Util::backquote($this->getDbName()) + . '.' . PMA_Util::backquote($trigger['name']) . ';'; + PMA_DBI_query($sql); + } + } + + /* + * tested also for a view, in MySQL 5.0.92, 5.1.55 and 5.5.13 + */ + $GLOBALS['sql_query'] = ' + RENAME TABLE ' . $this->getFullName(true) . ' + TO ' . $new_table->getFullName(true) . ';'; + // I don't think a specific error message for views is necessary + if (! PMA_DBI_query($GLOBALS['sql_query'])) { + // Restore triggers in the old database + if ($handle_triggers) { + PMA_DBI_select_db($this->getDbName()); + foreach ($triggers as $trigger) { + PMA_DBI_query($trigger['create']); + } + } + $this->errors[] = sprintf( + __('Error renaming table %1$s to %2$s'), + $this->getFullName(), + $new_table->getFullName() + ); + return false; + } + + $old_name = $this->getName(); + $old_db = $this->getDbName(); + $this->setName($new_name); + $this->setDbName($new_db); + + // Renable table in configuration storage + PMA_REL_renameTable( + $old_db, $new_db, + $old_name, $new_name + ); + + $this->messages[] = sprintf( + __('Table %1$s has been renamed to %2$s.'), + htmlspecialchars($old_name), + htmlspecialchars($new_name) + ); + return true; + } + + /** + * Get all unique columns + * + * returns an array with all columns with unqiue content, in fact these are + * all columns being single indexed in PRIMARY or UNIQUE + * + * e.g. + * - PRIMARY(id) // id + * - UNIQUE(name) // name + * - PRIMARY(fk_id1, fk_id2) // NONE + * - UNIQUE(x,y) // NONE + * + * @param bool $backquoted whether to quote name with backticks `` + * + * @return array + */ + public function getUniqueColumns($backquoted = true) + { + $sql = PMA_DBI_get_table_indexes_sql( + $this->getDbName(), + $this->getName(), + 'Non_unique = 0' + ); + $uniques = PMA_DBI_fetch_result( + $sql, + array('Key_name', null), + 'Column_name' + ); + + $return = array(); + foreach ($uniques as $index) { + if (count($index) > 1) { + continue; + } + $return[] = $this->getFullName($backquoted) . '.' + . ($backquoted ? PMA_Util::backquote($index[0]) : $index[0]); + } + + return $return; + } + + /** + * Get all indexed columns + * + * returns an array with all columns make use of an index, in fact only + * first columns in an index + * + * e.g. index(col1, col2) would only return col1 + * + * @param bool $backquoted whether to quote name with backticks `` + * + * @return array + */ + public function getIndexedColumns($backquoted = true) + { + $sql = PMA_DBI_get_table_indexes_sql( + $this->getDbName(), + $this->getName(), + 'Seq_in_index = 1' + ); + $indexed = PMA_DBI_fetch_result($sql, 'Column_name', 'Column_name'); + + $return = array(); + foreach ($indexed as $column) { + $return[] = $this->getFullName($backquoted) . '.' + . ($backquoted ? PMA_Util::backquote($column) : $column); + } + + return $return; + } + + /** + * Get all columns + * + * returns an array with all columns + * + * @param bool $backquoted whether to quote name with backticks `` + * + * @return array + */ + public function getColumns($backquoted = true) + { + $sql = 'SHOW COLUMNS FROM ' . $this->getFullName(true); + $indexed = PMA_DBI_fetch_result($sql, 'Field', 'Field'); + + $return = array(); + foreach ($indexed as $column) { + $return[] = $this->getFullName($backquoted) . '.' + . ($backquoted ? PMA_Util::backquote($column) : $column); + } + + return $return; + } + + /** + * Return UI preferences for this table from phpMyAdmin database. + * + * @return array + */ + protected function getUiPrefsFromDb() + { + $pma_table = PMA_Util::backquote($GLOBALS['cfg']['Server']['pmadb']) ."." + . PMA_Util::backquote($GLOBALS['cfg']['Server']['table_uiprefs']); + + // Read from phpMyAdmin database + $sql_query = " SELECT `prefs` FROM " . $pma_table + . " WHERE `username` = '" . $GLOBALS['cfg']['Server']['user'] . "'" + . " AND `db_name` = '" . PMA_Util::sqlAddSlashes($this->db_name) . "'" + . " AND `table_name` = '" . PMA_Util::sqlAddSlashes($this->name) . "'"; + + $row = PMA_DBI_fetch_array(PMA_queryAsControlUser($sql_query)); + if (isset($row[0])) { + return json_decode($row[0], true); + } else { + return array(); + } + } + + /** + * Save this table's UI preferences into phpMyAdmin database. + * + * @return true|PMA_Message + */ + protected function saveUiPrefsToDb() + { + $pma_table = PMA_Util::backquote($GLOBALS['cfg']['Server']['pmadb']) . "." + . PMA_Util::backquote($GLOBALS['cfg']['Server']['table_uiprefs']); + + $username = $GLOBALS['cfg']['Server']['user']; + $sql_query = " REPLACE INTO " . $pma_table + . " VALUES ('" . $username . "', '" . PMA_Util::sqlAddSlashes($this->db_name) + . "', '" . PMA_Util::sqlAddSlashes($this->name) . "', '" + . PMA_Util::sqlAddSlashes(json_encode($this->uiprefs)) . "', NULL)"; + + $success = PMA_DBI_try_query($sql_query, $GLOBALS['controllink']); + + if (!$success) { + $message = PMA_Message::error(__('Could not save table UI preferences')); + $message->addMessage('

      '); + $message->addMessage( + PMA_Message::rawError(PMA_DBI_getError($GLOBALS['controllink'])) + ); + return $message; + } + + // Remove some old rows in table_uiprefs if it exceeds the configured + // maximum rows + $sql_query = 'SELECT COUNT(*) FROM ' . $pma_table; + $rows_count = PMA_DBI_fetch_value($sql_query); + $max_rows = $GLOBALS['cfg']['Server']['MaxTableUiprefs']; + if ($rows_count > $max_rows) { + $num_rows_to_delete = $rows_count - $max_rows; + $sql_query + = ' DELETE FROM ' . $pma_table . + ' ORDER BY last_update ASC' . + ' LIMIT ' . $num_rows_to_delete; + $success = PMA_DBI_try_query($sql_query, $GLOBALS['controllink']); + + if (!$success) { + $message = PMA_Message::error( + sprintf( + __('Failed to cleanup table UI preferences (see $cfg[\'Servers\'][$i][\'MaxTableUiprefs\'] %s)'), + PMA_Util::showDocu('config', 'cfg_Servers_MaxTableUiprefs') + ) + ); + $message->addMessage('

      '); + $message->addMessage( + PMA_Message::rawError(PMA_DBI_getError($GLOBALS['controllink'])) + ); + print_r($message); + return $message; + } + } + + return true; + } + + /** + * Loads the UI preferences for this table. + * If pmadb and table_uiprefs is set, it will load the UI preferences from + * phpMyAdmin database. + * + * @return void + */ + protected function loadUiPrefs() + { + $server_id = $GLOBALS['server']; + // set session variable if it's still undefined + if (! isset($_SESSION['tmp_user_values']['table_uiprefs'][$server_id][$this->db_name][$this->name])) { + // check whether we can get from pmadb + $_SESSION['tmp_user_values']['table_uiprefs'][$server_id][$this->db_name][$this->name] + = (strlen($GLOBALS['cfg']['Server']['pmadb']) + && strlen($GLOBALS['cfg']['Server']['table_uiprefs'])) + ? $this->getUiPrefsFromDb() + : array(); + } + $this->uiprefs =& $_SESSION['tmp_user_values']['table_uiprefs'][$server_id] + [$this->db_name][$this->name]; + } + + /** + * Get a property from UI preferences. + * Return false if the property is not found. + * Available property: + * - PROP_SORTED_COLUMN + * - PROP_COLUMN_ORDER + * - PROP_COLUMN_VISIB + * + * @param string $property property + * + * @return mixed + */ + public function getUiProp($property) + { + if (! isset($this->uiprefs)) { + $this->loadUiPrefs(); + } + // do checking based on property + if ($property == self::PROP_SORTED_COLUMN) { + if (isset($this->uiprefs[$property])) { + // check if the column name is exist in this table + $tmp = explode(' ', $this->uiprefs[$property]); + $colname = $tmp[0]; + $avail_columns = $this->getColumns(); + foreach ($avail_columns as $each_col) { + // check if $each_col ends with $colname + if (substr_compare($each_col, $colname, strlen($each_col) - strlen($colname)) === 0) { + return $this->uiprefs[$property]; + } + } + // remove the property, since it is not exist anymore in database + $this->removeUiProp(self::PROP_SORTED_COLUMN); + return false; + } else { + return false; + } + } elseif ($property == self::PROP_COLUMN_ORDER + || $property == self::PROP_COLUMN_VISIB + ) { + if (! PMA_Table::isView($this->db_name, $this->name) + && isset($this->uiprefs[$property]) + ) { + // check if the table has not been modified + if (self::sGetStatusInfo($this->db_name, $this->name, 'Create_time') == $this->uiprefs['CREATE_TIME']) { + return $this->uiprefs[$property]; + } else { + // remove the property, since the table has been modified + $this->removeUiProp(self::PROP_COLUMN_ORDER); + return false; + } + } else { + return false; + } + } + // default behaviour for other property: + return isset($this->uiprefs[$property]) ? $this->uiprefs[$property] : false; + } + + /** + * Set a property from UI preferences. + * If pmadb and table_uiprefs is set, it will save the UI preferences to + * phpMyAdmin database. + * Available property: + * - PROP_SORTED_COLUMN + * - PROP_COLUMN_ORDER + * - PROP_COLUMN_VISIB + * + * @param string $property Property + * @param mixed $value Value for the property + * @param string $table_create_time Needed for PROP_COLUMN_ORDER + * and PROP_COLUMN_VISIB + * + * @return boolean|PMA_Message + */ + public function setUiProp($property, $value, $table_create_time = null) + { + if (! isset($this->uiprefs)) { + $this->loadUiPrefs(); + } + // we want to save the create time if the property is PROP_COLUMN_ORDER + if (! PMA_Table::isView($this->db_name, $this->name) + && ($property == self::PROP_COLUMN_ORDER + || $property == self::PROP_COLUMN_VISIB) + ) { + $curr_create_time = self::sGetStatusInfo( + $this->db_name, + $this->name, + 'CREATE_TIME' + ); + if (isset($table_create_time) + && $table_create_time == $curr_create_time + ) { + $this->uiprefs['CREATE_TIME'] = $curr_create_time; + } else { + // there is no $table_create_time, or + // supplied $table_create_time is older than current create time, + // so don't save + return PMA_Message::error( + sprintf( + __('Cannot save UI property "%s". The changes made will not be persistent after you refresh this page. Please check if the table structure has been changed.'), + $property + ) + ); + } + } + // save the value + $this->uiprefs[$property] = $value; + // check if pmadb is set + if (strlen($GLOBALS['cfg']['Server']['pmadb']) + && strlen($GLOBALS['cfg']['Server']['table_uiprefs']) + ) { + return $this->saveUiprefsToDb(); + } + return true; + } + + /** + * Remove a property from UI preferences. + * + * @param string $property the property + * + * @return true|PMA_Message + */ + public function removeUiProp($property) + { + if (! isset($this->uiprefs)) { + $this->loadUiPrefs(); + } + if (isset($this->uiprefs[$property])) { + unset($this->uiprefs[$property]); + // check if pmadb is set + if (strlen($GLOBALS['cfg']['Server']['pmadb']) + && strlen($GLOBALS['cfg']['Server']['table_uiprefs']) + ) { + return $this->saveUiprefsToDb(); + } + } + return true; + } + + /** + * Get all column names which are MySQL reserved words + * + * @return array + * @access public + */ + public function getReservedColumnNames() + { + $columns = $this->getColumns($backquoted = false); + $return = array(); + foreach ($columns as $column) { + $temp = explode('.', $column); + $column_name = $temp[2]; + if (PMA_SQP_isKeyWord($column_name)) { + $return[] = $column_name; + } + } + return $return; + } +} +?> diff --git a/phpmyadmin/libraries/TableSearch.class.php b/phpmyadmin/libraries/TableSearch.class.php new file mode 100644 index 000000000..d9bb83079 --- /dev/null +++ b/phpmyadmin/libraries/TableSearch.class.php @@ -0,0 +1,1229 @@ +_db = $db; + $this->_table = $table; + $this->_searchType = $searchType; + $this->_columnNames = array(); + $this->_columnNullFlags = array(); + $this->_columnTypes = array(); + $this->_columnCollations = array(); + $this->_geomColumnFlag = false; + $this->_foreigners = array(); + // Loads table's information + $this->_loadTableInfo(); + } + + /** + * Returns Column names array + * + * @return array column names + */ + public function getColumnNames() + { + return $this->_columnNames; + } + + /** + * Gets all the columns of a table along with their types, collations + * and whether null or not. + * + * @return void + */ + private function _loadTableInfo() + { + // Gets the list and number of columns + $columns = PMA_DBI_get_columns($this->_db, $this->_table, null, true); + // Get details about the geometry fucntions + $geom_types = PMA_Util::getGISDatatypes(); + + foreach ($columns as $row) { + // set column name + $this->_columnNames[] = $row['Field']; + + $type = $row['Type']; + // check whether table contains geometric columns + if (in_array($type, $geom_types)) { + $this->_geomColumnFlag = true; + } + // reformat mysql query output + if (strncasecmp($type, 'set', 3) == 0 + || strncasecmp($type, 'enum', 4) == 0 + ) { + $type = str_replace(',', ', ', $type); + } else { + // strip the "BINARY" attribute, except if we find "BINARY(" because + // this would be a BINARY or VARBINARY column type + if (! preg_match('@BINARY[\(]@i', $type)) { + $type = preg_replace('@BINARY@i', '', $type); + } + $type = preg_replace('@ZEROFILL@i', '', $type); + $type = preg_replace('@UNSIGNED@i', '', $type); + $type = strtolower($type); + } + if (empty($type)) { + $type = ' '; + } + $this->_columnTypes[] = $type; + $this->_columnNullFlags[] = $row['Null']; + $this->_columnCollations[] + = ! empty($row['Collation']) && $row['Collation'] != 'NULL' + ? $row['Collation'] + : ''; + } // end for + + // Retrieve foreign keys + $this->_foreigners = PMA_getForeigners($this->_db, $this->_table); + } + + /** + * Sets the table header for displaying a table in query-by-example format. + * + * @return HTML content, the tags and content for table header + */ + private function _getTableHeader() + { + // Display the Function column only if there is at least one geometry column + $func = ''; + if ($this->_geomColumnFlag) { + $func = '' . __('Function') . ''; + } + + return ' + ' . $func . '' . __('Column') . ' + ' . __('Type') . ' + ' . __('Collation') . ' + ' . __('Operator') . ' + ' . __('Value') . ' + + '; + } + + /** + * Returns an array with necessary configrations to create + * sub-tabs(Table Search and Zoom Search) in the table_select page. + * + * @return array Array containing configuration (icon, text, link, id, args) + * of sub-tabs for Table Search and Zoom search + */ + private function _getSubTabs() + { + $subtabs = array(); + $subtabs['search']['icon'] = 'b_search.png'; + $subtabs['search']['text'] = __('Table Search'); + $subtabs['search']['link'] = 'tbl_select.php'; + $subtabs['search']['id'] = 'tbl_search_id'; + $subtabs['search']['args']['pos'] = 0; + + $subtabs['zoom']['icon'] = 'b_props.png'; + $subtabs['zoom']['link'] = 'tbl_zoom_select.php'; + $subtabs['zoom']['text'] = __('Zoom Search'); + $subtabs['zoom']['id'] = 'zoom_search_id'; + + return $subtabs; + } + + /** + * Provides html elements for search criteria inputbox + * in case the column's type is geometrical + * + * @param int $column_index Column's index + * @param bool $in_fbs Whether we are in 'function based search' + * + * @return HTML elements. + */ + private function _getGeometricalInputBox($column_index, $in_fbs) + { + $html_output = ''; + + if ($in_fbs) { + $edit_url = 'gis_data_editor.php?' . PMA_generate_common_url(); + $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 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 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 ($func_type == 'IN (...)' + || $func_type == 'NOT IN (...)' + || $func_type == 'BETWEEN' + || $func_type == 'NOT BETWEEN' + ) { + $func_type = str_replace(' (...)', '', $func_type); + + // quote values one by one + $values = explode(',', $criteriaValues); + foreach ($values as &$value) { + $value = $quot . PMA_Util::sqlAddSlashes(trim($value)) + . $quot; + } + + if ($func_type == 'BETWEEN' || $func_type == 'NOT BETWEEN') { + $where = $backquoted_name . ' ' . $func_type . ' ' + . (isset($values[0]) ? $values[0] : '') + . ' AND ' . (isset($values[1]) ? $values[1] : ''); + } else { + $where = $backquoted_name . ' ' . $func_type + . ' (' . implode(',', $values) . ')'; + } + } 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( + 'SQL-Syntax', '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 = ($this->_searchType == 'zoom' ? 'tbl_zoom_select.php' : 'tbl_select.php'); + $formId = ($this->_searchType == 'zoom' ? 'zoom_search_form' : 'tbl_search_form'); + + $html_output .= '
      '; + + $html_output .= PMA_generate_common_hidden_inputs($this->_db, $this->_table); + $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) + { + $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 .= '
      '; + + $html_output .= $this->_getFormTag($goto); + + if ($this->_searchType == 'zoom') { + $html_output .= ''; + } else { + $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_generate_common_hidden_inputs($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; + } +} +?> diff --git a/phpmyadmin/libraries/Theme.class.php b/phpmyadmin/libraries/Theme.class.php new file mode 100644 index 000000000..bf1ee8f6f --- /dev/null +++ b/phpmyadmin/libraries/Theme.class.php @@ -0,0 +1,601 @@ +getPath() . '/info.inc.php')) { + return false; + } + + if ($this->mtime_info === filemtime($this->getPath() . '/info.inc.php')) { + return true; + } + + @include $this->getPath() . '/info.inc.php'; + + // was it set correctly? + if (! isset($theme_name)) { + return false; + } + + $this->mtime_info = filemtime($this->getPath() . '/info.inc.php'); + $this->filesize_info = filesize($this->getPath() . '/info.inc.php'); + + if (isset($theme_full_version)) { + $this->setVersion($theme_full_version); + } elseif (isset($theme_generation, $theme_version)) { + $this->setVersion($theme_generation . '.' . $theme_version); + } + $this->setName($theme_name); + + return true; + } + + /** + * returns theme object loaded from given folder + * or false if theme is invalid + * + * @param string $folder path to theme + * + * @return object PMA_Theme + * @static + * @access public + */ + static public function load($folder) + { + $theme = new PMA_Theme(); + + $theme->setPath($folder); + + if (! $theme->loadInfo()) { + return false; + } + + $theme->checkImgPath(); + + return $theme; + } + + /** + * checks image path for existance - if not found use img from fallback theme + * + * @access public + * @return bool + */ + public function checkImgPath() + { + // try current theme first + if (is_dir($this->getPath() . '/img/')) { + $this->setImgPath($this->getPath() . '/img/'); + return true; + } + + // try fallback theme + $fallback = $GLOBALS['cfg']['ThemePath'] . '/' + . PMA_Theme_Manager::FALLBACK_THEME + . '/img/'; + if (is_dir($fallback)) { + $this->setImgPath($fallback); + return true; + } + + // 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 to theme + */ + public function getPath() + { + return $this->path; + } + + /** + * returns layout file + * + * @access public + * @return string layout file + */ + public function getLayoutFile() + { + return $this->getPath() . '/layout.inc.php'; + } + + /** + * set path to theme + * + * @param string $path path to theme + * + * @return void + * @access public + */ + public function setPath($path) + { + $this->path = trim($path); + } + + /** + * sets version + * + * @param string $version version to set + * + * @return void + * @access public + */ + public function setVersion($version) + { + $this->version = trim($version); + } + + /** + * returns version + * + * @return string version + * @access public + */ + public function getVersion() + { + return $this->version; + } + + /** + * checks theme version agaisnt $version + * returns true if theme version is equal or higher to $version + * + * @param string $version version to compare to + * + * @return boolean true if theme version is equal or higher to $version + * @access public + */ + public function checkVersion($version) + { + return version_compare($this->getVersion(), $version, 'lt'); + } + + /** + * sets name + * + * @param string $name name to set + * + * @return void + * @access public + */ + public function setName($name) + { + $this->name = trim($name); + } + + /** + * returns name + * + * @access public + * @return string name + */ + public function getName() + { + return $this->name; + } + + /** + * sets id + * + * @param string $id new id + * + * @return void + * @access public + */ + public function setId($id) + { + $this->id = trim($id); + } + + /** + * returns id + * + * @return string id + * @access public + */ + public function getId() + { + return $this->id; + } + + /** + * Sets path to images for the theme + * + * @param string $path path to images for this theme + * + * @return void + * @access public + */ + public function setImgPath($path) + { + $this->img_path = $path; + } + + /** + * 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 + */ + public function getImgPath($file = null) + { + 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; + } + } + } + + /** + * Builds a CSS rule used for html formatted SQL queries + * + * @param string $classname The class name + * @param string $property The property name + * @param string $value The property value + * + * @return string The CSS rule + * + * @access public + * + * @see PMA_SQP_buildCssData() + */ + public function buildSQPCssRule($classname, $property, $value) + { + $str = '.' . $classname . ' {'; + if ($value != '') { + $str .= $property . ': ' . $value . ';'; + } + $str .= '}' . "\n"; + + return $str; + } // end of the "PMA_SQP_buildCssRule()" function + + + /** + * Builds CSS rules used for html formatted SQL queries + * + * @return string The CSS rules set + * + * @access public + * + * @global array The current PMA configuration + * + * @see PMA_SQP_buildCssRule() + */ + public function buildSQPCssData() + { + global $cfg; + + $css_string = ''; + foreach ($cfg['SQP']['fmtColor'] AS $key => $col) { + $css_string .= $this->buildSQPCssRule('syntax_' . $key, 'color', $col); + } + + for ($i = 0; $i < 8; $i++) { + $css_string .= $this->buildSQPCssRule( + 'syntax_indent' . $i, 'margin-left', + ($i * $cfg['SQP']['fmtInd']) . $cfg['SQP']['fmtIndUnit'] + ); + } + + return $css_string; + } // end of the "PMA_SQP_buildCssData()" function + + /** + * load css (send to stdout, normally the browser) + * + * @return bool + * @access public + */ + public function loadCss() + { + $success = true; + + echo $this->buildSQPCssData(); + + if ($GLOBALS['text_dir'] === 'ltr') { + $right = 'right'; + $left = 'left'; + } else { + $right = 'left'; + $left = 'right'; + } + + 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; + } + } + + include './themes/sprites.css.php'; + + return $success; + } + + /** + * Renders the preview for this theme + * + * @return string + * @access public + */ + public function getPrintPreview() + { + $url_params = array('set_theme' => $this->getId()); + $url = 'index.php'. PMA_generate_common_url($url_params); + + $retval = ''; + return $retval; + } + + /** + * Remove filter for IE. + * + * @return string CSS code. + */ + 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. + * + * @param string $start_color Color of gradient start, hex value without # + * @param string $end_color Color of gradient end, hex value without # + * + * @return string CSS code. + */ + 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-size: 100% 100%;'; + // Safari 4-5, Chrome 1-9 + $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 . ');'; + // Firefox 3.6+ + $result[] = 'background: -moz-linear-gradient(top, #' + . $start_color . ', #' . $end_color . ');'; + // IE 10 + $result[] = 'background: -ms-linear-gradient(top, #' + . $start_color . ', #' . $end_color . ');'; + // Opera 11.10 + $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 . '");'; + } + return implode("\n", $result); + } + + /** + * Returns CSS styles for CodeMirror editor based on query formatter colors. + * + * @return string CSS code. + */ + function getCssCodeMirror() + { + if (! $GLOBALS['cfg']['CodemirrorEnable']) { + return ''; + } + + $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 new file mode 100644 index 000000000..752051651 --- /dev/null +++ b/phpmyadmin/libraries/Theme_Manager.class.php @@ -0,0 +1,453 @@ +init(); + } + + /** + * sets path to folder containing the themes + * + * @param string $path path to themes folder + * + * @access public + * @return boolean success + */ + public function setThemesPath($path) + { + if (! $this->_checkThemeFolder($path)) { + return false; + } + + $this->_themes_path = trim($path); + return true; + } + + /** + * Returns path to folder containing themes + * + * @access public + * @return string theme path + */ + public function getThemesPath() + { + return $this->_themes_path; + } + + /** + * sets if there are different themes per server + * + * @param boolean $per_server + * + * @access public + * @return void + */ + public function setThemePerServer($per_server) + { + $this->per_server = (bool) $per_server; + } + + /** + * Initialise the class + * + * @access public + * @return void + */ + public function init() + { + $this->themes = array(); + $this->theme_default = self::FALLBACK_THEME; + $this->active_theme = ''; + + if (! $this->setThemesPath($GLOBALS['cfg']['ThemePath'])) { + return false; + } + + $this->setThemePerServer($GLOBALS['cfg']['ThemePerServer']); + + $this->loadThemes(); + + $this->theme = new PMA_Theme; + + + if (! $this->checkTheme($GLOBALS['cfg']['ThemeDefault'])) { + trigger_error( + sprintf( + __('Default theme %s not found!'), + htmlspecialchars($GLOBALS['cfg']['ThemeDefault']) + ), + E_USER_ERROR + ); + $GLOBALS['cfg']['ThemeDefault'] = false; + } + + $this->theme_default = $GLOBALS['cfg']['ThemeDefault']; + + // check if user have a theme cookie + if (! $this->getThemeCookie() + || ! $this->setActiveTheme($this->getThemeCookie()) + ) { + if ($GLOBALS['cfg']['ThemeDefault']) { + // otherwise use default theme + $this->setActiveTheme($this->theme_default); + } else { + // or fallback theme + $this->setActiveTheme(self::FALLBACK_THEME); + } + } + } + + /** + * Checks configuration + * + * @access public + * @return void + */ + public function checkConfig() + { + if ($this->_themes_path != trim($GLOBALS['cfg']['ThemePath']) + || $this->theme_default != $GLOBALS['cfg']['ThemeDefault'] + ) { + $this->init(); + } else { + // at least the theme path needs to be checked every time for new + // themes, as there is no other way at the moment to keep track of + // new or removed themes + $this->loadThemes(); + } + } + + /** + * 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( + sprintf( + __('Theme %s not found!'), + htmlspecialchars($theme) + ), + E_USER_ERROR + ); + return false; + } + + $this->active_theme = $theme; + $this->theme = $this->themes[$theme]; + + // need to set later + //$this->setThemeCookie(); + + return true; + } + + /** + * + * @return string cookie name + * @access public + */ + public function getThemeCookieName() + { + // Allow different theme per server + if (isset($GLOBALS['server']) && $this->per_server) { + return $this->cookie_name . '-' . $GLOBALS['server']; + } else { + return $this->cookie_name; + } + } + + /** + * returns name of theme stored in the cookie + * + * @return string theme name from cookie + * @access public + */ + public function getThemeCookie() + { + if (isset($_COOKIE[$this->getThemeCookieName()])) { + return $_COOKIE[$this->getThemeCookieName()]; + } + + return false; + } + + /** + * save theme in cookie + * + * @return bool true + * @access public + */ + public function setThemeCookie() + { + $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); + return true; + } + + /** + * @param string $folder + * + * @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 + ); + return false; + } + + return true; + } + + /** + * read all themes + * + * @return bool true + * @access public + */ + public function loadThemes() + { + $this->themes = array(); + + if ($handleThemes = opendir($this->getThemesPath())) { + // 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) + ) { + continue; + } + if (array_key_exists($PMA_Theme, $this->themes)) { + continue; + } + $new_theme = PMA_Theme::load( + $this->getThemesPath() . '/' . $PMA_Theme + ); + if ($new_theme) { + $new_theme->setId($PMA_Theme); + $this->themes[$PMA_Theme] = $new_theme; + } + } // end get themes + closedir($handleThemes); + } else { + trigger_error( + 'phpMyAdmin-ERROR: cannot open themes folder: ' . $this->getThemesPath(), + E_USER_WARNING + ); + return false; + } // end check for themes directory + + ksort($this->themes); + return true; + } + + /** + * checks if given theme name is a known theme + * + * @param string $theme name fo theme to check for + * + * @return bool + * @access public + */ + public function checkTheme($theme) + { + if (! array_key_exists($theme, $this->themes)) { + return false; + } + + return true; + } + + /** + * returns HTML selectbox, with or without form enclosed + * + * @param boolean $form whether enclosed by from tags or not + * + * @return string + * @access public + */ + public function getHtmlSelectBox($form = true) + { + $select_box = ''; + + if ($form) { + $select_box .= '
      '; + $select_box .= $theme_preview_href . __('Theme') . ':' . "\n"; + + $select_box .= ''; + + if ($form) { + $select_box .= '
      '; + } + + return $select_box; + } + + /** + * enables backward compatibility + * + * @return void + * @access public + */ + public function makeBc() + { + $GLOBALS['theme'] = $this->theme->getId(); + $GLOBALS['pmaThemePath'] = $this->theme->getPath(); + $GLOBALS['pmaThemeImage'] = $this->theme->getImgPath(); + + /** + * load layout file if exists + */ + if (file_exists($this->theme->getLayoutFile())) { + include $this->theme->getLayoutFile(); + } + } + + /** + * Renders the previews for all themes + * + * @return string + * @access public + */ + public function getPrintPreviews() + { + $retval = ''; + foreach ($this->themes as $each_theme) { + $retval .= $each_theme->getPrintPreview(); + } // end 'open themes' + return $retval; + } + + /** + * returns PMA_Theme object for fall back theme + * + * @return object PMA_Theme + * @access public + */ + public function getFallBackTheme() + { + if (isset($this->themes[self::FALLBACK_THEME])) { + return $this->themes[self::FALLBACK_THEME]; + } + + return false; + } + + /** + * prints css data + * + * @return bool + * @access public + */ + public function printCss() + { + 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()) { + return true; + } + + return false; + } +} +?> diff --git a/phpmyadmin/libraries/Tracker.class.php b/phpmyadmin/libraries/Tracker.class.php new file mode 100644 index 000000000..4e67c08a2 --- /dev/null +++ b/phpmyadmin/libraries/Tracker.class.php @@ -0,0 +1,1079 @@ + $export_type, + 'single_table' => isset($single_table) + ) + ); + + $sql_backquotes = true; + + $date = date('Y-m-d H:i:s'); + + // Get data definition snapshot of table + + $columns = PMA_DBI_get_columns($dbname, $tablename, null, true); + // int indices to reduce size + $columns = array_values($columns); + // remove Privileges to reduce size + for ($i = 0; $i < count($columns); $i++) { + unset($columns[$i]['Privileges']); + } + + $indexes = PMA_DBI_get_table_indexes($dbname, $tablename); + + $snapshot = array('COLUMNS' => $columns, 'INDEXES' => $indexes); + $snapshot = serialize($snapshot); + + // Get DROP TABLE / DROP VIEW and CREATE TABLE SQL statements + $sql_backquotes = true; + + $create_sql = ""; + + if (self::$add_drop_table == true && $is_view == false) { + $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_Util::backquote($tablename) . ";\n"; + } + + $create_sql .= self::getLogComment() . + $export_sql_plugin->getTableDef($dbname, $tablename, "\n", ""); + + // Save version + + $sql_query = "/*NOTRACK*/\n" . + "INSERT INTO" . self::$pma_table . " (" . + "db_name, " . + "table_name, " . + "version, " . + "date_created, " . + "date_updated, " . + "schema_snapshot, " . + "schema_sql, " . + "data_sql, " . + "tracking " . + ") " . + "values ( + '" . 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 + self::deactivateTracking($dbname, $tablename, ($version - 1)); + } + + return $result; + } + + + /** + * Removes all tracking data for a table + * + * @param string $dbname name of database + * @param string $tablename name of table + * + * @static + * + * @return int result of version insertion + */ + static public function deleteTracking($dbname, $tablename) + { + $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; + } + + /** + * Creates tracking version of a database + * (in other words: create a job to track future changes on the database). + * + * @param string $dbname name of database + * @param string $version version + * @param string $query query + * @param string $tracking_set set of tracking statements + * + * @static + * + * @return int result of version insertion + */ + 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_Util::backquote($dbname) . ";\n"; + } + + $create_sql .= self::getLogComment() . $query; + + // Save version + $sql_query = "/*NOTRACK*/\n" . + "INSERT INTO" . self::$pma_table . " (" . + "db_name, " . + "table_name, " . + "version, " . + "date_created, " . + "date_updated, " . + "schema_snapshot, " . + "schema_sql, " . + "data_sql, " . + "tracking " . + ") " . + "values ( + '" . 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; + } + + + + /** + * Changes tracking of a table. + * + * @param string $dbname name of database + * @param string $tablename name of table + * @param string $version version + * @param integer $new_state the new state of tracking + * + * @static + * + * @return int result of SQL query + */ + static private function _changeTracking($dbname, $tablename, + $version, $new_state + ) { + + $sql_query = " UPDATE " . self::$pma_table . + " SET `tracking_active` = '" . $new_state . "' " . + " WHERE `db_name` = '" . PMA_Util::sqlAddSlashes($dbname) . "' " . + " AND `table_name` = '" . PMA_Util::sqlAddSlashes($tablename) . "' " . + " AND `version` = '" . PMA_Util::sqlAddSlashes($version) . "' "; + + $result = PMA_queryAsControlUser($sql_query); + + return $result; + } + + /** + * Changes tracking data of a table. + * + * @param string $dbname name of database + * @param string $tablename name of table + * @param string $version version + * @param string $type type of data(DDL || DML) + * @param string|array $new_data the new tracking data + * + * @static + * + * @return bool result of change + */ + static public function changeTrackingData($dbname, $tablename, + $version, $type, $new_data + ) { + if ($type == 'DDL') { + $save_to = 'schema_sql'; + } elseif ($type == 'DML') { + $save_to = 'data_sql'; + } else { + return false; + } + $date = date('Y-m-d H:i:s'); + + $new_data_processed = ''; + if (is_array($new_data)) { + foreach ($new_data as $data) { + $new_data_processed .= '# log ' . $date . ' ' . $data['username'] + . PMA_Util::sqlAddSlashes($data['statement']) . "\n"; + } + } else { + $new_data_processed = $new_data; + } + + $sql_query = " UPDATE " . self::$pma_table . + " SET `" . $save_to . "` = '" . $new_data_processed . "' " . + " WHERE `db_name` = '" . PMA_Util::sqlAddSlashes($dbname) . "' " . + " AND `table_name` = '" . PMA_Util::sqlAddSlashes($tablename) . "' " . + " AND `version` = '" . PMA_Util::sqlAddSlashes($version) . "' "; + + $result = PMA_queryAsControlUser($sql_query); + + return $result; + } + + /** + * Activates tracking of a table. + * + * @param string $dbname name of database + * @param string $tablename name of table + * @param string $version version + * + * @static + * + * @return int result of SQL query + */ + static public function activateTracking($dbname, $tablename, $version) + { + return self::_changeTracking($dbname, $tablename, $version, 1); + } + + + /** + * Deactivates tracking of a table. + * + * @param string $dbname name of database + * @param string $tablename name of table + * @param string $version version + * + * @static + * + * @return int result of SQL query + */ + static public function deactivateTracking($dbname, $tablename, $version) + { + return self::_changeTracking($dbname, $tablename, $version, 0); + } + + + /** + * Gets the newest version of a tracking job + * (in other words: gets the HEAD version). + * + * @param string $dbname name of database + * @param string $tablename name of table + * @param string $statement tracked statement + * + * @static + * + * @return int (-1 if no version exists | > 0 if a version exists) + */ + static public function getVersion($dbname, $tablename, $statement = null) + { + $sql_query = " SELECT MAX(version) FROM " . self::$pma_table . + " 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" ; + } + $row = PMA_DBI_fetch_array(PMA_queryAsControlUser($sql_query)); + return isset($row[0]) + ? $row[0] + : -1; + } + + + /** + * Gets the record of a tracking job. + * + * @param string $dbname name of database + * @param string $tablename name of table + * @param string $version version number + * + * @static + * + * @return mixed record DDM log, DDL log, structure snapshot, tracked statements. + */ + static public function getTrackedData($dbname, $tablename, $version) + { + if (! isset(self::$pma_table)) { + self::init(); + } + $sql_query = " SELECT * FROM " . self::$pma_table . + " WHERE `db_name` = '" . PMA_Util::sqlAddSlashes($dbname) . "' "; + if (! empty($tablename)) { + $sql_query .= " AND `table_name` = '" + . PMA_Util::sqlAddSlashes($tablename) ."' "; + } + $sql_query .= " AND `version` = '" . PMA_Util::sqlAddSlashes($version) ."' ". + " ORDER BY `version` DESC LIMIT 1"; + + $mixed = PMA_DBI_fetch_assoc(PMA_queryAsControlUser($sql_query)); + + // Parse log + $log_schema_entries = explode('# log ', $mixed['schema_sql']); + $log_data_entries = explode('# log ', $mixed['data_sql']); + + $ddl_date_from = $date = date('Y-m-d H:i:s'); + + $ddlog = array(); + $i = 0; + + // Iterate tracked data definition statements + // For each log entry we want to get date, username and statement + foreach ($log_schema_entries as $log_entry) { + if (trim($log_entry) != '') { + $date = substr($log_entry, 0, 19); + $username = substr($log_entry, 20, strpos($log_entry, "\n") - 20); + if ($i == 0) { + $ddl_date_from = $date; + } + $statement = rtrim(strstr($log_entry, "\n")); + + $ddlog[] = array( 'date' => $date, + 'username'=> $username, + 'statement' => $statement ); + $i++; + } + } + + $date_from = $ddl_date_from; + $date_to = $ddl_date_to = $date; + + $dml_date_from = $date_from; + + $dmlog = array(); + $i = 0; + + // Iterate tracked data manipulation statements + // For each log entry we want to get date, username and statement + foreach ($log_data_entries as $log_entry) { + if (trim($log_entry) != '') { + $date = substr($log_entry, 0, 19); + $username = substr($log_entry, 20, strpos($log_entry, "\n") - 20); + if ($i == 0) { + $dml_date_from = $date; + } + $statement = rtrim(strstr($log_entry, "\n")); + + $dmlog[] = array( 'date' => $date, + 'username' => $username, + 'statement' => $statement ); + $i++; + } + } + + $dml_date_to = $date; + + // Define begin and end of date range for both logs + if (strtotime($ddl_date_from) <= strtotime($dml_date_from)) { + $data['date_from'] = $ddl_date_from; + } else { + $data['date_from'] = $dml_date_from; + } + if (strtotime($ddl_date_to) >= strtotime($dml_date_to)) { + $data['date_to'] = $ddl_date_to; + } else { + $data['date_to'] = $dml_date_to; + } + $data['ddlog'] = $ddlog; + $data['dmlog'] = $dmlog; + $data['tracking'] = self::_transformTrackingSet($mixed['tracking']); + $data['schema_snapshot'] = $mixed['schema_snapshot']; + + return $data; + } + + + /** + * Parses a query. Gets + * - statement identifier (UPDATE, ALTER TABLE, ...) + * - type of statement, is it part of DDL or DML ? + * - tablename + * + * @param string $query query + * + * @static + * @todo: using PMA SQL Parser when possible + * @todo: support multi-table/view drops + * + * @return mixed Array containing identifier, type and tablename. + * + */ + static public function parseQuery($query) + { + + // Usage of PMA_SQP does not work here + // + // require_once("libraries/sqlparser.lib.php"); + // $parsed_sql = PMA_SQP_parse($query); + // $sql_info = PMA_SQP_analyze($parsed_sql); + + $query = str_replace("\n", " ", $query); + $query = str_replace("\r", " ", $query); + + $query = trim($query); + $query = trim($query, ' -'); + + $tokens = explode(" ", $query); + foreach ($tokens as $key => $value) { + $tokens[$key] = strtoupper($value); + } + + // Parse USE statement, need it for SQL dump imports + if (substr($query, 0, 4) == 'USE ') { + $prefix = explode('USE ', $query); + $GLOBALS['db'] = self::getTableName($prefix[1]); + } + + /* + * DDL statements + */ + + $result['type'] = 'DDL'; + + // Parse CREATE VIEW statement + if (in_array('CREATE', $tokens) == true + && in_array('VIEW', $tokens) == true + && in_array('AS', $tokens) == true + ) { + $result['identifier'] = 'CREATE VIEW'; + + $index = array_search('VIEW', $tokens); + + $result['tablename'] = strtolower( + self::getTableName($tokens[$index + 1]) + ); + } + + // Parse ALTER VIEW statement + if (in_array('ALTER', $tokens) == true + && in_array('VIEW', $tokens) == true + && in_array('AS', $tokens) == true + && ! isset($result['identifier']) + ) { + $result['identifier'] = 'ALTER VIEW'; + + $index = array_search('VIEW', $tokens); + + $result['tablename'] = strtolower( + self::getTableName($tokens[$index + 1]) + ); + } + + // Parse DROP VIEW statement + if (! isset($result['identifier']) + && substr($query, 0, 10) == 'DROP VIEW ' + ) { + $result['identifier'] = 'DROP VIEW'; + + $prefix = explode('DROP VIEW ', $query); + $str = strstr($prefix[1], 'IF EXISTS'); + + if ($str == false ) { + $str = $prefix[1]; + } + $result['tablename'] = self::getTableName($str); + } + + // Parse CREATE DATABASE statement + 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); + + $prefix = explode('DEFAULT ', $str); + + $result['tablename'] = ''; + $GLOBALS['db'] = self::getTableName($prefix[0]); + } + + // Parse ALTER DATABASE statement + 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' + ) { + $result['identifier'] = 'DROP DATABASE'; + $str = str_replace('DROP DATABASE', '', $query); + $str = str_replace('IF EXISTS', '', $str); + $GLOBALS['db'] = self::getTableName($str); + $result['tablename'] = ''; + } + + // Parse CREATE TABLE statement + 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); + $suffix = explode('(', $prefix[1]); + $result['tablename'] = self::getTableName($suffix[0]); + } + + // Parse ALTER TABLE statement + if (! isset($result['identifier']) + && substr($query, 0, 12) == 'ALTER TABLE ' + ) { + $result['identifier'] = 'ALTER TABLE'; + + $prefix = explode('ALTER TABLE ', $query); + $suffix = explode(' ', $prefix[1]); + $result['tablename'] = self::getTableName($suffix[0]); + } + + // Parse DROP TABLE statement + if (! isset($result['identifier']) + && substr($query, 0, 11) == 'DROP TABLE ' + ) { + $result['identifier'] = 'DROP TABLE'; + + $prefix = explode('DROP TABLE ', $query); + $str = strstr($prefix[1], 'IF EXISTS'); + + if ($str == false ) { + $str = $prefix[1]; + } + $result['tablename'] = self::getTableName($str); + } + + // Parse CREATE INDEX statement + if (! isset($result['identifier']) + && (substr($query, 0, 12) == 'CREATE INDEX' + || substr($query, 0, 19) == 'CREATE UNIQUE INDEX' + || substr($query, 0, 20) == 'CREATE SPATIAL INDEX') + ) { + $result['identifier'] = 'CREATE INDEX'; + $prefix = explode('ON ', $query); + $suffix = explode('(', $prefix[1]); + $result['tablename'] = self::getTableName($suffix[0]); + } + + // Parse DROP INDEX statement + 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 ' + ) { + $result['identifier'] = 'RENAME TABLE'; + $prefix = explode('RENAME TABLE ', $query); + $names = explode(' TO ', $prefix[1]); + $result['tablename'] = self::getTableName($names[0]); + $result["tablename_after_rename"] = self::getTableName($names[1]); + } + + /* + * DML statements + */ + + if (! isset($result['identifier'])) { + $result["type"] = 'DML'; + } + // Parse UPDATE statement + if (! isset($result['identifier']) + && substr($query, 0, 6) == 'UPDATE' + ) { + $result['identifier'] = 'UPDATE'; + $prefix = explode('UPDATE ', $query); + $suffix = explode(' ', $prefix[1]); + $result['tablename'] = self::getTableName($suffix[0]); + } + + // Parse INSERT INTO statement + if (! isset($result['identifier']) + && substr($query, 0, 11) == 'INSERT INTO' + ) { + $result['identifier'] = 'INSERT'; + $prefix = explode('INSERT INTO', $query); + $suffix = explode('(', $prefix[1]); + $result['tablename'] = self::getTableName($suffix[0]); + } + + // Parse DELETE statement + if (! isset($result['identifier']) + && substr($query, 0, 6) == 'DELETE' + ) { + $result['identifier'] = 'DELETE'; + $prefix = explode('FROM ', $query); + $suffix = explode(' ', $prefix[1]); + $result['tablename'] = self::getTableName($suffix[0]); + } + + // Parse TRUNCATE statement + if (! isset($result['identifier']) + && substr($query, 0, 8) == 'TRUNCATE' + ) { + $result['identifier'] = 'TRUNCATE'; + $prefix = explode('TRUNCATE', $query); + $result['tablename'] = self::getTableName($prefix[1]); + } + + return $result; + } + + + /** + * Analyzes a given SQL statement and saves tracking data. + * + * @param string $query a SQL query + * + * @static + * + * @return void + */ + static public function handleQuery($query) + { + // If query is marked as untouchable, leave + if (strstr($query, "/*NOTRACK*/")) { + return; + } + + if (! (substr($query, -1) == ';')) { + $query = $query . ";\n"; + } + // Get some information about query + $result = self::parseQuery($query); + + // Get database name + $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'] + ); + + // If version not exists and auto-creation is enabled + if (self::$version_auto_create == true + && self::isTracked($dbname, $result['tablename']) == false + && $version == -1 + ) { + // Create the version + + switch ($result['identifier']) { + case 'CREATE TABLE': + self::createVersion($dbname, $result['tablename'], '1'); + break; + case 'CREATE VIEW': + self::createVersion( + $dbname, $result['tablename'], '1', '', true + ); + break; + case 'CREATE DATABASE': + self::createDatabaseVersion($dbname, '1', $query); + break; + } // end switch + } + + // If version exists + if (self::isTracked($dbname, $result['tablename']) && $version != -1) { + if ($result['type'] == 'DDL') { + $save_to = 'schema_sql'; + } elseif ($result['type'] == 'DML') { + $save_to = 'data_sql'; + } else { + $save_to = ''; + } + $date = date('Y-m-d H:i:s'); + + // Cut off `dbname`. from query + $query = preg_replace('/`' . $dbname . '`\s?\./', '', $query); + + // Add log information + $query = self::getLogComment() . $query ; + + // Mark it as untouchable + $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_Util::sqlAddSlashes($result['tablename_after_rename']) + . '\' '; + } + + // Save the tracking information only for + // 1. the database + // 2. the table / view + // 3. the statements + // we want to track + $sql_query .= + " WHERE FIND_IN_SET('" . $result['identifier'] . "',tracking) > 0" . + " AND `db_name` = '" . PMA_Util::sqlAddSlashes($dbname) . "' " . + " AND `table_name` = '" . PMA_Util::sqlAddSlashes($result['tablename']) . "' " . + " AND `version` = '" . PMA_Util::sqlAddSlashes($version) . "' "; + + $result = PMA_queryAsControlUser($sql_query); + } + } + } + + /** + * Transforms tracking set for Drizzle, which has no SET type + * + * Converts int<>string for Drizzle, does nothing for MySQL + * + * @param int|string $tracking_set + * + * @return int|string + */ + 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])) { + // initialize 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; + } + + 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++) { + $flag = 1 << $i; + if ($tracking_set & $flag) { + $aflags[] = self::$_tracking_set_flags[$flag]; + } + } + $flags = implode(',', $aflags); + } else { + // string > int conversion + $flags = 0; + foreach (explode(',', $tracking_set) as $strflag) { + if ($strflag == '') { + continue; + } + $flags |= self::$_tracking_set_flags[$strflag]; + } + } + + return $flags; + } +} +?> diff --git a/phpmyadmin/libraries/Types.class.php b/phpmyadmin/libraries/Types.class.php new file mode 100644 index 000000000..81e037e1f --- /dev/null +++ b/phpmyadmin/libraries/Types.class.php @@ -0,0 +1,984 @@ +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) { + $html .= ''; + } else { + $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( + '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 = PMA_DBI_fetch_result($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 000000000..3468776a4 --- /dev/null +++ b/phpmyadmin/libraries/Util.class.php @@ -0,0 +1,4098 @@ +'; + 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 + if (is_readable($_SESSION['PMA_Theme']->getPath() . '/sprites.lib.php')) { + include_once $_SESSION['PMA_Theme']->getPath() . '/sprites.lib.php'; + $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 mixed $parsed_sql pre-parsed SQL structure + * @param string $unparsed_sql raw SQL string + * + * @return string the formatted sql + * + * @global array the configuration array + * @global boolean whether the current statement is a multiple one or not + * + * @access public + * @todo move into PMA_Sql + */ + public static function formatSql($parsed_sql, $unparsed_sql = '') + { + global $cfg; + + // Check that we actually have a valid set of parsed data + // well, not quite + // first check for the SQL parser having hit an error + if (PMA_SQP_isError()) { + return htmlspecialchars($parsed_sql['raw']); + } + // then check for an array + if (! is_array($parsed_sql)) { + // We don't so just return the input directly + // This is intended to be used for when the SQL Parser is turned off + $formatted_sql = "
      \n";
      +            if (($cfg['SQP']['fmtType'] == 'none') && ($unparsed_sql != '')) {
      +                $formatted_sql .= $unparsed_sql;
      +            } else {
      +                $formatted_sql .= $parsed_sql;
      +            }
      +            $formatted_sql .= "\n
      "; + return $formatted_sql; + } + + $formatted_sql = ''; + + switch ($cfg['SQP']['fmtType']) { + case 'none': + if ($unparsed_sql != '') { + $formatted_sql = '
      ' . "\n"
      +                    . PMA_SQP_formatNone(array('raw' => $unparsed_sql)) . "\n"
      +                    . '
      '; + } else { + $formatted_sql = PMA_SQP_formatNone($parsed_sql); + } + break; + case 'html': + $formatted_sql = PMA_SQP_formatHtml($parsed_sql, 'color'); + break; + case 'text': + $formatted_sql = PMA_SQP_formatHtml($parsed_sql, 'text'); + break; + default: + break; + } // end switch + + return $formatted_sql; + } // 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 + + /** + * Displays a link to the official MySQL documentation + * + * @param string $chapter chapter of "HTML, one page per chapter" 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( + $chapter, $link, $big_icon = false, $anchor = '', $just_open = false + ) { + global $cfg; + + if (($cfg['MySQLManualType'] == 'none') || empty($cfg['MySQLManualBase'])) { + return ''; + } + + // Fixup for newly used names: + $chapter = str_replace('_', '-', strtolower($chapter)); + $link = str_replace('_', '-', strtolower($link)); + + switch ($cfg['MySQLManualType']) { + case 'chapters': + if (empty($chapter)) { + $chapter = 'index'; + } + if (empty($anchor)) { + $anchor = $link; + } + $url = $cfg['MySQLManualBase'] . '/' . $chapter . '.html#' . $anchor; + break; + case 'big': + if (empty($anchor)) { + $anchor = $link; + } + $url = $cfg['MySQLManualBase'] . '#' . $anchor; + break; + case 'searchable': + if (empty($link)) { + $link = 'index'; + } + $url = $cfg['MySQLManualBase'] . '/' . $link . '.html'; + if (! empty($anchor)) { + $url .= '#' . $anchor; + } + break; + case 'viewable': + default: + 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 = $cfg['MySQLManualBase'] + . '/' . $mysql . '/' . $lang . '/' . $link . '.html'; + if (! empty($anchor)) { + $url .= '#' . $anchor; + } + break; + } + + $open_link = ''; + if ($just_open) { + return $open_link; + } elseif ($big_icon) { + return $open_link + . self::getImage('b_sqlhelp.png', __('Documentation')) . ''; + } else { + return self::showDocLink(PMA_linkURL($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 the curent table + * @global string 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 = PMA_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 { + if (strlen($the_query) > $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) { + $formatted_sql = htmlspecialchars( + substr( + $the_query, 0, + $GLOBALS['cfg']['MaxCharactersInDisplayedSQL'] + ) + ) + . '[...]'; + } else { + $formatted_sql = self::formatSql( + PMA_SQP_parse($the_query), $the_query + ); + } + } + // --- + $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('SQL-Syntax', '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', '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 ($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 = PMA_DBI_get_tables_full( + $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 || PMA_is_system_schema($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 ($cfg['SQP']['fmtType'] == 'none' + && ! 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($parsed_sql)) { + $query_base = self::formatSql($parsed_sql, $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 = false; + 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 (preg_match('@^SELECT[[:space:]]+@i', $sql_query)) { + $explain_params['sql_query'] = 'EXPLAIN ' . $sql_query; + $_message = __('Explain SQL'); + $is_select = true; + } 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_generate_common_url($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_generate_common_url($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_generate_common_url($php_params); + $php_link = ' [' . self::linkOrButton($php_link, $_message) . ']'; + + if (isset($GLOBALS['show_as_php'])) { + + $runquery_link = 'import.php' + . PMA_generate_common_url($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_generate_common_url($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_generate_common_url($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 .= '";'; + } + if (! empty($GLOBALS['validatequery'])) { + $retval .= '
      '; + } else { + $retval .= ''; + } + + $retval .= '
      '; + // avoid displaying a Profiling checkbox that could + // be checked, which would reexecute an INSERT, for example + if (! empty($refresh_link)) { + $retval .= self::getProfilingForm($sql_query); + } + // if needed, generate an invisible form that contains controls for the + // Inline link; this way, the behavior of the Inline link does not + // depend on the profiling support or on the refresh link + if (empty($refresh_link) || !self::profilingSupported()) { + $retval .= '
      '; + $retval .= PMA_generate_common_hidden_inputs( + $GLOBALS['db'], $GLOBALS['table'] + ); + $retval .= ''; + $retval .= '
      '; + } + + // in the tools div, only display the Inline link when not in ajax + // mode because 1) it currently does not work and 2) we would + // have two similar mechanisms on the page for the same goal + if ($is_select || ($GLOBALS['is_ajax_request'] === false) + && ! $query_too_big + ) { + // see in js/functions.js the jQuery code attached to id inline_edit + // document.write conflicts with jQuery, hence used $().append() + $retval .= ""; + } + $retval .= $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) + && PMA_DBI_fetch_value("SHOW VARIABLES LIKE 'profiling'") + ) { + self::cacheSet('profiling_supported', true, true); + } else { + self::cacheSet('profiling_supported', false, true); + } + } + + return self::cacheGet('profiling_supported', true); + } + + /** + * Returns HTML for the form with the Profiling checkbox + * + * @param string $sql_query sql query + * + * @return string HTML for the form with the Profiling checkbox + * + * @access public + */ + public static function getProfilingForm($sql_query) + { + $retval = ''; + if (self::profilingSupported()) { + + $retval .= '
      ' . "\n"; + $retval .= PMA_generate_common_hidden_inputs( + $GLOBALS['db'], $GLOBALS['table'] + ); + + $retval .= '' . "\n" + . '' . "\n"; + + $retval .= self::getCheckbox( + 'profiling', __('Profiling'), isset($_SESSION['profiling']), true + ); + $retval .= '
      ' . "\n"; + + } + return $retval; + } + + /** + * 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_generate_common_url($url_params); + if (! empty($tab['args'])) { + foreach ($tab['args'] as $param => $value) { + $tab['link'] .= PMA_get_arg_separator('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); + + } 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']) { + if ($suhosin_get_MaxValueLength = ini_get('suhosin.get.max_value_length')) { + $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_get_arg_separator(); + // 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 PMA_STR_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 string path to current script + * @global boolean 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 = PMA_DBI_field_flags($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')) + // hexify only if this is a true not empty BLOB or a BINARY + && stristr($field_flags, 'BINARY') + && ! empty($row[$i]) + ) { + // 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']['PropertiesIconic'] === false) { + 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) { + // patch #474210 - part 1 + if ($GLOBALS['cfg']['NavigationBarIconic']) { + $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_generate_common_hidden_inputs($_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 ($GLOBALS['cfg']['NavigationBarIconic']) { + $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 void + */ + 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 + * + * @return string html content + * + * @todo support titles + */ + public static function getDropdown($select_name, $choices, $active_choice, $id) + { + $result = ''; + + return $result; + } + + /** + * Generates a slider effect (jQjuery) + * Takes care of generating the initial
      and the link + * controlling the slider; you have to generate the
      yourself + * after the sliding section. + * + * @param string $id the id of the
      on which to apply the effect + * @param string $message the message to show as a link + * + * @return string html div element + * + */ + public static function getDivForSliderEffect($id, $message) + { + if ($GLOBALS['cfg']['InitialSlidersState'] == 'disabled') { + return '
      '; + } + /** + * Bad hack on the next line. document.write() conflicts with jQuery, + * hence, opening the
      with PHP itself instead of JavaScript. + * + * @todo find a better solution that uses $.append(), the recommended + * method maybe by using an additional param, the id of the div to + * append to + */ + + return '
      '; +} + +/** + * Closes form tabs + * + * @return void + */ +function PMA_displayTabsBottom() +{ + echo "
      \n"; +} + +/** + * Displays bottom part of the form + * + * @return void + */ +function PMA_displayFormBottom() +{ + echo "\n"; +} + +/** + * Appends JS validation code to $js_array + * + * @param string $field_id ID of field to validate + * @param string|array $validators validators callback + * @param array &$js_array will be updated with javascript code + * + * @return void + */ +function PMA_addJsValidate($field_id, $validators, &$js_array) +{ + foreach ((array)$validators as $validator) { + $validator = (array)$validator; + $v_name = array_shift($validator); + $v_args = array(); + foreach ($validator as $arg) { + $v_args[] = PMA_escapeJsString($arg); + } + $v_args = $v_args ? ", ['" . implode("', '", $v_args) . "']" : ''; + $js_array[] = "validateField('$field_id', '$v_name', true$v_args)"; + } +} + +/** + * Displays JavaScript code + * + * @param array $js_array lines of javascript code + * + * @return void + */ +function PMA_displayJavascript($js_array) +{ + if (empty($js_array)) { + return; + } + echo '' . "\n"; +} + +/** + * Displays error list + * + * @param string $name name of item with errors + * @param array $error_list list of errors to show + * + * @return void + */ +function PMA_displayErrors($name, $error_list) +{ + echo '
      '; + echo '
      ' . htmlspecialchars($name) . '
      '; + foreach ($error_list as $error) { + echo '
      ' . htmlspecialchars($error) . '
      '; + } + echo '
      '; +} +?> diff --git a/phpmyadmin/libraries/config/config_functions.lib.php b/phpmyadmin/libraries/config/config_functions.lib.php new file mode 100644 index 000000000..44a262424 --- /dev/null +++ b/phpmyadmin/libraries/config/config_functions.lib.php @@ -0,0 +1,55 @@ + diff --git a/phpmyadmin/libraries/config/messages.inc.php b/phpmyadmin/libraries/config/messages.inc.php new file mode 100644 index 000000000..988c2eb57 --- /dev/null +++ b/phpmyadmin/libraries/config/messages.inc.php @@ -0,0 +1,523 @@ +CREATE TABLE options:'); +$strConfigExport_sql_dates_name = __('Creation/Update/Check dates'); +$strConfigExport_sql_delayed_name = __('Use delayed inserts'); +$strConfigExport_sql_disable_fk_name = __('Disable foreign key checks'); +$strConfigExport_sql_drop_database_name = sprintf(__('Add %s'), 'DROP DATABASE'); +$strConfigExport_sql_drop_table_name = sprintf(__('Add %s'), 'DROP TABLE / VIEW / PROCEDURE / FUNCTION / EVENT'); +$strConfigExport_sql_hex_for_blob_name = __('Use hexadecimal for BLOB'); +$strConfigExport_sql_if_not_exists_name = sprintf(__('Add %s'), 'IF NOT EXISTS'); +$strConfigExport_sql_ignore_name = __('Use ignore inserts'); +$strConfigExport_sql_include_comments_name = __('Comments'); +$strConfigExport_sql_insert_syntax_name = __('Syntax to use when inserting data'); +$strConfigExport_sql_max_query_size_name = __('Maximal length of created query'); +$strConfigExport_sql_mime_name = __('MIME type'); +$strConfigExport_sql_procedure_function_name = sprintf(__('Add %s'), 'CREATE PROCEDURE / FUNCTION / EVENT'); +$strConfigExport_sql_relation_name = __('Relations'); +$strConfigExport_sql_structure_or_data_name = __('Dump table'); +$strConfigExport_sql_type_name = __('Export type'); +$strConfigExport_sql_use_transaction_name = __('Enclose export in a transaction'); +$strConfigExport_sql_utc_time_name = __('Export time in UTC'); +$strConfigExport_texytext_columns_name = __('Put columns names in the first row'); +$strConfigExport_texytext_null_name = __('Replace NULL by'); +$strConfigExport_texytext_structure_or_data_name = __('Dump table'); +$strConfigExport_xls_columns_name = __('Put columns names in the first row'); +$strConfigExport_xls_null_name = __('Replace NULL by'); +$strConfigExport_xlsx_columns_name = __('Put columns names in the first row'); +$strConfigExport_xlsx_null_name = __('Replace NULL by'); +$strConfigForceSSL_desc = __('Force secured connection while using phpMyAdmin'); +$strConfigForceSSL_name = __('Force SSL connection'); +$strConfigForeignKeyDropdownOrder_desc = __('Sort order for items in a foreign-key dropdown box; [kbd]content[/kbd] is the referenced data, [kbd]id[/kbd] is the key value'); +$strConfigForeignKeyDropdownOrder_name = __('Foreign key dropdown order'); +$strConfigForeignKeyMaxLimit_desc = __('A dropdown will be used if fewer items are present'); +$strConfigForeignKeyMaxLimit_name = __('Foreign key limit'); +$strConfigForm_Browse = __('Browse mode'); +$strConfigForm_Browse_desc = __('Customize browse mode'); +$strConfigForm_CodeGen = 'CodeGen'; +$strConfigForm_CodeGen_desc = __('Customize default options'); +$strConfigForm_Csv = __('CSV'); +$strConfigForm_Csv_desc = __('Customize default options'); +$strConfigForm_Developer = __('Developer'); +$strConfigForm_Developer_desc = __('Settings for phpMyAdmin developers'); +$strConfigForm_Edit = __('Edit mode'); +$strConfigForm_Edit_desc = __('Customize edit mode'); +$strConfigForm_Export = __('Export'); +$strConfigForm_Export_defaults = __('Export defaults'); +$strConfigForm_Export_defaults_desc = __('Customize default export options'); +$strConfigForm_Features = __('Features'); +$strConfigForm_General = __('General'); +$strConfigForm_General_desc = __('Set some commonly used options'); +$strConfigForm_Import = __('Import'); +$strConfigForm_Import_defaults = __('Import defaults'); +$strConfigForm_Import_defaults_desc = __('Customize default common import options'); +$strConfigForm_Import_export = __('Import / export'); +$strConfigForm_Import_export_desc = __('Set import and export directories and compression options'); +$strConfigForm_Latex = __('LaTeX'); +$strConfigForm_Latex_desc = __('Customize default options'); +$strConfigForm_Navi_databases = __('Databases'); +$strConfigForm_Navi_databases_desc = __('Databases display options'); +$strConfigForm_Navi_panel = __('Navigation panel'); +$strConfigForm_Navi_panel_desc = __('Customize appearance of the navigation panel'); +$strConfigForm_Navi_servers = __('Servers'); +$strConfigForm_Navi_servers_desc = __('Servers display options'); +$strConfigForm_Navi_tables = __('Tables'); +$strConfigForm_Navi_tables_desc = __('Tables display options'); +$strConfigForm_Main_panel = __('Main panel'); +$strConfigForm_Microsoft_Office = __('Microsoft Office'); +$strConfigForm_Microsoft_Office_desc = __('Customize default options'); +$strConfigForm_Open_Document = 'OpenDocument'; +$strConfigForm_Open_Document_desc = __('Customize default options'); +$strConfigForm_Other_core_settings = __('Other core settings'); +$strConfigForm_Other_core_settings_desc = __('Settings that didn\'t fit anywhere else'); +$strConfigForm_Page_titles = __('Page titles'); +$strConfigForm_Page_titles_desc = __('Specify browser\'s title bar text. Refer to [doc@cfg_TitleTable]documentation[/doc] for magic strings that can be used to get special values.'); +$strConfigForm_Query_window = __('Query window'); +$strConfigForm_Query_window_desc = __('Customize query window options'); +$strConfigForm_Security = __('Security'); +$strConfigForm_Security_desc = __('Please note that phpMyAdmin is just a user interface and its features do not limit MySQL'); +$strConfigForm_Server = __('Basic settings'); +$strConfigForm_Server_auth = __('Authentication'); +$strConfigForm_Server_auth_desc = __('Authentication settings'); +$strConfigForm_Server_config = __('Server configuration'); +$strConfigForm_Server_config_desc = __('Advanced server configuration, do not change these options unless you know what they are for'); +$strConfigForm_Server_desc = __('Enter server connection parameters'); +$strConfigForm_Server_pmadb = __('Configuration storage'); +$strConfigForm_Server_pmadb_desc = __('Configure phpMyAdmin configuration storage to gain access to additional features, see [doc@linked-tables]phpMyAdmin configuration storage[/doc] in documentation'); +$strConfigForm_Server_tracking = __('Changes tracking'); +$strConfigForm_Server_tracking_desc = __('Tracking of changes made in database. Requires the phpMyAdmin configuration storage.'); +$strConfigFormset_Export = __('Customize export options'); +$strConfigFormset_Features = __('Features'); +$strConfigFormset_Import = __('Customize import defaults'); +$strConfigFormset_Navi_panel = __('Customize navigation panel'); +$strConfigFormset_Main_panel = __('Customize main panel'); +$strConfigFormset_Sql_queries = __('SQL queries'); +$strConfigForm_Sql = __('SQL'); +$strConfigForm_Sql_box = __('SQL Query box'); +$strConfigForm_Sql_box_desc = __('Customize links shown in SQL Query boxes'); +$strConfigForm_Sql_desc = __('Customize default options'); +$strConfigForm_Sql_queries = __('SQL queries'); +$strConfigForm_Sql_queries_desc = __('SQL queries settings'); +$strConfigForm_Sql_validator = __('SQL Validator'); +$strConfigForm_Sql_validator_desc = __('If you wish to use the SQL Validator service, you should be aware that [strong]all SQL statements are stored anonymously for statistical purposes[/strong].[br][em][a@http://sqlvalidator.mimer.com/]Mimer SQL Validator[/a], Copyright 2002 Upright Database Technology. All rights reserved.[/em]'); +$strConfigForm_Startup = __('Startup'); +$strConfigForm_Startup_desc = __('Customize startup page'); +$strConfigForm_DbStructure = __('Database structure'); +$strConfigForm_DbStructure_desc = __('Choose which details to show in the database structure (list of tables)'); +$strConfigForm_TableStructure = __('Table structure'); +$strConfigForm_TableStructure_desc = __('Settings for the table structure (list of columns)'); +$strConfigForm_Tabs = __('Tabs'); +$strConfigForm_Tabs_desc = __('Choose how you want tabs to work'); +$strConfigForm_Text_fields = __('Text fields'); +$strConfigForm_Text_fields_desc = __('Customize text input fields'); +$strConfigForm_Texy = __('Texy! text'); +$strConfigForm_Texy_desc = __('Customize default options'); +$strConfigForm_Warnings = __('Warnings'); +$strConfigForm_Warnings_desc = __('Disable some of the warnings shown by phpMyAdmin'); +$strConfigGZipDump_desc = __('Enable [a@http://en.wikipedia.org/wiki/Gzip]gzip[/a] compression for import and export operations'); +$strConfigGZipDump_name = __('GZip'); +$strConfigIconvExtraParams_name = __('Extra parameters for iconv'); +$strConfigIgnoreMultiSubmitErrors_desc = __('If enabled, phpMyAdmin continues computing multiple-statement queries even if one of the queries failed'); +$strConfigIgnoreMultiSubmitErrors_name = __('Ignore multiple statement errors'); +$strConfigImport_allow_interrupt_desc = __('Allow interrupt of import in case script detects it is close to time limit. This might be a good way to import large files, however it can break transactions.'); +$strConfigImport_allow_interrupt_name = __('Partial import: allow interrupt'); +$strConfigImport_charset_name = __('Character set of the file'); +$strConfigImport_csv_col_names_name = __('Lines terminated by'); +$strConfigImport_csv_enclosed_name = __('Columns enclosed by'); +$strConfigImport_csv_escaped_name = __('Columns escaped by'); +$strConfigImport_csv_ignore_name = __('Do not abort on INSERT error'); +$strConfigImport_csv_replace_name = __('Replace table data with file'); +$strConfigImport_csv_terminated_name = __('Columns terminated by'); +$strConfigImport_format_desc = __('Default format; be aware that this list depends on location (database, table) and only SQL is always available'); +$strConfigImport_format_name = __('Format of imported file'); +$strConfigImport_ldi_enclosed_name = __('Columns enclosed by'); +$strConfigImport_ldi_escaped_name = __('Columns escaped by'); +$strConfigImport_ldi_ignore_name = __('Do not abort on INSERT error'); +$strConfigImport_ldi_local_option_name = __('Use LOCAL keyword'); +$strConfigImport_ldi_replace_name = __('Replace table data with file'); +$strConfigImport_ldi_terminated_name = __('Columns terminated by'); +$strConfigImport_ods_col_names_name = __('Column names in first row'); +$strConfigImport_ods_empty_rows_name = __('Do not import empty rows'); +$strConfigImport_ods_recognize_currency_name = __('Import currencies ($5.00 to 5.00)'); +$strConfigImport_ods_recognize_percentages_name = __('Import percentages as proper decimals (12.00% to .12)'); +$strConfigImport_skip_queries_desc = __('Number of queries to skip from start'); +$strConfigImport_skip_queries_name = __('Partial import: skip queries'); +$strConfigImport_sql_compatibility_name = __('SQL compatibility mode'); +$strConfigImport_sql_no_auto_value_on_zero_name = __('Do not use AUTO_INCREMENT for zero values'); +$strConfigImport_xls_col_names_name = __('Column names in first row'); +$strConfigImport_xlsx_col_names_name = __('Column names in first row'); +$strConfigInitialSlidersState_name = __('Initial state for sliders'); +$strConfigInsertRows_desc = __('How many rows can be inserted at one time'); +$strConfigInsertRows_name = __('Number of inserted rows'); +$strConfigLimitChars_desc = __('Maximum number of characters shown in any non-numeric column on browse view'); +$strConfigLimitChars_name = __('Limit column characters'); +$strConfigLoginCookieDeleteAll_desc = __('If TRUE, logout deletes cookies for all servers; when set to FALSE, logout only occurs for the current server. Setting this to FALSE makes it easy to forget to log out from other servers when connected to multiple servers.'); +$strConfigLoginCookieDeleteAll_name = __('Delete all cookies on logout'); +$strConfigLoginCookieRecall_desc = __('Define whether the previous login should be recalled or not in cookie authentication mode'); +$strConfigLoginCookieRecall_name = __('Recall user name'); +$strConfigLoginCookieStore_desc = __('Defines how long (in seconds) a login cookie should be stored in browser. The default of 0 means that it will be kept for the existing session only, and will be deleted as soon as you close the browser window. This is recommended for non-trusted environments.'); +$strConfigLoginCookieStore_name = __('Login cookie store'); +$strConfigLoginCookieValidity_desc = __('Define how long (in seconds) a login cookie is valid'); +$strConfigLoginCookieValidity_name = __('Login cookie validity'); +$strConfigLongtextDoubleTextarea_desc = __('Double size of textarea for LONGTEXT columns'); +$strConfigLongtextDoubleTextarea_name = __('Bigger textarea for LONGTEXT'); +$strConfigMaxCharactersInDisplayedSQL_desc = __('Maximum number of characters used when a SQL query is displayed'); +$strConfigMaxCharactersInDisplayedSQL_name = __('Maximum displayed SQL length'); +$strConfigMaxDbList_cmt = __('Users cannot set a higher value'); +$strConfigMaxDbList_desc = __('Maximum number of databases displayed in database list'); +$strConfigMaxDbList_name = __('Maximum databases'); +$strConfigMaxNavigationItems_desc = __('The number of items that can be displayed on each page of the navigation tree'); +$strConfigMaxNavigationItems_name = __('Maximum items in branch'); +$strConfigMaxRows_desc = __('Number of rows displayed when browsing a result set. If the result set contains more rows, "Previous" and "Next" links will be shown.'); +$strConfigMaxRows_name = __('Maximum number of rows to display'); +$strConfigMaxTableList_cmt = __('Users cannot set a higher value'); +$strConfigMaxTableList_desc = __('Maximum number of tables displayed in table list'); +$strConfigMaxTableList_name = __('Maximum tables'); +$strConfigMcryptDisableWarning_desc = __('Disable the default warning that is displayed if mcrypt is missing for cookie authentication'); +$strConfigMcryptDisableWarning_name = __('mcrypt warning'); +$strConfigMemoryLimit_desc = __('The number of bytes a script is allowed to allocate, eg. [kbd]32M[/kbd] ([kbd]0[/kbd] for no limit)'); +$strConfigMemoryLimit_name = __('Memory limit'); +$strConfigNavigationDisplayLogo_desc = __('Show logo in navigation panel'); +$strConfigNavigationDisplayLogo_name = __('Display logo'); +$strConfigNavigationLogoLink_desc = __('URL where logo in the navigation panel will point to'); +$strConfigNavigationLogoLink_name = __('Logo link URL'); +$strConfigNavigationLogoLinkWindow_desc = __('Open the linked page in the main window ([kbd]main[/kbd]) or in a new one ([kbd]new[/kbd])'); +$strConfigNavigationLogoLinkWindow_name = __('Logo link target'); +$strConfigNavigationDisplayServers_desc = __('Display server choice at the top of the navigation panel'); +$strConfigNavigationDisplayServers_name = __('Display servers selection'); +$strConfigNavigationTreeDefaultTabTable_name = __('Target for quick access icon'); +$strConfigNavigationTreeDisplayItemFilterMinimum_desc = __('Defines the minimum number of items (tables, views, routines and events) to display a filter box.'); +$strConfigNavigationTreeDisplayItemFilterMinimum_name = __('Minimum number of items to display the filter box'); +$strConfigNavigationTreeDisplayDbFilterMinimum_name = __('Minimum number of databases to display the database filter box'); +$strConfigNavigationTreeEnableGrouping_desc = __('Group items in the navigation tree (determined by the separator defined below)'); +$strConfigNavigationTreeEnableGrouping_name = __('Group items in the tree'); +$strConfigNavigationTreeDbSeparator_desc = __('String that separates databases into different tree levels'); +$strConfigNavigationTreeDbSeparator_name = __('Database tree separator'); +$strConfigNavigationTreeTableSeparator_desc = __('String that separates tables into different tree levels'); +$strConfigNavigationTreeTableSeparator_name = __('Table tree separator'); +$strConfigNavigationTreeTableLevel_name = __('Maximum table tree depth'); +$strConfigNavigationTreePointerEnable_desc = __('Highlight server under the mouse cursor'); +$strConfigNavigationTreePointerEnable_name = __('Enable highlighting'); +$strConfigNumRecentTables_desc = __('Maximum number of recently used tables; set 0 to disable'); +$strConfigNumRecentTables_name = __('Recently used tables'); +$strConfigRowActionLinks_desc = __('These are Edit, Copy and Delete links'); +$strConfigRowActionLinks_name = __('Where to show the table row links'); +$strConfigNaturalOrder_desc = __('Use natural order for sorting table and database names'); +$strConfigNaturalOrder_name = __('Natural order'); +$strConfigNavigationBarIconic_desc = __('Use only icons, only text or both'); +$strConfigNavigationBarIconic_name = __('Iconic navigation bar'); +$strConfigOBGzip_desc = __('use GZip output buffering for increased speed in HTTP transfers'); +$strConfigOBGzip_name = __('GZip output buffering'); +$strConfigOrder_desc = __('[kbd]SMART[/kbd] - i.e. descending order for columns of type TIME, DATE, DATETIME and TIMESTAMP, ascending order otherwise'); +$strConfigOrder_name = __('Default sorting order'); +$strConfigPersistentConnections_desc = __('Use persistent connections to MySQL databases'); +$strConfigPersistentConnections_name = __('Persistent connections'); +$strConfigPmaNoRelation_DisableWarning_desc = __('Disable the default warning that is displayed on the database details Structure page if any of the required tables for the phpMyAdmin configuration storage could not be found'); +$strConfigPmaNoRelation_DisableWarning_name = __('Missing phpMyAdmin configuration storage tables'); +$strConfigServerLibraryDifference_DisableWarning_desc = __('Disable the default warning that is displayed if a difference between the MySQL library and server is detected'); +$strConfigServerLibraryDifference_DisableWarning_name = __('Server/library difference warning'); +$strConfigReservedWordDisableWarning_desc = __('Disable the default warning that is displayed on the Structure page if column names in a table are reserved MySQL words'); +$strConfigReservedWordDisableWarning_name = __('MySQL reserved word warning'); +$strConfigPropertiesIconic_desc = __('Use only icons, only text or both'); +$strConfigPropertiesIconic_name = __('Iconic table operations'); +$strConfigProtectBinary_desc = __('Disallow BLOB and BINARY columns from editing'); +$strConfigProtectBinary_name = __('Protect binary columns'); +$strConfigQueryHistoryDB_desc = __('Enable if you want DB-based query history (requires phpMyAdmin configuration storage). If disabled, this utilizes JS-routines to display query history (lost by window close).'); +$strConfigQueryHistoryDB_name = __('Permanent query history'); +$strConfigQueryHistoryMax_cmt = __('Users cannot set a higher value'); +$strConfigQueryHistoryMax_desc = __('How many queries are kept in history'); +$strConfigQueryHistoryMax_name = __('Query history length'); +$strConfigQueryWindowDefTab_desc = __('Tab displayed when opening a new query window'); +$strConfigQueryWindowDefTab_name = __('Default query window tab'); +$strConfigQueryWindowHeight_desc = __('Query window height (in pixels)'); +$strConfigQueryWindowHeight_name = __('Query window height'); +$strConfigQueryWindowWidth_desc = __('Query window width (in pixels)'); +$strConfigQueryWindowWidth_name = __('Query window width'); +$strConfigRecodingEngine_desc = __('Select which functions will be used for character set conversion'); +$strConfigRecodingEngine_name = __('Recoding engine'); +$strConfigRememberSorting_desc = __('When browsing tables, the sorting of each table is remembered'); +$strConfigRememberSorting_name = __('Remember table\'s sorting'); +$strConfigRepeatCells_desc = __('Repeat the headers every X cells, [kbd]0[/kbd] deactivates this feature'); +$strConfigRepeatCells_name = __('Repeat headers'); +$strConfigRestoreDefaultValue = __('Restore default value'); +$strConfigGridEditing_name = __('Grid editing: trigger action'); +$strConfigSaveCellsAtOnce_name = __('Grid editing: save all edited cells at once'); +$strConfigSaveDir_desc = __('Directory where exports can be saved on server'); +$strConfigSaveDir_name = __('Save directory'); +$strConfigServers_AllowDeny_order_desc = __('Leave blank if not used'); +$strConfigServers_AllowDeny_order_name = __('Host authorization order'); +$strConfigServers_AllowDeny_rules_desc = __('Leave blank for defaults'); +$strConfigServers_AllowDeny_rules_name = __('Host authorization rules'); +$strConfigServers_AllowNoPassword_name = __('Allow logins without a password'); +$strConfigServers_AllowRoot_name = __('Allow root login'); +$strConfigServers_auth_http_realm_desc = __('HTTP Basic Auth Realm name to display when doing HTTP Auth'); +$strConfigServers_auth_http_realm_name = __('HTTP Realm'); +$strConfigServers_auth_swekey_config_desc = __('The path for the config file for [a@http://swekey.com]SweKey hardware authentication[/a] (not located in your document root; suggested: /etc/swekey.conf)'); +$strConfigServers_auth_swekey_config_name = __('SweKey config file'); +$strConfigServers_auth_type_desc = __('Authentication method to use'); +$strConfigServers_auth_type_name = __('Authentication type'); +$strConfigServers_bookmarktable_desc = __('Leave blank for no [a@http://wiki.phpmyadmin.net/pma/bookmark]bookmark[/a] support, suggested: [kbd]pma__bookmark[/kbd]'); +$strConfigServers_bookmarktable_name = __('Bookmark table'); +$strConfigServers_column_info_desc = __('Leave blank for no column comments/mime types, suggested: [kbd]pma__column_info[/kbd]'); +$strConfigServers_column_info_name = __('Column information table'); +$strConfigServers_compress_desc = __('Compress connection to MySQL server'); +$strConfigServers_compress_name = __('Compress connection'); +$strConfigServers_connect_type_desc = __('How to connect to server, keep [kbd]tcp[/kbd] if unsure'); +$strConfigServers_connect_type_name = __('Connection type'); +$strConfigServers_controlpass_name = __('Control user password'); +$strConfigServers_controluser_desc = __('A special MySQL user configured with limited permissions, more information available on [a@http://wiki.phpmyadmin.net/pma/controluser]wiki[/a]'); +$strConfigServers_controluser_name = __('Control user'); +$strConfigServers_controlhost_desc = __('An alternate host to hold the configuration storage; leave blank to use the already defined host'); +$strConfigServers_controlhost_name = __('Control host'); +$strConfigServers_designer_coords_desc = __('Leave blank for no Designer support, suggested: [kbd]pma__designer_coords[/kbd]'); +$strConfigServers_designer_coords_name = __('Designer table'); +$strConfigServers_DisableIS_desc = __('More information on [a@https://sourceforge.net/p/phpmyadmin/bugs/2606/]PMA bug tracker[/a] and [a@http://bugs.mysql.com/19588]MySQL Bugs[/a]'); +$strConfigServers_DisableIS_name = __('Disable use of INFORMATION_SCHEMA'); +$strConfigServers_extension_desc = __('What PHP extension to use; you should use mysqli if supported'); +$strConfigServers_extension_name = __('PHP extension to use'); +$strConfigServers_hide_db_desc = __('Hide databases matching regular expression (PCRE)'); +$strConfigServers_hide_db_name = __('Hide databases'); +$strConfigServers_history_desc = __('Leave blank for no SQL query history support, suggested: [kbd]pma__history[/kbd]'); +$strConfigServers_history_name = __('SQL query history table'); +$strConfigServers_host_desc = __('Hostname where MySQL server is running'); +$strConfigServers_host_name = __('Server hostname'); +$strConfigServers_LogoutURL_name = __('Logout URL'); +$strConfigServers_MaxTableUiprefs_desc = __('Limits number of table preferences which are stored in database, the oldest records are automatically removed'); +$strConfigServers_MaxTableUiprefs_name = __('Maximal number of table preferences to store'); +$strConfigServers_nopassword_desc = __('Try to connect without password'); +$strConfigServers_nopassword_name = __('Connect without password'); +$strConfigServers_only_db_desc = __('You can use MySQL wildcard characters (% and _), escape them if you want to use their literal instances, i.e. use [kbd]\'my\_db\'[/kbd] and not [kbd]\'my_db\'[/kbd].'); +$strConfigServers_only_db_name = __('Show only listed databases'); +$strConfigServers_password_desc = __('Leave empty if not using config auth'); +$strConfigServers_password_name = __('Password for config auth'); +$strConfigServers_pdf_pages_desc = __('Leave blank for no PDF schema support, suggested: [kbd]pma__pdf_pages[/kbd]'); +$strConfigServers_pdf_pages_name = __('PDF schema: pages table'); +$strConfigServers_pmadb_desc = __('Database used for relations, bookmarks, and PDF features. See [a@http://wiki.phpmyadmin.net/pma/pmadb]pmadb[/a] for complete information. Leave blank for no support. Suggested: [kbd]phpmyadmin[/kbd]'); +$strConfigServers_pmadb_name = __('Database name'); +$strConfigServers_port_desc = __('Port on which MySQL server is listening, leave empty for default'); +$strConfigServers_port_name = __('Server port'); +$strConfigServers_recent_desc = __('Leave blank for no "persistent" recently used tables across sessions, suggested: [kbd]pma__recent[/kbd]'); +$strConfigServers_recent_name = __('Recently used table'); +$strConfigServers_relation_desc = __('Leave blank for no [a@http://wiki.phpmyadmin.net/pma/relation]relation-links[/a] support, suggested: [kbd]pma__relation[/kbd]'); +$strConfigServers_relation_name = __('Relation table'); +$strConfigServers_ShowDatabasesCommand_desc = __('SQL command to fetch available databases'); +$strConfigServers_ShowDatabasesCommand_name = __('SHOW DATABASES command'); +$strConfigServers_SignonSession_desc = __('See [a@http://wiki.phpmyadmin.net/pma/auth_types#signon]authentication types[/a] for an example'); +$strConfigServers_SignonSession_name = __('Signon session name'); +$strConfigServers_SignonURL_name = __('Signon URL'); +$strConfigServers_socket_desc = __('Socket on which MySQL server is listening, leave empty for default'); +$strConfigServers_socket_name = __('Server socket'); +$strConfigServers_ssl_desc = __('Enable SSL for connection to MySQL server'); +$strConfigServers_ssl_name = __('Use SSL'); +$strConfigServers_table_coords_desc = __('Leave blank for no PDF schema support, suggested: [kbd]pma__table_coords[/kbd]'); +$strConfigServers_table_coords_name = __('PDF schema: table coordinates'); +$strConfigServers_table_info_desc = __('Table to describe the display columns, leave blank for no support; suggested: [kbd]pma__table_info[/kbd]'); +$strConfigServers_table_info_name = __('Display columns table'); +$strConfigServers_table_uiprefs_desc = __('Leave blank for no "persistent" tables\'UI preferences across sessions, suggested: [kbd]pma__table_uiprefs[/kbd]'); +$strConfigServers_table_uiprefs_name = __('UI preferences table'); +$strConfigServers_tracking_add_drop_database_desc = __('Whether a DROP DATABASE IF EXISTS statement will be added as first line to the log when creating a database.'); +$strConfigServers_tracking_add_drop_database_name = __('Add DROP DATABASE'); +$strConfigServers_tracking_add_drop_table_desc = __('Whether a DROP TABLE IF EXISTS statement will be added as first line to the log when creating a table.'); +$strConfigServers_tracking_add_drop_table_name = __('Add DROP TABLE'); +$strConfigServers_tracking_add_drop_view_desc = __('Whether a DROP VIEW IF EXISTS statement will be added as first line to the log when creating a view.'); +$strConfigServers_tracking_add_drop_view_name = __('Add DROP VIEW'); +$strConfigServers_tracking_default_statements_desc = __('Defines the list of statements the auto-creation uses for new versions.'); +$strConfigServers_tracking_default_statements_name = __('Statements to track'); +$strConfigServers_tracking_desc = __('Leave blank for no SQL query tracking support, suggested: [kbd]pma__tracking[/kbd]'); +$strConfigServers_tracking_name = __('SQL query tracking table'); +$strConfigServers_tracking_version_auto_create_desc = __('Whether the tracking mechanism creates versions for tables and views automatically.'); +$strConfigServers_tracking_version_auto_create_name = __('Automatically create versions'); +$strConfigServers_userconfig_desc = __('Leave blank for no user preferences storage in database, suggested: [kbd]pma__userconfig[/kbd]'); +$strConfigServers_userconfig_name = __('User preferences storage table'); +$strConfigServers_user_desc = __('Leave empty if not using config auth'); +$strConfigServers_user_name = __('User for config auth'); +$strConfigServers_verbose_desc = __('A user-friendly description of this server. Leave blank to display the hostname instead.'); +$strConfigServers_verbose_name = __('Verbose name of this server'); +$strConfigShowAll_desc = __('Whether a user should be displayed a "show all (rows)" button'); +$strConfigShowAll_name = __('Allow to display all the rows'); +$strConfigShowChgPassword_desc = __('Please note that enabling this has no effect with [kbd]config[/kbd] authentication mode because the password is hard coded in the configuration file; this does not limit the ability to execute the same command directly'); +$strConfigShowChgPassword_name = __('Show password change form'); +$strConfigShowCreateDb_name = __('Show create database form'); +$strConfigShowDbStructureCreation_desc = __('Show or hide a column displaying the Creation timestamp for all tables'); +$strConfigShowDbStructureCreation_name = __('Show Creation timestamp'); +$strConfigShowDbStructureLastUpdate_desc = __('Show or hide a column displaying the Last update timestamp for all tables'); +$strConfigShowDbStructureLastUpdate_name = __('Show Last update timestamp'); +$strConfigShowDbStructureLastCheck_desc = __('Show or hide a column displaying the Last check timestamp for all tables'); +$strConfigShowDbStructureLastCheck_name = __('Show Last check timestamp'); +$strConfigShowDisplayDirection_desc = __('Defines whether or not type display direction option is shown when browsing a table'); +$strConfigShowDisplayDirection_name = __('Show display direction'); +$strConfigShowFieldTypesInDataEditView_desc = __('Defines whether or not type fields should be initially displayed in edit/insert mode'); +$strConfigShowFieldTypesInDataEditView_name = __('Show field types'); +$strConfigShowFunctionFields_desc = __('Display the function fields in edit/insert mode'); +$strConfigShowFunctionFields_name = __('Show function fields'); +$strConfigShowHint_desc = __('Whether to show hint or not'); +$strConfigShowHint_name = __('Show hint'); +$strConfigShowPhpInfo_desc = __('Shows link to [a@http://php.net/manual/function.phpinfo.php]phpinfo()[/a] output'); +$strConfigShowPhpInfo_name = __('Show phpinfo() link'); +$strConfigShowServerInfo_name = __('Show detailed MySQL server information'); +$strConfigShowSQL_desc = __('Defines whether SQL queries generated by phpMyAdmin should be displayed'); +$strConfigShowSQL_name = __('Show SQL queries'); +$strConfigRetainQueryBox_desc = __('Defines whether the query box should stay on-screen after its submission'); +$strConfigRetainQueryBox_name = __('Retain query box'); +$strConfigShowStats_desc = __('Allow to display database and table statistics (eg. space usage)'); +$strConfigShowStats_name = __('Show statistics'); +$strConfigShowTooltip_name = __('Display table comments in tooltips'); +$strConfigSkipLockedTables_desc = __('Mark used tables and make it possible to show databases with locked tables'); +$strConfigSkipLockedTables_name = __('Skip locked tables'); +$strConfigSQLQuery_Edit_name = __('Edit'); +$strConfigSQLQuery_Explain_name = __('Explain SQL'); +$strConfigSQLQuery_Refresh_name = __('Refresh'); +$strConfigSQLQuery_ShowAsPHP_name = __('Create PHP Code'); +$strConfigSQLQuery_Validate_desc = __('Requires SQL Validator to be enabled'); +$strConfigSQLQuery_Validate_name = __('Validate SQL'); +$strConfigSQLValidator_password_name = __('Password'); +$strConfigSQLValidator_use_desc = __('[strong]Warning:[/strong] requires PHP SOAP extension or PEAR SOAP to be installed'); +$strConfigSQLValidator_use_name = __('Enable SQL Validator'); +$strConfigSQLValidator_username_desc = __('If you have a custom username, specify it here (defaults to [kbd]anonymous[/kbd])'); +$strConfigSQLValidator_username_name = __('Username'); +$strConfigSuhosinDisableWarning_desc = __('A warning is displayed on the main page if Suhosin is detected'); +$strConfigSuhosinDisableWarning_name = __('Suhosin warning'); +$strConfigTextareaCols_desc = __('Textarea size (columns) in edit mode, this value will be emphasized for SQL query textareas (*2) and for query window (*1.25)'); +$strConfigTextareaCols_name = __('Textarea columns'); +$strConfigTextareaRows_desc = __('Textarea size (rows) in edit mode, this value will be emphasized for SQL query textareas (*2) and for query window (*1.25)'); +$strConfigTextareaRows_name = __('Textarea rows'); +$strConfigTitleDatabase_desc = __('Title of browser window when a database is selected'); +$strConfigTitleDatabase_name = __('Database'); +$strConfigTitleDefault_desc = __('Title of browser window when nothing is selected'); +$strConfigTitleDefault_name = __('Default title'); +$strConfigTitleServer_desc = __('Title of browser window when a server is selected'); +$strConfigTitleServer_name = __('Server'); +$strConfigTitleTable_desc = __('Title of browser window when a table is selected'); +$strConfigTitleTable_name = __('Table'); +$strConfigTrustedProxies_desc = __('Input proxies as [kbd]IP: trusted HTTP header[/kbd]. 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:[br][kbd]1.2.3.4: HTTP_X_FORWARDED_FOR[/kbd]'); +$strConfigTrustedProxies_name = __('List of trusted proxies for IP allow/deny'); +$strConfigUploadDir_desc = __('Directory on server where you can upload files for import'); +$strConfigUploadDir_name = __('Upload directory'); +$strConfigUseDbSearch_desc = __('Allow for searching inside the entire database'); +$strConfigUseDbSearch_name = __('Use database search'); +$strConfigUserprefsDeveloperTab_desc = __('When disabled, users cannot set any of the options below, regardless of the checkbox on the right'); +$strConfigUserprefsDeveloperTab_name = __('Enable the Developer tab in settings'); +$strConfigVersionCheckLink = __('Check for latest version'); +$strConfigVersionCheck_desc = __('Enables check for latest version on main phpMyAdmin page'); +$strConfigVersionCheck_name = __('Version check'); +$strConfigZipDump_desc = __('Enable [a@http://en.wikipedia.org/wiki/ZIP_(file_format)]ZIP[/a] compression for import and export operations'); +$strConfigZipDump_name = __('ZIP'); + +?> diff --git a/phpmyadmin/libraries/config/setup.forms.php b/phpmyadmin/libraries/config/setup.forms.php new file mode 100644 index 000000000..4a9cb1b48 --- /dev/null +++ b/phpmyadmin/libraries/config/setup.forms.php @@ -0,0 +1,367 @@ + array(1 => array('host'))); + * can be written as + * $forms['Form group']['Form name'] = array('Servers/1/host'); + * + * You can assign default values set by special button ("set value: ..."), eg.: + * 'Servers/1/pmadb' => 'phpmyadmin' + * + * To group options, use: + * ':group:' . __('group name') // just define a group + * or + * 'option' => ':group' // group starting from this option + * End group blocks with: + * ':group:end' + * + * @package PhpMyAdmin-Setup + */ + +$forms = array(); +$forms['_config.php'] = array( + 'DefaultLang', + 'ServerDefault'); +$forms['Servers']['Server'] = array('Servers' => array(1 => array( + 'verbose', + 'host', + 'port', + 'socket', + 'ssl', + 'connect_type', + 'extension', + 'compress', + 'nopassword'))); +$forms['Servers']['Server_auth'] = array('Servers' => array(1 => array( + 'auth_type', + ':group:' . __('Config authentication'), + 'user', + 'password', + ':group:end', + ':group:' . __('Cookie authentication'), + 'auth_swekey_config' => './swekey.conf', + ':group:end', + ':group:' . __('HTTP authentication'), + 'auth_http_realm', + ':group:end', + ':group:' . __('Signon authentication'), + 'SignonSession', + 'SignonURL', + 'LogoutURL'))); +$forms['Servers']['Server_config'] = array('Servers' => array(1 => array( + 'only_db', + 'hide_db', + 'AllowRoot', + 'AllowNoPassword', + 'DisableIS', + 'AllowDeny/order', + 'AllowDeny/rules', + 'ShowDatabasesCommand'))); +$forms['Servers']['Server_pmadb'] = array('Servers' => array(1 => array( + 'pmadb' => 'phpmyadmin', + 'controlhost', + 'controluser', + 'controlpass', + 'bookmarktable' => 'pma__bookmark', + 'relation' => 'pma__relation', + 'userconfig' => 'pma__userconfig', + 'table_info' => 'pma__table_info', + 'column_info' => 'pma__column_info', + 'history' => 'pma__history', + 'recent' => 'pma__recent', + 'table_uiprefs' => 'pma__table_uiprefs', + 'tracking' => 'pma__tracking', + 'table_coords' => 'pma__table_coords', + 'pdf_pages' => 'pma__pdf_pages', + 'designer_coords' => 'pma__designer_coords', + 'MaxTableUiprefs' => 100))); +$forms['Servers']['Server_tracking'] = array('Servers' => array(1 => array( + 'tracking_version_auto_create', + 'tracking_default_statements', + 'tracking_add_drop_view', + 'tracking_add_drop_table', + 'tracking_add_drop_database', +))); +$forms['Features']['Import_export'] = array( + 'UploadDir', + 'SaveDir', + 'RecodingEngine' => ':group', + 'IconvExtraParams', + ':group:end', + 'ZipDump', + 'GZipDump', + 'BZipDump', + 'CompressOnFly'); +$forms['Features']['Security'] = array( + 'blowfish_secret', + 'ForceSSL', + 'CheckConfigurationPermissions', + 'TrustedProxies', + 'AllowUserDropDatabase', + 'AllowArbitraryServer', + 'LoginCookieRecall', + 'LoginCookieValidity', + 'LoginCookieStore', + 'LoginCookieDeleteAll'); +$forms['Features']['Page_titles'] = array( + 'TitleDefault', + 'TitleTable', + 'TitleDatabase', + 'TitleServer'); +$forms['Features']['Warnings'] = array( + 'ServerLibraryDifference_DisableWarning', + 'PmaNoRelation_DisableWarning', + 'SuhosinDisableWarning', + 'McryptDisableWarning'); +$forms['Features']['Developer'] = array( + 'UserprefsDeveloperTab', + 'Error_Handler/display', + 'Error_Handler/gather', + 'DBG/sql'); +$forms['Features']['Other_core_settings'] = array( + 'VersionCheck', + 'NaturalOrder', + 'InitialSlidersState', + 'MaxDbList', + 'MaxTableList', + 'NumRecentTables', + 'ShowHint', + 'OBGzip', + 'PersistentConnections', + 'ExecTimeLimit', + 'MemoryLimit', + 'SkipLockedTables', + 'DisableMultiTableMaintenance', + 'UseDbSearch'); +$forms['Sql_queries']['Sql_queries'] = array( + 'ShowSQL', + 'Confirm', + 'QueryHistoryDB', + 'QueryHistoryMax', + 'IgnoreMultiSubmitErrors', + 'MaxCharactersInDisplayedSQL', + 'EditInWindow', + //'QueryWindowWidth', // overridden in theme + //'QueryWindowHeight', + 'QueryWindowDefTab', + 'RetainQueryBox', + 'CodemirrorEnable'); +$forms['Sql_queries']['Sql_box'] = array('SQLQuery' => array( + 'Edit', + 'Explain', + 'ShowAsPHP', + 'Validate', + 'Refresh')); +$forms['Sql_queries']['Sql_validator'] = array('SQLValidator' => array( + 'use', + 'username', + 'password')); +$forms['Navi_panel']['Navi_panel'] = array( + 'NavigationDisplayLogo', + 'NavigationLogoLink', + 'NavigationLogoLinkWindow', + 'NavigationTreePointerEnable', + 'MaxNavigationItems', + 'NavigationTreeEnableGrouping', + 'NavigationTreeDisplayItemFilterMinimum'); +$forms['Navi_panel']['Navi_servers'] = array( + 'NavigationDisplayServers', + 'DisplayServersList'); +$forms['Navi_panel']['Navi_databases'] = array( + 'NavigationTreeDbSeparator'); +$forms['Navi_panel']['Navi_tables'] = array( + 'NavigationTreeDefaultTabTable', + 'NavigationTreeTableSeparator', + 'NavigationTreeTableLevel', + 'ShowTooltip'); +$forms['Main_panel']['Startup'] = array( + 'ShowCreateDb', + 'ShowStats', + 'ShowServerInfo', + 'ShowPhpInfo', + 'ShowChgPassword'); +$forms['Main_panel']['DbStructure'] = array( + 'ShowDbStructureCreation', + 'ShowDbStructureLastUpdate', + 'ShowDbStructureLastCheck'); +$forms['Main_panel']['TableStructure'] = array( + 'HideStructureActions'); +$forms['Main_panel']['Browse'] = array( + 'NavigationBarIconic', + 'ShowAll', + 'MaxRows', + 'Order', + 'BrowsePointerEnable', + 'BrowseMarkerEnable', + 'GridEditing', + 'SaveCellsAtOnce', + 'ShowDisplayDirection', + 'RepeatCells', + 'LimitChars', + 'RowActionLinks', + 'DefaultDisplay', + 'RememberSorting'); +$forms['Main_panel']['Edit'] = array( + 'ProtectBinary', + 'ShowFunctionFields', + 'ShowFieldTypesInDataEditView', + 'CharEditing', + 'MinSizeForInputField', + 'MaxSizeForInputField', + 'CharTextareaCols', + 'CharTextareaRows', + 'TextareaCols', + 'TextareaRows', + 'LongtextDoubleTextarea', + 'InsertRows', + 'ForeignKeyDropdownOrder', + 'ForeignKeyMaxLimit'); +$forms['Main_panel']['Tabs'] = array( + 'PropertiesIconic', + 'DefaultTabServer', + 'DefaultTabDatabase', + 'DefaultTabTable', + 'QueryWindowDefTab'); +$forms['Import']['Import_defaults'] = array('Import' => array( + 'format', + 'charset', + 'allow_interrupt', + 'skip_queries')); +$forms['Import']['Sql'] = array('Import' => array( + 'sql_compatibility', + 'sql_no_auto_value_on_zero')); +$forms['Import']['Csv'] = array('Import' => array( + ':group:' . __('CSV'), + 'csv_replace', + 'csv_ignore', + 'csv_terminated', + 'csv_enclosed', + 'csv_escaped', + 'csv_col_names', + ':group:end', + ':group:' . __('CSV using LOAD DATA'), + 'ldi_replace', + 'ldi_ignore', + 'ldi_terminated', + 'ldi_enclosed', + 'ldi_escaped', + 'ldi_local_option', + ':group:end')); +$forms['Import']['Open_Document'] = array('Import' => array( + ':group:' . __('OpenDocument Spreadsheet'), + 'ods_col_names', + 'ods_empty_rows', + 'ods_recognize_percentages', + 'ods_recognize_currency')); +$forms['Export']['Export_defaults'] = array('Export' => array( + 'method', + ':group:' . __('Quick'), + 'quick_export_onserver', + 'quick_export_onserver_overwrite', + ':group:end', + ':group:' . __('Custom'), + 'format', + 'compression', + 'charset', + 'asfile' => ':group', + 'onserver', + 'onserver_overwrite', + ':group:end', + 'remember_file_template', + 'file_template_table', + 'file_template_database', + 'file_template_server')); +$forms['Export']['Sql'] = array('Export' => array( + 'sql_include_comments' => ':group', + 'sql_dates', + 'sql_relation', + 'sql_mime', + ':group:end', + 'sql_use_transaction', + 'sql_disable_fk', + 'sql_compatibility', + ':group:' . __('Database export options'), + 'sql_drop_database', + 'sql_structure_or_data', + ':group:end', + ':group:' . __('Structure'), + 'sql_drop_table', + 'sql_procedure_function', + 'sql_create_table_statements' => ':group', + 'sql_if_not_exists', + 'sql_auto_increment', + ':group:end', + 'sql_backquotes', + ':group:end', + ':group:' . __('Data'), + 'sql_delayed', + 'sql_ignore', + 'sql_type', + 'sql_insert_syntax', + 'sql_max_query_size', + 'sql_hex_for_blob', + 'sql_utc_time')); +$forms['Export']['CodeGen'] = array('Export' => array( + 'codegen_format')); +$forms['Export']['Csv'] = array('Export' => array( + ':group:' . __('CSV'), + 'csv_separator', + 'csv_enclosed', + 'csv_escaped', + 'csv_terminated', + 'csv_null', + 'csv_removeCRLF', + 'csv_columns', + ':group:end', + ':group:' . __('CSV for MS Excel'), + 'excel_null', + 'excel_removeCRLF', + 'excel_columns', + 'excel_edition')); +$forms['Export']['Latex'] = array('Export' => array( + 'latex_caption', + 'latex_structure_or_data', + ':group:' . __('Structure'), + 'latex_structure_caption', + 'latex_structure_continued_caption', + 'latex_structure_label', + 'latex_relation', + 'latex_comments', + 'latex_mime', + ':group:end', + ':group:' . __('Data'), + 'latex_columns', + 'latex_data_caption', + 'latex_data_continued_caption', + 'latex_data_label', + 'latex_null')); +$forms['Export']['Microsoft_Office'] = array('Export' => array( + ':group:' . __('Microsoft Word 2000'), + 'htmlword_structure_or_data', + 'htmlword_null', + 'htmlword_columns')); +$forms['Export']['Open_Document'] = array('Export' => array( + ':group:' . __('OpenDocument Spreadsheet'), + 'ods_columns', + 'ods_null', + ':group:end', + ':group:' . __('OpenDocument Text'), + 'odt_structure_or_data', + ':group:' . __('Structure'), + 'odt_relation', + 'odt_comments', + 'odt_mime', + ':group:end', + ':group:' . __('Data'), + 'odt_columns', + 'odt_null')); +$forms['Export']['Texy'] = array('Export' => array( + 'texytext_structure_or_data', + ':group:' . __('Data'), + 'texytext_null', + 'texytext_columns')); +?> diff --git a/phpmyadmin/libraries/config/user_preferences.forms.php b/phpmyadmin/libraries/config/user_preferences.forms.php new file mode 100644 index 000000000..e2d2bda03 --- /dev/null +++ b/phpmyadmin/libraries/config/user_preferences.forms.php @@ -0,0 +1,271 @@ + 'phpmyadmin' + * + * To group options, use: + * ':group:' . __('group name') // just define a group + * or + * 'option' => ':group' // group starting from this option + * End group blocks with: + * ':group:end' + * + * @package PhpMyAdmin + */ + +$forms = array(); +$forms['Features']['General'] = array( + 'VersionCheck', + 'NaturalOrder', + 'InitialSlidersState', + 'LoginCookieValidity', + 'Servers/1/only_db', // saves to Server/only_db + 'Servers/1/hide_db', // saves to Server/hide_db + 'SkipLockedTables', + 'DisableMultiTableMaintenance', + 'MaxDbList', + 'MaxTableList', + 'NumRecentTables', + 'ShowHint'); +$forms['Features']['Text_fields'] = array( + 'CharEditing', + 'MinSizeForInputField', + 'MaxSizeForInputField', + 'CharTextareaCols', + 'CharTextareaRows', + 'TextareaCols', + 'TextareaRows', + 'LongtextDoubleTextarea'); +$forms['Features']['Page_titles'] = array( + 'TitleDefault', + 'TitleTable', + 'TitleDatabase', + 'TitleServer'); +$forms['Features']['Warnings'] = array( + 'ServerLibraryDifference_DisableWarning', + 'PmaNoRelation_DisableWarning', + 'SuhosinDisableWarning', + 'McryptDisableWarning', + 'ReservedWordDisableWarning'); +// settings from this form are treated specially, +// see prefs_forms.php and user_preferences.lib.php +$forms['Features']['Developer'] = array( + 'Error_Handler/display', + 'Error_Handler/gather', + 'DBG/sql'); +$forms['Sql_queries']['Sql_queries'] = array( + 'ShowSQL', + 'Confirm', + 'QueryHistoryMax', + 'IgnoreMultiSubmitErrors', + 'MaxCharactersInDisplayedSQL', + 'EditInWindow', + //'QueryWindowWidth', // overridden in theme + //'QueryWindowHeight', + 'QueryWindowDefTab', + 'RetainQueryBox', + 'CodemirrorEnable'); +$forms['Sql_queries']['Sql_box'] = array( + 'SQLQuery/Edit', + 'SQLQuery/Explain', + 'SQLQuery/ShowAsPHP', + 'SQLQuery/Validate', + 'SQLQuery/Refresh'); +$forms['Navi_panel']['Navi_panel'] = array( + 'NavigationDisplayLogo', + 'NavigationLogoLink', + 'NavigationLogoLinkWindow', + 'NavigationTreePointerEnable', + 'MaxNavigationItems', + 'NavigationTreeEnableGrouping', + 'NavigationTreeDisplayItemFilterMinimum'); +$forms['Navi_panel']['Navi_databases'] = array( + 'NavigationTreeDisplayDbFilterMinimum', + 'NavigationTreeDbSeparator'); +$forms['Navi_panel']['Navi_tables'] = array( + 'NavigationTreeDefaultTabTable', + 'NavigationTreeTableSeparator', + 'NavigationTreeTableLevel', + 'ShowTooltip'); +$forms['Main_panel']['Startup'] = array( + 'ShowCreateDb', + 'ShowStats', + 'ShowServerInfo'); +$forms['Main_panel']['DbStructure'] = array( + 'ShowDbStructureCreation', + 'ShowDbStructureLastUpdate', + 'ShowDbStructureLastCheck'); +$forms['Main_panel']['TableStructure'] = array( + 'HideStructureActions'); +$forms['Main_panel']['Browse'] = array( + 'NavigationBarIconic', + 'PropertiesIconic', + 'ShowAll', + 'MaxRows', + 'Order', + 'DisplayBinaryAsHex', + 'BrowsePointerEnable', + 'BrowseMarkerEnable', + 'GridEditing', + 'SaveCellsAtOnce', + 'ShowDisplayDirection', + 'RepeatCells', + 'LimitChars', + 'RowActionLinks', + 'DefaultDisplay', + 'RememberSorting'); +$forms['Main_panel']['Edit'] = array( + 'ProtectBinary', + 'ShowFunctionFields', + 'ShowFieldTypesInDataEditView', + 'InsertRows', + 'ForeignKeyDropdownOrder', + 'ForeignKeyMaxLimit'); +$forms['Main_panel']['Tabs'] = array( + 'DefaultTabServer', + 'DefaultTabDatabase', + 'DefaultTabTable'); +$forms['Import']['Import_defaults'] = array( + 'Import/format', + 'Import/charset', + 'Import/allow_interrupt', + 'Import/skip_queries'); +$forms['Import']['Sql'] = array( + 'Import/sql_compatibility', + 'Import/sql_no_auto_value_on_zero'); +$forms['Import']['Csv'] = array( + ':group:' . __('CSV'), + 'Import/csv_replace', + 'Import/csv_ignore', + 'Import/csv_terminated', + 'Import/csv_enclosed', + 'Import/csv_escaped', + 'Import/csv_col_names', + ':group:end', + ':group:' . __('CSV using LOAD DATA'), + 'Import/ldi_replace', + 'Import/ldi_ignore', + 'Import/ldi_terminated', + 'Import/ldi_enclosed', + 'Import/ldi_escaped', + 'Import/ldi_local_option'); +$forms['Import']['Open_Document'] = array( + ':group:' . __('OpenDocument Spreadsheet'), + 'Import/ods_col_names', + 'Import/ods_empty_rows', + 'Import/ods_recognize_percentages', + 'Import/ods_recognize_currency'); +$forms['Export']['Export_defaults'] = array( + 'Export/method', + ':group:' . __('Quick'), + 'Export/quick_export_onserver', + 'Export/quick_export_onserver_overwrite', + ':group:end', + ':group:' . __('Custom'), + 'Export/format', + 'Export/compression', + 'Export/charset', + 'Export/asfile' => ':group', + 'Export/onserver', + 'Export/onserver_overwrite', + ':group:end', + 'Export/file_template_table', + 'Export/file_template_database', + 'Export/file_template_server'); +$forms['Export']['Sql'] = array( + 'Export/sql_include_comments' => ':group', + 'Export/sql_dates', + 'Export/sql_relation', + 'Export/sql_mime', + ':group:end', + 'Export/sql_use_transaction', + 'Export/sql_disable_fk', + 'Export/sql_compatibility', + ':group:' . __('Database export options'), + 'Export/sql_drop_database', + 'Export/sql_structure_or_data', + ':group:end', + ':group:' . __('Structure'), + 'Export/sql_drop_table', + 'Export/sql_procedure_function', + 'Export/sql_create_table_statements' => ':group', + 'Export/sql_if_not_exists', + 'Export/sql_auto_increment', + ':group:end', + 'Export/sql_backquotes', + ':group:end', + ':group:' . __('Data'), + 'Export/sql_delayed', + 'Export/sql_ignore', + 'Export/sql_type', + 'Export/sql_insert_syntax', + 'Export/sql_max_query_size', + 'Export/sql_hex_for_blob', + 'Export/sql_utc_time'); +$forms['Export']['CodeGen'] = array( + 'Export/codegen_format'); +$forms['Export']['Csv'] = array( + ':group:' . __('CSV'), + 'Export/csv_separator', + 'Export/csv_enclosed', + 'Export/csv_escaped', + 'Export/csv_terminated', + 'Export/csv_null', + 'Export/csv_removeCRLF', + 'Export/csv_columns', + ':group:end', + ':group:' . __('CSV for MS Excel'), + 'Export/excel_null', + 'Export/excel_removeCRLF', + 'Export/excel_columns', + 'Export/excel_edition'); +$forms['Export']['Latex'] = array( + 'Export/latex_caption', + 'Export/latex_structure_or_data', + ':group:' . __('Structure'), + 'Export/latex_structure_caption', + 'Export/latex_structure_continued_caption', + 'Export/latex_structure_label', + 'Export/latex_relation', + 'Export/latex_comments', + 'Export/latex_mime', + ':group:end', + ':group:' . __('Data'), + 'Export/latex_columns', + 'Export/latex_data_caption', + 'Export/latex_data_continued_caption', + 'Export/latex_data_label', + 'Export/latex_null'); +$forms['Export']['Microsoft_Office'] = array( + ':group:' . __('Microsoft Word 2000'), + 'Export/htmlword_structure_or_data', + 'Export/htmlword_null', + 'Export/htmlword_columns'); +$forms['Export']['Open_Document'] = array( + ':group:' . __('OpenDocument Spreadsheet'), + 'Export/ods_columns', + 'Export/ods_null', + ':group:end', + ':group:' . __('OpenDocument Text'), + 'Export/odt_structure_or_data', + ':group:' . __('Structure'), + 'Export/odt_relation', + 'Export/odt_comments', + 'Export/odt_mime', + ':group:end', + ':group:' . __('Data'), + 'Export/odt_columns', + 'Export/odt_null'); +$forms['Export']['Texy'] = array( + 'Export/texytext_structure_or_data', + ':group:' . __('Data'), + 'Export/texytext_null', + 'Export/texytext_columns'); +?> diff --git a/phpmyadmin/libraries/config/validate.lib.php b/phpmyadmin/libraries/config/validate.lib.php new file mode 100644 index 000000000..cd03b6bed --- /dev/null +++ b/phpmyadmin/libraries/config/validate.lib.php @@ -0,0 +1,584 @@ +getDbEntry('_validators', array()); + if (!defined('PMA_SETUP')) { + // not in setup script: load additional validators for user + // preferences we need original config values not overwritten + // by user preferences, creating a new PMA_Config instance is a + // better idea than hacking into its code + $org_cfg = $cf->getOrgConfigObj(); + $uvs = $cf->getDbEntry('_userValidators', array()); + foreach ($uvs as $field => $uv_list) { + $uv_list = (array)$uv_list; + foreach ($uv_list as &$uv) { + if (!is_array($uv)) { + continue; + } + for ($i = 1; $i < count($uv); $i++) { + if (substr($uv[$i], 0, 6) == 'value:') { + $uv[$i] = PMA_arrayRead( + substr($uv[$i], 6), $org_cfg->settings + ); + } + } + } + $validators[$field] = isset($validators[$field]) + ? array_merge((array)$validators[$field], $uv_list) + : $uv_list; + } + } + } + return $validators; +} + +/** + * Runs validation $validator_id on values $values and returns error list. + * + * Return values: + * o array, keys - field path or formset id, values - array of errors + * when $isPostSource is true values is an empty array to allow for error list + * cleanup in HTML documen + * o false - when no validators match name(s) given by $validator_id + * + * @param string|array $validator_id ID of validator(s) to run + * @param array &$values Values to validate + * @param bool $isPostSource tells whether $values are directly from + * POST request + * + * @return bool|array + */ +function PMA_config_validate($validator_id, &$values, $isPostSource) +{ + // find validators + $validator_id = (array) $validator_id; + $validators = PMA_config_get_validators(); + $vids = array(); + $cf = ConfigFile::getInstance(); + foreach ($validator_id as &$vid) { + $vid = $cf->getCanonicalPath($vid); + if (isset($validators[$vid])) { + $vids[] = $vid; + } + } + if (empty($vids)) { + return false; + } + + // create argument list with canonical paths and remember path mapping + $arguments = array(); + $key_map = array(); + foreach ($values as $k => $v) { + $k2 = $isPostSource ? str_replace('-', '/', $k) : $k; + $k2 = strpos($k2, '/') ? $cf->getCanonicalPath($k2) : $k2; + $key_map[$k2] = $k; + $arguments[$k2] = $v; + } + + // validate + $result = array(); + foreach ($vids as $vid) { + // call appropriate validation functions + foreach ((array)$validators[$vid] as $validator) { + $vdef = (array) $validator; + $vname = array_shift($vdef); + $args = array_merge(array($vid, &$arguments), $vdef); + $r = call_user_func_array($vname, $args); + + // merge results + if (is_array($r)) { + foreach ($r as $key => $error_list) { + // skip empty values if $isPostSource is false + if (!$isPostSource && empty($error_list)) { + continue; + } + if (!isset($result[$key])) { + $result[$key] = array(); + } + $result[$key] = array_merge($result[$key], (array)$error_list); + } + } + } + } + + // restore original paths + $new_result = array(); + foreach ($result as $k => $v) { + $k2 = isset($key_map[$k]) ? $key_map[$k] : $k; + $new_result[$k2] = $v; + } + return empty($new_result) ? true : $new_result; +} + +/** + * Empty error handler, used to temporarily restore PHP internal error handler + * + * @return bool + */ +function PMA_null_error_handler() +{ + return false; +} + +/** + * Ensures that $php_errormsg variable will be registered in case of an error + * and enables output buffering (when $start = true). + * Called with $start = false disables output buffering end restores + * html_errors and track_errors. + * + * @param boolean $start Whether to start buffering + * + * @return void + */ +function test_php_errormsg($start = true) +{ + static $old_html_errors, $old_track_errors, $old_error_reporting; + static $old_display_errors; + if ($start) { + $old_html_errors = ini_get('html_errors'); + $old_track_errors = ini_get('track_errors'); + $old_display_errors = ini_get('display_errors'); + $old_error_reporting = error_reporting(E_ALL); + ini_set('html_errors', false); + ini_set('track_errors', true); + ini_set('display_errors', true); + set_error_handler("PMA_null_error_handler"); + ob_start(); + } else { + ob_end_clean(); + restore_error_handler(); + error_reporting($old_error_reporting); + ini_set('html_errors', $old_html_errors); + ini_set('track_errors', $old_track_errors); + ini_set('display_errors', $old_display_errors); + } +} + +/** + * Test database connection + * + * @param string $extension 'drizzle', 'mysql' or 'mysqli' + * @param string $connect_type 'tcp' or 'socket' + * @param string $host host name + * @param string $port tcp port to use + * @param string $socket socket to use + * @param string $user username to use + * @param string $pass password to use + * @param string $error_key key to use in return array + * + * @return bool|array + */ +function test_db_connection( + $extension, + $connect_type, + $host, + $port, + $socket, + $user, + $pass = null, + $error_key = 'Server' +) { + // test_php_errormsg(); + $socket = empty($socket) || $connect_type == 'tcp' ? null : $socket; + $port = empty($port) || $connect_type == 'socket' ? null : ':' . $port; + $error = null; + if ($extension == 'drizzle') { + while (1) { + $drizzle = @drizzle_create(); + if (!$drizzle) { + $error = __('Could not initialize Drizzle connection library'); + break; + } + $conn = $socket + ? @drizzle_con_add_uds($socket, $user, $pass, null, 0) + : @drizzle_con_add_tcp( + $drizzle, $host, $port, $user, $pass, null, 0 + ); + if (!$conn) { + $error = __('Could not connect to Drizzle server'); + drizzle_free($drizzle); + break; + } + // connection object is set up but we have to send some query + // to actually connect + $res = @drizzle_query($conn, 'SELECT 1'); + if (!$res) { + $error = __('Could not connect to Drizzle server'); + } else { + drizzle_result_free($res); + } + drizzle_con_free($conn); + drizzle_free($drizzle); + break; + } + } else if ($extension == 'mysql') { + $conn = @mysql_connect($host . $socket . $port, $user, $pass); + if (!$conn) { + $error = __('Could not connect to MySQL server'); + } else { + mysql_close($conn); + } + } else { + $conn = @mysqli_connect($host, $user, $pass, null, $port, $socket); + if (!$conn) { + $error = __('Could not connect to MySQL server'); + } else { + mysqli_close($conn); + } + } + // test_php_errormsg(false); + if (isset($php_errormsg)) { + $error .= " - $php_errormsg"; + } + return is_null($error) ? true : array($error_key => $error); +} + +/** + * Validate server config + * + * @param string $path path to config, not used + * @param array $values config values + * + * @return array + */ +function validate_server($path, $values) +{ + $result = array( + 'Server' => '', + 'Servers/1/user' => '', + 'Servers/1/SignonSession' => '', + 'Servers/1/SignonURL' => '' + ); + $error = false; + if ($values['Servers/1/auth_type'] == 'config' + && empty($values['Servers/1/user']) + ) { + $result['Servers/1/user'] + = __('Empty username while using config authentication method'); + $error = true; + } + if ($values['Servers/1/auth_type'] == 'signon' + && empty($values['Servers/1/SignonSession']) + ) { + $result['Servers/1/SignonSession'] = __( + 'Empty signon session name ' + . 'while using signon authentication method' + ); + $error = true; + } + if ($values['Servers/1/auth_type'] == 'signon' + && empty($values['Servers/1/SignonURL']) + ) { + $result['Servers/1/SignonURL'] + = __('Empty signon URL while using signon authentication method'); + $error = true; + } + + if (!$error && $values['Servers/1/auth_type'] == 'config') { + $password = $values['Servers/1/nopassword'] ? null + : $values['Servers/1/password']; + $test = test_db_connection( + $values['Servers/1/extension'], + $values['Servers/1/connect_type'], + $values['Servers/1/host'], + $values['Servers/1/port'], + $values['Servers/1/socket'], + $values['Servers/1/user'], + $password, + 'Server' + ); + if ($test !== true) { + $result = array_merge($result, $test); + } + } + return $result; +} + +/** + * Validate pmadb config + * + * @param string $path path to config, not used + * @param array $values config values + * + * @return array + */ +function validate_pmadb($path, $values) +{ + $result = array( + 'Server_pmadb' => '', + 'Servers/1/controluser' => '', + 'Servers/1/controlpass' => '' + ); + $error = false; + + if ($values['Servers/1/pmadb'] == '') { + return $result; + } + + $result = array(); + if ($values['Servers/1/controluser'] == '') { + $result['Servers/1/controluser'] + = __('Empty phpMyAdmin control user while using pmadb'); + $error = true; + } + if ($values['Servers/1/controlpass'] == '') { + $result['Servers/1/controlpass'] + = __('Empty phpMyAdmin control user password while using pmadb'); + $error = true; + } + if (!$error) { + $test = test_db_connection( + $values['Servers/1/extension'], $values['Servers/1/connect_type'], + $values['Servers/1/host'], $values['Servers/1/port'], + $values['Servers/1/socket'], $values['Servers/1/controluser'], + $values['Servers/1/controlpass'], 'Server_pmadb' + ); + if ($test !== true) { + $result = array_merge($result, $test); + } + } + return $result; +} + + +/** + * Validates regular expression + * + * @param string $path path to config + * @param array $values config values + * + * @return array + */ +function validate_regex($path, $values) +{ + $result = array($path => ''); + + if ($values[$path] == '') { + return $result; + } + + test_php_errormsg(); + + $matches = array(); + // in libraries/List_Database.class.php _checkHideDatabase(), + // a '/' is used as the delimiter for hide_db + preg_match('/' . $values[$path] . '/', '', $matches); + + test_php_errormsg(false); + + if (isset($php_errormsg)) { + $error = preg_replace('/^preg_match\(\): /', '', $php_errormsg); + return array($path => $error); + } + + return $result; +} + +/** + * Validates TrustedProxies field + * + * @param string $path path to config + * @param array $values config values + * + * @return array + */ +function validate_trusted_proxies($path, $values) +{ + $result = array($path => array()); + + if (empty($values[$path])) { + return $result; + } + + if (is_array($values[$path])) { + // value already processed by FormDisplay::save + $lines = array(); + foreach ($values[$path] as $ip => $v) { + $lines[] = preg_match('/^-\d+$/', $ip) + ? $v + : $ip . ': ' . $v; + } + } else { + // AJAX validation + $lines = explode("\n", $values[$path]); + } + foreach ($lines as $line) { + $line = trim($line); + $matches = array(); + // we catch anything that may (or may not) be an IP + if (!preg_match("/^(.+):(?:[ ]?)\\w+$/", $line, $matches)) { + $result[$path][] = __('Incorrect value') . ': ' . $line; + continue; + } + // now let's check whether we really have an IP address + if (filter_var($matches[1], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false + && filter_var($matches[1], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false + ) { + $ip = htmlspecialchars(trim($matches[1])); + $result[$path][] = sprintf(__('Incorrect IP address: %s'), $ip); + continue; + } + } + + return $result; +} + +/** + * Tests integer value + * + * @param string $path path to config + * @param array $values config values + * @param bool $allow_neg allow negative values + * @param bool $allow_zero allow zero + * @param int $max_value max allowed value + * @param string $error_string error message key: + * $GLOBALS["strConfig$error_lang_key"] + * + * @return string empty string if test is successful + */ +function test_number( + $path, + $values, + $allow_neg, + $allow_zero, + $max_value, + $error_string +) { + if ($values[$path] === '') { + return ''; + } + + if (intval($values[$path]) != $values[$path] + || (!$allow_neg && $values[$path] < 0) + || (!$allow_zero && $values[$path] == 0) + || $values[$path] > $max_value + ) { + return $error_string; + } + + return ''; +} + +/** + * Validates port number + * + * @param string $path path to config + * @param array $values config values + * + * @return array + */ +function validate_port_number($path, $values) +{ + return array( + $path => test_number( + $path, + $values, + false, + false, + 65535, + __('Not a valid port number') + ) + ); +} + +/** + * Validates positive number + * + * @param string $path path to config + * @param array $values config values + * + * @return array + */ +function validate_positive_number($path, $values) +{ + return array( + $path => test_number( + $path, + $values, + false, + false, + PHP_INT_MAX, + __('Not a positive number') + ) + ); +} + +/** + * Validates non-negative number + * + * @param string $path path to config + * @param array $values config values + * + * @return array + */ +function validate_non_negative_number($path, $values) +{ + return array( + $path => test_number( + $path, + $values, + false, + true, + PHP_INT_MAX, + __('Not a non-negative number') + ) + ); +} + +/** + * Validates value according to given regular expression + * Pattern and modifiers must be a valid for PCRE and JavaScript RegExp + * + * @param string $path path to config + * @param array $values config values + * @param string $regex regullar expression to match + * + * @return array + */ +function validate_by_regex($path, $values, $regex) +{ + $result = preg_match($regex, $values[$path]); + return array($path => ($result ? '' : __('Incorrect value'))); +} + +/** + * Validates upper bound for numeric inputs + * + * @param string $path path to config + * @param array $values config values + * @param int $max_value maximal allowed value + * + * @return array + */ +function validate_upper_bound($path, $values, $max_value) +{ + $result = $values[$path] <= $max_value; + return array($path => ($result ? '' + : sprintf(__('Value must be equal or lower than %s'), $max_value))); +} +?> diff --git a/phpmyadmin/libraries/core.lib.php b/phpmyadmin/libraries/core.lib.php new file mode 100644 index 000000000..f5d92bd36 --- /dev/null +++ b/phpmyadmin/libraries/core.lib.php @@ -0,0 +1,802 @@ + + * // $_REQUEST['db'] not set + * echo PMA_ifSetOr($_REQUEST['db'], ''); // '' + * // $_REQUEST['sql_query'] not set + * echo PMA_ifSetOr($_REQUEST['sql_query']); // null + * // $cfg['ForceSSL'] not set + * echo PMA_ifSetOr($cfg['ForceSSL'], false, 'boolean'); // false + * echo PMA_ifSetOr($cfg['ForceSSL']); // null + * // $cfg['ForceSSL'] set to 1 + * echo PMA_ifSetOr($cfg['ForceSSL'], false, 'boolean'); // false + * echo PMA_ifSetOr($cfg['ForceSSL'], false, 'similar'); // 1 + * echo PMA_ifSetOr($cfg['ForceSSL'], false); // 1 + * // $cfg['ForceSSL'] set to true + * echo PMA_ifSetOr($cfg['ForceSSL'], false, 'boolean'); // true + * + * + * @param mixed &$var param to check + * @param mixed $default default value + * @param mixed $type var type or array of values to check against $var + * + * @return mixed $var or $default + * + * @see PMA_isValid() + */ +function PMA_ifSetOr(&$var, $default = null, $type = 'similar') +{ + if (! PMA_isValid($var, $type, $default)) { + return $default; + } + + return $var; +} + +/** + * checks given $var against $type or $compare + * + * $type can be: + * - false : no type checking + * - 'scalar' : whether type of $var is integer, float, string or boolean + * - 'numeric' : whether type of $var is any number repesentation + * - 'length' : whether type of $var is scalar with a string length > 0 + * - 'similar' : whether type of $var is similar to type of $compare + * - 'equal' : whether type of $var is identical to type of $compare + * - 'identical' : whether $var is identical to $compare, not only the type! + * - or any other valid PHP variable type + * + * + * // $_REQUEST['doit'] = true; + * PMA_isValid($_REQUEST['doit'], 'identical', 'true'); // false + * // $_REQUEST['doit'] = 'true'; + * PMA_isValid($_REQUEST['doit'], 'identical', 'true'); // true + * + * + * NOTE: call-by-reference is used to not get NOTICE on undefined vars, + * but the var is not altered inside this function, also after checking a var + * this var exists nut is not set, example: + * + * // $var is not set + * isset($var); // false + * functionCallByReference($var); // false + * isset($var); // true + * functionCallByReference($var); // true + * + * + * to avoid this we set this var to null if not isset + * + * @param mixed &$var variable to check + * @param mixed $type var type or array of valid values to check against $var + * @param mixed $compare var to compare with $var + * + * @return boolean whether valid or not + * + * @todo add some more var types like hex, bin, ...? + * @see http://php.net/gettype + */ +function PMA_isValid(&$var, $type = 'length', $compare = null) +{ + if (! isset($var)) { + // var is not even set + return false; + } + + if ($type === false) { + // no vartype requested + return true; + } + + if (is_array($type)) { + return in_array($var, $type); + } + + // allow some aliaes of var types + $type = strtolower($type); + switch ($type) { + case 'identic' : + $type = 'identical'; + break; + case 'len' : + $type = 'length'; + break; + case 'bool' : + $type = 'boolean'; + break; + case 'float' : + $type = 'double'; + break; + case 'int' : + $type = 'integer'; + break; + case 'null' : + $type = 'NULL'; + break; + } + + if ($type === 'identical') { + return $var === $compare; + } + + // whether we should check against given $compare + if ($type === 'similar') { + switch (gettype($compare)) { + case 'string': + case 'boolean': + $type = 'scalar'; + break; + case 'integer': + case 'double': + $type = 'numeric'; + break; + default: + $type = gettype($compare); + } + } elseif ($type === 'equal') { + $type = gettype($compare); + } + + // do the check + if ($type === 'length' || $type === 'scalar') { + $is_scalar = is_scalar($var); + if ($is_scalar && $type === 'length') { + return (bool) strlen($var); + } + return $is_scalar; + } + + if ($type === 'numeric') { + return is_numeric($var); + } + + if (gettype($var) === $type) { + return true; + } + + return false; +} + +/** + * Removes insecure parts in a path; used before include() or + * require() when a part of the path comes from an insecure source + * like a cookie or form. + * + * @param string $path The path to check + * + * @return string The secured path + * + * @access public + */ +function PMA_securePath($path) +{ + // change .. to . + $path = preg_replace('@\.\.*@', '.', $path); + + return $path; +} // end function + +/** + * displays the given error message on phpMyAdmin error page in foreign language, + * ends script execution and closes session + * + * loads language file if not loaded already + * + * @param string $error_message the error message or named error message + * @param string|array $message_args arguments applied to $error_message + * @param boolean $delete_session whether to delete session cookie + * + * @return exit + */ +function PMA_fatalError( + $error_message, $message_args = null, $delete_session = true +) { + /* Use format string if applicable */ + if (is_string($message_args)) { + $error_message = sprintf($error_message, $message_args); + } elseif (is_array($message_args)) { + $error_message = vsprintf($error_message, $message_args); + } + + if ($GLOBALS['is_ajax_request']) { + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', PMA_Message::error($error_message)); + } else { + $error_message = strtr($error_message, array('
      ' => '[br]')); + + /* Define fake gettext for fatal errors */ + if (!function_exists('__')) { + function __($text) + { + return $text; + } + } + + // these variables are used in the included file libraries/error.inc.php + $error_header = __('Error'); + $lang = $GLOBALS['available_languages'][$GLOBALS['lang']][1]; + $dir = $GLOBALS['text_dir']; + + // on fatal errors it cannot hurt to always delete the current session + if ($delete_session + && isset($GLOBALS['session_name']) + && isset($_COOKIE[$GLOBALS['session_name']]) + ) { + $GLOBALS['PMA_Config']->removeCookie($GLOBALS['session_name']); + } + + // Displays the error message + include './libraries/error.inc.php'; + } + if (! defined('TESTSUITE')) { + exit; + } +} + +/** + * Returns a link to the PHP documentation + * + * @param string $target anchor in documentation + * + * @return string the URL + * + * @access public + */ +function PMA_getPHPDocLink($target) +{ + /* List of PHP documentation translations */ + $php_doc_languages = array( + 'pt_BR', 'zh', 'fr', 'de', 'it', 'ja', 'pl', 'ro', 'ru', 'fa', 'es', 'tr' + ); + + $lang = 'en'; + if (in_array($GLOBALS['lang'], $php_doc_languages)) { + $lang = $GLOBALS['lang']; + } + + return PMA_linkURL('http://php.net/manual/' . $lang . '/' . $target); +} + +/** + * Warn or fail on missing extension. + * + * @param string $extension Extension name + * @param bool $fatal Whether the error is fatal. + * @param string $extra Extra string to append to messsage. + * + * @return void + */ +function PMA_warnMissingExtension($extension, $fatal = false, $extra = '') +{ + /* Gettext does not have to be loaded yet here */ + if (function_exists('__')) { + $message = __( + 'The %s extension is missing. Please check your PHP configuration.' + ); + } else { + $message + = 'The %s extension is missing. Please check your PHP configuration.'; + } + $doclink = PMA_getPHPDocLink('book.' . $extension . '.php'); + $message = sprintf( + $message, + '[a@' . $doclink . '@Documentation][em]' . $extension . '[/em][/a]' + ); + if ($extra != '') { + $message .= ' ' . $extra; + } + if ($fatal) { + PMA_fatalError($message); + } else { + $GLOBALS['error_handler']->addError( + $message, + E_USER_WARNING, + '', + '', + false + ); + } +} + +/** + * returns count of tables in given db + * + * @param string $db database to count tables for + * + * @return integer count of tables in $db + */ +function PMA_getTableCount($db) +{ + $tables = PMA_DBI_try_query( + 'SHOW TABLES FROM ' . PMA_Util::backquote($db) . ';', + null, PMA_DBI_QUERY_STORE + ); + if ($tables) { + $num_tables = PMA_DBI_num_rows($tables); + PMA_DBI_free_result($tables); + } else { + $num_tables = 0; + } + + return $num_tables; +} + +/** + * Converts numbers like 10M into bytes + * Used with permission from Moodle (http://moodle.org) by Martin Dougiamas + * (renamed with PMA prefix to avoid double definition when embedded + * in Moodle) + * + * @param string $size size + * + * @return integer $size + */ +function PMA_getRealSize($size = 0) +{ + if (! $size) { + return 0; + } + + $scan['gb'] = 1073741824; //1024 * 1024 * 1024; + $scan['g'] = 1073741824; //1024 * 1024 * 1024; + $scan['mb'] = 1048576; + $scan['m'] = 1048576; + $scan['kb'] = 1024; + $scan['k'] = 1024; + $scan['b'] = 1; + + foreach ($scan as $unit => $factor) { + if (strlen($size) > strlen($unit) + && strtolower(substr($size, strlen($size) - strlen($unit))) == $unit + ) { + return substr($size, 0, strlen($size) - strlen($unit)) * $factor; + } + } + + return $size; +} // end function PMA_getRealSize() + +/** + * merges array recursive like array_merge_recursive() but keyed-values are + * always overwritten. + * + * array PMA_arrayMergeRecursive(array $array1[, array $array2[, array ...]]) + * + * @return array merged array + * + * @see http://php.net/array_merge + * @see http://php.net/array_merge_recursive + */ +function PMA_arrayMergeRecursive() +{ + switch(func_num_args()) { + case 0 : + return false; + break; + case 1 : + // when does that happen? + return func_get_arg(0); + break; + case 2 : + $args = func_get_args(); + if (! is_array($args[0]) || ! is_array($args[1])) { + return $args[1]; + } + foreach ($args[1] as $key2 => $value2) { + if (isset($args[0][$key2]) && !is_int($key2)) { + $args[0][$key2] = PMA_arrayMergeRecursive( + $args[0][$key2], $value2 + ); + } else { + // we erase the parent array, otherwise we cannot override + // a directive that contains array elements, like this: + // (in config.default.php) + // $cfg['ForeignKeyDropdownOrder']= array('id-content','content-id'); + // (in config.inc.php) + // $cfg['ForeignKeyDropdownOrder']= array('content-id'); + if (is_int($key2) && $key2 == 0) { + unset($args[0]); + } + $args[0][$key2] = $value2; + } + } + return $args[0]; + break; + default : + $args = func_get_args(); + $args[1] = PMA_arrayMergeRecursive($args[0], $args[1]); + array_shift($args); + return call_user_func_array('PMA_arrayMergeRecursive', $args); + break; + } +} + +/** + * calls $function for every element in $array recursively + * + * this function is protected against deep recursion attack CVE-2006-1549, + * 1000 seems to be more than enough + * + * @param array &$array array to walk + * @param string $function function to call for every array element + * @param bool $apply_to_keys_also whether to call the function for the keys also + * + * @return void + * + * @see http://www.php-security.org/MOPB/MOPB-02-2007.html + * @see http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-1549 + */ +function PMA_arrayWalkRecursive(&$array, $function, $apply_to_keys_also = false) +{ + static $recursive_counter = 0; + if (++$recursive_counter > 1000) { + PMA_fatalError(__('possible deep recursion attack')); + } + foreach ($array as $key => $value) { + if (is_array($value)) { + PMA_arrayWalkRecursive($array[$key], $function, $apply_to_keys_also); + } else { + $array[$key] = $function($value); + } + + if ($apply_to_keys_also && is_string($key)) { + $new_key = $function($key); + if ($new_key != $key) { + $array[$new_key] = $array[$key]; + unset($array[$key]); + } + } + } + $recursive_counter--; +} + +/** + * boolean phpMyAdmin.PMA_checkPageValidity(string &$page, array $whitelist) + * + * checks given given $page against given $whitelist and returns true if valid + * it ignores optionaly query paramters in $page (script.php?ignored) + * + * @param string &$page page to check + * @param array $whitelist whitelist to check page against + * + * @return boolean whether $page is valid or not (in $whitelist or not) + */ +function PMA_checkPageValidity(&$page, $whitelist) +{ + if (! isset($page) || !is_string($page)) { + return false; + } + + if (in_array($page, $whitelist)) { + return true; + } elseif (in_array(substr($page, 0, strpos($page . '?', '?')), $whitelist)) { + return true; + } else { + $_page = urldecode($page); + if (in_array(substr($_page, 0, strpos($_page . '?', '?')), $whitelist)) { + return true; + } + } + return false; +} + +/** + * tries to find the value for the given environment variable name + * + * searches in $_SERVER, $_ENV then tries getenv() and apache_getenv() + * in this order + * + * @param string $var_name variable name + * + * @return string value of $var or empty string + */ +function PMA_getenv($var_name) +{ + if (isset($_SERVER[$var_name])) { + return $_SERVER[$var_name]; + } elseif (isset($_ENV[$var_name])) { + return $_ENV[$var_name]; + } elseif (getenv($var_name)) { + return getenv($var_name); + } elseif (function_exists('apache_getenv') + && apache_getenv($var_name, true)) { + return apache_getenv($var_name, true); + } + + return ''; +} + +/** + * Send HTTP header, taking IIS limits into account (600 seems ok) + * + * @param string $uri the header to send + * @param bool $use_refresh whether to use Refresh: header when running on IIS + * + * @return boolean always true + */ +function PMA_sendHeaderLocation($uri, $use_refresh = false) +{ + if (PMA_IS_IIS && strlen($uri) > 600) { + include_once './libraries/js_escape.lib.php'; + PMA_Response::getInstance()->disable(); + + echo '- - -' . "\n"; + echo '' . "\n"; + echo '' . "\n"; + echo '' . "\n"; + echo '' . "\n"; + echo '' . "\n"; + echo '' . "\n"; + echo '' . "\n"; + echo '' . "\n"; + + } else { + if (SID) { + if (strpos($uri, '?') === false) { + header('Location: ' . $uri . '?' . SID); + } else { + $separator = PMA_get_arg_separator(); + header('Location: ' . $uri . $separator . SID); + } + } else { + session_write_close(); + if (headers_sent()) { + if (function_exists('debug_print_backtrace')) { + echo '
      ';
      +                    debug_print_backtrace();
      +                    echo '
      '; + } + trigger_error( + 'PMA_sendHeaderLocation called when headers are already sent!', + E_USER_ERROR + ); + } + // bug #1523784: IE6 does not like 'Refresh: 0', it + // results in a blank page + // but we need it when coming from the cookie login panel) + if (PMA_IS_IIS && $use_refresh) { + header('Refresh: 0; ' . $uri); + } else { + header('Location: ' . $uri); + } + } + } +} + +/** + * Outputs headers to prevent caching in browser (and on the way). + * + * @return void + */ +function PMA_noCacheHeader() +{ + if (defined('TESTSUITE')) { + return; + } + // rfc2616 - Section 14.21 + header('Expires: ' . date(DATE_RFC1123)); + // HTTP/1.1 + header( + 'Cache-Control: no-store, no-cache, must-revalidate,' + . ' pre-check=0, post-check=0, max-age=0' + ); + if (PMA_USR_BROWSER_AGENT == 'IE') { + /* On SSL IE sometimes fails with: + * + * Internet Explorer was not able to open this Internet site. The + * requested site is either unavailable or cannot be found. Please + * try again later. + * + * Adding Pragma: public fixes this. + */ + header('Pragma: public'); + } else { + header('Pragma: no-cache'); // HTTP/1.0 + // test case: exporting a database into a .gz file with Safari + // would produce files not having the current time + // (added this header for Safari but should not harm other browsers) + header('Last-Modified: ' . date(DATE_RFC1123)); + } +} + + +/** + * Sends header indicating file download. + * + * @param string $filename Filename to include in headers if empty, + * none Content-Disposition header will be sent. + * @param string $mimetype MIME type to include in headers. + * @param int $length Length of content (optional) + * @param bool $no_cache Whether to include no-caching headers. + * + * @return void + */ +function PMA_downloadHeader($filename, $mimetype, $length = 0, $no_cache = true) +{ + if ($no_cache) { + PMA_noCacheHeader(); + } + /* Replace all possibly dangerous chars in filename */ + $filename = str_replace(array(';', '"', "\n", "\r"), '-', $filename); + if (!empty($filename)) { + header('Content-Description: File Transfer'); + header('Content-Disposition: attachment; filename="' . $filename . '"'); + } + header('Content-Type: ' . $mimetype); + header('Content-Transfer-Encoding: binary'); + if ($length > 0) { + header('Content-Length: ' . $length); + } +} + + +/** + * Returns value of an element in $array given by $path. + * $path is a string describing position of an element in an associative array, + * eg. Servers/1/host refers to $array[Servers][1][host] + * + * @param string $path path in the arry + * @param array $array the array + * @param mixed $default default value + * + * @return mixed array element or $default + */ +function PMA_arrayRead($path, $array, $default = null) +{ + $keys = explode('/', $path); + $value =& $array; + foreach ($keys as $key) { + if (! isset($value[$key])) { + return $default; + } + $value =& $value[$key]; + } + return $value; +} + +/** + * Stores value in an array + * + * @param string $path path in the array + * @param array &$array the array + * @param mixed $value value to store + * + * @return void + */ +function PMA_arrayWrite($path, &$array, $value) +{ + $keys = explode('/', $path); + $last_key = array_pop($keys); + $a =& $array; + foreach ($keys as $key) { + if (! isset($a[$key])) { + $a[$key] = array(); + } + $a =& $a[$key]; + } + $a[$last_key] = $value; +} + +/** + * Removes value from an array + * + * @param string $path path in the array + * @param array &$array the array + * + * @return void + */ +function PMA_arrayRemove($path, &$array) +{ + $keys = explode('/', $path); + $keys_last = array_pop($keys); + $path = array(); + $depth = 0; + + $path[0] =& $array; + $found = true; + // go as deep as required or possible + foreach ($keys as $key) { + if (! isset($path[$depth][$key])) { + $found = false; + break; + } + $depth++; + $path[$depth] =& $path[$depth-1][$key]; + } + // if element found, remove it + if ($found) { + unset($path[$depth][$keys_last]); + $depth--; + } + + // remove empty nested arrays + for (; $depth >= 0; $depth--) { + if (! isset($path[$depth+1]) || count($path[$depth+1]) == 0) { + unset($path[$depth][$keys[$depth]]); + } else { + break; + } + } +} + +/** + * Returns link to (possibly) external site using defined redirector. + * + * @param string $url URL where to go. + * + * @return string URL for a link. + */ +function PMA_linkURL($url) +{ + if (!preg_match('#^https?://#', $url) || defined('PMA_SETUP')) { + return $url; + } else { + if (!function_exists('PMA_generate_common_url')) { + include_once './libraries/url_generating.lib.php'; + } + $params = array(); + $params['url'] = $url; + return './url.php' . PMA_generate_common_url($params); + } +} + +/** + * Adds JS code snippets to be displayed by the PMA_Response class. + * Adds a newline to each snippet. + * + * @param string $str Js code to be added (e.g. "token=1234;") + * + * @return void + */ +function PMA_addJSCode($str) +{ + $response = PMA_Response::getInstance(); + $header = $response->getHeader(); + $scripts = $header->getScripts(); + $scripts->addCode($str); +} + +/** + * Adds JS code snippet for variable assignment + * to be displayed by the PMA_Response class. + * + * @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) + * + * @return void + */ +function PMA_addJSVar($key, $value, $escape = true) +{ + PMA_addJSCode(PMA_getJsValue($key, $value, $escape)); +} + +?> diff --git a/phpmyadmin/libraries/data_dictionary_relations.lib.php b/phpmyadmin/libraries/data_dictionary_relations.lib.php new file mode 100644 index 000000000..651dd658f --- /dev/null +++ b/phpmyadmin/libraries/data_dictionary_relations.lib.php @@ -0,0 +1,166 @@ + array( + 'DEFAULT_COLLATE_NAME' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ) + ), + 'COLLATIONS' => array( + 'CHARACTER_SET_NAME' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'CHARACTER_SETS', + 'foreign_field' => 'CHARACTER_SET_NAME' + ) + ), + 'COLUMNS' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'SCHEMAS', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'COLLATION_NAME' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ) + ), + 'INDEXES' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'SCHEMAS', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), + 'INDEX_PARTS' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'SCHEMAS', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), + 'INNODB_LOCKS' => array( + 'LOCK_TRX_ID' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'INNODB_TRX', + 'foreign_field' => 'TRX_ID' + ) + ), + 'INNODB_LOCK_WAITS' => array( + 'REQUESTING_TRX_ID' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'INNODB_TRX', + 'foreign_field' => 'TRX_ID' + ), + 'REQUESTED_LOCK_ID' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'INNODB_LOCKS', + 'foreign_field' => 'LOCK_ID' + ), + 'BLOCKING_TRX_ID' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'INNODB_TRX', + 'foreign_field' => 'TRX_ID' + ), + 'BLOCKING_LOCK_ID' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'INNODB_LOCKS', + 'foreign_field' => 'LOCK_ID' + ) + ), + 'INNODB_SYS_COLUMNS' => array( + 'TABLE_ID' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'INNODB_SYS_TABLES', + 'foreign_field' => 'TABLE_ID' + ) + ), + 'INNODB_SYS_FIELDS' => array( + 'INDEX_ID' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'INNODB_SYS_INDEXES', + 'foreign_field' => 'INDEX_ID' + ) + ), + 'INNODB_SYS_INDEXES' => array( + 'TABLE_ID' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'INNODB_SYS_TABLES', + 'foreign_field' => 'TABLE_ID' + ) + ), + 'INNODB_SYS_TABLESTATS' => array( + 'TABLE_ID' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'INNODB_SYS_TABLES', + 'foreign_field' => 'TABLE_ID' + ) + ), + 'PLUGINS' => array( + 'MODULE_NAME' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'MODULES', + 'foreign_field' => 'MODULE_NAME' + ) + ), + 'SCHEMAS' => array( + 'DEFAULT_COLLATION_NAME' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ) + ), + 'TABLES' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'SCHEMAS', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'TABLE_COLLATION' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ) + ), + 'TABLE_CACHE' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'SCHEMAS', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), + 'TABLE_CONSTRAINTS' => array( + 'CONSTRAINT_SCHEMA' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'SCHEMAS', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'SCHEMAS', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), + 'TABLE_DEFINITION_CACHE' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'data_dictionary', + 'foreign_table' => 'SCHEMAS', + 'foreign_field' => 'SCHEMA_NAME' + ) + ) +); + +?> diff --git a/phpmyadmin/libraries/database_interface.lib.php b/phpmyadmin/libraries/database_interface.lib.php new file mode 100644 index 000000000..de697ec11 --- /dev/null +++ b/phpmyadmin/libraries/database_interface.lib.php @@ -0,0 +1,2134 @@ +' . mysqli_error($link) . ''; + } + $_SESSION['debug']['queries'][$hash]['count'] = 1; + $_SESSION['debug']['queries'][$hash]['query'] = $query; + $_SESSION['debug']['queries'][$hash]['time'] = $time; + } + + $trace = array(); + foreach (debug_backtrace() as $trace_step) { + $trace[] + = (isset($trace_step['file']) + ? PMA_Error::relPath($trace_step['file']) + : '') + . (isset($trace_step['line']) + ? '#' . $trace_step['line'] . ': ' + : '') + . (isset($trace_step['class']) ? $trace_step['class'] : '') + . (isset($trace_step['type']) ? $trace_step['type'] : '') + . (isset($trace_step['function']) ? $trace_step['function'] : '') + . '(' + . (isset($trace_step['params']) + ? implode(', ', $trace_step['params']) + : '' + ) + . ')' + ; + } + $_SESSION['debug']['queries'][$hash]['trace'][] = $trace; +} + +/** + * runs a query and returns the result + * + * @param string $query query to run + * @param resource $link mysql link resource + * @param integer $options query options + * @param bool $cache_affected_rows whether to cache affected row + * + * @return mixed + */ +function PMA_DBI_try_query($query, $link = null, $options = 0, + $cache_affected_rows = true +) { + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + + if ($GLOBALS['cfg']['DBG']['sql']) { + $time = microtime(true); + } + + $result = PMA_DBI_real_query($query, $link, $options); + + if ($cache_affected_rows) { + $GLOBALS['cached_affected_rows'] = PMA_DBI_affected_rows($link, false); + } + + if ($GLOBALS['cfg']['DBG']['sql']) { + $time = microtime(true) - $time; + PMA_DBI_DBG_query($query, $link, $result, $time); + } + if ($result != false && PMA_Tracker::isActive() == true ) { + PMA_Tracker::handleQuery($query); + } + + return $result; +} + +/** + * Run multi query statement and return results + * + * @param string $multi_query multi query statement to execute + * @param mysqli $link mysqli object + * + * @return mysqli_result collection | boolean(false) + */ +function PMA_DBI_try_multi_query($multi_query = '', $link = null) +{ + + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + + return PMA_DBI_real_multi_query($link, $multi_query); + +} + +/** + * converts charset of a mysql message, usually coming from mysql_error(), + * into PMA charset, usally UTF-8 + * uses language to charset mapping from mysql/share/errmsg.txt + * and charset names to ISO charset from information_schema.CHARACTER_SETS + * + * @param string $message the message + * + * @return string $message + */ +function PMA_DBI_convert_message($message) +{ + // latin always last! + $encodings = array( + 'japanese' => 'EUC-JP', //'ujis', + 'japanese-sjis' => 'Shift-JIS', //'sjis', + 'korean' => 'EUC-KR', //'euckr', + 'russian' => 'KOI8-R', //'koi8r', + 'ukrainian' => 'KOI8-U', //'koi8u', + 'greek' => 'ISO-8859-7', //'greek', + 'serbian' => 'CP1250', //'cp1250', + 'estonian' => 'ISO-8859-13', //'latin7', + 'slovak' => 'ISO-8859-2', //'latin2', + 'czech' => 'ISO-8859-2', //'latin2', + 'hungarian' => 'ISO-8859-2', //'latin2', + 'polish' => 'ISO-8859-2', //'latin2', + 'romanian' => 'ISO-8859-2', //'latin2', + 'spanish' => 'CP1252', //'latin1', + 'swedish' => 'CP1252', //'latin1', + 'italian' => 'CP1252', //'latin1', + 'norwegian-ny' => 'CP1252', //'latin1', + 'norwegian' => 'CP1252', //'latin1', + 'portuguese' => 'CP1252', //'latin1', + 'danish' => 'CP1252', //'latin1', + 'dutch' => 'CP1252', //'latin1', + 'english' => 'CP1252', //'latin1', + 'french' => 'CP1252', //'latin1', + 'german' => 'CP1252', //'latin1', + ); + + $server_language = PMA_DBI_fetch_value( + 'SHOW VARIABLES LIKE \'language\';', + 0, + 1 + ); + if ($server_language) { + $found = array(); + $match = preg_match( + '&(?:\\\|\\/)([^\\\\\/]*)(?:\\\|\\/)$&i', + $server_language, + $found + ); + if ($match) { + $server_language = $found[1]; + } + } + + if (! empty($server_language) && isset($encodings[$server_language])) { + $encoding = $encodings[$server_language]; + } else { + /* Fallback to CP1252 if we can not detect */ + $encoding = 'CP1252'; + } + + if (function_exists('iconv')) { + if ((@stristr(PHP_OS, 'AIX')) + && (@strcasecmp(ICONV_IMPL, 'unknown') == 0) + && (@strcasecmp(ICONV_VERSION, 'unknown') == 0) + ) { + include_once './libraries/iconv_wrapper.lib.php'; + $message = PMA_aix_iconv_wrapper( + $encoding, + 'utf-8' . $GLOBALS['cfg']['IconvExtraParams'], + $message + ); + } else { + $message = iconv( + $encoding, + 'utf-8' . $GLOBALS['cfg']['IconvExtraParams'], + $message + ); + } + } elseif (function_exists('recode_string')) { + $message = recode_string( + $encoding . '..' . 'utf-8', + $message + ); + } elseif (function_exists('libiconv')) { + $message = libiconv($encoding, 'utf-8', $message); + } elseif (function_exists('mb_convert_encoding')) { + // do not try unsupported charsets + if (! in_array($server_language, array('ukrainian', 'greek', 'serbian'))) { + $message = mb_convert_encoding( + $message, + 'utf-8', + $encoding + ); + } + } + + return $message; +} + +/** + * returns array with table names for given db + * + * @param string $database name of database + * @param mixed $link mysql link resource|object + * + * @return array tables names + */ +function PMA_DBI_get_tables($database, $link = null) +{ + return PMA_DBI_fetch_result( + 'SHOW TABLES FROM ' . PMA_Util::backquote($database) . ';', + null, + 0, + $link, + PMA_DBI_QUERY_STORE + ); +} + +/** + * usort comparison callback + * + * @param string $a first argument to sort + * @param string $b second argument to sort + * + * @return integer a value representing whether $a should be before $b in the + * sorted array or not + * + * @access private + */ +function PMA_usort_comparison_callback($a, $b) +{ + if ($GLOBALS['cfg']['NaturalOrder']) { + $sorter = 'strnatcasecmp'; + } else { + $sorter = 'strcasecmp'; + } + /* No sorting when key is not present */ + if (! isset($a[$GLOBALS['callback_sort_by']]) + || ! isset($b[$GLOBALS['callback_sort_by']]) + ) { + return 0; + } + // produces f.e.: + // return -1 * strnatcasecmp($a["SCHEMA_TABLES"], $b["SCHEMA_TABLES"]) + return ($GLOBALS['callback_sort_order'] == 'ASC' ? 1 : -1) * $sorter( + $a[$GLOBALS['callback_sort_by']], $b[$GLOBALS['callback_sort_by']] + ); +} // end of the 'PMA_usort_comparison_callback()' function + +/** + * returns array of all tables in given db or dbs + * this function expects unquoted names: + * RIGHT: my_database + * WRONG: `my_database` + * WRONG: my\_database + * if $tbl_is_group is true, $table is used as filter for table names + * if $tbl_is_group is 'comment, $table is used as filter for table comments + * + * + * PMA_DBI_get_tables_full('my_database'); + * PMA_DBI_get_tables_full('my_database', 'my_table')); + * PMA_DBI_get_tables_full('my_database', 'my_tables_', true)); + * PMA_DBI_get_tables_full('my_database', 'my_tables_', 'comment')); + * + * + * @param string $database database + * @param string|bool $table table or false + * @param boolean|string $tbl_is_group $table is a table group + * @param mixed $link mysql link + * @param integer $limit_offset zero-based offset for the count + * @param boolean|integer $limit_count number of tables to return + * @param string $sort_by table attribute to sort by + * @param string $sort_order direction to sort (ASC or DESC) + * + * @todo move into PMA_Table + * + * @return array list of tables in given db(s) + */ +function PMA_DBI_get_tables_full($database, $table = false, + $tbl_is_group = false, $link = null, $limit_offset = 0, + $limit_count = false, $sort_by = 'Name', $sort_order = 'ASC' +) { + if (true === $limit_count) { + $limit_count = $GLOBALS['cfg']['MaxTableList']; + } + // prepare and check parameters + if (! is_array($database)) { + $databases = array($database); + } else { + $databases = $database; + } + + $tables = array(); + + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + // get table information from information_schema + if ($table) { + if (true === $tbl_is_group) { + $sql_where_table = 'AND t.`TABLE_NAME` LIKE \'' + . PMA_Util::escapeMysqlWildcards(PMA_Util::sqlAddSlashes($table)) + . '%\''; + } elseif ('comment' === $tbl_is_group) { + $sql_where_table = 'AND t.`TABLE_COMMENT` LIKE \'' + . PMA_Util::escapeMysqlWildcards(PMA_Util::sqlAddSlashes($table)) + . '%\''; + } else { + $sql_where_table = 'AND t.`TABLE_NAME` = \'' + . PMA_Util::sqlAddSlashes($table) . '\''; + } + } else { + $sql_where_table = ''; + } + + // for PMA bc: + // `SCHEMA_FIELD_NAME` AS `SHOW_TABLE_STATUS_FIELD_NAME` + // + // on non-Windows servers, + // added BINARY in the WHERE clause to force a case sensitive + // comparison (if we are looking for the db Aa we don't want + // to find the db aa) + $this_databases = array_map('PMA_Util::sqlAddSlashes', $databases); + + if (PMA_DRIZZLE) { + $engine_info = PMA_Util::cacheGet('drizzle_engines', true); + $stats_join = "LEFT JOIN (SELECT 0 NUM_ROWS) AS stat ON false"; + if (isset($engine_info['InnoDB']) + && $engine_info['InnoDB']['module_library'] == 'innobase' + ) { + $stats_join = "LEFT JOIN data_dictionary.INNODB_SYS_TABLESTATS stat" + . " ON (t.ENGINE = 'InnoDB' AND stat.NAME" + . " = (t.TABLE_SCHEMA || '/') || t.TABLE_NAME)"; + } + + // data_dictionary.table_cache may not contain any data for some tables, + // it's just a table cache + // auto_increment == 0 is cast to NULL because currently (2011.03.13 GA) + // Drizzle doesn't provide correct value + $sql = " + SELECT t.*, + t.TABLE_SCHEMA AS `Db`, + t.TABLE_NAME AS `Name`, + t.TABLE_TYPE AS `TABLE_TYPE`, + t.ENGINE AS `Engine`, + t.ENGINE AS `Type`, + t.TABLE_VERSION AS `Version`,-- VERSION + t.ROW_FORMAT AS `Row_format`, + coalesce(tc.ROWS, stat.NUM_ROWS) + AS `Rows`,-- TABLE_ROWS, + coalesce(tc.ROWS, stat.NUM_ROWS) + AS `TABLE_ROWS`, + tc.AVG_ROW_LENGTH AS `Avg_row_length`, -- AVG_ROW_LENGTH + tc.TABLE_SIZE AS `Data_length`, -- DATA_LENGTH + NULL AS `Max_data_length`, -- MAX_DATA_LENGTH + NULL AS `Index_length`, -- INDEX_LENGTH + NULL AS `Data_free`, -- DATA_FREE + nullif(t.AUTO_INCREMENT, 0) + AS `Auto_increment`, + t.TABLE_CREATION_TIME AS `Create_time`, -- CREATE_TIME + t.TABLE_UPDATE_TIME AS `Update_time`, -- UPDATE_TIME + NULL AS `Check_time`, -- CHECK_TIME + t.TABLE_COLLATION AS `Collation`, + NULL AS `Checksum`, -- CHECKSUM + NULL AS `Create_options`, -- CREATE_OPTIONS + t.TABLE_COMMENT AS `Comment` + FROM data_dictionary.TABLES t + LEFT JOIN data_dictionary.TABLE_CACHE tc + ON tc.TABLE_SCHEMA = t.TABLE_SCHEMA AND tc.TABLE_NAME + = t.TABLE_NAME + $stats_join + WHERE t.TABLE_SCHEMA IN ('" . implode("', '", $this_databases) . "') + " . $sql_where_table; + } else { + $sql = ' + SELECT *, + `TABLE_SCHEMA` AS `Db`, + `TABLE_NAME` AS `Name`, + `TABLE_TYPE` AS `TABLE_TYPE`, + `ENGINE` AS `Engine`, + `ENGINE` AS `Type`, + `VERSION` AS `Version`, + `ROW_FORMAT` AS `Row_format`, + `TABLE_ROWS` AS `Rows`, + `AVG_ROW_LENGTH` AS `Avg_row_length`, + `DATA_LENGTH` AS `Data_length`, + `MAX_DATA_LENGTH` AS `Max_data_length`, + `INDEX_LENGTH` AS `Index_length`, + `DATA_FREE` AS `Data_free`, + `AUTO_INCREMENT` AS `Auto_increment`, + `CREATE_TIME` AS `Create_time`, + `UPDATE_TIME` AS `Update_time`, + `CHECK_TIME` AS `Check_time`, + `TABLE_COLLATION` AS `Collation`, + `CHECKSUM` AS `Checksum`, + `CREATE_OPTIONS` AS `Create_options`, + `TABLE_COMMENT` AS `Comment` + FROM `information_schema`.`TABLES` t + WHERE ' . (PMA_IS_WINDOWS ? '' : 'BINARY') . ' `TABLE_SCHEMA` + IN (\'' . implode("', '", $this_databases) . '\') + ' . $sql_where_table; + } + + // Sort the tables + $sql .= " ORDER BY $sort_by $sort_order"; + + if ($limit_count) { + $sql .= ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset; + } + + $tables = PMA_DBI_fetch_result( + $sql, array('TABLE_SCHEMA', 'TABLE_NAME'), null, $link + ); + unset($sql_where_table, $sql); + + if (PMA_DRIZZLE) { + // correct I_S and D_D names returned by D_D.TABLES - + // Drizzle generally uses lower case for them, + // but TABLES returns uppercase + foreach ((array)$database as $db) { + $db_upper = strtoupper($db); + if (!isset($tables[$db]) && isset($tables[$db_upper])) { + $tables[$db] = $tables[$db_upper]; + unset($tables[$db_upper]); + } + } + } + + if ($sort_by == 'Name' && $GLOBALS['cfg']['NaturalOrder']) { + // here, the array's first key is by schema name + foreach ($tables as $one_database_name => $one_database_tables) { + uksort($one_database_tables, 'strnatcasecmp'); + + if ($sort_order == 'DESC') { + $one_database_tables = array_reverse($one_database_tables); + } + $tables[$one_database_name] = $one_database_tables; + } + } + } // end (get information from table schema) + + // If permissions are wrong on even one database directory, + // information_schema does not return any table info for any database + // this is why we fall back to SHOW TABLE STATUS even for MySQL >= 50002 + if (empty($tables) && !PMA_DRIZZLE) { + foreach ($databases as $each_database) { + if ($table || (true === $tbl_is_group)) { + $sql = 'SHOW TABLE STATUS FROM ' + . PMA_Util::backquote($each_database) + .' LIKE \'' + . PMA_Util::escapeMysqlWildcards( + PMA_Util::sqlAddSlashes($table, true) + ) + . '%\''; + } else { + $sql = 'SHOW TABLE STATUS FROM ' + . PMA_Util::backquote($each_database); + } + + $useStatusCache = false; + + if (extension_loaded('apc') + && isset($GLOBALS['cfg']['Server']['StatusCacheDatabases']) + && ! empty($GLOBALS['cfg']['Server']['StatusCacheLifetime']) + ) { + $statusCacheDatabases + = (array) $GLOBALS['cfg']['Server']['StatusCacheDatabases']; + if (in_array($each_database, $statusCacheDatabases)) { + $useStatusCache = true; + } + } + + $each_tables = null; + + if ($useStatusCache) { + $cacheKey = 'phpMyAdmin_tableStatus_' + . sha1($GLOBALS['cfg']['Server']['host'] . '_' . $sql); + + $each_tables = apc_fetch($cacheKey); + } + + if (!$each_tables) { + $each_tables = PMA_DBI_fetch_result($sql, 'Name', null, $link); + } + + if ($useStatusCache) { + apc_store( + $cacheKey, $each_tables, + $GLOBALS['cfg']['Server']['StatusCacheLifetime'] + ); + } + + // Sort naturally if the config allows it and we're sorting + // the Name column. + if ($sort_by == 'Name' && $GLOBALS['cfg']['NaturalOrder']) { + uksort($each_tables, 'strnatcasecmp'); + + if ($sort_order == 'DESC') { + $each_tables = array_reverse($each_tables); + } + } else { + // Prepare to sort by creating array of the selected sort + // value to pass to array_multisort + + // Size = Data_length + Index_length + if ($sort_by == 'Data_length') { + foreach ($each_tables as $table_name => $table_data) { + ${$sort_by}[$table_name] = strtolower( + $table_data['Data_length'] + $table_data['Index_length'] + ); + } + } else { + foreach ($each_tables as $table_name => $table_data) { + ${$sort_by}[$table_name] = strtolower($table_data[$sort_by]); + } + } + + if ($sort_order == 'DESC') { + array_multisort($$sort_by, SORT_DESC, $each_tables); + } else { + array_multisort($$sort_by, SORT_ASC, $each_tables); + } + + // cleanup the temporary sort array + unset($$sort_by); + } + + if ($limit_count) { + $each_tables = array_slice( + $each_tables, $limit_offset, $limit_count + ); + } + + foreach ($each_tables as $table_name => $each_table) { + if ('comment' === $tbl_is_group + && 0 === strpos($each_table['Comment'], $table) + ) { + // remove table from list + unset($each_tables[$table_name]); + continue; + } + + if (! isset($each_tables[$table_name]['Type']) + && isset($each_tables[$table_name]['Engine']) + ) { + // pma BC, same parts of PMA still uses 'Type' + $each_tables[$table_name]['Type'] + =& $each_tables[$table_name]['Engine']; + } elseif (! isset($each_tables[$table_name]['Engine']) + && isset($each_tables[$table_name]['Type'])) { + // old MySQL reports Type, newer MySQL reports Engine + $each_tables[$table_name]['Engine'] + =& $each_tables[$table_name]['Type']; + } + + // MySQL forward compatibility + // so pma could use this array as if every server is of version >5.0 + // todo : remove and check usage in the rest of the code, + // MySQL 5.0 is required by current PMA version + $each_tables[$table_name]['TABLE_SCHEMA'] = $each_database; + $each_tables[$table_name]['TABLE_NAME'] + =& $each_tables[$table_name]['Name']; + $each_tables[$table_name]['ENGINE'] + =& $each_tables[$table_name]['Engine']; + $each_tables[$table_name]['VERSION'] + =& $each_tables[$table_name]['Version']; + $each_tables[$table_name]['ROW_FORMAT'] + =& $each_tables[$table_name]['Row_format']; + $each_tables[$table_name]['TABLE_ROWS'] + =& $each_tables[$table_name]['Rows']; + $each_tables[$table_name]['AVG_ROW_LENGTH'] + =& $each_tables[$table_name]['Avg_row_length']; + $each_tables[$table_name]['DATA_LENGTH'] + =& $each_tables[$table_name]['Data_length']; + $each_tables[$table_name]['MAX_DATA_LENGTH'] + =& $each_tables[$table_name]['Max_data_length']; + $each_tables[$table_name]['INDEX_LENGTH'] + =& $each_tables[$table_name]['Index_length']; + $each_tables[$table_name]['DATA_FREE'] + =& $each_tables[$table_name]['Data_free']; + $each_tables[$table_name]['AUTO_INCREMENT'] + =& $each_tables[$table_name]['Auto_increment']; + $each_tables[$table_name]['CREATE_TIME'] + =& $each_tables[$table_name]['Create_time']; + $each_tables[$table_name]['UPDATE_TIME'] + =& $each_tables[$table_name]['Update_time']; + $each_tables[$table_name]['CHECK_TIME'] + =& $each_tables[$table_name]['Check_time']; + $each_tables[$table_name]['TABLE_COLLATION'] + =& $each_tables[$table_name]['Collation']; + $each_tables[$table_name]['CHECKSUM'] + =& $each_tables[$table_name]['Checksum']; + $each_tables[$table_name]['CREATE_OPTIONS'] + =& $each_tables[$table_name]['Create_options']; + $each_tables[$table_name]['TABLE_COMMENT'] + =& $each_tables[$table_name]['Comment']; + + if (strtoupper($each_tables[$table_name]['Comment']) === 'VIEW' + && $each_tables[$table_name]['Engine'] == null + ) { + $each_tables[$table_name]['TABLE_TYPE'] = 'VIEW'; + } else { + /** + * @todo difference between 'TEMPORARY' and 'BASE TABLE' + * but how to detect? + */ + $each_tables[$table_name]['TABLE_TYPE'] = 'BASE TABLE'; + } + } + + $tables[$each_database] = $each_tables; + } + } + + // cache table data + // so PMA_Table does not require to issue SHOW TABLE STATUS again + // Note: I don't see why we would need array_merge_recursive() here, + // as it creates double entries for the same table (for example a double + // entry for Comment when changing the storage engine in Operations) + // Note 2: Instead of array_merge(), simply use the + operator because + // array_merge() renumbers numeric keys starting with 0, therefore + // we would lose a db name thats consists only of numbers + foreach ($tables as $one_database => $its_tables) { + if (isset(PMA_Table::$cache[$one_database])) { + PMA_Table::$cache[$one_database] + = PMA_Table::$cache[$one_database] + $tables[$one_database]; + } else { + PMA_Table::$cache[$one_database] = $tables[$one_database]; + } + } + unset($one_database, $its_tables); + + if (! is_array($database)) { + if (isset($tables[$database])) { + return $tables[$database]; + } elseif (isset($tables[strtolower($database)])) { + // on windows with lower_case_table_names = 1 + // MySQL returns + // with SHOW DATABASES or information_schema.SCHEMATA: `Test` + // but information_schema.TABLES gives `test` + // bug #2036 + // https://sourceforge.net/p/phpmyadmin/bugs/2036/ + return $tables[strtolower($database)]; + } else { + // one database but inexact letter case match + // as Drizzle is always case insensitive, + // we can safely return the only result + if (PMA_DRIZZLE && count($tables) == 1) { + $keys = array_keys($tables); + if (strlen(array_pop($keys)) == strlen($database)) { + return array_pop($tables); + } + } + return $tables; + } + } else { + return $tables; + } +} + + +/** + * Get VIEWs in a particular database + * + * @param string $db Database name to look in + * + * @return array $views Set of VIEWs inside the database + */ +function PMA_DBI_getVirtualTables($db) +{ + + $tables_full = PMA_DBI_get_tables_full($db); + $views = array(); + + foreach ($tables_full as $table=>$tmp) { + + if (PMA_Table::isView($db, $table)) { + $views[] = $table; + } + + } + + return $views; + +} + + +/** + * returns array with databases containing extended infos about them + * + * @param string $database database + * @param boolean $force_stats retrieve stats also for MySQL < 5 + * @param resource $link mysql link + * @param string $sort_by column to order by + * @param string $sort_order ASC or DESC + * @param integer $limit_offset starting offset for LIMIT + * @param bool|int $limit_count row count for LIMIT or true + * for $GLOBALS['cfg']['MaxDbList'] + * + * @todo move into PMA_List_Database? + * + * @return array $databases + */ +function PMA_DBI_get_databases_full($database = null, $force_stats = false, + $link = null, $sort_by = 'SCHEMA_NAME', $sort_order = 'ASC', + $limit_offset = 0, $limit_count = false +) { + $sort_order = strtoupper($sort_order); + + if (true === $limit_count) { + $limit_count = $GLOBALS['cfg']['MaxDbList']; + } + + // initialize to avoid errors when there are no databases + $databases = array(); + + $apply_limit_and_order_manual = true; + + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + /** + * if $GLOBALS['cfg']['NaturalOrder'] is enabled, we cannot use LIMIT + * cause MySQL does not support natural ordering, we have to do it afterward + */ + $limit = ''; + if (!$GLOBALS['cfg']['NaturalOrder']) { + if ($limit_count) { + $limit = ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset; + } + + $apply_limit_and_order_manual = false; + } + + // get table information from information_schema + if ($database) { + $sql_where_schema = 'WHERE `SCHEMA_NAME` LIKE \'' + . PMA_Util::sqlAddSlashes($database) . '\''; + } else { + $sql_where_schema = ''; + } + + if (PMA_DRIZZLE) { + // data_dictionary.table_cache may not contain any data for some + // tables, it's just a table cache + $sql = 'SELECT + s.SCHEMA_NAME, + s.DEFAULT_COLLATION_NAME'; + if ($force_stats) { + // no TABLE_CACHE data, stable results are better than + // constantly changing + $sql .= ', + COUNT(t.TABLE_SCHEMA) AS SCHEMA_TABLES, + SUM(stat.NUM_ROWS) AS SCHEMA_TABLE_ROWS'; + } + $sql .= ' + FROM data_dictionary.SCHEMAS s'; + if ($force_stats) { + $engine_info = PMA_Util::cacheGet('drizzle_engines', true); + $stats_join = "LEFT JOIN (SELECT 0 NUM_ROWS) AS stat ON false"; + if (isset($engine_info['InnoDB']) + && $engine_info['InnoDB']['module_library'] == 'innobase' + ) { + $stats_join = "LEFT JOIN data_dictionary.INNODB_SYS_TABLESTATS" + . " stat ON (t.ENGINE = 'InnoDB' AND stat.NAME" + . " = (t.TABLE_SCHEMA || '/') || t.TABLE_NAME)"; + } + + $sql .= " + LEFT JOIN data_dictionary.TABLES t + ON t.TABLE_SCHEMA = s.SCHEMA_NAME + $stats_join"; + } + $sql .= $sql_where_schema . ' + GROUP BY s.SCHEMA_NAME + ORDER BY ' . PMA_Util::backquote($sort_by) . ' ' . $sort_order + . $limit; + } else { + $sql = 'SELECT + s.SCHEMA_NAME, + s.DEFAULT_COLLATION_NAME'; + if ($force_stats) { + $sql .= ', + COUNT(t.TABLE_SCHEMA) AS SCHEMA_TABLES, + SUM(t.TABLE_ROWS) AS SCHEMA_TABLE_ROWS, + SUM(t.DATA_LENGTH) AS SCHEMA_DATA_LENGTH, + SUM(t.MAX_DATA_LENGTH) AS SCHEMA_MAX_DATA_LENGTH, + SUM(t.INDEX_LENGTH) AS SCHEMA_INDEX_LENGTH, + SUM(t.DATA_LENGTH + t.INDEX_LENGTH) + AS SCHEMA_LENGTH, + SUM(t.DATA_FREE) AS SCHEMA_DATA_FREE'; + } + $sql .= ' + FROM `information_schema`.SCHEMATA s'; + if ($force_stats) { + $sql .= ' + LEFT JOIN `information_schema`.TABLES t + ON BINARY t.TABLE_SCHEMA = BINARY s.SCHEMA_NAME'; + } + $sql .= $sql_where_schema . ' + GROUP BY BINARY s.SCHEMA_NAME + ORDER BY BINARY ' . PMA_Util::backquote($sort_by) + . ' ' . $sort_order + . $limit; + } + + $databases = PMA_DBI_fetch_result($sql, 'SCHEMA_NAME', null, $link); + + $mysql_error = PMA_DBI_getError($link); + if (! count($databases) && $GLOBALS['errno']) { + PMA_Util::mysqlDie($mysql_error, $sql); + } + + // display only databases also in official database list + // f.e. to apply hide_db and only_db + $drops = array_diff( + array_keys($databases), (array) $GLOBALS['pma']->databases + ); + if (count($drops)) { + foreach ($drops as $drop) { + unset($databases[$drop]); + } + unset($drop); + } + unset($sql_where_schema, $sql, $drops); + } else { + foreach ($GLOBALS['pma']->databases as $database_name) { + // MySQL forward compatibility + // so pma could use this array as if every server is of version >5.0 + // todo : remove and check the rest of the code for usage, + // MySQL 5.0 or higher is required for current PMA version + $databases[$database_name]['SCHEMA_NAME'] = $database_name; + + if ($force_stats) { + include_once './libraries/mysql_charsets.lib.php'; + + $databases[$database_name]['DEFAULT_COLLATION_NAME'] + = PMA_getDbCollation($database_name); + + // get additional info about tables + $databases[$database_name]['SCHEMA_TABLES'] = 0; + $databases[$database_name]['SCHEMA_TABLE_ROWS'] = 0; + $databases[$database_name]['SCHEMA_DATA_LENGTH'] = 0; + $databases[$database_name]['SCHEMA_MAX_DATA_LENGTH'] = 0; + $databases[$database_name]['SCHEMA_INDEX_LENGTH'] = 0; + $databases[$database_name]['SCHEMA_LENGTH'] = 0; + $databases[$database_name]['SCHEMA_DATA_FREE'] = 0; + + $res = PMA_DBI_query( + 'SHOW TABLE STATUS FROM ' + . PMA_Util::backquote($database_name) . ';' + ); + + while ($row = PMA_DBI_fetch_assoc($res)) { + $databases[$database_name]['SCHEMA_TABLES']++; + $databases[$database_name]['SCHEMA_TABLE_ROWS'] + += $row['Rows']; + $databases[$database_name]['SCHEMA_DATA_LENGTH'] + += $row['Data_length']; + $databases[$database_name]['SCHEMA_MAX_DATA_LENGTH'] + += $row['Max_data_length']; + $databases[$database_name]['SCHEMA_INDEX_LENGTH'] + += $row['Index_length']; + + // for InnoDB, this does not contain the number of + // overhead bytes but the total free space + if ('InnoDB' != $row['Engine']) { + $databases[$database_name]['SCHEMA_DATA_FREE'] + += $row['Data_free']; + } + $databases[$database_name]['SCHEMA_LENGTH'] + += $row['Data_length'] + $row['Index_length']; + } + PMA_DBI_free_result($res); + unset($res); + } + } + } + + + /** + * apply limit and order manually now + * (caused by older MySQL < 5 or $GLOBALS['cfg']['NaturalOrder']) + */ + if ($apply_limit_and_order_manual) { + $GLOBALS['callback_sort_order'] = $sort_order; + $GLOBALS['callback_sort_by'] = $sort_by; + usort($databases, 'PMA_usort_comparison_callback'); + unset($GLOBALS['callback_sort_order'], $GLOBALS['callback_sort_by']); + + /** + * now apply limit + */ + if ($limit_count) { + $databases = array_slice($databases, $limit_offset, $limit_count); + } + } + + return $databases; +} + +/** + * returns detailed array with all columns for given table in database, + * or all tables/databases + * + * @param string $database name of database + * @param string $table name of table to retrieve columns from + * @param string $column name of specific column + * @param mixed $link mysql link resource + * + * @return array + */ +function PMA_DBI_get_columns_full($database = null, $table = null, + $column = null, $link = null +) { + $columns = array(); + + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $sql_wheres = array(); + $array_keys = array(); + + // get columns information from information_schema + if (null !== $database) { + $sql_wheres[] = '`TABLE_SCHEMA` = \'' + . PMA_Util::sqlAddSlashes($database) . '\' '; + } else { + $array_keys[] = 'TABLE_SCHEMA'; + } + if (null !== $table) { + $sql_wheres[] = '`TABLE_NAME` = \'' + . PMA_Util::sqlAddSlashes($table) . '\' '; + } else { + $array_keys[] = 'TABLE_NAME'; + } + if (null !== $column) { + $sql_wheres[] = '`COLUMN_NAME` = \'' + . PMA_Util::sqlAddSlashes($column) . '\' '; + } else { + $array_keys[] = 'COLUMN_NAME'; + } + + // for PMA bc: + // `[SCHEMA_FIELD_NAME]` AS `[SHOW_FULL_COLUMNS_FIELD_NAME]` + if (PMA_DRIZZLE) { + $sql = "SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, + column_name AS `Field`, + (CASE + WHEN character_maximum_length > 0 + THEN concat(lower(data_type), '(', character_maximum_length, ')') + WHEN numeric_precision > 0 OR numeric_scale > 0 + THEN concat(lower(data_type), '(', numeric_precision, + ',', numeric_scale, ')') + WHEN enum_values IS NOT NULL + THEN concat(lower(data_type), '(', enum_values, ')') + ELSE lower(data_type) END) + AS `Type`, + collation_name AS `Collation`, + (CASE is_nullable + WHEN 1 THEN 'YES' + ELSE 'NO' END) AS `Null`, + (CASE + WHEN is_used_in_primary THEN 'PRI' + ELSE '' END) AS `Key`, + column_default AS `Default`, + (CASE + WHEN is_auto_increment THEN 'auto_increment' + WHEN column_default_update + THEN 'on update ' || column_default_update + ELSE '' END) AS `Extra`, + NULL AS `Privileges`, + column_comment AS `Comment` + FROM data_dictionary.columns"; + } else { + $sql = ' + SELECT *, + `COLUMN_NAME` AS `Field`, + `COLUMN_TYPE` AS `Type`, + `COLLATION_NAME` AS `Collation`, + `IS_NULLABLE` AS `Null`, + `COLUMN_KEY` AS `Key`, + `COLUMN_DEFAULT` AS `Default`, + `EXTRA` AS `Extra`, + `PRIVILEGES` AS `Privileges`, + `COLUMN_COMMENT` AS `Comment` + FROM `information_schema`.`COLUMNS`'; + } + if (count($sql_wheres)) { + $sql .= "\n" . ' WHERE ' . implode(' AND ', $sql_wheres); + } + + $columns = PMA_DBI_fetch_result($sql, $array_keys, null, $link); + unset($sql_wheres, $sql); + } else { + if (null === $database) { + foreach ($GLOBALS['pma']->databases as $database) { + $columns[$database] = PMA_DBI_get_columns_full( + $database, null, null, $link + ); + } + return $columns; + } elseif (null === $table) { + $tables = PMA_DBI_get_tables($database); + foreach ($tables as $table) { + $columns[$table] = PMA_DBI_get_columns_full( + $database, $table, null, $link + ); + } + return $columns; + } + + $sql = 'SHOW FULL COLUMNS FROM ' + . PMA_Util::backquote($database) . '.' . PMA_Util::backquote($table); + if (null !== $column) { + $sql .= " LIKE '" . PMA_Util::sqlAddSlashes($column, true) . "'"; + } + + $columns = PMA_DBI_fetch_result($sql, 'Field', null, $link); + } + $ordinal_position = 1; + foreach ($columns as $column_name => $each_column) { + + // MySQL forward compatibility + // so pma could use this array as if every server is of version >5.0 + // todo : remove and check the rest of the code for usage, + // MySQL 5.0 or higher is required for current PMA version + $columns[$column_name]['COLUMN_NAME'] =& $columns[$column_name]['Field']; + $columns[$column_name]['COLUMN_TYPE'] =& $columns[$column_name]['Type']; + $columns[$column_name]['COLLATION_NAME'] + =& $columns[$column_name]['Collation']; + $columns[$column_name]['IS_NULLABLE'] =& $columns[$column_name]['Null']; + $columns[$column_name]['COLUMN_KEY'] =& $columns[$column_name]['Key']; + $columns[$column_name]['COLUMN_DEFAULT'] + =& $columns[$column_name]['Default']; + $columns[$column_name]['EXTRA'] + =& $columns[$column_name]['Extra']; + $columns[$column_name]['PRIVILEGES'] + =& $columns[$column_name]['Privileges']; + $columns[$column_name]['COLUMN_COMMENT'] + =& $columns[$column_name]['Comment']; + + $columns[$column_name]['TABLE_CATALOG'] = null; + $columns[$column_name]['TABLE_SCHEMA'] = $database; + $columns[$column_name]['TABLE_NAME'] = $table; + $columns[$column_name]['ORDINAL_POSITION'] = $ordinal_position; + $columns[$column_name]['DATA_TYPE'] + = substr( + $columns[$column_name]['COLUMN_TYPE'], + 0, + strpos($columns[$column_name]['COLUMN_TYPE'], '(') + ); + /** + * @todo guess CHARACTER_MAXIMUM_LENGTH from COLUMN_TYPE + */ + $columns[$column_name]['CHARACTER_MAXIMUM_LENGTH'] = null; + /** + * @todo guess CHARACTER_OCTET_LENGTH from CHARACTER_MAXIMUM_LENGTH + */ + $columns[$column_name]['CHARACTER_OCTET_LENGTH'] = null; + $columns[$column_name]['NUMERIC_PRECISION'] = null; + $columns[$column_name]['NUMERIC_SCALE'] = null; + $columns[$column_name]['CHARACTER_SET_NAME'] + = substr( + $columns[$column_name]['COLLATION_NAME'], + 0, + strpos($columns[$column_name]['COLLATION_NAME'], '_') + ); + + $ordinal_position++; + } + + if (null !== $column) { + reset($columns); + $columns = current($columns); + } + + return $columns; +} + +/** + * Returns SQL query for fetching columns for a table + * + * The 'Key' column is not calculated properly, use PMA_DBI_get_columns() to get + * correct values. + * + * @param string $database name of database + * @param string $table name of table to retrieve columns from + * @param string $column name of column, null to show all columns + * @param boolean $full whether to return full info or only column names + * + * @see PMA_DBI_get_columns() + * + * @return string + */ +function PMA_DBI_get_columns_sql($database, $table, $column = null, $full = false) +{ + if (PMA_DRIZZLE) { + // `Key` column: + // * used in primary key => PRI + // * unique one-column => UNI + // * indexed, one-column or first in multi-column => MUL + // Promotion of UNI to PRI in case no promary index exists + // is done after query is executed + $sql = "SELECT + column_name AS `Field`, + (CASE + WHEN character_maximum_length > 0 + THEN concat(lower(data_type), '(', character_maximum_length, ')') + WHEN numeric_precision > 0 OR numeric_scale > 0 + THEN concat(lower(data_type), '(', numeric_precision, + ',', numeric_scale, ')') + WHEN enum_values IS NOT NULL + THEN concat(lower(data_type), '(', enum_values, ')') + ELSE lower(data_type) END) + AS `Type`, + " . ($full ? " + collation_name AS `Collation`," : '') . " + (CASE is_nullable + WHEN 1 THEN 'YES' + ELSE 'NO' END) AS `Null`, + (CASE + WHEN is_used_in_primary THEN 'PRI' + WHEN is_unique AND NOT is_multi THEN 'UNI' + WHEN is_indexed + AND (NOT is_multi OR is_first_in_multi) THEN 'MUL' + ELSE '' END) AS `Key`, + column_default AS `Default`, + (CASE + WHEN is_auto_increment THEN 'auto_increment' + WHEN column_default_update <> '' + THEN 'on update ' || column_default_update + ELSE '' END) AS `Extra` + " . ($full ? " , + NULL AS `Privileges`, + column_comment AS `Comment`" : '') . " + FROM data_dictionary.columns + WHERE table_schema = '" . PMA_Util::sqlAddSlashes($database) . "' + AND table_name = '" . PMA_Util::sqlAddSlashes($table) . "' + " . (($column != null) ? " + AND column_name = '" . PMA_Util::sqlAddSlashes($column) . "'" : ''); + // ORDER BY ordinal_position + } else { + $sql = 'SHOW ' . ($full ? 'FULL' : '') . ' COLUMNS FROM ' + . PMA_Util::backquote($database) . '.' . PMA_Util::backquote($table) + . (($column != null) ? "LIKE '" + . PMA_Util::sqlAddSlashes($column, true) . "'" : ''); + } + return $sql; +} + +/** + * Returns descriptions of columns in given table (all or given by $column) + * + * @param string $database name of database + * @param string $table name of table to retrieve columns from + * @param string $column name of column, null to show all columns + * @param boolean $full whether to return full info or only column names + * @param mixed $link mysql link resource + * + * @return false|array array indexed by column names or, + * if $column is given, flat array description + */ +function PMA_DBI_get_columns($database, $table, $column = null, $full = false, + $link = null +) { + $sql = PMA_DBI_get_columns_sql($database, $table, $column, $full); + $fields = PMA_DBI_fetch_result($sql, 'Field', null, $link); + if (! is_array($fields) || count($fields) == 0) { + return null; + } + if (PMA_DRIZZLE) { + // fix Key column, it's much simpler in PHP than in SQL + $has_pk = false; + $has_pk_candidates = false; + foreach ($fields as $f) { + if ($f['Key'] == 'PRI') { + $has_pk = true; + break; + } else if ($f['Null'] == 'NO' + && ($f['Key'] == 'MUL' + || $f['Key'] == 'UNI') + ) { + $has_pk_candidates = true; + } + } + if (!$has_pk && $has_pk_candidates) { + // check whether we can promote some unique index to PRI + $sql = " + SELECT i.index_name, p.column_name + FROM data_dictionary.indexes i + JOIN data_dictionary.index_parts p + USING (table_schema, table_name) + WHERE i.table_schema = '" . PMA_Util::sqlAddSlashes($database) . "' + AND i.table_name = '" . PMA_Util::sqlAddSlashes($table) . "' + AND i.is_unique + AND NOT i.is_nullable"; + $fs = PMA_DBI_fetch_result($sql, 'index_name', null, $link); + $fs = $fs ? array_shift($fs) : array(); + foreach ($fs as $f) { + $fields[$f]['Key'] = 'PRI'; + } + } + } + + return ($column != null) ? array_shift($fields) : $fields; +} + +/** + * Returns all column names in given table + * + * @param string $database name of database + * @param string $table name of table to retrieve columns from + * @param mixed $link mysql link resource + * + * @return null|array + */ +function PMA_DBI_get_column_names($database, $table, $link = null) +{ + $sql = PMA_DBI_get_columns_sql($database, $table); + // We only need the 'Field' column which contains the table's column names + $fields = array_keys(PMA_DBI_fetch_result($sql, 'Field', null, $link)); + + if ( ! is_array($fields) || count($fields) == 0 ) { + return null; + } + return $fields; +} + +/** +* Returns SQL for fetching information on table indexes (SHOW INDEXES) +* +* @param string $database name of database +* @param string $table name of the table whose indexes are to be retreived +* @param string $where additional conditions for WHERE +* +* @return array $indexes +*/ +function PMA_DBI_get_table_indexes_sql($database, $table, $where = null) +{ + if (PMA_DRIZZLE) { + $sql = "SELECT + ip.table_name AS `Table`, + (NOT ip.is_unique) AS Non_unique, + ip.index_name AS Key_name, + ip.sequence_in_index+1 AS Seq_in_index, + ip.column_name AS Column_name, + (CASE + WHEN i.index_type = 'BTREE' THEN 'A' + ELSE NULL END) AS Collation, + NULL AS Cardinality, + compare_length AS Sub_part, + NULL AS Packed, + ip.is_nullable AS `Null`, + i.index_type AS Index_type, + NULL AS Comment, + i.index_comment AS Index_comment + FROM data_dictionary.index_parts ip + LEFT JOIN data_dictionary.indexes i + USING (table_schema, table_name, index_name) + WHERE table_schema = '" . PMA_Util::sqlAddSlashes($database) . "' + AND table_name = '" . PMA_Util::sqlAddSlashes($table) . "' + "; + } else { + $sql = 'SHOW INDEXES FROM ' . PMA_Util::backquote($database) . '.' + . PMA_Util::backquote($table); + } + if ($where) { + $sql .= (PMA_DRIZZLE ? ' AND (' : ' WHERE (') . $where . ')'; + } + return $sql; +} + +/** +* Returns indexes of a table +* +* @param string $database name of database +* @param string $table name of the table whose indexes are to be retrieved +* @param mixed $link mysql link resource +* +* @return array $indexes +*/ +function PMA_DBI_get_table_indexes($database, $table, $link = null) +{ + $sql = PMA_DBI_get_table_indexes_sql($database, $table); + $indexes = PMA_DBI_fetch_result($sql, null, null, $link); + + if (! is_array($indexes) || count($indexes) < 1) { + return array(); + } + return $indexes; +} + +/** + * returns value of given mysql server variable + * + * @param string $var mysql server variable name + * @param int $type PMA_DBI_GETVAR_SESSION|PMA_DBI_GETVAR_GLOBAL + * @param mixed $link mysql link resource|object + * + * @return mixed value for mysql server variable + */ +function PMA_DBI_get_variable($var, $type = PMA_DBI_GETVAR_SESSION, $link = null) +{ + if ($link === null) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + + switch ($type) { + case PMA_DBI_GETVAR_SESSION: + $modifier = ' SESSION'; + break; + case PMA_DBI_GETVAR_GLOBAL: + $modifier = ' GLOBAL'; + break; + default: + $modifier = ''; + } + return PMA_DBI_fetch_value( + 'SHOW' . $modifier . ' VARIABLES LIKE \'' . $var . '\';', 0, 1, $link + ); +} + +/** + * Function called just after a connection to the MySQL database server has + * been established. It sets the connection collation, and determins the + * version of MySQL which is running. + * + * @param mixed $link mysql link resource|object + * @param boolean $is_controluser whether link is for control user + * + * @return void + */ +function PMA_DBI_postConnect($link, $is_controluser = false) +{ + if (! defined('PMA_MYSQL_INT_VERSION')) { + if (PMA_Util::cacheExists('PMA_MYSQL_INT_VERSION', true)) { + define( + 'PMA_MYSQL_INT_VERSION', + PMA_Util::cacheGet('PMA_MYSQL_INT_VERSION', true) + ); + define( + 'PMA_MYSQL_MAJOR_VERSION', + PMA_Util::cacheGet('PMA_MYSQL_MAJOR_VERSION', true) + ); + define( + 'PMA_MYSQL_STR_VERSION', + PMA_Util::cacheGet('PMA_MYSQL_STR_VERSION', true) + ); + define( + 'PMA_MYSQL_VERSION_COMMENT', + PMA_Util::cacheGet('PMA_MYSQL_VERSION_COMMENT', true) + ); + } else { + $version = PMA_DBI_fetch_single_row( + 'SELECT @@version, @@version_comment', + 'ASSOC', + $link + ); + + if ($version) { + $match = explode('.', $version['@@version']); + define('PMA_MYSQL_MAJOR_VERSION', (int)$match[0]); + define( + 'PMA_MYSQL_INT_VERSION', + (int) sprintf( + '%d%02d%02d', $match[0], $match[1], intval($match[2]) + ) + ); + define('PMA_MYSQL_STR_VERSION', $version['@@version']); + define('PMA_MYSQL_VERSION_COMMENT', $version['@@version_comment']); + } else { + define('PMA_MYSQL_INT_VERSION', 50015); + define('PMA_MYSQL_MAJOR_VERSION', 5); + define('PMA_MYSQL_STR_VERSION', '5.00.15'); + define('PMA_MYSQL_VERSION_COMMENT', ''); + } + PMA_Util::cacheSet( + 'PMA_MYSQL_INT_VERSION', + PMA_MYSQL_INT_VERSION, + true + ); + PMA_Util::cacheSet( + 'PMA_MYSQL_MAJOR_VERSION', + PMA_MYSQL_MAJOR_VERSION, + true + ); + PMA_Util::cacheSet( + 'PMA_MYSQL_STR_VERSION', + PMA_MYSQL_STR_VERSION, + true + ); + PMA_Util::cacheSet( + 'PMA_MYSQL_VERSION_COMMENT', + PMA_MYSQL_VERSION_COMMENT, + true + ); + } + // detect Drizzle by version number: + // ..(.= 2009); + } + + // Skip charsets for Drizzle + if (!PMA_DRIZZLE) { + if (! empty($GLOBALS['collation_connection'])) { + PMA_DBI_query("SET CHARACTER SET 'utf8';", $link, PMA_DBI_QUERY_STORE); + $set_collation_con_query = "SET collation_connection = '" + . PMA_Util::sqlAddSlashes($GLOBALS['collation_connection']) . "';"; + PMA_DBI_query( + $set_collation_con_query, + $link, + PMA_DBI_QUERY_STORE + ); + } else { + PMA_DBI_query( + "SET NAMES 'utf8' COLLATE 'utf8_general_ci';", + $link, + PMA_DBI_QUERY_STORE + ); + } + } + + // Cache plugin list for Drizzle + if (PMA_DRIZZLE && !PMA_Util::cacheExists('drizzle_engines', true)) { + $sql = "SELECT p.plugin_name, m.module_library + FROM data_dictionary.plugins p + JOIN data_dictionary.modules m USING (module_name) + WHERE p.plugin_type = 'StorageEngine' + AND p.plugin_name NOT IN ('FunctionEngine', 'schema') + AND p.is_active = 'YES'"; + $engines = PMA_DBI_fetch_result($sql, 'plugin_name', null, $link); + PMA_Util::cacheSet('drizzle_engines', $engines, true); + } +} + +/** + * returns a single value from the given result or query, + * if the query or the result has more than one row or field + * the first field of the first row is returned + * + * + * $sql = 'SELECT `name` FROM `user` WHERE `id` = 123'; + * $user_name = PMA_DBI_fetch_value($sql); + * // produces + * // $user_name = 'John Doe' + * + * + * @param string|mysql_result $result query or mysql result + * @param integer $row_number row to fetch the value from, + * starting at 0, with 0 being default + * @param integer|string $field field to fetch the value from, + * starting at 0, with 0 being default + * @param resource $link mysql link + * + * @return mixed value of first field in first row from result + * or false if not found + */ +function PMA_DBI_fetch_value($result, $row_number = 0, $field = 0, $link = null) +{ + $value = false; + + if (is_string($result)) { + $result = PMA_DBI_try_query($result, $link, PMA_DBI_QUERY_STORE, false); + } + + // return false if result is empty or false + // or requested row is larger than rows in result + if (PMA_DBI_num_rows($result) < ($row_number + 1)) { + return $value; + } + + // if $field is an integer use non associative mysql fetch function + if (is_int($field)) { + $fetch_function = 'PMA_DBI_fetch_row'; + } else { + $fetch_function = 'PMA_DBI_fetch_assoc'; + } + + // get requested row + for ($i = 0; $i <= $row_number; $i++) { + $row = $fetch_function($result); + } + PMA_DBI_free_result($result); + + // return requested field + if (isset($row[$field])) { + $value = $row[$field]; + } + unset($row); + + return $value; +} + +/** + * returns only the first row from the result + * + * + * $sql = 'SELECT * FROM `user` WHERE `id` = 123'; + * $user = PMA_DBI_fetch_single_row($sql); + * // produces + * // $user = array('id' => 123, 'name' => 'John Doe') + * + * + * @param string|mysql_result $result query or mysql result + * @param string $type NUM|ASSOC|BOTH + * returned array should either numeric + * associativ or booth + * @param resource $link mysql link + * + * @return array|boolean first row from result + * or false if result is empty + */ +function PMA_DBI_fetch_single_row($result, $type = 'ASSOC', $link = null) +{ + if (is_string($result)) { + $result = PMA_DBI_try_query($result, $link, PMA_DBI_QUERY_STORE, false); + } + + // return null if result is empty or false + if (! PMA_DBI_num_rows($result)) { + return false; + } + + switch ($type) { + case 'NUM' : + $fetch_function = 'PMA_DBI_fetch_row'; + break; + case 'ASSOC' : + $fetch_function = 'PMA_DBI_fetch_assoc'; + break; + case 'BOTH' : + default : + $fetch_function = 'PMA_DBI_fetch_array'; + break; + } + + $row = $fetch_function($result); + PMA_DBI_free_result($result); + return $row; +} + +/** + * returns all rows in the resultset in one array + * + * + * $sql = 'SELECT * FROM `user`'; + * $users = PMA_DBI_fetch_result($sql); + * // produces + * // $users[] = array('id' => 123, 'name' => 'John Doe') + * + * $sql = 'SELECT `id`, `name` FROM `user`'; + * $users = PMA_DBI_fetch_result($sql, 'id'); + * // produces + * // $users['123'] = array('id' => 123, 'name' => 'John Doe') + * + * $sql = 'SELECT `id`, `name` FROM `user`'; + * $users = PMA_DBI_fetch_result($sql, 0); + * // produces + * // $users['123'] = array(0 => 123, 1 => 'John Doe') + * + * $sql = 'SELECT `id`, `name` FROM `user`'; + * $users = PMA_DBI_fetch_result($sql, 'id', 'name'); + * // or + * $users = PMA_DBI_fetch_result($sql, 0, 1); + * // produces + * // $users['123'] = 'John Doe' + * + * $sql = 'SELECT `name` FROM `user`'; + * $users = PMA_DBI_fetch_result($sql); + * // produces + * // $users[] = 'John Doe' + * + * $sql = 'SELECT `group`, `name` FROM `user`' + * $users = PMA_DBI_fetch_result($sql, array('group', null), 'name'); + * // produces + * // $users['admin'][] = 'John Doe' + * + * $sql = 'SELECT `group`, `name` FROM `user`' + * $users = PMA_DBI_fetch_result($sql, array('group', 'name'), 'id'); + * // produces + * // $users['admin']['John Doe'] = '123' + * + * + * @param string|mysql_result $result query or mysql result + * @param string|integer $key field-name or offset + * used as key for array + * @param string|integer $value value-name or offset + * used as value for array + * @param resource $link mysql link + * @param mixed $options query options + * + * @return array resultrows or values indexed by $key + */ +function PMA_DBI_fetch_result($result, $key = null, $value = null, + $link = null, $options = 0 +) { + $resultrows = array(); + + if (is_string($result)) { + $result = PMA_DBI_try_query($result, $link, $options, false); + } + + // return empty array if result is empty or false + if (! $result) { + return $resultrows; + } + + $fetch_function = 'PMA_DBI_fetch_assoc'; + + // no nested array if only one field is in result + if (null === $key && 1 === PMA_DBI_num_fields($result)) { + $value = 0; + $fetch_function = 'PMA_DBI_fetch_row'; + } + + // if $key is an integer use non associative mysql fetch function + if (is_int($key)) { + $fetch_function = 'PMA_DBI_fetch_row'; + } + + if (null === $key && null === $value) { + while ($row = $fetch_function($result)) { + $resultrows[] = $row; + } + } elseif (null === $key) { + while ($row = $fetch_function($result)) { + $resultrows[] = $row[$value]; + } + } elseif (null === $value) { + if (is_array($key)) { + while ($row = $fetch_function($result)) { + $result_target =& $resultrows; + foreach ($key as $key_index) { + if (null === $key_index) { + $result_target =& $result_target[]; + continue; + } + + if (! isset($result_target[$row[$key_index]])) { + $result_target[$row[$key_index]] = array(); + } + $result_target =& $result_target[$row[$key_index]]; + } + $result_target = $row; + } + } else { + while ($row = $fetch_function($result)) { + $resultrows[$row[$key]] = $row; + } + } + } else { + if (is_array($key)) { + while ($row = $fetch_function($result)) { + $result_target =& $resultrows; + foreach ($key as $key_index) { + if (null === $key_index) { + $result_target =& $result_target[]; + continue; + } + + if (! isset($result_target[$row[$key_index]])) { + $result_target[$row[$key_index]] = array(); + } + $result_target =& $result_target[$row[$key_index]]; + } + $result_target = $row[$value]; + } + } else { + while ($row = $fetch_function($result)) { + $resultrows[$row[$key]] = $row[$value]; + } + } + } + + PMA_DBI_free_result($result); + return $resultrows; +} + +/** + * Get supported SQL compatibility modes + * + * @return array supported SQL compatibility modes + */ +function PMA_DBI_getCompatibilities() +{ + // Drizzle doesn't support compatibility modes + if (PMA_DRIZZLE) { + return array(); + } + + $compats = array('NONE'); + $compats[] = 'ANSI'; + $compats[] = 'DB2'; + $compats[] = 'MAXDB'; + $compats[] = 'MYSQL323'; + $compats[] = 'MYSQL40'; + $compats[] = 'MSSQL'; + $compats[] = 'ORACLE'; + // removed; in MySQL 5.0.33, this produces exports that + // can't be read by POSTGRESQL (see our bug #1596328) + //$compats[] = 'POSTGRESQL'; + $compats[] = 'TRADITIONAL'; + + return $compats; +} + +/** + * returns warnings for last query + * + * @param resource $link mysql link resource + * + * @return array warnings + */ +function PMA_DBI_get_warnings($link = null) +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return array(); + } + } + + return PMA_DBI_fetch_result('SHOW WARNINGS', null, null, $link); +} + +/** + * returns true (int > 0) if current user is superuser + * otherwise 0 + * + * @return bool Whether use is a superuser + */ +function PMA_isSuperuser() +{ + if (PMA_Util::cacheExists('is_superuser', true)) { + return PMA_Util::cacheGet('is_superuser', true); + } + + // when connection failed we don't have a $userlink + if (isset($GLOBALS['userlink'])) { + if (PMA_DRIZZLE) { + // Drizzle has no authorization by default, so when no plugin is + // enabled everyone is a superuser + // Known authorization libraries: regex_policy, simple_user_policy + // Plugins limit object visibility (dbs, tables, processes), we can + // safely assume we always deal with superuser + $result = true; + } else { + // check access to mysql.user table + $result = (bool) PMA_DBI_try_query( + 'SELECT COUNT(*) FROM mysql.user', + $GLOBALS['userlink'], + PMA_DBI_QUERY_STORE + ); + } + PMA_Util::cacheSet('is_superuser', $result, true); + } else { + PMA_Util::cacheSet('is_superuser', false, true); + } + + return PMA_Util::cacheGet('is_superuser', true); +} + +/** + * returns an array of PROCEDURE or FUNCTION names for a db + * + * @param string $db db name + * @param string $which PROCEDURE | FUNCTION + * @param resource $link mysql link + * + * @return array the procedure names or function names + */ +function PMA_DBI_get_procedures_or_functions($db, $which, $link = null) +{ + if (PMA_DRIZZLE) { + // Drizzle doesn't support functions and procedures + return array(); + } + $shows = PMA_DBI_fetch_result('SHOW ' . $which . ' STATUS;', null, null, $link); + $result = array(); + foreach ($shows as $one_show) { + if ($one_show['Db'] == $db && $one_show['Type'] == $which) { + $result[] = $one_show['Name']; + } + } + return($result); +} + +/** + * returns the definition of a specific PROCEDURE, FUNCTION, EVENT or VIEW + * + * @param string $db db name + * @param string $which PROCEDURE | FUNCTION | EVENT | VIEW + * @param string $name the procedure|function|event|view name + * @param resource $link mysql link + * + * @return string the definition + */ +function PMA_DBI_get_definition($db, $which, $name, $link = null) +{ + $returned_field = array( + 'PROCEDURE' => 'Create Procedure', + 'FUNCTION' => 'Create Function', + 'EVENT' => 'Create Event', + 'VIEW' => 'Create View' + ); + $query = 'SHOW CREATE ' . $which . ' ' + . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($name); + return(PMA_DBI_fetch_value($query, 0, $returned_field[$which])); +} + +/** + * returns details about the TRIGGERs for a specific table or database + * + * @param string $db db name + * @param string $table table name + * @param string $delimiter the delimiter to use (may be empty) + * + * @return array information about triggers (may be empty) + */ +function PMA_DBI_get_triggers($db, $table = '', $delimiter = '//') +{ + if (PMA_DRIZZLE) { + // Drizzle doesn't support triggers + return array(); + } + + $result = array(); + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + // Note: in http://dev.mysql.com/doc/refman/5.0/en/faqs-triggers.html + // their example uses WHERE TRIGGER_SCHEMA='dbname' so let's use this + // instead of WHERE EVENT_OBJECT_SCHEMA='dbname' + $query = 'SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION' + . ', EVENT_OBJECT_TABLE, ACTION_TIMING, ACTION_STATEMENT' + . ', EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE, DEFINER' + . ' FROM information_schema.TRIGGERS' + . ' WHERE TRIGGER_SCHEMA= \'' . PMA_Util::sqlAddSlashes($db) . '\''; + + if (! empty($table)) { + $query .= " AND EVENT_OBJECT_TABLE = '" + . PMA_Util::sqlAddSlashes($table) . "';"; + } + } else { + $query = "SHOW TRIGGERS FROM " . PMA_Util::backquote($db); + if (! empty($table)) { + $query .= " LIKE '" . PMA_Util::sqlAddSlashes($table, true) . "';"; + } + } + + if ($triggers = PMA_DBI_fetch_result($query)) { + foreach ($triggers as $trigger) { + if ($GLOBALS['cfg']['Server']['DisableIS']) { + $trigger['TRIGGER_NAME'] = $trigger['Trigger']; + $trigger['ACTION_TIMING'] = $trigger['Timing']; + $trigger['EVENT_MANIPULATION'] = $trigger['Event']; + $trigger['EVENT_OBJECT_TABLE'] = $trigger['Table']; + $trigger['ACTION_STATEMENT'] = $trigger['Statement']; + $trigger['DEFINER'] = $trigger['Definer']; + } + $one_result = array(); + $one_result['name'] = $trigger['TRIGGER_NAME']; + $one_result['table'] = $trigger['EVENT_OBJECT_TABLE']; + $one_result['action_timing'] = $trigger['ACTION_TIMING']; + $one_result['event_manipulation'] = $trigger['EVENT_MANIPULATION']; + $one_result['definition'] = $trigger['ACTION_STATEMENT']; + $one_result['definer'] = $trigger['DEFINER']; + + // do not prepend the schema name; this way, importing the + // definition into another schema will work + $one_result['full_trigger_name'] = PMA_Util::backquote( + $trigger['TRIGGER_NAME'] + ); + $one_result['drop'] = 'DROP TRIGGER IF EXISTS ' + . $one_result['full_trigger_name']; + $one_result['create'] = 'CREATE TRIGGER ' + . $one_result['full_trigger_name'] . ' ' + . $trigger['ACTION_TIMING']. ' ' + . $trigger['EVENT_MANIPULATION'] + . ' ON ' . PMA_Util::backquote($trigger['EVENT_OBJECT_TABLE']) + . "\n" . ' FOR EACH ROW ' + . $trigger['ACTION_STATEMENT'] . "\n" . $delimiter . "\n"; + + $result[] = $one_result; + } + } + + // Sort results by name + $name = array(); + foreach ($result as $value) { + $name[] = $value['name']; + } + array_multisort($name, SORT_ASC, $result); + + return($result); +} + +/** + * Formats database error message in a friendly way. + * This is needed because some errors messages cannot + * be obtained by mysql_error(). + * + * @param int $error_number Error code + * @param string $error_message Error message as returned by server + * + * @return string HML text with error details + */ +function PMA_DBI_formatError($error_number, $error_message) +{ + if (! empty($error_message)) { + $error_message = PMA_DBI_convert_message($error_message); + } + + $error_message = htmlspecialchars($error_message); + + $error = '#' . ((string) $error_number); + + if ($error_number == 2002) { + $error .= ' - ' . $error_message; + $error .= '
      '; + $error .= __( + 'The server is not responding (or the local server\'s socket' + . ' is not correctly configured).' + ); + } elseif ($error_number == 2003) { + $error .= ' - ' . $error_message; + $error .= '
      ' . __('The server is not responding.'); + } elseif ($error_number == 1005) { + if (strpos($error_message, 'errno: 13') !== false) { + $error .= ' - ' . $error_message; + $error .= '
      ' + . __('Please check privileges of directory containing database.'); + } else { + /* InnoDB contraints, see + * http://dev.mysql.com/doc/refman/5.0/en/ + * innodb-foreign-key-constraints.html + */ + $error .= ' - ' . $error_message . + ' (' . __('Details…') . ')'; + } + } else { + $error .= ' - ' . $error_message; + } + + return $error; +} + +/** + * Checks whether given schema is a system schema: information_schema + * (MySQL and Drizzle) or data_dictionary (Drizzle) + * + * @param string $schema_name Name of schema (database) to test + * @param bool $test_for_mysql_schema Whether 'mysql' schema should + * be treated the same as IS and DD + * + * @return bool + */ +function PMA_is_system_schema($schema_name, $test_for_mysql_schema = false) +{ + return strtolower($schema_name) == 'information_schema' + || (!PMA_DRIZZLE && strtolower($schema_name) == 'performance_schema') + || (PMA_DRIZZLE && strtolower($schema_name) == 'data_dictionary') + || ($test_for_mysql_schema && !PMA_DRIZZLE && $schema_name == 'mysql'); +} + +/** + * Get regular expression which occur first inside the given sql query. + * + * @param Array $regex_array Comparing regular expressions. + * @param String $query SQL query to be checked. + * + * @return String Matching regular expression. + */ +function PMA_getFirstOccurringRegularExpression($regex_array, $query) +{ + + $minimum_first_occurence_index = null; + $regex = null; + + for ($i = 0; $i < count($regex_array); $i++) { + if (preg_match($regex_array[$i], $query, $matches, PREG_OFFSET_CAPTURE)) { + + if (is_null($minimum_first_occurence_index) + || ($matches[0][1] < $minimum_first_occurence_index) + ) { + $regex = $regex_array[$i]; + $minimum_first_occurence_index = $matches[0][1]; + } + + } + } + + return $regex; + +} + +?> diff --git a/phpmyadmin/libraries/db_common.inc.php b/phpmyadmin/libraries/db_common.inc.php new file mode 100644 index 000000000..6cd4fc468 --- /dev/null +++ b/phpmyadmin/libraries/db_common.inc.php @@ -0,0 +1,100 @@ + back to the welcome page + $uri = $cfg['PmaAbsoluteUri'] . 'index.php?' + . PMA_generate_common_url('', '', '&') + . (isset($message) ? '&message=' . urlencode($message) : '') . '&reload=1'; + if (! strlen($db) || ! $is_db) { + $response = PMA_Response::getInstance(); + if ($response->isAjax()) { + $response->isSuccess(false); + $response->addJSON( + 'message', + PMA_Message::error(__('No databases selected.')) + ); + } else { + PMA_sendHeaderLocation($uri); + } + exit; + } +} // end if (ensures db exists) + +/** + * Changes database charset if requested by the user + */ +if (isset($_REQUEST['submitcollation']) + && isset($_REQUEST['db_collation']) + && ! empty($_REQUEST['db_collation']) +) { + list($db_charset) = explode('_', $_REQUEST['db_collation']); + $sql_query = 'ALTER DATABASE ' + . PMA_Util::backquote($db) + . ' DEFAULT' . PMA_generateCharsetQueryPart($_REQUEST['db_collation']); + $result = PMA_DBI_query($sql_query); + $message = PMA_Message::success(); + unset($db_charset); + + /** + * If we are in an Ajax request, let us stop the execution here. Necessary for + * db charset change action on db_operations.php. If this causes a bug on + * other pages, we might have to move this to a different location. + */ + if ( $GLOBALS['is_ajax_request'] == true) { + $response = PMA_Response::getInstance(); + $response->isSuccess($message->isSuccess()); + $response->addJSON('message', $message); + exit; + } +} + +/** + * Set parameters for links + */ +$url_query = PMA_generate_common_url($db); + +?> diff --git a/phpmyadmin/libraries/db_info.inc.php b/phpmyadmin/libraries/db_info.inc.php new file mode 100644 index 000000000..569cb4a16 --- /dev/null +++ b/phpmyadmin/libraries/db_info.inc.php @@ -0,0 +1,224 @@ + 0) { + while ($tmp = PMA_DBI_fetch_row($db_info_result)) { + // if in use memorize tablename + if (preg_match('@in_use=[1-9]+@i', $tmp[1])) { + $sot_cache[$tmp[0]] = true; + } + } + PMA_DBI_free_result($db_info_result); + + if (isset($sot_cache)) { + $db_info_result = PMA_DBI_query( + 'SHOW TABLES FROM ' . PMA_Util::backquote($db) . $tbl_group_sql . ';', + null, PMA_DBI_QUERY_STORE + ); + if ($db_info_result && PMA_DBI_num_rows($db_info_result) > 0) { + while ($tmp = PMA_DBI_fetch_row($db_info_result)) { + if (! isset($sot_cache[$tmp[0]])) { + $sts_result = PMA_DBI_query( + 'SHOW TABLE STATUS FROM ' . PMA_Util::backquote($db) + . ' LIKE \'' . PMA_Util::sqlAddSlashes($tmp[0], true) . '\';' + ); + $sts_tmp = PMA_DBI_fetch_assoc($sts_result); + PMA_DBI_free_result($sts_result); + unset($sts_result); + + if (! isset($sts_tmp['Type']) && isset($sts_tmp['Engine'])) { + $sts_tmp['Type'] =& $sts_tmp['Engine']; + } + + if (! empty($tbl_group) + && ! preg_match('@' . preg_quote($tbl_group, '@') . '@i', $sts_tmp['Comment']) + ) { + continue; + } + + if ($cfg['ShowTooltip']) { + PMA_Util::fillTooltip( + $tooltip_truename, $tooltip_aliasname, $sts_tmp + ); + } + + $tables[$sts_tmp['Name']] = $sts_tmp; + } else { // table in use + $tables[$tmp[0]] = array('Name' => $tmp[0]); + } + } + if ($GLOBALS['cfg']['NaturalOrder']) { + uksort($tables, 'strnatcasecmp'); + } + + $sot_ready = true; + } elseif ($db_info_result) { + PMA_DBI_free_result($db_info_result); + } + unset($sot_cache); + } + unset($tmp); + } elseif ($db_info_result) { + PMA_DBI_free_result($db_info_result); + } +} + +if (! isset($sot_ready)) { + + // Set some sorting defaults + $sort = 'Name'; + $sort_order = 'ASC'; + + if (isset($_REQUEST['sort'])) { + $sortable_name_mappings = array( + 'table' => 'Name', + 'records' => 'Rows', + 'type' => 'Engine', + 'collation' => 'Collation', + 'size' => 'Data_length', + 'overhead' => 'Data_free', + 'creation' => 'Create_time', + 'last_update' => 'Update_time', + 'last_check' => 'Check_time' + ); + + // Make sure the sort type is implemented + if (isset($sortable_name_mappings[$_REQUEST['sort']])) { + $sort = $sortable_name_mappings[$_REQUEST['sort']]; + if ($_REQUEST['sort_order'] == 'DESC') { + $sort_order = 'DESC'; + } + } + } + + if (! empty($tbl_group)) { + // only tables for selected group + $tables = PMA_DBI_get_tables_full( + $db, $tbl_group, true, null, 0, false, $sort, $sort_order + ); + } else { + // all tables in db + // - get the total number of tables + // (needed for proper working of the MaxTableList feature) + $tables = PMA_DBI_get_tables($db); + $total_num_tables = count($tables); + if (isset($sub_part) && $sub_part == '_export') { + // (don't fetch only a subset if we are coming from db_export.php, + // because I think it's too risky to display only a subset of the + // table names when exporting a db) + /** + * + * @todo Page selector for table names? + */ + $tables = PMA_DBI_get_tables_full( + $db, false, false, null, 0, false, $sort, $sort_order + ); + } else { + // fetch the details for a possible limited subset + $tables = PMA_DBI_get_tables_full( + $db, false, false, null, $pos, true, $sort, $sort_order + ); + } + } + + if ($cfg['ShowTooltip']) { + foreach ($tables as $each_table) { + PMA_Util::fillTooltip( + $tooltip_truename, $tooltip_aliasname, $each_table + ); + } + } +} + +/** + * @global int count of tables in db + */ +$num_tables = count($tables); +// (needed for proper working of the MaxTableList feature) +if (! isset($total_num_tables)) { + $total_num_tables = $num_tables; +} + +/** + * cleanup + */ +unset($each_table, $tbl_group_sql, $db_info_result); + +/** + * If coming from a Show MySQL link on the home page, + * put something in $sub_part + */ +if (empty($sub_part)) { + $sub_part = '_structure'; +} +?> diff --git a/phpmyadmin/libraries/db_table_exists.lib.php b/phpmyadmin/libraries/db_table_exists.lib.php new file mode 100644 index 000000000..ef8b927d5 --- /dev/null +++ b/phpmyadmin/libraries/db_table_exists.lib.php @@ -0,0 +1,103 @@ + back to the welcome page + if (! defined('IS_TRANSFORMATION_WRAPPER')) { + $response = PMA_Response::getInstance(); + if ($response->isAjax()) { + $response->isSuccess(false); + $response->addJSON( + 'message', + PMA_Message::error(__('No databases selected.')) + ); + } else { + $url_params = array('reload' => 1); + if (isset($message)) { + $url_params['message'] = $message; + } + if (! empty($sql_query)) { + $url_params['sql_query'] = $sql_query; + } + if (isset($show_as_php)) { + $url_params['show_as_php'] = $show_as_php; + } + PMA_sendHeaderLocation( + $cfg['PmaAbsoluteUri'] . 'index.php' + . PMA_generate_common_url($url_params, '&') + ); + } + exit; + } + } +} // end if (ensures db exists) + +if (empty($is_table) + && !defined('PMA_SUBMIT_MULT') + && ! defined('TABLE_MAY_BE_ABSENT') +) { + // Not a valid table name -> back to the db_sql.php + + if (strlen($table)) { + $is_table = isset(PMA_Table::$cache[$db][$table]); + + if (! $is_table) { + $_result = PMA_DBI_try_query( + 'SHOW TABLES LIKE \'' . PMA_Util::sqlAddSlashes($table, true) . '\';', + null, PMA_DBI_QUERY_STORE + ); + $is_table = @PMA_DBI_num_rows($_result); + PMA_DBI_free_result($_result); + } + } else { + $is_table = false; + } + + if (! $is_table) { + if (! defined('IS_TRANSFORMATION_WRAPPER')) { + if (strlen($table)) { + // SHOW TABLES doesn't show temporary tables, so try select + // (as it can happen just in case temporary table, it should be + // fast): + + /** + * @todo should this check really + * only happen if IS_TRANSFORMATION_WRAPPER? + */ + $_result = PMA_DBI_try_query( + 'SELECT COUNT(*) FROM ' . PMA_Util::backquote($table) . ';', + null, + PMA_DBI_QUERY_STORE + ); + $is_table = ($_result && @PMA_DBI_num_rows($_result)); + PMA_DBI_free_result($_result); + } + + if (! $is_table) { + include './db_sql.php'; + exit; + } + } + + if (! $is_table) { + exit; + } + } +} // end if (ensures table exists) +?> diff --git a/phpmyadmin/libraries/dbi/drizzle-wrappers.lib.php b/phpmyadmin/libraries/dbi/drizzle-wrappers.lib.php new file mode 100644 index 000000000..430a78d97 --- /dev/null +++ b/phpmyadmin/libraries/dbi/drizzle-wrappers.lib.php @@ -0,0 +1,437 @@ +_dcon = $dcon; + } + + /** + * Executes given query. Opens database connection if not already done. + * + * @param string $query query to execute + * @param int $bufferMode PMA_Drizzle::BUFFER_RESULT,PMA_Drizzle::BUFFER_ROW + * @param int $fetchMode PMA_Drizzle::FETCH_ASSOC, PMA_Drizzle::FETCH_NUM + * or PMA_Drizzle::FETCH_BOTH + * + * @return PMA_DrizzleResult + */ + public function query($query, $bufferMode = PMA_Drizzle::BUFFER_RESULT, + $fetchMode = PMA_Drizzle::FETCH_ASSOC + ) { + $result = $this->_dcon->query($query); + if ($result instanceof DrizzleResult) { + $this->_lastResult = new PMA_DrizzleResult( + $result, $bufferMode, $fetchMode + ); + return $this->_lastResult; + } + return $result; + } + + /** + * Returns the number of rows affected by last query + * + * @return int|false + */ + public function affectedRows() + { + return $this->_lastResult + ? $this->_lastResult->affectedRows() + : false; + } + + /** + * Pass calls of undefined methods to DrizzleCon object + * + * @param string $method method name + * @param mixed $args method parameters + * + * @return mixed + */ + public function __call($method, $args) + { + return call_user_func_array(array($this->_dcon, $method), $args); + } + + /** + * Returns original Drizzle connection object + * + * @return DrizzleCon + */ + public function getConnectionObject() + { + return $this->_dcon; + } +} + +/** + * Wrapper around DrizzleResult. + * + * Allows for reading result rows as an associative array and hides complexity + * behind buffering. + * + * @package PhpMyAdmin-DBI + * @subpackage Drizzle + */ +class PMA_DrizzleResult +{ + /** + * Instamce of DrizzleResult class + * @var DrizzleResult + */ + private $_dresult; + /** + * Fetch mode + * @var int + */ + private $_fetchMode; + /** + * Buffering mode + * @var int + */ + private $_bufferMode; + + /** + * Cached column data + * @var DrizzleColumn[] + */ + private $_columns = null; + /** + * Cached column names + * @var string[] + */ + private $_columnNames = null; + + /** + * Constructor + * + * @param DrizzleResult $dresult result handler + * @param int $bufferMode buffering mode + * @param int $fetchMode fetching mode + */ + public function __construct(DrizzleResult $dresult, $bufferMode, $fetchMode) + { + $this->_dresult = $dresult; + $this->_bufferMode = $bufferMode; + $this->_fetchMode = $fetchMode; + + if ($this->_bufferMode == PMA_Drizzle::BUFFER_RESULT) { + $this->_dresult->buffer(); + } + } + + /** + * Sets fetch mode + * + * @param int $fetchMode fetch mode + * + * @return void + */ + public function setFetchMode($fetchMode) + { + $this->_fetchMode = $fetchMode; + } + + /** + * Reads information about columns contained in current result + * set into {@see $_columns} and {@see $_columnNames} arrays + * + * @return void + */ + private function _readColumns() + { + $this->_columns = array(); + $this->_columnNames = array(); + if ($this->_bufferMode == PMA_Drizzle::BUFFER_RESULT) { + while (($column = $this->_dresult->columnNext()) !== null) { + $this->_columns[] = $column; + $this->_columnNames[] = $column->name(); + } + } else { + while (($column = $this->_dresult->columnRead()) !== null) { + $this->_columns[] = $column; + $this->_columnNames[] = $column->name(); + } + } + } + + /** + * Returns columns in current result + * + * @return DrizzleColumn[] + */ + public function getColumns() + { + if (!$this->_columns) { + $this->_readColumns(); + } + return $this->_columns; + } + + /** + * Returns number if columns in result + * + * @return int + */ + public function numColumns() + { + return $this->_dresult->columnCount(); + } + + /** + * Transforms result row to conform to current fetch mode + * + * @param mixed &$row row to process + * @param int $fetchMode fetch mode + * + * @return void + */ + private function _transformResultRow(&$row, $fetchMode) + { + if (!$row) { + return; + } + + switch ($fetchMode) { + case PMA_Drizzle::FETCH_ASSOC: + $row = array_combine($this->_columnNames, $row); + break; + case PMA_Drizzle::FETCH_BOTH: + $length = count($row); + for ($i = 0; $i < $length; $i++) { + $row[$this->_columnNames[$i]] = $row[$i]; + } + break; + default: + break; + } + } + + /** + * Fetches next for from this result set + * + * @param int $fetchMode fetch mode to use, if not given the default one is used + * + * @return array|null + */ + public function fetchRow($fetchMode = null) + { + // read column names on first fetch, only buffered results + // allow for reading it later + if (!$this->_columns) { + $this->_readColumns(); + } + if ($fetchMode === null) { + $fetchMode = $this->_fetchMode; + } + $row = null; + switch ($this->_bufferMode) { + case PMA_Drizzle::BUFFER_RESULT: + $row = $this->_dresult->rowNext(); + break; + case PMA_Drizzle::BUFFER_ROW: + $row = $this->_dresult->rowBuffer(); + break; + } + $this->_transformResultRow($row, $fetchMode); + return $row; + } + + /** + * Adjusts the result pointer to an arbitrary row in buffered result + * + * @param integer $row_index where to seek + * + * @return bool + */ + public function seek($row_index) + { + if ($this->_bufferMode != PMA_Drizzle::BUFFER_RESULT) { + trigger_error( + __("Can't seek in an unbuffered result set"), E_USER_WARNING + ); + return false; + } + // rowSeek always returns NULL (drizzle extension v.0.5, API v.7) + if ($row_index >= 0 && $row_index < $this->_dresult->rowCount()) { + $this->_dresult->rowSeek($row_index); + return true; + } + return false; + } + + /** + * Returns the number of rows in buffered result set + * + * @return int|false + */ + public function numRows() + { + if ($this->_bufferMode != PMA_Drizzle::BUFFER_RESULT) { + trigger_error( + __("Can't count rows in an unbuffered result set"), E_USER_WARNING + ); + return false; + } + return $this->_dresult->rowCount(); + } + + /** + * Returns the number of rows affected by query + * + * @return int|false + */ + public function affectedRows() + { + return $this->_dresult->affectedRows(); + } + + /** + * Frees resources taken by this result + * + * @return void + */ + public function free() + { + unset($this->_columns); + unset($this->_columnNames); + drizzle_result_free($this->_dresult); + unset($this->_dresult); + } +} diff --git a/phpmyadmin/libraries/dbi/drizzle.dbi.lib.php b/phpmyadmin/libraries/dbi/drizzle.dbi.lib.php new file mode 100644 index 000000000..093e5d624 --- /dev/null +++ b/phpmyadmin/libraries/dbi/drizzle.dbi.lib.php @@ -0,0 +1,667 @@ +addUds($uds, $user, $password, $db, $options); + } else { + $con = $drizzle->addTcp($host, $port, $user, $password, $db, $options); + } + + return $con; +} + +/** + * connects to the database server + * + * @param string $user drizzle user name + * @param string $password drizzle user password + * @param bool $is_controluser whether this is a control user connection + * @param array $server host/port/socket/persistent + * @param bool $auxiliary_connection (when true, don't go back to login if + * connection fails) + * + * @return mixed false on error or a mysqli object on success + */ +function PMA_DBI_connect($user, $password, $is_controluser = false, + $server = null, $auxiliary_connection = false +) { + global $cfg; + + if ($server) { + $server_port = (empty($server['port'])) + ? false + : (int)$server['port']; + $server_socket = (empty($server['socket'])) + ? '' + : $server['socket']; + $server['host'] = (empty($server['host'])) + ? 'localhost' + : $server['host']; + } else { + $server_port = (empty($cfg['Server']['port'])) + ? false + : (int) $cfg['Server']['port']; + $server_socket = (empty($cfg['Server']['socket'])) + ? null + : $cfg['Server']['socket']; + } + + if (strtolower($GLOBALS['cfg']['Server']['connect_type']) == 'tcp') { + $GLOBALS['cfg']['Server']['socket'] = ''; + } + + $drizzle = new PMA_Drizzle(); + + $client_flags = 0; + + /* Optionally compress connection */ + if ($GLOBALS['cfg']['Server']['compress']) { + $client_flags |= DRIZZLE_CAPABILITIES_COMPRESS; + } + + /* Optionally enable SSL */ + if ($GLOBALS['cfg']['Server']['ssl']) { + $client_flags |= DRIZZLE_CAPABILITIES_SSL; + } + + if (!$server) { + $link = @PMA_DBI_real_connect( + $drizzle, $cfg['Server']['host'], $server_port, $server_socket, $user, + $password, false, $client_flags + ); + // Retry with empty password if we're allowed to + if ($link == false && isset($cfg['Server']['nopassword']) + && $cfg['Server']['nopassword'] && !$is_controluser + ) { + $link = @PMA_DBI_real_connect( + $drizzle, $cfg['Server']['host'], $server_port, $server_socket, + $user, null, false, $client_flags + ); + } + } else { + $link = @PMA_DBI_real_connect( + $drizzle, $server['host'], $server_port, $server_socket, + $user, $password + ); + } + + if ($link == false) { + if ($is_controluser) { + trigger_error( + __( + 'Connection for controluser as defined' + . ' in your configuration failed.' + ), + E_USER_WARNING + ); + return false; + } + // we could be calling PMA_DBI_connect() to connect to another + // server, for example in the Synchronize feature, so do not + // go back to main login if it fails + if (! $auxiliary_connection) { + PMA_log_user($user, 'drizzle-denied'); + global $auth_plugin; + $auth_plugin->authFails(); + } else { + return false; + } + } else { + PMA_DBI_postConnect($link, $is_controluser); + } + + return $link; +} + +/** + * selects given database + * + * @param string $dbname database name to select + * @param PMA_DrizzleCom $link connection object + * + * @return bool + */ +function PMA_DBI_select_db($dbname, $link = null) +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + return $link->selectDb($dbname); +} + +/** + * runs a query and returns the result + * + * @param string $query query to execute + * @param PMA_DrizzleCon $link connection object + * @param int $options query options + * + * @return PMA_DrizzleResult + */ +function PMA_DBI_real_query($query, $link, $options) +{ + $buffer_mode = $options & PMA_DBI_QUERY_UNBUFFERED + ? PMA_Drizzle::BUFFER_ROW + : PMA_Drizzle::BUFFER_RESULT; + $res = $link->query($query, $buffer_mode); + return $res; +} + +/** + * returns array of rows with associative and numeric keys from $result + * + * @param PMA_DrizzleResult $result Drizzle result object + * + * @return array + */ +function PMA_DBI_fetch_array($result) +{ + return $result->fetchRow(PMA_Drizzle::FETCH_BOTH); +} + +/** + * returns array of rows with associative keys from $result + * + * @param PMA_DrizzleResult $result Drizzle result object + * + * @return array + */ +function PMA_DBI_fetch_assoc($result) +{ + return $result->fetchRow(PMA_Drizzle::FETCH_ASSOC); +} + +/** + * returns array of rows with numeric keys from $result + * + * @param PMA_DrizzleResult $result Drizzle result object + * + * @return array + */ +function PMA_DBI_fetch_row($result) +{ + return $result->fetchRow(PMA_Drizzle::FETCH_NUM); +} + +/** + * Adjusts the result pointer to an arbitrary row in the result + * + * @param PMA_DrizzleResult $result Drizzle result object + * @param int $offset offset to seek + * + * @return boolean true on success, false on failure + */ +function PMA_DBI_data_seek($result, $offset) +{ + return $result->seek($offset); +} + +/** + * Frees memory associated with the result + * + * @param PMA_DrizzleResult $result database result + * + * @return void + */ +function PMA_DBI_free_result($result) +{ + if ($result instanceof PMA_DrizzleResult) { + $result->free(); + } +} + +/** + * Check if there are any more query results from a multi query + * + * @return bool false + */ +function PMA_DBI_more_results() +{ + // N.B.: PHP's 'mysql' extension does not support + // multi_queries so this function will always + // return false. Use the 'mysqli' extension, if + // you need support for multi_queries. + return false; +} + +/** + * Prepare next result from multi_query + * + * @return bool false + */ +function PMA_DBI_next_result() +{ + // N.B.: PHP's 'mysql' extension does not support + // multi_queries so this function will always + // return false. Use the 'mysqli' extension, if + // you need support for multi_queries. + return false; +} + +/** + * Returns a string representing the type of connection used + * + * @param PMA_DrizzleCon $link connection object + * + * @return string type of connection used + */ +function PMA_DBI_get_host_info($link = null) +{ + if (null === $link) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + + $str = $link->port() + ? $link->host() . ':' . $link->port() . ' via TCP/IP' + : 'Localhost via UNIX socket'; + return $str; +} + +/** + * Returns the version of the Drizzle protocol used + * + * @param PMA_DrizzleCon $link connection object + * + * @return int version of the Drizzle protocol used + */ +function PMA_DBI_get_proto_info($link = null) +{ + if (null === $link) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + + return $link->protocolVersion(); +} + +/** + * returns a string that represents the client library version + * + * @return string Drizzle client library version + */ +function PMA_DBI_get_client_info() +{ + return 'libdrizzle (Drizzle ' . drizzle_version() . ')'; +} + +/** + * returns last error message or false if no errors occured + * + * @param PMA_DrizzleCon $link connection object + * + * @return string|bool $error or false + */ +function PMA_DBI_getError($link = null) +{ + $GLOBALS['errno'] = 0; + + /* Treat false same as null because of controllink */ + if ($link === false) { + $link = null; + } + + if (null === $link && isset($GLOBALS['userlink'])) { + $link =& $GLOBALS['userlink']; + // Do not stop now. We still can get the error code + // with mysqli_connect_errno() + // } else { + // return false; + } + + if (null !== $link) { + $error_number = drizzle_con_errno($link->getConnectionObject()); + $error_message = drizzle_con_error($link->getConnectionObject()); + } else { + $error_number = drizzle_errno(); + $error_message = drizzle_error(); + } + if (0 == $error_number) { + return false; + } + + // keep the error number for further check after the call to PMA_DBI_getError() + $GLOBALS['errno'] = $error_number; + + return PMA_DBI_formatError($error_number, $error_message); +} + +/** + * returns the number of rows returned by last query + * + * @param PMA_DrizzleResult $result Drizzle result object + * + * @return string|int + */ +function PMA_DBI_num_rows($result) +{ + // see the note for PMA_DBI_try_query(); + if (!is_bool($result)) { + return @$result->numRows(); + } else { + return 0; + } +} + +/** + * returns last inserted auto_increment id for given $link or $GLOBALS['userlink'] + * + * @param PMA_DrizzleCon $link connection object + * + * @return string|int + */ +function PMA_DBI_insert_id($link = null) +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + + // copied from mysql and mysqli + + // When no controluser is defined, using mysqli_insert_id($link) + // does not always return the last insert id due to a mixup with + // the tracking mechanism, but this works: + return PMA_DBI_fetch_value('SELECT LAST_INSERT_ID();', 0, 0, $link); + // Curiously, this problem does not happen with the mysql extension but + // there is another problem with BIGINT primary keys so PMA_DBI_insert_id() + // in the mysql extension also uses this logic. +} + +/** + * returns the number of rows affected by last query + * + * @param PMA_DrizzleResult $link connection object + * @param bool $get_from_cache whether to retrieve from cache + * + * @return string|int + */ +function PMA_DBI_affected_rows($link = null, $get_from_cache = true) +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + if ($get_from_cache) { + return $GLOBALS['cached_affected_rows']; + } else { + return $link->affectedRows(); + } +} + +/** + * returns metainfo for fields in $result + * + * @param PMA_DrizzleResult $result Drizzle result object + * + * @return array meta info for fields in $result + */ +function PMA_DBI_get_fields_meta($result) +{ + // Build an associative array for a type look up + $typeAr = array(); + /*$typeAr[DRIZZLE_COLUMN_TYPE_DECIMAL] = 'real'; + $typeAr[DRIZZLE_COLUMN_TYPE_NEWDECIMAL] = 'real'; + $typeAr[DRIZZLE_COLUMN_TYPE_BIT] = 'int'; + $typeAr[DRIZZLE_COLUMN_TYPE_TINY] = 'int'; + $typeAr[DRIZZLE_COLUMN_TYPE_SHORT] = 'int'; + $typeAr[DRIZZLE_COLUMN_TYPE_LONG] = 'int'; + $typeAr[DRIZZLE_COLUMN_TYPE_FLOAT] = 'real'; + $typeAr[DRIZZLE_COLUMN_TYPE_DOUBLE] = 'real'; + $typeAr[DRIZZLE_COLUMN_TYPE_NULL] = 'null'; + $typeAr[DRIZZLE_COLUMN_TYPE_TIMESTAMP] = 'timestamp'; + $typeAr[DRIZZLE_COLUMN_TYPE_LONGLONG] = 'int'; + $typeAr[DRIZZLE_COLUMN_TYPE_INT24] = 'int'; + $typeAr[DRIZZLE_COLUMN_TYPE_DATE] = 'date'; + $typeAr[DRIZZLE_COLUMN_TYPE_TIME] = 'date'; + $typeAr[DRIZZLE_COLUMN_TYPE_DATETIME] = 'datetime'; + $typeAr[DRIZZLE_COLUMN_TYPE_YEAR] = 'year'; + $typeAr[DRIZZLE_COLUMN_TYPE_NEWDATE] = 'date'; + $typeAr[DRIZZLE_COLUMN_TYPE_ENUM] = 'unknown'; + $typeAr[DRIZZLE_COLUMN_TYPE_SET] = 'unknown'; + $typeAr[DRIZZLE_COLUMN_TYPE_VIRTUAL] = 'unknown'; + $typeAr[DRIZZLE_COLUMN_TYPE_TINY_BLOB] = 'blob'; + $typeAr[DRIZZLE_COLUMN_TYPE_MEDIUM_BLOB] = 'blob'; + $typeAr[DRIZZLE_COLUMN_TYPE_LONG_BLOB] = 'blob'; + $typeAr[DRIZZLE_COLUMN_TYPE_BLOB] = 'blob'; + $typeAr[DRIZZLE_COLUMN_TYPE_VAR_STRING] = 'string'; + $typeAr[DRIZZLE_COLUMN_TYPE_VARCHAR] = 'string'; + $typeAr[DRIZZLE_COLUMN_TYPE_STRING] = 'string'; + $typeAr[DRIZZLE_COLUMN_TYPE_GEOMETRY] = 'geometry';*/ + + $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_BLOB] = 'blob'; + $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_DATE] = 'date'; + $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_DATETIME] = 'datetime'; + $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_DOUBLE] = 'real'; + $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_ENUM] = 'unknown'; + $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_LONG] = 'int'; + $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_LONGLONG] = 'int'; + $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_MAX] = 'unknown'; + $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_NULL] = 'null'; + $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_TIMESTAMP] = 'timestamp'; + $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_TINY] = 'int'; + $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_VARCHAR] = 'string'; + + // array of DrizzleColumn + $columns = $result->getColumns(); + // columns in a standarized format + $std_columns = array(); + + foreach ($columns as $k => $column) { + $c = new stdClass(); + $c->name = $column->name(); + $c->orgname = $column->origName(); + $c->table = $column->table(); + $c->orgtable = $column->origTable(); + $c->def = $column->defaultValue(); + $c->db = $column->db(); + $c->catalog = $column->catalog(); + // $column->maxSize() returns always 0 while size() seems + // to return a correct value (drizzle extension v.0.5, API v.7) + $c->max_length = $column->size(); + $c->decimals = $column->decimals(); + $c->charsetnr = $column->charset(); + $c->type = $typeAr[$column->typeDrizzle()]; + $c->_type = $column->type(); + $c->flags = PMA_DBI_field_flags($result, $k); + $c->_flags = $column->flags(); + + $c->multiple_key = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_MULTIPLE_KEY); + $c->primary_key = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_PRI_KEY); + $c->unique_key = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_UNIQUE_KEY); + $c->not_null = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_NOT_NULL); + $c->unsigned = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_UNSIGNED); + $c->zerofill = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_ZEROFILL); + $c->numeric = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_NUM); + $c->blob = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_BLOB); + + $std_columns[] = $c; + } + + return $std_columns; +} + +/** + * return number of fields in given $result + * + * @param PMA_DrizzleResult $result Drizzle result object + * + * @return int field count + */ +function PMA_DBI_num_fields($result) +{ + return $result->numColumns(); +} + +/** + * returns the length of the given field $i in $result + * + * @param PMA_DrizzleResult $result Drizzle result object + * @param int $i field + * + * @return int length of field + */ +function PMA_DBI_field_len($result, $i) +{ + $colums = $result->getColumns(); + return $colums[$i]->size(); +} + +/** + * returns name of $i. field in $result + * + * @param PMA_DrizzleResult $result Drizzle result object + * @param int $i field + * + * @return string name of $i. field in $result + */ +function PMA_DBI_field_name($result, $i) +{ + $colums = $result->getColumns(); + return $colums[$i]->name(); +} + +/** + * returns concatenated string of human readable field flags + * + * @param PMA_DrizzleResult $result Drizzle result object + * @param int $i field + * + * @return string field flags + */ +function PMA_DBI_field_flags($result, $i) +{ + $columns = $result->getColumns(); + $f = $columns[$i]; + $type = $f->typeDrizzle(); + $charsetnr = $f->charset(); + $f = $f->flags(); + $flags = ''; + if ($f & DRIZZLE_COLUMN_FLAGS_UNIQUE_KEY) { + $flags .= 'unique '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_NUM) { + $flags .= 'num '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_PART_KEY) { + $flags .= 'part_key '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_SET) { + $flags .= 'set '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_TIMESTAMP) { + $flags .= 'timestamp '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_AUTO_INCREMENT) { + $flags .= 'auto_increment '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_ENUM) { + $flags .= 'enum '; + } + // See http://dev.mysql.com/doc/refman/6.0/en/c-api-datatypes.html: + // to determine if a string is binary, we should not use MYSQLI_BINARY_FLAG + // but instead the charsetnr member of the MYSQL_FIELD + // structure. Watch out: some types like DATE returns 63 in charsetnr + // so we have to check also the type. + // Unfortunately there is no equivalent in the mysql extension. + if (($type == DRIZZLE_COLUMN_TYPE_DRIZZLE_BLOB + || $type == DRIZZLE_COLUMN_TYPE_DRIZZLE_VARCHAR) + && 63 == $charsetnr + ) { + $flags .= 'binary '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_ZEROFILL) { + $flags .= 'zerofill '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_UNSIGNED) { + $flags .= 'unsigned '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_BLOB) { + $flags .= 'blob '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_MULTIPLE_KEY) { + $flags .= 'multiple_key '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_UNIQUE_KEY) { + $flags .= 'unique_key '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_PRI_KEY) { + $flags .= 'primary_key '; + } + if ($f & DRIZZLE_COLUMN_FLAGS_NOT_NULL) { + $flags .= 'not_null '; + } + return trim($flags); +} + +/** + * Store the result returned from multi query + * + * @return false + */ +function PMA_DBI_store_result() +{ + return false; +} + +?> diff --git a/phpmyadmin/libraries/dbi/dummy.lib.php b/phpmyadmin/libraries/dbi/dummy.lib.php new file mode 100644 index 000000000..66138bccf --- /dev/null +++ b/phpmyadmin/libraries/dbi/dummy.lib.php @@ -0,0 +1,511 @@ + 'SELECT 1', 'result' => array(array('1'))), + array( + 'query' => 'SELECT CURRENT_USER();', + 'result' => array(array('pma_test@localhost')), + ), + array( + 'query' => 'SELECT COUNT(*) FROM mysql.user', + 'result' => false, + ), + array( + 'query' => 'SHOW MASTER LOGS', + 'result' => false, + ), + array( + 'query' => 'SHOW STORAGE ENGINES', + 'result' => array( + array('Engine' => 'dummy', 'Support' => 'YES', 'Comment' => 'dummy comment'), + array('Engine' => 'dummy2', 'Support' => 'NO', 'Comment' => 'dummy2 comment'), + ) + ), + array( + 'query' => 'SHOW STATUS WHERE Variable_name LIKE \'Innodb\\_buffer\\_pool\\_%\' OR Variable_name = \'Innodb_page_size\';', + 'result' => array( + array('Innodb_buffer_pool_pages_data', 0), + array('Innodb_buffer_pool_pages_dirty', 0), + array('Innodb_buffer_pool_pages_flushed', 0), + array('Innodb_buffer_pool_pages_free', 0), + array('Innodb_buffer_pool_pages_misc', 0), + array('Innodb_buffer_pool_pages_total', 4096), + array('Innodb_buffer_pool_read_ahead_rnd', 0), + array('Innodb_buffer_pool_read_ahead', 0), + array('Innodb_buffer_pool_read_ahead_evicted', 0), + array('Innodb_buffer_pool_read_requests', 64), + array('Innodb_buffer_pool_reads', 32), + array('Innodb_buffer_pool_wait_free', 0), + array('Innodb_buffer_pool_write_requests', 64), + array('Innodb_page_size', 16384), + ) + ), + array( + 'query' => 'SHOW INNODB STATUS;', + 'result' => false, + ), + array( + 'query' => 'SELECT @@innodb_version;', + 'result' => array( + array('1.1.8'), + ) + ), + array( + 'query' => 'SHOW GLOBAL VARIABLES LIKE \'innodb_file_per_table\';', + 'result' => array( + array('innodb_file_per_table', 'OFF'), + ) + ), + array( + 'query' => 'SHOW GLOBAL VARIABLES LIKE \'innodb_file_format\';', + 'result' => array( + array('innodb_file_format', 'Antelope'), + ) + ), + array( + 'query' => 'SHOW VARIABLES LIKE \'collation_server\'', + 'result' => array( + array('collation_server', 'utf8_general_ci'), + ) + ), + array( + 'query' => 'SHOW VARIABLES LIKE \'language\';', + 'result' => array(), + ), + array( + 'query' => 'SHOW TABLES FROM `pma_test`;', + 'result' => array( + array('table1'), + array('table2'), + ) + ), + array( + 'query' => 'SHOW TABLES FROM `pmadb`', + 'result' => array( + array('column_info'), + ) + ), + array( + 'query' => 'SHOW COLUMNS FROM `pma_test`.`table1`', + 'columns' => array( + 'Field', 'Type', 'Null', 'Key', 'Default', 'Extra' + ), + 'result' => array( + array('i', 'int(11)', 'NO', 'PRI', 'NULL', 'auto_increment'), + array('o', 'int(11)', 'NO', 'MUL', 'NULL', ''), + ) + ), + array( + 'query' => 'SHOW INDEXES FROM `pma_test`.`table1` WHERE (Non_unique = 0)', + 'result' => array(), + ), + array( + 'query' => 'SHOW COLUMNS FROM `pma_test`.`table2`', + 'columns' => array( + 'Field', 'Type', 'Null', 'Key', 'Default', 'Extra' + ), + 'result' => array( + array('i', 'int(11)', 'NO', 'PRI', 'NULL', 'auto_increment'), + array('o', 'int(11)', 'NO', 'MUL', 'NULL', ''), + ) + ), + array( + 'query' => 'SHOW INDEXES FROM `pma_test`.`table1`', + 'result' => array(), + ), + array( + 'query' => 'SHOW INDEXES FROM `pma_test`.`table2`', + 'result' => array(), + ), + array( + 'query' => 'SHOW COLUMNS FROM `pma`.`table1`', + 'columns' => array( + 'Field', 'Type', 'Null', 'Key', 'Default', 'Extra', 'Privileges', 'Comment' + ), + 'result' => array( + array('i', 'int(11)', 'NO', 'PRI', 'NULL', 'auto_increment', 'select,insert,update,references', ''), + array('o', 'varchar(100)', 'NO', 'MUL', 'NULL', '', 'select,insert,update,references', ''), + ) + ), + array( + 'query' => 'SELECT * FROM information_schema.CHARACTER_SETS', + 'columns' => array('CHARACTER_SET_NAME', 'DEFAULT_COLLATE_NAME', 'DESCRIPTION', 'MAXLEN'), + 'result' => array( + array('utf8', 'utf8_general_ci', 'UTF-8 Unicode', 3), + ) + ), + array( + 'query' => 'SELECT * FROM information_schema.COLLATIONS', + 'columns' => array( + 'COLLATION_NAME', 'CHARACTER_SET_NAME', 'ID', 'IS_DEFAULT', 'IS_COMPILED', 'SORTLEN' + ), + 'result' => array( + array('utf8_general_ci', 'utf8', 33, 'Yes', 'Yes', 1), + array('utf8_bin', 'utf8', 83, '', 'Yes', 1), + ) + ), + array( + 'query' => 'SELECT `TABLE_NAME` FROM `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=\'pma_test\' AND `TABLE_TYPE`=\'BASE TABLE\'', + 'result' => array(), + ), + array( + 'query' => 'SELECT upper(plugin_name) f FROM data_dictionary.plugins WHERE plugin_name IN (\'MYSQL_PASSWORD\',\'ROT13\') AND plugin_type = \'Function\' AND is_active', + 'columns' => array('f'), + 'result' => array(array('ROT13')), + ), + array( + 'query' => 'SELECT `column_name`, `mimetype`, `transformation`, `transformation_options` FROM `pmadb`.`column_info` WHERE `db_name` = \'pma_test\' AND `table_name` = \'table1\' AND ( `mimetype` != \'\' OR `transformation` != \'\' OR `transformation_options` != \'\')', + 'columns' => array('column_name', 'mimetype', 'transformation', 'transformation_options'), + 'result' => array( + array('o', 'text/plain', 'sql'), + ) + ), + array( + 'query' => 'SELECT TABLE_NAME FROM information_schema.VIEWS WHERE TABLE_SCHEMA = \'pma_test\' AND TABLE_NAME = \'table1\'', + 'result' => array(), + ), + array( + 'query' => 'SELECT *, `TABLE_SCHEMA` AS `Db`, `TABLE_NAME` AS `Name`, `TABLE_TYPE` AS `TABLE_TYPE`, `ENGINE` AS `Engine`, `ENGINE` AS `Type`, `VERSION` AS `Version`, `ROW_FORMAT` AS `Row_format`, `TABLE_ROWS` AS `Rows`, `AVG_ROW_LENGTH` AS `Avg_row_length`, `DATA_LENGTH` AS `Data_length`, `MAX_DATA_LENGTH` AS `Max_data_length`, `INDEX_LENGTH` AS `Index_length`, `DATA_FREE` AS `Data_free`, `AUTO_INCREMENT` AS `Auto_increment`, `CREATE_TIME` AS `Create_time`, `UPDATE_TIME` AS `Update_time`, `CHECK_TIME` AS `Check_time`, `TABLE_COLLATION` AS `Collation`, `CHECKSUM` AS `Checksum`, `CREATE_OPTIONS` AS `Create_options`, `TABLE_COMMENT` AS `Comment` FROM `information_schema`.`TABLES` t WHERE BINARY `TABLE_SCHEMA` IN (\'pma_test\') AND t.`TABLE_NAME` = \'table1\' ORDER BY Name ASC', + 'columns' => array('TABLE_CATALOG', 'TABLE_SCHEMA', 'TABLE_NAME', 'TABLE_TYPE', 'ENGINE', 'VERSION', 'ROW_FORMAT', 'TABLE_ROWS', 'AVG_ROW_LENGTH', 'DATA_LENGTH', 'MAX_DATA_LENGTH', 'INDEX_LENGTH', 'DATA_FREE', 'AUTO_INCREMENT', 'CREATE_TIME', 'UPDATE_TIME', 'CHECK_TIME', 'TABLE_COLLATION', 'CHECKSUM', 'CREATE_OPTIONS', 'TABLE_COMMENT', 'Db', 'Name', 'TABLE_TYPE', 'Engine', 'Type', 'Version', 'Row_format', 'Rows', 'Avg_row_length', 'Data_length', 'Max_data_length', 'Index_length', 'Data_free', 'Auto_increment', 'Create_time', 'Update_time', 'Check_time', 'Collation', 'Checksum', 'Create_options', 'Comment'), + 'result' => array( + array('def', 'smash', 'issues_issue', 'BASE TABLE', 'InnoDB', '10', 'Compact', '9136', '862', '7880704', '0', '1032192', '420478976', '155862', '2012-08-29 13:28:28', 'NULL', 'NULL', 'utf8_general_ci', 'NULL', '', '', 'smash', 'issues_issue', 'BASE TABLE', 'InnoDB', 'InnoDB', '10', 'Compact', '9136', '862', '7880704', '0', '1032192', '420478976', '155862', '2012-08-29 13:28:28', 'NULL', 'NULL', 'utf8_general_ci', 'NULL'), + ), + ), + array( + 'query' => 'SELECT *, `TABLE_SCHEMA` AS `Db`, `TABLE_NAME` AS `Name`, `TABLE_TYPE` AS `TABLE_TYPE`, `ENGINE` AS `Engine`, `ENGINE` AS `Type`, `VERSION` AS `Version`, `ROW_FORMAT` AS `Row_format`, `TABLE_ROWS` AS `Rows`, `AVG_ROW_LENGTH` AS `Avg_row_length`, `DATA_LENGTH` AS `Data_length`, `MAX_DATA_LENGTH` AS `Max_data_length`, `INDEX_LENGTH` AS `Index_length`, `DATA_FREE` AS `Data_free`, `AUTO_INCREMENT` AS `Auto_increment`, `CREATE_TIME` AS `Create_time`, `UPDATE_TIME` AS `Update_time`, `CHECK_TIME` AS `Check_time`, `TABLE_COLLATION` AS `Collation`, `CHECKSUM` AS `Checksum`, `CREATE_OPTIONS` AS `Create_options`, `TABLE_COMMENT` AS `Comment` FROM `information_schema`.`TABLES` t WHERE `TABLE_SCHEMA` IN (\'pma_test\') AND t.`TABLE_NAME` = \'table1\' ORDER BY Name ASC', + 'columns' => array('TABLE_CATALOG', 'TABLE_SCHEMA', 'TABLE_NAME', 'TABLE_TYPE', 'ENGINE', 'VERSION', 'ROW_FORMAT', 'TABLE_ROWS', 'AVG_ROW_LENGTH', 'DATA_LENGTH', 'MAX_DATA_LENGTH', 'INDEX_LENGTH', 'DATA_FREE', 'AUTO_INCREMENT', 'CREATE_TIME', 'UPDATE_TIME', 'CHECK_TIME', 'TABLE_COLLATION', 'CHECKSUM', 'CREATE_OPTIONS', 'TABLE_COMMENT', 'Db', 'Name', 'TABLE_TYPE', 'Engine', 'Type', 'Version', 'Row_format', 'Rows', 'Avg_row_length', 'Data_length', 'Max_data_length', 'Index_length', 'Data_free', 'Auto_increment', 'Create_time', 'Update_time', 'Check_time', 'Collation', 'Checksum', 'Create_options', 'Comment'), + 'result' => array( + array('def', 'smash', 'issues_issue', 'BASE TABLE', 'InnoDB', '10', 'Compact', '9136', '862', '7880704', '0', '1032192', '420478976', '155862', '2012-08-29 13:28:28', 'NULL', 'NULL', 'utf8_general_ci', 'NULL', '', '', 'smash', 'issues_issue', 'BASE TABLE', 'InnoDB', 'InnoDB', '10', 'Compact', '9136', '862', '7880704', '0', '1032192', '420478976', '155862', '2012-08-29 13:28:28', 'NULL', 'NULL', 'utf8_general_ci', 'NULL'), + ), + ), + array( + 'query' => 'SELECT COUNT(*) FROM `pma_test`.`table1`', + 'result' => array(array(0)), + ), + array( + 'query' => 'SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`USER_PRIVILEGES` WHERE GRANTEE=\'\'\'pma_test\'\'@\'\'localhost\'\'\' AND PRIVILEGE_TYPE=\'TRIGGER\'', + 'result' => array(), + ), + array( + 'query' => 'SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`SCHEMA_PRIVILEGES` WHERE GRANTEE=\'\'\'pma_test\'\'@\'\'localhost\'\'\' AND PRIVILEGE_TYPE=\'TRIGGER\' AND TABLE_SCHEMA=\'pma\\\\_test\'', + + 'result' => array(), + ), + array( + 'query' => 'SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`TABLE_PRIVILEGES` WHERE GRANTEE=\'\'\'pma_test\'\'@\'\'localhost\'\'\' AND PRIVILEGE_TYPE=\'TRIGGER\' AND TABLE_SCHEMA=\'pma\\\\_test\' AND TABLE_NAME=\'table1\'', + 'result' => array(), + ), + array( + 'query' => 'SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`USER_PRIVILEGES` WHERE GRANTEE=\'\'\'pma_test\'\'@\'\'localhost\'\'\' AND PRIVILEGE_TYPE=\'EVENT\'', + 'result' => array(), + ), + array( + 'query' => 'SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`SCHEMA_PRIVILEGES` WHERE GRANTEE=\'\'\'pma_test\'\'@\'\'localhost\'\'\' AND PRIVILEGE_TYPE=\'EVENT\' AND TABLE_SCHEMA=\'pma\\\\_test\'', + + 'result' => array(), + ), + array( + 'query' => 'SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`TABLE_PRIVILEGES` WHERE GRANTEE=\'\'\'pma_test\'\'@\'\'localhost\'\'\' AND PRIVILEGE_TYPE=\'EVENT\' AND TABLE_SCHEMA=\'pma\\\\_test\' AND TABLE_NAME=\'table1\'', + 'result' => array(), + ), + array( + 'query' => 'RENAME TABLE `pma_test`.`table1` TO `pma_test`.`table3`;', + 'result' => array(), + ), + array( + 'query' => 'SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION, EVENT_OBJECT_TABLE, ACTION_TIMING, ACTION_STATEMENT, EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE, DEFINER FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA= \'pma_test\' AND EVENT_OBJECT_TABLE = \'table1\';', + 'result' => array(), + ), + array( + 'query' => 'SHOW TABLES FROM `pma`;', + 'result' => array(), + ), + array( + 'query' => "SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`SCHEMA_PRIVILEGES` WHERE GRANTEE='''pma_test''@''localhost''' AND PRIVILEGE_TYPE='EVENT' AND TABLE_SCHEMA='pma'", + 'result' => array(), + ), + array( + 'query' => "SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`SCHEMA_PRIVILEGES` WHERE GRANTEE='''pma_test''@''localhost''' AND PRIVILEGE_TYPE='TRIGGER' AND TABLE_SCHEMA='pma'", + 'result' => array(), + ), + +); +/** + * Current database. + */ +$GLOBALS['dummy_db'] = ''; + +/* Some basic setup for dummy driver */ +$GLOBALS['userlink'] = 1; +$GLOBALS['controllink'] = 2; +$GLOBALS['cfg']['DBG']['sql'] = false; +if (! defined('PMA_DRIZZLE')) { + define('PMA_DRIZZLE', 0); +} + + +/** + * Run the multi query and output the results + * + * @param mysqli $link mysqli object + * @param string $query multi query statement to execute + * + * @return boolean false always false since mysql extention not support + * for multi query executions + */ +function PMA_DBI_real_multi_query($link, $query) +{ + return false; +} + +/** + * connects to the database server + * + * @param string $user mysql user name + * @param string $password mysql user password + * @param bool $is_controluser whether this is a control user connection + * @param array $server host/port/socket/persistent + * @param bool $auxiliary_connection (when true, don't go back to login if + * connection fails) + * + * @return mixed false on error or a mysqli object on success + */ +function PMA_DBI_connect( + $user, $password, $is_controluser = false, $server = null, + $auxiliary_connection = false +) { + return true; +} + +/** + * selects given database + * + * @param string $dbname name of db to select + * @param resource $link mysql link resource + * + * @return bool + */ +function PMA_DBI_select_db($dbname, $link = null) +{ + $GLOBALS['dummy_db'] = $dbname; + return true; +} + +/** + * runs a query and returns the result + * + * @param string $query query to run + * @param resource $link mysql link resource + * @param int $options query options + * + * @return mixed + */ +function PMA_DBI_real_query($query, $link = null, $options = 0) +{ + $query = trim(preg_replace('/ */', ' ', str_replace("\n", ' ', $query))); + for ($i = 0; $i < count($GLOBALS['dummy_queries']); $i++) { + if ($GLOBALS['dummy_queries'][$i]['query'] == $query) { + $GLOBALS['dummy_queries'][$i]['pos'] = 0; + if (is_array($GLOBALS['dummy_queries'][$i]['result'])) { + return $i; + } else { + return false; + } + } + } + echo "Not supported query: $query\n"; + return false; +} + +/** + * returns result data from $result + * + * @param resource $result result MySQL result + * + * @return array + */ +function PMA_DBI_fetch_any($result) +{ + $query_data = $GLOBALS['dummy_queries'][$result]; + if ($query_data['pos'] >= count($query_data['result'])) { + return false; + } + $ret = $query_data['result'][$query_data['pos']]; + $GLOBALS['dummy_queries'][$result]['pos'] += 1; + return $ret; +} + +/** + * returns array of rows with associative and numeric keys from $result + * + * @param resource $result result MySQL result + * + * @return array + */ +function PMA_DBI_fetch_array($result) +{ + $data = PMA_DBI_fetch_any($result); + if (is_array($data) && isset($GLOBALS['dummy_queries'][$result]['columns'])) { + foreach ($data as $key => $val) { + $data[$GLOBALS['dummy_queries'][$result]['columns'][$key]] = $val; + } + return $data; + } + return $data; +} + +/** + * returns array of rows with associative keys from $result + * + * @param resource $result MySQL result + * + * @return array + */ +function PMA_DBI_fetch_assoc($result) +{ + $data = PMA_DBI_fetch_any($result); + if (is_array($data) && isset($GLOBALS['dummy_queries'][$result]['columns'])) { + $ret = array(); + foreach ($data as $key => $val) { + $ret[$GLOBALS['dummy_queries'][$result]['columns'][$key]] = $val; + } + return $ret; + } + return $data; +} + +/** + * returns array of rows with numeric keys from $result + * + * @param resource $result MySQL result + * + * @return array + */ +function PMA_DBI_fetch_row($result) +{ + $data = PMA_DBI_fetch_any($result); + return $data; +} + +/** + * Adjusts the result pointer to an arbitrary row in the result + * + * @param resource $result database result + * @param integer $offset offset to seek + * + * @return bool true on success, false on failure + */ +function PMA_DBI_data_seek($result, $offset) +{ + if ($offset > count($GLOBALS['dummy_queries'][$result]['result'])) { + return false; + } + $GLOBALS['dummy_queries'][$result]['pos'] = $offset; + return true; +} + +/** + * Frees memory associated with the result + * + * @param resource $result database result + * + * @return void + */ +function PMA_DBI_free_result($result) +{ + return; +} + +/** + * Check if there are any more query results from a multi query + * + * @return bool false + */ +function PMA_DBI_more_results() +{ + return false; +} + +/** + * Prepare next result from multi_query + * + * @return boo false + */ +function PMA_DBI_next_result() +{ + return false; +} + +/** + * returns the number of rows returned by last query + * + * @param resource $result MySQL result + * + * @return string|int + */ +function PMA_DBI_num_rows($result) +{ + if (!is_bool($result)) { + return count($GLOBALS['dummy_queries'][$result]['result']); + } else { + return 0; + } +} + +/** + * returns the number of rows affected by last query + * + * @param resource $link the mysql object + * @param bool $get_from_cache whether to retrieve from cache + * + * @return string|int + */ +function PMA_DBI_affected_rows($link = null, $get_from_cache = true) +{ + return 0; +} + +/** + * return number of fields in given $result + * + * @param resource $result MySQL result + * + * @return int field count + */ +function PMA_DBI_num_fields($result) +{ + if (isset($GLOBALS['dummy_queries'][$result]['columns'])) { + return count($GLOBALS['dummy_queries'][$result]['columns']); + } else { + return 0; + } +} + +/** + * returns last error message or false if no errors occured + * + * @param resource $link mysql link + * + * @return string|bool $error or false + */ +function PMA_DBI_getError($link = null) +{ + return false; +} diff --git a/phpmyadmin/libraries/dbi/mysql.dbi.lib.php b/phpmyadmin/libraries/dbi/mysql.dbi.lib.php new file mode 100644 index 000000000..6a7e15df5 --- /dev/null +++ b/phpmyadmin/libraries/dbi/mysql.dbi.lib.php @@ -0,0 +1,552 @@ +authFails(); + } else { + return false; + } + } // end if + if (! $server) { + PMA_DBI_postConnect($link, $is_controluser); + } + return $link; +} + +/** + * selects given database + * + * @param string $dbname name of db to select + * @param resource $link mysql link resource + * + * @return bool + */ +function PMA_DBI_select_db($dbname, $link = null) +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + return mysql_select_db($dbname, $link); +} + +/** + * runs a query and returns the result + * + * @param string $query query to run + * @param resource $link mysql link resource + * @param int $options query options + * + * @return mixed + */ +function PMA_DBI_real_query($query, $link, $options) +{ + if ($options == ($options | PMA_DBI_QUERY_STORE)) { + return mysql_query($query, $link); + } elseif ($options == ($options | PMA_DBI_QUERY_UNBUFFERED)) { + return mysql_unbuffered_query($query, $link); + } else { + return mysql_query($query, $link); + } +} + +/** + * returns array of rows with associative and numeric keys from $result + * + * @param resource $result result MySQL result + * + * @return array + */ +function PMA_DBI_fetch_array($result) +{ + return mysql_fetch_array($result, MYSQL_BOTH); +} + +/** + * returns array of rows with associative keys from $result + * + * @param resource $result MySQL result + * + * @return array + */ +function PMA_DBI_fetch_assoc($result) +{ + return mysql_fetch_array($result, MYSQL_ASSOC); +} + +/** + * returns array of rows with numeric keys from $result + * + * @param resource $result MySQL result + * + * @return array + */ +function PMA_DBI_fetch_row($result) +{ + return mysql_fetch_array($result, MYSQL_NUM); +} + +/** + * Adjusts the result pointer to an arbitrary row in the result + * + * @param resource $result database result + * @param integer $offset offset to seek + * + * @return bool true on success, false on failure + */ +function PMA_DBI_data_seek($result, $offset) +{ + return mysql_data_seek($result, $offset); +} + +/** + * Frees memory associated with the result + * + * @param resource $result database result + * + * @return void + */ +function PMA_DBI_free_result($result) +{ + if (is_resource($result) && get_resource_type($result) === 'mysql result') { + mysql_free_result($result); + } +} + +/** + * Check if there are any more query results from a multi query + * + * @return bool false + */ +function PMA_DBI_more_results() +{ + // N.B.: PHP's 'mysql' extension does not support + // multi_queries so this function will always + // return false. Use the 'mysqli' extension, if + // you need support for multi_queries. + return false; +} + +/** + * Prepare next result from multi_query + * + * @return boo false + */ +function PMA_DBI_next_result() +{ + // N.B.: PHP's 'mysql' extension does not support + // multi_queries so this function will always + // return false. Use the 'mysqli' extension, if + // you need support for multi_queries. + return false; +} + +/** + * Returns a string representing the type of connection used + * + * @param resource $link mysql link + * + * @return string type of connection used + */ +function PMA_DBI_get_host_info($link = null) +{ + if (null === $link) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + return mysql_get_host_info($link); +} + +/** + * Returns the version of the MySQL protocol used + * + * @param resource $link mysql link + * + * @return int version of the MySQL protocol used + */ +function PMA_DBI_get_proto_info($link = null) +{ + if (null === $link) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + return mysql_get_proto_info($link); +} + +/** + * returns a string that represents the client library version + * + * @return string MySQL client library version + */ +function PMA_DBI_get_client_info() +{ + return mysql_get_client_info(); +} + +/** + * returns last error message or false if no errors occured + * + * @param resource $link mysql link + * + * @return string|bool $error or false + */ +function PMA_DBI_getError($link = null) +{ + $GLOBALS['errno'] = 0; + + /* Treat false same as null because of controllink */ + if ($link === false) { + $link = null; + } + + if (null === $link && isset($GLOBALS['userlink'])) { + $link =& $GLOBALS['userlink']; + + // Do not stop now. On the initial connection, we don't have a $link, + // we don't have a $GLOBALS['userlink'], but we can catch the error code + // } else { + // return false; + } + + if (null !== $link && false !== $link) { + $error_number = mysql_errno($link); + $error_message = mysql_error($link); + } else { + $error_number = mysql_errno(); + $error_message = mysql_error(); + } + if (0 == $error_number) { + return false; + } + + // keep the error number for further check after the call to PMA_DBI_getError() + $GLOBALS['errno'] = $error_number; + + return PMA_DBI_formatError($error_number, $error_message); +} + +/** + * returns the number of rows returned by last query + * + * @param resource $result MySQL result + * + * @return string|int + */ +function PMA_DBI_num_rows($result) +{ + if (!is_bool($result)) { + return mysql_num_rows($result); + } else { + return 0; + } +} + +/** + * returns last inserted auto_increment id for given $link or $GLOBALS['userlink'] + * + * @param resource $link the mysql object + * + * @return string|int + */ +function PMA_DBI_insert_id($link = null) +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + // If the primary key is BIGINT we get an incorrect result + // (sometimes negative, sometimes positive) + // and in the present function we don't know if the PK is BIGINT + // so better play safe and use LAST_INSERT_ID() + // + return PMA_DBI_fetch_value('SELECT LAST_INSERT_ID();', 0, 0, $link); +} + +/** + * returns the number of rows affected by last query + * + * @param resource $link the mysql object + * @param bool $get_from_cache whether to retrieve from cache + * + * @return string|int + */ +function PMA_DBI_affected_rows($link = null, $get_from_cache = true) +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + + if ($get_from_cache) { + return $GLOBALS['cached_affected_rows']; + } else { + return mysql_affected_rows($link); + } +} + +/** + * returns metainfo for fields in $result + * + * @param resource $result MySQL result + * + * @return array meta info for fields in $result + * + * @todo add missing keys like in mysqli_query (decimals) + */ +function PMA_DBI_get_fields_meta($result) +{ + $fields = array(); + $num_fields = mysql_num_fields($result); + for ($i = 0; $i < $num_fields; $i++) { + $field = mysql_fetch_field($result, $i); + $field->flags = mysql_field_flags($result, $i); + $field->orgtable = mysql_field_table($result, $i); + $field->orgname = mysql_field_name($result, $i); + $fields[] = $field; + } + return $fields; +} + +/** + * return number of fields in given $result + * + * @param resource $result MySQL result + * + * @return int field count + */ +function PMA_DBI_num_fields($result) +{ + return mysql_num_fields($result); +} + +/** + * returns the length of the given field $i in $result + * + * @param resource $result MySQL result + * @param int $i field + * + * @return int length of field + */ +function PMA_DBI_field_len($result, $i) +{ + return mysql_field_len($result, $i); +} + +/** + * returns name of $i. field in $result + * + * @param resource $result MySQL result + * @param int $i field + * + * @return string name of $i. field in $result + */ +function PMA_DBI_field_name($result, $i) +{ + return mysql_field_name($result, $i); +} + +/** + * returns concatenated string of human readable field flags + * + * @param resource $result MySQL result + * @param int $i field + * + * @return string field flags + */ +function PMA_DBI_field_flags($result, $i) +{ + return mysql_field_flags($result, $i); +} + +/** + * Store the result returned from multi query + * + * @return false + */ +function PMA_DBI_store_result() +{ + return false; +} +?> diff --git a/phpmyadmin/libraries/dbi/mysqli.dbi.lib.php b/phpmyadmin/libraries/dbi/mysqli.dbi.lib.php new file mode 100644 index 000000000..bf485212d --- /dev/null +++ b/phpmyadmin/libraries/dbi/mysqli.dbi.lib.php @@ -0,0 +1,748 @@ += 50300) { + if ($cfg['PersistentConnections'] || $persistent) { + $host = 'p:' . $host; + } + } + if ($client_flags === null) { + return @mysqli_real_connect( + $link, + $host, + $user, + $password, + $dbname, + $server_port, + $server_socket + ); + } else { + return @mysqli_real_connect( + $link, + $host, + $user, + $password, + $dbname, + $server_port, + $server_socket, + $client_flags + ); + } +} + +/** + * connects to the database server + * + * @param string $user mysql user name + * @param string $password mysql user password + * @param bool $is_controluser whether this is a control user connection + * @param array $server host/port/socket/persistent + * @param bool $auxiliary_connection (when true, don't go back to login if + * connection fails) + * + * @return mixed false on error or a mysqli object on success + */ +function PMA_DBI_connect( + $user, $password, $is_controluser = false, $server = null, + $auxiliary_connection = false +) { + global $cfg; + + if ($server) { + $server_port = (empty($server['port'])) + ? false + : (int)$server['port']; + $server_socket = (empty($server['socket'])) + ? '' + : $server['socket']; + $server['host'] = (empty($server['host'])) + ? 'localhost' + : $server['host']; + } else { + $server_port = (empty($cfg['Server']['port'])) + ? false + : (int) $cfg['Server']['port']; + $server_socket = (empty($cfg['Server']['socket'])) + ? null + : $cfg['Server']['socket']; + } + + // NULL enables connection to the default socket + + $link = mysqli_init(); + + mysqli_options($link, MYSQLI_OPT_LOCAL_INFILE, true); + + $client_flags = 0; + + /* Optionally compress connection */ + if ($cfg['Server']['compress'] && defined('MYSQLI_CLIENT_COMPRESS')) { + $client_flags |= MYSQLI_CLIENT_COMPRESS; + } + + /* Optionally enable SSL */ + if ($cfg['Server']['ssl'] && defined('MYSQLI_CLIENT_SSL')) { + $client_flags |= MYSQLI_CLIENT_SSL; + } + + if (!$server) { + $return_value = @PMA_DBI_real_connect( + $link, + $cfg['Server']['host'], + $user, + $password, + false, + $server_port, + $server_socket, + $client_flags + ); + // Retry with empty password if we're allowed to + if ($return_value == false + && isset($cfg['Server']['nopassword']) && $cfg['Server']['nopassword'] + && !$is_controluser + ) { + $return_value = @PMA_DBI_real_connect( + $link, + $cfg['Server']['host'], + $user, + '', + false, + $server_port, + $server_socket, + $client_flags + ); + } + } else { + $return_value = @PMA_DBI_real_connect( + $link, + $server['host'], + $user, + $password, + false, + $server_port, + $server_socket + ); + } + + if ($return_value == false) { + if ($is_controluser) { + trigger_error( + __('Connection for controluser as defined in your configuration failed.'), + E_USER_WARNING + ); + return false; + } + // we could be calling PMA_DBI_connect() to connect to another + // server, for example in the Synchronize feature, so do not + // go back to main login if it fails + if (! $auxiliary_connection) { + PMA_log_user($user, 'mysql-denied'); + global $auth_plugin; + $auth_plugin->authFails(); + } else { + return false; + } + } else { + PMA_DBI_postConnect($link, $is_controluser); + } + + return $link; +} + +/** + * selects given database + * + * @param string $dbname database name to select + * @param mysqli $link the mysqli object + * + * @return boolean + */ +function PMA_DBI_select_db($dbname, $link = null) +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + return mysqli_select_db($link, $dbname); +} + +/** + * runs a query and returns the result + * + * @param string $query query to execute + * @param mysqli $link mysqli object + * @param int $options query options + * + * @return mysqli_result|bool + */ +function PMA_DBI_real_query($query, $link, $options) +{ + if ($options == ($options | PMA_DBI_QUERY_STORE)) { + $method = MYSQLI_STORE_RESULT; + } elseif ($options == ($options | PMA_DBI_QUERY_UNBUFFERED)) { + $method = MYSQLI_USE_RESULT; + } else { + $method = 0; + } + + return mysqli_query($link, $query, $method); +} + +/** + * Run the multi query and output the results + * + * @param mysqli $link mysqli object + * @param string $query multi query statement to execute + * + * @return mysqli_result collection | boolean(false) + */ +function PMA_DBI_real_multi_query($link, $query) +{ + return mysqli_multi_query($link, $query); +} + +/** + * returns array of rows with associative and numeric keys from $result + * + * @param mysqli_result $result result set identifier + * + * @return array + */ +function PMA_DBI_fetch_array($result) +{ + return mysqli_fetch_array($result, MYSQLI_BOTH); +} + +/** + * returns array of rows with associative keys from $result + * + * @param mysqli_result $result result set identifier + * + * @return array + */ +function PMA_DBI_fetch_assoc($result) +{ + return mysqli_fetch_array($result, MYSQLI_ASSOC); +} + +/** + * returns array of rows with numeric keys from $result + * + * @param mysqli_result $result result set identifier + * + * @return array + */ +function PMA_DBI_fetch_row($result) +{ + return mysqli_fetch_array($result, MYSQLI_NUM); +} + +/** + * Adjusts the result pointer to an arbitrary row in the result + * + * @param resource $result database result + * @param integer $offset offset to seek + * + * @return bool true on success, false on failure + */ +function PMA_DBI_data_seek($result, $offset) +{ + return mysqli_data_seek($result, $offset); +} + +/** + * Frees memory associated with the result + * + * @param mysqli_result $result database result + * + * @return void + */ +function PMA_DBI_free_result($result) +{ + if ($result instanceof mysqli_result) { + mysqli_free_result($result); + } +} + +/** + * Check if there are any more query results from a multi query + * + * @param mysqli $link the mysqli object + * + * @return bool true or false + */ +function PMA_DBI_more_results($link = null) +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + return mysqli_more_results($link); +} + +/** + * Prepare next result from multi_query + * + * @param mysqli $link the mysqli object + * + * @return bool true or false + */ +function PMA_DBI_next_result($link = null) +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + return mysqli_next_result($link); +} + +/** + * Store the result returned from multi query + * + * @return mixed false when empty results / result set when not empty + */ +function PMA_DBI_store_result() +{ + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + return mysqli_store_result($link); +} + +/** + * Returns a string representing the type of connection used + * + * @param resource $link mysql link + * + * @return string type of connection used + */ +function PMA_DBI_get_host_info($link = null) +{ + if (null === $link) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + return mysqli_get_host_info($link); +} + +/** + * Returns the version of the MySQL protocol used + * + * @param resource $link mysql link + * + * @return integer version of the MySQL protocol used + */ +function PMA_DBI_get_proto_info($link = null) +{ + if (null === $link) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + return mysqli_get_proto_info($link); +} + +/** + * returns a string that represents the client library version + * + * @return string MySQL client library version + */ +function PMA_DBI_get_client_info() +{ + return mysqli_get_client_info(); +} + +/** + * returns last error message or false if no errors occured + * + * @param resource $link mysql link + * + * @return string|bool $error or false + */ +function PMA_DBI_getError($link = null) +{ + $GLOBALS['errno'] = 0; + + /* Treat false same as null because of controllink */ + if ($link === false) { + $link = null; + } + + if (null === $link && isset($GLOBALS['userlink'])) { + $link =& $GLOBALS['userlink']; + // Do not stop now. We still can get the error code + // with mysqli_connect_errno() + } + + if (null !== $link) { + $error_number = mysqli_errno($link); + $error_message = mysqli_error($link); + } else { + $error_number = mysqli_connect_errno(); + $error_message = mysqli_connect_error(); + } + if (0 == $error_number) { + return false; + } + + // keep the error number for further check after the call to PMA_DBI_getError() + $GLOBALS['errno'] = $error_number; + + return PMA_DBI_formatError($error_number, $error_message); +} + +/** + * returns the number of rows returned by last query + * + * @param mysqli_result $result result set identifier + * + * @return string|int + */ +function PMA_DBI_num_rows($result) +{ + // see the note for PMA_DBI_try_query(); + if (!is_bool($result)) { + return @mysqli_num_rows($result); + } else { + return 0; + } +} + +/** + * returns last inserted auto_increment id for given $link or $GLOBALS['userlink'] + * + * @param mysqli $link the mysqli object + * + * @return string|int + */ +function PMA_DBI_insert_id($link = null) +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + // When no controluser is defined, using mysqli_insert_id($link) + // does not always return the last insert id due to a mixup with + // the tracking mechanism, but this works: + return PMA_DBI_fetch_value('SELECT LAST_INSERT_ID();', 0, 0, $link); + // Curiously, this problem does not happen with the mysql extension but + // there is another problem with BIGINT primary keys so PMA_DBI_insert_id() + // in the mysql extension also uses this logic. +} + +/** + * returns the number of rows affected by last query + * + * @param mysqli $link the mysqli object + * @param bool $get_from_cache whether to retrieve from cache + * + * @return string|int + */ +function PMA_DBI_affected_rows($link = null, $get_from_cache = true) +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + if ($get_from_cache) { + return $GLOBALS['cached_affected_rows']; + } else { + return mysqli_affected_rows($link); + } +} + +/** + * returns metainfo for fields in $result + * + * @param mysqli_result $result result set identifier + * + * @return array meta info for fields in $result + */ +function PMA_DBI_get_fields_meta($result) +{ + // Build an associative array for a type look up + $typeAr = array(); + $typeAr[MYSQLI_TYPE_DECIMAL] = 'real'; + $typeAr[MYSQLI_TYPE_NEWDECIMAL] = 'real'; + $typeAr[MYSQLI_TYPE_BIT] = 'int'; + $typeAr[MYSQLI_TYPE_TINY] = 'int'; + $typeAr[MYSQLI_TYPE_SHORT] = 'int'; + $typeAr[MYSQLI_TYPE_LONG] = 'int'; + $typeAr[MYSQLI_TYPE_FLOAT] = 'real'; + $typeAr[MYSQLI_TYPE_DOUBLE] = 'real'; + $typeAr[MYSQLI_TYPE_NULL] = 'null'; + $typeAr[MYSQLI_TYPE_TIMESTAMP] = 'timestamp'; + $typeAr[MYSQLI_TYPE_LONGLONG] = 'int'; + $typeAr[MYSQLI_TYPE_INT24] = 'int'; + $typeAr[MYSQLI_TYPE_DATE] = 'date'; + $typeAr[MYSQLI_TYPE_TIME] = 'time'; + $typeAr[MYSQLI_TYPE_DATETIME] = 'datetime'; + $typeAr[MYSQLI_TYPE_YEAR] = 'year'; + $typeAr[MYSQLI_TYPE_NEWDATE] = 'date'; + $typeAr[MYSQLI_TYPE_ENUM] = 'unknown'; + $typeAr[MYSQLI_TYPE_SET] = 'unknown'; + $typeAr[MYSQLI_TYPE_TINY_BLOB] = 'blob'; + $typeAr[MYSQLI_TYPE_MEDIUM_BLOB] = 'blob'; + $typeAr[MYSQLI_TYPE_LONG_BLOB] = 'blob'; + $typeAr[MYSQLI_TYPE_BLOB] = 'blob'; + $typeAr[MYSQLI_TYPE_VAR_STRING] = 'string'; + $typeAr[MYSQLI_TYPE_STRING] = 'string'; + $typeAr[MYSQLI_TYPE_VARCHAR] = 'string'; // for Drizzle + // MySQL returns MYSQLI_TYPE_STRING for CHAR + // and MYSQLI_TYPE_CHAR === MYSQLI_TYPE_TINY + // so this would override TINYINT and mark all TINYINT as string + // https://sourceforge.net/p/phpmyadmin/bugs/2205/ + //$typeAr[MYSQLI_TYPE_CHAR] = 'string'; + $typeAr[MYSQLI_TYPE_GEOMETRY] = 'geometry'; + $typeAr[MYSQLI_TYPE_BIT] = 'bit'; + + $fields = mysqli_fetch_fields($result); + + // this happens sometimes (seen under MySQL 4.0.25) + if (!is_array($fields)) { + return false; + } + + foreach ($fields as $k => $field) { + $fields[$k]->_type = $field->type; + $fields[$k]->type = $typeAr[$field->type]; + $fields[$k]->_flags = $field->flags; + $fields[$k]->flags = PMA_DBI_field_flags($result, $k); + + // Enhance the field objects for mysql-extension compatibilty + //$flags = explode(' ', $fields[$k]->flags); + //array_unshift($flags, 'dummy'); + $fields[$k]->multiple_key + = (int) (bool) ($fields[$k]->_flags & MYSQLI_MULTIPLE_KEY_FLAG); + $fields[$k]->primary_key + = (int) (bool) ($fields[$k]->_flags & MYSQLI_PRI_KEY_FLAG); + $fields[$k]->unique_key + = (int) (bool) ($fields[$k]->_flags & MYSQLI_UNIQUE_KEY_FLAG); + $fields[$k]->not_null + = (int) (bool) ($fields[$k]->_flags & MYSQLI_NOT_NULL_FLAG); + $fields[$k]->unsigned + = (int) (bool) ($fields[$k]->_flags & MYSQLI_UNSIGNED_FLAG); + $fields[$k]->zerofill + = (int) (bool) ($fields[$k]->_flags & MYSQLI_ZEROFILL_FLAG); + $fields[$k]->numeric + = (int) (bool) ($fields[$k]->_flags & MYSQLI_NUM_FLAG); + $fields[$k]->blob + = (int) (bool) ($fields[$k]->_flags & MYSQLI_BLOB_FLAG); + } + return $fields; +} + +/** + * return number of fields in given $result + * + * @param mysqli_result $result result set identifier + * + * @return int field count + */ +function PMA_DBI_num_fields($result) +{ + return mysqli_num_fields($result); +} + +/** + * returns the length of the given field $i in $result + * + * @param mysqli_result $result result set identifier + * @param int $i field + * + * @return int length of field + */ +function PMA_DBI_field_len($result, $i) +{ + return mysqli_fetch_field_direct($result, $i)->length; +} + +/** + * returns name of $i. field in $result + * + * @param mysqli_result $result result set identifier + * @param int $i field + * + * @return string name of $i. field in $result + */ +function PMA_DBI_field_name($result, $i) +{ + return mysqli_fetch_field_direct($result, $i)->name; +} + +/** + * returns concatenated string of human readable field flags + * + * @param mysqli_result $result result set identifier + * @param int $i field + * + * @return string field flags + */ +function PMA_DBI_field_flags($result, $i) +{ + // This is missing from PHP 5.2.5, see http://bugs.php.net/bug.php?id=44846 + if (! defined('MYSQLI_ENUM_FLAG')) { + define('MYSQLI_ENUM_FLAG', 256); // see MySQL source include/mysql_com.h + } + $f = mysqli_fetch_field_direct($result, $i); + $type = $f->type; + $charsetnr = $f->charsetnr; + $f = $f->flags; + $flags = ''; + if ($f & MYSQLI_UNIQUE_KEY_FLAG) { + $flags .= 'unique '; + } + if ($f & MYSQLI_NUM_FLAG) { + $flags .= 'num '; + } + if ($f & MYSQLI_PART_KEY_FLAG) { + $flags .= 'part_key '; + } + if ($f & MYSQLI_SET_FLAG) { + $flags .= 'set '; + } + if ($f & MYSQLI_TIMESTAMP_FLAG) { + $flags .= 'timestamp '; + } + if ($f & MYSQLI_AUTO_INCREMENT_FLAG) { + $flags .= 'auto_increment '; + } + if ($f & MYSQLI_ENUM_FLAG) { + $flags .= 'enum '; + } + // See http://dev.mysql.com/doc/refman/6.0/en/c-api-datatypes.html: + // to determine if a string is binary, we should not use MYSQLI_BINARY_FLAG + // but instead the charsetnr member of the MYSQL_FIELD + // structure. Watch out: some types like DATE returns 63 in charsetnr + // so we have to check also the type. + // Unfortunately there is no equivalent in the mysql extension. + if (($type == MYSQLI_TYPE_TINY_BLOB || $type == MYSQLI_TYPE_BLOB + || $type == MYSQLI_TYPE_MEDIUM_BLOB || $type == MYSQLI_TYPE_LONG_BLOB + || $type == MYSQLI_TYPE_VAR_STRING || $type == MYSQLI_TYPE_STRING) + && 63 == $charsetnr + ) { + $flags .= 'binary '; + } + if ($f & MYSQLI_ZEROFILL_FLAG) { + $flags .= 'zerofill '; + } + if ($f & MYSQLI_UNSIGNED_FLAG) { + $flags .= 'unsigned '; + } + if ($f & MYSQLI_BLOB_FLAG) { + $flags .= 'blob '; + } + if ($f & MYSQLI_MULTIPLE_KEY_FLAG) { + $flags .= 'multiple_key '; + } + if ($f & MYSQLI_UNIQUE_KEY_FLAG) { + $flags .= 'unique_key '; + } + if ($f & MYSQLI_PRI_KEY_FLAG) { + $flags .= 'primary_key '; + } + if ($f & MYSQLI_NOT_NULL_FLAG) { + $flags .= 'not_null '; + } + return trim($flags); +} + +?> diff --git a/phpmyadmin/libraries/display_change_password.lib.php b/phpmyadmin/libraries/display_change_password.lib.php new file mode 100644 index 000000000..ba5b012e2 --- /dev/null +++ b/phpmyadmin/libraries/display_change_password.lib.php @@ -0,0 +1,98 @@ += 5 + && PMA_USR_BROWSER_VER < 7) + ? 'onpropertychange' + : 'onchange'; + + $html = '
      '; + + $html .= PMA_generate_common_hidden_inputs(); + + if (strpos($GLOBALS['PMA_PHP_SELF'], 'server_privileges') !== false) { + $html .= '' + . ''; + } + $html .= '
      ' + . '' . __('Change password') . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '
      ' + . '' + . '' + . '
      ' + . '' + . '' + . '' + . '' + . '  ' . __('Re-type') . ': ' + . '' + . '
      ' . __('Password Hashing') . ':' + . '' + . '' + . '' + . '
       ' + . '' + . '' + . '
      ' + . '
      ' + . '' + . '
      '; + return $html; +} diff --git a/phpmyadmin/libraries/display_create_database.lib.php b/phpmyadmin/libraries/display_create_database.lib.php new file mode 100644 index 000000000..228477c1f --- /dev/null +++ b/phpmyadmin/libraries/display_create_database.lib.php @@ -0,0 +1,49 @@ + +
      + ' + . PMA_Util::getImage('b_newdb.png') + . " " . __('Create database') + . ' ' + . PMA_Util::showMySQLDocu('SQL-Syntax', 'CREATE_DATABASE'); ?>
      + + + + '; + } + ?> + +
      + + +
      + ' + . PMA_Util::getImage('s_error2.png', '', array('hspace' => 2, 'border' => 0, 'align' => 'middle')) + . '' . __('No Privileges') .''; +} // end create db form or message +?> diff --git a/phpmyadmin/libraries/display_create_table.lib.php b/phpmyadmin/libraries/display_create_table.lib.php new file mode 100644 index 000000000..eb803cc44 --- /dev/null +++ b/phpmyadmin/libraries/display_create_table.lib.php @@ -0,0 +1,63 @@ += 4.1.0, we should be able to detect if user has a CREATE + * privilege by looking at SHOW GRANTS output; + * for < 4.1.0, it could be more difficult because the logic tries to + * detect the current host and it might be expressed in many ways; also + * on a shared server, the user might be unable to define a controluser + * that has the proper rights to the "mysql" db; + * so we give up and assume that user has the right to create a table + * + * Note: in this case we could even skip the following "foreach" logic + * + * Addendum, 2006-01-19: ok, I give up. We got some reports about servers + * where the hostname field in mysql.user is not the same as the one + * in mysql.db for a user. In this case, SHOW GRANTS does not return + * the db-specific privileges. And probably, those users are on a shared + * server, so can't set up a control user with rights to the "mysql" db. + * We cannot reliably detect the db-specific privileges, so no more + * warnings about the lack of privileges for CREATE TABLE. Tested + * on MySQL 5.0.18. + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/** + * + */ +require_once './libraries/check_user_privileges.lib.php'; + +$is_create_table_priv = true; + +?> +
      +
      + + + + +
      + : + +
      +
      + : + +
      +
      +
      +
      + +
      +
      diff --git a/phpmyadmin/libraries/display_export.lib.php b/phpmyadmin/libraries/display_export.lib.php new file mode 100644 index 000000000..9e162a05e --- /dev/null +++ b/phpmyadmin/libraries/display_export.lib.php @@ -0,0 +1,443 @@ + $export_type, + 'single_table' => isset($single_table) + ) +); + +/* Fail if we didn't find any plugin */ +if (empty($export_list)) { + PMA_Message::error( + __('Could not load export plugins, please check your installation!') + )->display(); + exit; +} + +echo '
      '; + +if ($export_type == 'server') { + echo PMA_generate_common_hidden_inputs('', '', 1); +} elseif ($export_type == 'database') { + echo PMA_generate_common_hidden_inputs($db, '', 1); +} else { + echo PMA_generate_common_hidden_inputs($db, $table, 1); +} + +// just to keep this value for possible next display of this form after saving +// on server +if (isset($single_table)) { + echo '' . "\n"; +} + +echo ''; +echo "\n"; + +// If the export method was not set, the default is quick +if (isset($_GET['export_method'])) { + $cfg['Export']['method'] = $_GET['export_method']; +} elseif (! isset($cfg['Export']['method'])) { + $cfg['Export']['method'] = 'quick'; +} +// The export method (quick, custom or custom-no-form) +echo ''; + + +if (isset($_GET['sql_query'])) { + echo '' . "\n"; +} elseif (! empty($sql_query)) { + echo '' . "\n"; +} + +echo ''; + +if (isset($_GET['quick_or_custom'])) { + $export_method = $_GET['quick_or_custom']; +} else { + $export_method = $cfg['Export']['method']; +} + +echo '
      '; +echo '

      ' . __('Export Method:') . '

      '; +echo '
        '; +echo '
      • '; +echo ''; +echo ''; +echo '
      • '; + +echo '
      • '; +echo ''; +echo ''; +echo '
      • '; + +echo '
      '; +echo '
      '; + +echo '
      '; +if ($export_type == 'server') { + echo '

      ' . __('Database(s):') . '

      '; +} else if ($export_type == 'database') { + echo '

      ' . __('Table(s):') . '

      '; +} +if (! empty($multi_values)) { + echo $multi_values; +} +echo '
      '; + +if (strlen($table) && ! isset($num_tables) && ! PMA_Table::isMerge($db, $table)) { + echo '
      '; + echo '

      ' . __('Rows:') . '

      '; + echo '
        '; + echo '
      • '; + echo ''; + echo ''; + echo '
          '; + echo '
        • '; + echo ''; + echo ''; + echo '
        • '; + echo '
        • '; + echo ''; + echo ''; + echo '
        • '; + echo '
        '; + echo '
      • '; + echo '
      • '; + echo ''; + echo ' '; + echo '
      • '; + echo '
      '; + echo '
      '; +} + +if (isset($cfg['SaveDir']) && !empty($cfg['SaveDir'])) { + echo '
      '; + echo '

      ' . __('Output:') . '

      '; + echo '
        '; + echo '
      • '; + echo ''; + echo ''; + echo '
      • '; + echo '
      • '; + echo ''; + echo ''; + echo '
      • '; + echo '
      '; + echo '
      '; +} + +echo '
      '; +echo '

      ' . __('Output:') . '

      '; +echo '
        '; +echo '
      • '; +echo ''; +echo ''; +echo '
          '; +if (isset($cfg['SaveDir']) && !empty($cfg['SaveDir'])) { + echo '
        • '; + echo ''; + echo ''; + echo '
        • '; + echo '
        • '; + echo ''; + echo ''; + echo '
        • '; +} +echo '
        • '; +echo ''; +echo ''; +echo ''; +echo ''; +echo '
        • '; +// charset of file +if ($GLOBALS['PMA_recoding_engine'] != PMA_CHARSET_NONE) { + echo '
        • ' . "\n"; + reset($cfg['AvailableCharsets']); + echo '
        • '; +} // end if + +if (isset($_GET['compression'])) { + $selected_compression = $_GET['compression']; +} elseif (isset($cfg['Export']['compression'])) { + $selected_compression = $cfg['Export']['compression']; +} else { + $selected_compression = "none"; +} + +// zip, gzip and bzip2 encode features +$is_zip = ($cfg['ZipDump'] && @function_exists('gzcompress')); +$is_gzip = ($cfg['GZipDump'] && @function_exists('gzencode')); +$is_bzip2 = ($cfg['BZipDump'] && @function_exists('bzcompress')); +if ($is_zip || $is_gzip || $is_bzip2) { + echo '
        • '; + echo ''; + echo ''; + echo '
        • '; +} else { + echo ''; +} +echo '
        '; +echo '
      • '; +echo '
      • '; +echo ''; +echo '
      • '; +echo '
      '; +echo '
      '; + +echo '
      '; +echo '

      ' . __('Format:') . '

      '; +echo PMA_pluginGetChoice('Export', 'what', $export_list, 'format'); +echo '
      '; + +echo '
      '; +echo '

      ' . __('Format-specific options:') . '

      '; +echo '

      '; +echo __('Scroll down to fill in the options for the selected format and ignore the options for other formats.'); +echo '

      '; +echo PMA_pluginGetOptions('Export', $export_list); +echo '
      '; + +if (function_exists('PMA_set_enc_form')) { + // Encoding setting form appended by Y.Kawada + // Japanese encoding setting + echo '
      '; + echo '

      ' . __('Encoding Conversion:') . '

      '; + echo PMA_set_enc_form(' '); + echo '
      '; +} + +echo '
      '; + +echo PMA_Util::getExternalBug( + __('SQL compatibility mode'), 'mysql', '50027', '14515' +); + +echo ''; +echo '
      '; +echo '
      '; diff --git a/phpmyadmin/libraries/display_git_revision.lib.php b/phpmyadmin/libraries/display_git_revision.lib.php new file mode 100644 index 000000000..939c84f3f --- /dev/null +++ b/phpmyadmin/libraries/display_git_revision.lib.php @@ -0,0 +1,83 @@ +get('PMA_VERSION_GIT')) { + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + return; + } + + // load revision data from repo + $GLOBALS['PMA_Config']->checkGitRevision(); + + // if using a remote commit fast-forwarded, link to Github + $commit_hash = substr( + $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_COMMITHASH'), + 0, + 7 + ); + $commit_hash = '' . $commit_hash . ''; + if ($GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_ISREMOTECOMMIT')) { + $commit_hash = '' . $commit_hash . ''; + } + + $branch = $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_BRANCH'); + if ($GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_ISREMOTEBRANCH')) { + $branch = '' . $branch . ''; + } + if ($branch !== false) { + $branch = sprintf(__('%1$s from %2$s branch'), $commit_hash, $branch); + } else { + $branch = $commit_hash . ' (' . __('no branch') . ')'; + } + + $committer = $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_COMMITTER'); + $author = $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_AUTHOR'); + PMA_printListItem( + __('Git revision') . ': ' + . $branch . ',
      ' + . sprintf( + __('committed on %1$s by %2$s'), + PMA_Util::localisedDate(strtotime($committer['date'])), + '' + . htmlspecialchars($committer['name']) . '' + ) + . ($author != $committer + ? ',
      ' + . sprintf( + __('authored on %1$s by %2$s'), + PMA_Util::localisedDate(strtotime($author['date'])), + '' + . htmlspecialchars($author['name']) . '' + ) + : ''), + 'li_pma_version_git', null, null, null + ); +} diff --git a/phpmyadmin/libraries/display_import.lib.php b/phpmyadmin/libraries/display_import.lib.php new file mode 100644 index 000000000..79149d166 --- /dev/null +++ b/phpmyadmin/libraries/display_import.lib.php @@ -0,0 +1,338 @@ +display(); + exit; +} +?> + + + +
      + ajax clock + +
      > + + + '."\n"; + ?> + + + +
      +

      + '; + printf(__('File may be compressed (%s) or uncompressed.'), implode(", ", $compressions)); + echo '
      '; + echo __('A compressed file\'s name must end in .[format].[compression]. Example: .sql.zip'); + echo '
      '; +}?> + +
      + +
        +
      • + + +
      • +
      • + + +
      • +
      + display(); +} elseif (!empty($cfg['UploadDir'])) { + echo PMA_Util::getSelectUploadFileBlock($import_list, $cfg['UploadDir']); +} // end if (web-server upload directory) +?> +
      + +
      + ' . __('Character set of the file:') . ''; + reset($cfg['AvailableCharsets']); + echo '
      '; +} else { + echo '' . "\n"; + echo PMA_generateCharsetDropdownBox(PMA_CSDROPDOWN_CHARSET, 'charset_of_file', 'charset_of_file', 'utf8', false); +} // end if (recoding) + ?> +
      +
      +
      +

      + + ' . "\n"; + echo ''; + echo sprintf(__('Previous import timed out, after resubmitting will continue from position %d.'), $offset) . ''; + echo '
      ' . "\n"; +} + ?> +
      + /> +
      +
      + + +
      + + +
      + + + +
      + +
      +

      + +
      +
      + +
      +

      +

      Scroll down to fill in the options for the selected format and ignore the options for other formats.

      + +
      +
      + +
      +

      + +
      + +
      + +
      + +
      diff --git a/phpmyadmin/libraries/display_import_ajax.lib.php b/phpmyadmin/libraries/display_import_ajax.lib.php new file mode 100644 index 000000000..f8e917343 --- /dev/null +++ b/phpmyadmin/libraries/display_import_ajax.lib.php @@ -0,0 +1,132 @@ + diff --git a/phpmyadmin/libraries/display_select_lang.lib.php b/phpmyadmin/libraries/display_select_lang.lib.php new file mode 100644 index 000000000..41a9098d2 --- /dev/null +++ b/phpmyadmin/libraries/display_select_lang.lib.php @@ -0,0 +1,98 @@ + 1) { + $retval .= '
      '; + + $_form_params = array( + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], + ); + $retval .= PMA_generate_common_hidden_inputs($_form_params); + + // For non-English, display "Language" with emphasis because it's + // not a proper word in the current language; we show it to help + // people recognize the dialog + $language_title = __('Language') + . (__('Language') != 'Language' ? ' - Language' : ''); + if ($show_doc) { + $language_title .= PMA_Util::showDocu('faq', 'faq7-2'); + } + if ($use_fieldset) { + $retval .= '
      ' + . $language_title . ''; + } else { + $retval .= ''; + } + + $retval .= ''; + + if ($use_fieldset) { + $retval .= '
      '; + } + + $retval .= '
      '; + } + return $retval; +} + +?> diff --git a/phpmyadmin/libraries/engines/bdb.lib.php b/phpmyadmin/libraries/engines/bdb.lib.php new file mode 100644 index 000000000..91a56bb57 --- /dev/null +++ b/phpmyadmin/libraries/engines/bdb.lib.php @@ -0,0 +1,84 @@ + array( + 'title' => __('Version information'), + ), + 'bdb_cache_size' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + 'bdb_home' => array( + ), + 'bdb_log_buffer_size' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + 'bdb_logdir' => array( + ), + 'bdb_max_lock' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + 'bdb_shared_data' => array( + ), + 'bdb_tmpdir' => array( + ), + 'bdb_data_direct' => array( + ), + 'bdb_lock_detect' => array( + ), + 'bdb_log_direct' => array( + ), + 'bdb_no_recover' => array( + ), + 'bdb_no_sync' => array( + ), + 'skip_sync_bdb_logs' => array( + ), + 'sync_bdb_logs' => array( + ), + ); + } + + /** + * Returns the pattern to be used in the query for SQL variables + * related to this storage engine + * + * @return string LIKE pattern + */ + function getVariablesLikePattern() + { + return '%bdb%'; + } + + /** + * returns string with filename for the MySQL helppage + * about this storage engine + * + * @return string mysql helppage filename + */ + function getMysqlHelpPage() + { + return 'bdb'; + } +} + +?> diff --git a/phpmyadmin/libraries/engines/berkeleydb.lib.php b/phpmyadmin/libraries/engines/berkeleydb.lib.php new file mode 100644 index 000000000..d5324b1ac --- /dev/null +++ b/phpmyadmin/libraries/engines/berkeleydb.lib.php @@ -0,0 +1,24 @@ + diff --git a/phpmyadmin/libraries/engines/binlog.lib.php b/phpmyadmin/libraries/engines/binlog.lib.php new file mode 100644 index 000000000..ea8173896 --- /dev/null +++ b/phpmyadmin/libraries/engines/binlog.lib.php @@ -0,0 +1,28 @@ + diff --git a/phpmyadmin/libraries/engines/innobase.lib.php b/phpmyadmin/libraries/engines/innobase.lib.php new file mode 100644 index 000000000..f81ae3f3b --- /dev/null +++ b/phpmyadmin/libraries/engines/innobase.lib.php @@ -0,0 +1,23 @@ + diff --git a/phpmyadmin/libraries/engines/innodb.lib.php b/phpmyadmin/libraries/engines/innodb.lib.php new file mode 100644 index 000000000..b0eec39ce --- /dev/null +++ b/phpmyadmin/libraries/engines/innodb.lib.php @@ -0,0 +1,411 @@ + array( + 'title' => __('Data home directory'), + 'desc' => __('The common part of the directory path for all InnoDB data files.'), + ), + 'innodb_data_file_path' => array( + 'title' => __('Data files'), + ), + 'innodb_autoextend_increment' => array( + 'title' => __('Autoextend increment'), + 'desc' => __('The increment size for extending the size of an autoextending tablespace when it becomes full.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + 'innodb_buffer_pool_size' => array( + 'title' => __('Buffer pool size'), + 'desc' => __('The size of the memory buffer InnoDB uses to cache data and indexes of its tables.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + 'innodb_additional_mem_pool_size' => array( + 'title' => 'innodb_additional_mem_pool_size', + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + 'innodb_buffer_pool_awe_mem_mb' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + 'innodb_checksums' => array( + ), + 'innodb_commit_concurrency' => array( + ), + 'innodb_concurrency_tickets' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + 'innodb_doublewrite' => array( + ), + 'innodb_fast_shutdown' => array( + ), + 'innodb_file_io_threads' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + 'innodb_file_per_table' => array( + ), + 'innodb_flush_log_at_trx_commit' => array( + ), + 'innodb_flush_method' => array( + ), + 'innodb_force_recovery' => array( + ), + 'innodb_lock_wait_timeout' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + 'innodb_locks_unsafe_for_binlog' => array( + ), + 'innodb_log_arch_dir' => array( + ), + 'innodb_log_archive' => array( + ), + 'innodb_log_buffer_size' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + 'innodb_log_file_size' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + 'innodb_log_files_in_group' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + 'innodb_log_group_home_dir' => array( + ), + 'innodb_max_dirty_pages_pct' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + 'innodb_max_purge_lag' => array( + ), + 'innodb_mirrored_log_groups' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + 'innodb_open_files' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + 'innodb_support_xa' => array( + ), + 'innodb_sync_spin_loops' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + 'innodb_table_locks' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_BOOLEAN, + ), + 'innodb_thread_concurrency' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + 'innodb_thread_sleep_delay' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + ); + } + + /** + * Returns the pattern to be used in the query for SQL variables + * related to InnoDb storage engine + * + * @return string SQL query LIKE pattern + */ + function getVariablesLikePattern() + { + return 'innodb\\_%'; + } + + /** + * Get information pages + * + * @return array detail pages + */ + function getInfoPages() + { + if ($this->support < PMA_ENGINE_SUPPORT_YES) { + return array(); + } + $pages = array(); + $pages['Bufferpool'] = __('Buffer Pool'); + $pages['Status'] = __('InnoDB Status'); + return $pages; + } + + /** + * returns html tables with stats over inno db buffer pool + * + * @return string html table with stats + */ + function getPageBufferpool() + { + // The following query is only possible because we know + // that we are on MySQL 5 here (checked above)! + // side note: I love MySQL 5 for this. :-) + $sql = ' + SHOW STATUS + WHERE Variable_name LIKE \'Innodb\\_buffer\\_pool\\_%\' + OR Variable_name = \'Innodb_page_size\';'; + $status = PMA_DBI_fetch_result($sql, 0, 1); + + $output = '' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' '; + + // not present at least since MySQL 5.1.40 + if (isset($status['Innodb_buffer_pool_pages_latched'])) { + $output .= ' ' + . ' ' + . ' ' + . ' '; + } + + $output .= ' ' . "\n" + . '
      ' . "\n" + . ' ' . __('Buffer Pool Usage') . "\n" + . '
      ' . "\n" + . ' ' . __('Total') . "\n" + . ' : ' + . PMA_Util::formatNumber( + $status['Innodb_buffer_pool_pages_total'], 0 + ) + . ' ' . __('pages') + . ' / ' + . join( + ' ', + PMA_Util::formatByteDown( + $status['Innodb_buffer_pool_pages_total'] + * $status['Innodb_page_size'] + ) + ) . "\n" + . '
      ' . __('Free pages') . '' + . PMA_Util::formatNumber( + $status['Innodb_buffer_pool_pages_free'], 0 + ) + . '
      ' . __('Dirty pages') . '' + . PMA_Util::formatNumber( + $status['Innodb_buffer_pool_pages_dirty'], 0 + ) + . '
      ' . __('Pages containing data') . '' + . PMA_Util::formatNumber( + $status['Innodb_buffer_pool_pages_data'], 0 + ) . "\n" + . '
      ' . __('Pages to be flushed') . '' + . PMA_Util::formatNumber( + $status['Innodb_buffer_pool_pages_flushed'], 0 + ) . "\n" + . '
      ' . __('Busy pages') . '' + . PMA_Util::formatNumber( + $status['Innodb_buffer_pool_pages_misc'], 0 + ) . "\n" + . '
      ' . __('Latched pages') . '' + . PMA_Util::formatNumber( + $status['Innodb_buffer_pool_pages_latched'], 0 + ) + . '
      ' . "\n\n" + . '' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . '
      ' . "\n" + . ' ' . __('Buffer Pool Activity') . "\n" + . '
      ' . __('Read requests') . '' + . PMA_Util::formatNumber( + $status['Innodb_buffer_pool_read_requests'], 0 + ) . "\n" + . '
      ' . __('Write requests') . '' + . PMA_Util::formatNumber( + $status['Innodb_buffer_pool_write_requests'], 0 + ) . "\n" + . '
      ' . __('Read misses') . '' + . PMA_Util::formatNumber( + $status['Innodb_buffer_pool_reads'], 0 + ) . "\n" + . '
      ' . __('Write waits') . '' + . PMA_Util::formatNumber( + $status['Innodb_buffer_pool_wait_free'], 0 + ) . "\n" + . '
      ' . __('Read misses in %') . '' + . ($status['Innodb_buffer_pool_read_requests'] == 0 + ? '---' + : htmlspecialchars( + PMA_Util::formatNumber( + $status['Innodb_buffer_pool_reads'] * 100 + / $status['Innodb_buffer_pool_read_requests'], + 3, + 2 + ) + ) . ' %') . "\n" + . '
      ' . __('Write waits in %') . '' + . ($status['Innodb_buffer_pool_write_requests'] == 0 + ? '---' + : htmlspecialchars( + PMA_Util::formatNumber( + $status['Innodb_buffer_pool_wait_free'] * 100 + / $status['Innodb_buffer_pool_write_requests'], + 3, + 2 + ) + ) . ' %') . "\n" + . '
      ' . "\n"; + return $output; + } + + /** + * returns InnoDB status + * + * @return string result of SHOW INNODB STATUS inside pre tags + */ + function getPageStatus() + { + return '
      ' . "\n"
      +            . htmlspecialchars(
      +                PMA_DBI_fetch_value('SHOW INNODB STATUS;', 0, 'Status')
      +            ) . "\n"
      +            . '
      ' . "\n"; + } + + /** + * Returns content for page $id + * + * @param string $id page id + * + * @return string html output + */ + function getPage($id) + { + if (! array_key_exists($id, $this->getInfoPages())) { + return false; + } + + $id = 'getPage' . $id; + + return $this->$id(); + } + + /** + * returns string with filename for the MySQL helppage + * about this storage engine + * + * @return string mysql helppage filename + */ + function getMysqlHelpPage() + { + return 'innodb-storage-engine'; + } + + /** + * Gets the InnoDB plugin version number + * + * http://www.innodb.com/products/innodb_plugin + * (do not confuse this with phpMyAdmin's storage engine plugins!) + * + * @return string the version number, or empty if not running as a plugin + */ + function getInnodbPluginVersion() + { + return PMA_DBI_fetch_value('SELECT @@innodb_version;'); + } + + /** + * Gets the InnoDB file format + * + * (works only for the InnoDB plugin) + * http://www.innodb.com/products/innodb_plugin + * (do not confuse this with phpMyAdmin's storage engine plugins!) + * + * @return string the InnoDB file format + */ + function getInnodbFileFormat() + { + return PMA_DBI_fetch_value( + "SHOW GLOBAL VARIABLES LIKE 'innodb_file_format';", 0, 1 + ); + } + + /** + * Verifies if this server supports the innodb_file_per_table feature + * + * (works only for the InnoDB plugin) + * http://www.innodb.com/products/innodb_plugin + * (do not confuse this with phpMyAdmin's storage engine plugins!) + * + * @return boolean whether this feature is supported or not + */ + function supportsFilePerTable() + { + $innodb_file_per_table = PMA_DBI_fetch_value( + "SHOW GLOBAL VARIABLES LIKE 'innodb_file_per_table';", 0, 1 + ); + if ($innodb_file_per_table == 'ON') { + return true; + } else { + return false; + } + + } +} + +?> diff --git a/phpmyadmin/libraries/engines/memory.lib.php b/phpmyadmin/libraries/engines/memory.lib.php new file mode 100644 index 000000000..8e9fe5fc8 --- /dev/null +++ b/phpmyadmin/libraries/engines/memory.lib.php @@ -0,0 +1,34 @@ + array( + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + ); + } +} + +?> diff --git a/phpmyadmin/libraries/engines/merge.lib.php b/phpmyadmin/libraries/engines/merge.lib.php new file mode 100644 index 000000000..4bccfc79c --- /dev/null +++ b/phpmyadmin/libraries/engines/merge.lib.php @@ -0,0 +1,21 @@ + diff --git a/phpmyadmin/libraries/engines/mrg_myisam.lib.php b/phpmyadmin/libraries/engines/mrg_myisam.lib.php new file mode 100644 index 000000000..d3425365c --- /dev/null +++ b/phpmyadmin/libraries/engines/mrg_myisam.lib.php @@ -0,0 +1,33 @@ + diff --git a/phpmyadmin/libraries/engines/myisam.lib.php b/phpmyadmin/libraries/engines/myisam.lib.php new file mode 100644 index 000000000..5882824bc --- /dev/null +++ b/phpmyadmin/libraries/engines/myisam.lib.php @@ -0,0 +1,69 @@ + array( + 'title' => __('Data pointer size'), + 'desc' => __('The default pointer size in bytes, to be used by CREATE TABLE for MyISAM tables when no MAX_ROWS option is specified.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + 'myisam_recover_options' => array( + 'title' => __('Automatic recovery mode'), + 'desc' => __('The mode for automatic recovery of crashed MyISAM tables, as set via the --myisam-recover server startup option.'), + ), + 'myisam_max_sort_file_size' => array( + 'title' => __('Maximum size for temporary sort files'), + 'desc' => __('The maximum size of the temporary file MySQL is allowed to use while re-creating a MyISAM index (during REPAIR TABLE, ALTER TABLE, or LOAD DATA INFILE).'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + 'myisam_max_extra_sort_file_size' => array( + 'title' => __('Maximum size for temporary files on index creation'), + 'desc' => __('If the temporary file used for fast MyISAM index creation would be larger than using the key cache by the amount specified here, prefer the key cache method.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + 'myisam_repair_threads' => array( + 'title' => __('Repair threads'), + 'desc' => __('If this value is greater than 1, MyISAM table indexes are created in parallel (each index in its own thread) during the repair by sorting process.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, + ), + 'myisam_sort_buffer_size' => array( + 'title' => __('Sort buffer size'), + 'desc' => __('The buffer that is allocated when sorting MyISAM indexes during a REPAIR TABLE or when creating indexes with CREATE INDEX or ALTER TABLE.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + 'myisam_stats_method' => array( + ), + 'delay_key_write' => array( + ), + 'bulk_insert_buffer_size' => array( + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, + ), + 'skip_external_locking' => array( + ), + ); + } +} + +?> diff --git a/phpmyadmin/libraries/engines/ndbcluster.lib.php b/phpmyadmin/libraries/engines/ndbcluster.lib.php new file mode 100644 index 000000000..e57846b60 --- /dev/null +++ b/phpmyadmin/libraries/engines/ndbcluster.lib.php @@ -0,0 +1,55 @@ + array( + ), + ); + } + + /** + * Returns the pattern to be used in the query for SQL variables + * related to NDBCLUSTER storage engine + * + * @return string SQL query LIKE pattern + */ + function getVariablesLikePattern() + { + return 'ndb\\_%'; + } + + /** + * Returns string with filename for the MySQL help page + * about this storage engine + * + * @return string mysql helppage filename + */ + function getMysqlHelpPage() + { + return 'ndbcluster'; + } +} + +?> diff --git a/phpmyadmin/libraries/engines/pbxt.lib.php b/phpmyadmin/libraries/engines/pbxt.lib.php new file mode 100644 index 000000000..fc4e343f5 --- /dev/null +++ b/phpmyadmin/libraries/engines/pbxt.lib.php @@ -0,0 +1,142 @@ + array( + 'title' => __('Index cache size'), + 'desc' => __('This is the amount of memory allocated to the index cache. Default value is 32MB. The memory allocated here is used only for caching index pages.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE + ), + 'pbxt_record_cache_size' => array( + 'title' => __('Record cache size'), + 'desc' => __('This is the amount of memory allocated to the record cache used to cache table data. The default value is 32MB. This memory is used to cache changes to the handle data (.xtd) and row pointer (.xtr) files.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE + ), + 'pbxt_log_cache_size' => array( + 'title' => __('Log cache size'), + 'desc' => __('The amount of memory allocated to the transaction log cache used to cache on transaction log data. The default is 16MB.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE + ), + 'pbxt_log_file_threshold' => array( + 'title' => __('Log file threshold'), + 'desc' => __('The size of a transaction log before rollover, and a new log is created. The default value is 16MB.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE + ), + 'pbxt_transaction_buffer_size' => array( + 'title' => __('Transaction buffer size'), + 'desc' => __('The size of the global transaction log buffer (the engine allocates 2 buffers of this size). The default is 1MB.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE + ), + 'pbxt_checkpoint_frequency' => array( + 'title' => __('Checkpoint frequency'), + 'desc' => __('The amount of data written to the transaction log before a checkpoint is performed. The default value is 24MB.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE + ), + 'pbxt_data_log_threshold' => array( + 'title' => __('Data log threshold'), + 'desc' => __('The maximum size of a data log file. The default value is 64MB. PBXT can create a maximum of 32000 data logs, which are used by all tables. So the value of this variable can be increased to increase the total amount of data that can be stored in the database.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE + ), + 'pbxt_garbage_threshold' => array( + 'title' => __('Garbage threshold'), + 'desc' => __('The percentage of garbage in a data log file before it is compacted. This is a value between 1 and 99. The default is 50.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC + ), + 'pbxt_log_buffer_size' => array( + 'title' => __('Log buffer size'), + 'desc' => __('The size of the buffer used when writing a data log. The default is 256MB. The engine allocates one buffer per thread, but only if the thread is required to write a data log.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE + ), + 'pbxt_data_file_grow_size' => array( + 'title' => __('Data file grow size'), + 'desc' => __('The grow size of the handle data (.xtd) files.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE + ), + 'pbxt_row_file_grow_size' => array( + 'title' => __('Row file grow size'), + 'desc' => __('The grow size of the row pointer (.xtr) files.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE + ), + 'pbxt_log_file_count' => array( + 'title' => __('Log file count'), + 'desc' => __('This is the number of transaction log files (pbxt/system/xlog*.xt) the system will maintain. If the number of logs exceeds this value then old logs will be deleted, otherwise they are renamed and given the next highest number.'), + 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC + ), + ); + } + + /** + * returns the pbxt engine specific handling for + * PMA_ENGINE_DETAILS_TYPE_SIZE variables. + * + * @param string $formatted_size the size expression (for example 8MB) + * + * @return string the formatted value and its unit + */ + function resolveTypeSize($formatted_size) + { + if (preg_match('/^[0-9]+[a-zA-Z]+$/', $formatted_size)) { + $value = PMA_Util::extractValueFromFormattedSize($formatted_size); + } else { + $value = $formatted_size; + } + return PMA_Util::formatByteDown($value); + } + + //-------------------- + function getInfoPages() + { + $pages = array(); + $pages['Documentation'] = __('Documentation'); + return $pages; + } + + //-------------------- + function getPage($id) + { + if (! array_key_exists($id, $this->getInfoPages())) { + return false; + } + + $id = 'getPage' . $id; + + return $this->$id(); + } + + function getPageDocumentation() + { + $output = '

      ' + . sprintf(__('Documentation and further information about PBXT can be found on the %sPrimeBase XT Home Page%s.'), '', '') + . '

      ' . "\n" + . '

      ' . __('Related Links') . '

      ' . "\n" + . '' . "\n"; + + return $output; + } +} + +?> diff --git a/phpmyadmin/libraries/engines/performance_schema.lib.php b/phpmyadmin/libraries/engines/performance_schema.lib.php new file mode 100644 index 000000000..f7664b655 --- /dev/null +++ b/phpmyadmin/libraries/engines/performance_schema.lib.php @@ -0,0 +1,28 @@ + diff --git a/phpmyadmin/libraries/error.inc.php b/phpmyadmin/libraries/error.inc.php new file mode 100644 index 000000000..c48a7f142 --- /dev/null +++ b/phpmyadmin/libraries/error.inc.php @@ -0,0 +1,59 @@ + + + + + + + phpMyAdmin + + + + +

      phpMyAdmin -

      +

      + + + diff --git a/phpmyadmin/libraries/file_listing.lib.php b/phpmyadmin/libraries/file_listing.lib.php new file mode 100644 index 000000000..e5b680c2c --- /dev/null +++ b/phpmyadmin/libraries/file_listing.lib.php @@ -0,0 +1,103 @@ +' . htmlspecialchars($val) . '' . "\n"; + } + return $result; +} + +/** + * Get currently supported decompressions. + * + * @return string | separated list of extensions usable in PMA_getDirContent + */ +function PMA_supportedDecompressions() +{ + global $cfg; + + $compressions = ''; + + if ($cfg['GZipDump'] && @function_exists('gzopen')) { + if (!empty($compressions)) { + $compressions .= '|'; + } + $compressions .= 'gz'; + } + if ($cfg['BZipDump'] && @function_exists('bzopen')) { + if (!empty($compressions)) { + $compressions .= '|'; + } + $compressions .= 'bz2'; + } + if ($cfg['ZipDump'] && @function_exists('gzinflate')) { + if (!empty($compressions)) { + $compressions .= '|'; + } + $compressions .= 'zip'; + } + + return $compressions; +} diff --git a/phpmyadmin/libraries/gis/pma_gis_factory.php b/phpmyadmin/libraries/gis/pma_gis_factory.php new file mode 100644 index 000000000..1184ae346 --- /dev/null +++ b/phpmyadmin/libraries/gis/pma_gis_factory.php @@ -0,0 +1,61 @@ + diff --git a/phpmyadmin/libraries/gis/pma_gis_geometry.php b/phpmyadmin/libraries/gis/pma_gis_geometry.php new file mode 100644 index 000000000..206d7c459 --- /dev/null +++ b/phpmyadmin/libraries/gis/pma_gis_geometry.php @@ -0,0 +1,361 @@ + $min_max['maxX']) { + $min_max['maxX'] = $x; + } + if (! isset($min_max['minX']) || $x < $min_max['minX']) { + $min_max['minX'] = $x; + } + $y = (float) $cordinates[1]; + if (! isset($min_max['maxY']) || $y > $min_max['maxY']) { + $min_max['maxY'] = $y; + } + if (! isset($min_max['minY']) || $y < $min_max['minY']) { + $min_max['minY'] = $y; + } + } + return $min_max; + } + + /** + * Generates parameters for the GIS data editor from the value of the GIS column. + * This method performs common work. + * More specific work is performed by each of the geom classes. + * + * @param string $value value of the GIS column + * + * @return array parameters for the GIS editor from the value of the GIS column + * @access protected + */ + protected function generateParams($value) + { + $geom_types = '(POINT|MULTIPOINT|LINESTRING|MULTILINESTRING' + . '|POLYGON|MULTIPOLYGON|GEOMETRYCOLLECTION)'; + $srid = 0; + $wkt = ''; + if (preg_match("/^'" . $geom_types . "\(.*\)',[0-9]*$/i", $value)) { + $last_comma = strripos($value, ","); + $srid = trim(substr($value, $last_comma + 1)); + $wkt = trim(substr($value, 1, $last_comma - 2)); + } elseif (preg_match("/^" . $geom_types . "\(.*\)$/i", $value)) { + $wkt = $value; + } + return array('srid' => $srid, 'wkt' => $wkt); + } + + /** + * Extracts points, scales and returns them as an array. + * + * @param string $point_set string of comma sperated points + * @param array $scale_data data related to scaling + * @param boolean $linear if true, as a 1D array, else as a 2D array + * + * @return array scaled points + * @access protected + */ + protected function extractPoints($point_set, $scale_data, $linear = false) + { + $points_arr = array(); + + // Seperate each point + $points = explode(",", $point_set); + + foreach ($points as $point) { + // Extract cordinates of the point + $cordinates = explode(" ", $point); + + if (isset($cordinates[0]) && trim($cordinates[0]) != '' + && isset($cordinates[1]) && trim($cordinates[1]) != '' + ) { + if ($scale_data != null) { + $x = ($cordinates[0] - $scale_data['x']) * $scale_data['scale']; + $y = $scale_data['height'] + - ($cordinates[1] - $scale_data['y']) * $scale_data['scale']; + } else { + $x = trim($cordinates[0]); + $y = trim($cordinates[1]); + } + } else { + $x = ''; + $y = ''; + } + + + if (! $linear) { + $points_arr[] = array($x, $y); + } else { + $points_arr[] = $x; + $points_arr[] = $y; + } + } + + return $points_arr; + } + + /** + * Generates JavaScript for adding an array of polygons to OpenLayers. + * + * @param array $polygons x and y coordinates for each polygon + * @param string $srid spatial reference id + * + * @return string JavaScript for adding an array of polygons to OpenLayers + * @access protected + */ + protected function getPolygonArrayForOpenLayers($polygons, $srid) + { + $ol_array = 'new Array('; + foreach ($polygons as $polygon) { + $rings = explode("),(", $polygon); + $ol_array .= $this->getPolygonForOpenLayers($rings, $srid) . ', '; + } + $ol_array = substr($ol_array, 0, strlen($ol_array) - 2); + $ol_array .= ')'; + + return $ol_array; + } + + /** + * Generates JavaScript for adding points for OpenLayers polygon. + * + * @param array $polygon x and y coordinates for each line + * @param string $srid spatial reference id + * + * @return string JavaScript for adding points for OpenLayers polygon + * @access protected + */ + protected function getPolygonForOpenLayers($polygon, $srid) + { + return 'new OpenLayers.Geometry.Polygon(' + . $this->getLineArrayForOpenLayers($polygon, $srid, false) + . ')'; + } + + /** + * Generates JavaScript for adding an array of LineString + * or LineRing to OpenLayers. + * + * @param array $lines x and y coordinates for each line + * @param string $srid spatial reference id + * @param bool $is_line_string whether it's an array of LineString + * + * @return string JavaScript for adding an array of LineString + * or LineRing to OpenLayers + * @access protected + */ + protected function getLineArrayForOpenLayers($lines, $srid, + $is_line_string = true + ) { + $ol_array = 'new Array('; + foreach ($lines as $line) { + $points_arr = $this->extractPoints($line, null); + $ol_array .= $this->getLineForOpenLayers( + $points_arr, $srid, $is_line_string + ); + $ol_array .= ', '; + } + $ol_array = substr($ol_array, 0, strlen($ol_array) - 2); + $ol_array .= ')'; + + return $ol_array; + } + + /** + * Generates JavaScript for adding a LineString or LineRing to OpenLayers. + * + * @param array $points_arr x and y coordinates for each point + * @param string $srid spatial reference id + * @param bool $is_line_string whether it's a LineString + * + * @return string JavaScript for adding a LineString or LineRing to OpenLayers + * @access protected + */ + protected function getLineForOpenLayers($points_arr, $srid, + $is_line_string = true + ) { + return 'new OpenLayers.Geometry.' + . ($is_line_string ? 'LineString' : 'LinearRing') . '(' + . $this->getPointsArrayForOpenLayers($points_arr, $srid) + . ')'; + } + + /** + * Generates JavaScript for adding an array of points to OpenLayers. + * + * @param array $points_arr x and y coordinates for each point + * @param string $srid spatial reference id + * + * @return string JavaScript for adding an array of points to OpenLayers + * @access protected + */ + protected function getPointsArrayForOpenLayers($points_arr, $srid) + { + $ol_array = 'new Array('; + foreach ($points_arr as $point) { + $ol_array .= $this->getPointForOpenLayers($point, $srid) . ', '; + } + $ol_array = substr($ol_array, 0, strlen($ol_array) - 2); + $ol_array .= ')'; + + return $ol_array; + } + + /** + * Generates JavaScript for adding a point to OpenLayers. + * + * @param array $point array containing the x and y coordinates of the point + * @param string $srid spatial reference id + * + * @return string JavaScript for adding points to OpenLayers + * @access protected + */ + protected function getPointForOpenLayers($point, $srid) + { + return '(new OpenLayers.Geometry.Point(' . $point[0] . ',' . $point[1] . '))' + . '.transform(new OpenLayers.Projection("EPSG:' + . $srid . '"), map.getProjectionObject())'; + } +} +?> diff --git a/phpmyadmin/libraries/gis/pma_gis_geometrycollection.php b/phpmyadmin/libraries/gis/pma_gis_geometrycollection.php new file mode 100644 index 000000000..91c5a588c --- /dev/null +++ b/phpmyadmin/libraries/gis/pma_gis_geometrycollection.php @@ -0,0 +1,336 @@ +_explodeGeomCol($goem_col); + + foreach ($sub_parts as $sub_part) { + $type_pos = stripos($sub_part, '('); + $type = substr($sub_part, 0, $type_pos); + + $gis_obj = PMA_GIS_Factory::factory($type); + if (! $gis_obj) { + continue; + } + $scale_data = $gis_obj->scaleRow($sub_part); + + // Upadate minimum/maximum values for x and y cordinates. + $c_maxX = (float) $scale_data['maxX']; + if (! isset($min_max['maxX']) || $c_maxX > $min_max['maxX']) { + $min_max['maxX'] = $c_maxX; + } + + $c_minX = (float) $scale_data['minX']; + if (! isset($min_max['minX']) || $c_minX < $min_max['minX']) { + $min_max['minX'] = $c_minX; + } + + $c_maxY = (float) $scale_data['maxY']; + if (! isset($min_max['maxY']) || $c_maxY > $min_max['maxY']) { + $min_max['maxY'] = $c_maxY; + } + + $c_minY = (float) $scale_data['minY']; + if (! isset($min_max['minY']) || $c_minY < $min_max['minY']) { + $min_max['minY'] = $c_minY; + } + } + return $min_max; + } + + /** + * Adds to the PNG image object, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS GEOMETRYCOLLECTION object + * @param string $label label for the GIS GEOMETRYCOLLECTION object + * @param string $color color for the GIS GEOMETRYCOLLECTION object + * @param array $scale_data array containing data related to scaling + * @param object $image image object + * + * @return object the modified image object + * @access public + */ + public function prepareRowAsPng($spatial, $label, $color, $scale_data, $image) + { + // Trim to remove leading 'GEOMETRYCOLLECTION(' and trailing ')' + $goem_col = substr($spatial, 19, (strlen($spatial) - 20)); + // Split the geometry collection object to get its constituents. + $sub_parts = $this->_explodeGeomCol($goem_col); + + foreach ($sub_parts as $sub_part) { + $type_pos = stripos($sub_part, '('); + $type = substr($sub_part, 0, $type_pos); + + $gis_obj = PMA_GIS_Factory::factory($type); + if (! $gis_obj) { + continue; + } + $image = $gis_obj->prepareRowAsPng( + $sub_part, $label, $color, $scale_data, $image + ); + } + return $image; + } + + /** + * Adds to the TCPDF instance, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS GEOMETRYCOLLECTION object + * @param string $label label for the GIS GEOMETRYCOLLECTION object + * @param string $color color for the GIS GEOMETRYCOLLECTION object + * @param array $scale_data array containing data related to scaling + * @param object $pdf TCPDF instance + * + * @return object the modified TCPDF instance + * @access pubilc + */ + public function prepareRowAsPdf($spatial, $label, $color, $scale_data, $pdf) + { + // Trim to remove leading 'GEOMETRYCOLLECTION(' and trailing ')' + $goem_col = substr($spatial, 19, (strlen($spatial) - 20)); + // Split the geometry collection object to get its constituents. + $sub_parts = $this->_explodeGeomCol($goem_col); + + foreach ($sub_parts as $sub_part) { + $type_pos = stripos($sub_part, '('); + $type = substr($sub_part, 0, $type_pos); + + $gis_obj = PMA_GIS_Factory::factory($type); + if (! $gis_obj) { + continue; + } + $pdf = $gis_obj->prepareRowAsPdf( + $sub_part, $label, $color, $scale_data, $pdf + ); + } + return $pdf; + } + + /** + * Prepares and returns the code related to a row in the GIS dataset as SVG. + * + * @param string $spatial GIS GEOMETRYCOLLECTION object + * @param string $label label for the GIS GEOMETRYCOLLECTION object + * @param string $color color for the GIS GEOMETRYCOLLECTION object + * @param array $scale_data array containing data related to scaling + * + * @return string the code related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsSvg($spatial, $label, $color, $scale_data) + { + $row = ''; + + // Trim to remove leading 'GEOMETRYCOLLECTION(' and trailing ')' + $goem_col = substr($spatial, 19, (strlen($spatial) - 20)); + // Split the geometry collection object to get its constituents. + $sub_parts = $this->_explodeGeomCol($goem_col); + + foreach ($sub_parts as $sub_part) { + $type_pos = stripos($sub_part, '('); + $type = substr($sub_part, 0, $type_pos); + + $gis_obj = PMA_GIS_Factory::factory($type); + if (! $gis_obj) { + continue; + } + $row .= $gis_obj->prepareRowAsSvg( + $sub_part, $label, $color, $scale_data + ); + } + return $row; + } + + /** + * Prepares JavaScript related to a row in the GIS dataset + * to visualize it with OpenLayers. + * + * @param string $spatial GIS GEOMETRYCOLLECTION object + * @param int $srid spatial reference ID + * @param string $label label for the GIS GEOMETRYCOLLECTION object + * @param string $color color for the GIS GEOMETRYCOLLECTION object + * @param array $scale_data array containing data related to scaling + * + * @return string JavaScript related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsOl($spatial, $srid, $label, $color, $scale_data) + { + $row = ''; + + // Trim to remove leading 'GEOMETRYCOLLECTION(' and trailing ')' + $goem_col = substr($spatial, 19, (strlen($spatial) - 20)); + // Split the geometry collection object to get its constituents. + $sub_parts = $this->_explodeGeomCol($goem_col); + + foreach ($sub_parts as $sub_part) { + $type_pos = stripos($sub_part, '('); + $type = substr($sub_part, 0, $type_pos); + + $gis_obj = PMA_GIS_Factory::factory($type); + if (! $gis_obj) { + continue; + } + $row .= $gis_obj->prepareRowAsOl( + $sub_part, $srid, $label, $color, $scale_data + ); + } + return $row; + } + + /** + * Splits the GEOMETRYCOLLECTION object and get its constituents. + * + * @param string $goem_col geometry collection string + * + * @return array the constituents of the geometry collection object + * @access private + */ + private function _explodeGeomCol($goem_col) + { + $sub_parts = array(); + $br_count = 0; + $start = 0; + $count = 0; + foreach (str_split($goem_col) as $char) { + if ($char == '(') { + $br_count++; + } elseif ($char == ')') { + $br_count--; + if ($br_count == 0) { + $sub_parts[] = substr($goem_col, $start, ($count + 1 - $start)); + $start = $count + 2; + } + } + $count++; + } + return $sub_parts; + } + + /** + * Generates the WKT with the set of parameters passed by the GIS editor. + * + * @param array $gis_data GIS data + * @param int $index index into the parameter object + * @param string $empty value for empty points + * + * @return string WKT with the set of parameters passed by the GIS editor + * @access public + */ + public function generateWkt($gis_data, $index, $empty = '') + { + $geom_count = (isset($gis_data['GEOMETRYCOLLECTION']['geom_count'])) + ? $gis_data['GEOMETRYCOLLECTION']['geom_count'] : 1; + $wkt = 'GEOMETRYCOLLECTION('; + for ($i = 0; $i < $geom_count; $i++) { + if (isset($gis_data[$i]['gis_type'])) { + $type = $gis_data[$i]['gis_type']; + $gis_obj = PMA_GIS_Factory::factory($type); + if (! $gis_obj) { + continue; + } + $wkt .= $gis_obj->generateWkt($gis_data, $i, $empty) . ','; + } + } + if (isset($gis_data[0]['gis_type'])) { + $wkt = substr($wkt, 0, strlen($wkt) - 1); + } + $wkt .= ')'; + return $wkt; + } + + /** + * Generates parameters for the GIS data editor from the value of the GIS column. + * + * @param string $value of the GIS column + * + * @return array parameters for the GIS editor from the value of the GIS column + * @access public + */ + public function generateParams($value) + { + $params = array(); + $data = PMA_GIS_Geometry::generateParams($value); + $params['srid'] = $data['srid']; + $wkt = $data['wkt']; + + // Trim to remove leading 'GEOMETRYCOLLECTION(' and trailing ')' + $goem_col = substr($wkt, 19, (strlen($wkt) - 20)); + // Split the geometry collection object to get its constituents. + $sub_parts = $this->_explodeGeomCol($goem_col); + $params['GEOMETRYCOLLECTION']['geom_count'] = count($sub_parts); + + $i = 0; + foreach ($sub_parts as $sub_part) { + $type_pos = stripos($sub_part, '('); + $type = substr($sub_part, 0, $type_pos); + $gis_obj = PMA_GIS_Factory::factory($type); + if (! $gis_obj) { + continue; + } + $params = array_merge($params, $gis_obj->generateParams($sub_part, $i)); + $i++; + } + return $params; + } +} +?> diff --git a/phpmyadmin/libraries/gis/pma_gis_linestring.php b/phpmyadmin/libraries/gis/pma_gis_linestring.php new file mode 100644 index 000000000..9c4951224 --- /dev/null +++ b/phpmyadmin/libraries/gis/pma_gis_linestring.php @@ -0,0 +1,298 @@ +setMinMax($linesrting, array()); + } + + /** + * Adds to the PNG image object, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS LINESTRING object + * @param string $label Label for the GIS LINESTRING object + * @param string $line_color Color for the GIS LINESTRING object + * @param array $scale_data Array containing data related to scaling + * @param object $image Image object + * + * @return object the modified image object + * @access public + */ + public function prepareRowAsPng($spatial, $label, $line_color, + $scale_data, $image + ) { + // allocate colors + $black = imagecolorallocate($image, 0, 0, 0); + $red = hexdec(substr($line_color, 1, 2)); + $green = hexdec(substr($line_color, 3, 2)); + $blue = hexdec(substr($line_color, 4, 2)); + $color = imagecolorallocate($image, $red, $green, $blue); + + // Trim to remove leading 'LINESTRING(' and trailing ')' + $linesrting = substr($spatial, 11, (strlen($spatial) - 12)); + $points_arr = $this->extractPoints($linesrting, $scale_data); + + foreach ($points_arr as $point) { + if (! isset($temp_point)) { + $temp_point = $point; + } else { + // draw line section + imageline( + $image, $temp_point[0], $temp_point[1], + $point[0], $point[1], $color + ); + $temp_point = $point; + } + } + // print label if applicable + if (isset($label) && trim($label) != '') { + imagestring( + $image, 1, $points_arr[1][0], + $points_arr[1][1], trim($label), $black + ); + } + return $image; + } + + /** + * Adds to the TCPDF instance, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS LINESTRING object + * @param string $label Label for the GIS LINESTRING object + * @param string $line_color Color for the GIS LINESTRING object + * @param array $scale_data Array containing data related to scaling + * @param object $pdf TCPDF instance + * + * @return object the modified TCPDF instance + * @access public + */ + public function prepareRowAsPdf($spatial, $label, $line_color, $scale_data, $pdf) + { + // allocate colors + $red = hexdec(substr($line_color, 1, 2)); + $green = hexdec(substr($line_color, 3, 2)); + $blue = hexdec(substr($line_color, 4, 2)); + $line = array('width' => 1.5, 'color' => array($red, $green, $blue)); + + // Trim to remove leading 'LINESTRING(' and trailing ')' + $linesrting = substr($spatial, 11, (strlen($spatial) - 12)); + $points_arr = $this->extractPoints($linesrting, $scale_data); + + foreach ($points_arr as $point) { + if (! isset($temp_point)) { + $temp_point = $point; + } else { + // draw line section + $pdf->Line( + $temp_point[0], $temp_point[1], + $point[0], $point[1], $line + ); + $temp_point = $point; + } + } + // print label + if (isset($label) && trim($label) != '') { + $pdf->SetXY($points_arr[1][0], $points_arr[1][1]); + $pdf->SetFontSize(5); + $pdf->Cell(0, 0, trim($label)); + } + return $pdf; + } + + /** + * Prepares and returns the code related to a row in the GIS dataset as SVG. + * + * @param string $spatial GIS LINESTRING object + * @param string $label Label for the GIS LINESTRING object + * @param string $line_color Color for the GIS LINESTRING object + * @param array $scale_data Array containing data related to scaling + * + * @return string the code related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsSvg($spatial, $label, $line_color, $scale_data) + { + $line_options = array( + 'name' => $label, + 'id' => $label . rand(), + 'class' => 'linestring vector', + 'fill' => 'none', + 'stroke' => $line_color, + 'stroke-width'=> 2, + ); + + // Trim to remove leading 'LINESTRING(' and trailing ')' + $linesrting = substr($spatial, 11, (strlen($spatial) - 12)); + $points_arr = $this->extractPoints($linesrting, $scale_data); + + $row = ' $val) { + $row .= ' ' . $option . '="' . trim($val) . '"'; + } + $row .= '/>'; + + return $row; + } + + /** + * Prepares JavaScript related to a row in the GIS dataset + * to visualize it with OpenLayers. + * + * @param string $spatial GIS LINESTRING object + * @param int $srid Spatial reference ID + * @param string $label Label for the GIS LINESTRING object + * @param string $line_color Color for the GIS LINESTRING object + * @param array $scale_data Array containing data related to scaling + * + * @return string JavaScript related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsOl($spatial, $srid, $label, $line_color, $scale_data) + { + $style_options = array( + 'strokeColor' => $line_color, + 'strokeWidth' => 2, + 'label' => $label, + 'fontSize' => 10, + ); + if ($srid == 0) { + $srid = 4326; + } + $result = $this->getBoundsForOl($srid, $scale_data); + + // Trim to remove leading 'LINESTRING(' and trailing ')' + $linesrting = substr($spatial, 11, (strlen($spatial) - 12)); + $points_arr = $this->extractPoints($linesrting, null); + + $result .= 'vectorLayer.addFeatures(new OpenLayers.Feature.Vector(' + . $this->getLineForOpenLayers($points_arr, $srid) + . ', null, ' . json_encode($style_options) . '));'; + return $result; + } + + /** + * Generate the WKT with the set of parameters passed by the GIS editor. + * + * @param array $gis_data GIS data + * @param int $index Index into the parameter object + * @param string $empty Value for empty points + * + * @return string WKT with the set of parameters passed by the GIS editor + * @access public + */ + public function generateWkt($gis_data, $index, $empty = '') + { + $no_of_points = isset($gis_data[$index]['LINESTRING']['no_of_points']) + ? $gis_data[$index]['LINESTRING']['no_of_points'] : 2; + if ($no_of_points < 2) { + $no_of_points = 2; + } + $wkt = 'LINESTRING('; + for ($i = 0; $i < $no_of_points; $i++) { + $wkt .= ((isset($gis_data[$index]['LINESTRING'][$i]['x']) + && trim($gis_data[$index]['LINESTRING'][$i]['x']) != '') + ? $gis_data[$index]['LINESTRING'][$i]['x'] : $empty) + . ' ' . ((isset($gis_data[$index]['LINESTRING'][$i]['y']) + && trim($gis_data[$index]['LINESTRING'][$i]['y']) != '') + ? $gis_data[$index]['LINESTRING'][$i]['y'] : $empty) .','; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= ')'; + return $wkt; + } + + /** + * Generate parameters for the GIS data editor from the value of the GIS column. + * + * @param string $value of the GIS column + * @param int $index of the geometry + * + * @return array params for the GIS data editor from the value of the GIS column + * @access public + */ + public function generateParams($value, $index = -1) + { + if ($index == -1) { + $index = 0; + $params = array(); + $data = PMA_GIS_Geometry::generateParams($value); + $params['srid'] = $data['srid']; + $wkt = $data['wkt']; + } else { + $params[$index]['gis_type'] = 'LINESTRING'; + $wkt = $value; + } + + // Trim to remove leading 'LINESTRING(' and trailing ')' + $linestring = substr($wkt, 11, (strlen($wkt) - 12)); + $points_arr = $this->extractPoints($linestring, null); + + $no_of_points = count($points_arr); + $params[$index]['LINESTRING']['no_of_points'] = $no_of_points; + for ($i = 0; $i < $no_of_points; $i++) { + $params[$index]['LINESTRING'][$i]['x'] = $points_arr[$i][0]; + $params[$index]['LINESTRING'][$i]['y'] = $points_arr[$i][1]; + } + + return $params; + } +} +?> diff --git a/phpmyadmin/libraries/gis/pma_gis_multilinestring.php b/phpmyadmin/libraries/gis/pma_gis_multilinestring.php new file mode 100644 index 000000000..ce4a0c94a --- /dev/null +++ b/phpmyadmin/libraries/gis/pma_gis_multilinestring.php @@ -0,0 +1,370 @@ +setMinMax($linestring, $min_max); + } + + return $min_max; + } + + /** + * Adds to the PNG image object, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS MULTILINESTRING object + * @param string $label Label for the GIS MULTILINESTRING object + * @param string $line_color Color for the GIS MULTILINESTRING object + * @param array $scale_data Array containing data related to scaling + * @param object $image Image object + * + * @return object the modified image object + * @access public + */ + public function prepareRowAsPng($spatial, $label, $line_color, + $scale_data, $image + ) { + // allocate colors + $black = imagecolorallocate($image, 0, 0, 0); + $red = hexdec(substr($line_color, 1, 2)); + $green = hexdec(substr($line_color, 3, 2)); + $blue = hexdec(substr($line_color, 4, 2)); + $color = imagecolorallocate($image, $red, $green, $blue); + + // Trim to remove leading 'MULTILINESTRING((' and trailing '))' + $multilinestirng = substr($spatial, 17, (strlen($spatial) - 19)); + // Seperate each linestring + $linestirngs = explode("),(", $multilinestirng); + + $first_line = true; + foreach ($linestirngs as $linestring) { + $points_arr = $this->extractPoints($linestring, $scale_data); + foreach ($points_arr as $point) { + if (! isset($temp_point)) { + $temp_point = $point; + } else { + // draw line section + imageline( + $image, $temp_point[0], $temp_point[1], + $point[0], $point[1], $color + ); + $temp_point = $point; + } + } + unset($temp_point); + // print label if applicable + if (isset($label) && trim($label) != '' && $first_line) { + imagestring( + $image, 1, $points_arr[1][0], + $points_arr[1][1], trim($label), $black + ); + } + $first_line = false; + } + return $image; + } + + /** + * Adds to the TCPDF instance, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS MULTILINESTRING object + * @param string $label Label for the GIS MULTILINESTRING object + * @param string $line_color Color for the GIS MULTILINESTRING object + * @param array $scale_data Array containing data related to scaling + * @param object $pdf TCPDF instance + * + * @return object the modified TCPDF instance + * @access public + */ + public function prepareRowAsPdf($spatial, $label, $line_color, $scale_data, $pdf) + { + // allocate colors + $red = hexdec(substr($line_color, 1, 2)); + $green = hexdec(substr($line_color, 3, 2)); + $blue = hexdec(substr($line_color, 4, 2)); + $line = array('width' => 1.5, 'color' => array($red, $green, $blue)); + + // Trim to remove leading 'MULTILINESTRING((' and trailing '))' + $multilinestirng = substr($spatial, 17, (strlen($spatial) - 19)); + // Seperate each linestring + $linestirngs = explode("),(", $multilinestirng); + + $first_line = true; + foreach ($linestirngs as $linestring) { + $points_arr = $this->extractPoints($linestring, $scale_data); + foreach ($points_arr as $point) { + if (! isset($temp_point)) { + $temp_point = $point; + } else { + // draw line section + $pdf->Line( + $temp_point[0], $temp_point[1], $point[0], $point[1], $line + ); + $temp_point = $point; + } + } + unset($temp_point); + // print label + if (isset($label) && trim($label) != '' && $first_line) { + $pdf->SetXY($points_arr[1][0], $points_arr[1][1]); + $pdf->SetFontSize(5); + $pdf->Cell(0, 0, trim($label)); + } + $first_line = false; + } + return $pdf; + } + + /** + * Prepares and returns the code related to a row in the GIS dataset as SVG. + * + * @param string $spatial GIS MULTILINESTRING object + * @param string $label Label for the GIS MULTILINESTRING object + * @param string $line_color Color for the GIS MULTILINESTRING object + * @param array $scale_data Array containing data related to scaling + * + * @return string the code related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsSvg($spatial, $label, $line_color, $scale_data) + { + $line_options = array( + 'name' => $label, + 'class' => 'linestring vector', + 'fill' => 'none', + 'stroke' => $line_color, + 'stroke-width'=> 2, + ); + + // Trim to remove leading 'MULTILINESTRING((' and trailing '))' + $multilinestirng = substr($spatial, 17, (strlen($spatial) - 19)); + // Seperate each linestring + $linestirngs = explode("),(", $multilinestirng); + + $row = ''; + foreach ($linestirngs as $linestring) { + $points_arr = $this->extractPoints($linestring, $scale_data); + + $row .= ' $val) { + $row .= ' ' . $option . '="' . trim($val) . '"'; + } + $row .= '/>'; + } + + return $row; + } + + /** + * Prepares JavaScript related to a row in the GIS dataset + * to visualize it with OpenLayers. + * + * @param string $spatial GIS MULTILINESTRING object + * @param int $srid Spatial reference ID + * @param string $label Label for the GIS MULTILINESTRING object + * @param string $line_color Color for the GIS MULTILINESTRING object + * @param array $scale_data Array containing data related to scaling + * + * @return string JavaScript related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsOl($spatial, $srid, $label, $line_color, $scale_data) + { + $style_options = array( + 'strokeColor' => $line_color, + 'strokeWidth' => 2, + 'label' => $label, + 'fontSize' => 10, + ); + if ($srid == 0) { + $srid = 4326; + } + $row = $this->getBoundsForOl($srid, $scale_data); + + // Trim to remove leading 'MULTILINESTRING((' and trailing '))' + $multilinestirng = substr($spatial, 17, (strlen($spatial) - 19)); + // Seperate each linestring + $linestirngs = explode("),(", $multilinestirng); + + $row .= 'vectorLayer.addFeatures(new OpenLayers.Feature.Vector(' + . 'new OpenLayers.Geometry.MultiLineString(' + . $this->getLineArrayForOpenLayers($linestirngs, $srid) + . '), null, ' . json_encode($style_options) . '));'; + return $row; + } + + /** + * Generate the WKT with the set of parameters passed by the GIS editor. + * + * @param array $gis_data GIS data + * @param int $index Index into the parameter object + * @param string $empty Value for empty points + * + * @return string WKT with the set of parameters passed by the GIS editor + * @access public + */ + public function generateWkt($gis_data, $index, $empty = '') + { + $data_row = $gis_data[$index]['MULTILINESTRING']; + + $no_of_lines = isset($data_row['no_of_lines']) + ? $data_row['no_of_lines'] : 1; + if ($no_of_lines < 1) { + $no_of_lines = 1; + } + $wkt = 'MULTILINESTRING('; + for ($i = 0; $i < $no_of_lines; $i++) { + $no_of_points = isset($data_row[$i]['no_of_points']) + ? $data_row[$i]['no_of_points'] : 2; + if ($no_of_points < 2) { + $no_of_points = 2; + } + $wkt .= '('; + for ($j = 0; $j < $no_of_points; $j++) { + $wkt .= ((isset($data_row[$i][$j]['x']) + && trim($data_row[$i][$j]['x']) != '') + ? $data_row[$i][$j]['x'] : $empty) + . ' ' . ((isset($data_row[$i][$j]['y']) + && trim($data_row[$i][$j]['y']) != '') + ? $data_row[$i][$j]['y'] : $empty) . ','; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= '),'; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= ')'; + return $wkt; + } + + /** + * Generate the WKT for the data from ESRI shape files. + * + * @param array $row_data GIS data + * + * @return string the WKT for the data from ESRI shape files + * @access public + */ + public function getShape($row_data) + { + $wkt = 'MULTILINESTRING('; + for ($i = 0; $i < $row_data['numparts']; $i++) { + $wkt .= '('; + foreach ($row_data['parts'][$i]['points'] as $point) { + $wkt .= $point['x'] . ' ' . $point['y'] . ','; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= '),'; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= ')'; + return $wkt; + } + + /** + * Generate parameters for the GIS data editor from the value of the GIS column. + * + * @param string $value of the GIS column + * @param index $index of the geometry + * + * @return array params for the GIS data editor from the value of the GIS column + * @access public + */ + public function generateParams($value, $index = -1) + { + if ($index == -1) { + $index = 0; + $params = array(); + $data = PMA_GIS_Geometry::generateParams($value); + $params['srid'] = $data['srid']; + $wkt = $data['wkt']; + } else { + $params[$index]['gis_type'] = 'MULTILINESTRING'; + $wkt = $value; + } + + // Trim to remove leading 'MULTILINESTRING((' and trailing '))' + $multilinestirng = substr($wkt, 17, (strlen($wkt) - 19)); + // Seperate each linestring + $linestirngs = explode("),(", $multilinestirng); + $params[$index]['MULTILINESTRING']['no_of_lines'] = count($linestirngs); + + $j = 0; + foreach ($linestirngs as $linestring) { + $points_arr = $this->extractPoints($linestring, null); + $no_of_points = count($points_arr); + $params[$index]['MULTILINESTRING'][$j]['no_of_points'] = $no_of_points; + for ($i = 0; $i < $no_of_points; $i++) { + $params[$index]['MULTILINESTRING'][$j][$i]['x'] = $points_arr[$i][0]; + $params[$index]['MULTILINESTRING'][$j][$i]['y'] = $points_arr[$i][1]; + } + $j++; + } + return $params; + } +} +?> diff --git a/phpmyadmin/libraries/gis/pma_gis_multipoint.php b/phpmyadmin/libraries/gis/pma_gis_multipoint.php new file mode 100644 index 000000000..e6b7ef71a --- /dev/null +++ b/phpmyadmin/libraries/gis/pma_gis_multipoint.php @@ -0,0 +1,343 @@ +setMinMax($multipoint, array()); + } + + /** + * Adds to the PNG image object, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS MULTIPOINT object + * @param string $label Label for the GIS MULTIPOINT object + * @param string $point_color Color for the GIS MULTIPOINT object + * @param array $scale_data Array containing data related to scaling + * @param object $image Image object + * + * @return object the modified image object + * @access public + */ + public function prepareRowAsPng($spatial, $label, $point_color, + $scale_data, $image + ) { + // allocate colors + $black = imagecolorallocate($image, 0, 0, 0); + $red = hexdec(substr($point_color, 1, 2)); + $green = hexdec(substr($point_color, 3, 2)); + $blue = hexdec(substr($point_color, 4, 2)); + $color = imagecolorallocate($image, $red, $green, $blue); + + // Trim to remove leading 'MULTIPOINT(' and trailing ')' + $multipoint = substr($spatial, 11, (strlen($spatial) - 12)); + $points_arr = $this->extractPoints($multipoint, $scale_data); + + foreach ($points_arr as $point) { + // draw a small circle to mark the point + if ($point[0] != '' && $point[1] != '') { + imagearc($image, $point[0], $point[1], 7, 7, 0, 360, $color); + } + } + // print label for each point + if ((isset($label) && trim($label) != '') + && ($points_arr[0][0] != '' && $points_arr[0][1] != '') + ) { + imagestring( + $image, 1, $points_arr[0][0], $points_arr[0][1], trim($label), $black + ); + } + return $image; + } + + /** + * Adds to the TCPDF instance, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS MULTIPOINT object + * @param string $label Label for the GIS MULTIPOINT object + * @param string $point_color Color for the GIS MULTIPOINT object + * @param array $scale_data Array containing data related to scaling + * @param object $pdf TCPDF instance + * + * @return object the modified TCPDF instance + * @access public + */ + public function prepareRowAsPdf($spatial, $label, $point_color, + $scale_data, $pdf + ) { + // allocate colors + $red = hexdec(substr($point_color, 1, 2)); + $green = hexdec(substr($point_color, 3, 2)); + $blue = hexdec(substr($point_color, 4, 2)); + $line = array('width' => 1.25, 'color' => array($red, $green, $blue)); + + // Trim to remove leading 'MULTIPOINT(' and trailing ')' + $multipoint = substr($spatial, 11, (strlen($spatial) - 12)); + $points_arr = $this->extractPoints($multipoint, $scale_data); + + foreach ($points_arr as $point) { + // draw a small circle to mark the point + if ($point[0] != '' && $point[1] != '') { + $pdf->Circle($point[0], $point[1], 2, 0, 360, 'D', $line); + } + } + // print label for each point + if ((isset($label) && trim($label) != '') + && ($points_arr[0][0] != '' && $points_arr[0][1] != '') + ) { + $pdf->SetXY($points_arr[0][0], $points_arr[0][1]); + $pdf->SetFontSize(5); + $pdf->Cell(0, 0, trim($label)); + } + return $pdf; + } + + /** + * Prepares and returns the code related to a row in the GIS dataset as SVG. + * + * @param string $spatial GIS MULTIPOINT object + * @param string $label Label for the GIS MULTIPOINT object + * @param string $point_color Color for the GIS MULTIPOINT object + * @param array $scale_data Array containing data related to scaling + * + * @return string the code related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsSvg($spatial, $label, $point_color, $scale_data) + { + $point_options = array( + 'name' => $label, + 'class' => 'multipoint vector', + 'fill' => 'white', + 'stroke' => $point_color, + 'stroke-width'=> 2, + ); + + // Trim to remove leading 'MULTIPOINT(' and trailing ')' + $multipoint = substr($spatial, 11, (strlen($spatial) - 12)); + $points_arr = $this->extractPoints($multipoint, $scale_data); + + $row = ''; + foreach ($points_arr as $point) { + if ($point[0] != '' && $point[1] != '') { + $row .= ' $val) { + $row .= ' ' . $option . '="' . trim($val) . '"'; + } + $row .= '/>'; + } + } + + return $row; + } + + /** + * Prepares JavaScript related to a row in the GIS dataset + * to visualize it with OpenLayers. + * + * @param string $spatial GIS MULTIPOINT object + * @param int $srid Spatial reference ID + * @param string $label Label for the GIS MULTIPOINT object + * @param string $point_color Color for the GIS MULTIPOINT object + * @param array $scale_data Array containing data related to scaling + * + * @return string JavaScript related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsOl($spatial, $srid, $label, + $point_color, $scale_data + ) { + $style_options = array( + 'pointRadius' => 3, + 'fillColor' => '#ffffff', + 'strokeColor' => $point_color, + 'strokeWidth' => 2, + 'label' => $label, + 'labelYOffset' => -8, + 'fontSize' => 10, + ); + if ($srid == 0) { + $srid = 4326; + } + $result = $this->getBoundsForOl($srid, $scale_data); + + // Trim to remove leading 'MULTIPOINT(' and trailing ')' + $multipoint = substr($spatial, 11, (strlen($spatial) - 12)); + $points_arr = $this->extractPoints($multipoint, null); + + $result .= 'vectorLayer.addFeatures(new OpenLayers.Feature.Vector(' + . 'new OpenLayers.Geometry.MultiPoint(' + . $this->getPointsArrayForOpenLayers($points_arr, $srid) + . '), null, ' . json_encode($style_options) . '));'; + return $result; + } + + /** + * Generate the WKT with the set of parameters passed by the GIS editor. + * + * @param array $gis_data GIS data + * @param int $index Index into the parameter object + * @param string $empty Multipoint does not adhere to this + * + * @return string WKT with the set of parameters passed by the GIS editor + * @access public + */ + public function generateWkt($gis_data, $index, $empty = '') + { + $no_of_points = isset($gis_data[$index]['MULTIPOINT']['no_of_points']) + ? $gis_data[$index]['MULTIPOINT']['no_of_points'] : 1; + if ($no_of_points < 1) { + $no_of_points = 1; + } + $wkt = 'MULTIPOINT('; + for ($i = 0; $i < $no_of_points; $i++) { + $wkt .= ((isset($gis_data[$index]['MULTIPOINT'][$i]['x']) + && trim($gis_data[$index]['MULTIPOINT'][$i]['x']) != '') + ? $gis_data[$index]['MULTIPOINT'][$i]['x'] : '') + . ' ' . ((isset($gis_data[$index]['MULTIPOINT'][$i]['y']) + && trim($gis_data[$index]['MULTIPOINT'][$i]['y']) != '') + ? $gis_data[$index]['MULTIPOINT'][$i]['y'] : '') . ','; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= ')'; + return $wkt; + } + + /** + * Generate the WKT for the data from ESRI shape files. + * + * @param array $row_data GIS data + * + * @return string the WKT for the data from ESRI shape files + * @access public + */ + public function getShape($row_data) + { + $wkt = 'MULTIPOINT('; + for ($i = 0; $i < $row_data['numpoints']; $i++) { + $wkt .= $row_data['points'][$i]['x'] . ' ' + . $row_data['points'][$i]['y'] . ','; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= ')'; + return $wkt; + } + + /** + * Generate parameters for the GIS data editor from the value of the GIS column. + * + * @param string $value of the GIS column + * @param index $index of the geometry + * + * @return array params for the GIS data editor from the value of the GIS column + * @access public + */ + public function generateParams($value, $index = -1) + { + if ($index == -1) { + $index = 0; + $params = array(); + $data = PMA_GIS_Geometry::generateParams($value); + $params['srid'] = $data['srid']; + $wkt = $data['wkt']; + } else { + $params[$index]['gis_type'] = 'MULTIPOINT'; + $wkt = $value; + } + + // Trim to remove leading 'MULTIPOINT(' and trailing ')' + $points = substr($wkt, 11, (strlen($wkt) - 12)); + $points_arr = $this->extractPoints($points, null); + + $no_of_points = count($points_arr); + $params[$index]['MULTIPOINT']['no_of_points'] = $no_of_points; + for ($i = 0; $i < $no_of_points; $i++) { + $params[$index]['MULTIPOINT'][$i]['x'] = $points_arr[$i][0]; + $params[$index]['MULTIPOINT'][$i]['y'] = $points_arr[$i][1]; + } + + return $params; + } + + /** + * Overidden to make sure that only the points having valid values + * for x and y coordinates are added. + * + * @param array $points_arr x and y coordinates for each point + * @param string $srid spatial reference id + * + * @return string JavaScript for adding an array of points to OpenLayers + * @access protected + */ + protected function getPointsArrayForOpenLayers($points_arr, $srid) + { + $ol_array = 'new Array('; + foreach ($points_arr as $point) { + if ($point[0] != '' && $point[1] != '') { + $ol_array .= $this->getPointForOpenLayers($point, $srid) . ', '; + } + } + if (substr($ol_array, strlen($ol_array) - 2) == ', ') { + $ol_array = substr($ol_array, 0, strlen($ol_array) - 2); + } + $ol_array .= ')'; + + return $ol_array; + } +} +?> diff --git a/phpmyadmin/libraries/gis/pma_gis_multipolygon.php b/phpmyadmin/libraries/gis/pma_gis_multipolygon.php new file mode 100644 index 000000000..a8c824152 --- /dev/null +++ b/phpmyadmin/libraries/gis/pma_gis_multipolygon.php @@ -0,0 +1,527 @@ +setMinMax($ring, $min_max); + } + + return $min_max; + } + + /** + * Adds to the PNG image object, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS MULTIPOLYGON object + * @param string $label Label for the GIS MULTIPOLYGON object + * @param string $fill_color Color for the GIS MULTIPOLYGON object + * @param array $scale_data Array containing data related to scaling + * @param object $image Image object + * + * @return object the modified image object + * @access public + */ + public function prepareRowAsPng($spatial, $label, $fill_color, + $scale_data, $image + ) { + // allocate colors + $black = imagecolorallocate($image, 0, 0, 0); + $red = hexdec(substr($fill_color, 1, 2)); + $green = hexdec(substr($fill_color, 3, 2)); + $blue = hexdec(substr($fill_color, 4, 2)); + $color = imagecolorallocate($image, $red, $green, $blue); + + // Trim to remove leading 'MULTIPOLYGON(((' and trailing ')))' + $multipolygon = substr($spatial, 15, (strlen($spatial) - 18)); + // Seperate each polygon + $polygons = explode(")),((", $multipolygon); + + $first_poly = true; + foreach ($polygons as $polygon) { + // If the polygon doesnt have an inner polygon + if (strpos($polygon, "),(") === false) { + $points_arr = $this->extractPoints($polygon, $scale_data, true); + } else { + // Seperate outer and inner polygons + $parts = explode("),(", $polygon); + $outer = $parts[0]; + $inner = array_slice($parts, 1); + + $points_arr = $this->extractPoints($outer, $scale_data, true); + + foreach ($inner as $inner_poly) { + $points_arr = array_merge( + $points_arr, + $this->extractPoints($inner_poly, $scale_data, true) + ); + } + } + // draw polygon + imagefilledpolygon($image, $points_arr, sizeof($points_arr) / 2, $color); + // mark label point if applicable + if (isset($label) && trim($label) != '' && $first_poly) { + $label_point = array($points_arr[2], $points_arr[3]); + } + $first_poly = false; + } + // print label if applicable + if (isset($label_point)) { + imagestring( + $image, 1, $points_arr[2], $points_arr[3], trim($label), $black + ); + } + return $image; + } + + /** + * Adds to the TCPDF instance, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS MULTIPOLYGON object + * @param string $label Label for the GIS MULTIPOLYGON object + * @param string $fill_color Color for the GIS MULTIPOLYGON object + * @param array $scale_data Array containing data related to scaling + * @param object $pdf TCPDF instance + * + * @return object the modified TCPDF instance + * @access public + */ + public function prepareRowAsPdf($spatial, $label, $fill_color, $scale_data, $pdf) + { + // allocate colors + $red = hexdec(substr($fill_color, 1, 2)); + $green = hexdec(substr($fill_color, 3, 2)); + $blue = hexdec(substr($fill_color, 4, 2)); + $color = array($red, $green, $blue); + + // Trim to remove leading 'MULTIPOLYGON(((' and trailing ')))' + $multipolygon = substr($spatial, 15, (strlen($spatial) - 18)); + // Seperate each polygon + $polygons = explode(")),((", $multipolygon); + + $first_poly = true; + foreach ($polygons as $polygon) { + // If the polygon doesnt have an inner polygon + if (strpos($polygon, "),(") === false) { + $points_arr = $this->extractPoints($polygon, $scale_data, true); + } else { + // Seperate outer and inner polygons + $parts = explode("),(", $polygon); + $outer = $parts[0]; + $inner = array_slice($parts, 1); + + $points_arr = $this->extractPoints($outer, $scale_data, true); + + foreach ($inner as $inner_poly) { + $points_arr = array_merge( + $points_arr, + $this->extractPoints($inner_poly, $scale_data, true) + ); + } + } + // draw polygon + $pdf->Polygon($points_arr, 'F*', array(), $color, true); + // mark label point if applicable + if (isset($label) && trim($label) != '' && $first_poly) { + $label_point = array($points_arr[2], $points_arr[3]); + } + $first_poly = false; + } + + // print label if applicable + if (isset($label_point)) { + $pdf->SetXY($label_point[0], $label_point[1]); + $pdf->SetFontSize(5); + $pdf->Cell(0, 0, trim($label)); + } + return $pdf; + } + + /** + * Prepares and returns the code related to a row in the GIS dataset as SVG. + * + * @param string $spatial GIS MULTIPOLYGON object + * @param string $label Label for the GIS MULTIPOLYGON object + * @param string $fill_color Color for the GIS MULTIPOLYGON object + * @param array $scale_data Array containing data related to scaling + * + * @return string the code related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsSvg($spatial, $label, $fill_color, $scale_data) + { + $polygon_options = array( + 'name' => $label, + 'class' => 'multipolygon vector', + 'stroke' => 'black', + 'stroke-width'=> 0.5, + 'fill' => $fill_color, + 'fill-rule' => 'evenodd', + 'fill-opacity'=> 0.8, + ); + + $row = ''; + + // Trim to remove leading 'MULTIPOLYGON(((' and trailing ')))' + $multipolygon = substr($spatial, 15, (strlen($spatial) - 18)); + // Seperate each polygon + $polygons = explode(")),((", $multipolygon); + + foreach ($polygons as $polygon) { + $row .= '_drawPath($polygon, $scale_data); + } else { + // Seperate outer and inner polygons + $parts = explode("),(", $polygon); + $outer = $parts[0]; + $inner = array_slice($parts, 1); + + $row .= $this->_drawPath($outer, $scale_data); + + foreach ($inner as $inner_poly) { + $row .= $this->_drawPath($inner_poly, $scale_data); + } + } + $polygon_options['id'] = $label . rand(); + $row .= '"'; + foreach ($polygon_options as $option => $val) { + $row .= ' ' . $option . '="' . trim($val) . '"'; + } + $row .= '/>'; + } + + return $row; + } + + /** + * Prepares JavaScript related to a row in the GIS dataset + * to visualize it with OpenLayers. + * + * @param string $spatial GIS MULTIPOLYGON object + * @param int $srid Spatial reference ID + * @param string $label Label for the GIS MULTIPOLYGON object + * @param string $fill_color Color for the GIS MULTIPOLYGON object + * @param array $scale_data Array containing data related to scaling + * + * @return string JavaScript related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsOl($spatial, $srid, $label, $fill_color, $scale_data) + { + $style_options = array( + 'strokeColor' => '#000000', + 'strokeWidth' => 0.5, + 'fillColor' => $fill_color, + 'fillOpacity' => 0.8, + 'label' => $label, + 'fontSize' => 10, + ); + if ($srid == 0) { + $srid = 4326; + } + $row = $this->getBoundsForOl($srid, $scale_data); + + // Trim to remove leading 'MULTIPOLYGON(((' and trailing ')))' + $multipolygon = substr($spatial, 15, (strlen($spatial) - 18)); + // Seperate each polygon + $polygons = explode(")),((", $multipolygon); + + $row .= 'vectorLayer.addFeatures(new OpenLayers.Feature.Vector(' + . 'new OpenLayers.Geometry.MultiPolygon(' + . $this->getPolygonArrayForOpenLayers($polygons, $srid) + . '), null, ' . json_encode($style_options) . '));'; + return $row; + } + + /** + * Draws a ring of the polygon using SVG path element. + * + * @param string $polygon The ring + * @param array $scale_data Array containing data related to scaling + * + * @return string the code to draw the ring + * @access private + */ + private function _drawPath($polygon, $scale_data) + { + $points_arr = $this->extractPoints($polygon, $scale_data); + + $row = ' M ' . $points_arr[0][0] . ', ' . $points_arr[0][1]; + $other_points = array_slice($points_arr, 1, count($points_arr) - 2); + foreach ($other_points as $point) { + $row .= ' L ' . $point[0] . ', ' . $point[1]; + } + $row .= ' Z '; + + return $row; + } + + /** + * Generate the WKT with the set of parameters passed by the GIS editor. + * + * @param array $gis_data GIS data + * @param int $index Index into the parameter object + * @param string $empty Value for empty points + * + * @return string WKT with the set of parameters passed by the GIS editor + * @access public + */ + public function generateWkt($gis_data, $index, $empty = '') + { + $data_row = $gis_data[$index]['MULTIPOLYGON']; + + $no_of_polygons = isset($data_row['no_of_polygons']) + ? $data_row['no_of_polygons'] : 1; + if ($no_of_polygons < 1) { + $no_of_polygons = 1; + } + + $wkt = 'MULTIPOLYGON('; + for ($k = 0; $k < $no_of_polygons; $k++) { + $no_of_lines = isset($data_row[$k]['no_of_lines']) + ? $data_row[$k]['no_of_lines'] : 1; + if ($no_of_lines < 1) { + $no_of_lines = 1; + } + $wkt .= '('; + for ($i = 0; $i < $no_of_lines; $i++) { + $no_of_points = isset($data_row[$k][$i]['no_of_points']) + ? $data_row[$k][$i]['no_of_points'] : 4; + if ($no_of_points < 4) { + $no_of_points = 4; + } + $wkt .= '('; + for ($j = 0; $j < $no_of_points; $j++) { + $wkt .= ((isset($data_row[$k][$i][$j]['x']) + && trim($data_row[$k][$i][$j]['x']) != '') + ? $data_row[$k][$i][$j]['x'] : $empty) + . ' ' . ((isset($data_row[$k][$i][$j]['y']) + && trim($data_row[$k][$i][$j]['y']) != '') + ? $data_row[$k][$i][$j]['y'] : $empty) .','; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= '),'; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= '),'; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= ')'; + return $wkt; + } + + /** + * Generate the WKT for the data from ESRI shape files. + * + * @param array $row_data GIS data + * + * @return string the WKT for the data from ESRI shape files + * @access public + */ + public function getShape($row_data) + { + // Determines whether each line ring is an inner ring or an outer ring. + // If it's an inner ring get a point on the surface which can be used to + // correctly classify inner rings to their respective outer rings. + include_once './libraries/gis/pma_gis_polygon.php'; + foreach ($row_data['parts'] as $i => $ring) { + $row_data['parts'][$i]['isOuter'] + = PMA_GIS_Polygon::isOuterRing($ring['points']); + } + + // Find points on surface for inner rings + foreach ($row_data['parts'] as $i => $ring) { + if (! $ring['isOuter']) { + $row_data['parts'][$i]['pointOnSurface'] + = PMA_GIS_Polygon::getPointOnSurface($ring['points']); + } + } + + // Classify inner rings to their respective outer rings. + foreach ($row_data['parts'] as $j => $ring1) { + if (! $ring1['isOuter']) { + foreach ($row_data['parts'] as $k => $ring2) { + if ($ring2['isOuter']) { + // If the pointOnSurface of the inner ring + // is also inside the outer ring + if (PMA_GIS_Polygon::isPointInsidePolygon( + $ring1['pointOnSurface'], $ring2['points'] + )) { + if (! isset($ring2['inner'])) { + $row_data['parts'][$k]['inner'] = array(); + } + $row_data['parts'][$k]['inner'][] = $j; + } + } + } + } + } + + $wkt = 'MULTIPOLYGON('; + // for each polygon + foreach ($row_data['parts'] as $ring) { + if ($ring['isOuter']) { + $wkt .= '('; // start of polygon + + $wkt .= '('; // start of outer ring + foreach ($ring['points'] as $point) { + $wkt .= $point['x'] . ' ' . $point['y'] . ','; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= ')'; // end of outer ring + + // inner rings if any + if (isset($ring['inner'])) { + foreach ($ring['inner'] as $j) { + $wkt .= ',('; // start of inner ring + foreach ($row_data['parts'][$j]['points'] as $innerPoint) { + $wkt .= $innerPoint['x'] . ' ' . $innerPoint['y'] . ','; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= ')'; // end of inner ring + } + } + + $wkt .= '),'; // end of polygon + } + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + + $wkt .= ')'; // end of multipolygon + return $wkt; + } + + /** + * Generate parameters for the GIS data editor from the value of the GIS column. + * + * @param string $value of the GIS column + * @param index $index of the geometry + * + * @return array params for the GIS data editor from the value of the GIS column + * @access public + */ + public function generateParams($value, $index = -1) + { + if ($index == -1) { + $index = 0; + $params = array(); + $data = PMA_GIS_Geometry::generateParams($value); + $params['srid'] = $data['srid']; + $wkt = $data['wkt']; + } else { + $params[$index]['gis_type'] = 'MULTIPOLYGON'; + $wkt = $value; + } + + // Trim to remove leading 'MULTIPOLYGON(((' and trailing ')))' + $multipolygon = substr($wkt, 15, (strlen($wkt) - 18)); + // Seperate each polygon + $polygons = explode(")),((", $multipolygon); + + $param_row =& $params[$index]['MULTIPOLYGON']; + $param_row['no_of_polygons'] = count($polygons); + + $k = 0; + foreach ($polygons as $polygon) { + // If the polygon doesnt have an inner polygon + if (strpos($polygon, "),(") === false) { + $param_row[$k]['no_of_lines'] = 1; + $points_arr = $this->extractPoints($polygon, null); + $no_of_points = count($points_arr); + $param_row[$k][0]['no_of_points'] = $no_of_points; + for ($i = 0; $i < $no_of_points; $i++) { + $param_row[$k][0][$i]['x'] = $points_arr[$i][0]; + $param_row[$k][0][$i]['y'] = $points_arr[$i][1]; + } + } else { + // Seperate outer and inner polygons + $parts = explode("),(", $polygon); + $param_row[$k]['no_of_lines'] = count($parts); + $j = 0; + foreach ($parts as $ring) { + $points_arr = $this->extractPoints($ring, null); + $no_of_points = count($points_arr); + $param_row[$k][$j]['no_of_points'] = $no_of_points; + for ($i = 0; $i < $no_of_points; $i++) { + $param_row[$k][$j][$i]['x'] = $points_arr[$i][0]; + $param_row[$k][$j][$i]['y'] = $points_arr[$i][1]; + } + $j++; + } + } + $k++; + } + return $params; + } +} +?> diff --git a/phpmyadmin/libraries/gis/pma_gis_point.php b/phpmyadmin/libraries/gis/pma_gis_point.php new file mode 100644 index 000000000..e1e4d2370 --- /dev/null +++ b/phpmyadmin/libraries/gis/pma_gis_point.php @@ -0,0 +1,294 @@ +setMinMax($point, array()); + } + + /** + * Adds to the PNG image object, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS POINT object + * @param string $label Label for the GIS POINT object + * @param string $point_color Color for the GIS POINT object + * @param array $scale_data Array containing data related to scaling + * @param object $image Image object + * + * @return object the modified image object + * @access public + */ + public function prepareRowAsPng($spatial, $label, $point_color, + $scale_data, $image + ) { + // allocate colors + $black = imagecolorallocate($image, 0, 0, 0); + $red = hexdec(substr($point_color, 1, 2)); + $green = hexdec(substr($point_color, 3, 2)); + $blue = hexdec(substr($point_color, 4, 2)); + $color = imagecolorallocate($image, $red, $green, $blue); + + // Trim to remove leading 'POINT(' and trailing ')' + $point = substr($spatial, 6, (strlen($spatial) - 7)); + $points_arr = $this->extractPoints($point, $scale_data); + + // draw a small circle to mark the point + if ($points_arr[0][0] != '' && $points_arr[0][1] != '') { + imagearc( + $image, $points_arr[0][0], $points_arr[0][1], 7, 7, 0, 360, $color + ); + // print label if applicable + if (isset($label) && trim($label) != '') { + imagestring( + $image, 1, $points_arr[0][0], + $points_arr[0][1], trim($label), $black + ); + } + } + return $image; + } + + /** + * Adds to the TCPDF instance, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS POINT object + * @param string $label Label for the GIS POINT object + * @param string $point_color Color for the GIS POINT object + * @param array $scale_data Array containing data related to scaling + * @param object $pdf TCPDF instance + * + * @return object the modified TCPDF instance + * @access public + */ + public function prepareRowAsPdf($spatial, $label, $point_color, + $scale_data, $pdf + ) { + // allocate colors + $red = hexdec(substr($point_color, 1, 2)); + $green = hexdec(substr($point_color, 3, 2)); + $blue = hexdec(substr($point_color, 4, 2)); + $line = array('width' => 1.25, 'color' => array($red, $green, $blue)); + + // Trim to remove leading 'POINT(' and trailing ')' + $point = substr($spatial, 6, (strlen($spatial) - 7)); + $points_arr = $this->extractPoints($point, $scale_data); + + // draw a small circle to mark the point + if ($points_arr[0][0] != '' && $points_arr[0][1] != '') { + $pdf->Circle( + $points_arr[0][0], $points_arr[0][1], 2, 0, 360, 'D', $line + ); + // print label if applicable + if (isset($label) && trim($label) != '') { + $pdf->SetXY($points_arr[0][0], $points_arr[0][1]); + $pdf->SetFontSize(5); + $pdf->Cell(0, 0, trim($label)); + } + } + return $pdf; + } + + /** + * Prepares and returns the code related to a row in the GIS dataset as SVG. + * + * @param string $spatial GIS POINT object + * @param string $label Label for the GIS POINT object + * @param string $point_color Color for the GIS POINT object + * @param array $scale_data Array containing data related to scaling + * + * @return string the code related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsSvg($spatial, $label, $point_color, $scale_data) + { + $point_options = array( + 'name' => $label, + 'id' => $label . rand(), + 'class' => 'point vector', + 'fill' => 'white', + 'stroke' => $point_color, + 'stroke-width'=> 2, + ); + + // Trim to remove leading 'POINT(' and trailing ')' + $point = substr($spatial, 6, (strlen($spatial) - 7)); + $points_arr = $this->extractPoints($point, $scale_data); + + $row = ''; + if ($points_arr[0][0] != '' && $points_arr[0][1] != '') { + $row .= ' $val) { + $row .= ' ' . $option . '="' . trim($val) . '"'; + } + $row .= '/>'; + } + + return $row; + } + + /** + * Prepares JavaScript related to a row in the GIS dataset + * to visualize it with OpenLayers. + * + * @param string $spatial GIS POINT object + * @param int $srid Spatial reference ID + * @param string $label Label for the GIS POINT object + * @param string $point_color Color for the GIS POINT object + * @param array $scale_data Array containing data related to scaling + * + * @return string JavaScript related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsOl($spatial, $srid, $label, + $point_color, $scale_data + ) { + $style_options = array( + 'pointRadius' => 3, + 'fillColor' => '#ffffff', + 'strokeColor' => $point_color, + 'strokeWidth' => 2, + 'label' => $label, + 'labelYOffset' => -8, + 'fontSize' => 10, + ); + if ($srid == 0) { + $srid = 4326; + } + $result = $this->getBoundsForOl($srid, $scale_data); + + // Trim to remove leading 'POINT(' and trailing ')' + $point = substr($spatial, 6, (strlen($spatial) - 7)); + $points_arr = $this->extractPoints($point, null); + + if ($points_arr[0][0] != '' && $points_arr[0][1] != '') { + $result .= 'vectorLayer.addFeatures(new OpenLayers.Feature.Vector(' + . $this->getPointForOpenLayers($points_arr[0], $srid). ', null, ' + . json_encode($style_options) . '));'; + } + return $result; + } + + /** + * Generate the WKT with the set of parameters passed by the GIS editor. + * + * @param array $gis_data GIS data + * @param int $index Index into the parameter object + * @param string $empty Point deos not adhere to this parameter + * + * @return string WKT with the set of parameters passed by the GIS editor + * @access public + */ + public function generateWkt($gis_data, $index, $empty = '') + { + return 'POINT(' + . ((isset($gis_data[$index]['POINT']['x']) + && trim($gis_data[$index]['POINT']['x']) != '') + ? $gis_data[$index]['POINT']['x'] : '') + . ' ' + . ((isset($gis_data[$index]['POINT']['y']) + && trim($gis_data[$index]['POINT']['y']) != '') + ? $gis_data[$index]['POINT']['y'] : '') . ')'; + } + + /** + * Generate the WKT for the data from ESRI shape files. + * + * @param array $row_data GIS data + * + * @return string the WKT for the data from ESRI shape files + * @access public + */ + public function getShape($row_data) + { + return 'POINT(' . (isset($row_data['x']) ? $row_data['x'] : '') + . ' ' . (isset($row_data['y']) ? $row_data['y'] : '') . ')'; + } + + /** + * Generate parameters for the GIS data editor from the value of the GIS column. + * + * @param string $value of the GIS column + * @param index $index of the geometry + * + * @return array params for the GIS data editor from the value of the GIS column + * @access public + */ + public function generateParams($value, $index = -1) + { + if ($index == -1) { + $index = 0; + $params = array(); + $data = PMA_GIS_Geometry::generateParams($value); + $params['srid'] = $data['srid']; + $wkt = $data['wkt']; + } else { + $params[$index]['gis_type'] = 'POINT'; + $wkt = $value; + } + + // Trim to remove leading 'POINT(' and trailing ')' + $point = substr($wkt, 6, (strlen($wkt) - 7)); + $points_arr = $this->extractPoints($point, null); + + $params[$index]['POINT']['x'] = $points_arr[0][0]; + $params[$index]['POINT']['y'] = $points_arr[0][1]; + + return $params; + } +} +?> diff --git a/phpmyadmin/libraries/gis/pma_gis_polygon.php b/phpmyadmin/libraries/gis/pma_gis_polygon.php new file mode 100644 index 000000000..47dde132f --- /dev/null +++ b/phpmyadmin/libraries/gis/pma_gis_polygon.php @@ -0,0 +1,549 @@ +setMinMax($ring, array()); + } + + /** + * Adds to the PNG image object, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS POLYGON object + * @param string $label Label for the GIS POLYGON object + * @param string $fill_color Color for the GIS POLYGON object + * @param array $scale_data Array containing data related to scaling + * @param object $image Image object + * + * @return object the modified image object + * @access public + */ + public function prepareRowAsPng($spatial, $label, $fill_color, + $scale_data, $image + ) { + // allocate colors + $black = imagecolorallocate($image, 0, 0, 0); + $red = hexdec(substr($fill_color, 1, 2)); + $green = hexdec(substr($fill_color, 3, 2)); + $blue = hexdec(substr($fill_color, 4, 2)); + $color = imagecolorallocate($image, $red, $green, $blue); + + // Trim to remove leading 'POLYGON((' and trailing '))' + $polygon = substr($spatial, 9, (strlen($spatial) - 11)); + + // If the polygon doesnt have an inner polygon + if (strpos($polygon, "),(") === false) { + $points_arr = $this->extractPoints($polygon, $scale_data, true); + } else { + // Seperate outer and inner polygons + $parts = explode("),(", $polygon); + $outer = $parts[0]; + $inner = array_slice($parts, 1); + + $points_arr = $this->extractPoints($outer, $scale_data, true); + + foreach ($inner as $inner_poly) { + $points_arr = array_merge( + $points_arr, $this->extractPoints($inner_poly, $scale_data, true) + ); + } + } + + // draw polygon + imagefilledpolygon($image, $points_arr, sizeof($points_arr) / 2, $color); + // print label if applicable + if (isset($label) && trim($label) != '') { + imagestring( + $image, 1, $points_arr[2], $points_arr[3], trim($label), $black + ); + } + return $image; + } + + /** + * Adds to the TCPDF instance, the data related to a row in the GIS dataset. + * + * @param string $spatial GIS POLYGON object + * @param string $label Label for the GIS POLYGON object + * @param string $fill_color Color for the GIS POLYGON object + * @param array $scale_data Array containing data related to scaling + * @param object $pdf TCPDF instance + * + * @return object the modified TCPDF instance + * @access public + */ + public function prepareRowAsPdf($spatial, $label, $fill_color, $scale_data, $pdf) + { + // allocate colors + $red = hexdec(substr($fill_color, 1, 2)); + $green = hexdec(substr($fill_color, 3, 2)); + $blue = hexdec(substr($fill_color, 4, 2)); + $color = array($red, $green, $blue); + + // Trim to remove leading 'POLYGON((' and trailing '))' + $polygon = substr($spatial, 9, (strlen($spatial) - 11)); + + // If the polygon doesnt have an inner polygon + if (strpos($polygon, "),(") === false) { + $points_arr = $this->extractPoints($polygon, $scale_data, true); + } else { + // Seperate outer and inner polygons + $parts = explode("),(", $polygon); + $outer = $parts[0]; + $inner = array_slice($parts, 1); + + $points_arr = $this->extractPoints($outer, $scale_data, true); + + foreach ($inner as $inner_poly) { + $points_arr = array_merge( + $points_arr, $this->extractPoints($inner_poly, $scale_data, true) + ); + } + } + + // draw polygon + $pdf->Polygon($points_arr, 'F*', array(), $color, true); + // print label if applicable + if (isset($label) && trim($label) != '') { + $pdf->SetXY($points_arr[2], $points_arr[3]); + $pdf->SetFontSize(5); + $pdf->Cell(0, 0, trim($label)); + } + return $pdf; + } + + /** + * Prepares and returns the code related to a row in the GIS dataset as SVG. + * + * @param string $spatial GIS POLYGON object + * @param string $label Label for the GIS POLYGON object + * @param string $fill_color Color for the GIS POLYGON object + * @param array $scale_data Array containing data related to scaling + * + * @return string the code related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsSvg($spatial, $label, $fill_color, $scale_data) + { + $polygon_options = array( + 'name' => $label, + 'id' => $label . rand(), + 'class' => 'polygon vector', + 'stroke' => 'black', + 'stroke-width'=> 0.5, + 'fill' => $fill_color, + 'fill-rule' => 'evenodd', + 'fill-opacity'=> 0.8, + ); + + // Trim to remove leading 'POLYGON((' and trailing '))' + $polygon = substr($spatial, 9, (strlen($spatial) - 11)); + + $row = '_drawPath($polygon, $scale_data); + } else { + // Seperate outer and inner polygons + $parts = explode("),(", $polygon); + $outer = $parts[0]; + $inner = array_slice($parts, 1); + + $row .= $this->_drawPath($outer, $scale_data); + + foreach ($inner as $inner_poly) { + $row .= $this->_drawPath($inner_poly, $scale_data); + } + } + + $row .= '"'; + foreach ($polygon_options as $option => $val) { + $row .= ' ' . $option . '="' . trim($val) . '"'; + } + $row .= '/>'; + return $row; + } + + /** + * Prepares JavaScript related to a row in the GIS dataset + * to visualize it with OpenLayers. + * + * @param string $spatial GIS POLYGON object + * @param int $srid Spatial reference ID + * @param string $label Label for the GIS POLYGON object + * @param string $fill_color Color for the GIS POLYGON object + * @param array $scale_data Array containing data related to scaling + * + * @return string JavaScript related to a row in the GIS dataset + * @access public + */ + public function prepareRowAsOl($spatial, $srid, $label, $fill_color, $scale_data) + { + $style_options = array( + 'strokeColor' => '#000000', + 'strokeWidth' => 0.5, + 'fillColor' => $fill_color, + 'fillOpacity' => 0.8, + 'label' => $label, + 'fontSize' => 10, + ); + if ($srid == 0) { + $srid = 4326; + } + $row = $this->getBoundsForOl($srid, $scale_data); + + // Trim to remove leading 'POLYGON((' and trailing '))' + $polygon = substr($spatial, 9, (strlen($spatial) - 11)); + + // Seperate outer and inner polygons + $parts = explode("),(", $polygon); + $row .= 'vectorLayer.addFeatures(new OpenLayers.Feature.Vector(' + . $this->getPolygonForOpenLayers($parts, $srid) + . ', null, ' . json_encode($style_options) . '));'; + return $row; + } + + /** + * Draws a ring of the polygon using SVG path element. + * + * @param string $polygon The ring + * @param array $scale_data Array containing data related to scaling + * + * @return string the code to draw the ring + * @access private + */ + private function _drawPath($polygon, $scale_data) + { + $points_arr = $this->extractPoints($polygon, $scale_data); + + $row = ' M ' . $points_arr[0][0] . ', ' . $points_arr[0][1]; + $other_points = array_slice($points_arr, 1, count($points_arr) - 2); + foreach ($other_points as $point) { + $row .= ' L ' . $point[0] . ', ' . $point[1]; + } + $row .= ' Z '; + + return $row; + } + + /** + * Generate the WKT with the set of parameters passed by the GIS editor. + * + * @param array $gis_data GIS data + * @param int $index Index into the parameter object + * @param string $empty Value for empty points + * + * @return string WKT with the set of parameters passed by the GIS editor + * @access public + */ + public function generateWkt($gis_data, $index, $empty = '') + { + $no_of_lines = isset($gis_data[$index]['POLYGON']['no_of_lines']) + ? $gis_data[$index]['POLYGON']['no_of_lines'] : 1; + if ($no_of_lines < 1) { + $no_of_lines = 1; + } + $wkt = 'POLYGON('; + for ($i = 0; $i < $no_of_lines; $i++) { + $no_of_points = isset($gis_data[$index]['POLYGON'][$i]['no_of_points']) + ? $gis_data[$index]['POLYGON'][$i]['no_of_points'] : 4; + if ($no_of_points < 4) { + $no_of_points = 4; + } + $wkt .= '('; + for ($j = 0; $j < $no_of_points; $j++) { + $wkt .= ((isset($gis_data[$index]['POLYGON'][$i][$j]['x']) + && trim($gis_data[$index]['POLYGON'][$i][$j]['x']) != '') + ? $gis_data[$index]['POLYGON'][$i][$j]['x'] : $empty) + . ' ' . ((isset($gis_data[$index]['POLYGON'][$i][$j]['y']) + && trim($gis_data[$index]['POLYGON'][$i][$j]['y']) != '') + ? $gis_data[$index]['POLYGON'][$i][$j]['y'] : $empty) .','; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= '),'; + } + $wkt = substr($wkt, 0, strlen($wkt) - 1); + $wkt .= ')'; + return $wkt; + } + + /** + * Calculates the area of a closed simple polygon. + * + * @param array $ring array of points forming the ring + * + * @return float the area of a closed simple polygon + * @access public + * @static + */ + public static function area($ring) + { + + $no_of_points = count($ring); + + // If the last point is same as the first point ignore it + $last = count($ring) - 1; + if (($ring[0]['x'] == $ring[$last]['x']) + && ($ring[0]['y'] == $ring[$last]['y']) + ) { + $no_of_points--; + } + + // _n-1 + // A = _1_ \ (X(i) * Y(i+1)) - (Y(i) * X(i+1)) + // 2 /__ + // i=0 + $area = 0; + for ($i = 0; $i < $no_of_points; $i++) { + $j = ($i + 1) % $no_of_points; + $area += $ring[$i]['x'] * $ring[$j]['y']; + $area -= $ring[$i]['y'] * $ring[$j]['x']; + } + $area /= 2.0; + + return $area; + } + + /** + * Determines whether a set of points represents an outer ring. + * If points are in clockwise orientation then, they form an outer ring. + * + * @param array $ring array of points forming the ring + * + * @return bool whether a set of points represents an outer ring + * @access public + * @static + */ + public static function isOuterRing($ring) + { + // If area is negative then it's in clockwise orientation, + // i.e. it's an outer ring + if (PMA_GIS_Polygon::area($ring) < 0) { + return true; + } + return false; + } + + /** + * Determines whether a given point is inside a given polygon. + * + * @param array $point x, y coordinates of the point + * @param array $polygon array of points forming the ring + * + * @return bool whether a given point is inside a given polygon + * @access public + * @static + */ + public static function isPointInsidePolygon($point, $polygon) + { + // If first point is repeated at the end remove it + $last = count($polygon) - 1; + if (($polygon[0]['x'] == $polygon[$last]['x']) + && ($polygon[0]['y'] == $polygon[$last]['y']) + ) { + $polygon = array_slice($polygon, 0, $last); + } + + $no_of_points = count($polygon); + $counter = 0; + + // Use ray casting algorithm + $p1 = $polygon[0]; + for ($i = 1; $i <= $no_of_points; $i++) { + $p2 = $polygon[$i % $no_of_points]; + if ($point['y'] > min(array($p1['y'], $p2['y']))) { + if ($point['y'] <= max(array($p1['y'], $p2['y']))) { + if ($point['x'] <= max(array($p1['x'], $p2['x']))) { + if ($p1['y'] != $p2['y']) { + $xinters = ($point['y'] - $p1['y']) + * ($p2['x'] - $p1['x']) + / ($p2['y'] - $p1['y']) + $p1['x']; + if ($p1['x'] == $p2['x'] || $point['x'] <= $xinters) { + $counter++; + } + } + } + } + } + $p1 = $p2; + } + + if ($counter % 2 == 0) { + return false; + } else { + return true; + } + } + + /** + * Returns a point that is guaranteed to be on the surface of the ring. + * (for simple closed rings) + * + * @param array $ring array of points forming the ring + * + * @return array a point on the surface of the ring + * @access public + * @static + */ + public static function getPointOnSurface($ring) + { + // Find two consecutive distinct points. + for ($i = 0; $i < count($ring) - 1; $i++) { + if ($ring[$i]['y'] != $ring[$i + 1]['y']) { + $x0 = $ring[$i]['x']; + $x1 = $ring[$i + 1]['x']; + $y0 = $ring[$i]['y']; + $y1 = $ring[$i + 1]['y']; + break; + } + } + + if (! isset($x0)) { + return false; + } + + // Find the mid point + $x2 = ($x0 + $x1) / 2; + $y2 = ($y0 + $y1) / 2; + + // Always keep $epsilon < 1 to go with the reduction logic down here + $epsilon = 0.1; + $denominator = sqrt( + PMA_Util::pow(($y1 - $y0), 2) + + PMA_Util::pow(($x0 - $x1), 2) + ); + $pointA = array(); $pointB = array(); + + while (true) { + // Get the points on either sides of the line + // with a distance of epsilon to the mid point + $pointA['x'] = $x2 + ($epsilon * ($y1 - $y0)) / $denominator; + $pointA['y'] = $y2 + ($pointA['x'] - $x2) * ($x0 - $x1) / ($y1 - $y0); + + $pointB['x'] = $x2 + ($epsilon * ($y1 - $y0)) / (0 - $denominator); + $pointB['y'] = $y2 + ($pointB['x'] - $x2) * ($x0 - $x1) / ($y1 - $y0); + + // One of the points should be inside the polygon, + // unless epcilon chosen is too large + if (PMA_GIS_Polygon::isPointInsidePolygon($pointA, $ring)) { + return $pointA; + } elseif (PMA_GIS_Polygon::isPointInsidePolygon($pointB, $ring)) { + return $pointB; + } else { + //If both are outside the polygon reduce the epsilon and + //recalculate the points(reduce exponentially for faster convergance) + $epsilon = PMA_Util::pow($epsilon, 2); + if ($epsilon == 0) { + return false; + } + } + + } + } + + /** Generate parameters for the GIS data editor from the value of the GIS column. + * + * @param string $value of the GIS column + * @param index $index of the geometry + * + * @return array params for the GIS data editor from the value of the GIS column + * @access public + */ + public function generateParams($value, $index = -1) + { + if ($index == -1) { + $index = 0; + $params = array(); + $data = PMA_GIS_Geometry::generateParams($value); + $params['srid'] = $data['srid']; + $wkt = $data['wkt']; + } else { + $params[$index]['gis_type'] = 'POLYGON'; + $wkt = $value; + } + + // Trim to remove leading 'POLYGON((' and trailing '))' + $polygon = substr($wkt, 9, (strlen($wkt) - 11)); + // Seperate each linestring + $linerings = explode("),(", $polygon); + $params[$index]['POLYGON']['no_of_lines'] = count($linerings); + + $j = 0; + foreach ($linerings as $linering) { + $points_arr = $this->extractPoints($linering, null); + $no_of_points = count($points_arr); + $params[$index]['POLYGON'][$j]['no_of_points'] = $no_of_points; + for ($i = 0; $i < $no_of_points; $i++) { + $params[$index]['POLYGON'][$j][$i]['x'] = $points_arr[$i][0]; + $params[$index]['POLYGON'][$j][$i]['y'] = $points_arr[$i][1]; + } + $j++; + } + return $params; + } +} +?> diff --git a/phpmyadmin/libraries/gis/pma_gis_visualization.php b/phpmyadmin/libraries/gis/pma_gis_visualization.php new file mode 100644 index 000000000..c49589e83 --- /dev/null +++ b/phpmyadmin/libraries/gis/pma_gis_visualization.php @@ -0,0 +1,503 @@ + array( + '#B02EE0', + '#E0642E', + '#E0D62E', + '#2E97E0', + '#BCE02E', + '#E02E75', + '#5CE02E', + '#E0B02E', + '#0022E0', + '#726CB1', + '#481A36', + '#BAC658', + '#127224', + '#825119', + '#238C74', + '#4C489B', + '#87C9BF', + ), + + // The width of the GIS visualization. + 'width' => 600, + + // The height of the GIS visualization. + 'height' => 450, + ); + + /** + * @var array Options that the user has specified. + */ + private $_userSpecifiedSettings = null; + + /** + * Returns the settings array + * + * @return array the settings array + * @access public + */ + public function getSettings() + { + return $this->_settings; + } + + /** + * Constructor. Stores user specified options. + * + * @param array $data Data for the visualization + * @param array $options Users specified options + * + * @access public + */ + public function __construct($data, $options) + { + $this->_userSpecifiedSettings = $options; + $this->_data = $data; + } + + /** + * All the variable initialization, options handling has to be done here. + * + * @return void + * @access protected + */ + protected function init() + { + $this->_handleOptions(); + } + + /** + * A function which handles passed parameters. Useful if desired + * chart needs to be a little bit different from the default one. + * + * @return void + * @access private + */ + private function _handleOptions() + { + if (! is_null($this->_userSpecifiedSettings)) { + $this->_settings = array_merge( + $this->_settings, + $this->_userSpecifiedSettings + ); + } + } + + /** + * Sanitizes the file name. + * + * @param string $file_name file name + * @param string $ext extension of the file + * + * @return string the sanitized file name + * @access private + */ + private function _sanitizeName($file_name, $ext) + { + $file_name = PMA_sanitizeFilename($file_name); + + // Check if the user already added extension; + // get the substring where the extension would be if it was included + $extension_start_pos = strlen($file_name) - strlen($ext) - 1; + $user_extension = substr( + $file_name, $extension_start_pos, strlen($file_name) + ); + $required_extension = "." . $ext; + if (strtolower($user_extension) != $required_extension) { + $file_name .= $required_extension; + } + return $file_name; + } + + /** + * Handles common tasks of writing the visualization to file for various formats. + * + * @param string $file_name file name + * @param string $type mime type + * @param string $ext extension of the file + * + * @return void + * @access private + */ + private function _toFile($file_name, $type, $ext) + { + $file_name = $this->_sanitizeName($file_name, $ext); + PMA_downloadHeader($file_name, $type); + } + + /** + * Generate the visualization in SVG format. + * + * @return string the generated image resource + * @access private + */ + private function _svg() + { + $this->init(); + + $output = '' . "\n"; + $output .= ''; + $output .= ''; + + $scale_data = $this->_scaleDataSet($this->_data); + $output .= $this->_prepareDataSet($this->_data, $scale_data, 'svg', ''); + + $output .= ''; + $output .= ''; + + return $output; + } + + /** + * Get the visualization as a SVG. + * + * @return string the visualization as a SVG + * @access public + */ + public function asSVG() + { + $output = $this->_svg(); + return $output; + } + + /** + * Saves as a SVG image to a file. + * + * @param string $file_name File name + * + * @return void + * @access public + */ + public function toFileAsSvg($file_name) + { + $img = $this->_svg(); + $this->_toFile($file_name, 'image/svg+xml', 'svg'); + echo($img); + } + + /** + * Generate the visualization in PNG format. + * + * @return object the generated image resource + * @access private + */ + private function _png() + { + $this->init(); + + // create image + $image = imagecreatetruecolor( + $this->_settings['width'], + $this->_settings['height'] + ); + + // fill the background + $bg = imagecolorallocate($image, 229, 229, 229); + imagefilledrectangle( + $image, 0, 0, $this->_settings['width'] - 1, + $this->_settings['height'] - 1, $bg + ); + + $scale_data = $this->_scaleDataSet($this->_data); + $image = $this->_prepareDataSet($this->_data, $scale_data, 'png', $image); + + return $image; + } + + /** + * Get the visualization as a PNG. + * + * @return string the visualization as a PNG + * @access public + */ + public function asPng() + { + $img = $this->_png(); + + // render and save it to variable + ob_start(); + imagepng($img, null, 9, PNG_ALL_FILTERS); + imagedestroy($img); + $output = ob_get_contents(); + ob_end_clean(); + + // base64 encode + $encoded = base64_encode($output); + return ''; + } + + /** + * Saves as a PNG image to a file. + * + * @param string $file_name File name + * + * @return void + * @access public + */ + public function toFileAsPng($file_name) + { + $img = $this->_png(); + $this->_toFile($file_name, 'image/png', 'png'); + imagepng($img, null, 9, PNG_ALL_FILTERS); + imagedestroy($img); + } + + /** + * Get the code for visualization with OpenLayers. + * + * @return string the code for visualization with OpenLayers + * @access public + */ + public function asOl() + { + $this->init(); + $scale_data = $this->_scaleDataSet($this->_data); + $output + = 'var options = {' + . 'projection: new OpenLayers.Projection("EPSG:900913"),' + . 'displayProjection: new OpenLayers.Projection("EPSG:4326"),' + . 'units: "m",' + . 'numZoomLevels: 18,' + . 'maxResolution: 156543.0339,' + . 'maxExtent: new OpenLayers.Bounds(' + . '-20037508, -20037508, 20037508, 20037508),' + . 'restrictedExtent: new OpenLayers.Bounds(' + . '-20037508, -20037508, 20037508, 20037508)' + . '};' + . 'var map = new OpenLayers.Map("openlayersmap", options);' + . 'var layerNone = new OpenLayers.Layer.Boxes(' + . '"None", {isBaseLayer: true});' + . 'var layerMapnik = new OpenLayers.Layer.OSM.Mapnik("Mapnik");' + . 'var layerCycleMap = new OpenLayers.Layer.OSM.CycleMap("CycleMap");' + . 'map.addLayers([layerMapnik,layerCycleMap,layerNone]);' + . 'var vectorLayer = new OpenLayers.Layer.Vector("Data");' + . 'var bound;'; + $output .= $this->_prepareDataSet($this->_data, $scale_data, 'ol', ''); + $output .= + 'map.addLayer(vectorLayer);' + . 'map.zoomToExtent(bound);' + . 'if (map.getZoom() < 2) {' + . 'map.zoomTo(2);' + . '}' + . 'map.addControl(new OpenLayers.Control.LayerSwitcher());' + . 'map.addControl(new OpenLayers.Control.MousePosition());'; + return $output; + } + + /** + * Saves as a PDF to a file. + * + * @param string $file_name File name + * + * @return void + * @access public + */ + public function toFileAsPdf($file_name) + { + $this->init(); + + include_once './libraries/tcpdf/tcpdf.php'; + + // create pdf + $pdf = new TCPDF( + '', 'pt', $GLOBALS['cfg']['PDFDefaultPageSize'], true, 'UTF-8', false + ); + + // disable header and footer + $pdf->setPrintHeader(false); + $pdf->setPrintFooter(false); + + //set auto page breaks + $pdf->SetAutoPageBreak(false); + + // add a page + $pdf->AddPage(); + + $scale_data = $this->_scaleDataSet($this->_data); + $pdf = $this->_prepareDataSet($this->_data, $scale_data, 'pdf', $pdf); + + // sanitize file name + $file_name = $this->_sanitizeName($file_name, 'pdf'); + $pdf->Output($file_name, 'D'); + } + + /** + * Calculates the scale, horizontal and vertical offset that should be used. + * + * @param array $data Row data + * + * @return array an array containing the scale, x and y offsets + * @access private + */ + private function _scaleDataSet($data) + { + $min_max = array(); + $border = 15; + // effective width and height of the plot + $plot_width = $this->_settings['width'] - 2 * $border; + $plot_height = $this->_settings['height'] - 2 * $border; + + foreach ($data as $row) { + + // Figure out the data type + $ref_data = $row[$this->_settings['spatialColumn']]; + $type_pos = stripos($ref_data, '('); + $type = substr($ref_data, 0, $type_pos); + + $gis_obj = PMA_GIS_Factory::factory($type); + if (! $gis_obj) { + continue; + } + $scale_data = $gis_obj->scaleRow( + $row[$this->_settings['spatialColumn']] + ); + + // Upadate minimum/maximum values for x and y cordinates. + $c_maxX = (float) $scale_data['maxX']; + if (! isset($min_max['maxX']) || $c_maxX > $min_max['maxX']) { + $min_max['maxX'] = $c_maxX; + } + + $c_minX = (float) $scale_data['minX']; + if (! isset($min_max['minX']) || $c_minX < $min_max['minX']) { + $min_max['minX'] = $c_minX; + } + + $c_maxY = (float) $scale_data['maxY']; + if (! isset($min_max['maxY']) || $c_maxY > $min_max['maxY']) { + $min_max['maxY'] = $c_maxY; + } + + $c_minY = (float) $scale_data['minY']; + if (! isset($min_max['minY']) || $c_minY < $min_max['minY']) { + $min_max['minY'] = $c_minY; + } + } + + // scale the visualization + $x_ratio = ($min_max['maxX'] - $min_max['minX']) / $plot_width; + $y_ratio = ($min_max['maxY'] - $min_max['minY']) / $plot_height; + $ratio = ($x_ratio > $y_ratio) ? $x_ratio : $y_ratio; + + $scale = ($ratio != 0) ? (1 / $ratio) : 1; + + if ($x_ratio < $y_ratio) { + // center horizontally + $x = ($min_max['maxX'] + $min_max['minX'] - $plot_width / $scale) / 2; + // fit vertically + $y = $min_max['minY'] - ($border / $scale); + } else { + // fit horizontally + $x = $min_max['minX'] - ($border / $scale); + // center vertically + $y =($min_max['maxY'] + $min_max['minY'] - $plot_height / $scale) / 2; + } + + return array( + 'scale' => $scale, + 'x' => $x, + 'y' => $y, + 'minX' => $min_max['minX'], + 'maxX' => $min_max['maxX'], + 'minY' => $min_max['minY'], + 'maxY' => $min_max['maxY'], + 'height' => $this->_settings['height'], + ); + } + + /** + * Prepares and return the dataset as needed by the visualization. + * + * @param array $data Raw data + * @param array $scale_data Data related to scaling + * @param string $format Format of the visulaization + * @param object $results Image object in the case of png + * TCPDF object in the case of pdf + * + * @return mixed the formatted array of data + * @access private + */ + private function _prepareDataSet($data, $scale_data, $format, $results) + { + $color_number = 0; + + // loop through the rows + foreach ($data as $row) { + $index = $color_number % sizeof($this->_settings['colors']); + + // Figure out the data type + $ref_data = $row[$this->_settings['spatialColumn']]; + $type_pos = stripos($ref_data, '('); + $type = substr($ref_data, 0, $type_pos); + + $gis_obj = PMA_GIS_Factory::factory($type); + if (! $gis_obj) { + continue; + } + $label = ''; + if (isset($this->_settings['labelColumn']) + && isset($row[$this->_settings['labelColumn']]) + ) { + $label = $row[$this->_settings['labelColumn']]; + } + + if ($format == 'svg') { + $results .= $gis_obj->prepareRowAsSvg( + $row[$this->_settings['spatialColumn']], $label, + $this->_settings['colors'][$index], $scale_data + ); + } elseif ($format == 'png') { + $results = $gis_obj->prepareRowAsPng( + $row[$this->_settings['spatialColumn']], $label, + $this->_settings['colors'][$index], $scale_data, $results + ); + } elseif ($format == 'pdf') { + $results = $gis_obj->prepareRowAsPdf( + $row[$this->_settings['spatialColumn']], $label, + $this->_settings['colors'][$index], $scale_data, $results + ); + } elseif ($format == 'ol') { + $results .= $gis_obj->prepareRowAsOl( + $row[$this->_settings['spatialColumn']], $row['srid'], + $label, $this->_settings['colors'][$index], $scale_data + ); + } + $color_number++; + } + return $results; + } +} +?> diff --git a/phpmyadmin/libraries/gis_visualization.lib.php b/phpmyadmin/libraries/gis_visualization.lib.php new file mode 100644 index 000000000..63ad18814 --- /dev/null +++ b/phpmyadmin/libraries/gis_visualization.lib.php @@ -0,0 +1,182 @@ +getSettings() as $setting => $val) { + if (! isset($visualizationSettings[$setting])) { + $visualizationSettings[$setting] = $val; + } + } + } + if ($format == 'svg') { + return $visualization->asSvg(); + } elseif ($format == 'png') { + return $visualization->asPng(); + } elseif ($format == 'ol') { + return $visualization->asOl(); + } + } +} + +/** + * Generate visualization for the GIS query results and save it to a file. + * + * @param array $data data for the status chart + * @param array $visualizationSettings settings used to generate the chart + * @param string $format format of the visulaization + * @param string $fileName file name + * + * @return file File containing the visualization + */ +function PMA_GIS_saveToFile($data, $visualizationSettings, $format, $fileName) +{ + include_once './libraries/gis/pma_gis_visualization.php'; + include_once './libraries/gis/pma_gis_factory.php'; + + if (isset($data[0])) { + $visualization = new PMA_GIS_Visualization($data, $visualizationSettings); + + if ($format == 'svg') { + $visualization->toFileAsSvg($fileName); + } elseif ($format == 'png') { + $visualization->toFileAsPng($fileName); + } elseif ($format == 'pdf') { + $visualization->toFileAsPdf($fileName); + } + } +} +?> diff --git a/phpmyadmin/libraries/iconv_wrapper.lib.php b/phpmyadmin/libraries/iconv_wrapper.lib.php new file mode 100644 index 000000000..9bacffa82 --- /dev/null +++ b/phpmyadmin/libraries/iconv_wrapper.lib.php @@ -0,0 +1,105 @@ + "ISO8859-[1-9]" according to + // http://publibn.boulder.ibm.com/doc_link/en_US/ + // a_doc_lib/libs/basetrf2/setlocale.htm + 'iso-8859-1' => 'ISO8859-1', + 'iso-8859-2' => 'ISO8859-2', + 'iso-8859-3' => 'ISO8859-3', + 'iso-8859-4' => 'ISO8859-4', + 'iso-8859-5' => 'ISO8859-5', + 'iso-8859-6' => 'ISO8859-6', + 'iso-8859-7' => 'ISO8859-7', + 'iso-8859-8' => 'ISO8859-8', + 'iso-8859-9' => 'ISO8859-9', + + // "big5" --> "IBM-eucTW" according to + // http://kadesh.cepba.upc.es/mancpp/classref/ref/ITranscoder_DSC.htm + 'big5' => 'IBM-eucTW', + + // Other mappings corresponding to the phpMyAdmin dropdown box when using the + // charset conversion feature + 'euc-jp' => 'IBM-eucJP', + 'koi8-r' => 'IBM-eucKR', + 'ks_c_5601-1987' => 'KSC5601.1987-0', + 'tis-620' => 'TIS-620', + 'utf-8' => 'UTF-8' +); + +/** + * Wrapper around IBM AIX iconv(), whose character set naming differs + * from the GNU version of iconv(). + * + * @param string $in_charset input character set + * @param string $out_charset output character set + * @param string $str the string to convert + * + * @return mixed converted string or false on failure + * + * @access public + * + */ +function PMA_aix_iconv_wrapper($in_charset, $out_charset, $str) +{ + + global $gnu_iconv_to_aix_iconv_codepage_map; + + // Check for transliteration argument at the end of output character set name + $translit_search = strpos(strtolower($out_charset), '//translit'); + $using_translit = (!($translit_search === false)); + + // Extract "plain" output character set name + // (without any transliteration argument) + $out_charset_plain = ($using_translit + ? substr($out_charset, 0, $translit_search) + : $out_charset); + + // Transform name of input character set (if found) + $in_charset_exisits = array_key_exists( + strtolower($in_charset), + $gnu_iconv_to_aix_iconv_codepage_map + ); + if ($in_charset_exisits) { + $in_charset = $gnu_iconv_to_aix_iconv_codepage_map[strtolower($in_charset)]; + } + + // Transform name of "plain" output character set (if found) + $out_charset_plain_exists = array_key_exists( + strtolower($out_charset_plain), + $gnu_iconv_to_aix_iconv_codepage_map + ); + if ($out_charset_plain_exists) { + $out_charset_plain = $gnu_iconv_to_aix_iconv_codepage_map[ + strtolower($out_charset_plain)]; + } + + // Add transliteration argument again (exactly as specified by user) if used + // Build the output character set name that we will use + $out_charset = ($using_translit + ? $out_charset_plain . substr($out_charset, $translit_search) + : $out_charset_plain); + + // NOTE: Transliteration not supported; we will use the "plain" + // output character set name + $out_charset = $out_charset_plain; + + // Call iconv() with the possibly modified parameters + $result = iconv($in_charset, $out_charset, $str); + return $result; +} // end of the "PMA_aix_iconv_wrapper()" function + +?> diff --git a/phpmyadmin/libraries/import.lib.php b/phpmyadmin/libraries/import.lib.php new file mode 100644 index 000000000..aa15847a6 --- /dev/null +++ b/phpmyadmin/libraries/import.lib.php @@ -0,0 +1,1248 @@ + ($maximum_time - 5)) { + $timeout_passed = true; + return true; + } else { + return false; + } +} + +/** + * Detects what compression filse uses + * + * @param string $filepath filename to check + * + * @return string MIME type of compression, none for none + * @access public + */ +function PMA_detectCompression($filepath) +{ + $file = @fopen($filepath, 'rb'); + if (! $file) { + return false; + } + $test = fread($file, 4); + $len = strlen($test); + fclose($file); + if ($len >= 2 && $test[0] == chr(31) && $test[1] == chr(139)) { + return 'application/gzip'; + } + if ($len >= 3 && substr($test, 0, 3) == 'BZh') { + return 'application/bzip2'; + } + if ($len >= 4 && $test == "PK\003\004") { + return 'application/zip'; + } + return 'none'; +} + +/** + * Runs query inside import buffer. This is needed to allow displaying + * of last SELECT, SHOW or HANDLER results and similar nice stuff. + * + * @param string $sql query to run + * @param string $full query to display, this might be commented + * @param bool $controluser whether to use control user for queries + * @param array &$sql_data + * + * @return void + * @access public + */ +function PMA_importRunQuery($sql = '', $full = '', $controluser = false, + &$sql_data = array() +) { + global $import_run_buffer, $go_sql, $complete_query, $display_query, + $sql_query, $my_die, $error, $reload, + $last_query_with_results, + $skip_queries, $executed_queries, $max_sql_len, $read_multiply, + $cfg, $sql_query_disabled, $db, $run_query, $is_superuser; + $read_multiply = 1; + if (isset($import_run_buffer)) { + // Should we skip something? + if ($skip_queries > 0) { + $skip_queries--; + } else { + if (! empty($import_run_buffer['sql']) + && trim($import_run_buffer['sql']) != '' + ) { + + // USE query changes the database, son need to track + // while running multiple queries + $is_use_query + = (stripos($import_run_buffer['sql'], "use ") !== false) + ? true + : false; + + $max_sql_len = max($max_sql_len, strlen($import_run_buffer['sql'])); + if (! $sql_query_disabled) { + $sql_query .= $import_run_buffer['full']; + } + if (! $cfg['AllowUserDropDatabase'] + && ! $is_superuser + && preg_match('@^[[:space:]]*DROP[[:space:]]+(IF EXISTS[[:space:]]+)?DATABASE @i', $import_run_buffer['sql']) + ) { + $GLOBALS['message'] = PMA_Message::error(__('"DROP DATABASE" statements are disabled.')); + $error = true; + } else { + + $executed_queries++; + + if ($run_query + && $GLOBALS['finished'] + && empty($sql) + && ! $error + && ((! empty($import_run_buffer['sql']) + && preg_match('/^[\s]*(SELECT|SHOW|HANDLER)/i', $import_run_buffer['sql'])) + || ($executed_queries == 1)) + ) { + $go_sql = true; + if (! $sql_query_disabled) { + $complete_query = $sql_query; + $display_query = $sql_query; + } else { + $complete_query = ''; + $display_query = ''; + } + $sql_query = $import_run_buffer['sql']; + $sql_data['valid_sql'][] = $import_run_buffer['sql']; + $sql_data['valid_queries']++; + + // If a 'USE ' SQL-clause was found, + // set our current $db to the new one + list($db, $reload) = PMA_lookForUse( + $import_run_buffer['sql'], + $db, + $reload + ); + } elseif ($run_query) { + + if ($controluser) { + $result = PMA_queryAsControlUser( + $import_run_buffer['sql'] + ); + } else { + $result = PMA_DBI_try_query($import_run_buffer['sql']); + } + + $msg = '# '; + if ($result === false) { // execution failed + if (! isset($my_die)) { + $my_die = array(); + } + $my_die[] = array( + 'sql' => $import_run_buffer['full'], + 'error' => PMA_DBI_getError() + ); + + $msg .= __('Error'); + + if (! $cfg['IgnoreMultiSubmitErrors']) { + $error = true; + return; + } + } else { + $a_num_rows = (int)@PMA_DBI_num_rows($result); + $a_aff_rows = (int)@PMA_DBI_affected_rows(); + if ($a_num_rows > 0) { + $msg .= __('Rows'). ': ' . $a_num_rows; + $last_query_with_results = $import_run_buffer['sql']; + } elseif ($a_aff_rows > 0) { + $message = PMA_Message::getMessageForAffectedRows($a_aff_rows); + $msg .= $message->getMessage(); + } else { + $msg .= __('MySQL returned an empty result set (i.e. zero rows).'); + } + + if (($a_num_rows > 0) || $is_use_query) { + $sql_data['valid_sql'][] = $import_run_buffer['sql']; + $sql_data['valid_queries']++; + } + + } + if (! $sql_query_disabled) { + $sql_query .= $msg . "\n"; + } + + // If a 'USE ' SQL-clause was found and the query + // succeeded, set our current $db to the new one + if ($result != false) { + list($db, $reload) = PMA_lookForUse( + $import_run_buffer['sql'], + $db, + $reload + ); + } + + if ($result != false + && preg_match('@^[\s]*(DROP|CREATE)[\s]+(IF EXISTS[[:space:]]+)?(TABLE|DATABASE)[[:space:]]+(.+)@im', $import_run_buffer['sql']) + ) { + $reload = true; + } + } // end run query + } // end if not DROP DATABASE + // end non empty query + } elseif (! empty($import_run_buffer['full'])) { + if ($go_sql) { + $complete_query .= $import_run_buffer['full']; + $display_query .= $import_run_buffer['full']; + } else { + if (! $sql_query_disabled) { + $sql_query .= $import_run_buffer['full']; + } + } + } + // check length of query unless we decided to pass it to sql.php + // (if $run_query is false, we are just displaying so show + // the complete query in the textarea) + if (! $go_sql && $run_query) { + if (! empty($sql_query)) { + if (strlen($sql_query) > 50000 + || $executed_queries > 50 + || $max_sql_len > 1000 + ) { + $sql_query = ''; + $sql_query_disabled = true; + } + } + } + } // end do query (no skip) + } // end buffer exists + + // Do we have something to push into buffer? + if (! empty($sql) || ! empty($full)) { + $import_run_buffer = array('sql' => $sql, 'full' => $full); + } else { + unset($GLOBALS['import_run_buffer']); + } +} + +/** + * Looks for the presence of USE to possibly change current db + * + * @param string $buffer buffer to examine + * @param string $db current db + * @param bool $reload reload + * + * @return array (current or new db, whether to reload) + * @access public + */ +function PMA_lookForUse($buffer, $db, $reload) +{ + if (preg_match('@^[\s]*USE[[:space:]]+([\S]+)@i', $buffer, $match)) { + $db = trim($match[1]); + $db = trim($db, ';'); // for example, USE abc; + + // $db must not contain the escape characters generated by backquote() + // ( used in PMA_buildSQL() as: backquote($db_name), and then called + // in PMA_importRunQuery() which in turn calls PMA_lookForUse() ) + $db = PMA_Util::unQuote($db); + + $reload = true; + } + return(array($db, $reload)); +} + + +/** + * Returns next part of imported file/buffer + * + * @param int $size size of buffer to read + * (this is maximal size function will return) + * + * @return string part of file/buffer + * @access public + */ +function PMA_importGetNextChunk($size = 32768) +{ + global $compression, $import_handle, $charset_conversion, $charset_of_file, + $read_multiply; + + // Add some progression while reading large amount of data + if ($read_multiply <= 8) { + $size *= $read_multiply; + } else { + $size *= 8; + } + $read_multiply++; + + // We can not read too much + if ($size > $GLOBALS['read_limit']) { + $size = $GLOBALS['read_limit']; + } + + if (PMA_checkTimeout()) { + return false; + } + if ($GLOBALS['finished']) { + return true; + } + + if ($GLOBALS['import_file'] == 'none') { + // Well this is not yet supported and tested, + // but should return content of textarea + if (strlen($GLOBALS['import_text']) < $size) { + $GLOBALS['finished'] = true; + return $GLOBALS['import_text']; + } else { + $r = substr($GLOBALS['import_text'], 0, $size); + $GLOBALS['offset'] += $size; + $GLOBALS['import_text'] = substr($GLOBALS['import_text'], $size); + return $r; + } + } + + switch ($compression) { + case 'application/bzip2': + $result = bzread($import_handle, $size); + $GLOBALS['finished'] = feof($import_handle); + break; + case 'application/gzip': + $result = gzread($import_handle, $size); + $GLOBALS['finished'] = feof($import_handle); + break; + case 'application/zip': + $result = substr($GLOBALS['import_text'], 0, $size); + $GLOBALS['import_text'] = substr($GLOBALS['import_text'], $size); + $GLOBALS['finished'] = empty($GLOBALS['import_text']); + break; + case 'none': + $result = fread($import_handle, $size); + $GLOBALS['finished'] = feof($import_handle); + break; + } + $GLOBALS['offset'] += $size; + + if ($charset_conversion) { + return PMA_convert_string($charset_of_file, 'utf-8', $result); + } else { + /** + * Skip possible byte order marks (I do not think we need more + * charsets, but feel free to add more, you can use wikipedia for + * reference: ) + * + * @todo BOM could be used for charset autodetection + */ + if ($GLOBALS['offset'] == $size) { + // UTF-8 + if (strncmp($result, "\xEF\xBB\xBF", 3) == 0) { + $result = substr($result, 3); + // UTF-16 BE, LE + } elseif (strncmp($result, "\xFE\xFF", 2) == 0 + || strncmp($result, "\xFF\xFE", 2) == 0 + ) { + $result = substr($result, 2); + } + } + return $result; + } +} + +/** + * Returns the "Excel" column name (i.e. 1 = "A", 26 = "Z", 27 = "AA", etc.) + * + * This functions uses recursion to build the Excel column name. + * + * The column number (1-26) is converted to the responding + * ASCII character (A-Z) and returned. + * + * If the column number is bigger than 26 (= num of letters in alfabet), + * an extra character needs to be added. To find this extra character, + * the number is divided by 26 and this value is passed to another instance + * of the same function (hence recursion). In that new instance the number is + * evaluated again, and if it is still bigger than 26, it is divided again + * and passed to another instance of the same function. This continues until + * the number is smaller than 26. Then the last called function returns + * the corresponding ASCII character to the function that called it. + * Each time a called function ends an extra character is added to the column name. + * When the first function is reached, the last character is addded and the complete + * column name is returned. + * + * @param int $num the column number + * + * @return string The column's "Excel" name + * @access public + */ +function PMA_getColumnAlphaName($num) +{ + $A = 65; // ASCII value for capital "A" + $col_name = ""; + + if ($num > 26) { + $div = (int)($num / 26); + $remain = (int)($num % 26); + + // subtract 1 of divided value in case the modulus is 0, + // this is necessary because A-Z has no 'zero' + if ($remain == 0) { + $div--; + } + + // recursive function call + $col_name = PMA_getColumnAlphaName($div); + // use modulus as new column number + $num = $remain; + } + + if ($num == 0) { + // use 'Z' if column number is 0, + // this is necessary because A-Z has no 'zero' + $col_name .= chr(($A + 26) - 1); + } else { + // convert column number to ASCII character + $col_name .= chr(($A + $num) - 1); + } + + return $col_name; +} + +/** + * Returns the column number based on the Excel name. + * So "A" = 1, "Z" = 26, "AA" = 27, etc. + * + * Basicly this is a base26 (A-Z) to base10 (0-9) conversion. + * It iterates through all characters in the column name and + * calculates the corresponding value, based on character value + * (A = 1, ..., Z = 26) and position in the string. + * + * @param string $name column name(i.e. "A", or "BC", etc.) + * + * @return int The column number + * @access public + */ +function PMA_getColumnNumberFromName($name) +{ + if (! empty($name)) { + $name = strtoupper($name); + $num_chars = strlen($name); + $column_number = 0; + for ($i = 0; $i < $num_chars; ++$i) { + // read string from back to front + $char_pos = ($num_chars - 1) - $i; + + // convert capital character to ASCII value + // and subtract 64 to get corresponding decimal value + // ASCII value of "A" is 65, "B" is 66, etc. + // Decimal equivalent of "A" is 1, "B" is 2, etc. + $number = (ord($name[$char_pos]) - 64); + + // base26 to base10 conversion : multiply each number + // with corresponding value of the position, in this case + // $i=0 : 1; $i=1 : 26; $i=2 : 676; ... + $column_number += $number * PMA_Util::pow(26, $i); + } + return $column_number; + } else { + return 0; + } +} + +/** + * Constants definitions + */ + +/* MySQL type defs */ +define("NONE", 0); +define("VARCHAR", 1); +define("INT", 2); +define("DECIMAL", 3); +define("BIGINT", 4); +define("GEOMETRY", 5); + +/* Decimal size defs */ +define("M", 0); +define("D", 1); +define("FULL", 2); + +/* Table array defs */ +define("TBL_NAME", 0); +define("COL_NAMES", 1); +define("ROWS", 2); + +/* Analysis array defs */ +define("TYPES", 0); +define("SIZES", 1); +define("FORMATTEDSQL", 2); + +/** + * Obtains the precision (total # of digits) from a size of type decimal + * + * @param string $last_cumulative_size + * + * @return int Precision of the given decimal size notation + * @access public + */ +function PMA_getM($last_cumulative_size) +{ + return (int)substr($last_cumulative_size, 0, strpos($last_cumulative_size, ",")); +} + +/** + * Obtains the scale (# of digits to the right of the decimal point) + * from a size of type decimal + * + * @param string $last_cumulative_size + * + * @return int Scale of the given decimal size notation + * @access public + */ +function PMA_getD($last_cumulative_size) +{ + return (int) substr( + $last_cumulative_size, + (strpos($last_cumulative_size, ",") + 1), + (strlen($last_cumulative_size) - strpos($last_cumulative_size, ",")) + ); +} + +/** + * Obtains the decimal size of a given cell + * + * @param string &$cell cell content + * + * @return array Contains the precision, scale, and full size + * representation of the given decimal cell + * @access public + */ +function PMA_getDecimalSize(&$cell) +{ + $curr_size = strlen((string)$cell); + $decPos = strpos($cell, "."); + $decPrecision = ($curr_size - 1) - $decPos; + + $m = $curr_size - 1; + $d = $decPrecision; + + return array($m, $d, ($m . "," . $d)); +} + +/** + * Obtains the size of the given cell + * + * @param string $last_cumulative_size Last cumulative column size + * @param int $last_cumulative_type Last cumulative column type + * (NONE or VARCHAR or DECIMAL or INT or BIGINT) + * @param int $curr_type Type of the current cell + * (NONE or VARCHAR or DECIMAL or INT or BIGINT) + * @param string &$cell The current cell + * + * @return string Size of the given cell in the type-appropriate format + * @access public + * + * @todo Handle the error cases more elegantly + */ +function PMA_detectSize($last_cumulative_size, $last_cumulative_type, + $curr_type, &$cell +) { + $curr_size = strlen((string)$cell); + + /** + * If the cell is NULL, don't treat it as a varchar + */ + if (! strcmp('NULL', $cell)) { + return $last_cumulative_size; + } elseif ($curr_type == VARCHAR) { + /** + * What to do if the current cell is of type VARCHAR + */ + /** + * The last cumulative type was VARCHAR + */ + if ($last_cumulative_type == VARCHAR) { + if ($curr_size >= $last_cumulative_size) { + return $curr_size; + } else { + return $last_cumulative_size; + } + } elseif ($last_cumulative_type == DECIMAL) { + /** + * The last cumulative type was DECIMAL + */ + $oldM = PMA_getM($last_cumulative_size); + + if ($curr_size >= $oldM) { + return $curr_size; + } else { + return $oldM; + } + } elseif ($last_cumulative_type == BIGINT || $last_cumulative_type == INT) { + /** + * The last cumulative type was BIGINT or INT + */ + if ($curr_size >= $last_cumulative_size) { + return $curr_size; + } else { + return $last_cumulative_size; + } + } elseif (! isset($last_cumulative_type) || $last_cumulative_type == NONE) { + /** + * This is the first row to be analyzed + */ + return $curr_size; + } else { + /** + * An error has DEFINITELY occurred + */ + /** + * TODO: Handle this MUCH more elegantly + */ + + return -1; + } + } elseif ($curr_type == DECIMAL) { + /** + * What to do if the current cell is of type DECIMAL + */ + /** + * The last cumulative type was VARCHAR + */ + if ($last_cumulative_type == VARCHAR) { + /* Convert $last_cumulative_size from varchar to decimal format */ + $size = PMA_getDecimalSize($cell); + + if ($size[M] >= $last_cumulative_size) { + return $size[M]; + } else { + return $last_cumulative_size; + } + } elseif ($last_cumulative_type == DECIMAL) { + /** + * The last cumulative type was DECIMAL + */ + $size = PMA_getDecimalSize($cell); + + $oldM = PMA_getM($last_cumulative_size); + $oldD = PMA_getD($last_cumulative_size); + + /* New val if M or D is greater than current largest */ + if ($size[M] > $oldM || $size[D] > $oldD) { + /* Take the largest of both types */ + return (string) ((($size[M] > $oldM) ? $size[M] : $oldM) + . "," . (($size[D] > $oldD) ? $size[D] : $oldD)); + } else { + return $last_cumulative_size; + } + } elseif ($last_cumulative_type == BIGINT || $last_cumulative_type == INT) { + /** + * The last cumulative type was BIGINT or INT + */ + /* Convert $last_cumulative_size from int to decimal format */ + $size = PMA_getDecimalSize($cell); + + if ($size[M] >= $last_cumulative_size) { + return $size[FULL]; + } else { + return ($last_cumulative_size.",".$size[D]); + } + } elseif (! isset($last_cumulative_type) || $last_cumulative_type == NONE) { + /** + * This is the first row to be analyzed + */ + /* First row of the column */ + $size = PMA_getDecimalSize($cell); + + return $size[FULL]; + } else { + /** + * An error has DEFINITELY occurred + */ + /** + * TODO: Handle this MUCH more elegantly + */ + + return -1; + } + } elseif ($curr_type == BIGINT || $curr_type == INT) { + /** + * What to do if the current cell is of type BIGINT or INT + */ + /** + * The last cumulative type was VARCHAR + */ + if ($last_cumulative_type == VARCHAR) { + if ($curr_size >= $last_cumulative_size) { + return $curr_size; + } else { + return $last_cumulative_size; + } + } elseif ($last_cumulative_type == DECIMAL) { + /** + * The last cumulative type was DECIMAL + */ + $oldM = PMA_getM($last_cumulative_size); + $oldD = PMA_getD($last_cumulative_size); + $oldInt = $oldM - $oldD; + $newInt = strlen((string)$cell); + + /* See which has the larger integer length */ + if ($oldInt >= $newInt) { + /* Use old decimal size */ + return $last_cumulative_size; + } else { + /* Use $newInt + $oldD as new M */ + return (($newInt + $oldD) . "," . $oldD); + } + } elseif ($last_cumulative_type == BIGINT || $last_cumulative_type == INT) { + /** + * The last cumulative type was BIGINT or INT + */ + if ($curr_size >= $last_cumulative_size) { + return $curr_size; + } else { + return $last_cumulative_size; + } + } elseif (! isset($last_cumulative_type) || $last_cumulative_type == NONE) { + /** + * This is the first row to be analyzed + */ + return $curr_size; + } else { + /** + * An error has DEFINITELY occurred + */ + /** + * TODO: Handle this MUCH more elegantly + */ + + return -1; + } + } else { + /** + * An error has DEFINITELY occurred + */ + /** + * TODO: Handle this MUCH more elegantly + */ + + return -1; + } +} + +/** + * Determines what MySQL type a cell is + * + * @param int $last_cumulative_type Last cumulative column type + * (VARCHAR or INT or BIGINT or DECIMAL or NONE) + * @param string &$cell String representation of the cell for which + * a best-fit type is to be determined + * + * @return int The MySQL type representation + * (VARCHAR or INT or BIGINT or DECIMAL or NONE) + * @access public + */ +function PMA_detectType($last_cumulative_type, &$cell) +{ + /** + * If numeric, determine if decimal, int or bigint + * Else, we call it varchar for simplicity + */ + + if (! strcmp('NULL', $cell)) { + if ($last_cumulative_type === null || $last_cumulative_type == NONE) { + return NONE; + } else { + return $last_cumulative_type; + } + } elseif (is_numeric($cell)) { + if ($cell == (string)(float)$cell + && strpos($cell, ".") !== false + && substr_count($cell, ".") == 1 + ) { + return DECIMAL; + } else { + if (abs($cell) > 2147483647) { + return BIGINT; + } else { + return INT; + } + } + } else { + return VARCHAR; + } +} + +/** + * Determines if the column types are int, decimal, or string + * + * @param array &$table array(string $table_name, array $col_names, array $rows) + * + * @return array array(array $types, array $sizes) + * @access public + * + * @link http://wiki.phpmyadmin.net/pma/Import + * + * @todo Handle the error case more elegantly + */ +function PMA_analyzeTable(&$table) +{ + /* Get number of rows in table */ + $numRows = count($table[ROWS]); + /* Get number of columns */ + $numCols = count($table[COL_NAMES]); + /* Current type for each column */ + $types = array(); + $sizes = array(); + + /* Initialize $sizes to all 0's */ + for ($i = 0; $i < $numCols; ++$i) { + $sizes[$i] = 0; + } + + /* Initialize $types to NONE */ + for ($i = 0; $i < $numCols; ++$i) { + $types[$i] = NONE; + } + + /* Temp vars */ + $curr_type = NONE; + + /* If the passed array is not of the correct form, do not process it */ + if (is_array($table) + && ! is_array($table[TBL_NAME]) + && is_array($table[COL_NAMES]) + && is_array($table[ROWS]) + ) { + /* Analyze each column */ + for ($i = 0; $i < $numCols; ++$i) { + /* Analyze the column in each row */ + for ($j = 0; $j < $numRows; ++$j) { + /* Determine type of the current cell */ + $curr_type = PMA_detectType($types[$i], $table[ROWS][$j][$i]); + /* Determine size of the current cell */ + $sizes[$i] = PMA_detectSize( + $sizes[$i], + $types[$i], + $curr_type, + $table[ROWS][$j][$i] + ); + + /** + * If a type for this column has already been declared, + * only alter it if it was a number and a varchar was found + */ + if ($curr_type != NONE) { + if ($curr_type == VARCHAR) { + $types[$i] = VARCHAR; + } else if ($curr_type == DECIMAL) { + if ($types[$i] != VARCHAR) { + $types[$i] = DECIMAL; + } + } else if ($curr_type == BIGINT) { + if ($types[$i] != VARCHAR && $types[$i] != DECIMAL) { + $types[$i] = BIGINT; + } + } else if ($curr_type == INT) { + if ($types[$i] != VARCHAR + && $types[$i] != DECIMAL + && $types[$i] != BIGINT + ) { + $types[$i] = INT; + } + } + } + } + } + + /* Check to ensure that all types are valid */ + $len = count($types); + for ($n = 0; $n < $len; ++$n) { + if (! strcmp(NONE, $types[$n])) { + $types[$n] = VARCHAR; + $sizes[$n] = '10'; + } + } + + return array($types, $sizes); + } else { + /** + * TODO: Handle this better + */ + + return false; + } +} + +/* Needed to quell the beast that is PMA_Message */ +$import_notice = null; + +/** + * Builds and executes SQL statements to create the database and tables + * as necessary, as well as insert all the data. + * + * @param string $db_name Name of the database + * @param array &$tables Array of tables for the specified database + * @param array &$analyses Analyses of the tables + * @param array &$additional_sql Additional SQL statements to be executed + * @param array $options Associative array of options + * + * @return void + * @access public + * + * @link http://wiki.phpmyadmin.net/pma/Import + */ +function PMA_buildSQL($db_name, &$tables, &$analyses = null, + &$additional_sql = null, $options = null +) { + /* Take care of the options */ + if (isset($options['db_collation'])&& ! is_null($options['db_collation'])) { + $collation = $options['db_collation']; + } else { + $collation = "utf8_general_ci"; + } + + if (isset($options['db_charset']) && ! is_null($options['db_charset'])) { + $charset = $options['db_charset']; + } else { + $charset = "utf8"; + } + + if (isset($options['create_db'])) { + $create_db = $options['create_db']; + } else { + $create_db = true; + } + + /* Create SQL code to handle the database */ + $sql = array(); + + if ($create_db) { + if (PMA_DRIZZLE) { + $sql[] = "CREATE DATABASE IF NOT EXISTS " . PMA_Util::backquote($db_name) + . " COLLATE " . $collation; + } else { + $sql[] = "CREATE DATABASE IF NOT EXISTS " . PMA_Util::backquote($db_name) + . " DEFAULT CHARACTER SET " . $charset . " COLLATE " . $collation; + } + } + + /** + * The calling plug-in should include this statement, + * if necessary, in the $additional_sql parameter + * + * $sql[] = "USE " . backquote($db_name); + */ + + /* Execute the SQL statements create above */ + $sql_len = count($sql); + for ($i = 0; $i < $sql_len; ++$i) { + PMA_importRunQuery($sql[$i], $sql[$i]); + } + + /* No longer needed */ + unset($sql); + + /* Run the $additional_sql statements supplied by the caller plug-in */ + if ($additional_sql != null) { + /* Clean the SQL first */ + $additional_sql_len = count($additional_sql); + + /** + * Only match tables for now, because CREATE IF NOT EXISTS + * syntax is lacking or nonexisting for views, triggers, + * functions, and procedures. + * + * See: http://bugs.mysql.com/bug.php?id=15287 + * + * To the best of my knowledge this is still an issue. + * + * $pattern = 'CREATE (TABLE|VIEW|TRIGGER|FUNCTION|PROCEDURE)'; + */ + $pattern = '/CREATE [^`]*(TABLE)/'; + $replacement = 'CREATE \\1 IF NOT EXISTS'; + + /* Change CREATE statements to CREATE IF NOT EXISTS to support + * inserting into existing structures + */ + for ($i = 0; $i < $additional_sql_len; ++$i) { + $additional_sql[$i] = preg_replace( + $pattern, + $replacement, + $additional_sql[$i] + ); + /* Execute the resulting statements */ + PMA_importRunQuery($additional_sql[$i], $additional_sql[$i]); + } + } + + if ($analyses != null) { + $type_array = array( + NONE => "NULL", + VARCHAR => "varchar", + INT => "int", + DECIMAL => "decimal", + BIGINT => "bigint", + GEOMETRY => 'geometry' + ); + + /* TODO: Do more checking here to make sure they really are matched */ + if (count($tables) != count($analyses)) { + exit(); + } + + /* Create SQL code to create the tables */ + $tempSQLStr = ""; + $num_tables = count($tables); + for ($i = 0; $i < $num_tables; ++$i) { + $num_cols = count($tables[$i][COL_NAMES]); + $tempSQLStr = "CREATE TABLE IF NOT EXISTS " . PMA_Util::backquote($db_name) + . '.' . PMA_Util::backquote($tables[$i][TBL_NAME]) . " ("; + for ($j = 0; $j < $num_cols; ++$j) { + $size = $analyses[$i][SIZES][$j]; + if ((int)$size == 0) { + $size = 10; + } + + $tempSQLStr .= PMA_Util::backquote($tables[$i][COL_NAMES][$j]) . " " + . $type_array[$analyses[$i][TYPES][$j]]; + if ($analyses[$i][TYPES][$j] != GEOMETRY) { + $tempSQLStr .= "(" . $size . ")"; + } + + if ($j != (count($tables[$i][COL_NAMES]) - 1)) { + $tempSQLStr .= ", "; + } + } + $tempSQLStr .= ")" + . (PMA_DRIZZLE ? "" : " DEFAULT CHARACTER SET " . $charset) + . " COLLATE " . $collation . ";"; + + /** + * Each SQL statement is executed immediately + * after it is formed so that we don't have + * to store them in a (possibly large) buffer + */ + PMA_importRunQuery($tempSQLStr, $tempSQLStr); + } + } + + /** + * Create the SQL statements to insert all the data + * + * Only one insert query is formed for each table + */ + $tempSQLStr = ""; + $col_count = 0; + $num_tables = count($tables); + for ($i = 0; $i < $num_tables; ++$i) { + $num_cols = count($tables[$i][COL_NAMES]); + $num_rows = count($tables[$i][ROWS]); + + $tempSQLStr = "INSERT INTO " . PMA_Util::backquote($db_name) . '.' + . PMA_Util::backquote($tables[$i][TBL_NAME]) . " ("; + + for ($m = 0; $m < $num_cols; ++$m) { + $tempSQLStr .= PMA_Util::backquote($tables[$i][COL_NAMES][$m]); + + if ($m != ($num_cols - 1)) { + $tempSQLStr .= ", "; + } + } + + $tempSQLStr .= ") VALUES "; + + for ($j = 0; $j < $num_rows; ++$j) { + $tempSQLStr .= "("; + + for ($k = 0; $k < $num_cols; ++$k) { + // If fully formatted SQL, no need to enclose + // with aphostrophes, add shalshes etc. + if ($analyses != null + && isset($analyses[$i][FORMATTEDSQL][$col_count]) + && $analyses[$i][FORMATTEDSQL][$col_count] == true + ) { + $tempSQLStr .= (string) $tables[$i][ROWS][$j][$k]; + } else { + if ($analyses != null) { + $is_varchar = ($analyses[$i][TYPES][$col_count] === VARCHAR); + } else { + $is_varchar = ! is_numeric($tables[$i][ROWS][$j][$k]); + } + + /* Don't put quotes around NULL fields */ + if (! strcmp($tables[$i][ROWS][$j][$k], 'NULL')) { + $is_varchar = false; + } + + $tempSQLStr .= (($is_varchar) ? "'" : ""); + $tempSQLStr .= PMA_Util::sqlAddSlashes( + (string) $tables[$i][ROWS][$j][$k] + ); + $tempSQLStr .= (($is_varchar) ? "'" : ""); + } + + if ($k != ($num_cols - 1)) { + $tempSQLStr .= ", "; + } + + if ($col_count == ($num_cols - 1)) { + $col_count = 0; + } else { + $col_count++; + } + + /* Delete the cell after we are done with it */ + unset($tables[$i][ROWS][$j][$k]); + } + + $tempSQLStr .= ")"; + + if ($j != ($num_rows - 1)) { + $tempSQLStr .= ",\n "; + } + + $col_count = 0; + /* Delete the row after we are done with it */ + unset($tables[$i][ROWS][$j]); + } + + $tempSQLStr .= ";"; + + /** + * Each SQL statement is executed immediately + * after it is formed so that we don't have + * to store them in a (possibly large) buffer + */ + PMA_importRunQuery($tempSQLStr, $tempSQLStr); + } + + /* No longer needed */ + unset($tempSQLStr); + + /** + * A work in progress + */ + + /* Add the viewable structures from $additional_sql + * to $tables so they are also displayed + */ + $view_pattern = '@VIEW `[^`]+`\.`([^`]+)@'; + $table_pattern = '@CREATE TABLE IF NOT EXISTS `([^`]+)`@'; + /* Check a third pattern to make sure its not a "USE `db_name`;" statement */ + + $regs = array(); + + $inTables = false; + + $additional_sql_len = count($additional_sql); + for ($i = 0; $i < $additional_sql_len; ++$i) { + preg_match($view_pattern, $additional_sql[$i], $regs); + + if (count($regs) == 0) { + preg_match($table_pattern, $additional_sql[$i], $regs); + } + + if (count($regs)) { + for ($n = 0; $n < $num_tables; ++$n) { + if (! strcmp($regs[1], $tables[$n][TBL_NAME])) { + $inTables = true; + break; + } + } + + if (! $inTables) { + $tables[] = array(TBL_NAME => $regs[1]); + } + } + + /* Reset the array */ + $regs = array(); + $inTables = false; + } + + $params = array('db' => (string)$db_name); + $db_url = 'db_structure.php' . PMA_generate_common_url($params); + $db_ops_url = 'db_operations.php' . PMA_generate_common_url($params); + + $message = '

      '; + $message .= '' . __('The following structures have either been created or altered. Here you can:') . '
      '; + $message .= '
      • ' . __("View a structure's contents by clicking on its name") . '
      • '; + $message .= '
      • ' . __('Change any of its settings by clicking the corresponding "Options" link') . '
      • '; + $message .= '
      • ' . __('Edit structure by following the "Structure" link') . '
      • '; + $message .= sprintf( + '
      • %s (' . __('Options') . ')
      • ', + $db_url, + sprintf(__('Go to database: %s'), htmlspecialchars(PMA_Util::backquote($db_name))), + htmlspecialchars($db_name), + $db_ops_url, + sprintf(__('Edit settings for %s'), htmlspecialchars(PMA_Util::backquote($db_name))) + ); + + $message .= '
          '; + + unset($params); + + $num_tables = count($tables); + for ($i = 0; $i < $num_tables; ++$i) { + $params = array( + 'db' => (string) $db_name, + 'table' => (string) $tables[$i][TBL_NAME] + ); + $tbl_url = 'sql.php' . PMA_generate_common_url($params); + $tbl_struct_url = 'tbl_structure.php' . PMA_generate_common_url($params); + $tbl_ops_url = 'tbl_operations.php' . PMA_generate_common_url($params); + + unset($params); + + if (! PMA_Table::isView($db_name, $tables[$i][TBL_NAME])) { + $message .= sprintf( + '
        • %s (' . __('Structure') . ') (' . __('Options') . ')
        • ', + $tbl_url, + sprintf(__('Go to table: %s'), htmlspecialchars(PMA_Util::backquote($tables[$i][TBL_NAME]))), + htmlspecialchars($tables[$i][TBL_NAME]), + $tbl_struct_url, + sprintf(__('Structure of %s'), htmlspecialchars(PMA_Util::backquote($tables[$i][TBL_NAME]))), + $tbl_ops_url, + sprintf(__('Edit settings for %s'), htmlspecialchars(PMA_Util::backquote($tables[$i][TBL_NAME]))) + ); + } else { + $message .= sprintf( + '
        • %s
        • ', + $tbl_url, + sprintf(__('Go to view: %s'), htmlspecialchars(PMA_Util::backquote($tables[$i][TBL_NAME]))), + htmlspecialchars($tables[$i][TBL_NAME]) + ); + } + } + + $message .= '
      '; + + global $import_notice; + $import_notice = $message; + + unset($tables); +} + +?> diff --git a/phpmyadmin/libraries/index.lib.php b/phpmyadmin/libraries/index.lib.php new file mode 100644 index 000000000..ac45bb200 --- /dev/null +++ b/phpmyadmin/libraries/index.lib.php @@ -0,0 +1,44 @@ +' + . '
      '; + $html_output .= PMA_generate_common_hidden_inputs($GLOBALS['db'], $GLOBALS['table']) + . sprintf( + __('Create an index on  %s columns'), + '' + ); + $html_output .= '' + . ''; + + $html_output .= '
      ' + . '' + . '
      ' + . '
      '; + + return $html_output; +} + diff --git a/phpmyadmin/libraries/information_schema_relations.lib.php b/phpmyadmin/libraries/information_schema_relations.lib.php new file mode 100644 index 000000000..e9f3c0370 --- /dev/null +++ b/phpmyadmin/libraries/information_schema_relations.lib.php @@ -0,0 +1,138 @@ + array( + 'DEFAULT_COLLATE_NAME' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ) + ), + 'COLLATIONS' => array( + 'CHARACTER_SET_NAME' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'CHARACTER_SETS', + 'foreign_field' => 'CHARACTER_SET_NAME' + ) + ), + 'COLLATION_CHARACTER_SET_APPLICABILITY' => array( + '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' + ) + ), + 'COLUMNS' => array( + 'TABLE_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' + ) + ), + 'COLUMN_PRIVILEGES' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), + 'KEY_COLUMN_USAGE' => array( + 'CONSTRAINT_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), + 'ROUTINES' => array( + 'ROUTINE_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), + 'SCHEMATA' => array( + 'DEFAULT_CHARACTER_SET_NAME' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'CHARACTER_SETS', + 'foreign_field' => 'CHARACTER_SET_NAME' + ) + ), + 'SCHEMA_PRIVILEGES' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), + 'TABLES' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'TABLE_COLLATION' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ) + ), + 'TABLE_CONSTRAINTS' => array( + 'CONSTRAINT_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), + 'TABLE_PRIVILEGES' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), + 'VIEWS' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ) + ) +); + +?> diff --git a/phpmyadmin/libraries/insert_edit.lib.php b/phpmyadmin/libraries/insert_edit.lib.php new file mode 100644 index 000000000..af5cb90be --- /dev/null +++ b/phpmyadmin/libraries/insert_edit.lib.php @@ -0,0 +1,2366 @@ + $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 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] = PMA_DBI_query($local_query, null, PMA_DBI_QUERY_STORE); + $rows[$key_id] = PMA_DBI_fetch_assoc($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 reult 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 = PMA_DBI_get_fields_meta($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 = PMA_DBI_query( + 'SELECT * FROM ' . PMA_Util::backquote($db) + . '.' . PMA_Util::backquote($table) . ' LIMIT 1;', + null, + PMA_DBI_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 nothing + */ +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 + * + * @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_param &rownumber=row_id + * @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_param, + $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_param, $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_getNoSupportTypes( + $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_param &rownumber=row_id + * @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_param, $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']) { + $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 type 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']) { + $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 atttibute + * @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 +) { + $the_class = 'textfield'; + if ($column['pma_type'] == 'date') { + $the_class .= ' datefield'; + } elseif ($column['pma_type'] == 'datetime' + || substr($column['pma_type'], 0, 9) == 'timestamp' + ) { + $the_class .= ' datetimefield'; + } + 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 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 pma no support types + * + * @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 apecial 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_getNoSupportTypes($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_generate_common_hidden_inputs($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 = ''; + // (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 (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['tmp_user_values']['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']); + } 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['tmp_user_values']['display_binary_as_hex']) + && $_SESSION['tmp_user_values']['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'; + $is_insertignore = $_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 = false; + } + 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'); + 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 = PMA_DBI_query($local_query); + $row = PMA_DBI_fetch_row($res); + $meta = PMA_DBI_get_fields_meta($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_generate_common_url($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 paramters array + * @param string $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 = PMA_DBI_try_query($single_query); + } else { + $result = PMA_DBI_query($single_query); + } + if (! $result) { + $error_messages[] = PMA_Message::sanitize(PMA_DBI_getError()); + } else { + // The next line contains a real assignment, it's not a typo + if ($tmp = @PMA_DBI_affected_rows()) { + $total_affected_rows += $tmp; + } + unset($tmp); + + $insert_id = PMA_DBI_insert_id(); + 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; + } + PMA_DBI_free_result($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 (PMA_DBI_get_warnings() 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 = PMA_DBI_try_query($dispsql, null, PMA_DBI_QUERY_STORE); + if ($dispresult && PMA_DBI_num_rows($dispresult) > 0) { + list($dispval) = PMA_DBI_fetch_row($dispresult, 0); + } + @PMA_DBI_free_result($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['tmp_user_values']['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['tmp_user_values']['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_generate_common_url($_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 $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, $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 = PMA_DBI_fetch_value('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)) + ) { + return $multi_edit_funcs[$key] . '(' . $current_value . ')'; + } else { + return $multi_edit_funcs[$key] . '()'; + } +} + +/** + * Get query values array and query fileds 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 fileds + * @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 = PMA_DBI_fetch_single_row( + '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]; + + if (PMA_DBI_fetch_value($sql_for_real_value) !== false) { + $extra_data['truncatableFieldValue'] = PMA_DBI_fetch_value($sql_for_real_value); + } else { + $extra_data['isNeedToRecheck'] = false; + } + +} + +?> diff --git a/phpmyadmin/libraries/ip_allow_deny.lib.php b/phpmyadmin/libraries/ip_allow_deny.lib.php new file mode 100644 index 000000000..f253e37c1 --- /dev/null +++ b/phpmyadmin/libraries/ip_allow_deny.lib.php @@ -0,0 +1,327 @@ + -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 + * Found on + * Modified for phpMyAdmin + * + * Matches: + * xxx.xxx.xxx.xxx (exact) + * xxx.xxx.xxx.[yyy-zzz] (range) + * xxx.xxx.xxx.xxx/nn (CIDR) + * + * Does not match: + * xxx.xxx.xxx.xx[yyy-zzz] (range, partial octets not supported) + * + * @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_ipv4MaskTest($testRange, $ipToTest) +{ + $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])) { + $result = false; + } // end if + } else { + if ($maskocts[$i] <> $ipocts[$i]) { + $result = false; + } // end if + } // 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(); + if (preg_match('/\[([0-9a-f]+)\-([0-9a-f]+)\]/', $test_range, $range_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_ipv6MaskTest()" function + + +/** + * Runs through IP Allow/Deny rules the use of it below for more information + * + * @param string $type 'allow' | 'deny' type of rule to match + * + * @return bool Matched a rule ? + * + * @access public + * + * @see PMA_getIp() + */ +function PMA_allowDeny($type) +{ + global $cfg; + + // Grabs true IP of the user and returns if it can't be found + $remote_ip = PMA_getIp(); + if (empty($remote_ip)) { + return false; + } + + // copy username + $username = $cfg['Server']['user']; + + // copy rule database + $rules = $cfg['Server']['AllowDeny']['rules']; + + // lookup table for some name shortcuts + $shortcuts = array( + 'all' => '0.0.0.0/0', + 'localhost' => '127.0.0.1/8' + ); + + // Provide some useful shortcuts if server gives us address: + if (PMA_getenv('SERVER_ADDR')) { + $shortcuts['localnetA'] = PMA_getenv('SERVER_ADDR') . '/8'; + $shortcuts['localnetB'] = PMA_getenv('SERVER_ADDR') . '/16'; + $shortcuts['localnetC'] = PMA_getenv('SERVER_ADDR') . '/24'; + } + + foreach ($rules as $rule) { + // extract rule data + $rule_data = explode(' ', $rule); + + // check for rule type + if ($rule_data[0] != $type) { + continue; + } + + // check for username + if (($rule_data[1] != '%') //wildcarded first + && ($rule_data[1] != $username) + ) { + continue; + } + + // check if the config file has the full string with an extra + // 'from' in it and if it does, just discard it + if ($rule_data[2] == 'from') { + $rule_data[2] = $rule_data[3]; + } + + // Handle shortcuts with above array + if (isset($shortcuts[$rule_data[2]])) { + $rule_data[2] = $shortcuts[$rule_data[2]]; + } + + // Add code for host lookups here + // Excluded for the moment + + // Do the actual matching now + if (PMA_ipMaskTest($rule_data[2], $remote_ip)) { + return true; + } + } // end while + + return false; +} // end of the "PMA_AllowDeny()" function + +?> diff --git a/phpmyadmin/libraries/js_escape.lib.php b/phpmyadmin/libraries/js_escape.lib.php new file mode 100644 index 000000000..42d7fed52 --- /dev/null +++ b/phpmyadmin/libraries/js_escape.lib.php @@ -0,0 +1,133 @@ + + * this requires only to escape ' with \' and end of script block + * + * We also remove NUL byte as some browsers (namely MSIE) ignore it and + * inserting it anywhere inside '', + '\\' => '\\\\', + '\'' => '\\\'', + '"' => '\"', + "\n" => '\n', + "\r" => '\r' + ) + ) + ); +} + +/** + * Formats a value for javascript code. + * + * @param string $value String to be formatted. + * + * @return string formatted value. + */ +function PMA_formatJsVal($value) +{ + if (is_bool($value)) { + if ($value) { + return 'true'; + } else { + return 'false'; + } + } elseif (is_int($value)) { + return (int)$value; + } else { + return '"' . PMA_escapeJsString($value) . '"'; + } +} + +/** + * Formats 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 bool $escape Whether to escape value or keep it as it is + * (for inclusion of js code) + * + * @return string Javascript code. + */ +function PMA_getJsValue($key, $value, $escape = true) +{ + $result = $key . ' = '; + if (!$escape) { + $result .= $value; + } elseif (is_array($value)) { + $result .= '['; + foreach ($value as $val) { + $result .= PMA_formatJsVal($val) . ","; + } + $result .= "];\n"; + } else { + $result .= PMA_formatJsVal($value) . ";\n"; + } + return $result; +} + +/** + * 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 + * + * @return void + */ +function PMA_printJsValue($key, $value) +{ + echo PMA_getJsValue($key, $value); +} + +?> diff --git a/phpmyadmin/libraries/kanji-encoding.lib.php b/phpmyadmin/libraries/kanji-encoding.lib.php new file mode 100644 index 000000000..f78119f5e --- /dev/null +++ b/phpmyadmin/libraries/kanji-encoding.lib.php @@ -0,0 +1,161 @@ + + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/** + * Gets the php internal encoding codes and sets the available encoding + * codes list + * 2002/1/4 by Y.Kawada + * + * @global string the current encoding code + * @global string the available encoding codes list + * + * @return boolean always true + */ +function PMA_internal_enc_check() +{ + global $internal_enc, $enc_list; + + $internal_enc = mb_internal_encoding(); + if ($internal_enc == 'EUC-JP') { + $enc_list = 'ASCII,EUC-JP,SJIS,JIS'; + } else { + $enc_list = 'ASCII,SJIS,EUC-JP,JIS'; + } + + return true; +} // end of the 'PMA_internal_enc_check' function + + +/** + * Reverses SJIS & EUC-JP position in the encoding codes list + * 2002/1/4 by Y.Kawada + * + * @global string the available encoding codes list + * + * @return boolean always true + */ +function PMA_change_enc_order() +{ + global $enc_list; + + $p = explode(',', $enc_list); + if ($p[1] == 'EUC-JP') { + $enc_list = 'ASCII,SJIS,EUC-JP,JIS'; + } else { + $enc_list = 'ASCII,EUC-JP,SJIS,JIS'; + } + + return true; +} // end of the 'PMA_change_enc_order' function + + +/** + * Kanji string encoding convert + * 2002/1/4 by Y.Kawada + * + * @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 + * + * @return string the converted string + */ +function PMA_kanji_str_conv($str, $enc, $kana) +{ + global $enc_list; + + if ($enc == '' && $kana == '') { + return $str; + } + $nw = mb_detect_encoding($str, $enc_list); + + if ($kana == 'kana') { + $dist = mb_convert_kana($str, 'KV', $nw); + $str = $dist; + } + if ($nw != $enc && $enc != '') { + $dist = mb_convert_encoding($str, $enc, $nw); + } else { + $dist = $str; + } + return $dist; +} // end of the 'PMA_kanji_str_conv' function + + +/** + * Kanji file encoding convert + * 2002/1/4 by Y.Kawada + * + * @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 + */ +function PMA_kanji_file_conv($file, $enc, $kana) +{ + if ($enc == '' && $kana == '') { + return $file; + } + + $tmpfname = tempnam('', $enc); + $fpd = fopen($tmpfname, 'wb'); + $fps = fopen($file, 'r'); + PMA_change_enc_order(); + while (!feof($fps)) { + $line = fgets($fps, 4096); + $dist = PMA_kanji_str_conv($line, $enc, $kana); + fputs($fpd, $dist); + } // end while + PMA_change_enc_order(); + fclose($fps); + fclose($fpd); + unlink($file); + + return $tmpfname; +} // end of the 'PMA_kanji_file_conv' function + + +/** + * Defines radio form fields to switch between encoding modes + * 2002/1/4 by Y.Kawada + * + * @param string $spaces spaces character to prepend the output with + * + * @return string xhtml code for the radio controls + */ +function PMA_set_enc_form($spaces) +{ + 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(); + +?> diff --git a/phpmyadmin/libraries/language_stats.inc.php b/phpmyadmin/libraries/language_stats.inc.php new file mode 100644 index 000000000..f293cc698 --- /dev/null +++ b/phpmyadmin/libraries/language_stats.inc.php @@ -0,0 +1,76 @@ + 10, + 'ar' => 50, + 'az' => 16, + 'be@latin' => 34, + 'be' => 34, + 'bg' => 76, + 'bn' => 20, + 'br' => 26, + 'bs' => 18, + 'ca' => 99, + 'ckb' => 21, + 'cs' => 100, + 'cy' => 25, + 'da' => 99, + 'de' => 99, + 'el' => 100, + 'en_GB' => 99, + 'es' => 100, + 'et' => 100, + 'eu' => 22, + 'fa' => 36, + 'fi' => 69, + 'fr' => 100, + 'gl' => 99, + 'he' => 23, + 'hi' => 56, + 'hr' => 41, + 'hu' => 78, + 'hy' => 4, + 'id' => 74, + 'it' => 93, + 'ja' => 95, + 'ka' => 21, + 'kk' => 13, + 'ko' => 69, + 'lt' => 67, + 'lv' => 24, + 'mk' => 23, + 'ml' => 2, + 'mn' => 27, + 'ms' => 15, + 'nb' => 72, + 'nl' => 100, + 'pa' => 0, + 'pl' => 99, + 'pt_BR' => 100, + 'pt' => 50, + 'ro' => 57, + 'ru' => 99, + 'si' => 81, + 'sk' => 83, + 'sl' => 100, + 'sq' => 30, + 'sr@latin' => 68, + 'sr' => 32, + 'sv' => 99, + 'ta' => 15, + 'te' => 13, + 'th' => 45, + 'tk' => 0, + 'tr' => 100, + 'tt' => 23, + 'ug' => 14, + 'uk' => 92, + 'ur' => 25, + 'uz@latin' => 48, + 'uz' => 49, + 'zh_CN' => 99, + 'zh_TW' => 80, +); +?> diff --git a/phpmyadmin/libraries/logging.lib.php b/phpmyadmin/libraries/logging.lib.php new file mode 100644 index 000000000..dee8407f2 --- /dev/null +++ b/phpmyadmin/libraries/logging.lib.php @@ -0,0 +1,30 @@ + diff --git a/phpmyadmin/libraries/mime.lib.php b/phpmyadmin/libraries/mime.lib.php new file mode 100644 index 000000000..954c762fd --- /dev/null +++ b/phpmyadmin/libraries/mime.lib.php @@ -0,0 +1,34 @@ += 2 && $test[0] == chr(0xff) && $test[1] == chr(0xd8)) { + return 'image/jpeg'; + } + if ($len >= 3 && substr($test, 0, 3) == 'GIF') { + return 'image/gif'; + } + if ($len >= 4 && substr($test, 0, 4) == "\x89PNG") { + return 'image/png'; + } + return 'application/octet-stream'; +} +?> diff --git a/phpmyadmin/libraries/mult_submits.inc.php b/phpmyadmin/libraries/mult_submits.inc.php new file mode 100644 index 000000000..7423749f9 --- /dev/null +++ b/phpmyadmin/libraries/mult_submits.inc.php @@ -0,0 +1,578 @@ + $sval) { + switch ($what) { + case 'row_delete': + $full_query .= 'DELETE FROM ' . PMA_Util::backquote($db) . '.' . PMA_Util::backquote($table) + . ' WHERE ' . urldecode($sval) . ' LIMIT 1' + . ';
      '; + 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); + } + + // Displays the confirmation form + $_url_params = array( + 'query_type' => $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; + } + } + if ($what == 'replace_prefix_tbl' || $what == 'copy_tbl_change_prefix') { ?> +
      + +
      + : +
      ' . __('Column') . ''. __('Null') . '' . __('Value') . '
      ' + . '' + . '
      + + + + + + +
      + +
      + + +
      + + +
      + +
      + : + + + + +
      +
      +
      + + +
      +
      + +
      + : + +
      +
      +
      + +
      + + /> + +
      + + +
      + +
      + + + +
      +
      + databases->build(); + } +} else { + $message = PMA_Message::success(__('No change')); +} +?> diff --git a/phpmyadmin/libraries/mysql_charsets.lib.php b/phpmyadmin/libraries/mysql_charsets.lib.php new file mode 100644 index 000000000..45c48afe3 --- /dev/null +++ b/phpmyadmin/libraries/mysql_charsets.lib.php @@ -0,0 +1,455 @@ + $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); + +function PMA_generateCharsetDropdownBox($type = PMA_CSDROPDOWN_COLLATION, + $name = null, $id = null, $default = null, $label = true, $indent = 0, + $submitOnChange = false, $displayUnavailable = false +) { + global $mysql_charsets, $mysql_charsets_descriptions, + $mysql_charsets_available, $mysql_collations, $mysql_collations_available; + + if (empty($name)) { + if ($type == PMA_CSDROPDOWN_COLLATION) { + $name = 'collation'; + } else { + $name = 'character_set'; + } + } + + $return_str = '' . "\n"; + + return $return_str; +} + +function PMA_generateCharsetQueryPart($collation) +{ + if (!PMA_DRIZZLE) { + list($charset) = explode('_', $collation); + return ' CHARACTER SET ' . $charset + . ($charset == $collation ? '' : ' COLLATE ' . $collation); + } else { + return ' COLLATE ' . $collation; + } +} + +/** + * returns collation of given db + * + * @param string $db name of db + * + * @return string collation of $db + */ +function PMA_getDbCollation($db) +{ + if (PMA_is_system_schema($db)) { + // We don't have to check the collation of the virtual + // information_schema database: We know it! + return 'utf8_general_ci'; + } + + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + // this is slow with thousands of databases + $sql = PMA_DRIZZLE + ? 'SELECT DEFAULT_COLLATION_NAME FROM data_dictionary.SCHEMAS' + . ' WHERE SCHEMA_NAME = \'' . PMA_Util::sqlAddSlashes($db) + . '\' LIMIT 1' + : 'SELECT DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA' + . ' WHERE SCHEMA_NAME = \'' . PMA_Util::sqlAddSlashes($db) + . '\' LIMIT 1'; + return PMA_DBI_fetch_value($sql); + } else { + PMA_DBI_select_db($db); + $return = PMA_DBI_fetch_value( + 'SHOW VARIABLES LIKE \'collation_database\'', 0, 1 + ); + if ($db !== $GLOBALS['db']) { + PMA_DBI_select_db($GLOBALS['db']); + } + return $return; + } +} + +/** + * returns default server collation from show variables + * + * @return string $server_collation + */ +function PMA_getServerCollation() +{ + return PMA_DBI_fetch_value( + 'SHOW VARIABLES LIKE \'collation_server\'', 0, 1 + ); +} + +/** + * returns description for given collation + * + * @param string $collation MySQL collation string + * + * @return string collation description + */ +function PMA_getCollationDescr($collation) +{ + if ($collation == 'binary') { + return __('Binary'); + } + $parts = explode('_', $collation); + if (count($parts) == 1) { + $parts[1] = 'general'; + } elseif ($parts[1] == 'ci' || $parts[1] == 'cs') { + $parts[2] = $parts[1]; + $parts[1] = 'general'; + } + $descr = ''; + switch ($parts[1]) { + case 'bulgarian': + $descr = __('Bulgarian'); + break; + case 'chinese': + if ($parts[0] == 'gb2312' || $parts[0] == 'gbk') { + $descr = __('Simplified Chinese'); + } elseif ($parts[0] == 'big5') { + $descr = __('Traditional Chinese'); + } + break; + case 'ci': + $descr = __('case-insensitive'); + break; + case 'cs': + $descr = __('case-sensitive'); + break; + case 'croatian': + $descr = __('Croatian'); + break; + case 'czech': + $descr = __('Czech'); + break; + case 'danish': + $descr = __('Danish'); + break; + case 'english': + $descr = __('English'); + break; + case 'esperanto': + $descr = __('Esperanto'); + break; + case 'estonian': + $descr = __('Estonian'); + break; + case 'german1': + $descr = __('German') . ' (' . __('dictionary') . ')'; + break; + case 'german2': + $descr = __('German') . ' (' . __('phone book') . ')'; + break; + case 'hungarian': + $descr = __('Hungarian'); + break; + case 'icelandic': + $descr = __('Icelandic'); + break; + case 'japanese': + $descr = __('Japanese'); + break; + case 'latvian': + $descr = __('Latvian'); + break; + case 'lithuanian': + $descr = __('Lithuanian'); + break; + case 'korean': + $descr = __('Korean'); + break; + case 'persian': + $descr = __('Persian'); + break; + case 'polish': + $descr = __('Polish'); + break; + case 'roman': + $descr = __('West European'); + break; + case 'romanian': + $descr = __('Romanian'); + break; + case 'slovak': + $descr = __('Slovak'); + break; + case 'slovenian': + $descr = __('Slovenian'); + break; + case 'spanish': + $descr = __('Spanish'); + break; + case 'spanish2': + $descr = __('Traditional Spanish'); + break; + case 'swedish': + $descr = __('Swedish'); + break; + case 'thai': + $descr = __('Thai'); + break; + case 'turkish': + $descr = __('Turkish'); + break; + case 'ukrainian': + $descr = __('Ukrainian'); + break; + case 'unicode': + $descr = __('Unicode') . ' (' . __('multilingual') . ')'; + break; + case 'bin': + $is_bin = true; + case 'general': + switch ($parts[0]) { + // Unicode charsets + case 'ucs2': + case 'utf8': + $descr = __('Unicode') . ' (' . __('multilingual') . ')'; + break; + // West European charsets + case 'ascii': + case 'cp850': + case 'dec8': + case 'hp8': + case 'latin1': + case 'macroman': + $descr = __('West European') . ' (' . __('multilingual') . ')'; + break; + // Central European charsets + case 'cp1250': + case 'cp852': + case 'latin2': + case 'macce': + $descr = __('Central European') . ' (' . __('multilingual') . ')'; + break; + // Russian charsets + case 'cp866': + case 'koi8r': + $descr = __('Russian'); + break; + // Simplified Chinese charsets + case 'gb2312': + case 'gbk': + $descr = __('Simplified Chinese'); + break; + // Japanese charsets + case 'sjis': + case 'ujis': + case 'cp932': + case 'eucjpms': + $descr = __('Japanese'); + break; + // Baltic charsets + case 'cp1257': + case 'latin7': + $descr = __('Baltic') . ' (' . __('multilingual') . ')'; + break; + // Other + case 'armscii8': + case 'armscii': + $descr = __('Armenian'); + break; + case 'big5': + $descr = __('Traditional Chinese'); + break; + case 'cp1251': + $descr = __('Cyrillic') . ' (' . __('multilingual') . ')'; + break; + case 'cp1256': + $descr = __('Arabic'); + break; + case 'euckr': + $descr = __('Korean'); + break; + case 'hebrew': + $descr = __('Hebrew'); + break; + case 'geostd8': + $descr = __('Georgian'); + break; + case 'greek': + $descr = __('Greek'); + break; + case 'keybcs2': + $descr = __('Czech-Slovak'); + break; + case 'koi8u': + $descr = __('Ukrainian'); + break; + case 'latin5': + $descr = __('Turkish'); + break; + case 'swe7': + $descr = __('Swedish'); + break; + case 'tis620': + $descr = __('Thai'); + break; + default: + $descr = __('unknown'); + break; + } + if (!empty($is_bin)) { + $descr .= ', ' . __('Binary'); + } + break; + default: $descr = __('unknown'); + } + if (!empty($parts[2])) { + if ($parts[2] == 'ci') { + $descr .= ', ' . __('case-insensitive'); + } elseif ($parts[2] == 'cs') { + $descr .= ', ' . __('case-sensitive'); + } + } + + return $descr; +} +?> diff --git a/phpmyadmin/libraries/navigation/Navigation.class.php b/phpmyadmin/libraries/navigation/Navigation.class.php new file mode 100644 index 000000000..d140bbc33 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Navigation.class.php @@ -0,0 +1,77 @@ +isAjax()) { + $header = new PMA_NavigationHeader(); + $retval = $header->getDisplay(); + } + $tree = new PMA_NavigationTree(); + if (! PMA_Response::getInstance()->isAjax() + || ! empty($_REQUEST['full']) + || ! empty($_REQUEST['reload']) + ) { + $treeRender = $tree->renderState(); + } else { + $treeRender = $tree->renderPath(); + } + + if (! $treeRender) { + $retval .= PMA_Message::error( + __('An error has occured while loading the navigation tree') + )->getDisplay(); + } else { + $retval .= $treeRender; + } + + if (! PMA_Response::getInstance()->isAjax()) { + // closes the tags that were opened by the navigation header + $retval .= '
      '; + $retval .= '
      '; + $retval .= '
      '; + } + + return $retval; + } +} +?> diff --git a/phpmyadmin/libraries/navigation/NavigationHeader.class.php b/phpmyadmin/libraries/navigation/NavigationHeader.class.php new file mode 100644 index 000000000..b1513d2c0 --- /dev/null +++ b/phpmyadmin/libraries/navigation/NavigationHeader.class.php @@ -0,0 +1,298 @@ + true + ) + ); + $class = ' class="list_container'; + if ($GLOBALS['cfg']['NavigationTreePointerEnable']) { + $class .= ' highlight'; + } + $class .= '"'; + $buffer = '
      '; + $buffer .= '
      '; + $buffer .= '
      '; + $buffer .= '
      '; + $buffer .= sprintf( + '', + $link_url + ); + $buffer .= $this->_logo(); + $buffer .= $this->_links(); + $buffer .= $this->_serverChoice(); + $buffer .= $this->_recent(); + $buffer .= PMA_Util::getImage( + 'ajax_clock_small.gif', + __('Loading'), + array('style' => 'visibility: hidden;', 'class' => 'throbber') + ); + $buffer .= '
      '; + return $buffer; + } + + /** + * Create the code for displaying the phpMyAdmin + * logo based on configuration settings + * + * @return string HTML code for the logo + */ + private function _logo() + { + $retval = ''; + // display Logo, depending on $GLOBALS['cfg']['NavigationDisplayLogo'] + if ($GLOBALS['cfg']['NavigationDisplayLogo']) { + $logo = 'phpMyAdmin'; + if (@file_exists($GLOBALS['pmaThemeImage'] . 'logo_left.png')) { + $logo = ''; + } elseif (@file_exists($GLOBALS['pmaThemeImage'] . 'pma_logo2.png')) { + $logo = ''; + } + $retval .= '"; + } + } + } + if ($node->hasSiblings() || isset($_REQUEST['results'])) { + $retval .= ""; + } + return $retval; + } + + /** + * Makes some nodes visible based on the which node is active + * + * @return nothing + */ + private function _setVisibility() + { + foreach ($this->_vPath as $path) { + $node = $this->_tree; + foreach ($path as $value) { + $child = $node->getChild($value); + if ($child !== false) { + $child->visible = true; + $node = $child; + } + } + } + } + + /** + * Generates the HTML code for displaying the fast filter for tables + * + * @param Node $node The node for which to generate the fast filter html + * + * @return string LI element used for the fast filter + */ + private function _fastFilterHtml($node) + { + $retval = ''; + if ($node === $this->_tree + && $this->_tree->getPresence() >= (int)$GLOBALS['cfg']['NavigationTreeDisplayDbFilterMinimum'] + ) { + $url_params = array( + 'pos' => 0 + ); + $retval .= "
        "; + $retval .= "
      • "; + $retval .= "
        "; + $retval .= PMA_getHiddenFields($url_params); + $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') + ) + && $node->realParent()->getPresence($node->real_name) >= (int)$GLOBALS['cfg']['NavigationTreeDisplayItemFilterMinimum'] + ) { + $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 .= ""; + $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 000000000..7d8106af9 --- /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 000000000..a1f0e3b44 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node.class.php @@ -0,0 +1,455 @@ +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 nothing + */ + 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 nothing + */ + 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 = '') + { + // @todo obey the DisableIS directive + $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 PMA_DBI_fetch_result($query); + } + + /** + * Returns the comment associated with node + * This method should be overridden by specific type of nodes + * + * @return string + */ + public function getComment() + { + return ''; + } + + /** + * 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 = '') + { + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA` "; + $query .= $this->_getWhereClause($searchClause); + $retval = (int)PMA_DBI_fetch_value($query); + } else { + $query = "SHOW DATABASES "; + if (! empty($searchClause)) { + $query .= "LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%' "; + } + $retval = PMA_DBI_num_rows(PMA_DBI_try_query($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; + } + +} +?> 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 000000000..9c663e7ad --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Column.class.php @@ -0,0 +1,71 @@ +icon = PMA_Util::getImage('pause.png', ''); + $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'] + ); + } + + /** + * Returns the comment associated with node + * This method should be overridden by specific type of nodes + * + * @return string + */ + public function getComment() + { + $db = PMA_Util::sqlAddSlashes( + $this->realParent()->realParent()->real_name + ); + $table = PMA_Util::sqlAddSlashes( + $this->realParent()->real_name + ); + $column = PMA_Util::sqlAddSlashes( + $this->real_name + ); + $query = "SELECT `COLUMN_COMMENT` "; + $query .= "FROM `INFORMATION_SCHEMA`.`COLUMNS` "; + $query .= "WHERE `TABLE_SCHEMA`='$db' "; + $query .= "AND `TABLE_NAME`='$table' "; + $query .= "AND `COLUMN_NAME`='$column' "; + return PMA_DBI_fetch_value($query); + } +} + +?> 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 000000000..1ae57a8f7 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Column_Container.class.php @@ -0,0 +1,56 @@ +icon = PMA_Util::getImage('pause.png', ''); + $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 = PMA_NodeFactory::getInstance('Node', _pgettext('Create new column', 'New')); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_column_add.png', ''); + $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 000000000..5c0815f40 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Database.class.php @@ -0,0 +1,447 @@ +icon = PMA_Util::getImage('s_db.png'); + $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'] + ); + } + + /** + * 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': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$db' "; + $query .= "AND `TABLE_TYPE`='BASE TABLE' "; + if (! empty($searchClause)) { + $query .= "AND `TABLE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $retval = (int)PMA_DBI_fetch_value($query); + } else { + $query = "SHOW FULL TABLES FROM "; + $query .= PMA_Util::backquote($db); + $query .= " WHERE `Table_type`='BASE TABLE' "; + if (! empty($searchClause)) { + $query .= "AND " . PMA_Util::backquote( + "Tables_in_" . $db + ); + $query .= " LIKE '%" . PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $retval = PMA_DBI_num_rows(PMA_DBI_try_query($query)); + } + break; + case 'views': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$db' "; + $query .= "AND `TABLE_TYPE`!='BASE TABLE' "; + if (! empty($searchClause)) { + $query .= "AND `TABLE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $retval = (int)PMA_DBI_fetch_value($query); + } else { + $query = "SHOW FULL TABLES FROM "; + $query .= PMA_Util::backquote($db); + $query .= " WHERE `Table_type`!='BASE TABLE' "; + if (! empty($searchClause)) { + $query .= "AND " . PMA_Util::backquote( + "Tables_in_" . $db + ); + $query .= " LIKE '%" . PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $retval = PMA_DBI_num_rows(PMA_DBI_try_query($query)); + } + break; + case 'procedures': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $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)PMA_DBI_fetch_value($query); + } else { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SHOW PROCEDURE STATUS WHERE `Db`='$db' "; + if (! empty($searchClause)) { + $query .= "AND `Name` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $retval = PMA_DBI_num_rows(PMA_DBI_try_query($query)); + } + break; + case 'functions': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $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)PMA_DBI_fetch_value($query); + } else { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SHOW FUNCTION STATUS WHERE `Db`='$db' "; + if (! empty($searchClause)) { + $query .= "AND `Name` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $retval = PMA_DBI_num_rows(PMA_DBI_try_query($query)); + } + break; + case 'events': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $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)PMA_DBI_fetch_value($query); + } else { + $db = PMA_Util::backquote($db); + $query = "SHOW EVENTS FROM $db "; + if (! empty($searchClause)) { + $query .= "WHERE `Name` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $retval = PMA_DBI_num_rows(PMA_DBI_try_query($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': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `TABLE_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$db' "; + $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 = PMA_DBI_fetch_result($query); + } else { + $query = " SHOW FULL TABLES FROM "; + $query .= PMA_Util::backquote($db); + $query .= " WHERE `Table_type`='BASE TABLE' "; + if (! empty($searchClause)) { + $query .= "AND " . PMA_Util::backquote( + "Tables_in_" . $db + ); + $query .= " LIKE '%" . PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $handle = PMA_DBI_try_query($query); + if ($handle !== false) { + $count = 0; + while ($arr = PMA_DBI_fetch_array($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr[0]; + $count++; + } + $pos--; + } + } + } + break; + case 'views': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `TABLE_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$db' "; + $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 = PMA_DBI_fetch_result($query); + } else { + $query = "SHOW FULL TABLES FROM "; + $query .= PMA_Util::backquote($db); + $query .= " WHERE `Table_type`!='BASE TABLE' "; + if (! empty($searchClause)) { + $query .= "AND " . PMA_Util::backquote( + "Tables_in_" . $db + ); + $query .= " LIKE '%" . PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $handle = PMA_DBI_try_query($query); + if ($handle !== false) { + $count = 0; + while ($arr = PMA_DBI_fetch_array($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr[0]; + $count++; + } + $pos--; + } + } + } + break; + case 'procedures': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `ROUTINE_NAME` AS `name` "; + $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 .= "%'"; + } + $query .= "ORDER BY `ROUTINE_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = PMA_DBI_fetch_result($query); + } else { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SHOW PROCEDURE STATUS WHERE `Db`='$db' "; + if (! empty($searchClause)) { + $query .= "AND `Name` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $handle = PMA_DBI_try_query($query); + if ($handle !== false) { + $count = 0; + while ($arr = PMA_DBI_fetch_array($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Name']; + $count++; + } + $pos--; + } + } + } + break; + case 'functions': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `ROUTINE_NAME` AS `name` "; + $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 .= "%'"; + } + $query .= "ORDER BY `ROUTINE_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = PMA_DBI_fetch_result($query); + } else { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SHOW FUNCTION STATUS WHERE `Db`='$db' "; + if (! empty($searchClause)) { + $query .= "AND `Name` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $handle = PMA_DBI_try_query($query); + if ($handle !== false) { + $count = 0; + while ($arr = PMA_DBI_fetch_array($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Name']; + $count++; + } + $pos--; + } + } + } + break; + case 'events': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `EVENT_NAME` AS `name` "; + $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 .= "%'"; + } + $query .= "ORDER BY `EVENT_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = PMA_DBI_fetch_result($query); + } else { + $db = PMA_Util::backquote($db); + $query = "SHOW EVENTS FROM $db "; + if (! empty($searchClause)) { + $query .= "WHERE `Name` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $handle = PMA_DBI_try_query($query); + if ($handle !== false) { + $count = 0; + while ($arr = PMA_DBI_fetch_array($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Name']; + $count++; + } + $pos--; + } + } + } + break; + default: + break; + } + return $retval; + } + + + /** + * Returns the comment associated with node + * This method should be overridden by specific type of nodes + * + * @return string + */ + public function getComment() + { + return PMA_getDbComment($this->real_name); + } +} + +?> 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 000000000..5b8299960 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Event.class.php @@ -0,0 +1,66 @@ +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 comment associated with node + * This method should be overridden by specific type of nodes + * + * @return string + */ + public function getComment() + { + $db = PMA_Util::sqlAddSlashes( + $this->realParent()->real_name + ); + $event = PMA_Util::sqlAddSlashes( + $this->real_name + ); + $query = "SELECT `EVENT_COMMENT` "; + $query .= "FROM `INFORMATION_SCHEMA`.`EVENTS` "; + $query .= "WHERE `EVENT_SCHEMA`='$db' "; + $query .= "AND `EVENT_NAME`='$event' "; + return PMA_DBI_fetch_value($query); + } +} + +?> 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 000000000..16bdd0019 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Event_Container.class.php @@ -0,0 +1,52 @@ +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 000000000..f6e01a5e4 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Function.class.php @@ -0,0 +1,67 @@ +icon = PMA_Util::getImage('b_routines.png'); + $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 comment associated with node + * This method should be overridden by specific type of nodes + * + * @return string + */ + public function getComment() + { + $db = PMA_Util::sqlAddSlashes( + $this->realParent()->real_name + ); + $routine = PMA_Util::sqlAddSlashes( + $this->real_name + ); + $query = "SELECT `ROUTINE_COMMENT` "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA`='$db' "; + $query .= "AND `ROUTINE_NAME`='$routine' "; + $query .= "AND `ROUTINE_TYPE`='FUNCTION' "; + return PMA_DBI_fetch_value($query); + } +} + +?> 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 000000000..1ddc313ab --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Function_Container.class.php @@ -0,0 +1,52 @@ +icon = PMA_Util::getImage('b_routines.png'); + $this->links = array( + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'], + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'], + ); + $this->real_name = 'functions'; + + $new = PMA_NodeFactory::getInstance('Node', _pgettext('Create new function', 'New')); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_routine_add.png', ''); + $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 000000000..918a2123e --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Index.class.php @@ -0,0 +1,45 @@ +icon = PMA_Util::getImage('b_index.png'); + $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 000000000..732dfddf3 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Index_Container.class.php @@ -0,0 +1,54 @@ +icon = PMA_Util::getImage('b_index.png', ''); + $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 = PMA_NodeFactory::getInstance('Node', _pgettext('Create new index', 'New')); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_index_add.png', ''); + $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 000000000..e89fe2f98 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Procedure.class.php @@ -0,0 +1,67 @@ +icon = PMA_Util::getImage('b_routines.png'); + $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 comment associated with node + * This method should be overridden by specific type of nodes + * + * @return string + */ + public function getComment() + { + $db = PMA_Util::sqlAddSlashes( + $this->realParent()->real_name + ); + $routine = PMA_Util::sqlAddSlashes( + $this->real_name + ); + $query = "SELECT `ROUTINE_COMMENT` "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA`='$db' "; + $query .= "AND `ROUTINE_NAME`='$routine' "; + $query .= "AND `ROUTINE_TYPE`='PROCEDURE' "; + return PMA_DBI_fetch_value($query); + } +} + +?> 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 000000000..8af1185c7 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Procedure_Container.class.php @@ -0,0 +1,52 @@ +icon = PMA_Util::getImage('b_routines.png'); + $this->links = array( + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'], + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'], + ); + $this->real_name = 'procedures'; + + $new = PMA_NodeFactory::getInstance('Node', _pgettext('Create new procedure', 'New')); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_routine_add.png', ''); + $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 000000000..c5449d922 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Table.class.php @@ -0,0 +1,229 @@ +icon = PMA_Util::getImage('b_browse.png'); + $this->links = array( + 'text' => 'sql.php?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'] + ); + } + + /** + * 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': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $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)PMA_DBI_fetch_value($query); + } else { + $db = PMA_Util::backquote($db); + $table = PMA_Util::backquote($table); + $query = "SHOW COLUMNS FROM $table FROM $db"; + $retval = (int)PMA_DBI_num_rows(PMA_DBI_try_query($query)); + } + break; + case 'indexes': + $db = PMA_Util::backquote($db); + $table = PMA_Util::backquote($table); + $query = "SHOW INDEXES FROM $table FROM $db"; + $retval = (int)PMA_DBI_num_rows(PMA_DBI_try_query($query)); + break; + case 'triggers': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $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)PMA_DBI_fetch_value($query); + } else { + $db = PMA_Util::backquote($db); + $table = PMA_Util::sqlAddSlashes($table); + $query = "SHOW TRIGGERS FROM $db WHERE `Table` = '$table'"; + $retval = (int)PMA_DBI_num_rows(PMA_DBI_try_query($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': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $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 = PMA_DBI_fetch_result($query); + } else { + $db = PMA_Util::backquote($db); + $table = PMA_Util::backquote($table); + $query = "SHOW COLUMNS FROM $table FROM $db"; + $handle = PMA_DBI_try_query($query); + if ($handle !== false) { + $count = 0; + while ($arr = PMA_DBI_fetch_array($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Field']; + $count++; + } + $pos--; + } + } + } + break; + case 'indexes': + $db = PMA_Util::backquote($db); + $table = PMA_Util::backquote($table); + $query = "SHOW INDEXES FROM $table FROM $db"; + $handle = PMA_DBI_try_query($query); + if ($handle !== false) { + $count = 0; + while ($arr = PMA_DBI_fetch_array($handle)) { + if (! in_array($arr['Key_name'], $retval)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Key_name']; + $count++; + } + $pos--; + } + } + } + break; + case 'triggers': + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $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 = PMA_DBI_fetch_result($query); + } else { + $db = PMA_Util::backquote($db); + $table = PMA_Util::sqlAddSlashes($table); + $query = "SHOW TRIGGERS FROM $db WHERE `Table` = '$table'"; + $handle = PMA_DBI_try_query($query); + if ($handle !== false) { + $count = 0; + while ($arr = PMA_DBI_fetch_array($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Trigger']; + $count++; + } + $pos--; + } + } + } + break; + default: + break; + } + return $retval; + } + + /** + * Returns the comment associated with node + * This method should be overridden by specific type of nodes + * + * @return string + */ + public function getComment() + { + $db = $this->realParent()->real_name; + $table = PMA_Util::sqlAddSlashes($this->real_name); + if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `TABLE_COMMENT` "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$db' "; + $query .= "AND `TABLE_NAME`='$table' "; + $retval = PMA_DBI_fetch_value($query); + } else { + $db = PMA_Util::backquote($db); + $query = "SHOW TABLE STATUS FROM $db "; + $query .= "WHERE Name = '$table'"; + $arr = PMA_DBI_fetch_assoc(PMA_DBI_try_query($query)); + $retval = $arr['Comment']; + } + return $retval; + } +} + +?> 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 000000000..3d3ef146d --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Table_Container.class.php @@ -0,0 +1,54 @@ +icon = PMA_Util::getImage('b_browse.png', ''); + $this->links = array( + 'text' => 'db_structure.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'], + 'icon' => 'db_structure.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'], + ); + if ($GLOBALS['cfg']['NavigationTreeEnableGrouping']) { + $this->separator = $GLOBALS['cfg']['NavigationTreeTableSeparator']; + $this->separator_depth = (int)($GLOBALS['cfg']['NavigationTreeTableLevel']); + } + $this->real_name = 'tables'; + + $new = PMA_NodeFactory::getInstance('Node', _pgettext('Create new table', 'New')); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_table_add.png', ''); + $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 000000000..bc51106ca --- /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 000000000..7f8f3cb94 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_Trigger_Container.class.php @@ -0,0 +1,53 @@ +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 000000000..3f47579a7 --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_View.class.php @@ -0,0 +1,44 @@ +icon = PMA_Util::getImage('b_views.png'); + $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'] + ); + } +} + +?> 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 000000000..ada9027ff --- /dev/null +++ b/phpmyadmin/libraries/navigation/Nodes/Node_View_Container.class.php @@ -0,0 +1,50 @@ +icon = PMA_Util::getImage('b_views.png', ''); + $this->links = array( + 'text' => 'db_structure.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'], + 'icon' => 'db_structure.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'], + ); + $this->real_name = 'views'; + + $new = PMA_NodeFactory::getInstance('Node', _pgettext('Create new view', 'New')); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_view_add.png', ''); + $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/opendocument.lib.php b/phpmyadmin/libraries/opendocument.lib.php new file mode 100644 index 000000000..b1325034d --- /dev/null +++ b/phpmyadmin/libraries/opendocument.lib.php @@ -0,0 +1,170 @@ + addFile($mime, 'mimetype'); + $zipfile -> addFile($data, 'content.xml'); + $zipfile -> addFile( + '' + . '' + . '' + . 'phpMyAdmin ' . PMA_VERSION . '' + . 'phpMyAdmin ' . PMA_VERSION + . '' + . '' . strftime('%Y-%m-%dT%H:%M:%S') + . '' + . '' + . '', + 'meta.xml' + ); + $zipfile -> addFile( + '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '', + 'styles.xml' + ); + $zipfile -> addFile( + '' + . '' + . '' + . '' + . '' + . '' + . '', + '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 000000000..94be5a2eb --- /dev/null +++ b/phpmyadmin/libraries/operations.lib.php @@ -0,0 +1,1609 @@ +' + . '
      ' + . PMA_generate_common_hidden_inputs($db) + . '
      ' + . ''; + if ($GLOBALS['cfg']['PropertiesIconic']) { + $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_generate_common_hidden_inputs($db) + . '
      ' + . ''; + + if ($GLOBALS['cfg']['PropertiesIconic']) { + $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 ($GLOBALS['cfg']['PropertiesIconic']) { + $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_generate_common_hidden_inputs($db); + $html_output .= '
      ' + . ''; + + if ($GLOBALS['cfg']['PropertiesIconic']) { + $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 ($GLOBALS['cfg']['PropertiesIconic']) { + $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 + * + * @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 = 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($_REQUEST['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($_REQUEST['newname']); + PMA_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 = PMA_DBI_fetch_value( + 'SHOW VARIABLES LIKE "lower_case_table_names"', 0, 1 + ); + if ($lower_case_table_names === '1') { + $_REQUEST['newname'] = PMA_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 PMA_DBI_query() changes $GLOBALS['db'] + // for some statements, one of which being CREATE DATABASE + $original_db = $GLOBALS['db']; + PMA_DBI_query($local_query); + $GLOBALS['db'] = $original_db; + + // 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 databse 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 +) { + $sql_constraints_query_full_db = array(); + foreach ($tables_full as $each_table => $tmp) { + $sql_constraints = ''; + $sql_drop_foreign_keys = ''; + $sql_structure = $export_sql_plugin->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)) { + $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 strin $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" + ); + PMA_DBI_select_db($_REQUEST['newname']); + PMA_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 databse 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 = PMA_DBI_get_triggers($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) { + PMA_DBI_select_db($_REQUEST['newname']); + foreach ($triggers as $trigger) { + PMA_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 = PMA_DBI_fetch_result( + 'SELECT EVENT_NAME FROM information_schema.EVENTS WHERE EVENT_SCHEMA= \'' + . PMA_Util::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($_REQUEST['newname']); + PMA_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 databse 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() +{ + PMA_DBI_select_db($_REQUEST['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']); +} + +/** + * 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_generate_common_hidden_inputs( + $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_generate_common_hidden_inputs($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', '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_generate_common_hidden_inputs($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_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 + * @param array $params url parameters array + * @param array $url_params + * @param string $link contains name of page/anchor that is being linked + * @param string $chapter chapter of "HTML, one page per chapter" documentation + * + * @return string $html_output + */ +function PMA_getMaintainActionlink($action, $params, $url_params, $link, + $chapter = 'MySQL_Database_Administration' +) { + return '
    • ' + . '' + . $action + . '' + . PMA_Util::showMySQLDocu($chapter, $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( + 'SQL-Syntax', $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_generate_common_hidden_inputs($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', + '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_table'] . '.' + . $arr['foreign_field'] + . '
      • ' . "\n"; + } // foreach $foreign + $html_output .= '
      '; + + return $html_output; +} + +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 = PMA_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 $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 (PMA_DBI_get_warnings() 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 = PMA_DBI_query($sql_query); + + return array($sql_query, $result); +} + +?> diff --git a/phpmyadmin/libraries/parse_analyze.lib.php b/phpmyadmin/libraries/parse_analyze.lib.php new file mode 100644 index 000000000..9b9c80068 --- /dev/null +++ b/phpmyadmin/libraries/parse_analyze.lib.php @@ -0,0 +1,61 @@ + diff --git a/phpmyadmin/libraries/php-gettext/gettext.inc b/phpmyadmin/libraries/php-gettext/gettext.inc new file mode 100644 index 000000000..00b966692 --- /dev/null +++ b/phpmyadmin/libraries/php-gettext/gettext.inc @@ -0,0 +1,536 @@ + + Copyright (c) 2009 Danilo Segan + + Drop in replacement for native gettext. + + This file is part of PHP-gettext. + + PHP-gettext is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PHP-gettext 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 PHP-gettext; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +/* +LC_CTYPE 0 +LC_NUMERIC 1 +LC_TIME 2 +LC_COLLATE 3 +LC_MONETARY 4 +LC_MESSAGES 5 +LC_ALL 6 +*/ + +// LC_MESSAGES is not available if php-gettext is not loaded +// while the other constants are already available from session extension. +if (!defined('LC_MESSAGES')) { + define('LC_MESSAGES', 5); +} + +require('streams.php'); +require('gettext.php'); + + +// Variables + +global $text_domains, $default_domain, $LC_CATEGORIES, $EMULATEGETTEXT, $CURRENTLOCALE; +$text_domains = array(); +$default_domain = 'messages'; +$LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MONETARY', 'LC_MESSAGES', 'LC_ALL'); +$EMULATEGETTEXT = 0; +$CURRENTLOCALE = ''; + +/* Class to hold a single domain included in $text_domains. */ +class domain { + var $l10n; + var $path; + var $codeset; +} + +// Utility functions + +/** + * Return a list of locales to try for any POSIX-style locale specification. + */ +function get_list_of_locales($locale) { + /* Figure out all possible locale names and start with the most + * specific ones. I.e. for sr_CS.UTF-8@latin, look through all of + * sr_CS.UTF-8@latin, sr_CS@latin, sr@latin, sr_CS.UTF-8, sr_CS, sr. + */ + $locale_names = array(); + $lang = NULL; + $country = NULL; + $charset = NULL; + $modifier = NULL; + if ($locale) { + if (preg_match("/^(?P[a-z]{2,3})" // language code + ."(?:_(?P[A-Z]{2}))?" // country code + ."(?:\.(?P[-A-Za-z0-9_]+))?" // charset + ."(?:@(?P[-A-Za-z0-9_]+))?$/", // @ modifier + $locale, $matches)) { + + if (isset($matches["lang"])) $lang = $matches["lang"]; + if (isset($matches["country"])) $country = $matches["country"]; + if (isset($matches["charset"])) $charset = $matches["charset"]; + if (isset($matches["modifier"])) $modifier = $matches["modifier"]; + + if ($modifier) { + if ($country) { + if ($charset) + array_push($locale_names, "${lang}_$country.$charset@$modifier"); + array_push($locale_names, "${lang}_$country@$modifier"); + } elseif ($charset) + array_push($locale_names, "${lang}.$charset@$modifier"); + array_push($locale_names, "$lang@$modifier"); + } + if ($country) { + if ($charset) + array_push($locale_names, "${lang}_$country.$charset"); + array_push($locale_names, "${lang}_$country"); + } elseif ($charset) + array_push($locale_names, "${lang}.$charset"); + array_push($locale_names, $lang); + } + + // If the locale name doesn't match POSIX style, just include it as-is. + if (!in_array($locale, $locale_names)) + array_push($locale_names, $locale); + } + return $locale_names; +} + +/** + * Utility function to get a StreamReader for the given text domain. + */ +function _get_reader($domain=null, $category=5, $enable_cache=true) { + global $text_domains, $default_domain, $LC_CATEGORIES; + if (!isset($domain)) $domain = $default_domain; + if (!isset($text_domains[$domain]->l10n)) { + // get the current locale + $locale = _setlocale(LC_MESSAGES, 0); + $bound_path = isset($text_domains[$domain]->path) ? + $text_domains[$domain]->path : './'; + $subpath = $LC_CATEGORIES[$category] ."/$domain.mo"; + + $locale_names = get_list_of_locales($locale); + $input = null; + foreach ($locale_names as $locale) { + $full_path = $bound_path . $locale . "/" . $subpath; + if (file_exists($full_path)) { + $input = new FileReader($full_path); + break; + } + } + + if (!array_key_exists($domain, $text_domains)) { + // Initialize an empty domain object. + $text_domains[$domain] = new domain(); + } + $text_domains[$domain]->l10n = new gettext_reader($input, + $enable_cache); + } + return $text_domains[$domain]->l10n; +} + +/** + * Returns whether we are using our emulated gettext API or PHP built-in one. + */ +function locale_emulation() { + global $EMULATEGETTEXT; + return $EMULATEGETTEXT; +} + +/** + * Checks if the current locale is supported on this system. + */ +function _check_locale_and_function($function=false) { + global $EMULATEGETTEXT; + if ($function and !function_exists($function)) + return false; + return !$EMULATEGETTEXT; +} + +/** + * Get the codeset for the given domain. + */ +function _get_codeset($domain=null) { + global $text_domains, $default_domain, $LC_CATEGORIES; + if (!isset($domain)) $domain = $default_domain; + return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding'); +} + +/** + * Convert the given string to the encoding set by bind_textdomain_codeset. + */ +function _encode($text) { + $source_encoding = mb_detect_encoding($text); + $target_encoding = _get_codeset(); + if ($source_encoding != $target_encoding) { + return mb_convert_encoding($text, $target_encoding, $source_encoding); + } + else { + return $text; + } +} + + +// Custom implementation of the standard gettext related functions + +/** + * Returns passed in $locale, or environment variable $LANG if $locale == ''. + */ +function _get_default_locale($locale) { + if ($locale == '') // emulate variable support + return getenv('LANG'); + else + return $locale; +} + +/** + * Sets a requested locale, if needed emulates it. + */ +function _setlocale($category, $locale) { + global $CURRENTLOCALE, $EMULATEGETTEXT; + if ($locale === 0) { // use === to differentiate between string "0" + if ($CURRENTLOCALE != '') + return $CURRENTLOCALE; + else + // obey LANG variable, maybe extend to support all of LC_* vars + // even if we tried to read locale without setting it first + return _setlocale($category, $CURRENTLOCALE); + } else { + if (function_exists('setlocale')) { + $ret = setlocale($category, $locale); + if (($locale == '' and !$ret) or // failed setting it by env + ($locale != '' and $ret != $locale)) { // failed setting it + // Failed setting it according to environment. + $CURRENTLOCALE = _get_default_locale($locale); + $EMULATEGETTEXT = 1; + } else { + $CURRENTLOCALE = $ret; + $EMULATEGETTEXT = 0; + } + } else { + // No function setlocale(), emulate it all. + $CURRENTLOCALE = _get_default_locale($locale); + $EMULATEGETTEXT = 1; + } + // Allow locale to be changed on the go for one translation domain. + global $text_domains, $default_domain; + if (array_key_exists($default_domain, $text_domains)) { + unset($text_domains[$default_domain]->l10n); + } + return $CURRENTLOCALE; + } +} + +/** + * Sets the path for a domain. + */ +function _bindtextdomain($domain, $path) { + global $text_domains; + // ensure $path ends with a slash ('/' should work for both, but lets still play nice) + if (substr(php_uname(), 0, 7) == "Windows") { + if ($path[strlen($path)-1] != '\\' and $path[strlen($path)-1] != '/') + $path .= '\\'; + } else { + if ($path[strlen($path)-1] != '/') + $path .= '/'; + } + if (!array_key_exists($domain, $text_domains)) { + // Initialize an empty domain object. + $text_domains[$domain] = new domain(); + } + $text_domains[$domain]->path = $path; +} + +/** + * Specify the character encoding in which the messages from the DOMAIN message catalog will be returned. + */ +function _bind_textdomain_codeset($domain, $codeset) { + global $text_domains; + $text_domains[$domain]->codeset = $codeset; +} + +/** + * Sets the default domain. + */ +function _textdomain($domain) { + global $default_domain; + $default_domain = $domain; +} + +/** + * Lookup a message in the current domain. + */ +function _gettext($msgid) { + $l10n = _get_reader(); + return _encode($l10n->translate($msgid)); +} + +/** + * Alias for gettext. + */ +function __($msgid) { + return _gettext($msgid); +} + +/** + * Plural version of gettext. + */ +function _ngettext($singular, $plural, $number) { + $l10n = _get_reader(); + return _encode($l10n->ngettext($singular, $plural, $number)); +} + +/** + * Override the current domain. + */ +function _dgettext($domain, $msgid) { + $l10n = _get_reader($domain); + return _encode($l10n->translate($msgid)); +} + +/** + * Plural version of dgettext. + */ +function _dngettext($domain, $singular, $plural, $number) { + $l10n = _get_reader($domain); + return _encode($l10n->ngettext($singular, $plural, $number)); +} + +/** + * Overrides the domain and category for a single lookup. + */ +function _dcgettext($domain, $msgid, $category) { + $l10n = _get_reader($domain, $category); + return _encode($l10n->translate($msgid)); +} +/** + * Plural version of dcgettext. + */ +function _dcngettext($domain, $singular, $plural, $number, $category) { + $l10n = _get_reader($domain, $category); + return _encode($l10n->ngettext($singular, $plural, $number)); +} + +/** + * Context version of gettext. + */ +function _pgettext($context, $msgid) { + $l10n = _get_reader(); + return _encode($l10n->pgettext($context, $msgid)); +} + +/** + * Override the current domain in a context gettext call. + */ +function _dpgettext($domain, $context, $msgid) { + $l10n = _get_reader($domain); + return _encode($l10n->pgettext($context, $msgid)); +} + +/** + * Overrides the domain and category for a single context-based lookup. + */ +function _dcpgettext($domain, $context, $msgid, $category) { + $l10n = _get_reader($domain, $category); + return _encode($l10n->pgettext($context, $msgid)); +} + +/** + * Context version of ngettext. + */ +function _npgettext($context, $singular, $plural) { + $l10n = _get_reader(); + return _encode($l10n->npgettext($context, $singular, $plural)); +} + +/** + * Override the current domain in a context ngettext call. + */ +function _dnpgettext($domain, $context, $singular, $plural) { + $l10n = _get_reader($domain); + return _encode($l10n->npgettext($context, $singular, $plural)); +} + +/** + * Overrides the domain and category for a plural context-based lookup. + */ +function _dcnpgettext($domain, $context, $singular, $plural, $category) { + $l10n = _get_reader($domain, $category); + return _encode($l10n->npgettext($context, $singular, $plural)); +} + + + +// Wrappers to use if the standard gettext functions are available, +// but the current locale is not supported by the system. +// Use the standard impl if the current locale is supported, use the +// custom impl otherwise. + +function T_setlocale($category, $locale) { + return _setlocale($category, $locale); +} + +function T_bindtextdomain($domain, $path) { + if (_check_locale_and_function()) return bindtextdomain($domain, $path); + else return _bindtextdomain($domain, $path); +} +function T_bind_textdomain_codeset($domain, $codeset) { + // bind_textdomain_codeset is available only in PHP 4.2.0+ + if (_check_locale_and_function('bind_textdomain_codeset')) + return bind_textdomain_codeset($domain, $codeset); + else return _bind_textdomain_codeset($domain, $codeset); +} +function T_textdomain($domain) { + if (_check_locale_and_function()) return textdomain($domain); + else return _textdomain($domain); +} +function T_gettext($msgid) { + if (_check_locale_and_function()) return gettext($msgid); + else return _gettext($msgid); +} +function T_($msgid) { + if (_check_locale_and_function()) return _($msgid); + return __($msgid); +} +function T_ngettext($singular, $plural, $number) { + if (_check_locale_and_function()) + return ngettext($singular, $plural, $number); + else return _ngettext($singular, $plural, $number); +} +function T_dgettext($domain, $msgid) { + if (_check_locale_and_function()) return dgettext($domain, $msgid); + else return _dgettext($domain, $msgid); +} +function T_dngettext($domain, $singular, $plural, $number) { + if (_check_locale_and_function()) + return dngettext($domain, $singular, $plural, $number); + else return _dngettext($domain, $singular, $plural, $number); +} +function T_dcgettext($domain, $msgid, $category) { + if (_check_locale_and_function()) + return dcgettext($domain, $msgid, $category); + else return _dcgettext($domain, $msgid, $category); +} +function T_dcngettext($domain, $singular, $plural, $number, $category) { + if (_check_locale_and_function()) + return dcngettext($domain, $singular, $plural, $number, $category); + else return _dcngettext($domain, $singular, $plural, $number, $category); +} + +function T_pgettext($context, $msgid) { + if (_check_locale_and_function('pgettext')) + return pgettext($context, $msgid); + else + return _pgettext($context, $msgid); +} + +function T_dpgettext($domain, $context, $msgid) { + if (_check_locale_and_function('dpgettext')) + return dpgettext($domain, $context, $msgid); + else + return _dpgettext($domain, $context, $msgid); +} + +function T_dcpgettext($domain, $context, $msgid, $category) { + if (_check_locale_and_function('dcpgettext')) + return dcpgettext($domain, $context, $msgid, $category); + else + return _dcpgettext($domain, $context, $msgid, $category); +} + +function T_npgettext($context, $singular, $plural, $number) { + if (_check_locale_and_function('npgettext')) + return npgettext($context, $singular, $plural, $number); + else + return _npgettext($context, $singular, $plural, $number); +} + +function T_dnpgettext($domain, $context, $singular, $plural, $number) { + if (_check_locale_and_function('dnpgettext')) + return dnpgettext($domain, $context, $singular, $plural, $number); + else + return _dnpgettext($domain, $context, $singular, $plural, $number); +} + +function T_dcnpgettext($domain, $context, $singular, $plural, + $number, $category) { + if (_check_locale_and_function('dcnpgettext')) + return dcnpgettext($domain, $context, $singular, + $plural, $number, $category); + else + return _dcnpgettext($domain, $context, $singular, + $plural, $number, $category); +} + + + +// Wrappers used as a drop in replacement for the standard gettext functions + +if (!function_exists('gettext')) { + function bindtextdomain($domain, $path) { + return _bindtextdomain($domain, $path); + } + function bind_textdomain_codeset($domain, $codeset) { + return _bind_textdomain_codeset($domain, $codeset); + } + function textdomain($domain) { + return _textdomain($domain); + } + function gettext($msgid) { + return _gettext($msgid); + } + function _($msgid) { + return __($msgid); + } + function ngettext($singular, $plural, $number) { + return _ngettext($singular, $plural, $number); + } + function dgettext($domain, $msgid) { + return _dgettext($domain, $msgid); + } + function dngettext($domain, $singular, $plural, $number) { + return _dngettext($domain, $singular, $plural, $number); + } + function dcgettext($domain, $msgid, $category) { + return _dcgettext($domain, $msgid, $category); + } + function dcngettext($domain, $singular, $plural, $number, $category) { + return _dcngettext($domain, $singular, $plural, $number, $category); + } + function pgettext($context, $msgid) { + return _pgettext($context, $msgid); + } + function npgettext($context, $singular, $plural, $number) { + return _npgettext($context, $singular, $plural, $number); + } + function dpgettext($domain, $context, $msgid) { + return _dpgettext($domain, $context, $msgid); + } + function dnpgettext($domain, $context, $singular, $plural, $number) { + return _dnpgettext($domain, $context, $singular, $plural, $number); + } + function dcpgettext($domain, $context, $msgid, $category) { + return _dcpgettext($domain, $context, $msgid, $category); + } + function dcnpgettext($domain, $context, $singular, $plural, + $number, $category) { + return _dcnpgettext($domain, $context, $singular, $plural, + $number, $category); + } +} + +?> diff --git a/phpmyadmin/libraries/php-gettext/gettext.php b/phpmyadmin/libraries/php-gettext/gettext.php new file mode 100644 index 000000000..5064047cb --- /dev/null +++ b/phpmyadmin/libraries/php-gettext/gettext.php @@ -0,0 +1,432 @@ +. + Copyright (c) 2005 Nico Kaiser + + This file is part of PHP-gettext. + + PHP-gettext is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PHP-gettext 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 PHP-gettext; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/** + * Provides a simple gettext replacement that works independently from + * the system's gettext abilities. + * It can read MO files and use them for translating strings. + * The files are passed to gettext_reader as a Stream (see streams.php) + * + * This version has the ability to cache all strings and translations to + * speed up the string lookup. + * While the cache is enabled by default, it can be switched off with the + * second parameter in the constructor (e.g. whenusing very large MO files + * that you don't want to keep in memory) + */ +class gettext_reader { + //public: + var $error = 0; // public variable that holds error code (0 if no error) + + //private: + var $BYTEORDER = 0; // 0: low endian, 1: big endian + var $STREAM = NULL; + var $short_circuit = false; + var $enable_cache = false; + var $originals = NULL; // offset of original table + var $translations = NULL; // offset of translation table + var $pluralheader = NULL; // cache header field for plural forms + var $total = 0; // total string count + var $table_originals = NULL; // table for original strings (offsets) + var $table_translations = NULL; // table for translated strings (offsets) + var $cache_translations = NULL; // original -> translation mapping + + + /* Methods */ + + + /** + * Reads a 32bit Integer from the Stream + * + * @access private + * @return Integer from the Stream + */ + function readint() { + if ($this->BYTEORDER == 0) { + // low endian + $input=unpack('V', $this->STREAM->read(4)); + return array_shift($input); + } else { + // big endian + $input=unpack('N', $this->STREAM->read(4)); + return array_shift($input); + } + } + + function read($bytes) { + return $this->STREAM->read($bytes); + } + + /** + * Reads an array of Integers from the Stream + * + * @param int count How many elements should be read + * @return Array of Integers + */ + function readintarray($count) { + if ($this->BYTEORDER == 0) { + // low endian + return unpack('V'.$count, $this->STREAM->read(4 * $count)); + } else { + // big endian + return unpack('N'.$count, $this->STREAM->read(4 * $count)); + } + } + + /** + * Constructor + * + * @param object Reader the StreamReader object + * @param boolean enable_cache Enable or disable caching of strings (default on) + */ + function gettext_reader($Reader, $enable_cache = true) { + // If there isn't a StreamReader, turn on short circuit mode. + if (! $Reader || isset($Reader->error) ) { + $this->short_circuit = true; + return; + } + + // Caching can be turned off + $this->enable_cache = $enable_cache; + + $MAGIC1 = "\x95\x04\x12\xde"; + $MAGIC2 = "\xde\x12\x04\x95"; + + $this->STREAM = $Reader; + $magic = $this->read(4); + if ($magic == $MAGIC1) { + $this->BYTEORDER = 1; + } elseif ($magic == $MAGIC2) { + $this->BYTEORDER = 0; + } else { + $this->error = 1; // not MO file + return false; + } + + // FIXME: Do we care about revision? We should. + $revision = $this->readint(); + + $this->total = $this->readint(); + $this->originals = $this->readint(); + $this->translations = $this->readint(); + } + + /** + * Loads the translation tables from the MO file into the cache + * If caching is enabled, also loads all strings into a cache + * to speed up translation lookups + * + * @access private + */ + function load_tables() { + if (is_array($this->cache_translations) && + is_array($this->table_originals) && + is_array($this->table_translations)) + return; + + /* get original and translations tables */ + if (!is_array($this->table_originals)) { + $this->STREAM->seekto($this->originals); + $this->table_originals = $this->readintarray($this->total * 2); + } + if (!is_array($this->table_translations)) { + $this->STREAM->seekto($this->translations); + $this->table_translations = $this->readintarray($this->total * 2); + } + + if ($this->enable_cache) { + $this->cache_translations = array (); + /* read all strings in the cache */ + for ($i = 0; $i < $this->total; $i++) { + $this->STREAM->seekto($this->table_originals[$i * 2 + 2]); + $original = $this->STREAM->read($this->table_originals[$i * 2 + 1]); + $this->STREAM->seekto($this->table_translations[$i * 2 + 2]); + $translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]); + $this->cache_translations[$original] = $translation; + } + } + } + + /** + * Returns a string from the "originals" table + * + * @access private + * @param int num Offset number of original string + * @return string Requested string if found, otherwise '' + */ + function get_original_string($num) { + $length = $this->table_originals[$num * 2 + 1]; + $offset = $this->table_originals[$num * 2 + 2]; + if (! $length) + return ''; + $this->STREAM->seekto($offset); + $data = $this->STREAM->read($length); + return (string)$data; + } + + /** + * Returns a string from the "translations" table + * + * @access private + * @param int num Offset number of original string + * @return string Requested string if found, otherwise '' + */ + function get_translation_string($num) { + $length = $this->table_translations[$num * 2 + 1]; + $offset = $this->table_translations[$num * 2 + 2]; + if (! $length) + return ''; + $this->STREAM->seekto($offset); + $data = $this->STREAM->read($length); + return (string)$data; + } + + /** + * Binary search for string + * + * @access private + * @param string string + * @param int start (internally used in recursive function) + * @param int end (internally used in recursive function) + * @return int string number (offset in originals table) + */ + function find_string($string, $start = -1, $end = -1) { + if (($start == -1) or ($end == -1)) { + // find_string is called with only one parameter, set start end end + $start = 0; + $end = $this->total; + } + if (abs($start - $end) <= 1) { + // We're done, now we either found the string, or it doesn't exist + $txt = $this->get_original_string($start); + if ($string == $txt) + return $start; + else + return -1; + } else if ($start > $end) { + // start > end -> turn around and start over + return $this->find_string($string, $end, $start); + } else { + // Divide table in two parts + $half = (int)(($start + $end) / 2); + $cmp = strcmp($string, $this->get_original_string($half)); + if ($cmp == 0) + // string is exactly in the middle => return it + return $half; + else if ($cmp < 0) + // The string is in the upper half + return $this->find_string($string, $start, $half); + else + // The string is in the lower half + return $this->find_string($string, $half, $end); + } + } + + /** + * Translates a string + * + * @access public + * @param string string to be translated + * @return string translated string (or original, if not found) + */ + function translate($string) { + if ($this->short_circuit) + return $string; + $this->load_tables(); + + if ($this->enable_cache) { + // Caching enabled, get translated string from cache + if (array_key_exists($string, $this->cache_translations)) + return $this->cache_translations[$string]; + else + return $string; + } else { + // Caching not enabled, try to find string + $num = $this->find_string($string); + if ($num == -1) + return $string; + else + return $this->get_translation_string($num); + } + } + + /** + * Sanitize plural form expression for use in PHP eval call. + * + * @access private + * @return string sanitized plural form expression + */ + function sanitize_plural_expression($expr) { + // Get rid of disallowed characters. + $expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr); + + // Add parenthesis for tertiary '?' operator. + $expr .= ';'; + $res = ''; + $p = 0; + for ($i = 0; $i < strlen($expr); $i++) { + $ch = $expr[$i]; + switch ($ch) { + case '?': + $res .= ' ? ('; + $p++; + break; + case ':': + $res .= ') : ('; + break; + case ';': + $res .= str_repeat( ')', $p) . ';'; + $p = 0; + break; + default: + $res .= $ch; + } + } + return $res; + } + + /** + * Parse full PO header and extract only plural forms line. + * + * @access private + * @return string verbatim plural form header field + */ + function extract_plural_forms_header_from_po_header($header) { + if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs)) + $expr = $regs[2]; + else + $expr = "nplurals=2; plural=n == 1 ? 0 : 1;"; + return $expr; + } + + /** + * Get possible plural forms from MO header + * + * @access private + * @return string plural form header + */ + function get_plural_forms() { + // lets assume message number 0 is header + // this is true, right? + $this->load_tables(); + + // cache header field for plural forms + if (! is_string($this->pluralheader)) { + if ($this->enable_cache) { + $header = $this->cache_translations[""]; + } else { + $header = $this->get_translation_string(0); + } + $expr = $this->extract_plural_forms_header_from_po_header($header); + $this->pluralheader = $this->sanitize_plural_expression($expr); + } + return $this->pluralheader; + } + + /** + * Detects which plural form to take + * + * @access private + * @param n count + * @return int array index of the right plural form + */ + function select_string($n) { + $string = $this->get_plural_forms(); + $string = str_replace('nplurals',"\$total",$string); + $string = str_replace("n",$n,$string); + $string = str_replace('plural',"\$plural",$string); + + $total = 0; + $plural = 0; + + eval("$string"); + if ($plural >= $total) $plural = $total - 1; + return $plural; + } + + /** + * Plural version of gettext + * + * @access public + * @param string single + * @param string plural + * @param string number + * @return translated plural form + */ + function ngettext($single, $plural, $number) { + if ($this->short_circuit) { + if ($number != 1) + return $plural; + else + return $single; + } + + // find out the appropriate form + $select = $this->select_string($number); + + // this should contains all strings separated by NULLs + $key = $single . chr(0) . $plural; + + + if ($this->enable_cache) { + if (! array_key_exists($key, $this->cache_translations)) { + return ($number != 1) ? $plural : $single; + } else { + $result = $this->cache_translations[$key]; + $list = explode(chr(0), $result); + return $list[$select]; + } + } else { + $num = $this->find_string($key); + if ($num == -1) { + return ($number != 1) ? $plural : $single; + } else { + $result = $this->get_translation_string($num); + $list = explode(chr(0), $result); + return $list[$select]; + } + } + } + + function pgettext($context, $msgid) { + $key = $context . chr(4) . $msgid; + $ret = $this->translate($key); + if (strpos($ret, "\004") !== FALSE) { + return $msgid; + } else { + return $ret; + } + } + + function npgettext($context, $singular, $plural, $number) { + $key = $context . chr(4) . $singular; + $ret = $this->ngettext($key, $plural, $number); + if (strpos($ret, "\004") !== FALSE) { + return $singular; + } else { + return $ret; + } + + } +} + +?> diff --git a/phpmyadmin/libraries/php-gettext/streams.php b/phpmyadmin/libraries/php-gettext/streams.php new file mode 100644 index 000000000..3cdc1584e --- /dev/null +++ b/phpmyadmin/libraries/php-gettext/streams.php @@ -0,0 +1,167 @@ +. + + This file is part of PHP-gettext. + + PHP-gettext is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PHP-gettext 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 PHP-gettext; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + + + // Simple class to wrap file streams, string streams, etc. + // seek is essential, and it should be byte stream +class StreamReader { + // should return a string [FIXME: perhaps return array of bytes?] + function read($bytes) { + return false; + } + + // should return new position + function seekto($position) { + return false; + } + + // returns current position + function currentpos() { + return false; + } + + // returns length of entire stream (limit for seekto()s) + function length() { + return false; + } +}; + +class StringReader { + var $_pos; + var $_str; + + function StringReader($str='') { + $this->_str = $str; + $this->_pos = 0; + } + + function read($bytes) { + $data = substr($this->_str, $this->_pos, $bytes); + $this->_pos += $bytes; + if (strlen($this->_str)<$this->_pos) + $this->_pos = strlen($this->_str); + + return $data; + } + + function seekto($pos) { + $this->_pos = $pos; + if (strlen($this->_str)<$this->_pos) + $this->_pos = strlen($this->_str); + return $this->_pos; + } + + function currentpos() { + return $this->_pos; + } + + function length() { + return strlen($this->_str); + } + +}; + + +class FileReader { + var $_pos; + var $_fd; + var $_length; + + function FileReader($filename) { + if (file_exists($filename)) { + + $this->_length=filesize($filename); + $this->_pos = 0; + $this->_fd = fopen($filename,'rb'); + if (!$this->_fd) { + $this->error = 3; // Cannot read file, probably permissions + return false; + } + } else { + $this->error = 2; // File doesn't exist + return false; + } + } + + function read($bytes) { + if ($bytes) { + fseek($this->_fd, $this->_pos); + + // PHP 5.1.1 does not read more than 8192 bytes in one fread() + // the discussions at PHP Bugs suggest it's the intended behaviour + $data = ''; + while ($bytes > 0) { + $chunk = fread($this->_fd, $bytes); + $data .= $chunk; + $bytes -= strlen($chunk); + } + $this->_pos = ftell($this->_fd); + + return $data; + } else return ''; + } + + function seekto($pos) { + fseek($this->_fd, $pos); + $this->_pos = ftell($this->_fd); + return $this->_pos; + } + + function currentpos() { + return $this->_pos; + } + + function length() { + return $this->_length; + } + + function close() { + fclose($this->_fd); + } + +}; + +// Preloads entire file in memory first, then creates a StringReader +// over it (it assumes knowledge of StringReader internals) +class CachedFileReader extends StringReader { + function CachedFileReader($filename) { + if (file_exists($filename)) { + + $length=filesize($filename); + $fd = fopen($filename,'rb'); + + if (!$fd) { + $this->error = 3; // Cannot read file, probably permissions + return false; + } + $this->_str = fread($fd, $length); + fclose($fd); + + } else { + $this->error = 2; // File doesn't exist + return false; + } + } +}; + + +?> diff --git a/phpmyadmin/libraries/phpseclib/Crypt/AES.php b/phpmyadmin/libraries/phpseclib/Crypt/AES.php new file mode 100644 index 000000000..58c8b52c9 --- /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 000000000..b5aef38a9 --- /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 new file mode 100644 index 000000000..b4fe7f6d6 --- /dev/null +++ b/phpmyadmin/libraries/plugin_interface.lib.php @@ -0,0 +1,508 @@ +'; + $default = PMA_pluginGetDefault($section, $cfgname); + foreach ($list as $plugin) { + $plugin_name = strtolower(substr(get_class($plugin), strlen($section))); + $ret .= 'getProperties(); + $text = null; + if ($properties != null) { + $text = $properties->getText(); + } + $ret .= ' value="' . $plugin_name . '">' + . PMA_getString($text) + . '' . "\n"; + } + $ret .= '' . "\n"; + + // Whether each plugin has to be saved as a file + foreach ($list as $plugin) { + $plugin_name = strtolower(substr(get_class($plugin), strlen($section))); + $ret .= ''. "\n"; + } + + return $ret; +} + +/** + * Returns single option in a list element + * + * @param string $section name of config section in + * $GLOBALS['cfg'][$section] for plugin + * @param string $plugin_name unique plugin name + * @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, + &$propertyGroup, + $is_subgroup = false +) { + $ret = "\n"; + + if (! $is_subgroup) { + // for subgroup headers + if (strpos(get_class($propertyGroup), "PropertyItem")) { + $properties = array($propertyGroup); + } else { + // for main groups + $ret .= '
      '; + + if (method_exists($propertyGroup, 'getText')) { + $text = $propertyGroup->getText(); + } + + if ($text != null) { + $ret .= '

      ' . PMA_getString($text) . '

      '; + } + $ret .= '
        '; + } + } + + if (! isset($properties)) { + $not_subgroup_header = true; + if (method_exists($propertyGroup, 'getProperties')) { + $properties = $propertyGroup->getProperties(); + } + } + + 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": + $ret .= '
      • ' . "\n"; + $ret .= ''; + $ret .= 'getSize() != null + ? ' size="' . $propertyItem->getSize() . '"' + : '') + . ($propertyItem->getLen() != null + ? ' maxlength="' . $propertyItem->getLen() . '"' + : '') + . ' />'; + break; + default:; + } + } + } + } + + if ($is_subgroup) { + // end subgroup + $ret .= '
      '; + } else { + // end main group + if (! empty($not_subgroup_header)) { + $ret .= '
      '; + } + } + + if (method_exists($propertyGroup, "getDoc")) { + $doc = $propertyGroup->getDoc(); + if ($doc != null) { + if (count($doc) == 3) { + $ret .= PMA_Util::showMySQLDocu( + $doc[0], + $doc[1], + false, + $doc[2] + ); + } elseif (count($doc) == 1) { + $ret .= PMA_Util::showDocu('faq', $doc[0]); + } else { + $ret .= PMA_Util::showMySQLDocu( + $doc[0], + $doc[1] + ); + } + } + } + + // 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; +} + +/** + * Returns 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 + * + * @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) { + $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, + $propertyMainGroup + ); + } + } + + if ($no_options) { + $ret .= '

      ' . __('This format has no options') . '

      '; + } + $ret .= '
      '; + } + return $ret; +} diff --git a/phpmyadmin/libraries/plugins/AuthenticationPlugin.class.php b/phpmyadmin/libraries/plugins/AuthenticationPlugin.class.php new file mode 100644 index 000000000..3ddf55ee2 --- /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 000000000..0af20d3c2 --- /dev/null +++ b/phpmyadmin/libraries/plugins/ExportPlugin.class.php @@ -0,0 +1,205 @@ +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 000000000..0890dcf53 --- /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 000000000..28400b7b6 --- /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 type SplObjectStorage + */ + public function getStorage() + { + return $this->_storage; + } + + /** + * Setter for $_storage + * + * @param SplObjectStorage $_storage the list with all the plugins that + * attach to it + * + * @return void + */ + public function setStorage($_storage) + { + $this->_storage = $_storage; + } + + /** + * Gets the information about the current plugin state + * It is called by all the plugins in $_storage in their update() method + * + * @return type mixed + */ + public function getStatus() + { + return $this->_status; + } + + /** + * Setter for $_status + * If a plugin changes its status, this has to be remembered in order to + * notify the rest of the plugins that they should update + * + * @param mixed $_status contains information about the current plugin state + * + * @return void + */ + public function setStatus($_status) + { + $this->_status = $_status; + } +} +?> \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/PluginObserver.class.php b/phpmyadmin/libraries/plugins/PluginObserver.class.php new file mode 100644 index 000000000..520d62a4d --- /dev/null +++ b/phpmyadmin/libraries/plugins/PluginObserver.class.php @@ -0,0 +1,90 @@ +_pluginManager = $pluginManager; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * TODO Declare this function abstract, removing its body, + * as soon as we drop support for PHP 5.2.x. + * See bug #3538655. + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + throw new Exception( + 'PluginObserver::update must be overridden in child classes.' + ); + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the PluginManager instance that contains the list with all the + * plugins that attached to it + * + * @return type PluginManager + */ + public function getPluginManager() + { + return $this->_pluginManager; + } + + /** + * Setter for $_pluginManager + * + * @param PluginManager $_pluginManager the private instance that it will + * attach to + * + * @return void + */ + public function setPluginManager($_pluginManager) + { + $this->_pluginManager = $_pluginManager; + } +} +?> diff --git a/phpmyadmin/libraries/plugins/TransformationsInterface.int.php b/phpmyadmin/libraries/plugins/TransformationsInterface.int.php new file mode 100644 index 000000000..1bcb8af45 --- /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 000000000..959a8e191 --- /dev/null +++ b/phpmyadmin/libraries/plugins/TransformationsPlugin.class.php @@ -0,0 +1,49 @@ + diff --git a/phpmyadmin/libraries/plugins/UploadInterface.int.php b/phpmyadmin/libraries/plugins/UploadInterface.int.php new file mode 100644 index 000000000..ab660d610 --- /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 000000000..07ad7cb55 --- /dev/null +++ b/phpmyadmin/libraries/plugins/auth/AuthenticationConfig.class.php @@ -0,0 +1,172 @@ + authentication failed + * + * @global string the MySQL error message PHP returns + * @global string the connection type (persistent or not) + * @global string the MySQL server port to use + * @global string the MySQL socket port to use + * @global array the current server settings + * @global string the font face to use in case of failure + * @global string the default font size to use in case of failure + * @global string the big font size to use in case of failure + * @global boolean tell the "PMA_mysqlDie()" function headers have been + * sent + * + * @return boolean always true (no return indeed) + */ + public function authFails() + { + $conn_error = PMA_DBI_getError(); + if (! $conn_error) { + $conn_error = __('Cannot connect: invalid settings.'); + } + + /* HTML header */ + $response = PMA_Response::getInstance(); + $response->getFooter()->setMinimal(); + $header = $response->getHeader(); + $header->setBodyId('loginform'); + $header->setTitle(__('Access denied')); + $header->disableMenu(); + echo '

      +
      +

      '; + 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"; + 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 000000000..72274d9e3 --- /dev/null +++ b/phpmyadmin/libraries/plugins/auth/AuthenticationCookie.class.php @@ -0,0 +1,696 @@ +setCookie( + 'pma_mcrypt_iv', + base64_encode($iv) + ); + } +} + +/** + * Handles the cookie authentication method + * + * @package PhpMyAdmin-Authentication + */ +class AuthenticationCookie extends AuthenticationPlugin +{ + /** + * Displays authentication form + * + * this function MUST exit/quit the application + * + * @global string the last connection error + * + * @return void + */ + public function auth() + { + global $conn_error; + + $response = PMA_Response::getInstance(); + if ($response->isAjax()) { + $response->isSuccess(false); + + $login_link = '

      [ ' . + 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 + ) + ); + } + exit; + } + + /* Perform logout to custom URL */ + if (! empty($_REQUEST['old_usr']) + && ! empty($GLOBALS['cfg']['Server']['LogoutURL']) + ) { + PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['LogoutURL']); + exit; + } + + // No recall if blowfish secret is not configured as it would produce + // garbage + if ($GLOBALS['cfg']['LoginCookieRecall'] + && ! empty($GLOBALS['cfg']['blowfish_secret']) + ) { + $default_user = $GLOBALS['PHP_AUTH_USER']; + $default_server = $GLOBALS['pma_auth_server']; + $autocomplete = ''; + } else { + $default_user = ''; + $default_server = ''; + // skip the IE autocomplete feature. + $autocomplete = ' autocomplete="off"'; + } + + $cell_align = ($GLOBALS['text_dir'] == 'ltr') ? 'left' : 'right'; + + $response->getFooter()->setMinimal(); + $header = $response->getHeader(); + $header->setBodyId('loginform'); + $header->setTitle('phpMyAdmin'); + $header->disableMenu(); + $header->disableWarnings(); + + if (file_exists(CUSTOM_HEADER_FILE)) { + include CUSTOM_HEADER_FILE; + } + echo ' +
      + +

      '; + 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; + } + exit; + } + + /** + * Gets advanced authentication settings + * + * this function DOES NOT check authentication - it just checks/provides + * authentication credentials required to connect to the MySQL server + * usually with PMA_DBI_connect() + * + * it returns false if something is missing - which usually leads to + * auth() which displays login form + * + * it returns true if all seems ok which usually leads to auth_set_user() + * + * it directly switches to authFails() if user inactivity timout is reached + * + * @todo AllowArbitraryServer on does not imply that the user wants an + * arbitrary server, or? so we should also check if this is filled + * and not only if allowed + * + * @return boolean whether we get authentication settings or not + */ + public function authCheck() + { + // Initialization + /** + * @global $GLOBALS['pma_auth_server'] the user provided server to + * connect to + */ + $GLOBALS['pma_auth_server'] = ''; + + $GLOBALS['PHP_AUTH_USER'] = $GLOBALS['PHP_AUTH_PW'] = ''; + $GLOBALS['from_cookie'] = false; + + // BEGIN Swekey Integration + if (! Swekey_auth_check()) { + return false; + } + // END Swekey Integration + + if (defined('PMA_CLEAR_COOKIES')) { + foreach ($GLOBALS['cfg']['Servers'] as $key => $val) { + $GLOBALS['PMA_Config']->removeCookie('pmaPass-' . $key); + $GLOBALS['PMA_Config']->removeCookie('pmaServer-' . $key); + $GLOBALS['PMA_Config']->removeCookie('pmaUser-' . $key); + } + return false; + } + + if (! empty($_REQUEST['old_usr'])) { + // The user wants to be logged out + // -> delete his choices that were stored in session + + // according to the PHP manual we should do this before the destroy: + //$_SESSION = array(); + + session_destroy(); + // -> delete password cookie(s) + if ($GLOBALS['cfg']['LoginCookieDeleteAll']) { + foreach ($GLOBALS['cfg']['Servers'] as $key => $val) { + $GLOBALS['PMA_Config']->removeCookie('pmaPass-' . $key); + if (isset($_COOKIE['pmaPass-' . $key])) { + unset($_COOKIE['pmaPass-' . $key]); + } + } + } else { + $GLOBALS['PMA_Config']->removeCookie( + 'pmaPass-' . $GLOBALS['server'] + ); + if (isset($_COOKIE['pmaPass-' . $GLOBALS['server']])) { + unset($_COOKIE['pmaPass-' . $GLOBALS['server']]); + } + } + } + + if (! empty($_REQUEST['pma_username'])) { + // The user just logged in + $GLOBALS['PHP_AUTH_USER'] = $_REQUEST['pma_username']; + $GLOBALS['PHP_AUTH_PW'] = empty($_REQUEST['pma_password']) + ? '' + : $_REQUEST['pma_password']; + if ($GLOBALS['cfg']['AllowArbitraryServer'] + && isset($_REQUEST['pma_servername']) + ) { + $GLOBALS['pma_auth_server'] = $_REQUEST['pma_servername']; + } + return true; + } + + // At the end, try to set the $GLOBALS['PHP_AUTH_USER'] + // and $GLOBALS['PHP_AUTH_PW'] variables from cookies + + // servername + if ($GLOBALS['cfg']['AllowArbitraryServer'] + && ! empty($_COOKIE['pmaServer-' . $GLOBALS['server']]) + ) { + $GLOBALS['pma_auth_server'] + = $_COOKIE['pmaServer-' . $GLOBALS['server']]; + } + + // username + if (empty($_COOKIE['pmaUser-' . $GLOBALS['server']])) { + return false; + } + + $GLOBALS['PHP_AUTH_USER'] = $this->blowfishDecrypt( + $_COOKIE['pmaUser-' . $GLOBALS['server']], + $this->_getBlowfishSecret() + ); + + // user was never logged in since session start + if (empty($_SESSION['last_access_time'])) { + return false; + } + + // User inactive too long + $last_access_time = time() - $GLOBALS['cfg']['LoginCookieValidity']; + if ($_SESSION['last_access_time'] < $last_access_time + ) { + PMA_Util::cacheUnset('is_create_db_priv', true); + PMA_Util::cacheUnset('is_process_priv', true); + PMA_Util::cacheUnset('is_reload_priv', true); + PMA_Util::cacheUnset('db_to_create', true); + PMA_Util::cacheUnset('dbs_where_create_table_allowed', true); + $GLOBALS['no_activity'] = true; + $this->authFails(); + exit; + } + + // password + if (empty($_COOKIE['pmaPass-' . $GLOBALS['server']])) { + return false; + } + + $GLOBALS['PHP_AUTH_PW'] = $this->blowfishDecrypt( + $_COOKIE['pmaPass-' . $GLOBALS['server']], + $this->_getBlowfishSecret() + ); + + if ($GLOBALS['PHP_AUTH_PW'] == "\xff(blank)") { + $GLOBALS['PHP_AUTH_PW'] = ''; + } + + $GLOBALS['from_cookie'] = true; + + return true; + } + + /** + * Set the user and password after last checkings if required + * + * @return boolean always true + */ + public function authSetUser() + { + global $cfg; + + // Ensures valid authentication mode, 'only_db', bookmark database and + // table names and relation table name are used + if ($cfg['Server']['user'] != $GLOBALS['PHP_AUTH_USER']) { + foreach ($cfg['Servers'] as $idx => $current) { + if ($current['host'] == $cfg['Server']['host'] + && $current['port'] == $cfg['Server']['port'] + && $current['socket'] == $cfg['Server']['socket'] + && $current['ssl'] == $cfg['Server']['ssl'] + && $current['connect_type'] == $cfg['Server']['connect_type'] + && $current['user'] == $GLOBALS['PHP_AUTH_USER'] + ) { + $GLOBALS['server'] = $idx; + $cfg['Server'] = $current; + break; + } + } // end foreach + } // end if + + if ($GLOBALS['cfg']['AllowArbitraryServer'] + && ! empty($GLOBALS['pma_auth_server']) + ) { + /* Allow to specify 'host port' */ + $parts = explode(' ', $GLOBALS['pma_auth_server']); + if (count($parts) == 2) { + $tmp_host = $parts[0]; + $tmp_port = $parts[1]; + } else { + $tmp_host = $GLOBALS['pma_auth_server']; + $tmp_port = ''; + } + if ($cfg['Server']['host'] != $GLOBALS['pma_auth_server']) { + $cfg['Server']['host'] = $tmp_host; + if (! empty($tmp_port)) { + $cfg['Server']['port'] = $tmp_port; + } + } + unset($tmp_host, $tmp_port, $parts); + } + $cfg['Server']['user'] = $GLOBALS['PHP_AUTH_USER']; + $cfg['Server']['password'] = $GLOBALS['PHP_AUTH_PW']; + + // Avoid showing the password in phpinfo()'s output + unset($GLOBALS['PHP_AUTH_PW']); + unset($_SERVER['PHP_AUTH_PW']); + + $_SESSION['last_access_time'] = time(); + + // Name and password cookies need to be refreshed each time + // Duration = one month for username + $GLOBALS['PMA_Config']->setCookie( + 'pmaUser-' . $GLOBALS['server'], + $this->blowfishEncrypt( + $cfg['Server']['user'], + $this->_getBlowfishSecret() + ) + ); + + // Duration = as configured + $GLOBALS['PMA_Config']->setCookie( + 'pmaPass-' . $GLOBALS['server'], + $this->blowfishEncrypt( + ! empty($cfg['Server']['password']) + ? $cfg['Server']['password'] : "\xff(blank)", + $this->_getBlowfishSecret() + ), + null, + $GLOBALS['cfg']['LoginCookieStore'] + ); + + // Set server cookies if required (once per session) and, in this case, + // force reload to ensure the client accepts cookies + if (! $GLOBALS['from_cookie']) { + if ($GLOBALS['cfg']['AllowArbitraryServer']) { + if (! empty($GLOBALS['pma_auth_server'])) { + // Duration = one month for servername + $GLOBALS['PMA_Config']->setCookie( + 'pmaServer-' . $GLOBALS['server'], + $cfg['Server']['host'] + ); + } else { + // Delete servername cookie + $GLOBALS['PMA_Config']->removeCookie( + 'pmaServer-' . $GLOBALS['server'] + ); + } + } + + // URL where to go: + $redirect_url = $cfg['PmaAbsoluteUri'] . 'index.php'; + + // any parameters to pass? + $url_params = array(); + if (strlen($GLOBALS['db'])) { + $url_params['db'] = $GLOBALS['db']; + } + if (strlen($GLOBALS['table'])) { + $url_params['table'] = $GLOBALS['table']; + } + // any target to pass? + if (! empty($GLOBALS['target']) + && $GLOBALS['target'] != 'index.php' + ) { + $url_params['target'] = $GLOBALS['target']; + } + + /** + * Clear user cache. + */ + PMA_Util::clearUserCache(); + + PMA_Response::getInstance()->disable(); + + PMA_sendHeaderLocation( + $redirect_url . PMA_generate_common_url($url_params, '&'), + true + ); + exit; + } // end if + + return true; + + } + + /** + * User is not allowed to login to MySQL -> authentication failed + * + * prepares error message and switches to auth() which display the error + * and the login form + * + * this function MUST exit/quit the application, + * currently doen by call to auth() + * + * @return void + */ + public function authFails() + { + global $conn_error; + + // Deletes password cookie and displays the login form + $GLOBALS['PMA_Config']->removeCookie('pmaPass-' . $GLOBALS['server']); + + if (! empty($GLOBALS['login_without_password_is_forbidden'])) { + $conn_error = __( + 'Login without a password is forbidden by configuration' + . ' (see AllowNoPassword)' + ); + } elseif (! empty($GLOBALS['allowDeny_forbidden'])) { + $conn_error = __('Access denied'); + } elseif (! empty($GLOBALS['no_activity'])) { + $conn_error = sprintf( + __('No activity within %s seconds; please log in again'), + $GLOBALS['cfg']['LoginCookieValidity'] + ); + } elseif (PMA_DBI_getError()) { + $conn_error = '#' . $GLOBALS['errno'] . ' ' + . __('Cannot log in to the MySQL server'); + } else { + $conn_error = __('Cannot log in to the MySQL server'); + } + + // needed for PHP-CGI (not need for FastCGI or mod-php) + header('Cache-Control: no-store, no-cache, must-revalidate'); + header('Pragma: no-cache'); + + $this->auth(); + } + + /** + * Returns blowfish secret or generates one if needed. + * + * @return string + */ + private function _getBlowfishSecret() + { + if (empty($GLOBALS['cfg']['blowfish_secret'])) { + if (empty($_SESSION['auto_blowfish_secret'])) { + // this returns 23 characters + $_SESSION['auto_blowfish_secret'] = uniqid('', true); + } + return $_SESSION['auto_blowfish_secret']; + } else { + // apply md5() to work around too long secrets (returns 32 characters) + return md5($GLOBALS['cfg']['blowfish_secret']); + } + } + + /** + * Encryption using blowfish algorithm (mcrypt) + * or phpseclib's AES if mcrypt not available + * + * @param string $data original data + * @param string $secret the secret + * + * @return string the encrypted result + */ + public function blowfishEncrypt($data, $secret) + { + global $iv; + if (! function_exists('mcrypt_encrypt')) { + /** + * This library uses mcrypt when available, so + * we could always call it instead of having an + * if/then/else logic, however the include_once + * call is costly + */ + include_once "./libraries/phpseclib/Crypt/AES.php"; + $cipher = new Crypt_AES(CRYPT_AES_MODE_ECB); + $cipher->setKey($secret); + return base64_encode($cipher->encrypt($data)); + } else { + return base64_encode( + mcrypt_encrypt( + MCRYPT_BLOWFISH, + $secret, + $data, + MCRYPT_MODE_CBC, + $iv + ) + ); + } + } + + /** + * Decryption using blowfish algorithm (mcrypt) + * or phpseclib's AES if mcrypt not available + * + * @param string $encdata encrypted data + * @param string $secret the secret + * + * @return string original data + */ + public function blowfishDecrypt($encdata, $secret) + { + global $iv; + if (! function_exists('mcrypt_encrypt')) { + include_once "./libraries/phpseclib/Crypt/AES.php"; + $cipher = new Crypt_AES(CRYPT_AES_MODE_ECB); + $cipher->setKey($secret); + return $cipher->decrypt(base64_decode($encdata)); + } else { + $data = base64_decode($encdata); + $decrypted = mcrypt_decrypt( + MCRYPT_BLOWFISH, + $secret, + $data, + MCRYPT_MODE_CBC, + $iv + ); + return trim($decrypted); + } + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +} diff --git a/phpmyadmin/libraries/plugins/auth/AuthenticationHttp.class.php b/phpmyadmin/libraries/plugins/auth/AuthenticationHttp.class.php new file mode 100644 index 000000000..f81ab92a5 --- /dev/null +++ b/phpmyadmin/libraries/plugins/auth/AuthenticationHttp.class.php @@ -0,0 +1,249 @@ +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; + } + + exit; + } + + /** + * Gets advanced authentication settings + * + * @global string the username if register_globals is on + * @global string the password if register_globals is on + * @global array the array of server variables if register_globals is + * off + * @global array the array of environment variables if register_globals + * is off + * @global string the username for the ? server + * @global string the password for the ? server + * @global string the username for the WebSite Professional server + * @global string the password for the WebSite Professional server + * @global string the username of the user who logs out + * + * @return boolean whether we get authentication settings or not + */ + public function authCheck() + { + global $PHP_AUTH_USER, $PHP_AUTH_PW; + + // Grabs the $PHP_AUTH_USER variable whatever are the values of the + // 'register_globals' and the 'variables_order' directives + if (empty($PHP_AUTH_USER)) { + if (PMA_getenv('PHP_AUTH_USER')) { + $PHP_AUTH_USER = PMA_getenv('PHP_AUTH_USER'); + } elseif (PMA_getenv('REMOTE_USER')) { + // CGI, might be encoded, see below + $PHP_AUTH_USER = PMA_getenv('REMOTE_USER'); + } elseif (PMA_getenv('REDIRECT_REMOTE_USER')) { + // CGI, might be encoded, see below + $PHP_AUTH_USER = PMA_getenv('REDIRECT_REMOTE_USER'); + } elseif (PMA_getenv('AUTH_USER')) { + // WebSite Professional + $PHP_AUTH_USER = PMA_getenv('AUTH_USER'); + } elseif (PMA_getenv('HTTP_AUTHORIZATION') + && false === strpos(PMA_getenv('HTTP_AUTHORIZATION'), '<') + ) { + // IIS, might be encoded, see below; also prevent XSS + $PHP_AUTH_USER = PMA_getenv('HTTP_AUTHORIZATION'); + } elseif (PMA_getenv('Authorization')) { + // FastCGI, might be encoded, see below + $PHP_AUTH_USER = PMA_getenv('Authorization'); + } + } + // Grabs the $PHP_AUTH_PW variable whatever are the values of the + // 'register_globals' and the 'variables_order' directives + if (empty($PHP_AUTH_PW)) { + if (PMA_getenv('PHP_AUTH_PW')) { + $PHP_AUTH_PW = PMA_getenv('PHP_AUTH_PW'); + } elseif (PMA_getenv('REMOTE_PASSWORD')) { + // Apache/CGI + $PHP_AUTH_PW = PMA_getenv('REMOTE_PASSWORD'); + } elseif (PMA_getenv('AUTH_PASSWORD')) { + // WebSite Professional + $PHP_AUTH_PW = PMA_getenv('AUTH_PASSWORD'); + } + } + + // Decode possibly encoded information (used by IIS/CGI/FastCGI) + // (do not use explode() because a user might have a colon in his password + if (strcmp(substr($PHP_AUTH_USER, 0, 6), 'Basic ') == 0) { + $usr_pass = base64_decode(substr($PHP_AUTH_USER, 6)); + if (! empty($usr_pass)) { + $colon = strpos($usr_pass, ':'); + if ($colon) { + $PHP_AUTH_USER = substr($usr_pass, 0, $colon); + $PHP_AUTH_PW = substr($usr_pass, $colon + 1); + } + unset($colon); + } + unset($usr_pass); + } + + // User logged out -> ensure the new username is not the same + $old_usr = isset($_REQUEST['old_usr']) ? $_REQUEST['old_usr'] : ''; + if (! empty($old_usr) + && (isset($PHP_AUTH_USER) && $old_usr == $PHP_AUTH_USER) + ) { + $PHP_AUTH_USER = ''; + // -> delete user's choices that were stored in session + session_destroy(); + } + + // Returns whether we get authentication settings or not + if (empty($PHP_AUTH_USER)) { + return false; + } else { + return true; + } + } + + /** + * Set the user and password after last checkings if required + * + * @global array the valid servers settings + * @global integer the id of the current server + * @global array the current server settings + * @global string the current username + * @global string the current password + * + * @return boolean always true + */ + public function authSetUser() + { + global $cfg, $server; + global $PHP_AUTH_USER, $PHP_AUTH_PW; + + // Ensures valid authentication mode, 'only_db', bookmark database and + // table names and relation table name are used + if ($cfg['Server']['user'] != $PHP_AUTH_USER) { + $servers_cnt = count($cfg['Servers']); + for ($i = 1; $i <= $servers_cnt; $i++) { + if (isset($cfg['Servers'][$i]) + && ($cfg['Servers'][$i]['host'] == $cfg['Server']['host'] + && $cfg['Servers'][$i]['user'] == $PHP_AUTH_USER) + ) { + $server = $i; + $cfg['Server'] = $cfg['Servers'][$i]; + break; + } + } // end for + } // end if + + $cfg['Server']['user'] = $PHP_AUTH_USER; + $cfg['Server']['password'] = $PHP_AUTH_PW; + + // Avoid showing the password in phpinfo()'s output + unset($GLOBALS['PHP_AUTH_PW']); + unset($_SERVER['PHP_AUTH_PW']); + + return true; + } + + /** + * User is not allowed to login to MySQL -> authentication failed + * + * @return boolean always true (no return indeed) + */ + public function authFails() + { + $error = PMA_DBI_getError(); + if ($error && $GLOBALS['errno'] != 1045) { + PMA_fatalError($error); + } else { + $this->auth(); + return true; + } + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +} diff --git a/phpmyadmin/libraries/plugins/auth/AuthenticationSignon.class.php b/phpmyadmin/libraries/plugins/auth/AuthenticationSignon.class.php new file mode 100644 index 000000000..ee1cf364b --- /dev/null +++ b/phpmyadmin/libraries/plugins/auth/AuthenticationSignon.class.php @@ -0,0 +1,284 @@ + authentication failed + * + * @return boolean always true (no return indeed) + */ + public function authFails() + { + /* Session name */ + $session_name = $GLOBALS['cfg']['Server']['SignonSession']; + + /* Does session exist? */ + if (isset($_COOKIE[$session_name])) { + /* End current session */ + $old_session = session_name(); + $old_id = session_id(); + session_write_close(); + + /* Load single signon session */ + session_name($session_name); + session_id($_COOKIE[$session_name]); + session_start(); + + /* Set error message */ + if (! empty($GLOBALS['login_without_password_is_forbidden'])) { + $_SESSION['PMA_single_signon_error_message'] = __( + 'Login without a password is forbidden by configuration ' + . '(see AllowNoPassword)' + ); + } elseif (! empty($GLOBALS['allowDeny_forbidden'])) { + $_SESSION['PMA_single_signon_error_message'] = __('Access denied'); + } elseif (! empty($GLOBALS['no_activity'])) { + $_SESSION['PMA_single_signon_error_message'] = sprintf( + __('No activity within %s seconds; please log in again'), + $GLOBALS['cfg']['LoginCookieValidity'] + ); + } elseif (PMA_DBI_getError()) { + $_SESSION['PMA_single_signon_error_message'] = PMA_sanitize( + PMA_DBI_getError() + ); + } else { + $_SESSION['PMA_single_signon_error_message'] = __( + 'Cannot log in to the MySQL server' + ); + } + } + $this->auth(); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +} \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/auth/swekey/authentication.inc.php b/phpmyadmin/libraries/plugins/auth/swekey/authentication.inc.php new file mode 100644 index 000000000..1977f883e --- /dev/null +++ b/phpmyadmin/libraries/plugins/auth/swekey/authentication.inc.php @@ -0,0 +1,172 @@ + + + diff --git a/phpmyadmin/libraries/plugins/auth/swekey/musbe-ca.crt b/phpmyadmin/libraries/plugins/auth/swekey/musbe-ca.crt new file mode 100644 index 000000000..2a31ad18f --- /dev/null +++ b/phpmyadmin/libraries/plugins/auth/swekey/musbe-ca.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIJAMjw7QcLWCd6MA0GCSqGSIb3DQEBBQUAMGsxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQKEwtNdXNiZSwgSW5j +LjESMBAGA1UEAxMJbXVzYmUuY29tMR0wGwYJKoZIhvcNAQkBFg5pbmZvQG11c2Jl +LmNvbTAeFw0wODA5MDQxNDE2MTNaFw0zNzEyMjExNDE2MTNaMGsxCzAJBgNVBAYT +AlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQKEwtNdXNiZSwgSW5jLjES +MBAGA1UEAxMJbXVzYmUuY29tMR0wGwYJKoZIhvcNAQkBFg5pbmZvQG11c2JlLmNv +bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOBhOljxVzQfK4gted2I +d3BemcjW4abAUOzn3KYWXpPO5xIfVeXNDGkDbyH+X+7fo94sX25/ewuKNFDSOcvo +tXHq7uQenTHB35r+a+LY81KceUHgW90a3XsqPAkwAjyYcgo3zmM2DtLvw+5Yod8T +wAHk9m3qavnQ1uk99jBTwL7RZ9jIZHh9pFCL93uJc2obtd8O96Iycbn2q0w/AWbb ++eUVWIHzvLtfPvROeL3lJzr/Uz5LjKapxJ3qyqASflfHpnj9pU8l6g2TQ6Hg5KT5 +tLFkRe7uGhOfRtOQ/+NjaWrEuNCFnpyN4Q5Fv+5qA1Ip1IpH0200sWbAf/k2u0Qp +Sx0CAwEAAaOB0DCBzTAdBgNVHQ4EFgQUczJrQ7hCvtsnzcqiDIZ/GSn/CiwwgZ0G +A1UdIwSBlTCBkoAUczJrQ7hCvtsnzcqiDIZ/GSn/Ciyhb6RtMGsxCzAJBgNVBAYT +AlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQKEwtNdXNiZSwgSW5jLjES +MBAGA1UEAxMJbXVzYmUuY29tMR0wGwYJKoZIhvcNAQkBFg5pbmZvQG11c2JlLmNv +bYIJAMjw7QcLWCd6MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGxk +8xzIljeBDQWWVRr0NEALVSv3i09V4jAKkyEOfmZ8lKMKJi0atwbtjrXTzLnNYj+Q +pyUbyY/8ItWvV7pnVxMiF9qcer7e9X4vw358GZuMVE/da1nWxz+CwzTm5oO30RzA +antM9bISFFr9lJq69bDWOnCUi1IG8DSL3TxtlABso7S4vqiZ+sB33l6k1K4a/Njb +QkU9UejKhKkVVZTsOrumfnOJ4MCmPfX8Y/AY2o670y5HnzpxerIYziCVzApPVrW7 +sKH0tuVGturMfQOKgstYe4/m9glBTeTLMkjD+6MJC2ONBD7GAiOO95gNl5M1fzJQ +FEe5CJ7DCYl0GdmLXXw= +-----END CERTIFICATE----- diff --git a/phpmyadmin/libraries/plugins/auth/swekey/swekey.auth.lib.php b/phpmyadmin/libraries/plugins/auth/swekey/swekey.auth.lib.php new file mode 100644 index 000000000..2231de469 --- /dev/null +++ b/phpmyadmin/libraries/plugins/auth/swekey/swekey.auth.lib.php @@ -0,0 +1,293 @@ + + + \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://")) { + return "Internal Error: CA File $caFile not found"; + } + + $result = null; + $swekey_id = $_GET['swekey_id']; + $swekey_otp = $_GET['swekey_otp']; + + if (isset($swekey_id)) { + unset($_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY']); + if (! isset($_SESSION['SWEKEY']['RND_TOKEN'])) { + unset($swekey_id); + } else { + if (strlen($swekey_id) == 32) { + $res = Swekey_CheckOtp($swekey_id, $_SESSION['SWEKEY']['RND_TOKEN'], $swekey_otp); + unset($_SESSION['SWEKEY']['RND_TOKEN']); + if (! $res) { + $result = __('Hardware authentication failed') . ' (' . Swekey_GetLastError() . ')'; + } else { + $_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY'] = $swekey_id; + $_SESSION['SWEKEY']['FORCE_USER'] = $_SESSION['SWEKEY']['VALID_SWEKEYS'][$swekey_id]; + return null; + } + } else { + $result = __('No valid authentication key plugged'); + if ($_SESSION['SWEKEY']['CONF_DEBUG']) { + $result .= "
      " . htmlspecialchars($swekey_id); + } + unset($_SESSION['SWEKEY']['CONF_LOADED']); // reload the conf file + } + } + } else { + unset($_SESSION['SWEKEY']); + } + + $_SESSION['SWEKEY']['RND_TOKEN'] = Swekey_GetFastRndToken(); + if (strlen($_SESSION['SWEKEY']['RND_TOKEN']) != 64) { + $result = __('Hardware authentication failed') . ' (' . Swekey_GetLastError() . ')'; + unset($_SESSION['SWEKEY']['CONF_LOADED']); // reload the conf file + } + + if (! isset($swekey_id)) { + ?> + + display(); + if ($GLOBALS['error_handler']->hasDisplayErrors()) { + echo '
      '; + $GLOBALS['error_handler']->dispErrors(); + echo '
      '; + } + } + + if (isset($_SESSION['SWEKEY']) && $_SESSION['SWEKEY']['ENABLED']) { + echo ''; + } +} + +if (!empty($_GET['session_to_unset'])) { + session_write_close(); + session_id($_GET['session_to_unset']); + session_start(); + $_SESSION = array(); + session_write_close(); + session_destroy(); + exit; +} + +if (isset($_GET['swekey_reset'])) { + unset($_SESSION['SWEKEY']); +} + +?> diff --git a/phpmyadmin/libraries/plugins/auth/swekey/swekey.php b/phpmyadmin/libraries/plugins/auth/swekey/swekey.php new file mode 100644 index 000000000..d495d45b4 --- /dev/null +++ b/phpmyadmin/libraries/plugins/auth/swekey/swekey.php @@ -0,0 +1,522 @@ +"; + +/** + * Servers addresses + * Use the Swekey_SetXxxServer($server) functions to set them + */ + +global $gSwekeyCheckServer; +if (! isset($gSwekeyCheckServer)) { + $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER; +} + +global $gSwekeyRndTokenServer; +if (! isset($gSwekeyRndTokenServer)) { + $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER; +} + +global $gSwekeyStatusServer; +if (! isset($gSwekeyStatusServer)) { + $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER; +} + +global $gSwekeyCA; + +global $gSwekeyTokenCacheEnabled; +if (! isset($gSwekeyTokenCacheEnabled)) { + $gSwekeyTokenCacheEnabled = true; +} + +/** + * Change the address of the Check server. + * If $server is empty the default value 'http://auth-check.musbe.net' will be used + * + * @param server The protocol and hostname to use + * + * @access public + */ +function Swekey_SetCheckServer($server) +{ + global $gSwekeyCheckServer; + if (empty($server)) { + $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER; + } else { + $gSwekeyCheckServer = $server; + } +} + +/** + * Change the address of the Random Token Generator server. + * If $server is empty the default value 'http://auth-rnd-gen.musbe.net' will be used + * + * @param server The protocol and hostname to use + * + * @access public + */ +function Swekey_SetRndTokenServer($server) +{ + global $gSwekeyRndTokenServer; + if (empty($server)) { + $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER; + } else { + $gSwekeyRndTokenServer = $server; + } +} + +/** + * Change the address of the Satus server. + * If $server is empty the default value 'http://auth-status.musbe.net' will be used + * + * @param server The protocol and hostname to use + * + * @access public + */ +function Swekey_SetStatusServer($server) +{ + global $gSwekeyStatusServer; + if (empty($server)) { + $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER; + } else { + $gSwekeyStatusServer = $server; + } +} + +/** + * Change the certificat file in case of the the severs use https instead of http + * + * @param cafile The path of the crt file to use + * + * @access public + */ +function Swekey_SetCAFile($cafile) +{ + global $gSwekeyCA; + $gSwekeyCA = $cafile; +} + +/** + * Enable or disable the random token caching + * Because everybody has full access to the cache file, it can be a DOS vulnerability + * So disable it if you are running in a non secure enviromnement + * + * @param $enable + * + * @access public + */ +function Swekey_EnableTokenCache($enable) +{ + global $gSwekeyTokenCacheEnabled; + $gSwekeyTokenCacheEnabled = ! empty($enable); +} + + +/** + * Return the last error. + * + * @return The Last Error + * @access public + */ +function Swekey_GetLastError() +{ + global $gSwekeyLastError; + return $gSwekeyLastError; +} + +/** + * Return the last result. + * + * @return The Last Error + * @access public + */ +function Swekey_GetLastResult() +{ + global $gSwekeyLastResult; + return $gSwekeyLastResult; +} + +/** + * Send a synchronous request to the server. + * This function manages timeout then will not block if one of the server is down + * + * @param url The url to get + * @param response_code The response code + * + * @return The body of the response or "" in case of error + * @access private + */ +function Swekey_HttpGet($url, &$response_code) +{ + global $gSwekeyLastError; + $gSwekeyLastError = 0; + global $gSwekeyLastResult; + $gSwekeyLastResult = ""; + + // use curl if available + if (function_exists('curl_init')) { + $sess = curl_init($url); + if (substr($url, 0, 8) == "https://") { + global $gSwekeyCA; + + if (! empty($gSwekeyCA)) { + if (file_exists($gSwekeyCA)) { + if (! curl_setopt($sess, CURLOPT_CAINFO, $gSwekeyCA)) { + error_log("SWEKEY_ERROR:Could not set CA file : ".curl_error($sess)); + } else { + $caFileOk = true; + } + } else { + error_log("SWEKEY_ERROR:Could not find CA file $gSwekeyCA getting $url"); + } + } + + curl_setopt($sess, CURLOPT_SSL_VERIFYHOST, '2'); + curl_setopt($sess, CURLOPT_SSL_VERIFYPEER, '2'); + curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '20'); + curl_setopt($sess, CURLOPT_TIMEOUT, '20'); + } else { + curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '3'); + curl_setopt($sess, CURLOPT_TIMEOUT, '5'); + } + + curl_setopt($sess, CURLOPT_RETURNTRANSFER, '1'); + $res=curl_exec($sess); + $response_code = curl_getinfo($sess, CURLINFO_HTTP_CODE); + $curlerr = curl_error($sess); + curl_close($sess); + + if ($response_code == 200) { + $gSwekeyLastResult = $res; + return $res; + } + + if (! empty($response_code)) { + $gSwekeyLastError = $response_code; + error_log("SWEKEY_ERROR:Error $gSwekeyLastError ($curlerr) getting $url"); + return ""; + } + + $response_code = 408; // Request Timeout + $gSwekeyLastError = $response_code; + error_log("SWEKEY_ERROR:Error $curlerr getting $url"); + return ""; + } + + // use pecl_http if available + if (class_exists('HttpRequest')) { + // retry if one of the server is down + for ($num=1; $num <= 3; $num++ ) { + $r = new HttpRequest($url); + $options = array('timeout' => '3'); + + if (substr($url, 0, 6) == "https:") { + $sslOptions = array(); + $sslOptions['verifypeer'] = true; + $sslOptions['verifyhost'] = true; + + $capath = __FILE__; + $name = strrchr($capath, '/'); + // windows + if (empty($name)) { + $name = strrchr($capath, '\\'); + } + $capath = substr($capath, 0, strlen($capath) - strlen($name) + 1).'musbe-ca.crt'; + + if (! empty($gSwekeyCA)) { + $sslOptions['cainfo'] = $gSwekeyCA; + } + + $options['ssl'] = $sslOptions; + } + + $r->setOptions($options); + + // try + { + $reply = $r->send(); + $res = $reply->getBody(); + $info = $r->getResponseInfo(); + $response_code = $info['response_code']; + if ($response_code != 200) { + $gSwekeyLastError = $response_code; + error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url); + return ""; + } + + + $gSwekeyLastResult = $res; + return $res; + } + // catch (HttpException $e) + // { + // error_log("SWEKEY_WARNING:HttpException ".$e." getting ".$url); + // } + } + + $response_code = 408; // Request Timeout + $gSwekeyLastError = $response_code; + error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url); + return ""; + } + + global $http_response_header; + $res = @file_get_contents($url); + $response_code = substr($http_response_header[0], 9, 3); //HTTP/1.0 + if ($response_code == 200) { + $gSwekeyLastResult = $res; + return $res; + } + + $gSwekeyLastError = $response_code; + error_log("SWEKEY_ERROR:Error ".$response_code." getting ".$url); + return ""; +} + +/** + * Get a Random Token from a Token Server + * The RT is a 64 vhars hexadecimal value + * You should better use Swekey_GetFastRndToken() for performance + * @access public + */ +function Swekey_GetRndToken() +{ + global $gSwekeyRndTokenServer; + return Swekey_HttpGet($gSwekeyRndTokenServer.'/FULL-RND-TOKEN', $response_code); +} + +/** + * Get a Half Random Token from a Token Server + * The RT is a 64 vhars hexadecimal value + * Use this value if you want to make your own Swekey_GetFastRndToken() + * @access public + */ +function Swekey_GetHalfRndToken() +{ + global $gSwekeyRndTokenServer; + return Swekey_HttpGet($gSwekeyRndTokenServer.'/HALF-RND-TOKEN', $response_code); +} + +/** + * Get a Half Random Token + * The RT is a 64 vhars hexadecimal value + * This function get a new random token and reuse it. + * Token are refetched from the server only once every 30 seconds. + * You should always use this function to get half random token. + * @access public + */ +function Swekey_GetFastHalfRndToken() +{ + global $gSwekeyTokenCacheEnabled; + + $res = ""; + $cachefile = ""; + + // We check if we have a valid RT is the session + if (isset($_SESSION['rnd-token-date'])) { + if (time() - $_SESSION['rnd-token-date'] < 30) { + $res = $_SESSION['rnd-token']; + } + } + + // If not we try to get it from a temp file (PHP >= 5.2.1 only) + if (strlen($res) != 32 && $gSwekeyTokenCacheEnabled) { + if (function_exists('sys_get_temp_dir')) { + $tempdir = sys_get_temp_dir(); + $cachefile = $tempdir."/swekey-rnd-token-".get_current_user(); + $modif = filemtime($cachefile); + if ($modif != false) { + if (time() - $modif < 30) { + $res = @file_get_contents($cachefile); + if (strlen($res) != 32) { + $res = ""; + } else { + $_SESSION['rnd-token'] = $res; + $_SESSION['rnd-token-date'] = $modif; + } + } + } + } + } + + // If we don't have a valid RT here we have to get it from the server + if (strlen($res) != 32) { + $res = substr(Swekey_GetHalfRndToken(), 0, 32); + $_SESSION['rnd-token'] = $res; + $_SESSION['rnd-token-date'] = time(); + if (! empty($cachefile)) { + // we unlink the file so no possible tempfile race attack + unlink($cachefile); + $file = fopen($cachefile, "x"); + if ($file != false) { + @fwrite($file, $res); + @fclose($file); + } + } + } + + return $res."00000000000000000000000000000000"; +} + +/** + * Get a Random Token + * The RT is a 64 vhars hexadecimal value + * This function generates a unique random token for each call but call the + * server only once every 30 seconds. + * You should always use this function to get random token. + * @access public + */ +function Swekey_GetFastRndToken() +{ + $res = Swekey_GetFastHalfRndToken(); + if (strlen($res) == 64) { + return substr($res, 0, 32).strtoupper(md5("Musbe Authentication Key" . mt_rand() . date(DATE_ATOM))); + } + return ""; +} + + +/** + * Checks that an OTP generated by a Swekey is valid + * + * @param id The id of the swekey + * @param rt The random token used to generate the otp + * @param otp The otp generated by the swekey + * + * @return true or false + * @access public + */ +function Swekey_CheckOtp($id, $rt, $otp) +{ + global $gSwekeyCheckServer; + $res = Swekey_HttpGet($gSwekeyCheckServer.'/CHECK-OTP/'.$id.'/'.$rt.'/'.$otp, $response_code); + return $response_code == 200 && $res == "OK"; +} + +/** + * Values that are associated with a key. + * The following values can be returned by the Swekey_GetStatus() function + */ +define("SWEKEY_STATUS_OK", 0); +define("SWEKEY_STATUS_NOT_FOUND", 1); // The key does not exist in the db +define("SWEKEY_STATUS_INACTIVE", 2); // The key has never been activated +define("SWEKEY_STATUS_LOST", 3); // The user has lost his key +define("SWEKEY_STATUS_STOLEN", 4); // The key was stolen +define("SWEKEY_STATUS_FEE_DUE", 5); // The annual fee was not paid +define("SWEKEY_STATUS_OBSOLETE", 6); // The hardware is no longer supported +define("SWEKEY_STATUS_UNKOWN", 201); // We could not connect to the authentication server + +/** + * Values that are associated with a key. + * The Javascript Api can also return the following values + */ +define("SWEKEY_STATUS_REPLACED", 100); // This key has been replaced by a backup key +define("SWEKEY_STATUS_BACKUP_KEY", 101); // This key is a backup key that is not activated yet +define("SWEKEY_STATUS_NOTPLUGGED", 200); // This key is not plugged in the computer + + +/** + * Return the text corresponding to the integer status of a key + * + * @param status The status + * + * @return The text corresponding to the status + * @access public + */ +function Swekey_GetStatusStr($status) +{ + switch($status) + { + case SWEKEY_STATUS_OK : + return 'OK'; + case SWEKEY_STATUS_NOT_FOUND : + return 'Key does not exist in the db'; + case SWEKEY_STATUS_INACTIVE : + return 'Key not activated'; + case SWEKEY_STATUS_LOST : + return 'Key was lost'; + case SWEKEY_STATUS_STOLEN : + return 'Key was stolen'; + case SWEKEY_STATUS_FEE_DUE : + return 'The annual fee was not paid'; + case SWEKEY_STATUS_OBSOLETE : + return 'Key no longer supported'; + case SWEKEY_STATUS_REPLACED : + return 'This key has been replaced by a backup key'; + case SWEKEY_STATUS_BACKUP_KEY : + return 'This key is a backup key that is not activated yet'; + case SWEKEY_STATUS_NOTPLUGGED : + return 'This key is not plugged in the computer'; + case SWEKEY_STATUS_UNKOWN : + return 'Unknow Status, could not connect to the authentication server'; + } + return 'unknown status '.$status; +} + +/** + * If your web site requires a key to login you should check that the key + * is still valid (has not been lost or stolen) before requiring it. + * A key can be authenticated only if its status is SWEKEY_STATUS_OK + * + * @param id The id of the swekey + * + * @return The status of the swekey + * @access public + */ +function Swekey_GetStatus($id) +{ + global $gSwekeyStatusServer; + $res = Swekey_HttpGet($gSwekeyStatusServer.'/GET-STATUS/'.$id, $response_code); + if ($response_code == 200) { + return intval($res); + } + return SWEKEY_STATUS_UNKOWN; +} + +?> diff --git a/phpmyadmin/libraries/plugins/export/ExportCodegen.class.php b/phpmyadmin/libraries/plugins/export/ExportCodegen.class.php new file mode 100644 index 000000000..d0a2216a4 --- /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 = PMA_DBI_query( + sprintf( + 'DESC %s.%s', PMA_Util::backquote($db), + PMA_Util::backquote($table) + ) + ); + if ($result) { + $tableProperties = array(); + while ($row = PMA_DBI_fetch_row($result)) { + $tableProperties[] = new TableProperty($row); + } + PMA_DBI_free_result($result); + $lines[] = 'using System;'; + $lines[] = 'using System.Collections;'; + $lines[] = 'using System.Collections.Generic;'; + $lines[] = 'using System.Text;'; + $lines[] = 'namespace ' . ExportCodegen::cgMakeIdentifier($db); + $lines[] = '{'; + $lines[] = ' #region ' . ExportCodegen::cgMakeIdentifier($table); + $lines[] = ' public class ' . ExportCodegen::cgMakeIdentifier($table); + $lines[] = ' {'; + $lines[] = ' #region Member Variables'; + foreach ($tableProperties as $tableProperty) { + $lines[] = $tableProperty->formatCs( + ' protected #dotNetPrimitiveType# _#name#;' + ); + } + $lines[] = ' #endregion'; + $lines[] = ' #region Constructors'; + $lines[] = ' public ' + . ExportCodegen::cgMakeIdentifier($table) . '() { }'; + $temp = array(); + foreach ($tableProperties as $tableProperty) { + if (! $tableProperty->isPK()) { + $temp[] = $tableProperty->formatCs( + '#dotNetPrimitiveType# #name#' + ); + } + } + $lines[] = ' public ' + . ExportCodegen::cgMakeIdentifier($table) + . '(' + . implode(', ', $temp) + . ')'; + $lines[] = ' {'; + foreach ($tableProperties as $tableProperty) { + if (! $tableProperty->isPK()) { + $lines[] = $tableProperty->formatCs( + ' this._#name#=#name#;' + ); + } + } + $lines[] = ' }'; + $lines[] = ' #endregion'; + $lines[] = ' #region Public Properties'; + foreach ($tableProperties as $tableProperty) { + $lines[] = $tableProperty->formatCs( + ' public virtual #dotNetPrimitiveType# #ucfirstName#' + . "\n" + . ' {' . "\n" + . ' get {return _#name#;}' . "\n" + . ' set {_#name#=value;}' . "\n" + . ' }' + ); + } + $lines[] = ' #endregion'; + $lines[] = ' }'; + $lines[] = ' #endregion'; + $lines[] = '}'; + } + return implode("\n", $lines); + } + + /** + * XML Handler + * + * @param string $db database name + * @param string $table table name + * @param string $crlf line separator + * + * @return string containing XML code lines, separated by "\n" + */ + private function _handleNHibernateXMLBody($db, $table, $crlf) + { + $lines = array(); + $lines[] = ''; + $lines[] = ''; + $lines[] = ' '; + $result = PMA_DBI_query( + sprintf( + "DESC %s.%s", PMA_Util::backquote($db), + PMA_Util::backquote($table) + ) + ); + if ($result) { + while ($row = PMA_DBI_fetch_row($result)) { + $tableProperty = new TableProperty($row); + if ($tableProperty->isPK()) { + $lines[] = $tableProperty->formatXml( + ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' + ); + } else { + $lines[] = $tableProperty->formatXml( + ' ' . "\n" + . ' ' . "\n" + . ' ' + ); + } + } + PMA_DBI_free_result($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 000000000..98558e925 --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/ExportCsv.class.php @@ -0,0 +1,345 @@ +setProperties(); + } + + /** + * Sets the export CSV properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('CSV'); + $exportPluginProperties->setExtension('csv'); + $exportPluginProperties->setMimeType('text/comma-separated-values'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create leaf items and add them to the group + $leaf = new TextPropertyItem(); + $leaf->setName("separator"); + $leaf->setText(__('Columns separated with:')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("enclosed"); + $leaf->setText(__('Columns enclosed with:')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("escaped"); + $leaf->setText(__('Columns escaped with:')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("terminated"); + $leaf->setText(__('Lines terminated with:')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('Replace NULL with:')); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('removeCRLF'); + $leaf->setText( + __('Remove carriage return/line feed characters within columns') + ); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('columns'); + $leaf->setText(__('Put columns names in the first row')); + $generalOptions->addProperty($leaf); + $leaf = new HiddenPropertyItem(); + $leaf->setName('structure_or_data'); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped; + + // Here we just prepare some values for export + if ($what == 'excel') { + $csv_terminated = "\015\012"; + switch($GLOBALS['excel_edition']) { + case 'win': + // as tested on Windows with Excel 2002 and Excel 2007 + $csv_separator = ';'; + break; + case 'mac_excel2003': + $csv_separator = ';'; + break; + case 'mac_excel2008': + $csv_separator = ','; + break; + } + $csv_enclosed = '"'; + $csv_escaped = '"'; + if (isset($GLOBALS['excel_columns'])) { + $GLOBALS['csv_columns'] = 'yes'; + } + } else { + if (empty($csv_terminated) || strtolower($csv_terminated) == 'auto') { + $csv_terminated = $GLOBALS['crlf']; + } else { + $csv_terminated = str_replace('\\r', "\015", $csv_terminated); + $csv_terminated = str_replace('\\n', "\012", $csv_terminated); + $csv_terminated = str_replace('\\t', "\011", $csv_terminated); + } // end if + $csv_separator = str_replace('\\t', "\011", $csv_separator); + } + + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs the content of a table in CSV format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped; + + // Gets the data from the database + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $fields_cnt = PMA_DBI_num_fields($result); + + // If required, get fields name at the first line + if (isset($GLOBALS['csv_columns'])) { + $schema_insert = ''; + for ($i = 0; $i < $fields_cnt; $i++) { + if ($csv_enclosed == '') { + $schema_insert .= stripslashes(PMA_DBI_field_name($result, $i)); + } else { + $schema_insert .= $csv_enclosed + . str_replace( + $csv_enclosed, + $csv_escaped . $csv_enclosed, + stripslashes(PMA_DBI_field_name($result, $i)) + ) + . $csv_enclosed; + } + $schema_insert .= $csv_separator; + } // end for + $schema_insert = trim(substr($schema_insert, 0, -1)); + if (! PMA_exportOutputHandler($schema_insert . $csv_terminated)) { + return false; + } + } // end if + + // Format the data + while ($row = PMA_DBI_fetch_row($result)) { + $schema_insert = ''; + for ($j = 0; $j < $fields_cnt; $j++) { + if (! isset($row[$j]) || is_null($row[$j])) { + $schema_insert .= $GLOBALS[$what . '_null']; + } elseif ($row[$j] == '0' || $row[$j] != '') { + // always enclose fields + if ($what == 'excel') { + $row[$j] = preg_replace("/\015(\012)?/", "\012", $row[$j]); + } + // remove CRLF characters within field + if (isset($GLOBALS[$what . '_removeCRLF']) + && $GLOBALS[$what . '_removeCRLF'] + ) { + $row[$j] = str_replace( + "\n", + "", + str_replace( + "\r", + "", + $row[$j] + ) + ); + } + if ($csv_enclosed == '') { + $schema_insert .= $row[$j]; + } else { + // also double the escape string if found in the data + if ($csv_escaped != $csv_enclosed) { + $schema_insert .= $csv_enclosed + . str_replace( + $csv_enclosed, + $csv_escaped . $csv_enclosed, + str_replace( + $csv_escaped, + $csv_escaped . $csv_escaped, + $row[$j] + ) + ) + . $csv_enclosed; + } else { + // avoid a problem when escape string equals enclose + $schema_insert .= $csv_enclosed + . str_replace( + $csv_enclosed, + $csv_escaped . $csv_enclosed, + $row[$j] + ) + . $csv_enclosed; + } + } + } else { + $schema_insert .= ''; + } + if ($j < $fields_cnt-1) { + $schema_insert .= $csv_separator; + } + } // end for + + if (! PMA_exportOutputHandler($schema_insert . $csv_terminated)) { + return false; + } + } // end while + PMA_DBI_free_result($result); + + return true; + } +} +?> \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/export/ExportExcel.class.php b/phpmyadmin/libraries/plugins/export/ExportExcel.class.php new file mode 100644 index 000000000..1bb1060d2 --- /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 000000000..cdd5ec683 --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/ExportHtmlword.class.php @@ -0,0 +1,645 @@ +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 = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $fields_cnt = PMA_DBI_num_fields($result); + + // If required, get fields name at the first line + if (isset($GLOBALS['htmlword_columns'])) { + $schema_insert = ''; + 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 = PMA_DBI_fetch_row($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 + PMA_DBI_free_result($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 = PMA_DBI_get_table_indexes($db, $view); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + + $columns = PMA_DBI_get_columns($db, $view); + foreach ($columns as $column) { + $schema_insert .= $this->formatOneColumnDefinition( + $column, + $unique_keys + ); + $schema_insert .= ''; + } + + $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 + */ + PMA_DBI_select_db($db); + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + /** + * Displays the table structure + */ + $schema_insert .= ''; + + $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 = PMA_DBI_get_columns($db, $table); + /** + * Get the unique keys in the table + */ + $unique_keys = array(); + $keys = PMA_DBI_get_table_indexes($db, $table); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + foreach ($columns as $column) { + $schema_insert .= $this->formatOneColumnDefinition( + $column, + $unique_keys + ); + $field_name = $column['Field']; + + if ($do_relation && $have_rel) { + $schema_insert .= ''; + } + 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 = PMA_DBI_get_triggers($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 = PMA_DBI_get_triggers($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; + } +} +?> \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/export/ExportJson.class.php b/phpmyadmin/libraries/plugins/export/ExportJson.class.php new file mode 100644 index 000000000..299e248c0 --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/ExportJson.class.php @@ -0,0 +1,221 @@ +setProperties(); + } + + /** + * Sets the export JSON properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('JSON'); + $exportPluginProperties->setExtension('json'); + $exportPluginProperties->setMimeType('text/plain'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new HiddenPropertyItem(); + $leaf->setName("structure_or_data"); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + PMA_exportOutputHandler( + '/**' . $GLOBALS['crlf'] + . ' Export to JSON plugin for PHPMyAdmin' . $GLOBALS['crlf'] + . ' @version 0.1' . $GLOBALS['crlf'] + . ' */' . $GLOBALS['crlf'] . $GLOBALS['crlf'] + ); + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + PMA_exportOutputHandler('// Database \'' . $db . '\'' . $GLOBALS['crlf']); + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs the content of a table in JSON format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $columns_cnt = PMA_DBI_num_fields($result); + + // Get field information + $fields_meta = PMA_DBI_get_fields_meta($result); + + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = stripslashes(PMA_DBI_field_name($result, $i)); + } + unset($i); + + $buffer = ''; + $record_cnt = 0; + while ($record = PMA_DBI_fetch_row($result)) { + + $record_cnt++; + + // Output table name as comment if this is the first record of the table + if ($record_cnt == 1) { + $buffer .= '// ' . $db . '.' . $table . $crlf . $crlf; + $buffer .= '[{'; + } else { + $buffer .= ', {'; + } + + for ($i = 0; $i < $columns_cnt; $i++) { + $isLastLine = ($i + 1 >= $columns_cnt); + $column = $columns[$i]; + if (is_null($record[$i])) { + $buffer .= '"' . addslashes($column) + . '": null' + . (! $isLastLine ? ',' : ''); + } elseif ($fields_meta[$i]->numeric) { + $buffer .= '"' . addslashes($column) + . '": ' + . $record[$i] + . (! $isLastLine ? ',' : ''); + } else { + $buffer .= '"' . addslashes($column) + . '": "' + . addslashes($record[$i]) + . '"' + . (! $isLastLine ? ',' : ''); + } + } + + $buffer .= '}'; + } + + if ($record_cnt) { + $buffer .= ']'; + } + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + PMA_DBI_free_result($result); + return true; + } +} +?> \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/export/ExportLatex.class.php b/phpmyadmin/libraries/plugins/export/ExportLatex.class.php new file mode 100644 index 000000000..0f5c953a8 --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/ExportLatex.class.php @@ -0,0 +1,655 @@ +initSpecificVariables(); + + $this->setProperties(); + } + + /** + * Initialize the local variables that are used for export Latex + * + * @return void + */ + protected function initSpecificVariables() + { + /* Messages used in default captions */ + $GLOBALS['strLatexContent'] = __('Content of table @TABLE@'); + $GLOBALS['strLatexContinued'] = __('(continued)'); + $GLOBALS['strLatexStructure'] = __('Structure of table @TABLE@'); + } + + /** + * Sets the export Latex properties + * + * @return void + */ + protected function setProperties() + { + global $plugin_param; + $hide_structure = false; + if ($plugin_param['export_type'] == 'table' + && ! $plugin_param['single_table'] + ) { + $hide_structure = true; + } + + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('LaTeX'); + $exportPluginProperties->setExtension('tex'); + $exportPluginProperties->setMimeType('application/x-tex'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("caption"); + $leaf->setText(__('Include table caption')); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // what to dump (structure/data/both) main group + $dumpWhat = new OptionsPropertyMainGroup(); + $dumpWhat->setName("dump_what"); + $dumpWhat->setText(__('Dump table')); + // create primary items and add them to the group + $leaf = new RadioPropertyItem(); + $leaf->setName("structure_or_data"); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $dumpWhat->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($dumpWhat); + + // structure options main group + if (! $hide_structure) { + $structureOptions = new OptionsPropertyMainGroup(); + $structureOptions->setName("structure"); + $structureOptions->setText(__('Object creation options')); + $structureOptions->setForce('data'); + // create primary items and add them to the group + $leaf = new TextPropertyItem(); + $leaf->setName("structure_caption"); + $leaf->setText(__('Table caption')); + $leaf->setDoc('faq6-27'); + $structureOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("structure_continued_caption"); + $leaf->setText(__('Table caption (continued)')); + $leaf->setDoc('faq6-27'); + $structureOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("structure_label"); + $leaf->setText(__('Label key')); + $leaf->setDoc('faq6-27'); + $structureOptions->addProperty($leaf); + if (! empty($GLOBALS['cfgRelation']['relation'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName("relation"); + $leaf->setText(__('Display foreign key relationships')); + $structureOptions->addProperty($leaf); + } + $leaf = new BoolPropertyItem(); + $leaf->setName("comments"); + $leaf->setText(__('Display comments')); + $structureOptions->addProperty($leaf); + if (! empty($GLOBALS['cfgRelation']['mimework'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName("mime"); + $leaf->setText(__('Display MIME types')); + $structureOptions->addProperty($leaf); + } + // add the main group to the root group + $exportSpecificOptions->addProperty($structureOptions); + } + + // data options main group + $dataOptions = new OptionsPropertyMainGroup(); + $dataOptions->setName("data"); + $dataOptions->setText(__('Data dump options')); + $dataOptions->setForce('structure'); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Put columns names in the first row')); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("data_caption"); + $leaf->setText(__('Table caption')); + $leaf->setDoc('faq6-27'); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("data_continued_caption"); + $leaf->setText(__('Table caption (continued)')); + $leaf->setDoc('faq6-27'); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("data_label"); + $leaf->setText(__('Label key')); + $leaf->setDoc('faq6-27'); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('Replace NULL with:')); + $dataOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($dataOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + global $crlf; + global $cfg; + + $head = '% phpMyAdmin LaTeX Dump' . $crlf + . '% version ' . PMA_VERSION . $crlf + . '% http://www.phpmyadmin.net' . $crlf + . '%' . $crlf + . '% ' . __('Host') . ': ' . $cfg['Server']['host']; + if (! empty($cfg['Server']['port'])) { + $head .= ':' . $cfg['Server']['port']; + } + $head .= $crlf + . '% ' . __('Generation Time') . ': ' + . PMA_Util::localisedDate() . $crlf + . '% ' . __('Server version') . ': ' . PMA_MYSQL_STR_VERSION . $crlf + . '% ' . __('PHP Version') . ': ' . phpversion() . $crlf; + return PMA_exportOutputHandler($head); + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + global $crlf; + $head = '% ' . $crlf + . '% ' . __('Database') . ': ' . '\'' . $db . '\'' . $crlf + . '% ' . $crlf; + return PMA_exportOutputHandler($head); + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs the content of a table in JSON format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $result = PMA_DBI_try_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + + $columns_cnt = PMA_DBI_num_fields($result); + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = PMA_DBI_field_name($result, $i); + } + unset($i); + + $buffer = $crlf . '%' . $crlf . '% ' . __('Data') . ': ' . $table + . $crlf . '%' . $crlf . ' \\begin{longtable}{|'; + + for ($index = 0; $index < $columns_cnt; $index++) { + $buffer .= 'l|'; + } + $buffer .= '} ' . $crlf ; + + $buffer .= ' \\hline \\endhead \\hline \\endfoot \\hline ' . $crlf; + if (isset($GLOBALS['latex_caption'])) { + $buffer .= ' \\caption{' + . PMA_Util::expandUserString( + $GLOBALS['latex_data_caption'], + array( + 'texEscape', + get_class($this), + 'libraries/plugins/export/' . get_class($this) . ".class.php" + ), + array('table' => $table, 'database' => $db) + ) + . '} \\label{' + . PMA_Util::expandUserString( + $GLOBALS['latex_data_label'], + null, + array('table' => $table, 'database' => $db) + ) + . '} \\\\'; + } + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + // show column names + if (isset($GLOBALS['latex_columns'])) { + $buffer = '\\hline '; + for ($i = 0; $i < $columns_cnt; $i++) { + $buffer .= '\\multicolumn{1}{|c|}{\\textbf{' + . self::texEscape(stripslashes($columns[$i])) . '}} & '; + } + + $buffer = substr($buffer, 0, -2) . '\\\\ \\hline \hline '; + if (! PMA_exportOutputHandler($buffer . ' \\endfirsthead ' . $crlf)) { + return false; + } + if (isset($GLOBALS['latex_caption'])) { + if (! PMA_exportOutputHandler( + '\\caption{' + . PMA_Util::expandUserString( + $GLOBALS['latex_data_continued_caption'], + array( + 'texEscape', + get_class($this), + 'libraries/plugins/export/' + . get_class($this) . ".class.php" + ), + array('table' => $table, 'database' => $db) + ) + . '} \\\\ ' + )) { + return false; + } + } + if (! PMA_exportOutputHandler($buffer . '\\endhead \\endfoot' . $crlf)) { + return false; + } + } else { + if (! PMA_exportOutputHandler('\\\\ \hline')) { + return false; + } + } + + // print the whole table + while ($record = PMA_DBI_fetch_assoc($result)) { + $buffer = ''; + // print each row + for ($i = 0; $i < $columns_cnt; $i++) { + if ((! function_exists('is_null') + || ! is_null($record[$columns[$i]])) + && isset($record[$columns[$i]]) + ) { + $column_value = self::texEscape( + stripslashes($record[$columns[$i]]) + ); + } else { + $column_value = $GLOBALS['latex_null']; + } + + // last column ... no need for & character + if ($i == ($columns_cnt - 1)) { + $buffer .= $column_value; + } else { + $buffer .= $column_value . " & "; + } + } + $buffer .= ' \\\\ \\hline ' . $crlf; + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + } + + $buffer = ' \\end{longtable}' . $crlf; + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + PMA_DBI_free_result($result); + return true; + } // end getTableLaTeX + + /** + * Outputs table's structure + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $export_mode 'create_table', 'triggers', 'create_view', + * 'stand_in' + * @param string $export_type 'server', 'database', 'table' + * @param bool $do_relation whether to include relation comments + * @param bool $do_comments whether to include the pmadb-style column + * comments as comments in the structure; + * this is deprecated but the parameter is + * left here because export.php calls + * exportStructure() also for other + * export types which use this parameter + * @param bool $do_mime whether to include mime comments + * @param bool $dates whether to include creation/update/check dates + * + * @return bool Whether it succeeded + */ + public function exportStructure( + $db, + $table, + $crlf, + $error_url, + $export_mode, + $export_type, + $do_relation = false, + $do_comments = false, + $do_mime = false, + $dates = false + ) { + global $cfgRelation; + + /* We do not export triggers */ + if ($export_mode == 'triggers') { + return true; + } + + /** + * Get the unique keys in the table + */ + $unique_keys = array(); + $keys = PMA_DBI_get_table_indexes($db, $table); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + + /** + * Gets fields properties + */ + PMA_DBI_select_db($db); + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + /** + * Displays the table structure + */ + $buffer = $crlf . '%' . $crlf . '% ' . __('Structure') . ': ' . $table + . $crlf . '%' . $crlf . ' \\begin{longtable}{'; + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + $columns_cnt = 4; + $alignment = '|l|c|c|c|'; + if ($do_relation && $have_rel) { + $columns_cnt++; + $alignment .= 'l|'; + } + if ($do_comments) { + $columns_cnt++; + $alignment .= 'l|'; + } + if ($do_mime && $cfgRelation['mimework']) { + $columns_cnt++; + $alignment .='l|'; + } + $buffer = $alignment . '} ' . $crlf ; + + $header = ' \\hline '; + $header .= '\\multicolumn{1}{|c|}{\\textbf{' . __('Column') + . '}} & \\multicolumn{1}{|c|}{\\textbf{' . __('Type') + . '}} & \\multicolumn{1}{|c|}{\\textbf{' . __('Null') + . '}} & \\multicolumn{1}{|c|}{\\textbf{' . __('Default') . '}}'; + if ($do_relation && $have_rel) { + $header .= ' & \\multicolumn{1}{|c|}{\\textbf{' . __('Links to') . '}}'; + } + if ($do_comments) { + $header .= ' & \\multicolumn{1}{|c|}{\\textbf{' . __('Comments') . '}}'; + $comments = PMA_getComments($db, $table); + } + if ($do_mime && $cfgRelation['mimework']) { + $header .= ' & \\multicolumn{1}{|c|}{\\textbf{MIME}}'; + $mime_map = PMA_getMIME($db, $table, true); + } + + // Table caption for first page and label + if (isset($GLOBALS['latex_caption'])) { + $buffer .= ' \\caption{' + . PMA_Util::expandUserString( + $GLOBALS['latex_structure_caption'], + array( + 'texEscape', + get_class($this), + 'libraries/plugins/export/' . get_class($this) . ".class.php" + ), + array('table' => $table, 'database' => $db) + ) + . '} \\label{' + . PMA_Util::expandUserString( + $GLOBALS['latex_structure_label'], + null, + array('table' => $table, 'database' => $db) + ) + . '} \\\\' . $crlf; + } + $buffer .= $header . ' \\\\ \\hline \\hline' . $crlf + . '\\endfirsthead' . $crlf; + // Table caption on next pages + if (isset($GLOBALS['latex_caption'])) { + $buffer .= ' \\caption{' + . PMA_Util::expandUserString( + $GLOBALS['latex_structure_continued_caption'], + array( + 'texEscape', + get_class($this), + 'libraries/plugins/export/' . get_class($this) . ".class.php" + ), + array('table' => $table, 'database' => $db) + ) + . '} \\\\ ' . $crlf; + } + $buffer .= $header . ' \\\\ \\hline \\hline \\endhead \\endfoot ' . $crlf; + + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + $fields = PMA_DBI_get_columns($db, $table); + foreach ($fields as $row) { + $extracted_columnspec + = PMA_Util::extractColumnSpec( + $row['Type'] + ); + $type = $extracted_columnspec['print_type']; + if (empty($type)) { + $type = ' '; + } + + if (! isset($row['Default'])) { + if ($row['Null'] != 'NO') { + $row['Default'] = 'NULL'; + } + } + + $field_name = $row['Field']; + + $local_buffer = $field_name . "\000" . $type . "\000" + . (($row['Null'] == '' || $row['Null'] == 'NO') + ? __('No') : __('Yes')) + . "\000" . (isset($row['Default']) ? $row['Default'] : ''); + + if ($do_relation && $have_rel) { + $local_buffer .= "\000"; + if (isset($res_rel[$field_name])) { + $local_buffer .= $res_rel[$field_name]['foreign_table'] . ' (' + . $res_rel[$field_name]['foreign_field'] . ')'; + } + } + if ($do_comments && $cfgRelation['commwork']) { + $local_buffer .= "\000"; + if (isset($comments[$field_name])) { + $local_buffer .= $comments[$field_name]; + } + } + if ($do_mime && $cfgRelation['mimework']) { + $local_buffer .= "\000"; + if (isset($mime_map[$field_name])) { + $local_buffer .= str_replace( + '_', + '/', + $mime_map[$field_name]['mimetype'] + ); + } + } + $local_buffer = self::texEscape($local_buffer); + if ($row['Key']=='PRI') { + $pos=strpos($local_buffer, "\000"); + $local_buffer = '\\textit{' + . substr($local_buffer, 0, $pos) + . '}' . substr($local_buffer, $pos); + } + if (in_array($field_name, $unique_keys)) { + $pos=strpos($local_buffer, "\000"); + $local_buffer = '\\textbf{' + . substr($local_buffer, 0, $pos) + . '}' . substr($local_buffer, $pos); + } + $buffer = str_replace("\000", ' & ', $local_buffer); + $buffer .= ' \\\\ \\hline ' . $crlf; + + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + } // end while + + $buffer = ' \\end{longtable}' . $crlf; + return PMA_exportOutputHandler($buffer); + } // end of the 'exportStructure' method + + /** + * Escapes some special characters for use in TeX/LaTeX + * + * @param string $string the string to convert + * + * @return string the converted string with escape codes + */ + public static function texEscape($string) + { + $escape = array('$', '%', '{', '}', '&', '#', '_', '^'); + $cnt_escape = count($escape); + for ($k = 0; $k < $cnt_escape; $k++) { + $string = str_replace($escape[$k], '\\' . $escape[$k], $string); + } + return $string; + } +} +?> diff --git a/phpmyadmin/libraries/plugins/export/ExportMediawiki.class.php b/phpmyadmin/libraries/plugins/export/ExportMediawiki.class.php new file mode 100644 index 000000000..89afe7100 --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/ExportMediawiki.class.php @@ -0,0 +1,364 @@ +setProperties(); + } + + /** + * Sets the export MediaWiki properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/groups/OptionsPropertySubgroup.class.php"; + include_once "$props/options/items/MessageOnlyPropertyItem.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('MediaWiki Table'); + $exportPluginProperties->setExtension('mediawiki'); + $exportPluginProperties->setMimeType('text/plain'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + $generalOptions->setText(__('Dump table')); + + // what to dump (structure/data/both) + $subgroup = new OptionsPropertySubgroup(); + $subgroup->setName("dump_table"); + $subgroup->setText("Dump table"); + $leaf = new RadioPropertyItem(); + $leaf->setName('structure_or_data'); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $subgroup->setSubgroupHeader($leaf); + $generalOptions->addProperty($subgroup); + + // export table name + $leaf = new BoolPropertyItem(); + $leaf->setName("caption"); + $leaf->setText(__('Export table names')); + $generalOptions->addProperty($leaf); + + // export table headers + $leaf = new BoolPropertyItem(); + $leaf->setName("headers"); + $leaf->setText(__('Export table headers')); + $generalOptions->addProperty($leaf); + //add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs table's structure + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $export_mode 'create_table','triggers','create_view', + * 'stand_in' + * @param string $export_type 'server', 'database', 'table' + * @param bool $do_relation whether to include relation comments + * @param bool $do_comments whether to include the pmadb-style column + * comments as comments in the structure; this is + * deprecated but the parameter is left here + * because export.php calls exportStructure() + * also for other export types which use this + * parameter + * @param bool $do_mime whether to include mime comments + * @param bool $dates whether to include creation/update/check dates + * + * @return bool Whether it succeeded + */ + public function exportStructure( + $db, + $table, + $crlf, + $error_url, + $export_mode, + $export_type, + $do_relation = false, + $do_comments = false, + $do_mime = false, + $dates = false + ) { + switch($export_mode) { + case 'create_table': + $columns = PMA_DBI_get_columns($db, $table); + $columns = array_values($columns); + $row_cnt = count($columns); + + // Print structure comment + $output = $this->_exportComment( + "Table structure for " + . PMA_Util::backquote($table) + ); + + // Begin the table construction + $output .= "{| class=\"wikitable\" style=\"text-align:center;\"" + . $this->_exportCRLF(); + + // Add the table name + if ($GLOBALS['mediawiki_caption']) { + $output .= "|+'''" . $table . "'''" . $this->_exportCRLF(); + } + + // Add the table headers + if ($GLOBALS['mediawiki_headers']) { + $output .= "|- style=\"background:#ffdead;\"" . $this->_exportCRLF(); + $output .= "! style=\"background:#ffffff\" | " + . $this->_exportCRLF(); + for ($i = 0; $i < $row_cnt; ++$i) { + $output .= " | " . $columns[$i]['Field']. $this->_exportCRLF(); + } + } + + // Add the table structure + $output .= "|-" . $this->_exportCRLF(); + $output .= "! Type" . $this->_exportCRLF(); + for ($i = 0; $i < $row_cnt; ++$i) { + $output .= " | " . $columns[$i]['Type'] . $this->_exportCRLF(); + } + + $output .= "|-" . $this->_exportCRLF(); + $output .= "! Null" . $this->_exportCRLF(); + for ($i = 0; $i < $row_cnt; ++$i) { + $output .= " | " . $columns[$i]['Null'] . $this->_exportCRLF(); + } + + $output .= "|-" . $this->_exportCRLF(); + $output .= "! Default" . $this->_exportCRLF(); + for ($i = 0; $i < $row_cnt; ++$i) { + $output .= " | " . $columns[$i]['Default'] . $this->_exportCRLF(); + } + + $output .= "|-" . $this->_exportCRLF(); + $output .= "! Extra" . $this->_exportCRLF(); + for ($i = 0; $i < $row_cnt; ++$i) { + $output .= " | " . $columns[$i]['Extra'] . $this->_exportCRLF(); + } + + $output .= "|}" . str_repeat($this->_exportCRLF(), 2); + break; + } // end switch + + return PMA_exportOutputHandler($output); + } + + /** + * Outputs the content of a table in MediaWiki format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData( + $db, + $table, + $crlf, + $error_url, + $sql_query + ) { + // Print data comment + $output = $this->_exportComment( + "Table data for ". PMA_Util::backquote($table) + ); + + // Begin the table construction + // Use the "wikitable" class for style + // Use the "sortable" class for allowing tables to be sorted by column + $output .= "{| class=\"wikitable sortable\" style=\"text-align:center;\"" + . $this->_exportCRLF(); + + // Add the table name + if ($GLOBALS['mediawiki_caption']) { + $output .= "|+'''" . $table . "'''" . $this->_exportCRLF(); + } + + // Add the table headers + if ($GLOBALS['mediawiki_headers']) { + // Get column names + $column_names = PMA_DBI_get_column_names($db, $table); + + // Add column names as table headers + if ( ! is_null($column_names) ) { + // Use '|-' for separating rows + $output .= "|-" . $this->_exportCRLF(); + + // Use '!' for separating table headers + foreach ($column_names as $column) { + $output .= " ! " . $column . "" . $this->_exportCRLF(); + } + } + } + + // Get the table data from the database + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $fields_cnt = PMA_DBI_num_fields($result); + + while ($row = PMA_DBI_fetch_row($result)) { + $output .= "|-" . $this->_exportCRLF(); + + // Use '|' for separating table columns + for ($i = 0; $i < $fields_cnt; ++ $i) { + $output .= " | " . $row[$i] . "" . $this->_exportCRLF(); + } + } + + // End table construction + $output .= "|}" . str_repeat($this->_exportCRLF(), 2); + return PMA_exportOutputHandler($output); + } + + /** + * Outputs comments containing info about the exported tables + * + * @param string $text Text of comment + * + * @return string The formatted comment + */ + private function _exportComment($text = '') + { + // see http://www.mediawiki.org/wiki/Help:Formatting + $comment = $this->_exportCRLF(); + $comment .= '' . 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 000000000..b1e9f91e7 --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/ExportOds.class.php @@ -0,0 +1,334 @@ +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 = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $fields_cnt = PMA_DBI_num_fields($result); + $fields_meta = PMA_DBI_get_fields_meta($result); + $field_flags = array(); + for ($j = 0; $j < $fields_cnt; $j++) { + $field_flags[$j] = PMA_DBI_field_flags($result, $j); + } + + $GLOBALS['ods_buffer'] .= + ''; + + // 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(PMA_DBI_field_name($result, $i)) + ) + . '' + . ''; + } // end for + $GLOBALS['ods_buffer'] .= ''; + } // end if + + // Format the data + while ($row = PMA_DBI_fetch_row($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 + PMA_DBI_free_result($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 000000000..bb608f0e6 --- /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 = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $fields_cnt = PMA_DBI_num_fields($result); + $fields_meta = PMA_DBI_get_fields_meta($result); + $field_flags = array(); + for ($j = 0; $j < $fields_cnt; $j++) { + $field_flags[$j] = PMA_DBI_field_flags($result, $j); + } + + $GLOBALS['odt_buffer'] .= + '' + . __('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(PMA_DBI_field_name($result, $i)) + ) + . '' + . ''; + } // end for + $GLOBALS['odt_buffer'] .= ''; + } // end if + + // Format the data + while ($row = PMA_DBI_fetch_row($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 + PMA_DBI_free_result($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 + */ + PMA_DBI_select_db($db); + + /** + * Displays the table structure + */ + $GLOBALS['odt_buffer'] .= + ''; + $columns_cnt = 4; + $GLOBALS['odt_buffer'] .= + ''; + /* Header */ + $GLOBALS['odt_buffer'] .= '' + . '' + . '' . __('Column') . '' + . '' + . '' + . '' . __('Type') . '' + . '' + . '' + . '' . __('Null') . '' + . '' + . '' + . '' . __('Default') . '' + . '' + . ''; + + $columns = PMA_DBI_get_columns($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 + */ + PMA_DBI_select_db($db); + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + /** + * Displays the table structure + */ + $GLOBALS['odt_buffer'] .= ''; + $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 = PMA_DBI_get_columns($db, $table); + foreach ($columns as $column) { + $field_name = $column['Field']; + $GLOBALS['odt_buffer'] .= $this->formatOneColumnDefinition($column); + + if ($do_relation && $have_rel) { + if (isset($res_rel[$field_name])) { + $GLOBALS['odt_buffer'] .= + '' + . '' + . 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 = PMA_DBI_get_triggers($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 = PMA_DBI_get_triggers($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'] = ''; + } + } else { + $column['Default'] = $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 000000000..ffabb96ef --- /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 000000000..2d3b73c54 --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/ExportPhparray.class.php @@ -0,0 +1,227 @@ +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( + ' " . var_export($record[$i], true) + . (($i + 1 >= $columns_cnt) ? '' : ','); + } + + $buffer .= ')'; + } + + $buffer .= $crlf . ');' . $crlf; + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + PMA_DBI_free_result($result); + return true; + } +} +?> diff --git a/phpmyadmin/libraries/plugins/export/ExportSql.class.php b/phpmyadmin/libraries/plugins/export/ExportSql.class.php new file mode 100644 index 000000000..448101372 --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/ExportSql.class.php @@ -0,0 +1,1876 @@ +setProperties(); + + // Avoids undefined variables, use NULL so isset() returns false + if (! isset($GLOBALS['sql_backquotes'])) { + $GLOBALS['sql_backquotes'] = null; + } + } + + /** + * Sets the export SQL properties + * + * @return void + */ + protected function setProperties() + { + global $plugin_param; + + $hide_sql = false; + $hide_structure = false; + if ($plugin_param['export_type'] == 'table' + && ! $plugin_param['single_table'] + ) { + $hide_structure = true; + $hide_sql = true; + } + + if (! $hide_sql) { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/groups/OptionsPropertySubgroup.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/MessageOnlyPropertyItem.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/SelectPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('SQL'); + $exportPluginProperties->setExtension('sql'); + $exportPluginProperties->setMimeType('text/x-sql'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + + // comments + $subgroup = new OptionsPropertySubgroup(); + $subgroup->setName("include_comments"); + $leaf = new BoolPropertyItem(); + $leaf->setName('include_comments'); + $leaf->setText( + __( + 'Display comments (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); + + // compatibility maximization + $compats = PMA_DBI_getCompatibilities(); + if (count($compats) > 0) { + $values = array(); + foreach ($compats as $val) { + $values[$val] = $val; + } + + $leaf = new SelectPropertyItem(); + $leaf->setName("compatibility"); + $leaf->setText( + __( + 'Database system or older MySQL server to maximize output' + . ' compatibility with:' + ) + ); + $leaf->setValues($values); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'Server_SQL_mode' + ) + ); + $generalOptions->addProperty($leaf); + + unset($values); + } + + // server export options + if ($plugin_param['export_type'] == 'server') { + $leaf = new BoolPropertyItem(); + $leaf->setName("drop_database"); + $leaf->setText( + sprintf(__('Add %s statement'), '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') { + 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 TextPropertyItem(); + $leaf->setName("max_query_size"); + $leaf->setText(__('Maximal length of created query')); + $dataOptions->addProperty($leaf); + + // Dump binary columns in hexadecimal + $leaf = new BoolPropertyItem(); + $leaf->setName("hex_for_blob"); + $leaf->setText( + __( + 'Dump binary columns in hexadecimal notation' + . ' (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 = PMA_DBI_get_procedures_or_functions($db, 'PROCEDURE'); + $function_names = PMA_DBI_get_procedures_or_functions($db, 'FUNCTION'); + + if ($procedure_names || $function_names) { + $text .= $crlf + . 'DELIMITER ' . $delimiter . $crlf; + } + + if ($procedure_names) { + $text .= + $this->_exportComment() + . $this->_exportComment(__('Procedures')) + . $this->_exportComment(); + + foreach ($procedure_names as $procedure_name) { + if (! empty($GLOBALS['sql_drop_table'])) { + $text .= 'DROP PROCEDURE IF EXISTS ' + . PMA_Util::backquote($procedure_name) + . $delimiter . $crlf; + } + $text .= PMA_DBI_get_definition($db, 'PROCEDURE', $procedure_name) + . $delimiter . $crlf . $crlf; + } + } + + if ($function_names) { + $text .= + $this->_exportComment() + . $this->_exportComment(__('Functions')) + . $this->_exportComment(); + + foreach ($function_names as $function_name) { + if (! empty($GLOBALS['sql_drop_table'])) { + $text .= 'DROP FUNCTION IF EXISTS ' + . PMA_Util::backquote($function_name) + . $delimiter . $crlf; + } + $text .= PMA_DBI_get_definition($db, 'FUNCTION', $function_name) + . $delimiter . $crlf . $crlf; + } + } + + if ($procedure_names || $function_names) { + $text .= 'DELIMITER ;' . $crlf; + } + + if (! empty($text)) { + return PMA_exportOutputHandler($text); + } else { + return false; + } + } + + /** + * Possibly outputs comment + * + * @param string $text Text of comment + * + * @return string The formatted comment + */ + private function _exportComment($text = '') + { + if (isset($GLOBALS['sql_include_comments']) + && $GLOBALS['sql_include_comments'] + ) { + // see http://dev.mysql.com/doc/refman/5.0/en/ansi-diff-comments.html + return '--' . (empty($text) ? '' : ' ') . $text . $GLOBALS['crlf']; + } else { + return ''; + } + } + + /** + * Possibly outputs CRLF + * + * @return string $crlf or nothing + */ + private function _possibleCRLF() + { + if (isset($GLOBALS['sql_include_comments']) + && $GLOBALS['sql_include_comments'] + ) { + return $GLOBALS['crlf']; + } else { + return ''; + } + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter() + { + global $crlf, $mysql_charset_map; + + $foot = ''; + + if (isset($GLOBALS['sql_disable_fk'])) { + $foot .= 'SET FOREIGN_KEY_CHECKS=1;' . $crlf; + } + + if (isset($GLOBALS['sql_use_transaction'])) { + $foot .= 'COMMIT;' . $crlf; + } + + // restore connection settings + $charset_of_file = isset($GLOBALS['charset_of_file']) + ? $GLOBALS['charset_of_file'] : ''; + if (! empty($GLOBALS['asfile']) + && isset($mysql_charset_map[$charset_of_file]) + && ! PMA_DRIZZLE + ) { + $foot .= $crlf + . '/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;' + . $crlf + . '/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;' + . $crlf + . '/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;' + . $crlf; + } + + /* Restore timezone */ + if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) { + PMA_DBI_query('SET time_zone = "' . $GLOBALS['old_tz'] . '"'); + } + + return PMA_exportOutputHandler($foot); + } + + /** + * Outputs export header. It is the first method to be called, so all + * the required variables are initialized here. + * + * @return bool Whether it succeeded + */ + public function exportHeader() + { + global $crlf, $cfg; + global $mysql_charset_map; + + if (isset($GLOBALS['sql_compatibility'])) { + $tmp_compat = $GLOBALS['sql_compatibility']; + if ($tmp_compat == 'NONE') { + $tmp_compat = ''; + } + PMA_DBI_try_query('SET SQL_MODE="' . $tmp_compat . '"'); + unset($tmp_compat); + } + $head = $this->_exportComment('phpMyAdmin SQL Dump') + . $this->_exportComment('version ' . PMA_VERSION) + . $this->_exportComment('http://www.phpmyadmin.net') + . $this->_exportComment(); + $host_string = __('Host') . ': ' . $cfg['Server']['host']; + if (! empty($cfg['Server']['port'])) { + $host_string .= ':' . $cfg['Server']['port']; + } + $head .= $this->_exportComment($host_string); + $head .= + $this->_exportComment( + __('Generation Time') . ': ' + . PMA_Util::localisedDate() + ) + . $this->_exportComment( + __('Server version') . ': ' . PMA_MYSQL_STR_VERSION + ) + . $this->_exportComment(__('PHP Version') . ': ' . phpversion()) + . $this->_possibleCRLF(); + + if (isset($GLOBALS['sql_header_comment']) + && ! empty($GLOBALS['sql_header_comment']) + ) { + // '\n' is not a newline (like "\n" would be), it's the characters + // backslash and n, as explained on the export interface + $lines = explode('\n', $GLOBALS['sql_header_comment']); + $head .= $this->_exportComment(); + foreach ($lines as $one_line) { + $head .= $this->_exportComment($one_line); + } + $head .= $this->_exportComment(); + } + + if (isset($GLOBALS['sql_disable_fk'])) { + $head .= 'SET FOREIGN_KEY_CHECKS=0;' . $crlf; + } + + // We want exported AUTO_INCREMENT columns to have still same value, + // do this only for recent MySQL exports + if ((! isset($GLOBALS['sql_compatibility']) + || $GLOBALS['sql_compatibility'] == 'NONE') + && ! PMA_DRIZZLE + ) { + $head .= 'SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";' . $crlf; + } + + if (isset($GLOBALS['sql_use_transaction'])) { + $head .= 'SET AUTOCOMMIT = 0;' . $crlf + . 'START TRANSACTION;' . $crlf; + } + + /* Change timezone if we should export timestamps in UTC */ + if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) { + $head .= 'SET time_zone = "+00:00";' . $crlf; + $GLOBALS['old_tz'] = PMA_DBI_fetch_value('SELECT @@session.time_zone'); + PMA_DBI_query('SET time_zone = "+00:00"'); + } + + $head .= $this->_possibleCRLF(); + + if (! empty($GLOBALS['asfile']) && ! PMA_DRIZZLE) { + // we are saving as file, therefore we provide charset information + // so that a utility like the mysql client can interpret + // the file correctly + if (isset($GLOBALS['charset_of_file']) + && isset($mysql_charset_map[$GLOBALS['charset_of_file']]) + ) { + // we got a charset from the export dialog + $set_names = $mysql_charset_map[$GLOBALS['charset_of_file']]; + } else { + // by default we use the connection charset + $set_names = $mysql_charset_map['utf-8']; + } + $head .= $crlf + . '/*!40101 SET @OLD_CHARACTER_SET_CLIENT=' + . '@@CHARACTER_SET_CLIENT */;' . $crlf + . '/*!40101 SET @OLD_CHARACTER_SET_RESULTS=' + . '@@CHARACTER_SET_RESULTS */;' . $crlf + . '/*!40101 SET @OLD_COLLATION_CONNECTION=' + . '@@COLLATION_CONNECTION */;'. $crlf + . '/*!40101 SET NAMES ' . $set_names . ' */;' . $crlf . $crlf; + } + + return PMA_exportOutputHandler($head); + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + global $crlf; + + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + if (isset($GLOBALS['sql_drop_database'])) { + if (! PMA_exportOutputHandler( + 'DROP DATABASE ' + . (isset($GLOBALS['sql_backquotes']) + ? PMA_Util::backquoteCompat($db, $compat) : $db) + . ';' . $crlf + )) { + return false; + } + } + $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; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader($db) + { + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + $head = $this->_exportComment() + . $this->_exportComment( + __('Database') . ': ' + . (isset($GLOBALS['sql_backquotes']) + ? PMA_Util::backquoteCompat($db, $compat) + : '\'' . $db . '\'') + ) + . $this->_exportComment(); + return PMA_exportOutputHandler($head); + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter($db) + { + global $crlf; + + $result = true; + if (isset($GLOBALS['sql_constraints'])) { + $result = PMA_exportOutputHandler($GLOBALS['sql_constraints']); + unset($GLOBALS['sql_constraints']); + } + + if (($GLOBALS['sql_structure_or_data'] == 'structure' + || $GLOBALS['sql_structure_or_data'] == 'structure_and_data') + && isset($GLOBALS['sql_procedure_function']) + ) { + $text = ''; + $delimiter = '$$'; + + if (PMA_MYSQL_INT_VERSION > 50100) { + $event_names = PMA_DBI_fetch_result( + 'SELECT EVENT_NAME FROM information_schema.EVENTS WHERE' + . ' EVENT_SCHEMA= \'' + . PMA_Util::sqlAddSlashes($db, true) + . '\';' + ); + } else { + $event_names = array(); + } + + if ($event_names) { + $text .= $crlf + . 'DELIMITER ' . $delimiter . $crlf; + + $text .= + $this->_exportComment() + . $this->_exportComment(__('Events')) + . $this->_exportComment(); + + foreach ($event_names as $event_name) { + if (! empty($GLOBALS['sql_drop_table'])) { + $text .= 'DROP EVENT ' + . PMA_Util::backquote($event_name) + . $delimiter . $crlf; + } + $text .= PMA_DBI_get_definition($db, 'EVENT', $event_name) + . $delimiter . $crlf . $crlf; + } + + $text .= 'DELIMITER ;' . $crlf; + } + + if (! empty($text)) { + $result = PMA_exportOutputHandler($text); + } + } + return $result; + } + + /** + * Returns a stand-in CREATE definition to resolve view dependencies + * + * @param string $db the database name + * @param string $view the view name + * @param string $crlf the end of line sequence + * + * @return string resulting definition + */ + public function getTableDefStandIn($db, $view, $crlf) + { + $create_query = ''; + if (! empty($GLOBALS['sql_drop_table'])) { + $create_query .= 'DROP VIEW IF EXISTS ' + . PMA_Util::backquote($view) + . ';' . $crlf; + } + + $create_query .= 'CREATE TABLE '; + + if (isset($GLOBALS['sql_if_not_exists']) + && $GLOBALS['sql_if_not_exists'] + ) { + $create_query .= 'IF NOT EXISTS '; + } + $create_query .= PMA_Util::backquote($view) . ' (' . $crlf; + $tmp = array(); + $columns = PMA_DBI_get_columns_full($db, $view); + foreach ($columns as $column_name => $definition) { + $tmp[] = PMA_Util::backquote($column_name) . ' ' . + $definition['Type'] . $crlf; + } + $create_query .= implode(',', $tmp) . ');'; + return($create_query); + } + + /** + * Returns $table's CREATE definition + * + * @param string $db the database name + * @param string $table the table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param bool $show_dates whether to include creation/update/check + * dates + * @param bool $add_semicolon whether to add semicolon and end-of-line at + * the end + * @param bool $view whether we're handling a view + * + * @return string resulting schema + */ + public function getTableDef( + $db, + $table, + $crlf, + $error_url, + $show_dates = false, + $add_semicolon = true, + $view = false + ) { + global $sql_drop_table, $sql_backquotes, $sql_constraints, + $sql_constraints_query, $sql_drop_foreign_keys; + + $schema_create = ''; + $auto_increment = ''; + $new_crlf = $crlf; + + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + + // need to use PMA_DBI_QUERY_STORE with PMA_DBI_num_rows() in mysqli + $result = PMA_DBI_query( + 'SHOW TABLE STATUS FROM ' . PMA_Util::backquote($db) + . ' LIKE \'' . PMA_Util::sqlAddSlashes($table, true) . '\'', + null, + PMA_DBI_QUERY_STORE + ); + if ($result != false) { + if (PMA_DBI_num_rows($result) > 0) { + $tmpres = PMA_DBI_fetch_assoc($result); + if (PMA_DRIZZLE && $show_dates) { + // Drizzle doesn't give Create_time and Update_time in + // SHOW TABLE STATUS, add it + $sql ="SELECT + TABLE_CREATION_TIME AS Create_time, + TABLE_UPDATE_TIME AS Update_time + FROM data_dictionary.TABLES + WHERE TABLE_SCHEMA = '" + . PMA_Util::sqlAddSlashes($db) . "' + AND TABLE_NAME = '" + . PMA_Util::sqlAddSlashes($table) . "'"; + $tmpres = array_merge(PMA_DBI_fetch_single_row($sql), $tmpres); + } + // Here we optionally add the AUTO_INCREMENT next value, + // but starting with MySQL 5.0.24, the clause is already included + // in SHOW CREATE TABLE so we'll remove it below + // It's required for Drizzle because SHOW CREATE TABLE uses + // the value from table's creation time + if (isset($GLOBALS['sql_auto_increment']) + && ! empty($tmpres['Auto_increment']) + ) { + $auto_increment .= ' AUTO_INCREMENT=' + . $tmpres['Auto_increment'] . ' '; + } + + if ($show_dates + && isset($tmpres['Create_time']) + && ! empty($tmpres['Create_time']) + ) { + $schema_create .= $this->_exportComment( + __('Creation') . ': ' + . PMA_Util::localisedDate( + strtotime($tmpres['Create_time']) + ) + ); + $new_crlf = $this->_exportComment() . $crlf; + } + + if ($show_dates + && isset($tmpres['Update_time']) + && ! empty($tmpres['Update_time']) + ) { + $schema_create .= $this->_exportComment( + __('Last update') . ': ' + . PMA_Util::localisedDate( + strtotime($tmpres['Update_time']) + ) + ); + $new_crlf = $this->_exportComment() . $crlf; + } + + if ($show_dates + && isset($tmpres['Check_time']) + && ! empty($tmpres['Check_time']) + ) { + $schema_create .= $this->_exportComment( + __('Last check') . ': ' + . PMA_Util::localisedDate( + strtotime($tmpres['Check_time']) + ) + ); + $new_crlf = $this->_exportComment() . $crlf; + } + } + PMA_DBI_free_result($result); + } + + $schema_create .= $new_crlf; + + // no need to generate a DROP VIEW here, it was done earlier + if (! empty($sql_drop_table) && ! PMA_Table::isView($db, $table)) { + $schema_create .= 'DROP TABLE IF EXISTS ' + . PMA_Util::backquote($table, $sql_backquotes) . ';' + . $crlf; + } + + // Complete table dump, + // Whether to quote table and column names or not + // Drizzle always quotes names + if (! PMA_DRIZZLE) { + if ($sql_backquotes) { + PMA_DBI_query('SET SQL_QUOTE_SHOW_CREATE = 1'); + } else { + PMA_DBI_query('SET SQL_QUOTE_SHOW_CREATE = 0'); + } + } + + // I don't see the reason why this unbuffered query could cause problems, + // because SHOW CREATE TABLE returns only one row, and we free the + // results below. Nonetheless, we got 2 user reports about this + // (see bug 1562533) so I removed the unbuffered mode. + // $result = PMA_DBI_query('SHOW CREATE TABLE ' . backquote($db) + // . '.' . backquote($table), null, PMA_DBI_QUERY_UNBUFFERED); + // + // Note: SHOW CREATE TABLE, at least in MySQL 5.1.23, does not + // produce a displayable result for the default value of a BIT + // column, nor does the mysqldump command. See MySQL bug 35796 + $result = PMA_DBI_try_query( + 'SHOW CREATE TABLE ' . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table) + ); + // an error can happen, for example the table is crashed + $tmp_error = PMA_DBI_getError(); + if ($tmp_error) { + return $this->_exportComment(__('in use') . '(' . $tmp_error . ')'); + } + + if ($result != false && ($row = PMA_DBI_fetch_row($result))) { + $create_query = $row[1]; + unset($row); + + // Convert end of line chars to one that we want (note that MySQL + // doesn't return query it will accept in all cases) + if (strpos($create_query, "(\r\n ")) { + $create_query = str_replace("\r\n", $crlf, $create_query); + } elseif (strpos($create_query, "(\n ")) { + $create_query = str_replace("\n", $crlf, $create_query); + } elseif (strpos($create_query, "(\r ")) { + $create_query = str_replace("\r", $crlf, $create_query); + } + + /* + * Drop database name from VIEW creation. + * + * This is a bit tricky, but we need to issue SHOW CREATE TABLE with + * database name, but we don't want name to show up in CREATE VIEW + * statement. + */ + if ($view) { + $create_query = preg_replace( + '/' . PMA_Util::backquote($db) . '\./', + '', + $create_query + ); + } + + // Should we use IF NOT EXISTS? + // It always must be OFF for MSSQL compatibility mode + if (isset($GLOBALS['sql_if_not_exists']) && $compat != 'MSSQL') { + $create_query = preg_replace( + '/^CREATE TABLE/', + 'CREATE TABLE IF NOT EXISTS', + $create_query + ); + } + + // In MSSQL + // 1. DATE field doesn't exists, we will use DATETIME instead + // 2. UNSIGNED attribute doesn't exist + // 3. No length on INT, TINYINT, SMALLINT, BIGINT and no precision on + // FLOAT fields + // 4. No KEY and INDEX inside CREATE TABLE + // 5. DOUBLE field doesn't exists, we will use FLOAT instead + if ($compat == 'MSSQL') { + // first we need to replace all lines ended with '" DATE ...,\n' + // last preg_replace preserve us from situation with date text + // inside DEFAULT field value + $create_query = preg_replace( + "/\" date DEFAULT NULL(,)?\n/", + '" datetime DEFAULT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + "/\" date NOT NULL(,)?\n/", + '" datetime NOT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" date NOT NULL DEFAULT \'([^\'])/', + '" datetime NOT NULL DEFAULT \'$1', + $create_query + ); + + // next we need to replace all lines ended with ') UNSIGNED ...,' + // last preg_replace preserve us from situation with unsigned text + // inside DEFAULT field value + $create_query = preg_replace( + "/\) unsigned NOT NULL(,)?\n/", + ') NOT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + "/\) unsigned DEFAULT NULL(,)?\n/", + ') DEFAULT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + '/\) unsigned NOT NULL DEFAULT \'([^\'])/', + ') NOT NULL DEFAULT \'$1', + $create_query + ); + + // we need to replace all lines ended with + // '" INT|TINYINT([0-9]{1,}) ...,' last preg_replace preserve us + // from situation with int([0-9]{1,}) text inside DEFAULT field + // value + $create_query = preg_replace( + '/" (int|tinyint|smallint|bigint)\([0-9]+\) DEFAULT NULL(,)?\n/', + '" $1 DEFAULT NULL$2' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL(,)?\n/', + '" $1 NOT NULL$2' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL DEFAULT \'([^\'])/', + '" $1 NOT NULL DEFAULT \'$2', + $create_query + ); + + // we need to replace all lines ended with + // '" FLOAT|DOUBLE([0-9,]{1,}) ...,' + // last preg_replace preserve us from situation with + // float([0-9,]{1,}) text inside DEFAULT field value + $create_query = preg_replace( + '/" (float|double)(\([0-9]+,[0-9,]+\))? DEFAULT NULL(,)?\n/', + '" float DEFAULT NULL$3' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL(,)?\n/', + '" float NOT NULL$3' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL DEFAULT \'([^\'])/', + '" float NOT NULL DEFAULT \'$3', + $create_query + ); + + // @todo remove indexes from CREATE TABLE + } + + // Drizzle (checked on 2011.03.13) returns ROW_FORMAT surrounded + // with quotes, which is not accepted by parser + if (PMA_DRIZZLE) { + $create_query = preg_replace( + '/ROW_FORMAT=\'(\S+)\'/', + 'ROW_FORMAT=$1', + $create_query + ); + } + + // are there any constraints to cut out? + if (preg_match('@CONSTRAINT|FOREIGN[\s]+KEY@', $create_query)) { + + // Split the query into lines, so we can easily handle it. + // We know lines are separated by $crlf (done few lines above). + $sql_lines = explode($crlf, $create_query); + $sql_count = count($sql_lines); + + // lets find first line with constraints + for ($i = 0; $i < $sql_count; $i++) { + if (preg_match( + '@^[\s]*(CONSTRAINT|FOREIGN[\s]+KEY)@', + $sql_lines[$i] + )) { + break; + } + } + + // If we really found a constraint + if ($i != $sql_count) { + + // remove, from the end of create statement + $sql_lines[$i - 1] = preg_replace( + '@,$@', + '', + $sql_lines[$i - 1] + ); + + // prepare variable for constraints + if (! isset($sql_constraints)) { + if (isset($GLOBALS['no_constraints_comments'])) { + $sql_constraints = ''; + } else { + $sql_constraints = $crlf + . $this->_exportComment() + . $this->_exportComment( + __('Constraints for dumped tables') + ) + . $this->_exportComment(); + } + } + + // comments for current table + if (! isset($GLOBALS['no_constraints_comments'])) { + $sql_constraints .= $crlf + . $this->_exportComment() + . $this->_exportComment( + __('Constraints for table') + . ' ' + . PMA_Util::backquoteCompat($table, $compat) + ) + . $this->_exportComment(); + } + + // let's do the work + $sql_constraints_query .= 'ALTER TABLE ' + . PMA_Util::backquoteCompat($table, $compat) + . $crlf; + $sql_constraints .= 'ALTER TABLE ' + . PMA_Util::backquoteCompat($table, $compat) + . $crlf; + $sql_drop_foreign_keys .= 'ALTER TABLE ' + . PMA_Util::backquoteCompat($db, $compat) . '.' + . PMA_Util::backquoteCompat($table, $compat) + . $crlf; + + $first = true; + for ($j = $i; $j < $sql_count; $j++) { + if (preg_match( + '@CONSTRAINT|FOREIGN[\s]+KEY@', + $sql_lines[$j] + )) { + if (! $first) { + $sql_constraints .= $crlf; + } + if (strpos($sql_lines[$j], 'CONSTRAINT') === false) { + $tmp_str = preg_replace( + '/(FOREIGN[\s]+KEY)/', + 'ADD \1', + $sql_lines[$j] + ); + $sql_constraints_query .= $tmp_str; + $sql_constraints .= $tmp_str; + } else { + $tmp_str = preg_replace( + '/(CONSTRAINT)/', + 'ADD \1', + $sql_lines[$j] + ); + $sql_constraints_query .= $tmp_str; + $sql_constraints .= $tmp_str; + preg_match( + '/(CONSTRAINT)([\s])([\S]*)([\s])/', + $sql_lines[$j], + $matches + ); + if (! $first) { + $sql_drop_foreign_keys .= ', '; + } + $sql_drop_foreign_keys .= 'DROP FOREIGN KEY ' + . $matches[3]; + } + $first = false; + } else { + break; + } + } + $sql_constraints .= ';' . $crlf; + $sql_constraints_query .= ';'; + + $create_query = implode( + $crlf, + array_slice($sql_lines, 0, $i) + ) + . $crlf + . implode( + $crlf, + array_slice($sql_lines, $j, $sql_count - 1) + ); + unset($sql_lines); + } + } + $schema_create .= $create_query; + } + + // remove a possible "AUTO_INCREMENT = value" clause + // that could be there starting with MySQL 5.0.24 + // in Drizzle it's useless as it contains the value given at table + // creation time + $schema_create = preg_replace( + '/AUTO_INCREMENT\s*=\s*([0-9])+/', + '', + $schema_create + ); + + $schema_create .= ($compat != 'MSSQL') ? $auto_increment : ''; + + PMA_DBI_free_result($result); + return $schema_create . ($add_semicolon ? ';' . $crlf : ''); + } // end of the 'getTableDef()' function + + /** + * Returns $table's comments, relations etc. + * + * @param string $db database name + * @param string $table table name + * @param string $crlf end of line sequence + * @param bool $do_relation whether to include relation comments + * @param bool $do_mime whether to include mime comments + * + * @return string resulting comments + */ + private function _getTableComments( + $db, + $table, + $crlf, + $do_relation = false, + $do_mime = false + ) { + global $cfgRelation, $sql_backquotes; + + $schema_create = ''; + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + if ($do_mime && $cfgRelation['mimework']) { + if (! ($mime_map = PMA_getMIME($db, $table, true))) { + unset($mime_map); + } + } + + if (isset($mime_map) && count($mime_map) > 0) { + $schema_create .= $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('MIME TYPES FOR TABLE'). ' ' + . PMA_Util::backquote($table, $sql_backquotes) . ':' + ); + @reset($mime_map); + foreach ($mime_map AS $mime_field => $mime) { + $schema_create .= + $this->_exportComment( + ' ' + . PMA_Util::backquote($mime_field, $sql_backquotes) + ) + . $this->_exportComment( + ' ' + . PMA_Util::backquote( + $mime['mimetype'], + $sql_backquotes + ) + ); + } + $schema_create .= $this->_exportComment(); + } + + if ($have_rel) { + $schema_create .= $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('RELATIONS FOR TABLE') . ' ' + . PMA_Util::backquote($table, $sql_backquotes) + . ':' + ); + foreach ($res_rel AS $rel_field => $rel) { + $schema_create .= + $this->_exportComment( + ' ' + . PMA_Util::backquote($rel_field, $sql_backquotes) + ) + . $this->_exportComment( + ' ' + . PMA_Util::backquote( + $rel['foreign_table'], + $sql_backquotes + ) + . ' -> ' + . PMA_Util::backquote( + $rel['foreign_field'], + $sql_backquotes + ) + ); + } + $schema_create .= $this->_exportComment(); + } + + return $schema_create; + + } // end of the '_getTableComments()' function + + /** + * Outputs table's structure + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $export_mode 'create_table','triggers','create_view', + * 'stand_in' + * @param string $export_type 'server', 'database', 'table' + * @param bool $relation whether to include relation comments + * @param bool $comments whether to include the pmadb-style column + * comments as comments in the structure; this is + * deprecated but the parameter is left here + * because export.php calls exportStructure() + * also for other export types which use this + * parameter + * @param bool $mime whether to include mime comments + * @param bool $dates whether to include creation/update/check dates + * + * @return bool Whether it succeeded + */ + public function exportStructure( + $db, + $table, + $crlf, + $error_url, + $export_mode, + $export_type, + $relation = false, + $comments = false, + $mime = false, + $dates = false + ) { + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + + $formatted_table_name = (isset($GLOBALS['sql_backquotes'])) + ? PMA_Util::backquoteCompat($table, $compat) + : '\'' . $table . '\''; + $dump = $this->_possibleCRLF() + . $this->_exportComment(str_repeat('-', 56)) + . $this->_possibleCRLF() + . $this->_exportComment(); + + switch($export_mode) { + case 'create_table': + $dump .= $this->_exportComment( + __('Table structure for table') . ' '. $formatted_table_name + ); + $dump .= $this->_exportComment(); + $dump .= $this->getTableDef($db, $table, $crlf, $error_url, $dates); + $dump .= $this->_getTableComments($db, $table, $crlf, $relation, $mime); + break; + case 'triggers': + $dump = ''; + $triggers = PMA_DBI_get_triggers($db, $table); + if ($triggers) { + $dump .= $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('Triggers') . ' ' . $formatted_table_name + ) + . $this->_exportComment(); + $delimiter = '//'; + foreach ($triggers as $trigger) { + $dump .= $trigger['drop'] . ';' . $crlf; + $dump .= 'DELIMITER ' . $delimiter . $crlf; + $dump .= $trigger['create']; + $dump .= 'DELIMITER ;' . $crlf; + } + } + break; + case 'create_view': + $dump .= + $this->_exportComment( + __('Structure for view') + . ' ' + . $formatted_table_name + ) + . $this->_exportComment(); + // delete the stand-in table previously created (if any) + if ($export_type != 'table') { + $dump .= 'DROP TABLE IF EXISTS ' + . PMA_Util::backquote($table) . ';' . $crlf; + } + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $dates, true, true + ); + break; + case 'stand_in': + $dump .= + $this->_exportComment( + __('Stand-in structure for view') . ' ' . $formatted_table_name + ) + . $this->_exportComment(); + // export a stand-in definition to resolve view dependencies + $dump .= $this->getTableDefStandIn($db, $table, $crlf); + } // end switch + + // this one is built by getTableDef() to use in table copy/move + // but not in the case of export + unset($GLOBALS['sql_constraints_query']); + + return PMA_exportOutputHandler($dump); + } + + /** + * Outputs the content of a table in SQL format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $current_row, $sql_backquotes; + + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + + $formatted_table_name = (isset($GLOBALS['sql_backquotes'])) + ? PMA_Util::backquoteCompat($table, $compat) + : '\'' . $table . '\''; + + // Do not export data for a VIEW + // (For a VIEW, this is called only when exporting a single VIEW) + if (PMA_Table::isView($db, $table)) { + $head = $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment('VIEW ' . ' ' . $formatted_table_name) + . $this->_exportComment(__('Data') . ': ' . __('None')) + . $this->_exportComment() + . $this->_possibleCRLF(); + + if (! PMA_exportOutputHandler($head)) { + return false; + } + return true; + } + + // analyze the query to get the true column names, not the aliases + // (this fixes an undefined index, also if Complete inserts + // are used, we did not get the true column name in case of aliases) + $analyzed_sql = PMA_SQP_analyze(PMA_SQP_parse($sql_query)); + + $result = PMA_DBI_try_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + // a possible error: the table has crashed + $tmp_error = PMA_DBI_getError(); + if ($tmp_error) { + return PMA_exportOutputHandler( + $this->_exportComment( + __('Error reading data:') . ' (' . $tmp_error . ')' + ) + ); + } + + if ($result != false) { + $fields_cnt = PMA_DBI_num_fields($result); + + // Get field information + $fields_meta = PMA_DBI_get_fields_meta($result); + $field_flags = array(); + for ($j = 0; $j < $fields_cnt; $j++) { + $field_flags[$j] = PMA_DBI_field_flags($result, $j); + } + + for ($j = 0; $j < $fields_cnt; $j++) { + if (isset($analyzed_sql[0]['select_expr'][$j]['column'])) { + $field_set[$j] = PMA_Util::backquoteCompat( + $analyzed_sql[0]['select_expr'][$j]['column'], + $compat, + $sql_backquotes + ); + } else { + $field_set[$j] = PMA_Util::backquoteCompat( + $fields_meta[$j]->name, + $compat, + $sql_backquotes + ); + } + } + + if (isset($GLOBALS['sql_type']) + && $GLOBALS['sql_type'] == 'UPDATE' + ) { + // update + $schema_insert = 'UPDATE '; + if (isset($GLOBALS['sql_ignore'])) { + $schema_insert .= 'IGNORE '; + } + // avoid EOL blank + $schema_insert .= PMA_Util::backquoteCompat( + $table, + $compat, + $sql_backquotes + ) . ' SET'; + } else { + // insert or replace + if (isset($GLOBALS['sql_type']) + && $GLOBALS['sql_type'] == 'REPLACE' + ) { + $sql_command = 'REPLACE'; + } else { + $sql_command = 'INSERT'; + } + + // delayed inserts? + if (isset($GLOBALS['sql_delayed'])) { + $insert_delayed = ' DELAYED'; + } else { + $insert_delayed = ''; + } + + // insert ignore? + if (isset($GLOBALS['sql_type']) + && $GLOBALS['sql_type'] == 'INSERT' + && isset($GLOBALS['sql_ignore']) + ) { + $insert_delayed .= ' IGNORE'; + } + //truncate table before insert + if (isset($GLOBALS['sql_truncate']) + && $GLOBALS['sql_truncate'] + && $sql_command == 'INSERT' + ) { + $truncate = 'TRUNCATE TABLE ' + . PMA_Util::backquoteCompat( + $table, + $compat, + $sql_backquotes + ) . ";"; + $truncatehead = $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('Truncate table before insert') . ' ' + . $formatted_table_name + ) + . $this->_exportComment() + . $crlf; + PMA_exportOutputHandler($truncatehead); + PMA_exportOutputHandler($truncate); + } else { + $truncate = ''; + } + + // scheme for inserting fields + if ($GLOBALS['sql_insert_syntax'] == 'complete' + || $GLOBALS['sql_insert_syntax'] == 'both' + ) { + $fields = implode(', ', $field_set); + $schema_insert = $sql_command . $insert_delayed .' INTO ' + . PMA_Util::backquoteCompat( + $table, + $compat, + $sql_backquotes + ) + // avoid EOL blank + . ' (' . $fields . ') VALUES'; + } else { + $schema_insert = $sql_command . $insert_delayed .' INTO ' + . PMA_Util::backquoteCompat( + $table, + $compat, + $sql_backquotes + ) + . ' VALUES'; + } + } + + //\x08\\x09, not required + $search = array("\x00", "\x0a", "\x0d", "\x1a"); + $replace = array('\0', '\n', '\r', '\Z'); + $current_row = 0; + $query_size = 0; + if (($GLOBALS['sql_insert_syntax'] == 'extended' + || $GLOBALS['sql_insert_syntax'] == 'both') + && (! isset($GLOBALS['sql_type']) + || $GLOBALS['sql_type'] != 'UPDATE') + ) { + $separator = ','; + $schema_insert .= $crlf; + } else { + $separator = ';'; + } + + while ($row = PMA_DBI_fetch_row($result)) { + if ($current_row == 0) { + $head = $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('Dumping data for table') . ' ' + . $formatted_table_name + ) + . $this->_exportComment() + . $crlf; + if (! PMA_exportOutputHandler($head)) { + return false; + } + } + // We need to SET IDENTITY_INSERT ON for MSSQL + if (isset($GLOBALS['sql_compatibility']) + && $GLOBALS['sql_compatibility'] == 'MSSQL' + && $current_row == 0 + ) { + if (! PMA_exportOutputHandler( + 'SET IDENTITY_INSERT ' + . PMA_Util::backquoteCompat( + $table, + $compat + ) + . ' ON ;'.$crlf + )) { + return false; + } + } + $current_row++; + for ($j = 0; $j < $fields_cnt; $j++) { + // NULL + if (! isset($row[$j]) || is_null($row[$j])) { + $values[] = 'NULL'; + } elseif ($fields_meta[$j]->numeric + && $fields_meta[$j]->type != 'timestamp' + && ! $fields_meta[$j]->blob + ) { + // a number + // timestamp is numeric on some MySQL 4.1, BLOBs are + // sometimes numeric + $values[] = $row[$j]; + } elseif (stristr($field_flags[$j], 'BINARY') + && $fields_meta[$j]->blob + && isset($GLOBALS['sql_hex_for_blob']) + ) { + // a true BLOB + // - mysqldump only generates hex data when the --hex-blob + // option is used, for fields having the binary attribute + // no hex is generated + // - a TEXT field returns type blob but a real blob + // returns also the 'binary' flag + + // empty blobs need to be different, but '0' is also empty + // :-( + if (empty($row[$j]) && $row[$j] != '0') { + $values[] = '\'\''; + } else { + $values[] = '0x' . bin2hex($row[$j]); + } + } elseif ($fields_meta[$j]->type == 'bit') { + // detection of 'bit' works only on mysqli extension + $values[] = "b'" . PMA_Util::sqlAddSlashes( + PMA_Util::printableBitValue( + $row[$j], $fields_meta[$j]->length + ) + ) + . "'"; + } else { + // something else -> treat as a string + $values[] = '\'' + . str_replace( + $search, $replace, + PMA_Util::sqlAddSlashes($row[$j]) + ) + . '\''; + } // end if + } // end for + + // should we make update? + if (isset($GLOBALS['sql_type']) + && $GLOBALS['sql_type'] == 'UPDATE' + ) { + + $insert_line = $schema_insert; + for ($i = 0; $i < $fields_cnt; $i++) { + if (0 == $i) { + $insert_line .= ' '; + } + if ($i > 0) { + // avoid EOL blank + $insert_line .= ','; + } + $insert_line .= $field_set[$i] . ' = ' . $values[$i]; + } + + list($tmp_unique_condition, $tmp_clause_is_unique) + = PMA_Util::getUniqueCondition( + $result, + $fields_cnt, + $fields_meta, + $row + ); + $insert_line .= ' WHERE ' . $tmp_unique_condition; + unset($tmp_unique_condition, $tmp_clause_is_unique); + + } else { + + // Extended inserts case + if ($GLOBALS['sql_insert_syntax'] == 'extended' + || $GLOBALS['sql_insert_syntax'] == 'both' + ) { + if ($current_row == 1) { + $insert_line = $schema_insert . '(' + . implode(', ', $values) . ')'; + } else { + $insert_line = '(' . implode(', ', $values) . ')'; + $sql_max_size = $GLOBALS['sql_max_query_size']; + if (isset($sql_max_size) + && $sql_max_size > 0 + && $query_size + strlen($insert_line) > $sql_max_size + ) { + if (! PMA_exportOutputHandler(';' . $crlf)) { + return false; + } + $query_size = 0; + $current_row = 1; + $insert_line = $schema_insert . $insert_line; + } + } + $query_size += strlen($insert_line); + // Other inserts case + } else { + $insert_line = $schema_insert + . '(' + . implode(', ', $values) + . ')'; + } + } + unset($values); + + if (! PMA_exportOutputHandler( + ($current_row == 1 ? '' : $separator . $crlf) + . $insert_line + )) { + return false; + } + + } // end while + + if ($current_row > 0) { + if (! PMA_exportOutputHandler(';' . $crlf)) { + return false; + } + } + + // We need to SET IDENTITY_INSERT OFF for MSSQL + if (isset($GLOBALS['sql_compatibility']) + && $GLOBALS['sql_compatibility'] == 'MSSQL' + && $current_row > 0 + ) { + $outputSucceeded = PMA_exportOutputHandler( + $crlf . 'SET IDENTITY_INSERT ' + . PMA_Util::backquoteCompat($table, $compat) + . ' OFF;' . $crlf + ); + if (! $outputSucceeded) { + return false; + } + } + } // end if ($result != false) + PMA_DBI_free_result($result); + + return true; + } // end of the 'exportData()' function +} diff --git a/phpmyadmin/libraries/plugins/export/ExportTexytext.class.php b/phpmyadmin/libraries/plugins/export/ExportTexytext.class.php new file mode 100644 index 000000000..3aa609c34 --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/ExportTexytext.class.php @@ -0,0 +1,574 @@ +setProperties(); + } + + /** + * Sets the export Texy! text properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('Texy! text'); + $exportPluginProperties->setExtension('txt'); + $exportPluginProperties->setMimeType('text/plain'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // what to dump (structure/data/both) main group + $dumpWhat = new OptionsPropertyMainGroup(); + $dumpWhat->setName("general_opts"); + $dumpWhat->setText(__('Dump table')); + // create primary items and add them to the group + $leaf = new RadioPropertyItem(); + $leaf->setName("structure_or_data"); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $dumpWhat->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($dumpWhat); + + // data options main group + $dataOptions = new OptionsPropertyMainGroup(); + $dataOptions->setName("data"); + $dataOptions->setText(__('Data dump options')); + $dataOptions->setForce('structure'); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Put columns names in the first row')); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('Replace NULL with:')); + $dataOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($dataOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return PMA_exportOutputHandler( + '===' . __('Database') . ' ' . $db . "\n\n" + ); + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + /** + * Outputs the content of a table in NHibernate format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $what; + + if (! PMA_exportOutputHandler( + '== ' . __('Dumping data for table') . ' ' . $table . "\n\n" + )) { + return false; + } + + // Gets the data from the database + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $fields_cnt = PMA_DBI_num_fields($result); + + // If required, get fields name at the first line + if (isset($GLOBALS[$what . '_columns'])) { + $text_output = "|------\n"; + for ($i = 0; $i < $fields_cnt; $i++) { + $text_output .= '|' + . htmlspecialchars( + stripslashes(PMA_DBI_field_name($result, $i)) + ); + } // end for + $text_output .= "\n|------\n"; + if (! PMA_exportOutputHandler($text_output)) { + return false; + } + } // end if + + // Format the data + while ($row = PMA_DBI_fetch_row($result)) { + $text_output = ''; + for ($j = 0; $j < $fields_cnt; $j++) { + if (! isset($row[$j]) || is_null($row[$j])) { + $value = $GLOBALS[$what . '_null']; + } elseif ($row[$j] == '0' || $row[$j] != '') { + $value = $row[$j]; + } else { + $value = ' '; + } + $text_output .= '|' + . str_replace( + '|', '|', htmlspecialchars($value) + ); + } // end for + $text_output .= "\n"; + if (! PMA_exportOutputHandler($text_output)) { + return false; + } + } // end while + PMA_DBI_free_result($result); + + return true; + } + + /** + * Returns a stand-in CREATE definition to resolve view dependencies + * + * @param string $db the database name + * @param string $view the view name + * @param string $crlf the end of line sequence + * + * @return string resulting definition + */ + function getTableDefStandIn($db, $view, $crlf) + { + $text_output = ''; + + /** + * Get the unique keys in the table + */ + $unique_keys = array(); + $keys = PMA_DBI_get_table_indexes($db, $view); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + + /** + * Gets fields properties + */ + PMA_DBI_select_db($db); + + /** + * Displays the table structure + */ + + $text_output .= "|------\n" + . '|' . __('Column') + . '|' . __('Type') + . '|' . __('Null') + . '|' . __('Default') + . "\n|------\n"; + + $columns = PMA_DBI_get_columns($db, $view); + foreach ($columns as $column) { + $text_output .= $this->formatOneColumnDefinition($column, $unique_keys); + $text_output .= "\n"; + } // end foreach + + return $text_output; + } + + /** + * Returns $table's CREATE definition + * + * @param string $db the database name + * @param string $table the table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param bool $do_relation whether to include relation comments + * @param bool $do_comments whether to include the pmadb-style column + * comments as comments in the structure; + * this is deprecated but the parameter is + * left here because export.php calls + * $this->exportStructure() also for other + * export types which use this parameter + * @param bool $do_mime whether to include mime comments + * @param bool $show_dates whether to include creation/update/check dates + * @param bool $add_semicolon whether to add semicolon and end-of-line + * at the end + * @param bool $view whether we're handling a view + * + * @return string resulting schema + */ + function getTableDef( + $db, + $table, + $crlf, + $error_url, + $do_relation, + $do_comments, + $do_mime, + $show_dates = false, + $add_semicolon = true, + $view = false + ) { + global $cfgRelation; + + $text_output = ''; + + /** + * Get the unique keys in the table + */ + $unique_keys = array(); + $keys = PMA_DBI_get_table_indexes($db, $table); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + + /** + * Gets fields properties + */ + PMA_DBI_select_db($db); + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + /** + * Displays the table structure + */ + + $columns_cnt = 4; + if ($do_relation && $have_rel) { + $columns_cnt++; + } + if ($do_comments && $cfgRelation['commwork']) { + $columns_cnt++; + } + if ($do_mime && $cfgRelation['mimework']) { + $columns_cnt++; + } + + $text_output .= "|------\n"; + $text_output .= '|' . __('Column'); + $text_output .= '|' . __('Type'); + $text_output .= '|' . __('Null'); + $text_output .= '|' . __('Default'); + if ($do_relation && $have_rel) { + $text_output .= '|' . __('Links to'); + } + if ($do_comments) { + $text_output .= '|' . __('Comments'); + $comments = PMA_getComments($db, $table); + } + if ($do_mime && $cfgRelation['mimework']) { + $text_output .= '|' . htmlspecialchars('MIME'); + $mime_map = PMA_getMIME($db, $table, true); + } + $text_output .= "\n|------\n"; + + $columns = PMA_DBI_get_columns($db, $table); + foreach ($columns as $column) { + $text_output .= $this->formatOneColumnDefinition($column, $unique_keys); + $field_name = $column['Field']; + + if ($do_relation && $have_rel) { + $text_output .= '|' + . (isset($res_rel[$field_name]) + ? htmlspecialchars( + $res_rel[$field_name]['foreign_table'] + . ' (' . $res_rel[$field_name]['foreign_field'] . ')' + ) + : ''); + } + if ($do_comments && $cfgRelation['commwork']) { + $text_output .= '|' + . (isset($comments[$field_name]) + ? htmlspecialchars($comments[$field_name]) + : ''); + } + if ($do_mime && $cfgRelation['mimework']) { + $text_output .= '|' + . (isset($mime_map[$field_name]) + ? htmlspecialchars( + str_replace('_', '/', $mime_map[$field_name]['mimetype']) + ) + : ''); + } + + $text_output .= "\n"; + } // end foreach + + return $text_output; + } // end of the '$this->getTableDef()' function + + /** + * Outputs triggers + * + * @param string $db database name + * @param string $table table name + * + * @return string Formatted triggers list + */ + function getTriggers($db, $table) + { + $text_output .= "|------\n"; + $text_output .= '|' . __('Column'); + $dump = "|------\n"; + $dump .= '|' . __('Name'); + $dump .= '|' . __('Time'); + $dump .= '|' . __('Event'); + $dump .= '|' . __('Definition'); + $dump .= "\n|------\n"; + + $triggers = PMA_DBI_get_triggers($db, $table); + + foreach ($triggers as $trigger) { + $dump .= '|' . $trigger['name']; + $dump .= '|' . $trigger['action_timing']; + $dump .= '|' . $trigger['event_manipulation']; + $dump .= '|' . + str_replace( + '|', + '|', + htmlspecialchars($trigger['definition']) + ); + $dump .= "\n"; + } + + return $dump; + } + + /** + * Outputs table's structure + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $export_mode 'create_table', 'triggers', 'create_view', + * 'stand_in' + * @param string $export_type 'server', 'database', 'table' + * @param bool $do_relation whether to include relation comments + * @param bool $do_comments whether to include the pmadb-style column + * comments as comments in the structure; + * this is deprecated but the parameter is + * left here because export.php calls + * $this->exportStructure() also for other + * export types which use this parameter + * @param bool $do_mime whether to include mime comments + * @param bool $dates whether to include creation/update/check dates + * + * @return bool Whether it succeeded + */ + function exportStructure( + $db, + $table, + $crlf, + $error_url, + $export_mode, + $export_type, + $do_relation = false, + $do_comments = false, + $do_mime = false, + $dates = false + ) { + $dump = ''; + + switch($export_mode) { + case 'create_table': + $dump .= '== ' . __('Table structure for table') . ' ' .$table . "\n\n"; + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, + $do_mime, $dates + ); + break; + case 'triggers': + $dump = ''; + $triggers = PMA_DBI_get_triggers($db, $table); + if ($triggers) { + $dump .= '== ' . __('Triggers') . ' ' .$table . "\n\n"; + $dump .= $this->getTriggers($db, $table); + } + break; + case 'create_view': + $dump .= '== ' . __('Structure for view') . ' ' .$table . "\n\n"; + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, + $do_mime, $dates, true, true + ); + break; + case 'stand_in': + $dump .= '== ' . __('Stand-in structure for view') + . ' ' .$table . "\n\n"; + // export a stand-in definition to resolve view dependencies + $dump .= $this->getTableDefStandIn($db, $table, $crlf); + } // end switch + + return PMA_exportOutputHandler($dump); + } + + /** + * Formats the definition for one column + * + * @param array $column info about this column + * @param array $unique_keys unique keys for this table + * + * @return string Formatted column definition + */ + function formatOneColumnDefinition( + $column, $unique_keys + ) { + $extracted_columnspec + = PMA_Util::extractColumnSpec($column['Type']); + $type = $extracted_columnspec['print_type']; + if (empty($type)) { + $type = ' '; + } + + if (! isset($column['Default'])) { + if ($column['Null'] != 'NO') { + $column['Default'] = 'NULL'; + } + } + + $fmt_pre = ''; + $fmt_post = ''; + if (in_array($column['Field'], $unique_keys)) { + $fmt_pre = '**' . $fmt_pre; + $fmt_post = $fmt_post . '**'; + } + if ($column['Key']=='PRI') { + $fmt_pre = '//' . $fmt_pre; + $fmt_post = $fmt_post . '//'; + } + $definition = '|' + . $fmt_pre . htmlspecialchars($column['Field']) . $fmt_post; + $definition .= '|' . htmlspecialchars($type); + $definition .= '|' + . (($column['Null'] == '' || $column['Null'] == 'NO') + ? __('No') : __('Yes')); + $definition .= '|' + . htmlspecialchars( + isset($column['Default']) ? $column['Default'] : '' + ); + return $definition; + } +} +?> \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/export/ExportXml.class.php b/phpmyadmin/libraries/plugins/export/ExportXml.class.php new file mode 100644 index 000000000..711824c32 --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/ExportXml.class.php @@ -0,0 +1,536 @@ +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 = PMA_DBI_fetch_result( + "SELECT + 'utf8' AS DEFAULT_CHARACTER_SET_NAME, + DEFAULT_COLLATION_NAME + FROM data_dictionary.SCHEMAS + WHERE SCHEMA_NAME = '" + . PMA_Util::sqlAddSlashes($db) . "'" + ); + } else { + $result = PMA_DBI_fetch_result( + 'SELECT `DEFAULT_CHARACTER_SET_NAME`, `DEFAULT_COLLATION_NAME`' + . ' FROM `information_schema`.`SCHEMATA` WHERE `SCHEMA_NAME`' + . ' = \''.PMA_Util::sqlAddSlashes($db).'\' LIMIT 1' + ); + } + $db_collation = $result[0]['DEFAULT_COLLATION_NAME']; + $db_charset = $result[0]['DEFAULT_CHARACTER_SET_NAME']; + + $head .= ' ' . $crlf; + $head .= ' ' . $crlf; + $head .= ' ' . $crlf; + + if (count($tables) == 0) { + $tables[] = $table; + } + + foreach ($tables as $table) { + // Export tables and views + $result = PMA_DBI_fetch_result( + 'SHOW CREATE TABLE ' . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table), + 0 + ); + $tbl = $result[$table][1]; + + $is_view = PMA_Table::isView($db, $table); + + if ($is_view) { + $type = 'view'; + } else { + $type = 'table'; + } + + if ($is_view && ! isset($GLOBALS['xml_export_views'])) { + continue; + } + + if (! $is_view && ! isset($GLOBALS['xml_export_tables'])) { + continue; + } + + $head .= ' ' + . $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 = PMA_DBI_get_triggers($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 = PMA_DBI_get_procedures_or_functions($db, 'FUNCTION'); + if ($functions) { + foreach ($functions as $function) { + $head .= ' ' . $crlf; + + // Do some formatting + $sql = PMA_DBI_get_definition($db, 'FUNCTION', $function); + $sql = rtrim($sql); + $sql = " " . htmlspecialchars($sql); + $sql = str_replace("\n", "\n ", $sql); + + $head .= $sql . $crlf; + $head .= ' ' . $crlf; + } + + unset($function); + unset($functions); + } + } + + if (isset($GLOBALS['xml_export_procedures']) + && $GLOBALS['xml_export_procedures'] + ) { + // Export procedures + $procedures = PMA_DBI_get_procedures_or_functions($db, 'PROCEDURE'); + if ($procedures) { + foreach ($procedures as $procedure) { + $head .= ' ' . $crlf; + + // Do some formatting + $sql = PMA_DBI_get_definition($db, 'PROCEDURE', $procedure); + $sql = rtrim($sql); + $sql = " " . htmlspecialchars($sql); + $sql = str_replace("\n", "\n ", $sql); + + $head .= $sql . $crlf; + $head .= ' ' . $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 = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + + $columns_cnt = PMA_DBI_num_fields($result); + $columns = array(); + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = stripslashes(PMA_DBI_field_name($result, $i)); + } + unset($i); + + $buffer = ' ' . $crlf; + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + while ($record = PMA_DBI_fetch_row($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; + } + } + PMA_DBI_free_result($result); + } + + return true; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the table name + * + * @return void + */ + private function _getTable() + { + return $this->_table; + } + + /** + * Sets the table name + * + * @param string $table table name + * + * @return void + */ + private function _setTable($table) + { + $this->_table = $table; + } + + /** + * Gets the table names + * + * @return array + */ + private function _getTables() + { + return $this->_tables; + } + + /** + * Sets the table names + * + * @param array $tables table names + * + * @return void + */ + private function _setTables($tables) + { + $this->_tables = $tables; + } +} +?> diff --git a/phpmyadmin/libraries/plugins/export/ExportYaml.class.php b/phpmyadmin/libraries/plugins/export/ExportYaml.class.php new file mode 100644 index 000000000..044daeee4 --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/ExportYaml.class.php @@ -0,0 +1,214 @@ +setProperties(); + } + + /** + * Sets the export YAML properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('YAML'); + $exportPluginProperties->setExtension('yml'); + $exportPluginProperties->setMimeType('text/yaml'); + $exportPluginProperties->setForceFile(true); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new HiddenPropertyItem(); + $leaf->setName("structure_or_data"); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + PMA_exportOutputHandler( + '%YAML 1.1' . $GLOBALS['crlf'] . '---' . $GLOBALS['crlf'] + ); + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + PMA_exportOutputHandler('...' . $GLOBALS['crlf']); + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs the content of a table in JSON format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + + $columns_cnt = PMA_DBI_num_fields($result); + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = stripslashes(PMA_DBI_field_name($result, $i)); + } + unset($i); + + $buffer = ''; + $record_cnt = 0; + while ($record = PMA_DBI_fetch_row($result)) { + $record_cnt++; + + // Output table name as comment if this is the first record of the table + if ($record_cnt == 1) { + $buffer = '# ' . $db . '.' . $table . $crlf; + $buffer .= '-' . $crlf; + } else { + $buffer = '-' . $crlf; + } + + for ($i = 0; $i < $columns_cnt; $i++) { + if (! isset($record[$i])) { + continue; + } + + $column = $columns[$i]; + + if (is_null($record[$i])) { + $buffer .= ' ' . $column . ': null' . $crlf; + continue; + } + + if (is_numeric($record[$i])) { + $buffer .= ' ' . $column . ': ' . $record[$i] . $crlf; + continue; + } + + $record[$i] = str_replace( + array('\\', '"', "\n", "\r"), + array('\\\\', '\"', '\n', '\r'), + $record[$i] + ); + $buffer .= ' ' . $column . ': "' . $record[$i] . '"' . $crlf; + } + + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + } + PMA_DBI_free_result($result); + + return true; + } // end getTableYAML +} +?> \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/export/PMA_ExportPdf.class.php b/phpmyadmin/libraries/plugins/export/PMA_ExportPdf.class.php new file mode 100644 index 000000000..1913d5ecd --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/PMA_ExportPdf.class.php @@ -0,0 +1,408 @@ +empty_string($y)) { + $y = $this->y; + } + $current_page = $this->page; + if ((($y + $h) > $this->PageBreakTrigger) + AND (! $this->InFooter) + AND ($this->AcceptPageBreak()) + ) { + if ($addpage) { + //Automatic page break + $x = $this->x; + $this->AddPage($this->CurOrientation); + $this->y = $this->dataY; + $oldpage = $this->page - 1; + + $this_page_orm = $this->pagedim[$this->page]['orm']; + $old_page_orm = $this->pagedim[$oldpage]['orm']; + $this_page_olm = $this->pagedim[$this->page]['olm']; + $old_page_olm = $this->pagedim[$oldpage]['olm']; + if ($this->rtl) { + if ($this_page_orm!= $old_page_orm) { + $this->x = $x - ($this_page_orm - $old_page_orm); + } else { + $this->x = $x; + } + } else { + if ($this_page_olm != $old_page_olm) { + $this->x = $x + ($this_page_olm - $old_page_olm); + } else { + $this->x = $x; + } + } + } + return true; + } + if ($current_page != $this->page) { + // account for columns mode + return true; + } + return false; + } + + /** + * This method is used to render the page header. + * + * @return void + */ + function Header() + { + global $maxY; + // We don't want automatic page breaks while generating header + // as this can lead to infinite recursion as auto generated page + // will want header as well causing another page break + // FIXME: Better approach might be to try to compact the content + $this->SetAutoPageBreak(false); + // Check if header for this page already exists + if (! isset($this->headerset[$this->page])) { + $fullwidth = 0; + foreach ($this->tablewidths as $width) { + $fullwidth += $width; + } + $this->SetY(($this->tMargin) - ($this->FontSizePt / $this->k) * 5); + $this->cellFontSize = $this->FontSizePt ; + $this->SetFont( + PMA_PDF_FONT, + '', + ($this->titleFontSize + ? $this->titleFontSize + : $this->FontSizePt) + ); + $this->Cell(0, $this->FontSizePt, $this->titleText, 0, 1, 'C'); + $this->SetFont(PMA_PDF_FONT, '', $this->cellFontSize); + $this->SetY(($this->tMargin) - ($this->FontSizePt / $this->k) * 2.5); + $this->Cell( + 0, + $this->FontSizePt, + __('Database') . ': ' . $this->currentDb . ', ' + . __('Table') . ': ' . $this->currentTable, + 0, 1, 'L' + ); + $l = ($this->lMargin); + foreach ($this->colTitles as $col => $txt) { + $this->SetXY($l, ($this->tMargin)); + $this->MultiCell( + $this->tablewidths[$col], + $this->FontSizePt, + $txt + ); + $l += $this->tablewidths[$col] ; + $maxY = ($maxY < $this->getY()) ? $this->getY() : $maxY ; + } + $this->SetXY($this->lMargin, $this->tMargin); + $this->setFillColor(200, 200, 200); + $l = ($this->lMargin); + foreach ($this->colTitles as $col => $txt) { + $this->SetXY($l, $this->tMargin); + $this->cell( + $this->tablewidths[$col], + $maxY-($this->tMargin), + '', + 1, + 0, + 'L', + 1 + ); + $this->SetXY($l, $this->tMargin); + $this->MultiCell( + $this->tablewidths[$col], + $this->FontSizePt, + $txt, + 0, + 'C' + ); + $l += $this->tablewidths[$col]; + } + $this->setFillColor(255, 255, 255); + // set headerset + $this->headerset[$this->page] = 1; + } + + $this->dataY = $maxY; + $this->SetAutoPageBreak(true); + } + + function morepagestable($lineheight = 8) + { + // some things to set and 'remember' + $l = $this->lMargin; + $startheight = $h = $this->dataY; + $startpage = $currpage = $this->page; + + // calculate the whole width + $fullwidth = 0; + foreach ($this->tablewidths as $width) { + $fullwidth += $width; + } + + // Now let's start to write the table + $row = 0; + $tmpheight = array(); + $maxpage = $this->page; + + while ($data = PMA_DBI_fetch_row($this->results)) { + $this->page = $currpage; + // write the horizontal borders + $this->Line($l, $h, $fullwidth+$l, $h); + // write the content and remember the height of the highest col + foreach ($data as $col => $txt) { + $this->page = $currpage; + $this->SetXY($l, $h); + if ($this->tablewidths[$col] > 0) { + $this->MultiCell( + $this->tablewidths[$col], + $lineheight, + $txt, + 0, + $this->colAlign[$col] + ); + $l += $this->tablewidths[$col]; + } + + if (! isset($tmpheight[$row.'-'.$this->page])) { + $tmpheight[$row.'-'.$this->page] = 0; + } + if ($tmpheight[$row.'-'.$this->page] < $this->GetY()) { + $tmpheight[$row.'-'.$this->page] = $this->GetY(); + } + if ($this->page > $maxpage) { + $maxpage = $this->page; + } + unset($data[$col]); + } + + // get the height we were in the last used page + $h = $tmpheight[$row.'-'.$maxpage]; + // set the "pointer" to the left margin + $l = $this->lMargin; + // set the $currpage to the last page + $currpage = $maxpage; + unset($data[$row]); + $row++; + } + // draw the borders + // we start adding a horizontal line on the last page + $this->page = $maxpage; + $this->Line($l, $h, $fullwidth+$l, $h); + // now we start at the top of the document and walk down + for ($i = $startpage; $i <= $maxpage; $i++) { + $this->page = $i; + $l = $this->lMargin; + $t = ($i == $startpage) ? $startheight : $this->tMargin; + $lh = ($i == $maxpage) ? $h : $this->h-$this->bMargin; + $this->Line($l, $t, $l, $lh); + foreach ($this->tablewidths as $width) { + $l += $width; + $this->Line($l, $t, $l, $lh); + } + } + // set it to the last page, if not it'll cause some problems + $this->page = $maxpage; + } + + /** + * Sets a set of attributes. + * + * @param array $attr array containing the attributes + * + * @return void + */ + function setAttributes($attr = array()) + { + foreach ($attr as $key => $val) { + $this->$key = $val ; + } + } + + /** + * Defines the top margin. + * The method can be called before creating the first page. + * + * @param float $topMargin the margin + * + * @return void + */ + function setTopMargin($topMargin) + { + $this->tMargin = $topMargin; + } + + function mysqlReport($query) + { + unset($this->tablewidths); + unset($this->colTitles); + unset($this->titleWidth); + unset($this->colFits); + unset($this->display_column); + unset($this->colAlign); + + /** + * Pass 1 for column widths + */ + $this->results = PMA_DBI_query($query, null, PMA_DBI_QUERY_UNBUFFERED); + $this->numFields = PMA_DBI_num_fields($this->results); + $this->fields = PMA_DBI_get_fields_meta($this->results); + + // sColWidth = starting col width (an average size width) + $availableWidth = $this->w - $this->lMargin - $this->rMargin; + $this->sColWidth = $availableWidth / $this->numFields; + $totalTitleWidth = 0; + + // loop through results header and set initial + // col widths/ titles/ alignment + // if a col title is less than the starting col width, + // reduce that column size + $colFits = array(); + for ($i = 0; $i < $this->numFields; $i++) { + $stringWidth = $this->getstringwidth($this->fields[$i]->name) + 6 ; + // save the real title's width + $titleWidth[$i] = $stringWidth; + $totalTitleWidth += $stringWidth; + + // set any column titles less than the start width to + // the column title width + if ($stringWidth < $this->sColWidth) { + $colFits[$i] = $stringWidth ; + } + $this->colTitles[$i] = $this->fields[$i]->name; + $this->display_column[$i] = true; + + switch ($this->fields[$i]->type) { + case 'int': + $this->colAlign[$i] = 'R'; + break; + case 'blob': + case 'tinyblob': + case 'mediumblob': + case 'longblob': + /** + * @todo do not deactivate completely the display + * but show the field's name and [BLOB] + */ + if (stristr($this->fields[$i]->flags, 'BINARY')) { + $this->display_column[$i] = false; + unset($this->colTitles[$i]); + } + $this->colAlign[$i] = 'L'; + break; + default: + $this->colAlign[$i] = 'L'; + } + } + + // title width verification + if ($totalTitleWidth > $availableWidth) { + $adjustingMode = true; + } else { + $adjustingMode = false; + // we have enough space for all the titles at their + // original width so use the true title's width + foreach ($titleWidth as $key => $val) { + $colFits[$key] = $val; + } + } + + // loop through the data; any column whose contents + // is greater than the column size is resized + /** + * @todo force here a LIMIT to avoid reading all rows + */ + while ($row = PMA_DBI_fetch_row($this->results)) { + foreach ($colFits as $key => $val) { + $stringWidth = $this->getstringwidth($row[$key]) + 6 ; + if ($adjustingMode && ($stringWidth > $this->sColWidth)) { + // any column whose data's width is bigger than + // the start width is now discarded + unset($colFits[$key]); + } else { + // if data's width is bigger than the current column width, + // enlarge the column (but avoid enlarging it if the + // data's width is very big) + if ($stringWidth > $val + && $stringWidth < ($this->sColWidth * 3) + ) { + $colFits[$key] = $stringWidth ; + } + } + } + } + + $totAlreadyFitted = 0; + foreach ($colFits as $key => $val) { + // set fitted columns to smallest size + $this->tablewidths[$key] = $val; + // to work out how much (if any) space has been freed up + $totAlreadyFitted += $val; + } + + if ($adjustingMode) { + $surplus = (sizeof($colFits) * $this->sColWidth) - $totAlreadyFitted; + $surplusToAdd = $surplus / ($this->numFields - sizeof($colFits)); + } else { + $surplusToAdd = 0; + } + + for ($i = 0; $i < $this->numFields; $i++) { + if (! in_array($i, array_keys($colFits))) { + $this->tablewidths[$i] = $this->sColWidth + $surplusToAdd; + } + if ($this->display_column[$i] == false) { + $this->tablewidths[$i] = 0; + } + } + + ksort($this->tablewidths); + + PMA_DBI_free_result($this->results); + + // Pass 2 + + $this->results = PMA_DBI_query($query, null, PMA_DBI_QUERY_UNBUFFERED); + $this->setY($this->tMargin); + $this->AddPage(); + $this->SetFont(PMA_PDF_FONT, '', 9); + $this->morepagestable($this->FontSizePt); + PMA_DBI_free_result($this->results); + + } // end of mysqlReport function + +} // end of PMA_Export_PDF class +?> diff --git a/phpmyadmin/libraries/plugins/export/README b/phpmyadmin/libraries/plugins/export/README new file mode 100644 index 000000000..68d5a26f1 --- /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 000000000..a928a6c3d --- /dev/null +++ b/phpmyadmin/libraries/plugins/export/TableProperty.class.php @@ -0,0 +1,288 @@ +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 000000000..62ca8bb54 --- /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 000000000..d48056484 --- /dev/null +++ b/phpmyadmin/libraries/plugins/import/ImportCsv.class.php @@ -0,0 +1,588 @@ +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 by'), false); + $error = true; + $param_error = true; + // The default dialog of MS Excel when generating a CSV produces a + // semi-colon-separated file with no chance of specifying the + // enclosing character. Thus, users who want to import this file + // tend to remove the enclosing character on the Import dialog. + // I could not find a test case where having no enclosing characters + // confuses this script. + // But the parser won't work correctly with strings so we allow just + // one character. + } elseif (strlen($csv_enclosed) > 1) { + $message = PMA_Message::error( + __('Invalid parameter for CSV import: %s') + ); + $message->addParam(__('Columns enclosed by'), false); + $error = true; + $param_error = true; + } elseif (strlen($csv_escaped) != 1) { + $message = PMA_Message::error( + __('Invalid parameter for CSV import: %s') + ); + $message->addParam(__('Columns escaped by'), false); + $error = true; + $param_error = true; + } elseif (strlen($csv_new_line) != 1 && $csv_new_line != 'auto') { + $message = PMA_Message::error( + __('Invalid parameter for CSV import: %s') + ); + $message->addParam(__('Lines terminated by'), false); + $error = true; + $param_error = true; + } + + // If there is an error in the parameters entered, + // indicate that immediately. + if ($param_error) { + PMA_Util::mysqlDie($message->getMessage(), '', '', $err_url); + } + + $buffer = ''; + $required_fields = 0; + + if (! $this->_getAnalyze()) { + if (isset($_POST['csv_replace'])) { + $sql_template = 'REPLACE'; + } else { + $sql_template = 'INSERT'; + if (isset($_POST['csv_ignore'])) { + $sql_template .= ' IGNORE'; + } + } + $sql_template .= ' INTO ' . PMA_Util::backquote($table); + + $tmp_fields = PMA_DBI_get_columns($db, $table); + + if (empty($csv_columns)) { + $fields = $tmp_fields; + } else { + $sql_template .= ' ('; + $fields = array(); + $tmp = preg_split('/,( ?)/', $csv_columns); + foreach ($tmp as $key => $val) { + if (count($fields) > 0) { + $sql_template .= ', '; + } + /* Trim also `, if user already included backquoted fields */ + $val = trim($val, " \t\r\n\0\x0B`"); + $found = false; + foreach ($tmp_fields as $field) { + if ($field['Field'] == $val) { + $found = true; + break; + } + } + if (! $found) { + $message = PMA_Message::error( + __( + 'Invalid column (%s) specified! Ensure that columns' + . ' names are spelled correctly, separated by commas' + . ', and not enclosed in quotes.' + ) + ); + $message->addParam($val); + $error = true; + break; + } + $fields[] = $field; + $sql_template .= PMA_Util::backquote($val); + } + $sql_template .= ') '; + } + + $required_fields = count($fields); + + $sql_template .= ' VALUES ('; + } + + // Defaults for parser + $i = 0; + $len = 0; + $line = 1; + $lasti = -1; + $values = array(); + $csv_finish = false; + + $tempRow = array(); + $rows = array(); + $col_names = array(); + $tables = array(); + + $col_count = 0; + $max_cols = 0; + + while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { + $data = PMA_importGetNextChunk(); + if ($data === false) { + // subtract data we didn't handle yet and stop processing + $offset -= strlen($buffer); + break; + } elseif ($data === true) { + // Handle rest of buffer + } else { + // Append new data to buffer + $buffer .= $data; + unset($data); + // Do not parse string when we're not at the end + // and don't have new line inside + if (($csv_new_line == 'auto' + && strpos($buffer, "\r") === false + && strpos($buffer, "\n") === false) + || ($csv_new_line != 'auto' + && strpos($buffer, $csv_new_line) === false) + ) { + continue; + } + } + + // Current length of our buffer + $len = strlen($buffer); + // Currently parsed char + $ch = $buffer[$i]; + while ($i < $len) { + // Deadlock protection + if ($lasti == $i && $lastlen == $len) { + $message = PMA_Message::error( + __('Invalid format of CSV input on line %d.') + ); + $message->addParam($line); + $error = true; + break; + } + $lasti = $i; + $lastlen = $len; + + // This can happen with auto EOL and \r at the end of buffer + if (! $csv_finish) { + // Grab empty field + if ($ch == $csv_terminated) { + if ($i == $len - 1) { + break; + } + $values[] = ''; + $i++; + $ch = $buffer[$i]; + continue; + } + + // Grab one field + $fallbacki = $i; + if ($ch == $csv_enclosed) { + if ($i == $len - 1) { + break; + } + $need_end = true; + $i++; + $ch = $buffer[$i]; + } else { + $need_end = false; + } + $fail = false; + $value = ''; + while (($need_end + && ( $ch != $csv_enclosed || $csv_enclosed == $csv_escaped )) + || ( ! $need_end + && ! ( $ch == $csv_terminated + || $ch == $csv_new_line + || ( $csv_new_line == 'auto' + && ( $ch == "\r" || $ch == "\n" ) ) ) ) + ) { + if ($ch == $csv_escaped) { + if ($i == $len - 1) { + $fail = true; + break; + } + $i++; + $ch = $buffer[$i]; + if ($csv_enclosed == $csv_escaped + && ($ch == $csv_terminated + || $ch == $csv_new_line + || ($csv_new_line == 'auto' + && ($ch == "\r" || $ch == "\n"))) + ) { + break; + } + } + $value .= $ch; + if ($i == $len - 1) { + if (! $finished) { + $fail = true; + } + break; + } + $i++; + $ch = $buffer[$i]; + } + + // unquoted NULL string + if (false === $need_end && $value === 'NULL') { + $value = null; + } + + if ($fail) { + $i = $fallbacki; + $ch = $buffer[$i]; + break; + } + // Need to strip trailing enclosing char? + if ($need_end && $ch == $csv_enclosed) { + if ($finished && $i == $len - 1) { + $ch = null; + } elseif ($i == $len - 1) { + $i = $fallbacki; + $ch = $buffer[$i]; + break; + } else { + $i++; + $ch = $buffer[$i]; + } + } + // Are we at the end? + if ($ch == $csv_new_line + || ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n")) + || ($finished && $i == $len - 1) + ) { + $csv_finish = true; + } + // Go to next char + if ($ch == $csv_terminated) { + if ($i == $len - 1) { + $i = $fallbacki; + $ch = $buffer[$i]; + break; + } + $i++; + $ch = $buffer[$i]; + } + // If everything went okay, store value + $values[] = $value; + } + + // End of line + if ($csv_finish + || $ch == $csv_new_line + || ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n")) + ) { + if ($csv_new_line == 'auto' && $ch == "\r") { // Handle "\r\n" + if ($i >= ($len - 2) && ! $finished) { + break; // We need more data to decide new line + } + if ($buffer[$i + 1] == "\n") { + $i++; + } + } + // We didn't parse value till the end of line, so there was + // empty one + if (! $csv_finish) { + $values[] = ''; + } + + if ($this->_getAnalyze()) { + foreach ($values as $val) { + $tempRow[] = $val; + ++$col_count; + } + + if ($col_count > $max_cols) { + $max_cols = $col_count; + } + $col_count = 0; + + $rows[] = $tempRow; + $tempRow = array(); + } else { + // Do we have correct count of values? + if (count($values) != $required_fields) { + + // Hack for excel + if ($values[count($values) - 1] == ';') { + unset($values[count($values) - 1]); + } else { + $message = PMA_Message::error( + __('Invalid column count in CSV input on line %d.') + ); + $message->addParam($line); + $error = true; + break; + } + } + + $first = true; + $sql = $sql_template; + foreach ($values as $key => $val) { + if (! $first) { + $sql .= ', '; + } + if ($val === null) { + $sql .= 'NULL'; + } else { + $sql .= '\'' + . PMA_Util::sqlAddSlashes($val) + . '\''; + } + + $first = false; + } + $sql .= ')'; + + /** + * @todo maybe we could add original line to verbose + * SQL in comment + */ + PMA_importRunQuery($sql, $sql); + } + + $line++; + $csv_finish = false; + $values = array(); + $buffer = substr($buffer, $i + 1); + $len = strlen($buffer); + $i = 0; + $lasti = -1; + $ch = $buffer[0]; + } + } // End of parser loop + } // End of import loop + + if ($this->_getAnalyze()) { + /* Fill out all rows */ + $num_rows = count($rows); + for ($i = 0; $i < $num_rows; ++$i) { + for ($j = count($rows[$i]); $j < $max_cols; ++$j) { + $rows[$i][] = 'NULL'; + } + } + + if (isset($_REQUEST['csv_col_names'])) { + $col_names = array_splice($rows, 0, 1); + $col_names = $col_names[0]; + } + + if ((isset($col_names) && count($col_names) != $max_cols) + || ! isset($col_names) + ) { + // Fill out column names + for ($i = 0; $i < $max_cols; ++$i) { + $col_names[] = 'COL '.($i+1); + } + } + + if (strlen($db)) { + $result = PMA_DBI_fetch_result('SHOW TABLES'); + $tbl_name = 'TABLE '.(count($result) + 1); + } else { + $tbl_name = 'TBL_NAME'; + } + + $tables[] = array($tbl_name, $col_names, $rows); + + /* Obtain the best-fit MySQL types for each column */ + $analyses = array(); + $analyses[] = PMA_analyzeTable($tables[0]); + + /** + * string $db_name (no backquotes) + * + * array $table = array(table_name, array() column_names, array()() rows) + * array $tables = array of "$table"s + * + * array $analysis = array(array() column_types, array() column_sizes) + * array $analyses = array of "$analysis"s + * + * array $create = array of SQL strings + * + * array $options = an associative array of options + */ + + /* Set database name to the currently selected one, if applicable */ + if (strlen($db)) { + $db_name = $db; + $options = array('create_db' => false); + } else { + $db_name = 'CSV_DB'; + $options = null; + } + + /* Non-applicable parameters */ + $create = null; + + /* Created and execute necessary SQL statements from data */ + PMA_buildSQL($db_name, $tables, $analyses, $create, $options); + + unset($tables); + unset($analyses); + } + + // Commit any possible data in buffers + PMA_importRunQuery(); + + if (count($values) != 0 && ! $error) { + $message = PMA_Message::error( + __('Invalid format of CSV input on line %d.') + ); + $message->addParam($line); + $error = true; + } + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Returns true if the table should be analyzed, false otherwise + * + * @return bool + */ + private function _getAnalyze() + { + return $this->_analyze; + } + + /** + * Sets to true if the table should be analyzed, false otherwise + * + * @param bool $analyze status + * + * @return void + */ + private function _setAnalyze($analyze) + { + $this->_analyze = $analyze; + } +} diff --git a/phpmyadmin/libraries/plugins/import/ImportLdi.class.php b/phpmyadmin/libraries/plugins/import/ImportLdi.class.php new file mode 100644 index 000000000..e38def9c8 --- /dev/null +++ b/phpmyadmin/libraries/plugins/import/ImportLdi.class.php @@ -0,0 +1,172 @@ +setProperties(); + } + + /** + * Sets the import plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + if ($GLOBALS['cfg']['Import']['ldi_local_option'] == 'auto') { + $GLOBALS['cfg']['Import']['ldi_local_option'] = false; + + $result = PMA_DBI_try_query('SHOW VARIABLES LIKE \'local\\_infile\';'); + if ($result != false && PMA_DBI_num_rows($result) > 0) { + $tmp = PMA_DBI_fetch_row($result); + if ($tmp[1] == 'ON') { + $GLOBALS['cfg']['Import']['ldi_local_option'] = true; + } + } + PMA_DBI_free_result($result); + unset($result); + } + + $generalOptions = parent::setProperties(); + $this->properties->setText('CSV using LOAD DATA'); + $this->properties->setExtension('ldi'); + + $leaf = new TextPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Column names: ')); + $generalOptions->addProperty($leaf); + + $leaf = new BoolPropertyItem(); + $leaf->setName("ignore"); + $leaf->setText(__('Do not abort on INSERT error')); + $generalOptions->addProperty($leaf); + + $leaf = new BoolPropertyItem(); + $leaf->setName("local_option"); + $leaf->setText(__('Use LOCAL keyword')); + $generalOptions->addProperty($leaf); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + global $finished, $error, $import_file, $compression, $charset_conversion, $table; + global $ldi_local_option, $ldi_replace, $ldi_ignore, $ldi_terminated, $ldi_enclosed, + $ldi_escaped, $ldi_new_line, $skip_queries, $ldi_columns; + + if ($import_file == 'none' + || $compression != 'none' + || $charset_conversion + ) { + // We handle only some kind of data! + $message = PMA_Message::error( + __('This plugin does not support compressed imports!') + ); + $error = true; + return; + } + + $sql = 'LOAD DATA'; + if (isset($ldi_local_option)) { + $sql .= ' LOCAL'; + } + $sql .= ' INFILE \'' . PMA_Util::sqlAddSlashes($import_file) . '\''; + if (isset($ldi_replace)) { + $sql .= ' REPLACE'; + } elseif (isset($ldi_ignore)) { + $sql .= ' IGNORE'; + } + $sql .= ' INTO TABLE ' . PMA_Util::backquote($table); + + if (strlen($ldi_terminated) > 0) { + $sql .= ' FIELDS TERMINATED BY \'' . $ldi_terminated . '\''; + } + if (strlen($ldi_enclosed) > 0) { + $sql .= ' ENCLOSED BY \'' + . PMA_Util::sqlAddSlashes($ldi_enclosed) . '\''; + } + if (strlen($ldi_escaped) > 0) { + $sql .= ' ESCAPED BY \'' + . PMA_Util::sqlAddSlashes($ldi_escaped) . '\''; + } + if (strlen($ldi_new_line) > 0) { + if ($ldi_new_line == 'auto') { + $ldi_new_line + = (PMA_Util::whichCrlf() == "\n") + ? '\n' + : '\r\n'; + } + $sql .= ' LINES TERMINATED BY \'' . $ldi_new_line . '\''; + } + if ($skip_queries > 0) { + $sql .= ' IGNORE ' . $skip_queries . ' LINES'; + $skip_queries = 0; + } + if (strlen($ldi_columns) > 0) { + $sql .= ' ('; + $tmp = preg_split('/,( ?)/', $ldi_columns); + $cnt_tmp = count($tmp); + for ($i = 0; $i < $cnt_tmp; $i++) { + if ($i > 0) { + $sql .= ', '; + } + /* Trim also `, if user already included backquoted fields */ + $sql .= PMA_Util::backquote( + trim($tmp[$i], " \t\r\n\0\x0B`") + ); + } // end for + $sql .= ')'; + } + + PMA_importRunQuery($sql, $sql); + PMA_importRunQuery(); + $finished = true; + } +} \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/import/ImportMediawiki.class.php b/phpmyadmin/libraries/plugins/import/ImportMediawiki.class.php new file mode 100644 index 000000000..767c966c1 --- /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 + $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 = PMA_DBI_fetch_result('SHOW TABLES'); + // todo check if the name below already exists + $table_name = 'TABLE '.(count($result) + 1); + } + } + + /** + * Set generic names for table headers, if they don't exist + * + * @param array &$table_headers reference to the array containing the headers + * of a table + * @param array $table_row array containing the first content row + * + * @return void + */ + private function _setTableHeaders(&$table_headers, $table_row) + { + if (empty($table_headers)) { + // The first table row should contain the number of columns + // If they are not set, generic names will be given (COL 1, COL 2, etc) + $num_cols = count($table_row); + for ($i = 0; $i < $num_cols; ++ $i) { + $table_headers [$i] = 'COL '. ($i + 1); + } + } + } + + /** + * Sets the database name and additional options and calls PMA_buildSQL() + * Used in PMA_importDataAllTables() and $this->_importDataOneTable() + * + * @param array &$tables structure: + * array( + * array(table_name, array() column_names, array()() rows) + * ) + * @param array &$analyses structure: + * $analyses = array( + * array(array() column_types, array() column_sizes) + * ) + * + * @global string $db name of the database to import in + * + * @return void + */ + private function _executeImportTables(&$tables, &$analyses) + { + global $db; + + // $db_name : The currently selected database name, if applicable + // No backquotes + // $options : An associative array of options + if (strlen($db)) { + $db_name = $db; + $options = array('create_db' => false); + } else { + $db_name = 'mediawiki_DB'; + $options = null; + } + + // Array of SQL strings + // Non-applicable parameters + $create = null; + + // Create and execute necessary SQL statements from data + PMA_buildSQL($db_name, $tables, $analyses, $create, $options); + + unset($tables); + unset($analyses); + } + + + /** + * Replaces all instances of the '||' separator between delimiters + * in a given string + * + * @param string $start_delim start delimiter + * @param string $end_delim end delimiter + * @param string $replace the string to be replaced with + * @param string $subject the text to be replaced + * + * @return string with replacements + */ + private function _delimiterReplace($start_delim, $end_delim, $replace, $subject) + { + // String that will be returned + $cleaned = ""; + // Possible states of current character + $inside_tag = false; + $inside_attribute = false; + // Attributes can be declared with either " or ' + $start_attribute_character = false; + + // The full separator is "||"; + // This rembembers if the previous character was '|' + $partial_separator = false; + + // Parse text char by char + for ($i = 0; $i < strlen($subject); $i ++) { + $cur_char = $subject[$i]; + // Check for separators + if ($cur_char == '|') { + // If we're not inside a tag, then this is part of a real separator, + // so we append it to the current segment + if (! $inside_attribute) { + $cleaned .= $cur_char; + if ($partial_separator) { + $inside_tag = false; + $inside_attribute = false; + } + } elseif ($partial_separator) { + // If we are inside a tag, we replace the current char with + // the placeholder and append that to the current segment + $cleaned .= $replace; + } + + // If the previous character was also '|', then this ends a + // full separator. If not, this may be the beginning of one + $partial_separator = ! $partial_separator; + } else { + // If we're inside a tag attribute and the current character is + // not '|', but the previous one was, it means that the single '|' + // was not appended, so we append it now + if ($partial_separator && $inside_attribute) { + $cleaned .= "|"; + } + // If the char is different from "|", no separator can be formed + $partial_separator = false; + + // any other character should be appended to the current segment + $cleaned .= $cur_char; + + if ($cur_char == '<' && ! $inside_attribute) { + // start of a tag + $inside_tag = true; + } elseif ($cur_char == '>' && ! $inside_attribute) { + // end of a tag + $inside_tag = false; + } elseif (($cur_char == '"' || $cur_char == "'") && $inside_tag) { + // start or end of an attribute + if (! $inside_attribute) { + $inside_attribute = true; + // remember the attribute`s declaration character (" or ') + $start_attribute_character = $cur_char; + } else { + if ($cur_char == $start_attribute_character) { + $inside_attribute = false; + // unset attribute declaration character + $start_attribute_character = false; + } + } + } + } + } // end for each character in $subject + + return $cleaned; + } + + /** + * Separates a string into items, similarly to explode + * Uses the '||' separator (which is standard in the mediawiki format) + * and ignores any instances of it inside markup tags + * Used in parsing buffer lines containing data cells + * + * @param string $text text to be split + * + * @return array + */ + private function _explodeMarkup($text) + { + $separator = "||"; + $placeholder = "\x00"; + + // Remove placeholder instances + $text = str_replace($placeholder, '', $text); + + // Replace instances of the separator inside HTML-like + // tags with the placeholder + $cleaned = $this->_delimiterReplace("<", ">", $placeholder, $text); + // Explode, then put the replaced separators back in + $items = explode($separator, $cleaned); + foreach ($items as $i => $str) { + $items[$i] = str_replace($placeholder, $separator, $str); + } + + return $items; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Returns true if the table should be analyzed, false otherwise + * + * @return bool + */ + private function _getAnalyze() + { + return $this->_analyze; + } + + /** + * Sets to true if the table should be analyzed, false otherwise + * + * @param bool $analyze status + * + * @return void + */ + private function _setAnalyze($analyze) + { + $this->_analyze = $analyze; + } +} \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/import/ImportOds.class.php b/phpmyadmin/libraries/plugins/import/ImportOds.class.php new file mode 100644 index 000000000..5a681e97a --- /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 */ + $offset -= strlen($buffer); + break; + } elseif ($data === true) { + /* Handle rest of buffer */ + } else { + /* Append new data to buffer */ + $buffer .= $data; + unset($data); + } + } + + unset($data); + + /** + * Disable loading of external XML entities. + */ + libxml_disable_entity_loader(); + + /** + * Load the XML string + * + * The option LIBXML_COMPACT is specified because it can + * result in increased performance without the need to + * alter the code in any way. It's basically a freebee. + */ + $xml = simplexml_load_string($buffer, "SimpleXMLElement", LIBXML_COMPACT); + + unset($buffer); + + if ($xml === false) { + $sheets = array(); + $message = PMA_Message::error( + __( + 'The XML file specified was either malformed or incomplete.' + . ' Please correct the issue and try again.' + ) + ); + $error = true; + } else { + $root = $xml->children('office', true)->{'body'}->{'spreadsheet'}; + if (empty($root)) { + $sheets = array(); + $message = PMA_Message::error( + __('Could not parse OpenDocument Spreasheet!') + ); + $error = true; + } else { + $sheets = $root->children('table', true); + } + } + + $tables = array(); + + $max_cols = 0; + + $row_count = 0; + $col_count = 0; + $col_names = array(); + + $tempRow = array(); + $tempRows = array(); + $rows = array(); + + /* Iterate over tables */ + foreach ($sheets as $sheet) { + $col_names_in_first_row = isset($_REQUEST['ods_col_names']); + + /* Iterate over rows */ + foreach ($sheet as $row) { + $type = $row->getName(); + if (! strcmp('table-row', $type)) { + /* Iterate over columns */ + foreach ($row as $cell) { + $text = $cell->children('text', true); + $cell_attrs = $cell->attributes('office', true); + + if (count($text) != 0) { + $attr = $cell->attributes('table', true); + $num_repeat = (int) $attr['number-columns-repeated']; + $num_iterations = $num_repeat ? $num_repeat : 1; + + for ($k = 0; $k < $num_iterations; $k++) { + if ($_REQUEST['ods_recognize_percentages'] + && ! strcmp( + 'percentage', + $cell_attrs['value-type'] + ) + ) { + $value = (double)$cell_attrs['value']; + } elseif ($_REQUEST['ods_recognize_currency'] + && !strcmp('currency', $cell_attrs['value-type']) + ) { + $value = (double)$cell_attrs['value']; + } else { + /* We need to concatenate all paragraphs */ + $values = array(); + foreach ($text as $paragraph) { + $values[] = (string)$paragraph; + } + $value = implode("\n", $values); + } + if (! $col_names_in_first_row) { + $tempRow[] = $value; + } else { + $col_names[] = $value; + } + + ++$col_count; + } + } else { + /* Number of blank columns repeated */ + if ($col_count < count($row->children('table', true)) - 1 + ) { + $attr = $cell->attributes('table', true); + $num_null = (int)$attr['number-columns-repeated']; + + if ($num_null) { + if (! $col_names_in_first_row) { + for ($i = 0; $i < $num_null; ++$i) { + $tempRow[] = 'NULL'; + ++$col_count; + } + } else { + for ($i = 0; $i < $num_null; ++$i) { + $col_names[] = PMA_getColumnAlphaName( + $col_count + 1 + ); + ++$col_count; + } + } + } else { + if (! $col_names_in_first_row) { + $tempRow[] = 'NULL'; + } else { + $col_names[] = PMA_getColumnAlphaName( + $col_count + 1 + ); + } + + ++$col_count; + } + } + } + } + + /* Find the widest row */ + if ($col_count > $max_cols) { + $max_cols = $col_count; + } + + /* Don't include a row that is full of NULL values */ + if (! $col_names_in_first_row) { + if ($_REQUEST['ods_empty_rows']) { + foreach ($tempRow as $cell) { + if (strcmp('NULL', $cell)) { + $tempRows[] = $tempRow; + break; + } + } + } else { + $tempRows[] = $tempRow; + } + } + + $col_count = 0; + $col_names_in_first_row = false; + $tempRow = array(); + } + } + + /* Skip over empty sheets */ + if (count($tempRows) == 0 || count($tempRows[0]) == 0) { + $col_names = array(); + $tempRow = array(); + $tempRows = array(); + continue; + } + + /** + * Fill out each row as necessary to make + * every one exactly as wide as the widest + * row. This included column names. + */ + + /* Fill out column names */ + for ($i = count($col_names); $i < $max_cols; ++$i) { + $col_names[] = PMA_getColumnAlphaName($i + 1); + } + + /* Fill out all rows */ + $num_rows = count($tempRows); + for ($i = 0; $i < $num_rows; ++$i) { + for ($j = count($tempRows[$i]); $j < $max_cols; ++$j) { + $tempRows[$i][] = 'NULL'; + } + } + + /* Store the table name so we know where to place the row set */ + $tbl_attr = $sheet->attributes('table', true); + $tables[] = array((string)$tbl_attr['name']); + + /* Store the current sheet in the accumulator */ + $rows[] = array((string)$tbl_attr['name'], $col_names, $tempRows); + $tempRows = array(); + $col_names = array(); + $max_cols = 0; + } + + unset($tempRow); + unset($tempRows); + unset($col_names); + unset($sheets); + unset($xml); + + /** + * Bring accumulated rows into the corresponding table + */ + $num_tbls = count($tables); + for ($i = 0; $i < $num_tbls; ++$i) { + for ($j = 0; $j < count($rows); ++$j) { + if (! strcmp($tables[$i][TBL_NAME], $rows[$j][TBL_NAME])) { + if (! isset($tables[$i][COL_NAMES])) { + $tables[$i][] = $rows[$j][COL_NAMES]; + } + + $tables[$i][ROWS] = $rows[$j][ROWS]; + } + } + } + + /* No longer needed */ + unset($rows); + + /* Obtain the best-fit MySQL types for each column */ + $analyses = array(); + + $len = count($tables); + for ($i = 0; $i < $len; ++$i) { + $analyses[] = PMA_analyzeTable($tables[$i]); + } + + /** + * string $db_name (no backquotes) + * + * array $table = array(table_name, array() column_names, array()() rows) + * array $tables = array of "$table"s + * + * array $analysis = array(array() column_types, array() column_sizes) + * array $analyses = array of "$analysis"s + * + * array $create = array of SQL strings + * + * array $options = an associative array of options + */ + + /* Set database name to the currently selected one, if applicable */ + if (strlen($db)) { + $db_name = $db; + $options = array('create_db' => false); + } else { + $db_name = 'ODS_DB'; + $options = null; + } + + /* Non-applicable parameters */ + $create = null; + + /* Created and execute necessary SQL statements from data */ + PMA_buildSQL($db_name, $tables, $analyses, $create, $options); + + unset($tables); + unset($analyses); + + /* Commit any possible data in buffers */ + PMA_importRunQuery(); + } +} diff --git a/phpmyadmin/libraries/plugins/import/ImportShp.class.php b/phpmyadmin/libraries/plugins/import/ImportShp.class.php new file mode 100644 index 000000000..39af95403 --- /dev/null +++ b/phpmyadmin/libraries/plugins/import/ImportShp.class.php @@ -0,0 +1,342 @@ +setProperties(); + } + + /** + * Sets the import plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText(__('ESRI Shape File')); + $importPluginProperties->setExtension('shp'); + $importPluginProperties->setOptions(array()); + $importPluginProperties->setOptionsText(__('Options')); + + $this->properties = $importPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + global $db, $error, $finished, $compression, + $import_file, $local_import_file; + + if ((int) ini_get('memory_limit') < 512) { + @ini_set('memory_limit', '512M'); + } + @set_time_limit(300); + + $GLOBALS['finished'] = false; + $buffer = ''; + $eof = false; + + + $shp = new PMA_ShapeFile(1); + // If the zip archive has more than one file, + // get the correct content to the buffer from .shp file. + if ($compression == 'application/zip' + && PMA_getNoOfFilesInZip($import_file) > 1 + ) { + $zip_content = PMA_getZipContents($import_file, '/^.*\.shp$/i'); + $GLOBALS['import_text'] = $zip_content['data']; + } + + $temp_dbf_file = false; + // We need dbase extension to handle .dbf file + if (extension_loaded('dbase')) { + // If we can extract the zip archive to 'TempDir' + // and use the files in it for import + if ($compression == 'application/zip' + && ! empty($GLOBALS['cfg']['TempDir']) + && is_writable($GLOBALS['cfg']['TempDir']) + ) { + $dbf_file_name = PMA_findFileFromZipArchive( + '/^.*\.dbf$/i', $import_file + ); + // If the corresponding .dbf file is in the zip archive + if ($dbf_file_name) { + // Extract the .dbf file and point to it. + $extracted = PMA_zipExtract( + $import_file, + realpath($GLOBALS['cfg']['TempDir']), + array($dbf_file_name) + ); + if ($extracted) { + $dbf_file_path = realpath($GLOBALS['cfg']['TempDir']) + . (PMA_IS_WINDOWS ? '\\' : '/') . $dbf_file_name; + $temp_dbf_file = true; + // Replace the .dbf with .*, as required + // by the bsShapeFiles library. + $file_name = substr( + $dbf_file_path, 0, strlen($dbf_file_path) - 4 + ) . '.*'; + $shp->FileName = $file_name; + } + } + } elseif (! empty($local_import_file) + && ! empty($GLOBALS['cfg']['UploadDir']) + && $compression == 'none' + ) { + // If file is in UploadDir, use .dbf file in the same UploadDir + // to load extra data. + // Replace the .shp with .*, + // so the bsShapeFiles library correctly locates .dbf file. + $file_name = substr($import_file, 0, strlen($import_file) - 4) + . '.*'; + $shp->FileName = $file_name; + } + } + + // Load data + $shp->loadFromFile(''); + if ($shp->lastError != "") { + $error = true; + $message = PMA_Message::error( + __('There was an error importing the ESRI shape file: "%s".') + ); + $message->addParam($shp->lastError); + return; + } + + // Delete the .dbf file extracted to 'TempDir' + if ($temp_dbf_file + && isset($dbf_file_path) + && file_exists($dbf_file_path) + ) { + unlink($dbf_file_path); + } + + $esri_types = array( + 0 => 'Null Shape', + 1 => 'Point', + 3 => 'PolyLine', + 5 => 'Polygon', + 8 => 'MultiPoint', + 11 => 'PointZ', + 13 => 'PolyLineZ', + 15 => 'PolygonZ', + 18 => 'MultiPointZ', + 21 => 'PointM', + 23 => 'PolyLineM', + 25 => 'PolygonM', + 28 => 'MultiPointM', + 31 => 'MultiPatch', + ); + + switch ($shp->shapeType) { + // ESRI Null Shape + case 0: + break; + // ESRI Point + case 1: + $gis_type = 'point'; + break; + // ESRI PolyLine + case 3: + $gis_type = 'multilinestring'; + break; + // ESRI Polygon + case 5: + $gis_type = 'multipolygon'; + break; + // ESRI MultiPoint + case 8: + $gis_type = 'multipoint'; + break; + default: + $error = true; + if (! isset($esri_types[$shp->shapeType])) { + $message = PMA_Message::error( + __( + 'You tried to import an invalid file or the imported file' + . ' contains invalid data' + ) + ); + } else { + $message = PMA_Message::error( + __('MySQL Spatial Extension does not support ESRI type "%s".') + ); + $message->addParam($param); + } + return; + } + + if (isset($gis_type)) { + include_once './libraries/gis/pma_gis_factory.php'; + $gis_obj = PMA_GIS_Factory::factory($gis_type); + } else { + $gis_obj = null; + } + + $num_rows = count($shp->records); + // If .dbf file is loaded, the number of extra data columns + $num_data_cols = isset($shp->DBFHeader) ? count($shp->DBFHeader) : 0; + + $rows = array(); + $col_names = array(); + if ($num_rows != 0) { + foreach ($shp->records as $record) { + $tempRow = array(); + if ($gis_obj == null) { + $tempRow[] = null; + } else { + $tempRow[] = "GeomFromText('" + . $gis_obj->getShape($record->SHPData) . "')"; + } + + if (isset($shp->DBFHeader)) { + foreach ($shp->DBFHeader as $c) { + $cell = trim($record->DBFData[$c[0]]); + + if (! strcmp($cell, '')) { + $cell = 'NULL'; + } + + $tempRow[] = $cell; + } + } + $rows[] = $tempRow; + } + } + + if (count($rows) == 0) { + $error = true; + $message = PMA_Message::error( + __('The imported file does not contain any data') + ); + return; + } + + // Column names for spatial column and the rest of the columns, + // if they are available + $col_names[] = 'SPATIAL'; + for ($n = 0; $n < $num_data_cols; $n++) { + $col_names[] = $shp->DBFHeader[$n][0]; + } + + // Set table name based on the number of tables + if (strlen($db)) { + $result = PMA_DBI_fetch_result('SHOW TABLES'); + $table_name = 'TABLE '.(count($result) + 1); + } else { + $table_name = 'TBL_NAME'; + } + $tables = array(array($table_name, $col_names, $rows)); + + // Use data from shape file to chose best-fit MySQL types for each column + $analyses = array(); + $analyses[] = PMA_analyzeTable($tables[0]); + + $table_no = 0; $spatial_col = 0; + $analyses[$table_no][TYPES][$spatial_col] = GEOMETRY; + $analyses[$table_no][FORMATTEDSQL][$spatial_col] = true; + + // Set database name to the currently selected one, if applicable + if (strlen($db)) { + $db_name = $db; + $options = array('create_db' => false); + } else { + $db_name = 'SHP_DB'; + $options = null; + } + + // Created and execute necessary SQL statements from data + $null_param = null; + PMA_buildSQL($db_name, $tables, $analyses, $null_param, $options); + + unset($tables); + unset($analyses); + + $finished = true; + $error = false; + + // Commit any possible data in buffers + PMA_importRunQuery(); + } + + /** + * Returns specified number of bytes from the buffer. + * Buffer automatically fetches next chunk of data when the buffer + * falls short. + * Sets $eof when $GLOBALS['finished'] is set and the buffer falls short. + * + * @param int $length number of bytes + * + * @return string + */ + public static function readFromBuffer($length) + { + global $buffer, $eof; + + if (strlen($buffer) < $length) { + if ($GLOBALS['finished']) { + $eof = true; + } else { + $buffer .= PMA_importGetNextChunk(); + } + } + $result = substr($buffer, 0, $length); + $buffer = substr($buffer, $length); + return $result; + } +} \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/import/ImportSql.class.php b/phpmyadmin/libraries/plugins/import/ImportSql.class.php new file mode 100644 index 000000000..146485a23 --- /dev/null +++ b/phpmyadmin/libraries/plugins/import/ImportSql.class.php @@ -0,0 +1,440 @@ +setProperties(); + } + + /** + * Sets the import plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/SelectPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText('SQL'); + $importPluginProperties->setExtension('sql'); + $importPluginProperties->setOptionsText(__('Options')); + + $compats = PMA_DBI_getCompatibilities(); + if (count($compats) > 0) { + $values = array(); + foreach ($compats as $val) { + $values[$val] = $val; + } + + // create the root group that will be the options field for + // $importPluginProperties + // this will be shown as "Format specific options" + $importSpecificOptions = new OptionsPropertyRootGroup(); + $importSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new SelectPropertyItem(); + $leaf->setName("compatibility"); + $leaf->setText(__('SQL compatibility mode:')); + $leaf->setValues($values); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'Server_SQL_mode', + ) + ); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("no_auto_value_on_zero"); + $leaf->setText( + __('Do not use 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) { + PMA_DBI_try_query('SET SQL_MODE="' . implode(',', $sql_modes) . '"'); + } + unset($sql_modes); + + /** + * will be set in PMA_importGetNextChunk() + * + * @global boolean $GLOBALS['finished'] + */ + $GLOBALS['finished'] = false; + + while (! ($GLOBALS['finished'] && $i >= $len) + && ! $error + && ! $timeout_passed + ) { + $data = PMA_importGetNextChunk(); + if ($data === false) { + // subtract data we didn't handle yet and stop processing + $offset -= strlen($buffer); + break; + } elseif ($data === true) { + // Handle rest of buffer + } else { + // Append new data to buffer + $buffer .= $data; + // free memory + unset($data); + // Do not parse string when we're not at the end + // and don't have ; inside + if ((strpos($buffer, $sql_delimiter, $i) === false) + && ! $GLOBALS['finished'] + ) { + continue; + } + } + // Current length of our buffer + $len = strlen($buffer); + + // Grab some SQL queries out of it + while ($i < $len) { + $found_delimiter = false; + // Find first interesting character + $old_i = $i; + // this is about 7 times faster that looking for each sequence i + // one by one with strpos() + $match = preg_match( + '/(\'|"|#|-- |\/\*|`|(?i)(? unclosed quote, + // but we handle it as end of query + if ($GLOBALS['finished']) { + $endq = true; + $i = $len - 1; + } + $found_delimiter = false; + break; + } + // Was not the quote escaped? + $j = $pos - 1; + while ($buffer[$j] == '\\') { + $j--; + } + // Even count means it was not escaped + $endq = (((($pos - 1) - $j) % 2) == 0); + // Skip the string + $i = $pos; + + if ($first_sql_delimiter < $pos) { + $found_delimiter = false; + } + } + if (! $endq) { + break; + } + $i++; + // Aren't we at the end? + if ($GLOBALS['finished'] && $i == $len) { + $i--; + } else { + continue; + } + } + + // Not enough data to decide + if ((($i == ($len - 1) && ($ch == '-' || $ch == '/')) + || ($i == ($len - 2) && (($ch == '-' && $buffer[$i + 1] == '-') + || ($ch == '/' && $buffer[$i + 1] == '*')))) + && ! $GLOBALS['finished'] + ) { + break; + } + + // Comments + if ($ch == '#' + || ($i < ($len - 1) && $ch == '-' && $buffer[$i + 1] == '-' + && (($i < ($len - 2) && $buffer[$i + 2] <= ' ') + || ($i == ($len - 1) && $GLOBALS['finished']))) + || ($i < ($len - 1) && $ch == '/' && $buffer[$i + 1] == '*') + ) { + // Copy current string to SQL + if ($start_pos != $i) { + $sql .= substr($buffer, $start_pos, $i - $start_pos); + } + // Skip the rest + $start_of_comment = $i; + // do not use PHP_EOL here instead of "\n", because the export + // file might have been produced on a different system + $i = strpos($buffer, $ch == '/' ? '*/' : "\n", $i); + // didn't we hit end of string? + if ($i === false) { + if ($GLOBALS['finished']) { + $i = $len - 1; + } else { + break; + } + } + // Skip * + if ($ch == '/') { + $i++; + } + // Skip last char + $i++; + // We need to send the comment part in case we are defining + // a procedure or function and comments in it are valuable + $sql .= substr( + $buffer, + $start_of_comment, + $i - $start_of_comment + ); + // Next query part will start here + $start_pos = $i; + // Aren't we at the end? + if ($i == $len) { + $i--; + } else { + continue; + } + } + // Change delimiter, if redefined, and skip it + // (don't send to server!) + if (($i + $length_of_delimiter_keyword < $len) + && strtoupper( + substr($buffer, $i, $length_of_delimiter_keyword) + ) == $delimiter_keyword + ) { + // look for EOL on the character immediately after 'DELIMITER ' + // (see previous comment about PHP_EOL) + $new_line_pos = strpos( + $buffer, + "\n", + $i + $length_of_delimiter_keyword + ); + // it might happen that there is no EOL + if (false === $new_line_pos) { + $new_line_pos = $len; + } + $sql_delimiter = substr( + $buffer, + $i + $length_of_delimiter_keyword, + $new_line_pos - $i - $length_of_delimiter_keyword + ); + $i = $new_line_pos + 1; + // Next query part will start here + $start_pos = $i; + continue; + } + + // End of SQL + if ($found_delimiter + || ($GLOBALS['finished'] + && ($i == $len - 1)) + ) { + $tmp_sql = $sql; + if ($start_pos < $len) { + $length_to_grab = $i - $start_pos; + + if (! $found_delimiter) { + $length_to_grab++; + } + $tmp_sql .= substr($buffer, $start_pos, $length_to_grab); + unset($length_to_grab); + } + // Do not try to execute empty SQL + if (! preg_match('/^([\s]*;)*$/', trim($tmp_sql))) { + $sql = $tmp_sql; + PMA_importRunQuery( + $sql, + substr($buffer, 0, $i + strlen($sql_delimiter)), + false, + $sql_data + ); + $buffer = substr($buffer, $i + strlen($sql_delimiter)); + // Reset parser: + $len = strlen($buffer); + $sql = ''; + $i = 0; + $start_pos = 0; + // Any chance we will get a complete query? + //if ((strpos($buffer, ';') === false) + //&& ! $GLOBALS['finished']) { + if (strpos($buffer, $sql_delimiter) === false + && ! $GLOBALS['finished'] + ) { + break; + } + } else { + $i++; + $start_pos = $i; + } + } + } // End of parser loop + } // End of import loop + // Commit any possible data in buffers + PMA_importRunQuery('', substr($buffer, 0, $len), false, $sql_data); + PMA_importRunQuery('', '', false, $sql_data); + } +} \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/import/ImportXml.class.php b/phpmyadmin/libraries/plugins/import/ImportXml.class.php new file mode 100644 index 000000000..9c0e99959 --- /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 */ + $offset -= strlen($buffer); + break; + } elseif ($data === true) { + /* Handle rest of buffer */ + } else { + /* Append new data to buffer */ + $buffer .= $data; + unset($data); + } + } + + unset($data); + + /** + * Disable loading of external XML entities. + */ + libxml_disable_entity_loader(); + + /** + * Load the XML string + * + * The option LIBXML_COMPACT is specified because it can + * result in increased performance without the need to + * alter the code in any way. It's basically a freebee. + */ + $xml = simplexml_load_string($buffer, "SimpleXMLElement", LIBXML_COMPACT); + + unset($buffer); + + /** + * The XML was malformed + */ + if ($xml === false) { + PMA_Message::error( + __( + 'The XML file specified was either malformed or incomplete.' + . ' Please correct the issue and try again.' + ) + )->display(); + unset($xml); + $GLOBALS['finished'] = false; + return; + } + + /** + * Table accumulator + */ + $tables = array(); + /** + * Row accumulator + */ + $rows = array(); + + /** + * Temp arrays + */ + $tempRow = array(); + $tempCells = array(); + + /** + * CREATE code included (by default: no) + */ + $struct_present = false; + + /** + * Analyze the data in each table + */ + $namespaces = $xml->getNameSpaces(true); + + /** + * Get the database name, collation and charset + */ + $db_attr = $xml->children($namespaces['pma']) + ->{'structure_schemas'}->{'database'}; + + if ($db_attr instanceof SimpleXMLElement) { + $db_attr = $db_attr->attributes(); + $db_name = (string)$db_attr['name']; + $collation = (string)$db_attr['collation']; + $charset = (string)$db_attr['charset']; + } else { + /** + * If the structure section is not present + * get the database name from the data section + */ + $db_attr = $xml->children()->attributes(); + $db_name = (string)$db_attr['name']; + $collation = null; + $charset = null; + } + + /** + * The XML was malformed + */ + if ($db_name === null) { + PMA_Message::error( + __( + 'The XML file specified was either malformed or incomplete.' + . ' Please correct the issue and try again.' + ) + )->display(); + unset($xml); + $GLOBALS['finished'] = false; + return; + } + + /** + * Retrieve the structure information + */ + if (isset($namespaces['pma'])) { + /** + * Get structures for all tables + */ + $struct = $xml->children($namespaces['pma']); + + $create = array(); + + foreach ($struct as $tier1 => $val1) { + foreach ($val1 as $tier2 => $val2) { + // Need to select the correct database for the creation of + // tables, views, triggers, etc. + /** + * @todo Generating a USE here blocks importing of a table + * into another database. + */ + $attrs = $val2->attributes(); + $create[] = "USE " + . PMA_Util::backquote( + $attrs["name"] + ); + + foreach ($val2 as $val3) { + /** + * Remove the extra cosmetic spacing + */ + $val3 = str_replace(" ", "", (string)$val3); + $create[] = $val3; + } + } + } + + $struct_present = true; + } + + /** + * Move down the XML tree to the actual data + */ + $xml = $xml->children()->children(); + + $data_present = false; + + /** + * Only attempt to analyze/collect data if there is data present + */ + if ($xml && @count($xml->children())) { + $data_present = true; + + /** + * Process all database content + */ + foreach ($xml as $k1 => $v1) { + $tbl_attr = $v1->attributes(); + + $isInTables = false; + for ($i = 0; $i < count($tables); ++$i) { + if (! strcmp($tables[$i][TBL_NAME], (string)$tbl_attr['name'])) { + $isInTables = true; + break; + } + } + + if ($isInTables == false) { + $tables[] = array((string)$tbl_attr['name']); + } + + foreach ($v1 as $k2 => $v2) { + $row_attr = $v2->attributes(); + if (! array_search((string)$row_attr['name'], $tempRow)) { + $tempRow[] = (string)$row_attr['name']; + } + $tempCells[] = (string)$v2; + } + + $rows[] = array((string)$tbl_attr['name'], $tempRow, $tempCells); + + $tempRow = array(); + $tempCells = array(); + } + + unset($tempRow); + unset($tempCells); + unset($xml); + + /** + * Bring accumulated rows into the corresponding table + */ + $num_tbls = count($tables); + for ($i = 0; $i < $num_tbls; ++$i) { + for ($j = 0; $j < count($rows); ++$j) { + if (! strcmp($tables[$i][TBL_NAME], $rows[$j][TBL_NAME])) { + if (! isset($tables[$i][COL_NAMES])) { + $tables[$i][] = $rows[$j][COL_NAMES]; + } + + $tables[$i][ROWS][] = $rows[$j][ROWS]; + } + } + } + + unset($rows); + + if (! $struct_present) { + $analyses = array(); + + $len = count($tables); + for ($i = 0; $i < $len; ++$i) { + $analyses[] = PMA_analyzeTable($tables[$i]); + } + } + } + + unset($xml); + unset($tempRows); + unset($tempCells); + unset($rows); + + /** + * Only build SQL from data if there is data present + */ + if ($data_present) { + /** + * Set values to NULL if they were not present + * to maintain PMA_buildSQL() call integrity + */ + if (! isset($analyses)) { + $analyses = null; + if (! $struct_present) { + $create = null; + } + } + } + + /** + * string $db_name (no backquotes) + * + * array $table = array(table_name, array() column_names, array()() rows) + * array $tables = array of "$table"s + * + * array $analysis = array(array() column_types, array() column_sizes) + * array $analyses = array of "$analysis"s + * + * array $create = array of SQL strings + * + * array $options = an associative array of options + */ + + /* Set database name to the currently selected one, if applicable */ + if (strlen($db)) { + /* Override the database name in the XML file, if one is selected */ + $db_name = $db; + $options = array('create_db' => false); + } else { + if ($db_name === null) { + $db_name = 'XML_DB'; + } + + /* Set database collation/charset */ + $options = array( + 'db_collation' => $collation, + 'db_charset' => $charset, + ); + } + + /* Created and execute necessary SQL statements from data */ + PMA_buildSQL($db_name, $tables, $analyses, $create, $options); + + unset($analyses); + unset($tables); + unset($create); + + /* Commit any possible data in buffers */ + PMA_importRunQuery(); + } +} \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/import/README b/phpmyadmin/libraries/plugins/import/README new file mode 100644 index 000000000..76d2b07cc --- /dev/null +++ b/phpmyadmin/libraries/plugins/import/README @@ -0,0 +1,173 @@ +This directory holds import plugins for phpMyAdmin. Any new plugin should +basically follow the structure presented here. Official plugins need to +have str* messages with their definition in language files, but if you build +some plugins for your use, you can directly use texts in plugin. + +setProperties(); + } + + /** + * Sets the import plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + // set properties + $props = 'libraries/properties/'; + // include the main class for properties for the import plug-ins + include_once "$props/plugins/ImportPluginProperties.class.php"; + // include the group properties classes + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + // include the needed single property items + include_once "$props/options/items/RadioPropertyItem.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText('[name]'); // the name of your plug-in + $importPluginProperties->setExtension('[ext]'); // extension this plug-in can handle + $importPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $importPluginProperties + // this will be shown as "Format specific options" + $importSpecificOptions = new OptionsPropertyRootGroup(); + $importSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + + // optional : + // create primary items and add them to the group + // type - one of the classes listed in libraries/properties/options/items/ + // name - form element name + // text - description in GUI + // size - size of text element + // len - maximal size of input + // values - possible values of the item + $leaf = new RadioPropertyItem(); + $leaf->setName("structure_or_data"); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $generalOptions->addProperty($leaf); + + // add the main group to the root group + $importSpecificOptions->addProperty($generalOptions); + + // set the options for the import plugin property item + $importPluginProperties->setOptions($importSpecificOptions); + $this->properties = $importPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + // get globals (others are optional) + global $error, $timeout_passed, $finished; + + $buffer = ''; + while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { + $data = PMA_importGetNextChunk(); + if ($data === false) { + // subtract data we didn't handle yet and stop processing + $offset -= strlen($buffer); + break; + } elseif ($data === true) { + // Handle rest of buffer + } else { + // Append new data to buffer + $buffer .= $data; + } + // PARSE $buffer here, post sql queries using: + PMA_importRunQuery($sql, $verbose_sql_with_comments); + } // End of import loop + // Commit any possible data in buffers + PMA_importRunQuery(); + } + + + // optional: + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Getter description + * + * @return type + */ + private function _getMyOptionalVariable() + { + return $this->_myOptionalVariable; + } + + /** + * Setter description + * + * @param type $my_optional_variable description + * + * @return void + */ + private function _setMyOptionalVariable($my_optional_variable) + { + $this->_myOptionalVariable = $my_optional_variable; + } +} +?> \ No newline at end of file diff --git a/phpmyadmin/libraries/plugins/import/ShapeFile.class.php b/phpmyadmin/libraries/plugins/import/ShapeFile.class.php new file mode 100644 index 000000000..121bf124d --- /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 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 000000000..efefd0c80 --- /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 void + * @see ShapeRecord::_loadPoint() + */ + function _loadPoint() + { + $data = array(); + + $data["x"] = loadData("d", ImportShp::readFromBuffer(8)); + $data["y"] = loadData("d", ImportShp::readFromBuffer(8)); + + return $data; + } + + /** + * Loads data from a multipoint record + * + * @return void + * @see ShapeRecord::_loadMultiPointRecord() + */ + function _loadMultiPointRecord() + { + $this->SHPData = array(); + $this->SHPData["xmin"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->SHPData["ymin"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->SHPData["xmax"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->SHPData["ymax"] = loadData("d", ImportShp::readFromBuffer(8)); + + $this->SHPData["numpoints"] = loadData("V", ImportShp::readFromBuffer(4)); + + for ($i = 0; $i <= $this->SHPData["numpoints"]; $i++) { + $this->SHPData["points"][] = $this->_loadPoint(); + } + } + + /** + * Loads data from a polyline record + * + * @return void + * @see ShapeRecord::_loadPolyLineRecord() + */ + function _loadPolyLineRecord() + { + $this->SHPData = array(); + $this->SHPData["xmin"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->SHPData["ymin"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->SHPData["xmax"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->SHPData["ymax"] = loadData("d", ImportShp::readFromBuffer(8)); + + $this->SHPData["numparts"] = loadData("V", ImportShp::readFromBuffer(4)); + $this->SHPData["numpoints"] = loadData("V", ImportShp::readFromBuffer(4)); + + for ($i = 0; $i < $this->SHPData["numparts"]; $i++) { + $this->SHPData["parts"][$i] = loadData( + "V", ImportShp::readFromBuffer(4) + ); + } + + $readPoints = 0; + reset($this->SHPData["parts"]); + while (list($partIndex, $partData) = each($this->SHPData["parts"])) { + if (! isset($this->SHPData["parts"][$partIndex]["points"]) + || !is_array($this->SHPData["parts"][$partIndex]["points"]) + ) { + $this->SHPData["parts"][$partIndex] = array(); + $this->SHPData["parts"][$partIndex]["points"] = array(); + } + while (! in_array($readPoints, $this->SHPData["parts"]) + && ($readPoints < ($this->SHPData["numpoints"])) + ) { + $this->SHPData["parts"][$partIndex]["points"][] + = $this->_loadPoint(); + $readPoints++; + } + } + } +} +?> diff --git a/phpmyadmin/libraries/plugins/import/upload/UploadApc.class.php b/phpmyadmin/libraries/plugins/import/upload/UploadApc.class.php new file mode 100644 index 000000000..881832fda --- /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 000000000..90148ded4 --- /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 000000000..1a507763d --- /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 000000000..36404133e --- /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 000000000..46bda7045 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Application_Octetstream_Download.class.php @@ -0,0 +1,64 @@ + 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 000000000..f876abbe3 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Application_Octetstream_Hex.class.php @@ -0,0 +1,65 @@ + 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 000000000..934df75ea --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Image_JPEG_Inline.class.php @@ -0,0 +1,65 @@ + 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 000000000..fc04040f2 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Image_JPEG_Link.class.php @@ -0,0 +1,65 @@ + 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 000000000..e879c2374 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Image_PNG_Inline.class.php @@ -0,0 +1,65 @@ + diff --git a/phpmyadmin/libraries/plugins/transformations/README b/phpmyadmin/libraries/plugins/transformations/README new file mode 100644 index 000000000..7d7a1255d --- /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 000000000..b0ce2f045 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/TEMPLATE @@ -0,0 +1,68 @@ + diff --git a/phpmyadmin/libraries/plugins/transformations/TEMPLATE_ABSTRACT b/phpmyadmin/libraries/plugins/transformations/TEMPLATE_ABSTRACT new file mode 100644 index 000000000..5cc1d26bd --- /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 000000000..8a102cbfd --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Text_Plain_Append.class.php @@ -0,0 +1,66 @@ + 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 000000000..ed8c9e561 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Text_Plain_Dateformat.class.php @@ -0,0 +1,65 @@ + 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 000000000..1aa321a51 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Text_Plain_External.class.php @@ -0,0 +1,65 @@ + 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 000000000..5c6b683e7 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Text_Plain_Formatted.class.php @@ -0,0 +1,65 @@ + 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 000000000..4cb180072 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Text_Plain_Imagelink.class.php @@ -0,0 +1,65 @@ + 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 000000000..1e642039b --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Text_Plain_Link.class.php @@ -0,0 +1,65 @@ + 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 000000000..44eea5070 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Text_Plain_Longtoipv4.class.php @@ -0,0 +1,65 @@ + 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 000000000..cc9249142 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Text_Plain_Sql.class.php @@ -0,0 +1,65 @@ + 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 000000000..b04231ff2 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/Text_Plain_Substring.class.php @@ -0,0 +1,65 @@ + 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 000000000..0fc3b4de7 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/abstract/AppendTransformationsPlugin.class.php @@ -0,0 +1,86 @@ + \ No newline at end of file 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 000000000..530379f10 --- /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 000000000..82eda40f7 --- /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 000000000..f93f0695a --- /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 000000000..e6bb8d9ba --- /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 000000000..8022da9e0 --- /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 000000000..456f102bd --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/abstract/ImageLinkTransformationsPlugin.class.php @@ -0,0 +1,89 @@ + '[BLOB]' + ); + $buffer = PMA_transformation_global_html_replace( + $buffer, + $transform_options + ); + + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Link"; + } +} +?> diff --git a/phpmyadmin/libraries/plugins/transformations/abstract/InlineTransformationsPlugin.class.php b/phpmyadmin/libraries/plugins/transformations/abstract/InlineTransformationsPlugin.class.php new file mode 100644 index 000000000..b1ef0ae45 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/abstract/InlineTransformationsPlugin.class.php @@ -0,0 +1,103 @@ + '[__BUFFER__]' + ); + } else { + $transform_options = array ( + 'string' => '[__BUFFER__]' + ); + } + $buffer = PMA_transformation_global_html_replace( + $buffer, + $transform_options + ); + + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Inline"; + } +} +?> diff --git a/phpmyadmin/libraries/plugins/transformations/abstract/LongToIPv4TransformationsPlugin.class.php b/phpmyadmin/libraries/plugins/transformations/abstract/LongToIPv4TransformationsPlugin.class.php new file mode 100644 index 000000000..58dda957e --- /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 000000000..2123cdb3d --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/abstract/SQLTransformationsPlugin.class.php @@ -0,0 +1,81 @@ + \ No newline at end of file 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 000000000..2de48e6bb --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/abstract/SubstringTransformationsPlugin.class.php @@ -0,0 +1,116 @@ + \ No newline at end of file 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 000000000..054b2f9b8 --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/abstract/TextImageLinkTransformationsPlugin.class.php @@ -0,0 +1,96 @@ + '' + . $buffer . '' + ); + + $buffer = PMA_transformation_global_html_replace( + $buffer, + $transform_options + ); + + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Image Link"; + } +} +?> diff --git a/phpmyadmin/libraries/plugins/transformations/abstract/TextLinkTransformationsPlugin.class.php b/phpmyadmin/libraries/plugins/transformations/abstract/TextLinkTransformationsPlugin.class.php new file mode 100644 index 000000000..fdc33b29b --- /dev/null +++ b/phpmyadmin/libraries/plugins/transformations/abstract/TextLinkTransformationsPlugin.class.php @@ -0,0 +1,98 @@ + '' . (isset($options[1]) ? $options[1] : $buffer) + . '' + ); + + $buffer = PMA_transformation_global_html_replace( + $buffer, + $transform_options + ); + + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Link"; + } +} +?> diff --git a/phpmyadmin/libraries/plugins/transformations/generator_main_class.sh b/phpmyadmin/libraries/plugins/transformations/generator_main_class.sh new file mode 100755 index 000000000..05876671a --- /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 000000000..225a2cb98 --- /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 new file mode 100644 index 000000000..5bf7c58bb --- /dev/null +++ b/phpmyadmin/libraries/pmd_common.php @@ -0,0 +1,262 @@ + internal ".$GLOBALS['db']." - ".$val[0]." - "; + //print_r($row); + if ($row !== false) { + foreach ($row as $field => $value) { + $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['SCN'][$i] = urlencode($value['foreign_field']); + $i++; + } + } + $row = PMA_getForeigners($GLOBALS['db'], $val[0], '', 'foreign'); + //echo "
      INNO "; + //print_r($row); + if ($row !== false) { + foreach ($row as $field => $value) { + $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['SCN'][$i] = urlencode($value['foreign_field']); + $i++; + } + } + } + + $ti = 0; + $retval = array(); + for ($i = 0, $cnt = count($con["C_NAME"]); $i < $cnt; $i++) { + $c_name_i = $con['C_NAME'][$i]; + $dtn_i = $con['DTN'][$i]; + $retval[$ti] = array(); + $retval[$ti][$c_name_i] = array(); + if (in_array($dtn_i, $GLOBALS['PMD_URL']["TABLE_NAME"]) + && in_array($con['STN'][$i], $GLOBALS['PMD_URL']["TABLE_NAME"]) + ) { + $retval[$ti][$c_name_i][$dtn_i] = array(); + $retval[$ti][$c_name_i][$dtn_i][$con['DCN'][$i]] = array( + 0 => $con['STN'][$i], + 1 => $con['SCN'][$i] + ); + } + $ti++; + } + return $retval; +} + +/** + * Returns UNIQUE and PRIMARY indices + * + * @return array unique or primary indices + */ +function get_pk_or_unique_keys() +{ + return get_all_keys(true); +} + +/** + * returns all indices + * + * @param bool $unique_only whether to include only unique ones + * + * @return array indices + */ +function get_all_keys($unique_only = false) +{ + include_once './libraries/Index.class.php'; + + $keys = array(); + + foreach ($GLOBALS['PMD']['TABLE_NAME_SMALL'] as $I => $table) { + $schema = $GLOBALS['PMD']['OWNER'][$I]; + // for now, take into account only the first index segment + foreach (PMA_Index::getFromTable($table, $schema) as $index) { + if ($unique_only && ! $index->isUnique()) { + continue; + } + $columns = $index->getColumns(); + foreach ($columns as $column_name => $dummy) { + $keys[$schema . '.' .$table . '.' . $column_name] = 1; + } + } + } + return $keys; +} + +/** + * Return script to create j_tab and h_tab arrays + * + * @return string + */ +function get_script_tabs() +{ + $script_tabs = 'var j_tabs = new Array();' . "\n" + . 'var h_tabs = new Array();' . "\n" ; + + $retval = array( + 'j_tabs' => array(), + 'h_tabs' => array() + ); + + for ($i = 0, $cnt = count($GLOBALS['PMD']['TABLE_NAME']); $i < $cnt; $i++) { + $j = 0; + if (PMA_Util::isForeignKeySupported($GLOBALS['PMD']['TABLE_TYPE'][$i])) { + $j = 1; + } + $retval['j_tabs'][$GLOBALS['PMD_URL']['TABLE_NAME'][$i]] = $j; + $retval['h_tabs'][$GLOBALS['PMD_URL']['TABLE_NAME'][$i]] = 1; + } + return $retval; +} + +/** + * Returns table position + * + * @return array table positions and sizes + */ +function get_tab_pos() +{ + $cfgRelation = PMA_getRelationsParam(); + + if (! $cfgRelation['designerwork']) { + return null; + } + + $query = " + SELECT CONCAT_WS('.', `db_name`, `table_name`) AS `name`, + `x` AS `X`, + `y` AS `Y`, + `v` AS `V`, + `h` AS `H` + FROM " . PMA_Util::backquote($cfgRelation['db']) + . "." . PMA_Util::backquote($cfgRelation['designer_coords']); + $tab_pos = PMA_DBI_fetch_result( + $query, 'name', null, $GLOBALS['controllink'], PMA_DBI_QUERY_STORE + ); + return count($tab_pos) ? $tab_pos : null; +} +?> diff --git a/phpmyadmin/libraries/properties/PropertyItem.class.php b/phpmyadmin/libraries/properties/PropertyItem.class.php new file mode 100644 index 000000000..21d50682c --- /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 000000000..ebff9b321 --- /dev/null +++ b/phpmyadmin/libraries/properties/options/OptionsPropertyGroup.class.php @@ -0,0 +1,104 @@ +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), + // for PHP 5.2 compability + create_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 000000000..a1718a2fc --- /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 000000000..e19c15cd4 --- /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 000000000..4e69aa7ac --- /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 000000000..a081744fa --- /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 000000000..0eeb52437 --- /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 000000000..f33067fcd --- /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 000000000..55aff6147 --- /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 000000000..53bfe465a --- /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 000000000..98f2e709f --- /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/RadioPropertyItem.class.php b/phpmyadmin/libraries/properties/options/items/RadioPropertyItem.class.php new file mode 100644 index 000000000..4d8ed7a21 --- /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 000000000..28460c95a --- /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 000000000..9339cdf07 --- /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 000000000..617089718 --- /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 000000000..65c3092cf --- /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 000000000..af46be225 --- /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 new file mode 100644 index 000000000..efa02110c --- /dev/null +++ b/phpmyadmin/libraries/relation.lib.php @@ -0,0 +1,1396 @@ +' + . __('not OK') + . '' + . ' [ ' + . __('Documentation') + . ' ]'; + + $messages['ok'] = '' + . _pgettext('Correctly working', 'OK') + . ''; + + $messages['enabled'] = '' . __('Enabled') . ''; + $messages['disabled'] = '' . __('Disabled') . ''; + + if (false === $GLOBALS['cfg']['Server']['pmadb']) { + $retval .= 'PMA Database ... ' + . sprintf($messages['error'], 'pmadb') + . '
      ' . "\n" + . __('General relation features') + . ' ' . __('Disabled') + . '' . "\n"; + } else { + $retval .= '' . "\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 .= '
      '; + $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 .= '
      '; + } + + return $retval; +} + +/** + * prints out one diagnostic message for a feature + * + * @param string $feature_name feature name in a message string + * @param string $relation_parameter the $GLOBALS['cfgRelation'] parameter to check + * @param array $messages utility messages + * @param boolean $skip_line whether to skip a line after the message + * + * @return string + */ +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) { + $retval .= ' '; + } + return $retval; +} + +/** + * prints out one diagnostic message for a configuration parameter + * + * @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 + * + * @return void + */ +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; +} + + +/** + * Defines the relation parameters for the current user + * just a copy of the functions used for relations ;-) + * but added some stuff to check what will work + * + * @access protected + * @return array the relation parameters for the current user + */ +function PMA__getRelationsParam() +{ + $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']) + ) { + // No server selected -> no bookmark table + // we return the array with the falses in it, + // to avoid some 'Unitialized string offset' errors later + $GLOBALS['cfg']['Server']['pmadb'] = false; + return $cfgRelation; + } + + + $cfgRelation['user'] = $GLOBALS['cfg']['Server']['user']; + $cfgRelation['db'] = $GLOBALS['cfg']['Server']['pmadb']; + + // Now I just check if all tables that i need are present so I can for + // example enable relations but not pdf... + // 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_Util::backquote( + $GLOBALS['cfg']['Server']['pmadb'] + ); + $tab_rs = PMA_queryAsControlUser($tab_query, false, PMA_DBI_QUERY_STORE); + + if (! $tab_rs) { + // query failed ... ? + //$GLOBALS['cfg']['Server']['pmadb'] = false; + return $cfgRelation; + } + + while ($curr_table = @PMA_DBI_fetch_row($tab_rs)) { + if ($curr_table[0] == $GLOBALS['cfg']['Server']['bookmarktable']) { + $cfgRelation['bookmark'] = $curr_table[0]; + } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['relation']) { + $cfgRelation['relation'] = $curr_table[0]; + } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['table_info']) { + $cfgRelation['table_info'] = $curr_table[0]; + } 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]; + } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['column_info']) { + $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]; + } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['recent']) { + $cfgRelation['recent'] = $curr_table[0]; + } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['table_uiprefs']) { + $cfgRelation['table_uiprefs'] = $curr_table[0]; + } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['tracking']) { + $cfgRelation['tracking'] = $curr_table[0]; + } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['userconfig']) { + $cfgRelation['userconfig'] = $curr_table[0]; + } + } // end while + PMA_DBI_free_result($tab_rs); + + if (isset($cfgRelation['relation'])) { + $cfgRelation['relwork'] = true; + if (isset($cfgRelation['table_info'])) { + $cfgRelation['displaywork'] = true; + } + } + + if (isset($cfgRelation['table_coords']) && isset($cfgRelation['pdf_pages'])) { + $cfgRelation['pdfwork'] = true; + } + + if (isset($cfgRelation['column_info'])) { + $cfgRelation['commwork'] = true; + $cfgRelation['mimework'] = true; + } + + if (isset($cfgRelation['history'])) { + $cfgRelation['historywork'] = true; + } + + if (isset($cfgRelation['recent'])) { + $cfgRelation['recentwork'] = true; + } + + if (isset($cfgRelation['table_uiprefs'])) { + $cfgRelation['uiprefswork'] = true; + } + + if (isset($cfgRelation['tracking'])) { + $cfgRelation['trackingwork'] = true; + } + + if (isset($cfgRelation['userconfig'])) { + $cfgRelation['userconfigwork'] = true; + } + + // we do not absolutely need that the internal relations or the PDF + // schema feature be activated + if (isset($cfgRelation['designer_coords'])) { + $cfgRelation['designerwork'] = true; + } + + if (isset($cfgRelation['bookmark'])) { + $cfgRelation['bookmarkwork'] = 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['allworks'] = true; + } + + return $cfgRelation; +} // end of the 'PMA_getRelationsParam()' function + +/** + * Gets all Relations to foreign tables for a given table or + * optionally a given column in a table + * + * @param string $db the name of the db to check for + * @param string $table the name of the table to check for + * @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 + * + * @access public + */ +function PMA_getForeigners($db, $table, $column = '', $source = 'both') +{ + $cfgRelation = PMA_getRelationsParam(); + $foreign = array(); + + if ($cfgRelation['relwork'] && ($source == 'both' || $source == 'internal')) { + $rel_query = ' + SELECT `master_field`, + `foreign_db`, + `foreign_table`, + `foreign_field` + 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_Util::sqlAddSlashes($column) . '\''; + } + $foreign = PMA_DBI_fetch_result($rel_query, 'master_field', null, $GLOBALS['controllink']); + } + + if (($source == 'both' || $source == 'foreign') && strlen($table)) { + + $show_create_table_query = 'SHOW CREATE TABLE ' + . PMA_Util::backquote($db) . '.' . PMA_Util::backquote($table); + $show_create_table = PMA_DBI_fetch_value($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) { + // The analyzer may return more than one column name in the + // index list or the ref_index_list; if this happens, + // the current logic just discards the whole index; having + // more than one index field is currently unsupported (see FAQ 3.6) + if (count($one_key['index_list']) == 1) { + foreach ($one_key['index_list'] as $i => $field) { + // If a foreign key is defined in the 'internal' source (pmadb) + // and as a native foreign key, we won't get it twice + // if $source='both' because we use $field as key + + // The parser looks for a CONSTRAINT clause just before + // the FOREIGN KEY clause. It finds it (as output from + // SHOW CREATE TABLE) in MySQL 4.0.13, but not in older + // versions like 3.23.58. + // In those cases, the FOREIGN KEY parsing will put numbers + // like -1, 0, 1... instead of the constraint number. + + if (isset($one_key['constraint'])) { + $foreign[$field]['constraint'] = $one_key['constraint']; + } + + if (isset($one_key['ref_db_name'])) { + $foreign[$field]['foreign_db'] = $one_key['ref_db_name']; + } else { + $foreign[$field]['foreign_db'] = $db; + } + $foreign[$field]['foreign_table'] = $one_key['ref_table_name']; + $foreign[$field]['foreign_field'] = $one_key['ref_index_list'][$i]; + if (isset($one_key['on_delete'])) { + $foreign[$field]['on_delete'] = $one_key['on_delete']; + } + if (isset($one_key['on_update'])) { + $foreign[$field]['on_update'] = $one_key['on_update']; + } + } + } + } + } + + /** + * Emulating relations for some information_schema and data_dictionary tables + */ + $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) { + $relations_key = 'information_schema_relations'; + include_once './libraries/information_schema_relations.lib.php'; + } else { + $relations_key = 'data_dictionary_relations'; + include_once './libraries/data_dictionary_relations.lib.php'; + } + if (isset($GLOBALS[$relations_key][$table])) { + foreach ($GLOBALS[$relations_key][$table] as $field => $relations) { + if ((! strlen($column) || $column == $field) + && (! isset($foreign[$field]) || ! strlen($foreign[$field])) + ) { + $foreign[$field] = $relations; + } + } + } + } + + return $foreign; +} // end of the 'PMA_getForeigners()' function + +/** + * Gets the display field of a table + * + * @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 + * + * @access public + */ +function PMA_getDisplayField($db, $table) +{ + $cfgRelation = PMA_getRelationsParam(); + + /** + * Try to fetch the display field from DB. + */ + if ($cfgRelation['displaywork']) { + $disp_query = ' + SELECT `display_field` + 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']); + if (isset($row['display_field'])) { + return $row['display_field']; + } + } + + /** + * Emulating the display field for some information_schema tables. + */ + if ($db == 'information_schema') { + switch ($table) { + case 'CHARACTER_SETS': + return 'DESCRIPTION'; + case 'TABLES': + return 'TABLE_COMMENT'; + } + } + + /** + * No Luck... + */ + return false; + +} // end of the 'PMA_getDisplayField()' function + +/** + * 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 [column_name] = comment + * + * @access public + */ +function PMA_getComments($db, $table = '') +{ + $comments = array(); + + if ($table != '') { + // MySQL native column comments + $columns = PMA_DBI_get_columns($db, $table, null, true); + if ($columns) { + foreach ($columns as $column) { + if (! empty($column['Comment'])) { + $comments[$column['Field']] = $column['Comment']; + } + } + } + } else { + $comments[] = PMA_getDbComment($db); + } + + return $comments; +} // end of the 'PMA_getComments()' function + +/** + * Gets the comment for a db + * + * @param string $db the name of the db to check for + * + * @return string comment + * + * @access public + */ +function PMA_getDbComment($db) +{ + $cfgRelation = PMA_getRelationsParam(); + $comment = ''; + + if ($cfgRelation['commwork']) { + // pmadb internal db comment + $com_qry = " + SELECT `comment` + 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_queryAsControlUser($com_qry, true, PMA_DBI_QUERY_STORE); + + if ($com_rs && PMA_DBI_num_rows($com_rs) > 0) { + $row = PMA_DBI_fetch_assoc($com_rs); + $comment = $row['comment']; + } + PMA_DBI_free_result($com_rs); + } + + return $comment; +} // end of the 'PMA_getDbComment()' function + +/** + * Gets the comment for a db + * + * @access public + * + * @return string comment + */ +function PMA_getDbComments() +{ + $cfgRelation = PMA_getRelationsParam(); + $comments = array(); + + if ($cfgRelation['commwork']) { + // pmadb internal db comment + $com_qry = " + SELECT `db_name`, `comment` + FROM " . PMA_Util::backquote($cfgRelation['db']) . "." . PMA_Util::backquote($cfgRelation['column_info']) . " + WHERE `column_name` = '(db_comment)'"; + $com_rs = PMA_queryAsControlUser($com_qry, true, PMA_DBI_QUERY_STORE); + + if ($com_rs && PMA_DBI_num_rows($com_rs) > 0) { + while ($row = PMA_DBI_fetch_assoc($com_rs)) { + $comments[$row['db_name']] = $row['comment']; + } + } + PMA_DBI_free_result($com_rs); + } + + return $comments; +} // end of the 'PMA_getDbComments()' function + +/** + * Set a database comment to a certain value. + * + * @param string $db the name of the db + * @param string $comment the value of the column + * + * @return boolean true, if comment-query was made. + * + * @access public + */ +function PMA_setDbComment($db, $comment = '') +{ + $cfgRelation = PMA_getRelationsParam(); + + if (! $cfgRelation['commwork']) { + return false; + } + + if (strlen($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_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_queryAsControlUser($upd_query); + } + + return false; +} // end of 'PMA_setDbComment()' function + +/** + * Set a SQL history entry + * + * @param string $db the name of the db + * @param string $table the name of the table + * @param string $username the username + * @param string $sqlquery the sql query + * + * @return void + * + * @access public + */ +function PMA_setHistory($db, $table, $username, $sqlquery) +{ + // Prevent to run this automatically on Footer class destroying in testsuite + if (defined('TESTSUITE') || strlen($sqlquery) > $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) { + return; + } + + $cfgRelation = PMA_getRelationsParam(); + + if (! isset($_SESSION['sql_history'])) { + $_SESSION['sql_history'] = array(); + } + + $key = md5($sqlquery . $db . $table); + + if (isset($_SESSION['sql_history'][$key])) { + unset($_SESSION['sql_history'][$key]); + } + + $_SESSION['sql_history'][$key] = array( + 'db' => $db, + 'table' => $table, + 'sqlquery' => $sqlquery, + ); + + if (count($_SESSION['sql_history']) > $GLOBALS['cfg']['QueryHistoryMax']) { + // history should not exceed a maximum count + array_shift($_SESSION['sql_history']); + } + + if (! $cfgRelation['historywork'] || ! $GLOBALS['cfg']['QueryHistoryDB']) { + return; + } + + PMA_queryAsControlUser( + 'INSERT INTO + ' . PMA_Util::backquote($cfgRelation['db']) . '.' . PMA_Util::backquote($cfgRelation['history']) . ' + (`username`, + `db`, + `table`, + `timevalue`, + `sqlquery`) + VALUES + (\'' . PMA_Util::sqlAddSlashes($username) . '\', + \'' . PMA_Util::sqlAddSlashes($db) . '\', + \'' . PMA_Util::sqlAddSlashes($table) . '\', + NOW(), + \'' . PMA_Util::sqlAddSlashes($sqlquery) . '\')' + ); +} // end of 'PMA_setHistory()' function + +/** + * Gets a SQL history entry + * + * @param string $username the username + * + * @return array list of history items + * + * @access public + */ +function PMA_getHistory($username) +{ + $cfgRelation = PMA_getRelationsParam(); + + if (! $cfgRelation['historywork']) { + return false; + } + + $hist_query = ' + SELECT `db`, + `table`, + `sqlquery` + 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']); +} // end of 'PMA_getHistory()' function + +/** + * purges SQL history + * + * deletes entries that exceeds $cfg['QueryHistoryMax'], oldest first, for the + * given user + * + * @param string $username the username + * + * @return void + * + * @access public + */ +function PMA_purgeHistory($username) +{ + $cfgRelation = PMA_getRelationsParam(); + if (! $GLOBALS['cfg']['QueryHistoryDB'] || ! $cfgRelation['historywork']) { + return; + } + + if (! $cfgRelation['historywork']) { + return; + } + + $search_query = ' + SELECT `timevalue` + 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_queryAsControlUser( + 'DELETE FROM + ' . PMA_Util::backquote($cfgRelation['db']) . '.' . PMA_Util::backquote($cfgRelation['history']) . ' + WHERE `username` = \'' . PMA_Util::sqlAddSlashes($username) . '\' + AND `timevalue` <= \'' . $max_time . '\'' + ); + } +} // end of 'PMA_purgeHistory()' function + +/** + * Prepares the dropdown for one mode + * + * @param array $foreign the keys and values for foreigns + * @param string $data the current data of the dropdown + * @param string $mode the needed mode + * + * @return array the '; + } elseif ($mode == 'id-content') { + $reloptions[] = $reloption . '>' . htmlspecialchars($key) . ' - ' . $value . ''; + } elseif ($mode == 'id-only') { + $reloptions[] = $reloption . '>' . htmlspecialchars($key) . ''; + } + } // end foreach + + return $reloptions; +} // end of 'PMA__foreignDropdownBuild' function + +/** + * Outputs dropdown with values of foreign fields + * + * @param array $disp_row array of the displayed row + * @param string $foreign_field the foreign field + * @param string $foreign_display the foreign field to display + * @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 '; + $top_count = count($top); + if ($max == -1 || $top_count < $max) { + $ret .= implode('', $top); + if ($foreign_display && $top_count > 0) { + // this empty option is to visually mark the beginning of the + // second series of values (bottom) + $ret .= ''; + } + } + if ($foreign_display) { + $ret .= implode('', $bottom); + } + + return $ret; +} // end of 'PMA_foreignDropdown()' function + +/** + * Gets foreign keys in preparation for a drop-down selector + * + * @param array $foreigners array of the foreign keys + * @param string $field the foreign field name + * @param bool $override_total whether to override the total + * @param string $foreign_filter a possible filter + * @param string $foreign_limit a possible LIMIT clause + * + * @return array data about the foreign keys + * + * @access public + */ + +function PMA_getForeignData($foreigners, $field, $override_total, $foreign_filter, $foreign_limit) +{ + // we always show the foreign field in the drop-down; if a display + // field is defined, we show it besides the foreign field + $foreign_link = false; + if ($foreigners && isset($foreigners[$field])) { + $foreigner = $foreigners[$field]; + $foreign_db = $foreigner['foreign_db']; + $foreign_table = $foreigner['foreign_table']; + $foreign_field = $foreigner['foreign_field']; + + // Count number of rows in the foreign table. Currently we do + // not use a drop-down if more than ForeignKeyMaxLimit rows in the + // foreign table, + // for speed reasons and because we need a better interface for this. + // + // We could also do the SELECT anyway, with a LIMIT, and ensure that + // the current value of the field is one of the choices. + + $the_total = PMA_Table::countRecords($foreign_db, $foreign_table, true); + + if ($override_total == true || $the_total < $GLOBALS['cfg']['ForeignKeyMaxLimit']) { + // foreign_display can be false if no display field defined: + $foreign_display = PMA_getDisplayField($foreign_db, $foreign_table); + + $f_query_main = 'SELECT ' . PMA_Util::backquote($foreign_field) + . (($foreign_display == false) ? '' : ', ' . PMA_Util::backquote($foreign_display)); + $f_query_from = ' FROM ' . PMA_Util::backquote($foreign_db) . '.' . PMA_Util::backquote($foreign_table); + $f_query_filter = empty($foreign_filter) ? '' : ' WHERE ' . PMA_Util::backquote($foreign_field) + . ' LIKE "%' . PMA_Util::sqlAddSlashes($foreign_filter, true) . '%"' + . (($foreign_display == false) ? '' : ' OR ' . PMA_Util::backquote($foreign_display) + . ' LIKE "%' . PMA_Util::sqlAddSlashes($foreign_filter, true) . '%"' + ); + $f_query_order = ($foreign_display == false) ? '' :' ORDER BY ' . PMA_Util::backquote($foreign_table) . '.' . PMA_Util::backquote($foreign_display); + $f_query_limit = isset($foreign_limit) ? $foreign_limit : ''; + + if (!empty($foreign_filter)) { + $res = PMA_DBI_query('SELECT COUNT(*)' . $f_query_from . $f_query_filter); + if ($res) { + $the_total = PMA_DBI_fetch_value($res); + @PMA_DBI_free_result($res); + } else { + $the_total = 0; + } + } + + $disp = PMA_DBI_query($f_query_main . $f_query_from . $f_query_filter . $f_query_order . $f_query_limit); + if ($disp && PMA_DBI_num_rows($disp) > 0) { + // If a resultset has been created, pre-cache it in the $disp_row array + // This helps us from not needing to use mysql_data_seek by accessing a pre-cached + // PHP array. Usually those resultsets are not that big, so a performance hit should + // not be expected. + $disp_row = array(); + while ($single_disp_row = @PMA_DBI_fetch_assoc($disp)) { + $disp_row[] = $single_disp_row; + } + @PMA_DBI_free_result($disp); + } + } else { + $disp_row = null; + $foreign_link = true; + } + } // end if $foreigners + + $foreignData['foreign_link'] = $foreign_link; + $foreignData['the_total'] = isset($the_total) ? $the_total : null; + $foreignData['foreign_display'] = isset($foreign_display) ? $foreign_display : null; + $foreignData['disp_row'] = isset($disp_row) ? $disp_row : null; + $foreignData['foreign_field'] = isset($foreign_field) ? $foreign_field : null; + return $foreignData; +} // end of 'PMA_getForeignData()' function + +/** + * Finds all related tables + * + * @param array $all_tables All the involved tables + * @param string $master The master table to form the LEFT JOIN clause + * + * @return string LEFT JOIN + * @access private + */ +function PMA_getRelatives($all_tables, $master) +{ + $fromclause = ''; + $emerg = ''; + + // The list of tables that we still couldn't connect + $remaining_tables = $all_tables; + unset($remaining_tables[$master]); + // The list of allready connected tables + $known_tables[$master] = $master; + $run = 0; + while (count($remaining_tables) > 0) { + // Whether to go from master to foreign or vice versa + if ($run % 2 == 0) { + $from = 'master'; + $to = 'foreign'; + } else { + $from = 'foreign'; + $to = 'master'; + } + $in_know = '(\'' . implode('\', \'', $known_tables) . '\')'; + $in_left = '(\'' . implode('\', \'', $remaining_tables) . '\')'; + $rel_query = 'SELECT *' + . ' FROM ' . PMA_Util::backquote($GLOBALS['cfgRelation']['db']) + . '.' . PMA_Util::backquote($GLOBALS['cfgRelation']['relation']) + . ' WHERE ' . $from . '_db = \'' . PMA_Util::sqlAddSlashes($GLOBALS['db']) . '\'' + . ' AND ' . $to . '_db = \'' . PMA_Util::sqlAddSlashes($GLOBALS['db']) . '\'' + . ' AND ' . $from . '_table IN ' . $in_know + . ' AND ' . $to . '_table IN ' . $in_left; + $relations = @PMA_DBI_query($rel_query, $GLOBALS['controllink']); + while ($row = PMA_DBI_fetch_assoc($relations)) { + $found_table = $row[$to . '_table']; + if (isset($remaining_tables[$found_table])) { + $fromclause + .= "\n" . ' LEFT JOIN ' + . PMA_Util::backquote($GLOBALS['db']) . '.' . PMA_Util::backquote($row[$to . '_table']) . ' ON ' + . PMA_Util::backquote($row[$from . '_table']) . '.' + . PMA_Util::backquote($row[$from . '_field']) . ' = ' + . PMA_Util::backquote($row[$to . '_table']) . '.' + . PMA_Util::backquote($row[$to . '_field']) . ' '; + $known_tables[$found_table] = $found_table; + unset($remaining_tables[$found_table]); + } + } // end while + $run++; + if ($run > 5) { + foreach ($remaining_tables as $table) { + $emerg .= ', ' . PMA_Util::backquote($table); + unset($remaining_tables[$table]); + } + } + } // end while + $fromclause = $emerg . $fromclause; + return $fromclause; +} // end of the "PMA_getRelatives()" function + +/** + * Rename a field in relation tables + * + * usually called after a column in a table was renamed + * + * @param string $db databse name + * @param string $table table name + * @param string $field old field name + * @param string $new_name new field name + * + * @return void + */ +function PMA_REL_renameField($db, $table, $field, $new_name) +{ + $cfgRelation = PMA_getRelationsParam(); + + if ($cfgRelation['displaywork']) { + $table_query = 'UPDATE ' + . PMA_Util::backquote($cfgRelation['db']) . '.' + . PMA_Util::backquote($cfgRelation['table_info']) + . ' SET display_field = \'' . PMA_Util::sqlAddSlashes($new_name) . '\'' + . ' WHERE db_name = \'' . PMA_Util::sqlAddSlashes($db) . '\'' + . ' AND table_name = \'' . PMA_Util::sqlAddSlashes($table) . '\'' + . ' AND display_field = \'' . PMA_Util::sqlAddSlashes($field) . '\''; + PMA_queryAsControlUser($table_query); + } + + if ($cfgRelation['relwork']) { + $table_query = 'UPDATE ' + . PMA_Util::backquote($cfgRelation['db']) . '.' + . PMA_Util::backquote($cfgRelation['relation']) + . ' SET master_field = \'' . PMA_Util::sqlAddSlashes($new_name) . '\'' + . ' WHERE master_db = \'' . PMA_Util::sqlAddSlashes($db) . '\'' + . ' AND master_table = \'' . PMA_Util::sqlAddSlashes($table) . '\'' + . ' AND master_field = \'' . PMA_Util::sqlAddSlashes($field) . '\''; + PMA_queryAsControlUser($table_query); + + $table_query = 'UPDATE ' + . PMA_Util::backquote($cfgRelation['db']) . '.' + . PMA_Util::backquote($cfgRelation['relation']) + . ' SET foreign_field = \'' . PMA_Util::sqlAddSlashes($new_name) . '\'' + . ' WHERE foreign_db = \'' . PMA_Util::sqlAddSlashes($db) . '\'' + . ' AND foreign_table = \'' . PMA_Util::sqlAddSlashes($table) . '\'' + . ' AND foreign_field = \'' . PMA_Util::sqlAddSlashes($field) . '\''; + PMA_queryAsControlUser($table_query); + + } // end if relwork +} + + +/** + * Performs SQL query used for renaming table. + * + * @param string $table Relation table to use + * @param string $source_db Source database name + * @param string $target_db Target database name + * @param string $source_table Source table name + * @param string $target_table Target table name + * @param string $db_field Name of database field + * @param string $table_field Name of table field + * + * @return nothing. + */ +function PMA_REL_renameSingleTable($table, + $source_db, $target_db, + $source_table, $target_table, + $db_field, $table_field +) { + $query = 'UPDATE ' + . PMA_Util::backquote($GLOBALS['cfgRelation']['db']) . '.' + . PMA_Util::backquote($GLOBALS['cfgRelation'][$table]) + . ' SET ' . $db_field . ' = \'' . PMA_Util::sqlAddSlashes($target_db) . '\', ' + . ' ' . $table_field . ' = \'' . PMA_Util::sqlAddSlashes($target_table) . '\'' + . ' WHERE ' + . $db_field . ' = \'' . PMA_Util::sqlAddSlashes($source_db) . '\'' + . ' AND ' + . $table_field . ' = \'' . PMA_Util::sqlAddSlashes($source_table) . '\''; + PMA_queryAsControlUser($query); +} + + +/** + * Rename a table in relation tables + * + * usually called after table has been moved + * + * @param string $source_db Source database name + * @param string $target_db Target database name + * @param string $source_table Source table name + * @param string $target_table Target table name + * + * @return nothing + */ +function PMA_REL_renameTable($source_db, $target_db, $source_table, $target_table) +{ + // Move old entries from PMA-DBs to new table + if ($GLOBALS['cfgRelation']['commwork']) { + PMA_REL_renameSingleTable( + 'column_info', + $source_db, $target_db, + $source_table, $target_table, + 'db_name', 'table_name' + ); + } + + // updating bookmarks is not possible since only a single table is + // moved, and not the whole DB. + + if ($GLOBALS['cfgRelation']['displaywork']) { + PMA_REL_renameSingleTable( + 'table_info', + $source_db, $target_db, + $source_table, $target_table, + 'db_name', 'table_name' + ); + } + + if ($GLOBALS['cfgRelation']['relwork']) { + PMA_REL_renameSingleTable( + 'relation', + $source_db, $target_db, + $source_table, $target_table, + 'foreign_db', 'foreign_table' + ); + + PMA_REL_renameSingleTable( + 'relation', + $source_db, $target_db, + $source_table, $target_table, + 'master_db', 'master_table' + ); + } + + /** + * @todo Can't get moving PDFs the right way. The page numbers + * always get screwed up independently from duplication because the + * numbers do not seem to be stored on a per-database basis. Would + * the author of pdf support please have a look at it? + */ + + if ($GLOBALS['cfgRelation']['pdfwork']) { + PMA_REL_renameSingleTable( + 'table_coords', + $source_db, $target_db, + $source_table, $target_table, + 'db_name', 'table_name' + ); + } + + if ($GLOBALS['cfgRelation']['designerwork']) { + PMA_REL_renameSingleTable( + 'designer_coords', + $source_db, $target_db, + $source_table, $target_table, + 'db_name', 'table_name' + ); + } +} + +/** + * Create a PDF page + * + * @param string $newpage name of the new PDF page + * @param array $cfgRelation Relation configuration + * @param string $db database name + * + * @return string $pdf_page_number + */ +function PMA_REL_createPage($newpage, $cfgRelation, $db) +{ + if (! isset($newpage) || $newpage == '') { + $newpage = __('no description'); + } + $ins_query = 'INSERT INTO ' + . PMA_Util::backquote($GLOBALS['cfgRelation']['db']) . '.' + . PMA_Util::backquote($cfgRelation['pdf_pages']) + . ' (db_name, page_descr)' + . ' VALUES (\'' + . PMA_Util::sqlAddSlashes($db) . '\', \'' + . PMA_Util::sqlAddSlashes($newpage) . '\')'; + PMA_queryAsControlUser($ins_query, false); + + return PMA_DBI_insert_id( + isset($GLOBALS['controllink']) ? $GLOBALS['controllink'] : '' + ); +} +?> diff --git a/phpmyadmin/libraries/relation_cleanup.lib.php b/phpmyadmin/libraries/relation_cleanup.lib.php new file mode 100644 index 000000000..1c86a4b78 --- /dev/null +++ b/phpmyadmin/libraries/relation_cleanup.lib.php @@ -0,0 +1,165 @@ + diff --git a/phpmyadmin/libraries/replication.inc.php b/phpmyadmin/libraries/replication.inc.php new file mode 100644 index 000000000..467b3d541 --- /dev/null +++ b/phpmyadmin/libraries/replication.inc.php @@ -0,0 +1,307 @@ + 'No', + 'Slave_SQL_Running' => 'No', +); +$slave_variables_oks = array( + 'Slave_IO_Running' => 'Yes', + 'Slave_SQL_Running' => 'Yes', +); + +// check which replication is available and +// set $server_{master/slave}_status and assign values + +// replication info is more easily passed to functions +/* + * @todo use $replication_info everywhere instead of the generated variable names + */ +$replication_info = array(); + +foreach ($replication_types as $type) { + if (count(${"server_{$type}_replication"}) > 0) { + ${"server_{$type}_status"} = true; + $replication_info[$type]['status'] = true; + } else { + ${"server_{$type}_status"} = false; + $replication_info[$type]['status'] = false; + } + if (${"server_{$type}_status"}) { + if ($type == "master") { + ${"server_{$type}_Do_DB"} = explode(",", $server_master_replication[0]["Binlog_Do_DB"]); + $replication_info[$type]['Do_DB'] = ${"server_{$type}_Do_DB"}; + + ${"server_{$type}_Ignore_DB"} = explode(",", $server_master_replication[0]["Binlog_Ignore_DB"]); + $replication_info[$type]['Ignore_DB'] = ${"server_{$type}_Ignore_DB"}; + } elseif ($type == "slave") { + ${"server_{$type}_Do_DB"} = explode(",", $server_slave_replication[0]["Replicate_Do_DB"]); + $replication_info[$type]['Do_DB'] = ${"server_{$type}_Do_DB"}; + + ${"server_{$type}_Ignore_DB"} = explode(",", $server_slave_replication[0]["Replicate_Ignore_DB"]); + $replication_info[$type]['Ignore_DB'] = ${"server_{$type}_Ignore_DB"}; + + ${"server_{$type}_Do_Table"} = explode(",", $server_slave_replication[0]["Replicate_Do_Table"]); + $replication_info[$type]['Do_Table'] = ${"server_{$type}_Do_Table"}; + + ${"server_{$type}_Ignore_Table"} = explode(",", $server_slave_replication[0]["Replicate_Ignore_Table"]); + $replication_info[$type]['Ignore_Table'] = ${"server_{$type}_Ignore_Table"}; + + ${"server_{$type}_Wild_Do_Table"} = explode(",", $server_slave_replication[0]["Replicate_Wild_Do_Table"]); + $replication_info[$type]['Wild_Do_Table'] = ${"server_{$type}_Wild_Do_Table"}; + + ${"server_{$type}_Wild_Ignore_Table"} = explode(",", $server_slave_replication[0]["Replicate_Wild_Ignore_Table"]); + $replication_info[$type]['Wild_Ignore_Table'] = ${"server_{$type}_Wild_Ignore_Table"}; + } + } +} + +/** + * Extracts database or table name from string + * + * @param string $string contains "dbname.tablename" + * @param string $what what to extract (db|table) + * + * @return $string the extracted part + */ +function PMA_extract_db_or_table($string, $what = 'db') +{ + $list = explode(".", $string); + if ('db' == $what) { + return $list[0]; + } else { + return $list[1]; + } +} + +/** + * Configures replication slave + * + * @param string $action possible values: START or STOP + * @param string $control default: null, possible values: SQL_THREAD or IO_THREAD or null. + * If it is set to null, it controls both SQL_THREAD and IO_THREAD + * @param mixed $link mysql link + * + * @return mixed output of PMA_DBI_try_query + */ +function PMA_replication_slave_control($action, $control = null, $link = null) +{ + $action = strtoupper($action); + $control = strtoupper($control); + + if ($action != "START" && $action != "STOP") { + return -1; + } + if ($control != "SQL_THREAD" && $control != "IO_THREAD" && $control != null) { + return -1; + } + + return PMA_DBI_try_query($action . " SLAVE " . $control . ";", $link); +} + +/** + * Changes master for replication slave + * + * @param string $user replication user on master + * @param string $password password for the user + * @param string $host master's hostname or IP + * @param int $port port, where mysql is running + * @param array $pos position of mysql replication, + * array should contain fields File and Position + * @param bool $stop shall we stop slave? + * @param bool $start shall we start slave? + * @param mixed $link mysql link + * + * @return output of CHANGE MASTER mysql command + */ +function PMA_replication_slave_change_master($user, $password, $host, $port, + $pos, $stop = true, $start = true, $link = null +) { + if ($stop) { + PMA_replication_slave_control("STOP", null, $link); + } + + $out = PMA_DBI_try_query( + 'CHANGE MASTER TO ' . + 'MASTER_HOST=\'' . $host . '\',' . + 'MASTER_PORT=' . ($port * 1) . ',' . + 'MASTER_USER=\'' . $user . '\',' . + 'MASTER_PASSWORD=\'' . $password . '\',' . + 'MASTER_LOG_FILE=\'' . $pos["File"] . '\',' . + 'MASTER_LOG_POS=' . $pos["Position"] . ';', $link + ); + + if ($start) { + PMA_replication_slave_control("START", null, $link); + } + + return $out; +} + +/** + * This function provides connection to remote mysql server + * + * @param string $user mysql username + * @param string $password password for the user + * @param string $host mysql server's hostname or IP + * @param int $port mysql remote port + * @param string $socket path to unix socket + * + * @return mixed $link mysql link on success + */ +function PMA_replication_connect_to_master($user, $password, $host = null, $port = null, $socket = null) +{ + $server = array(); + $server["host"] = $host; + $server["port"] = $port; + $server["socket"] = $socket; + + // 5th parameter set to true means that it's an auxiliary connection + // and we must not go back to login page if it fails + return PMA_DBI_connect($user, $password, false, $server, true); +} +/** + * Fetches position and file of current binary log on master + * + * @param mixed $link mysql link + * + * @return array an array containing File and Position in MySQL replication + * on master server, useful for PMA_replication_slave_change_master + */ +function PMA_replication_slave_bin_log_master($link = null) +{ + $data = PMA_DBI_fetch_result('SHOW MASTER STATUS', null, null, $link); + $output = array(); + + if (! empty($data)) { + $output["File"] = $data[0]["File"]; + $output["Position"] = $data[0]["Position"]; + } + return $output; +} + +/** + * Get list of replicated databases on master server + * + * @param mixed $link mysql link + * + * @return array array of replicated databases + */ + +function PMA_replication_master_replicated_dbs($link = null) +{ + // let's find out, which databases are replicated + $data = PMA_DBI_fetch_result('SHOW MASTER STATUS', null, null, $link); + + $do_db = array(); + $ignore_db = array(); + + if (! empty($data[0]['Binlog_Do_DB'])) { + $do_db = explode(',', $data[0]['Binlog_Do_DB']); + } + if (! empty($data[0]['Binlog_Ignore_DB'])) { + $ignore_db = explode(',', $data[0]['Binlog_Ignore_DB']); + } + + $tmp_alldbs = PMA_DBI_query('SHOW DATABASES;', $link); + while ($tmp_row = PMA_DBI_fetch_row($tmp_alldbs)) { + if (PMA_is_system_schema($tmp_row[0])) { + continue; + } + if (count($do_db) == 0) { + if (array_search($tmp_row[0], $ignore_db) !== false) { + continue; + } + $dblist[] = $tmp_row[0]; + + } else { + if (array_search($tmp_row[0], $do_db) !== false) { + $dblist[] = $tmp_row[0]; + } + } + } // end while + + return $link; +} +?> diff --git a/phpmyadmin/libraries/replication_gui.lib.php b/phpmyadmin/libraries/replication_gui.lib.php new file mode 100644 index 000000000..3743f39fe --- /dev/null +++ b/phpmyadmin/libraries/replication_gui.lib.php @@ -0,0 +1,401 @@ +'; + + foreach ($GLOBALS['pma']->databases as $current_db) { + if (PMA_is_system_schema($current_db)) { + continue; + } + if (! empty($selectall) || (isset($tmp_select) && strpos(' ' . $tmp_select, '|' . $current_db . '|'))) { + $is_selected = ' selected="selected"'; + } else { + $is_selected = ''; + } + $current_db = htmlspecialchars($current_db); + $multi_values .= ' '; + } // end while + + $multi_values .= ''; + $multi_values .= '
      ' . __('Uncheck All') . ''; + + return $multi_values; +} + +/** + * prints out code for changing master + * + * @param String $submitname - submit button name + * + * @return void + */ + +function PMA_replication_gui_changemaster($submitname) +{ + + 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 '
      '; +} + +/** + * This function prints out 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 + * + * @return void + */ +function PMA_replication_print_status_table($type, $hidden = false, $title = true) +{ + global ${"{$type}_variables"}; + global ${"{$type}_variables_alerts"}; + global ${"{$type}_variables_oks"}; + global ${"server_{$type}_replication"}; + global ${"strReplicationStatus_{$type}"}; + + // 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 + // + //$server_id = PMA_DBI_fetch_value("SHOW VARIABLES LIKE 'server_id'", 0, 1); + + echo '
      '; + + if ($title) { + if ($type == 'master') { + echo '

      ' . __('Master status') . '

      '; + } else { + echo '

      ' . __('Slave status') . '

      '; + } + } else { + echo '
      '; + } + + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + + $odd_row = true; + foreach (${"{$type}_variables"} as $variable) { + echo ' '; + echo ' '; + echo ' '; + echo ' '; + + $odd_row = ! $odd_row; + } + + echo ' '; + echo '
      ' . __('Variable') . '' . __('Value') . '
      '; + echo $variable; + echo ' '; + + + // 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 ''; + + } elseif (isset(${"{$type}_variables_oks"}[$variable]) + && ${"{$type}_variables_oks"}[$variable] == ${"server_{$type}_replication"}[0][$variable] + ) { + echo ''; + } else { + echo ''; + } + // 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)) { + echo str_replace(',', ', ', ${"server_{$type}_replication"}[0][$variable]); + } else { + echo ${"server_{$type}_replication"}[0][$variable]; + } + echo ''; + + echo '
      '; + echo '
      '; + echo '
      '; + +} + +/** + * Prints table with slave users connected to this master + * + * @param boolean $hidden - if true, then default style is set to hidden, default value false + * + * @return void + */ +function PMA_replication_print_slaves_table($hidden = false) +{ + + // Fetch data + $data = PMA_DBI_fetch_result('SHOW SLAVE HOSTS', null, null); + + echo '
      '; + echo '
      '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + + $odd_row = true; + foreach ($data as $slave) { + echo ' '; + echo ' '; + echo ' '; + echo ' '; + + $odd_row = ! $odd_row; + } + + echo ' '; + echo '
      ' . __('Server ID') . '' . __('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 '
      '; +} + +/** + * get the correct username and hostname lengths for this MySQL server + * + * @return array username length, hostname length + */ + +function PMA_replication_get_username_hostname_length() +{ + $fields_info = PMA_DBI_get_columns('mysql', 'user'); + $username_length = 16; + $hostname_length = 41; + foreach ($fields_info as $val) { + if ($val['Field'] == 'User') { + strtok($val['Type'], '()'); + $v = strtok('()'); + if (is_int($v)) { + $username_length = $v; + } + } elseif ($val['Field'] == 'Host') { + strtok($val['Type'], '()'); + $v = strtok('()'); + if (is_int($v)) { + $hostname_length = $v; + } + } + } + return array($username_length, $hostname_length); +} + +/** + * Print code to add a replication slave user to the master + * + * @return void + */ +function PMA_replication_gui_master_addslaveuser() +{ + + list($username_length, $hostname_length) = PMA_replication_get_username_hostname_length(); + + if (isset($GLOBALS['username']) && strlen($GLOBALS['username']) === 0) { + $GLOBALS['pred_username'] = 'any'; + } + echo '
      '; + echo '
      '; + echo PMA_generate_common_hidden_inputs('', ''); + echo '
      ' + . ''.__('Add slave replication user').'' + . '' + . '' + . '' + . '' + . '' + . '' + . '
      ' + . '' + . '' + . ' ' + . '' + . '' + . '
      ' + . '
      ' + . '' + . '' + . ' ' + . '' + . '' + . PMA_Util::showHint( + __('When Host table is used, this field is ignored and values stored in Host table are used instead.') + ) + . '
      ' + . '
      ' + . '' + . '' + . ' ' + . '' + . '' + . '
      ' + . '
      ' + . '' + . ' ' + . '' + . '
      ' + . '
      ' + . '' + . '' + . ' ' + . '' + . '' + . '
      ' + . '
      '; + echo ''; + echo '
      '; + echo '
      '; +} +?> diff --git a/phpmyadmin/libraries/rte/rte_events.lib.php b/phpmyadmin/libraries/rte/rte_events.lib.php new file mode 100644 index 000000000..7d4ce6cf3 --- /dev/null +++ b/phpmyadmin/libraries/rte/rte_events.lib.php @@ -0,0 +1,637 @@ + array('ENABLE', + 'DISABLE', + 'DISABLE ON SLAVE'), + 'display' => array('ENABLED', + 'DISABLED', + 'SLAVESIDE_DISABLED') + ); + $event_type = array('RECURRING', + 'ONE TIME'); + $event_interval = array('YEAR', + 'QUARTER', + 'MONTH', + 'DAY', + 'HOUR', + 'MINUTE', + 'WEEK', + 'SECOND', + 'YEAR_MONTH', + 'DAY_HOUR', + 'DAY_MINUTE', + 'DAY_SECOND', + 'HOUR_MINUTE', + 'HOUR_SECOND', + 'MINUTE_SECOND'); +} + +/** + * Main function for the events functionality + * + * @return void + */ +function PMA_EVN_main() +{ + global $db; + + PMA_EVN_setGlobals(); + /** + * Process all requests + */ + PMA_EVN_handleEditor(); + PMA_EVN_handleExport(); + /** + * Display a list of available events + */ + $columns = "`EVENT_NAME`, `EVENT_TYPE`, `STATUS`"; + $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); + echo PMA_RTE_getList('event', $items); + /** + * Display a link for adding a new event, if + * the user has the privileges and a link to + * toggle the state of the event scheduler. + */ + echo PMA_EVN_getFooterLinks(); +} // end PMA_EVN_main() + +/** + * Handles editor requests for adding or editing an item + * + * @return void + */ +function PMA_EVN_handleEditor() +{ + global $_REQUEST, $_POST, $errors, $db; + + if (! empty($_REQUEST['editor_process_add']) + || ! empty($_REQUEST['editor_process_edit']) + ) { + $sql_query = ''; + + $item_query = PMA_EVN_getQueryFromRequest(); + + if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest() + // 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( + $db, + 'EVENT', + $_REQUEST['item_original_name'] + ); + $drop_item = "DROP EVENT " + . PMA_Util::backquote($_REQUEST['item_original_name']) . ";\n"; + $result = PMA_DBI_try_query($drop_item); + if (! $result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($drop_item) + ) + . '
      ' + . __('MySQL said: ') . PMA_DBI_getError(null); + } else { + $result = PMA_DBI_try_query($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); + if (! $result) { + // 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. + $errors[] = __( + 'Sorry, we failed to restore the dropped event.' + ) + . '
      ' + . __('The backed up query was:') + . "\"" . htmlspecialchars($create_item) . "\"" + . '
      ' + . __('MySQL said: ') . PMA_DBI_getError(null); + } + } else { + $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); + if (! $result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($item_query) + ) + . '

      ' + . __('MySQL said: ') . PMA_DBI_getError(null); + } else { + $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->addString('
        '); + foreach ($errors as $string) { + $message->addString('
      • ' . $string . '
      • '); + } + $message->addString('
      '); + } + + $output = PMA_Util::getMessage($message, $sql_query); + if ($GLOBALS['is_ajax_request']) { + $response = PMA_Response::getInstance(); + if ($message->isSuccess()) { + $columns = "`EVENT_NAME`, `EVENT_TYPE`, `STATUS`"; + $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 = PMA_DBI_fetch_single_row($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->isSuccess(false); + $response->addJSON('message', $message); + } + 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']) + || ! empty($_REQUEST['item_changetype']))) + ) { // FIXME: this must be simpler than that + $operation = ''; + if (! empty($_REQUEST['item_changetype'])) { + $operation = 'change'; + } + // Get the data for the form (if any) + if (! empty($_REQUEST['add_item'])) { + $title = PMA_RTE_getWord('add'); + $item = PMA_EVN_getDataFromRequest(); + $mode = 'add'; + } else if (! empty($_REQUEST['edit_item'])) { + $title = __("Edit event"); + if (! empty($_REQUEST['item_name']) + && empty($_REQUEST['editor_process_edit']) + && empty($_REQUEST['item_changetype']) + ) { + $item = PMA_EVN_getDataFromName($_REQUEST['item_name']); + if ($item !== false) { + $item['item_original_name'] = $item['item_name']; + } + } else { + $item = PMA_EVN_getDataFromRequest(); + } + $mode = 'edit'; + } + if ($item !== false) { + // Show form + $editor = PMA_EVN_getEditorForm($mode, $operation, $item); + if ($GLOBALS['is_ajax_request']) { + $response = PMA_Response::getInstance(); + $response->addJSON('message', $editor); + $response->addJSON('title', $title); + } else { + echo "\n\n

      $title

      \n\n$editor"; + unset($_POST); + } + exit; + } else { + $message = __('Error in processing request') . ' : '; + $message .= sprintf( + PMA_RTE_getWord('not_found'), + htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(PMA_Util::backquote($db)) + ); + $message = PMA_message::error($message); + if ($GLOBALS['is_ajax_request']) { + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', $message); + exit; + } else { + $message->display(); + } + } + } +} // end PMA_EVN_handleEditor() + +/** + * This function will generate the values that are required to for the editor + * + * @return array Data necessary to create the editor. + */ +function PMA_EVN_getDataFromRequest() +{ + $retval = array(); + $indices = array('item_name', + 'item_original_name', + 'item_status', + 'item_execute_at', + 'item_interval_value', + 'item_interval_field', + 'item_starts', + 'item_ends', + 'item_definition', + 'item_preserve', + 'item_comment', + 'item_definer'); + foreach ($indices as $index) { + $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : ''; + } + $retval['item_type'] = 'ONE TIME'; + $retval['item_type_toggle'] = 'RECURRING'; + if (isset($_REQUEST['item_type']) && $_REQUEST['item_type'] == 'RECURRING') { + $retval['item_type'] = 'RECURRING'; + $retval['item_type_toggle'] = 'ONE TIME'; + } + return $retval; +} // end 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. + * + * @return array Data necessary to create the editor. + */ +function PMA_EVN_getDataFromName($name) +{ + global $db; + + $retval = array(); + $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_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); + if (! $item) { + return false; + } + $retval['item_name'] = $item['EVENT_NAME']; + $retval['item_status'] = $item['STATUS']; + $retval['item_type'] = $item['EVENT_TYPE']; + if ($retval['item_type'] == 'RECURRING') { + $retval['item_type_toggle'] = 'ONE TIME'; + } else { + $retval['item_type_toggle'] = 'RECURRING'; + } + $retval['item_execute_at'] = $item['EXECUTE_AT']; + $retval['item_interval_value'] = $item['INTERVAL_VALUE']; + $retval['item_interval_field'] = $item['INTERVAL_FIELD']; + $retval['item_starts'] = $item['STARTS']; + $retval['item_ends'] = $item['ENDS']; + $retval['item_preserve'] = ''; + if ($item['ON_COMPLETION'] == 'PRESERVE') { + $retval['item_preserve'] = " checked='checked'"; + } + $retval['item_definition'] = $item['EVENT_DEFINITION']; + $retval['item_definer'] = $item['DEFINER']; + $retval['item_comment'] = $item['EVENT_COMMENT']; + + return $retval; +} // end PMA_EVN_getDataFromName() + +/** + * Displays a form used to add/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 + * JS turned off, this will hold the name of + * the current operation + * @param array $item Data for the event returned by + * PMA_EVN_getDataFromRequest() or + * PMA_EVN_getDataFromName() + * + * @return string HTML code for the editor. + */ +function PMA_EVN_getEditorForm($mode, $operation, $item) +{ + global $db, $table, $event_status, $event_type, $event_interval; + + // Escape special characters + $need_escape = array( + 'item_original_name', + 'item_name', + 'item_type', + 'item_execute_at', + 'item_interval_value', + 'item_starts', + 'item_ends', + 'item_definition', + 'item_definer', + 'item_comment' + ); + foreach ($need_escape as $index) { + $item[$index] = htmlentities($item[$index], ENT_QUOTES); + } + $original_data = ''; + if ($mode == 'edit') { + $original_data = "\n"; + } + // Handle some logic first + if ($operation == 'change') { + if ($item['item_type'] == 'RECURRING') { + $item['item_type'] = 'ONE TIME'; + $item['item_type_toggle'] = 'RECURRING'; + } else { + $item['item_type'] = 'RECURRING'; + $item['item_type_toggle'] = 'ONE TIME'; + } + } + if ($item['item_type'] == 'ONE TIME') { + $isrecurring_class = ' hide'; + $isonetime_class = ''; + } else { + $isrecurring_class = ''; + $isonetime_class = ' hide'; + } + // Create the output + $retval = ""; + $retval .= "\n\n"; + $retval .= "
      \n"; + $retval .= "\n"; + $retval .= $original_data; + $retval .= PMA_generate_common_hidden_inputs($db, $table) . "\n"; + $retval .= "
      \n"; + $retval .= "" . __('Details') . "\n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + + return $retval; +} // end PMA_RTN_getRowForList() + +/** + * 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'] + * + * @return string HTML code of a cell for the list of triggers + */ +function PMA_TRI_getRowForList($trigger, $rowclass = '') +{ + global $ajax_class, $url_query, $db, $table, $titles; + + $retval = " \n"; + $retval .= " \n"; + if (empty($table)) { + $retval .= " \n"; + } + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + + return $retval; +} // end PMA_TRI_getRowForList() + +/** + * 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'] + * + * @return string HTML code of a cell for the list of events + */ +function PMA_EVN_getRowForList($event, $rowclass = '') +{ + global $ajax_class, $url_query, $db, $titles; + + $sql_drop = sprintf( + 'DROP EVENT IF EXISTS %s', + PMA_Util::backquote($event['EVENT_NAME']) + ); + + $retval = " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + + return $retval; +} // end PMA_EVN_getRowForList() + +?> diff --git a/phpmyadmin/libraries/rte/rte_main.inc.php b/phpmyadmin/libraries/rte/rte_main.inc.php new file mode 100644 index 000000000..355240f70 --- /dev/null +++ b/phpmyadmin/libraries/rte/rte_main.inc.php @@ -0,0 +1,92 @@ + '', + '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_Util::buildActionTitles(); + +/** + * Keep a list of errors that occured while + * processing an 'Add' or 'Edit' operation. + */ +$errors = array(); + + +/** + * Call the appropriate main function + */ +switch ($_PMA_RTE) { +case 'RTN': + PMA_RTN_main(); + break; +case 'TRI': + PMA_TRI_main(); + break; +case 'EVN': + PMA_EVN_main(); + break; +} + +?> diff --git a/phpmyadmin/libraries/rte/rte_routines.lib.php b/phpmyadmin/libraries/rte/rte_routines.lib.php new file mode 100644 index 000000000..b69c4bb4c --- /dev/null +++ b/phpmyadmin/libraries/rte/rte_routines.lib.php @@ -0,0 +1,1676 @@ + '', + 1 => '', + 2 => '', + 3 => '', + 4 => ''); + $parsed_param = PMA_SQP_parse($value); + $pos = 0; + if (in_array(strtoupper($parsed_param[$pos]['data']), $param_directions)) { + $retval[0] = strtoupper($parsed_param[0]['data']); + $pos++; + } + if ($parsed_param[$pos]['type'] == 'alpha_identifier' + || $parsed_param[$pos]['type'] == 'quote_backtick' + ) { + $retval[1] = PMA_Util::unQuote( + $parsed_param[$pos]['data'] + ); + $pos++; + } + $depth = 0; + $param_length = ''; + $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 + ) { + $retval[2] = strtoupper($parsed_param[$i]['data']); + } 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 + ) { + $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' + ) { + $param_opts[] = strtolower($parsed_param[$i+1]['data']); + } + } else if ($parsed_param[$i]['type'] == 'alpha_columnAttrib' + && $depth == 0 + ) { + $param_opts[] = strtoupper($parsed_param[$i]['data']); + } + } + $retval[3] = $param_length; + sort($param_opts); + $retval[4] = implode(' ', $param_opts); + + return $retval; +} // end PMA_RTN_parseOneParameter() + +/** + * This function looks through the contents of a parsed + * 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' + * + * @return array Information about the parameteres of a routine. + */ +function PMA_RTN_parseAllParameters($parsed_query, $routine_type) +{ + $retval = array(); + $retval['num'] = 0; + + // First get the list of parameters from the query + $buffer = ''; + $params = array(); + $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 + ) { + $fetching = true; + } 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' + ) { + $depth--; + if ($depth > 0) { + $buffer .= $parsed_query[$i]['data'] . ' '; + } else { + break; + } + } else if ($parsed_query[$i]['type'] == 'punct_listsep' && $depth == 1) { + $params[] = $buffer; + $retval['num']++; + $buffer = ''; + } else if ($fetching == true && $depth > 0) { + $buffer .= $parsed_query[$i]['data'] . ' '; + } + } + if (! empty($buffer)) { + $params[] = $buffer; + $retval['num']++; + } + // Now parse each parameter individually + foreach ($params as $key => $value) { + list($retval['dir'][], + $retval['name'][], + $retval['type'][], + $retval['length'][], + $retval['opts'][]) = PMA_RTN_parseOneParameter($value); + } + // Since some indices of $retval may be still undefined, we fill + // them each with an empty array to avoid E_ALL errors in PHP. + foreach (array('dir', 'name', 'type', 'length', 'opts') as $key => $index) { + if (! isset($retval[$index])) { + $retval[$index] = array(); + } + } + + return $retval; +} // end PMA_RTN_parseAllParameters() + +/** + * This function looks through the contents of a parsed + * SHOW CREATE [PROCEDURE | FUNCTION] query and extracts + * information about the routine's definer. + * + * @param array $parsed_query Parsed query, returned by PMA_SQP_parse() + * + * @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' + ) { + $fetching = true; + } 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_Util::unQuote( + $parsed_query[$i]['data'] + ); + } else if ($fetching == true && $parsed_query[$i]['type'] == 'punct_user') { + $retval .= $parsed_query[$i]['data']; + } + } + return $retval; +} // end PMA_RTN_parseRoutineDefiner() + +/** + * Handles editor requests for adding or editing an item + * + * @return Does not return + */ +function PMA_RTN_handleEditor() +{ + global $_GET, $_POST, $_REQUEST, $GLOBALS, $db, $errors; + + if (! empty($_REQUEST['editor_process_add']) + || ! empty($_REQUEST['editor_process_edit']) + ) { + /** + * Handle a request to create/edit a routine + */ + $sql_query = ''; + $routine_query = PMA_RTN_getQueryFromRequest(); + if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest() + // Execute the created query + if (! empty($_REQUEST['editor_process_edit'])) { + if (! in_array($_REQUEST['item_original_type'], array('PROCEDURE', 'FUNCTION'))) { + $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_Util::backquote($_REQUEST['item_original_name']) + . ";\n"; + $result = PMA_DBI_try_query($drop_routine); + if (! $result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($drop_routine) + ) + . '
      ' + . __('MySQL said: ') . PMA_DBI_getError(null); + } else { + $result = PMA_DBI_try_query($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 + // Try to restore the backup query + $result = PMA_DBI_try_query($create_routine); + if (! $result) { + // 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. + $errors[] = __( + 'Sorry, we failed to restore' + . ' the dropped routine.' + ) + . '
      ' + . __('The backed up query was:') + . "\"" . htmlspecialchars($create_routine) . "\"" + . '
      ' + . __('MySQL said: ') . PMA_DBI_getError(null); + } + } else { + $message = PMA_Message::success( + __('Routine %1$s has been modified.') + ); + $message->addParam( + PMA_Util::backquote($_REQUEST['item_name']) + ); + $sql_query = $drop_routine . $routine_query; + } + } + } + } else { + // 'Add a new routine' mode + $result = PMA_DBI_try_query($routine_query); + if (! $result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($routine_query) + ) + . '

      ' + . __('MySQL said: ') . PMA_DBI_getError(null); + } else { + $message = PMA_Message::success( + __('Routine %1$s has been created.') + ); + $message->addParam( + PMA_Util::backquote($_REQUEST['item_name']) + ); + $sql_query = $routine_query; + } + } + } + + if (count($errors)) { + $message = PMA_Message::error( + __( + 'One or more errors have occured while' + . ' processing your request:' + ) + ); + $message->addString('
        '); + foreach ($errors as $string) { + $message->addString('
      • ' . $string . '
      • '); + } + $message->addString('
      '); + } + + $output = PMA_Util::getMessage($message, $sql_query); + if ($GLOBALS['is_ajax_request']) { + $response = PMA_Response::getInstance(); + if ($message->isSuccess()) { + $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 = PMA_DBI_fetch_single_row( + "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->isSuccess(false); + $response->addJSON('message', $output); + } + exit; + } + } + + /** + * Display a form used to add/edit a routine, if necessary + */ + // 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']))) + ) { + // Handle requests to add/remove parameters and changing routine type + // This is necessary when JS is disabled + $operation = ''; + if (! empty($_REQUEST['routine_addparameter'])) { + $operation = 'add'; + } else if (! empty($_REQUEST['routine_removeparameter'])) { + $operation = 'remove'; + } else if (! empty($_REQUEST['routine_changetype'])) { + $operation = 'change'; + } + // Get the data for the form (if any) + if (! empty($_REQUEST['add_item'])) { + $title = PMA_RTE_getWord('add'); + $routine = PMA_RTN_getDataFromRequest(); + $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 ($routine !== false) { + $routine['item_original_name'] = $routine['item_name']; + $routine['item_original_type'] = $routine['item_type']; + } + } else { + $routine = PMA_RTN_getDataFromRequest(); + } + $mode = 'edit'; + } + if ($routine !== false) { + // Show form + $editor = PMA_RTN_getEditorForm($mode, $operation, $routine); + if ($GLOBALS['is_ajax_request']) { + $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"; + } + exit; + } else { + $message = __('Error in processing request') . ' : '; + $message .= sprintf( + PMA_RTE_getWord('not_found'), + htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(PMA_Util::backquote($db)) + ); + $message = PMA_message::error($message); + if ($GLOBALS['is_ajax_request']) { + $response->isSuccess(false); + $response->addJSON('message', $message); + exit; + } else { + $message->display(); + } + } + } +} // end PMA_RTN_handleEditor() + +/** + * This function will generate the values that are required to + * complete the editor form. It is especially necessary to handle + * 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. + */ +function PMA_RTN_getDataFromRequest() +{ + global $_REQUEST, $param_directions, $param_sqldataaccess; + + $retval = array(); + $indices = array('item_name', + 'item_original_name', + 'item_returnlength', + 'item_returnopts_num', + 'item_returnopts_text', + 'item_definition', + 'item_comment', + 'item_definer'); + foreach ($indices as $key => $index) { + $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : ''; + } + + $retval['item_type'] = 'PROCEDURE'; + $retval['item_type_toggle'] = 'FUNCTION'; + if (isset($_REQUEST['item_type']) && $_REQUEST['item_type'] == 'FUNCTION') { + $retval['item_type'] = 'FUNCTION'; + $retval['item_type_toggle'] = 'PROCEDURE'; + } + $retval['item_original_type'] = 'PROCEDURE'; + if (isset($_REQUEST['item_original_type']) + && $_REQUEST['item_original_type'] == 'FUNCTION' + ) { + $retval['item_original_type'] = 'FUNCTION'; + } + $retval['item_num_params'] = 0; + $retval['item_param_dir'] = array(); + $retval['item_param_name'] = array(); + $retval['item_param_type'] = array(); + $retval['item_param_length'] = array(); + $retval['item_param_opts_num'] = array(); + $retval['item_param_opts_text'] = array(); + if ( isset($_REQUEST['item_param_name']) + && isset($_REQUEST['item_param_type']) + && isset($_REQUEST['item_param_length']) + && isset($_REQUEST['item_param_opts_num']) + && isset($_REQUEST['item_param_opts_text']) + && is_array($_REQUEST['item_param_name']) + && is_array($_REQUEST['item_param_type']) + && is_array($_REQUEST['item_param_length']) + && is_array($_REQUEST['item_param_opts_num']) + && is_array($_REQUEST['item_param_opts_text']) + ) { + if ($_REQUEST['item_type'] == 'PROCEDURE') { + $retval['item_param_dir'] = $_REQUEST['item_param_dir']; + foreach ($retval['item_param_dir'] as $key => $value) { + if (! in_array($value, $param_directions, true)) { + $retval['item_param_dir'][$key] = ''; + } + } + } + $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_Util::getSupportedDatatypes(), true)) { + $retval['item_param_type'][$key] = ''; + } + } + $retval['item_param_length'] = $_REQUEST['item_param_length']; + $retval['item_param_opts_num'] = $_REQUEST['item_param_opts_num']; + $retval['item_param_opts_text'] = $_REQUEST['item_param_opts_text']; + $retval['item_num_params'] = max( + count($retval['item_param_name']), + count($retval['item_param_type']), + count($retval['item_param_length']), + count($retval['item_param_opts_num']), + count($retval['item_param_opts_text']) + ); + } + $retval['item_returntype'] = ''; + if (isset($_REQUEST['item_returntype']) + && in_array($_REQUEST['item_returntype'], PMA_Util::getSupportedDatatypes()) + ) { + $retval['item_returntype'] = $_REQUEST['item_returntype']; + } + + $retval['item_isdeterministic'] = ''; + if (isset($_REQUEST['item_isdeterministic']) + && strtolower($_REQUEST['item_isdeterministic']) == 'on' + ) { + $retval['item_isdeterministic'] = " checked='checked'"; + } + $retval['item_securitytype_definer'] = ''; + $retval['item_securitytype_invoker'] = ''; + if (isset($_REQUEST['item_securitytype'])) { + if ($_REQUEST['item_securitytype'] === 'DEFINER') { + $retval['item_securitytype_definer'] = " selected='selected'"; + } else if ($_REQUEST['item_securitytype'] === 'INVOKER') { + $retval['item_securitytype_invoker'] = " selected='selected'"; + } + } + $retval['item_sqldataaccess'] = ''; + if (isset($_REQUEST['item_sqldataaccess']) + && in_array($_REQUEST['item_sqldataaccess'], $param_sqldataaccess, true) + ) { + $retval['item_sqldataaccess'] = $_REQUEST['item_sqldataaccess']; + } + + return $retval; +} // end 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. + * + * @return array Data necessary to create the routine editor. + */ +function PMA_RTN_getDataFromName($name, $type, $all = true) +{ + global $db; + + $retval = array(); + + // Build and execute the query + $fields = "SPECIFIC_NAME, ROUTINE_TYPE, DTD_IDENTIFIER, " + . "ROUTINE_DEFINITION, IS_DETERMINISTIC, SQL_DATA_ACCESS, " + . "ROUTINE_COMMENT, SECURITY_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); + + if (! $routine) { + return false; + } + + // Get required data + $retval['item_name'] = $routine['SPECIFIC_NAME']; + $retval['item_type'] = $routine['ROUTINE_TYPE']; + $parsed_query = PMA_SQP_parse( + PMA_DBI_get_definition( + $db, + $routine['ROUTINE_TYPE'], + $routine['SPECIFIC_NAME'] + ) + ); + $params = PMA_RTN_parseAllParameters($parsed_query, $routine['ROUTINE_TYPE']); + $retval['item_num_params'] = $params['num']; + $retval['item_param_dir'] = $params['dir']; + $retval['item_param_name'] = $params['name']; + $retval['item_param_type'] = $params['type']; + $retval['item_param_length'] = $params['length']; + $retval['item_param_opts_num'] = $params['opts']; + $retval['item_param_opts_text'] = $params['opts']; + + // Get extra data + if ($all) { + if ($retval['item_type'] == 'FUNCTION') { + $retval['item_type_toggle'] = 'PROCEDURE'; + } else { + $retval['item_type_toggle'] = 'FUNCTION'; + } + $retval['item_returntype'] = ''; + $retval['item_returnlength'] = ''; + $retval['item_returnopts_num'] = ''; + $retval['item_returnopts_text'] = ''; + if (! empty($routine['DTD_IDENTIFIER'])) { + if (strlen($routine['DTD_IDENTIFIER']) > 63) { + // If the DTD_IDENTIFIER string from INFORMATION_SCHEMA is + // at least 64 characters, then it may actually have been + // chopped because that column is a varchar(64), so we will + // parse the output of SHOW CREATE query to get accurate + // information about the return variable. + $dtd = ''; + $fetching = false; + for ($i=0; $i<$parsed_query['len']; $i++) { + if ($parsed_query[$i]['type'] == 'alpha_reservedWord' + && strtoupper($parsed_query[$i]['data']) == 'RETURNS' + ) { + $fetching = true; + } 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 + // characters. We can safely assume that the return + // datatype is either ENUM or SET, so we only look + // for CHARSET. + $word = strtoupper($parsed_query[$i]['data']); + if ($word == 'CHARSET' + && ($parsed_query[$i+1]['type'] == 'alpha_charset' + || $parsed_query[$i+1]['type'] == 'alpha_identifier') + ) { + $dtd .= $word . ' ' . $parsed_query[$i+1]['data']; + } + break; + } else if ($fetching == true) { + $dtd .= $parsed_query[$i]['data'] . ' '; + } + } + $routine['DTD_IDENTIFIER'] = $dtd; + } + $returnparam = PMA_RTN_parseOneParameter($routine['DTD_IDENTIFIER']); + $retval['item_returntype'] = $returnparam[2]; + $retval['item_returnlength'] = $returnparam[3]; + $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_isdeterministic'] = ''; + if ($routine['IS_DETERMINISTIC'] == 'YES') { + $retval['item_isdeterministic'] = " checked='checked'"; + } + $retval['item_securitytype_definer'] = ''; + $retval['item_securitytype_invoker'] = ''; + if ($routine['SECURITY_TYPE'] == 'DEFINER') { + $retval['item_securitytype_definer'] = " selected='selected'"; + } else if ($routine['SECURITY_TYPE'] == 'INVOKER') { + $retval['item_securitytype_invoker'] = " selected='selected'"; + } + $retval['item_sqldataaccess'] = $routine['SQL_DATA_ACCESS']; + $retval['item_comment'] = $routine['ROUTINE_COMMENT']; + } + + return $retval; +} // PMA_RTN_getDataFromName() + +/** + * 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. + * + * @return string HTML code of one row of parameter table for the editor. + */ +function PMA_RTN_getParameterRow($routine = array(), $index = null, $class = '') +{ + global $param_directions, $param_opts_num, $titles; + + if ($index === null) { + // template row for AJAX request + $i = 0; + $index = '%s'; + $drop_class = ''; + $routine = array( + 'item_param_dir' => array(0 => ''), + 'item_param_name' => array(0 => ''), + 'item_param_type' => array(0 => ''), + 'item_param_length' => array(0 => ''), + 'item_param_opts_num' => array(0 => ''), + 'item_param_opts_text' => array(0 => '') + ); + } else if (! empty($routine)) { + // regular row for routine editor + $drop_class = ' hide'; + $i = $index; + } else { + // No input data. This shouldn't happen, + // but better be safe than sorry. + return ''; + } + + // Create the output + $retval = ""; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + + return $retval; +} // end PMA_RTN_getParameterRow() + +/** + * 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() + * + * @return string HTML code for the editor. + */ +function PMA_RTN_getEditorForm($mode, $operation, $routine) +{ + global $db, $errors, $param_sqldataaccess, $param_opts_num; + + // Escape special characters + $need_escape = array( + 'item_original_name', + 'item_name', + 'item_returnlength', + 'item_definition', + 'item_definer', + 'item_comment' + ); + foreach ($need_escape as $key => $index) { + $routine[$index] = htmlentities($routine[$index], ENT_QUOTES, 'UTF-8'); + } + for ($i=0; $i<$routine['item_num_params']; $i++) { + $routine['item_param_name'][$i] = htmlentities( + $routine['item_param_name'][$i], + ENT_QUOTES + ); + $routine['item_param_length'][$i] = htmlentities( + $routine['item_param_length'][$i], + ENT_QUOTES + ); + } + + // Handle some logic first + if ($operation == 'change') { + if ($routine['item_type'] == 'PROCEDURE') { + $routine['item_type'] = 'FUNCTION'; + $routine['item_type_toggle'] = 'PROCEDURE'; + } else { + $routine['item_type'] = 'PROCEDURE'; + $routine['item_type_toggle'] = 'FUNCTION'; + } + } else if ($operation == 'add' + || ($routine['item_num_params'] == 0 && $mode == 'add' && ! $errors) + ) { + $routine['item_param_dir'][] = ''; + $routine['item_param_name'][] = ''; + $routine['item_param_type'][] = ''; + $routine['item_param_length'][] = ''; + $routine['item_param_opts_num'][] = ''; + $routine['item_param_opts_text'][] = ''; + $routine['item_num_params']++; + } else if ($operation == 'remove') { + unset($routine['item_param_dir'][$routine['item_num_params']-1]); + unset($routine['item_param_name'][$routine['item_num_params']-1]); + unset($routine['item_param_type'][$routine['item_num_params']-1]); + unset($routine['item_param_length'][$routine['item_num_params']-1]); + unset($routine['item_param_opts_num'][$routine['item_num_params']-1]); + unset($routine['item_param_opts_text'][$routine['item_num_params']-1]); + $routine['item_num_params']--; + } + $disable_remove_parameter = ''; + if (! $routine['item_num_params']) { + $disable_remove_parameter = " color: gray;' disabled='disabled"; + } + $original_routine = ''; + if ($mode == 'edit') { + $original_routine = "\n" + . "\n"; + } + $isfunction_class = ''; + $isprocedure_class = ''; + $isfunction_select = ''; + $isprocedure_select = ''; + if ($routine['item_type'] == 'PROCEDURE') { + $isfunction_class = ' hide'; + $isprocedure_select = " selected='selected'"; + } else { + $isprocedure_class = ' hide'; + $isfunction_select = " selected='selected'"; + } + + // Create the output + $retval = ""; + $retval .= "\n\n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= $original_routine; + $retval .= PMA_generate_common_hidden_inputs($db) . "\n"; + $retval .= "
      \n"; + $retval .= "" . __('Details') . "\n"; + $retval .= "
      " . __('Event name') . "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "
      " . __('Event type') . "\n"; + if ($GLOBALS['is_ajax_request']) { + $retval .= " \n"; + } else { + $retval .= " \n"; + $retval .= " {$item['item_type']}\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " $value) { + $selected = ""; + if (! empty($item['item_interval_field']) + && $item['item_interval_field'] == $value + ) { + $selected = " selected='selected'"; + } + $retval .= "$value"; + } + $retval .= " \n"; + $retval .= "
      " . _pgettext('Start of recurring event', 'Start'); + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "
      " . __('On completion preserve') . "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + } + $retval .= "\n\n"; + $retval .= "\n\n"; + + return $retval; +} // end PMA_EVN_getEditorForm() + +/** + * Composes the query necessary to create an event from an HTTP request. + * + * @return string The CREATE EVENT query. + */ +function PMA_EVN_getQueryFromRequest() +{ + global $_REQUEST, $errors, $event_status, $event_type, $event_interval; + + $query = 'CREATE '; + if (! empty($_REQUEST['item_definer'])) { + if (strpos($_REQUEST['item_definer'], '@') !== false) { + $arr = explode('@', $_REQUEST['item_definer']); + $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_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 ($_REQUEST['item_type'] == 'RECURRING') { + if (! empty($_REQUEST['item_interval_value']) + && !empty($_REQUEST['item_interval_field']) + && in_array($_REQUEST['item_interval_field'], $event_interval) + ) { + $query .= 'EVERY ' . intval($_REQUEST['item_interval_value']) . ' '; + $query .= $_REQUEST['item_interval_field'] . ' '; + } else { + $errors[] = __('You must provide a valid interval value for the event.'); + } + if (! empty($_REQUEST['item_starts'])) { + $query .= "STARTS '" + . PMA_Util::sqlAddSlashes($_REQUEST['item_starts']) . "' "; + } + if (! empty($_REQUEST['item_ends'])) { + $query .= "ENDS '" + . PMA_Util::sqlAddSlashes($_REQUEST['item_ends']) . "' "; + } + } else { + if (! empty($_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.'); + } + } + } else { + $errors[] = __('You must provide a valid type for the event.'); + } + $query .= 'ON COMPLETION '; + if (empty($_REQUEST['item_preserve'])) { + $query .= 'NOT '; + } + $query .= 'PRESERVE '; + if (! empty($_REQUEST['item_status'])) { + foreach ($event_status['display'] as $key => $value) { + if ($value == $_REQUEST['item_status']) { + $query .= $event_status['query'][$key] . ' '; + break; + } + } + } + if (! empty($_REQUEST['item_comment'])) { + $query .= "COMMENT '" . PMA_Util::sqlAddslashes( + $_REQUEST['item_comment'] + ) . "' "; + } + $query .= 'DO '; + if (! empty($_REQUEST['item_definition'])) { + $query .= $_REQUEST['item_definition']; + } else { + $errors[] = __('You must provide an event definition.'); + } + + return $query; +} // end PMA_EVN_getQueryFromRequest() + +?> diff --git a/phpmyadmin/libraries/rte/rte_export.lib.php b/phpmyadmin/libraries/rte/rte_export.lib.php new file mode 100644 index 000000000..a553ae9be --- /dev/null +++ b/phpmyadmin/libraries/rte/rte_export.lib.php @@ -0,0 +1,122 @@ +' + . htmlspecialchars(trim($export_data)) . ''; + $title = sprintf(PMA_RTE_getWord('export'), $item_name); + if ($GLOBALS['is_ajax_request'] == true) { + $response = PMA_Response::getInstance(); + $response->addJSON('message', $export_data); + $response->addJSON('title', $title); + exit; + } else { + echo "
      \n" + . "$title\n" + . $export_data + . "
      \n"; + } + } else { + $_db = htmlspecialchars(PMA_Util::backquote($db)); + $response = __('Error in Processing Request') . ' : ' + . sprintf(PMA_RTE_getWord('not_found'), $item_name, $_db); + $response = PMA_message::error($response); + if ($GLOBALS['is_ajax_request'] == true) { + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', $response); + exit; + } else { + $response->display(); + } + } +} // end PMA_RTE_handleExport() + +/** + * If necessary, prepares event information and passes + * it to PMA_RTE_handleExport() for the actual export. + * + * @return void + */ +function PMA_EVN_handleExport() +{ + global $_GET, $db; + + if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) { + $item_name = $_GET['item_name']; + $export_data = PMA_DBI_get_definition($db, 'EVENT', $item_name); + PMA_RTE_handleExport($item_name, $export_data); + } +} // end 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() +{ + global $_GET, $db; + + if ( ! empty($_GET['export_item']) + && ! empty($_GET['item_name']) + && ! empty($_GET['item_type']) + ) { + if ($_GET['item_type'] == 'FUNCTION' || $_GET['item_type'] == 'PROCEDURE') { + $export_data = PMA_DBI_get_definition( + $db, + $_GET['item_type'], + $_GET['item_name'] + ); + PMA_RTE_handleExport($_GET['item_name'], $export_data); + } + } +} // end 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() +{ + global $_GET, $db, $table; + + if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) { + $item_name = $_GET['item_name']; + $triggers = PMA_DBI_get_triggers($db, $table, ''); + $export_data = false; + foreach ($triggers as $trigger) { + if ($trigger['name'] === $item_name) { + $export_data = $trigger['create']; + break; + } + } + PMA_RTE_handleExport($item_name, $export_data); + } +} // end PMA_TRI_handleExport() +?> diff --git a/phpmyadmin/libraries/rte/rte_footer.lib.php b/phpmyadmin/libraries/rte/rte_footer.lib.php new file mode 100644 index 000000000..88d31d35a --- /dev/null +++ b/phpmyadmin/libraries/rte/rte_footer.lib.php @@ -0,0 +1,127 @@ +\n"; + $retval .= "
      \n"; + $retval .= " " . _pgettext('Create new procedure', 'New') . "\n"; + $retval .= " \n"; + $retval .= "
      \n"; + $retval .= "\n\n"; + + return $retval; +} // end PMA_RTE_getFooterLinks() + +/** + * Creates a fieldset for adding a new routine, if the user has the privileges. + * + * @return string HTML code with containing the fotter fieldset + */ +function PMA_RTN_getFooterLinks() +{ + return PMA_RTE_getFooterLinks('CREATE_PROCEDURE', 'CREATE ROUTINE', 'ROUTINE'); +}// end 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 + */ +function PMA_TRI_getFooterLinks() +{ + return PMA_RTE_getFooterLinks('CREATE_TRIGGER', 'TRIGGER', 'TRIGGER'); +} // end 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 + */ +function PMA_EVN_getFooterLinks() +{ + global $db, $url_query; + + /** + * For events, we show the usual 'Add event' form and also + * a form for toggling the state of the event scheduler + */ + // Init options for the event scheduler toggle functionality + $es_state = PMA_DBI_fetch_value( + "SHOW GLOBAL VARIABLES LIKE 'event_scheduler'", + 0, + 1 + ); + $es_state = strtolower($es_state); + $options = array( + 0 => array( + 'label' => __('OFF'), + 'value' => "SET GLOBAL event_scheduler=\"OFF\"", + 'selected' => ($es_state != 'on') + ), + 1 => array( + 'label' => __('ON'), + 'value' => "SET GLOBAL event_scheduler=\"ON\"", + 'selected' => ($es_state == 'on') + ) + ); + // Generate output + $retval = "\n"; + $retval .= "
      \n"; + // show the usual footer + $retval .= PMA_RTE_getFooterLinks('CREATE_EVENT', 'EVENT', 'EVENT'); + $retval .= "
      \n"; + $retval .= " \n"; + $retval .= " " . __('Event scheduler status') . "\n"; + $retval .= " \n"; + $retval .= "
      \n"; + // show the toggle button + $retval .= PMA_Util::toggleButton( + "sql.php?$url_query&goto=db_events.php" . urlencode("?db=$db"), + 'sql_query', + $options, + 'PMA_slidingMessage(data.sql_query);' + ); + $retval .= "
      \n"; + $retval .= "
      \n"; + $retval .= "
      \n"; + $retval .= "
      "; + $retval .= "\n"; + + return $retval; +} // end PMA_EVN_getFooterLinks() + +?> diff --git a/phpmyadmin/libraries/rte/rte_list.lib.php b/phpmyadmin/libraries/rte/rte_list.lib.php new file mode 100644 index 000000000..d531cd86f --- /dev/null +++ b/phpmyadmin/libraries/rte/rte_list.lib.php @@ -0,0 +1,366 @@ +\n"; + $retval .= "
      \n"; + $retval .= " \n"; + $retval .= " " . PMA_RTE_getWord('title') . "\n"; + $retval .= " " . PMA_Util::showMySQLDocu('SQL-Syntax', PMA_RTE_getWord('docu')) . "\n"; + $retval .= " \n"; + $retval .= "
      \n"; + $retval .= " " . PMA_RTE_getWord('nothing') . "\n"; + $retval .= "
      \n"; + $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"; + if (empty($table)) { + $retval .= " \n"; + } + $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; + } + $retval .= " \n"; + $retval .= " \n"; + $ct = 0; + foreach ($items as $item) { + $rowclass = ($ct % 2 == 0) ? 'odd' : 'even'; + if ($GLOBALS['is_ajax_request'] && empty($_REQUEST['ajax_page_request'])) { + $rowclass .= ' ajaxInsert hide'; + } + // Get each row from the correct function + switch ($type) { + case 'routine': + $retval .= PMA_RTN_getRowForList($item, $rowclass); + break; + case 'trigger': + $retval .= PMA_TRI_getRowForList($item, $rowclass); + break; + case 'event': + $retval .= PMA_EVN_getRowForList($item, $rowclass); + break; + default: + break; + } + $ct++; + } + $retval .= "
      " . __('Name') . "" . __('Action') . "" . __('Type') . "" . __('Returns') . "
      " . __('Name') . "" . __('Table') . "" . __('Action') . "" . __('Time') . "" . __('Event') . "
      " . __('Name') . "" . __('Status') . "" . __('Action') . "" . __('Type') . "
      \n"; + $retval .= "
      \n"; + $retval .= "\n"; + + return $retval; +} // end PMA_RTE_getList() + +/** + * 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'] + * + * @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_Util::backquote($routine['SPECIFIC_NAME']) + ); + $type_link = "item_type={$routine['ROUTINE_TYPE']}"; + + $retval = "
      \n"; + $retval .= " " . htmlspecialchars($sql_drop) . "\n"; + $retval .= " \n"; + $retval .= " " . htmlspecialchars($routine['SPECIFIC_NAME']) . "\n"; + $retval .= " \n"; + $retval .= " \n"; + if ($routine['ROUTINE_DEFINITION'] !== null + && PMA_Util::currentUserHasPrivilege('ALTER ROUTINE', $db) + && PMA_Util::currentUserHasPrivilege('CREATE ROUTINE', $db) + ) { + $retval .= ' ' . $titles['Edit'] . "\n"; + } else { + $retval .= " {$titles['NoEdit']}\n"; + } + $retval .= " \n"; + if ($routine['ROUTINE_DEFINITION'] !== null + && PMA_Util::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; + } + $retval .= ' ' . $titles['Execute'] . "\n"; + } + } else { + $retval .= " {$titles['NoExecute']}\n"; + } + $retval .= " \n"; + $retval .= ' ' . $titles['Export'] . "\n"; + $retval .= " \n"; + if (PMA_Util::currentUserHasPrivilege('ALTER ROUTINE', $db)) { + $retval .= ' ' . $titles['Drop'] . "\n"; + } else { + $retval .= " {$titles['NoDrop']}\n"; + } + $retval .= " \n"; + $retval .= " {$routine['ROUTINE_TYPE']}\n"; + $retval .= " \n"; + $retval .= " " . htmlspecialchars($routine['DTD_IDENTIFIER']) . "\n"; + $retval .= "
      \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_Util::currentUserHasPrivilege('TRIGGER', $db, $table)) { + $retval .= ' ' . $titles['Edit'] . "\n"; + } else { + $retval .= " {$titles['NoEdit']}\n"; + } + $retval .= " \n"; + $retval .= ' ' . $titles['Export'] . "\n"; + $retval .= " \n"; + if (PMA_Util::currentUserHasPrivilege('TRIGGER', $db)) { + $retval .= ' ' . $titles['Drop'] . "\n"; + } else { + $retval .= " {$titles['NoDrop']}\n"; + } + $retval .= " \n"; + $retval .= " {$trigger['action_timing']}\n"; + $retval .= " \n"; + $retval .= " {$trigger['event_manipulation']}\n"; + $retval .= "
      \n"; + $retval .= " " . htmlspecialchars($sql_drop) . "\n"; + $retval .= " \n"; + $retval .= " " . htmlspecialchars($event['EVENT_NAME']) . "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " {$event['STATUS']}\n"; + $retval .= " \n"; + if (PMA_Util::currentUserHasPrivilege('EVENT', $db)) { + $retval .= ' ' . $titles['Edit'] . "\n"; + } else { + $retval .= " {$titles['NoEdit']}\n"; + } + $retval .= " \n"; + $retval .= ' ' . $titles['Export'] . "\n"; + $retval .= " \n"; + if (PMA_Util::currentUserHasPrivilege('EVENT', $db)) { + $retval .= ' ' . $titles['Drop'] . "\n"; + } else { + $retval .= " {$titles['NoDrop']}\n"; + } + $retval .= " \n"; + $retval .= " {$event['EVENT_TYPE']}\n"; + $retval .= "
      \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " ---\n"; + $retval .= PMA_generateCharsetDropdownBox( + PMA_CSDROPDOWN_CHARSET, + "item_param_opts_text[$index]", + null, + $routine['item_param_opts_text'][$i] + ); + $retval .= " ---\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " {$titles['Drop']}\n"; + $retval .= " \n"; + $retval .= "
      \n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + // parameter handling end + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= "
      " . __('Routine name') . "\n"; + $retval .= " \n"; + if ($GLOBALS['is_ajax_request']) { + $retval .= " \n"; + } else { + $retval .= "\n" + . "
      \n" + . $routine['item_type'] . "\n" + . "
      \n" + . "\n"; + } + $retval .= "
      " . __('Parameters') . "\n"; + // parameter handling start + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " "; + for ($i=0; $i<$routine['item_num_params']; $i++) { // each parameter + $retval .= PMA_RTN_getParameterRow($routine, $i, $isprocedure_class); + } + $retval .= "
      " + . __('Direction') . "" . __('Name') . "" . __('Type') . "" . __('Length/Values') . "" . __('Options') . " 
      \n"; + $retval .= "
       \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "
      " . __('Return type') . "
      " . __('Return length/values') . "\n"; + $retval .= "
      \n"; + $retval .= PMA_generateCharsetDropdownBox( + PMA_CSDROPDOWN_CHARSET, + "item_returnopts_text", + null, + $routine['item_returnopts_text'] + ); + $retval .= "\n
      \n"; + $retval .= "
      \n"; + $retval .= "
      ---
      \n"; + $retval .= "
      " . __('Definition') . "
      " . __('Is deterministic') . "
      " . __('Definer') . "\n"; + $retval .= "
      " . __('SQL data access') . "
      " . __('Comment') . "\n"; + $retval .= "\n"; + } + $retval .= "\n\n"; + $retval .= "\n\n"; + + return $retval; +} // end PMA_RTN_getEditorForm() + +/** + * Composes the query necessary to create a routine from an HTTP request. + * + * @return string The CREATE [ROUTINE | PROCEDURE] query. + */ +function PMA_RTN_getQueryFromRequest() +{ + global $_REQUEST, $errors, $param_sqldataaccess, $param_directions; + + $_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_Util::backquote($arr[0]); + $query .= '@' . PMA_Util::backquote($arr[1]) . ' '; + } else { + $errors[] = __('The definer must be in the "username@hostname" format'); + } + } + if ($_REQUEST['item_type'] == 'FUNCTION' + || $_REQUEST['item_type'] == 'PROCEDURE' + ) { + $query .= $_REQUEST['item_type'] . ' '; + } else { + $errors[] = sprintf( + __('Invalid routine type: "%s"'), + htmlspecialchars($_REQUEST['item_type']) + ); + } + if (! empty($_REQUEST['item_name'])) { + $query .= PMA_Util::backquote($_REQUEST['item_name']); + } else { + $errors[] = __('You must provide a routine name'); + } + $params = ''; + $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']) + && is_array($_REQUEST['item_param_name']) + && is_array($_REQUEST['item_param_type']) + && is_array($_REQUEST['item_param_length']) + ) { + for ($i=0; $igetTypeClass($_REQUEST['item_param_type'][$i]) == 'CHAR') { + $params .= ' CHARSET ' + . strtolower($_REQUEST['item_param_opts_text'][$i]); + } + } + if (! empty($_REQUEST['item_param_opts_num'][$i])) { + if ($GLOBALS['PMA_Types']->getTypeClass($_REQUEST['item_param_type'][$i]) == 'NUMBER') { + $params .= ' ' + . strtoupper($_REQUEST['item_param_opts_num'][$i]); + } + } + if ($i != count($_REQUEST['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.' + ); + break; + } + } + } + $query .= "(" . $params . ") "; + if ($_REQUEST['item_type'] == 'FUNCTION') { + if (! empty($_REQUEST['item_returntype']) + && in_array( + $_REQUEST['item_returntype'], PMA_Util::getSupportedDatatypes() + ) + ) { + $query .= "RETURNS {$_REQUEST['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'] + ) + ) { + $query .= "(" . $_REQUEST['item_returnlength'] . ")"; + } else if (empty($_REQUEST['item_returnlength']) + && preg_match( + '@^(ENUM|SET|VARCHAR|VARBINARY)$@i', $_REQUEST['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.' + ); + } + } + if (! empty($_REQUEST['item_returnopts_text'])) { + if ($GLOBALS['PMA_Types']->getTypeClass($_REQUEST['item_returntype']) == 'CHAR') { + $query .= ' CHARSET ' + . strtolower($_REQUEST['item_returnopts_text']); + } + } + if (! empty($_REQUEST['item_returnopts_num'])) { + if ($GLOBALS['PMA_Types']->getTypeClass($_REQUEST['item_returntype']) == 'NUMBER') { + $query .= ' ' . strtoupper($_REQUEST['item_returnopts_num']); + } + } + $query .= ' '; + } + if (! empty($_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) + ) { + $query .= $_REQUEST['item_sqldataaccess'] . ' '; + } + if (! empty($_REQUEST['item_securitytype'])) { + if ($_REQUEST['item_securitytype'] == 'DEFINER' + || $_REQUEST['item_securitytype'] == 'INVOKER' + ) { + $query .= 'SQL SECURITY ' . $_REQUEST['item_securitytype'] . ' '; + } + } + if (! empty($_REQUEST['item_definition'])) { + $query .= $_REQUEST['item_definition']; + } else { + $errors[] = __('You must provide a routine definition.'); + } + + return $query; +} // end PMA_RTN_getQueryFromRequest() + +/** + * Handles requests for executing a routine + * + * @return Does not return + */ +function PMA_RTN_handleExecute() +{ + 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 + ); + 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_Util::sqlAddSlashes($value); + if (! empty($_REQUEST['funcs'][$routine['item_param_name'][$i]]) + && in_array( + $_REQUEST['funcs'][$routine['item_param_name'][$i]], + $all_functions + ) + ) { + $queries[] = "SET @p$i=" + . $_REQUEST['funcs'][$routine['item_param_name'][$i]] + . "('$value');\n"; + } else { + $queries[] = "SET @p$i='$value';\n"; + } + $args[] = "@p$i"; + } else { + $args[] = "@p$i"; + } + if ($routine['item_type'] == 'PROCEDURE') { + if ($routine['item_param_dir'][$i] == 'OUT' + || $routine['item_param_dir'][$i] == 'INOUT' + ) { + $end_query[] = "@p$i AS " + . PMA_Util::backquote($routine['item_param_name'][$i]); + } + } + } + if ($routine['item_type'] == 'PROCEDURE') { + $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_Util::backquote($routine['item_name']) + . "(" . implode(', ', $args) . ") " + . "AS " . PMA_Util::backquote($routine['item_name']) + . ";\n"; + } + + // Get all the queries as one SQL statement + $multiple_query = implode("", $queries); + + $outcome = true; + $affected = 0; + + // Execute query + if (! PMA_DBI_try_multi_query($multiple_query)) { + $outcome = false; + } + + // Generate output + if ($outcome) { + + // Pass the SQL queries through the "pretty printer" + $output = ''; + $output .= PMA_SQP_formatHtml(PMA_SQP_parse(implode($queries))); + $output .= ''; + + // 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 = PMA_DBI_store_result(); + $num_rows = PMA_DBI_num_rows($result); + + if (($result !== false) && ($num_rows > 0)) { + + $output .= ""; + foreach (PMA_DBI_get_fields_meta($result) as $key => $field) { + $output .= ""; + } + $output .= ""; + + $color_class = 'odd'; + + while ($row = PMA_DBI_fetch_assoc($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 (! PMA_DBI_more_results()) { + break; + } + + $output .= "
      "; + + PMA_DBI_free_result($result); + + } while (PMA_DBI_next_result()); + + $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', + '%d rows affected by the last statement inside the procedure', + $affected + ), + $affected + ); + } + $message = PMA_message::success($message); + + if ($num_of_rusults_set_to_display == 0) { + $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($multiple_query) + ) + . '

      ' + . __('MySQL said: ') . PMA_DBI_getError(null) + ); + } + + // Print/send output + if ($GLOBALS['is_ajax_request']) { + $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()) { + // At least one query has failed, so shouldn't + // execute any more queries, so we quit. + exit; + } + unset($_POST); + // Now deliberately fall through to displaying the routines list + } + } else { + $message = __('Error in processing request') . ' : '; + $message .= sprintf( + PMA_RTE_getWord('not_found'), + htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(PMA_Util::backquote($db)) + ); + $message = PMA_message::error($message); + if ($GLOBALS['is_ajax_request']) { + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', $message); + exit; + } else { + echo $message->getDisplay(); + unset($_POST); + } + } + } else if (! empty($_GET['execute_dialog']) && ! empty($_GET['item_name'])) { + /** + * Display the execute form for a routine. + */ + $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) { + $title = __("Execute routine") . " " . PMA_Util::backquote( + htmlentities($_GET['item_name'], ENT_QUOTES) + ); + $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; + } + exit; + } else if (($GLOBALS['is_ajax_request'] == true)) { + $message = __('Error in processing request') . ' : '; + $message .= sprintf( + PMA_RTE_getWord('not_found'), + htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(PMA_Util::backquote($db)) + ); + $message = PMA_message::error($message); + + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', $message); + exit; + } + } +} + +/** + * Creates the HTML code that shows the routine execution dialog. + * + * @param array $routine Data for the routine returned by + * PMA_RTN_getDataFromName() + * + * @return string HTML code for the routine execution dialog. + */ +function PMA_RTN_getExecuteForm($routine) +{ + global $db, $cfg; + + // Escape special characters + $routine['item_name'] = htmlentities($routine['item_name'], ENT_QUOTES); + for ($i=0; $i<$routine['item_num_params']; $i++) { + $routine['item_param_name'][$i] = htmlentities( + $routine['item_param_name'][$i], + ENT_QUOTES + ); + } + + // Create the output + $retval = ""; + $retval .= "\n\n"; + $retval .= "
      \n"; + $retval .= "\n"; + $retval .= "\n"; + } + $retval .= "\n"; + $retval .= "\n"; + $retval .= "\n"; + if ($cfg['ShowFunctionFields']) { + $retval .= "\n"; + } + $retval .= "\n"; + $retval .= "\n"; + // Get a list of data types that are not yet supported. + $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' + ) { + continue; + } + $rowclass = ($i % 2 == 0) ? 'even' : 'odd'; + $retval .= "\n\n"; + $retval .= "\n"; + $retval .= "\n"; + if ($cfg['ShowFunctionFields']) { + $retval .= "\n"; + } + // Append a class to date/time fields so that + // jQuery can attach a datepicker to them + $class = ''; + if ($routine['item_param_type'][$i] == 'DATETIME' + || $routine['item_param_type'][$i] == 'TIMESTAMP' + ) { + $class = 'datetimefield'; + } else if ($routine['item_param_type'][$i] == 'DATE') { + $class = 'datefield'; + } + $retval .= "\n"; + $retval .= "\n"; + } + $retval .= "\n
      " . __('Name') . "" . __('Type') . "" . __('Function') . "" . __('Value') . "
      {$routine['item_param_name'][$i]}{$routine['item_param_type'][$i]}\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 + ) + ) { + $retval .= "--\n"; + } else { + $field = array( + 'True_Type' => strtolower($routine['item_param_type'][$i]), + 'Type' => '', + 'Key' => '', + 'Field' => '', + 'Default' => '', + 'first_timestamp' => false + ); + $retval .= ""; + } + $retval .= "\n"; + if (in_array($routine['item_param_type'][$i], array('ENUM', 'SET'))) { + $tokens = PMA_SQP_parse($routine['item_param_length'][$i]); + if ($routine['item_param_type'][$i] == 'ENUM') { + $input_type = 'radio'; + } else { + $input_type = 'checkbox'; + } + for ($j=0; $j<$tokens['len']; $j++) { + if ($tokens[$j]['type'] != 'punct_listsep') { + $tokens[$j]['data'] = htmlentities( + PMA_Util::unquote($tokens[$j]['data']), + ENT_QUOTES + ); + $retval .= "" + . "{$tokens[$j]['data']}
      \n"; + } + } + } else if (in_array( + strtolower($routine['item_param_type'][$i]), $no_support_types + )) { + $retval .= "\n"; + } else { + $retval .= "\n"; + } + $retval .= "
      \n"; + if ($GLOBALS['is_ajax_request'] != true) { + $retval .= "\n\n"; + $retval .= "
      \n"; + $retval .= " \n"; + $retval .= "
      \n"; + } else { + $retval .= ""; + $retval .= ""; + } + $retval .= "
      \n\n"; + $retval .= "\n\n"; + + return $retval; +} // end PMA_RTN_getExecuteForm() + +?> diff --git a/phpmyadmin/libraries/rte/rte_triggers.lib.php b/phpmyadmin/libraries/rte/rte_triggers.lib.php new file mode 100644 index 000000000..504eb9824 --- /dev/null +++ b/phpmyadmin/libraries/rte/rte_triggers.lib.php @@ -0,0 +1,486 @@ +' + . __('MySQL said: ') . PMA_DBI_getError(null); + } else { + $result = PMA_DBI_try_query($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); + if (! $result) { + // 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. + $errors[] = __( + 'Sorry, we failed to restore the dropped trigger.' + ) + . '
      ' + . __('The backed up query was:') + . "\"" . htmlspecialchars($create_item) . "\"" + . '
      ' + . __('MySQL said: ') . PMA_DBI_getError(null); + } + } else { + $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); + if (! $result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($item_query) + ) + . '

      ' + . __('MySQL said: ') . PMA_DBI_getError(null); + } else { + $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->addString('
        '); + foreach ($errors as $string) { + $message->addString('
      • ' . $string . '
      • '); + } + $message->addString('
      '); + } + + $output = PMA_Util::getMessage($message, $sql_query); + if ($GLOBALS['is_ajax_request']) { + $response = PMA_Response::getInstance(); + if ($message->isSuccess()) { + $items = PMA_DBI_get_triggers($db, $table, ''); + $trigger = false; + foreach ($items as $value) { + if ($value['name'] == $_REQUEST['item_name']) { + $trigger = $value; + } + } + $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->addJSON('insert', $insert); + $response->addJSON('message', $output); + } else { + $response->addJSON('message', $message); + $response->isSuccess(false); + } + 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 + ) { + // Get the data for the form (if any) + if (! empty($_REQUEST['add_item'])) { + $title = PMA_RTE_getWord('add'); + $item = PMA_TRI_getDataFromRequest(); + $mode = 'add'; + } else if (! empty($_REQUEST['edit_item'])) { + $title = __("Edit trigger"); + if (! empty($_REQUEST['item_name']) + && empty($_REQUEST['editor_process_edit']) + ) { + $item = PMA_TRI_getDataFromName($_REQUEST['item_name']); + if ($item !== false) { + $item['item_original_name'] = $item['item_name']; + } + } else { + $item = PMA_TRI_getDataFromRequest(); + } + $mode = 'edit'; + } + if ($item !== false) { + // Show form + $editor = PMA_TRI_getEditorForm($mode, $item); + if ($GLOBALS['is_ajax_request']) { + $response = PMA_Response::getInstance(); + $response->addJSON('message', $editor); + $response->addJSON('title', $title); + } else { + echo "\n\n

      $title

      \n\n$editor"; + unset($_POST); + } + exit; + } else { + $message = __('Error in processing request') . ' : '; + $message .= sprintf( + PMA_RTE_getWord('not_found'), + htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(PMA_Util::backquote($db)) + ); + $message = PMA_message::error($message); + if ($GLOBALS['is_ajax_request']) { + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', $message); + exit; + } else { + $message->display(); + } + } + } +} // end PMA_TRI_handleEditor() + +/** + * This function will generate the values that are required to for the editor + * + * @return array Data necessary to create the editor. + */ +function PMA_TRI_getDataFromRequest() +{ + $retval = array(); + $indices = array('item_name', + 'item_table', + 'item_original_name', + 'item_action_timing', + 'item_event_manipulation', + 'item_definition', + 'item_definer'); + foreach ($indices as $index) { + $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : ''; + } + return $retval; +} // end 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. + * + * @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, ''); + foreach ($items as $value) { + if ($value['name'] == $name) { + $temp = $value; + } + } + if (empty($temp)) { + return false; + } else { + $retval = array(); + $retval['create'] = $temp['create']; + $retval['drop'] = $temp['drop']; + $retval['item_name'] = $temp['name']; + $retval['item_table'] = $temp['table']; + $retval['item_action_timing'] = $temp['action_timing']; + $retval['item_event_manipulation'] = $temp['event_manipulation']; + $retval['item_definition'] = $temp['definition']; + $retval['item_definer'] = $temp['definer']; + return $retval; + } +} // end PMA_TRI_getDataFromName() + +/** + * 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() + * + * @return string HTML code for the editor. + */ +function PMA_TRI_getEditorForm($mode, $item) +{ + global $db, $table, $event_manipulations, $action_timings; + + // Escape special characters + $need_escape = array( + 'item_original_name', + 'item_name', + 'item_definition', + 'item_definer' + ); + foreach ($need_escape as $key => $index) { + $item[$index] = htmlentities($item[$index], ENT_QUOTES, 'UTF-8'); + } + $original_data = ''; + if ($mode == 'edit') { + $original_data = "\n"; + } + $query = "SELECT `TABLE_NAME` FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='" . PMA_Util::sqlAddSlashes($db) . "' "; + $query .= "AND `TABLE_TYPE`='BASE TABLE'"; + $tables = PMA_DBI_fetch_result($query); + + // Create the output + $retval = ""; + $retval .= "\n\n"; + $retval .= "
      \n"; + $retval .= "\n"; + $retval .= $original_data; + $retval .= PMA_generate_common_hidden_inputs($db, $table) . "\n"; + $retval .= "
      \n"; + $retval .= "" . __('Details') . "\n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= "
      " . __('Trigger name') . "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "
      " . _pgettext('Trigger action time', 'Time') . "
      " . __('Event') . "
      " . __('Definition') . "
      " . __('Definer') . "\n"; + $retval .= "\n"; + } + $retval .= "\n\n"; + $retval .= "\n\n"; + + return $retval; +} // end PMA_TRI_getEditorForm() + +/** + * Composes the query necessary to create a trigger from an HTTP request. + * + * @return string The CREATE TRIGGER query. + */ +function PMA_TRI_getQueryFromRequest() +{ + global $_REQUEST, $db, $errors, $action_timings, $event_manipulations; + + $query = 'CREATE '; + if (! empty($_REQUEST['item_definer'])) { + if (strpos($_REQUEST['item_definer'], '@') !== false) { + $arr = explode('@', $_REQUEST['item_definer']); + $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_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) + ) { + $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) + ) { + $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_Util::backquote($_REQUEST['item_table']); + } else { + $errors[] = __('You must provide a valid table name'); + } + $query .= ' FOR EACH ROW '; + if (! empty($_REQUEST['item_definition'])) { + $query .= $_REQUEST['item_definition']; + } else { + $errors[] = __('You must provide a trigger definition.'); + } + + return $query; +} // end PMA_TRI_getQueryFromRequest() + +?> diff --git a/phpmyadmin/libraries/rte/rte_words.lib.php b/phpmyadmin/libraries/rte/rte_words.lib.php new file mode 100644 index 000000000..2aabfde67 --- /dev/null +++ b/phpmyadmin/libraries/rte/rte_words.lib.php @@ -0,0 +1,64 @@ + __('Add routine'), + 'docu' => 'STORED_ROUTINES', + 'export' => __('Export of routine %s'), + 'human' => __('routine'), + 'no_create' => __('You do not have the necessary privileges to create a routine'), + 'not_found' => __('No routine with name %1$s found in database %2$s'), + 'nothing' => __('There are no routines to display.'), + 'title' => __('Routines'), + ); + break; + case 'TRI': + $words = array( + 'add' => __('Add trigger'), + 'docu' => 'TRIGGERS', + 'export' => __('Export of trigger %s'), + 'human' => __('trigger'), + 'no_create' => __('You do not have the necessary privileges to create a trigger'), + 'not_found' => __('No trigger with name %1$s found in database %2$s'), + 'nothing' => __('There are no triggers to display.'), + 'title' => __('Triggers'), + ); + break; + case 'EVN': + $words = array( + 'add' => __('Add event'), + 'docu' => 'EVENTS', + 'export' => __('Export of event %s'), + 'human' => __('event'), + 'no_create' => __('You do not have the necessary privileges to create an event'), + 'not_found' => __('No event with name %1$s found in database %2$s'), + 'nothing' => __('There are no events to display.'), + 'title' => __('Events'), + ); + break; + default: + $words = array(); + break; + } + + return isset($words[$index]) ? $words[$index] : ''; +} // end PMA_RTE_getWord() + +?> diff --git a/phpmyadmin/libraries/sanitizing.lib.php b/phpmyadmin/libraries/sanitizing.lib.php new file mode 100644 index 000000000..edfb39774 --- /dev/null +++ b/phpmyadmin/libraries/sanitizing.lib.php @@ -0,0 +1,190 @@ +'; +} + +/** + * 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. + * + * If you want to include result in element attribute, you should escape it. + * + * Examples: + * + *

      + * + *
      bar + * + * @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 + */ +function PMA_sanitize($message, $escape = false, $safe = false) +{ + if (!$safe) { + $message = strtr($message, array('<' => '<', '>' => '>')); + } + + /* Interpret bb code */ + $replace_pairs = array( + '[em]' => '', + '[/em]' => '', + '[strong]' => '', + '[/strong]' => '', + '[code]' => '', + '[/code]' => '', + '[kbd]' => '', + '[/kbd]' => '', + '[br]' => '
      ', + '[/a]' => '', + '[/doc]' => '', + '[sup]' => '', + '[/sup]' => '', + // used in common.inc.php: + '[conferr]' => '