From 5bf66662a9bdd62c5bccab15e607cd95cfb8fcab Mon Sep 17 00:00:00 2001 From: Charles Cabergs Date: Mon, 27 Jul 2020 10:05:23 +0200 Subject: Removed wordpress and phpmyadmin, my server doesn't handle it well and it brings shame on my familly --- srcs/phpmyadmin/libraries/classes/Advisor.php | 707 --- srcs/phpmyadmin/libraries/classes/Bookmark.php | 395 -- .../libraries/classes/BrowseForeigners.php | 361 -- .../libraries/classes/CentralColumns.php | 1207 ----- srcs/phpmyadmin/libraries/classes/Charsets.php | 210 - .../libraries/classes/Charsets/Charset.php | 103 - .../libraries/classes/Charsets/Collation.php | 549 -- .../libraries/classes/CheckUserPrivileges.php | 372 -- srcs/phpmyadmin/libraries/classes/Config.php | 1813 ------- .../libraries/classes/Config/ConfigFile.php | 531 -- .../libraries/classes/Config/Descriptions.php | 934 ---- srcs/phpmyadmin/libraries/classes/Config/Form.php | 238 - .../libraries/classes/Config/FormDisplay.php | 924 ---- .../classes/Config/FormDisplayTemplate.php | 526 -- .../libraries/classes/Config/Forms/BaseForm.php | 89 - .../classes/Config/Forms/BaseFormList.php | 150 - .../classes/Config/Forms/Page/BrowseForm.php | 30 - .../classes/Config/Forms/Page/DbStructureForm.php | 30 - .../classes/Config/Forms/Page/EditForm.php | 32 - .../classes/Config/Forms/Page/ExportForm.php | 18 - .../classes/Config/Forms/Page/ImportForm.php | 18 - .../classes/Config/Forms/Page/NaviForm.php | 18 - .../classes/Config/Forms/Page/PageFormList.php | 37 - .../classes/Config/Forms/Page/SqlForm.php | 18 - .../Config/Forms/Page/TableStructureForm.php | 30 - .../classes/Config/Forms/Setup/ConfigForm.php | 32 - .../classes/Config/Forms/Setup/ExportForm.php | 18 - .../classes/Config/Forms/Setup/FeaturesForm.php | 77 - .../classes/Config/Forms/Setup/ImportForm.php | 18 - .../classes/Config/Forms/Setup/MainForm.php | 29 - .../classes/Config/Forms/Setup/NaviForm.php | 18 - .../classes/Config/Forms/Setup/ServersForm.php | 116 - .../classes/Config/Forms/Setup/SetupFormList.php | 37 - .../classes/Config/Forms/Setup/SqlForm.php | 28 - .../classes/Config/Forms/User/ExportForm.php | 160 - .../classes/Config/Forms/User/FeaturesForm.php | 95 - .../classes/Config/Forms/User/ImportForm.php | 73 - .../classes/Config/Forms/User/MainForm.php | 98 - .../classes/Config/Forms/User/NaviForm.php | 74 - .../classes/Config/Forms/User/SqlForm.php | 54 - .../classes/Config/Forms/User/UserFormList.php | 35 - .../libraries/classes/Config/PageSettings.php | 233 - .../classes/Config/ServerConfigChecks.php | 583 -- .../classes/Config/SpecialSchemaLinks.php | 478 -- .../libraries/classes/Config/Validator.php | 594 -- srcs/phpmyadmin/libraries/classes/Console.php | 158 - .../classes/Controllers/AbstractController.php | 51 - .../classes/Controllers/AjaxController.php | 97 - .../Controllers/BrowseForeignersController.php | 82 - .../Controllers/Database/AbstractController.php | 42 - .../Database/CentralColumnsController.php | 195 - .../Database/DataDictionaryController.php | 156 - .../Controllers/Database/EventsController.php | 43 - .../Database/MultiTableQueryController.php | 61 - .../Controllers/Database/RoutinesController.php | 44 - .../classes/Controllers/Database/SqlController.php | 49 - .../Controllers/Database/StructureController.php | 1088 ---- .../Controllers/Database/TriggersController.php | 43 - .../classes/Controllers/HomeController.php | 517 -- .../Controllers/Server/BinlogController.php | 149 - .../Controllers/Server/CollationsController.php | 100 - .../Controllers/Server/DatabasesController.php | 424 -- .../Controllers/Server/EnginesController.php | 69 - .../Controllers/Server/PluginsController.php | 77 - .../Controllers/Server/ReplicationController.php | 72 - .../classes/Controllers/Server/SqlController.php | 34 - .../Server/Status/AbstractController.php | 42 - .../Server/Status/AdvisorController.php | 60 - .../Server/Status/MonitorController.php | 146 - .../Server/Status/ProcessesController.php | 240 - .../Server/Status/QueriesController.php | 75 - .../Controllers/Server/Status/StatusController.php | 260 - .../Server/Status/VariablesController.php | 639 --- .../Controllers/Server/VariablesController.php | 238 - .../Controllers/Setup/AbstractController.php | 70 - .../classes/Controllers/Setup/ConfigController.php | 55 - .../classes/Controllers/Setup/FormController.php | 50 - .../classes/Controllers/Setup/HomeController.php | 228 - .../Controllers/Setup/ServersController.php | 66 - .../Controllers/Table/AbstractController.php | 54 - .../classes/Controllers/Table/ChartController.php | 261 - .../Table/GisVisualizationController.php | 227 - .../Controllers/Table/IndexesController.php | 179 - .../Controllers/Table/RelationController.php | 398 -- .../classes/Controllers/Table/SearchController.php | 1244 ----- .../classes/Controllers/Table/SqlController.php | 53 - .../Controllers/Table/StructureController.php | 1648 ------ .../TransformationOverviewController.php | 80 - srcs/phpmyadmin/libraries/classes/Core.php | 1302 ----- .../libraries/classes/CreateAddField.php | 555 -- .../libraries/classes/Database/DatabaseList.php | 60 - .../libraries/classes/Database/Designer.php | 407 -- .../libraries/classes/Database/Designer/Common.php | 830 --- .../classes/Database/Designer/DesignerTable.php | 103 - .../libraries/classes/Database/MultiTableQuery.php | 145 - srcs/phpmyadmin/libraries/classes/Database/Qbe.php | 1963 ------- .../libraries/classes/Database/Search.php | 347 -- .../libraries/classes/DatabaseInterface.php | 3187 ----------- .../libraries/classes/Dbi/DbiExtension.php | 248 - .../phpmyadmin/libraries/classes/Dbi/DbiMysqli.php | 610 --- srcs/phpmyadmin/libraries/classes/Di/Migration.php | 71 - .../libraries/classes/Display/ChangePassword.php | 182 - .../libraries/classes/Display/CreateTable.php | 56 - .../phpmyadmin/libraries/classes/Display/Error.php | 56 - .../libraries/classes/Display/Export.php | 825 --- .../libraries/classes/Display/GitRevision.php | 144 - .../libraries/classes/Display/Import.php | 127 - .../libraries/classes/Display/ImportAjax.php | 140 - .../libraries/classes/Display/Results.php | 5698 -------------------- srcs/phpmyadmin/libraries/classes/Encoding.php | 358 -- srcs/phpmyadmin/libraries/classes/Engines/Bdb.php | 76 - .../libraries/classes/Engines/Berkeleydb.php | 19 - .../libraries/classes/Engines/Binlog.php | 31 - .../libraries/classes/Engines/Innobase.php | 19 - .../libraries/classes/Engines/Innodb.php | 395 -- .../libraries/classes/Engines/Memory.php | 34 - .../phpmyadmin/libraries/classes/Engines/Merge.php | 21 - .../libraries/classes/Engines/MrgMyisam.php | 29 - .../libraries/classes/Engines/Myisam.php | 88 - .../libraries/classes/Engines/Ndbcluster.php | 54 - srcs/phpmyadmin/libraries/classes/Engines/Pbxt.php | 195 - .../classes/Engines/PerformanceSchema.php | 31 - srcs/phpmyadmin/libraries/classes/Error.php | 526 -- srcs/phpmyadmin/libraries/classes/ErrorHandler.php | 604 --- srcs/phpmyadmin/libraries/classes/ErrorReport.php | 294 - srcs/phpmyadmin/libraries/classes/Export.php | 1225 ----- srcs/phpmyadmin/libraries/classes/File.php | 828 --- srcs/phpmyadmin/libraries/classes/FileListing.php | 108 - srcs/phpmyadmin/libraries/classes/Font.php | 236 - srcs/phpmyadmin/libraries/classes/Footer.php | 370 -- .../libraries/classes/Gis/GisFactory.php | 50 - .../libraries/classes/Gis/GisGeometry.php | 407 -- .../classes/Gis/GisGeometryCollection.php | 419 -- .../libraries/classes/Gis/GisLineString.php | 360 -- .../libraries/classes/Gis/GisMultiLineString.php | 449 -- .../libraries/classes/Gis/GisMultiPoint.php | 416 -- .../libraries/classes/Gis/GisMultiPolygon.php | 617 --- srcs/phpmyadmin/libraries/classes/Gis/GisPoint.php | 363 -- .../libraries/classes/Gis/GisPolygon.php | 618 --- .../libraries/classes/Gis/GisVisualization.php | 726 --- srcs/phpmyadmin/libraries/classes/Header.php | 705 --- srcs/phpmyadmin/libraries/classes/Import.php | 1727 ------ srcs/phpmyadmin/libraries/classes/Index.php | 901 ---- srcs/phpmyadmin/libraries/classes/IndexColumn.php | 188 - srcs/phpmyadmin/libraries/classes/InsertEdit.php | 3520 ------------ .../libraries/classes/InternalRelations.php | 505 -- srcs/phpmyadmin/libraries/classes/IpAllowDeny.php | 336 -- srcs/phpmyadmin/libraries/classes/Language.php | 204 - .../libraries/classes/LanguageManager.php | 975 ---- srcs/phpmyadmin/libraries/classes/Linter.php | 186 - srcs/phpmyadmin/libraries/classes/ListAbstract.php | 107 - srcs/phpmyadmin/libraries/classes/ListDatabase.php | 177 - srcs/phpmyadmin/libraries/classes/Logging.php | 102 - srcs/phpmyadmin/libraries/classes/Menu.php | 680 --- srcs/phpmyadmin/libraries/classes/Message.php | 812 --- srcs/phpmyadmin/libraries/classes/Mime.php | 41 - srcs/phpmyadmin/libraries/classes/MultSubmits.php | 651 --- .../libraries/classes/Navigation/Navigation.php | 280 - .../classes/Navigation/NavigationTree.php | 1581 ------ .../libraries/classes/Navigation/NodeFactory.php | 93 - .../libraries/classes/Navigation/Nodes/Node.php | 842 --- .../classes/Navigation/Nodes/NodeColumn.php | 116 - .../Navigation/Nodes/NodeColumnContainer.php | 55 - .../classes/Navigation/Nodes/NodeDatabase.php | 717 --- .../classes/Navigation/Nodes/NodeDatabaseChild.php | 62 - .../Nodes/NodeDatabaseChildContainer.php | 43 - .../Navigation/Nodes/NodeDatabaseContainer.php | 52 - .../classes/Navigation/Nodes/NodeEvent.php | 51 - .../Navigation/Nodes/NodeEventContainer.php | 52 - .../classes/Navigation/Nodes/NodeFunction.php | 53 - .../Navigation/Nodes/NodeFunctionContainer.php | 53 - .../classes/Navigation/Nodes/NodeIndex.php | 41 - .../Navigation/Nodes/NodeIndexContainer.php | 55 - .../classes/Navigation/Nodes/NodeProcedure.php | 53 - .../Navigation/Nodes/NodeProcedureContainer.php | 53 - .../classes/Navigation/Nodes/NodeTable.php | 310 -- .../Navigation/Nodes/NodeTableContainer.php | 54 - .../classes/Navigation/Nodes/NodeTrigger.php | 41 - .../Navigation/Nodes/NodeTriggerContainer.php | 52 - .../classes/Navigation/Nodes/NodeView.php | 51 - .../classes/Navigation/Nodes/NodeViewContainer.php | 54 - .../phpmyadmin/libraries/classes/Normalization.php | 1105 ---- srcs/phpmyadmin/libraries/classes/OpenDocument.php | 179 - srcs/phpmyadmin/libraries/classes/Operations.php | 2263 -------- .../libraries/classes/OutputBuffering.php | 144 - srcs/phpmyadmin/libraries/classes/ParseAnalyze.php | 84 - srcs/phpmyadmin/libraries/classes/Partition.php | 270 - srcs/phpmyadmin/libraries/classes/Pdf.php | 178 - srcs/phpmyadmin/libraries/classes/Plugins.php | 633 --- .../classes/Plugins/Auth/AuthenticationConfig.php | 172 - .../classes/Plugins/Auth/AuthenticationCookie.php | 964 ---- .../classes/Plugins/Auth/AuthenticationHttp.php | 214 - .../classes/Plugins/Auth/AuthenticationSignon.php | 282 - .../classes/Plugins/AuthenticationPlugin.php | 371 -- .../classes/Plugins/Export/ExportCodegen.php | 447 -- .../libraries/classes/Plugins/Export/ExportCsv.php | 347 -- .../classes/Plugins/Export/ExportExcel.php | 90 - .../classes/Plugins/Export/ExportHtmlword.php | 670 --- .../classes/Plugins/Export/ExportJson.php | 295 - .../classes/Plugins/Export/ExportLatex.php | 709 --- .../classes/Plugins/Export/ExportMediawiki.php | 386 -- .../libraries/classes/Plugins/Export/ExportOds.php | 345 -- .../libraries/classes/Plugins/Export/ExportOdt.php | 813 --- .../libraries/classes/Plugins/Export/ExportPdf.php | 395 -- .../classes/Plugins/Export/ExportPhparray.php | 259 - .../libraries/classes/Plugins/Export/ExportSql.php | 2915 ---------- .../classes/Plugins/Export/ExportTexytext.php | 624 --- .../libraries/classes/Plugins/Export/ExportXml.php | 593 -- .../classes/Plugins/Export/ExportYaml.php | 230 - .../classes/Plugins/Export/Helpers/Pdf.php | 855 --- .../Plugins/Export/Helpers/TableProperty.php | 277 - .../libraries/classes/Plugins/Export/README | 255 - .../libraries/classes/Plugins/ExportPlugin.php | 386 -- .../classes/Plugins/IOTransformationsPlugin.php | 98 - .../classes/Plugins/Import/AbstractImportCsv.php | 94 - .../libraries/classes/Plugins/Import/ImportCsv.php | 818 --- .../libraries/classes/Plugins/Import/ImportLdi.php | 176 - .../classes/Plugins/Import/ImportMediawiki.php | 604 --- .../libraries/classes/Plugins/Import/ImportOds.php | 427 -- .../libraries/classes/Plugins/Import/ImportShp.php | 335 -- .../libraries/classes/Plugins/Import/ImportSql.php | 200 - .../libraries/classes/Plugins/Import/ImportXml.php | 375 -- .../libraries/classes/Plugins/Import/README | 156 - .../classes/Plugins/Import/ShapeFileImport.php | 46 - .../classes/Plugins/Import/Upload/UploadApc.php | 83 - .../Plugins/Import/Upload/UploadNoplugin.php | 60 - .../Plugins/Import/Upload/UploadProgress.php | 97 - .../Plugins/Import/Upload/UploadSession.php | 95 - .../libraries/classes/Plugins/ImportPlugin.php | 96 - .../libraries/classes/Plugins/Schema/Dia/Dia.php | 190 - .../Plugins/Schema/Dia/DiaRelationSchema.php | 238 - .../Plugins/Schema/Dia/RelationStatsDia.php | 228 - .../classes/Plugins/Schema/Dia/TableStatsDia.php | 231 - .../libraries/classes/Plugins/Schema/Eps/Eps.php | 280 - .../Plugins/Schema/Eps/EpsRelationSchema.php | 254 - .../Plugins/Schema/Eps/RelationStatsEps.php | 120 - .../classes/Plugins/Schema/Eps/TableStatsEps.php | 183 - .../Plugins/Schema/ExportRelationSchema.php | 310 -- .../libraries/classes/Plugins/Schema/Pdf/Pdf.php | 422 -- .../Plugins/Schema/Pdf/PdfRelationSchema.php | 798 --- .../Plugins/Schema/Pdf/RelationStatsPdf.php | 163 - .../classes/Plugins/Schema/Pdf/TableStatsPdf.php | 233 - .../classes/Plugins/Schema/RelationStats.php | 120 - .../libraries/classes/Plugins/Schema/SchemaDia.php | 100 - .../libraries/classes/Plugins/Schema/SchemaEps.php | 101 - .../libraries/classes/Plugins/Schema/SchemaPdf.php | 133 - .../libraries/classes/Plugins/Schema/SchemaSvg.php | 88 - .../Plugins/Schema/Svg/RelationStatsSvg.php | 140 - .../libraries/classes/Plugins/Schema/Svg/Svg.php | 281 - .../Plugins/Schema/Svg/SvgRelationSchema.php | 284 - .../classes/Plugins/Schema/Svg/TableStatsSvg.php | 204 - .../classes/Plugins/Schema/TableStats.php | 208 - .../libraries/classes/Plugins/SchemaPlugin.php | 90 - .../Abs/Bool2TextTransformationsPlugin.php | 69 - .../Abs/CodeMirrorEditorTransformationPlugin.php | 75 - .../Abs/DateFormatTransformationsPlugin.php | 158 - .../Abs/DownloadTransformationsPlugin.php | 93 - .../Abs/ExternalTransformationsPlugin.php | 160 - .../Abs/FormattedTransformationsPlugin.php | 65 - .../Abs/HexTransformationsPlugin.php | 71 - .../Abs/ImageLinkTransformationsPlugin.php | 63 - .../Abs/ImageUploadTransformationsPlugin.php | 121 - .../Abs/InlineTransformationsPlugin.php | 78 - .../Abs/LongToIPv4TransformationsPlugin.php | 66 - .../Abs/PreApPendTransformationsPlugin.php | 68 - .../Abs/RegexValidationTransformationsPlugin.php | 74 - .../Abs/SQLTransformationsPlugin.php | 62 - .../Abs/SubstringTransformationsPlugin.php | 93 - .../Abs/TextFileUploadTransformationsPlugin.php | 103 - .../Abs/TextImageLinkTransformationsPlugin.php | 75 - .../Abs/TextLinkTransformationsPlugin.php | 77 - .../Transformations/Input/Image_JPEG_Upload.php | 44 - .../Input/Text_Plain_FileUpload.php | 43 - .../Input/Text_Plain_Iptobinary.php | 141 - .../Input/Text_Plain_JsonEditor.php | 85 - .../Input/Text_Plain_RegexValidation.php | 44 - .../Transformations/Input/Text_Plain_SqlEditor.php | 85 - .../Transformations/Input/Text_Plain_XmlEditor.php | 85 - .../Output/Application_Octetstream_Download.php | 43 - .../Output/Application_Octetstream_Hex.php | 43 - .../Transformations/Output/Image_JPEG_Inline.php | 43 - .../Transformations/Output/Image_JPEG_Link.php | 43 - .../Transformations/Output/Image_PNG_Inline.php | 43 - .../Output/Text_Octetstream_Sql.php | 43 - .../Output/Text_Plain_Binarytoip.php | 97 - .../Output/Text_Plain_Bool2Text.php | 45 - .../Output/Text_Plain_Dateformat.php | 43 - .../Transformations/Output/Text_Plain_External.php | 43 - .../Output/Text_Plain_Formatted.php | 43 - .../Output/Text_Plain_Imagelink.php | 43 - .../Transformations/Output/Text_Plain_Json.php | 101 - .../Transformations/Output/Text_Plain_Sql.php | 60 - .../Transformations/Output/Text_Plain_Xml.php | 101 - .../classes/Plugins/Transformations/README | 4 - .../classes/Plugins/Transformations/TEMPLATE | 45 - .../Plugins/Transformations/TEMPLATE_ABSTRACT | 73 - .../Plugins/Transformations/Text_Plain_Link.php | 43 - .../Transformations/Text_Plain_Longtoipv4.php | 43 - .../Transformations/Text_Plain_PreApPend.php | 44 - .../Transformations/Text_Plain_Substring.php | 43 - .../classes/Plugins/TransformationsInterface.php | 47 - .../classes/Plugins/TransformationsPlugin.php | 69 - .../classes/Plugins/TwoFactor/Application.php | 162 - .../classes/Plugins/TwoFactor/Invalid.php | 68 - .../libraries/classes/Plugins/TwoFactor/Key.php | 213 - .../libraries/classes/Plugins/TwoFactor/Simple.php | 68 - .../libraries/classes/Plugins/TwoFactorPlugin.php | 183 - .../libraries/classes/Plugins/UploadInterface.php | 35 - .../Options/Groups/OptionsPropertyMainGroup.php | 35 - .../Options/Groups/OptionsPropertyRootGroup.php | 35 - .../Options/Groups/OptionsPropertySubgroup.php | 66 - .../Properties/Options/Items/BoolPropertyItem.php | 35 - .../Properties/Options/Items/DocPropertyItem.php | 35 - .../Options/Items/HiddenPropertyItem.php | 35 - .../Options/Items/MessageOnlyPropertyItem.php | 35 - .../Options/Items/NumberPropertyItem.php | 35 - .../Properties/Options/Items/RadioPropertyItem.php | 35 - .../Options/Items/SelectPropertyItem.php | 35 - .../Properties/Options/Items/TextPropertyItem.php | 35 - .../Properties/Options/OptionsPropertyGroup.php | 109 - .../Properties/Options/OptionsPropertyItem.php | 136 - .../Properties/Options/OptionsPropertyOneItem.php | 161 - .../Properties/Plugins/ExportPluginProperties.php | 64 - .../Properties/Plugins/ImportPluginProperties.php | 33 - .../Properties/Plugins/PluginPropertyItem.php | 177 - .../Properties/Plugins/SchemaPluginProperties.php | 46 - .../libraries/classes/Properties/PropertyItem.php | 48 - .../libraries/classes/RecentFavoriteTable.php | 405 -- srcs/phpmyadmin/libraries/classes/Relation.php | 2280 -------- .../libraries/classes/RelationCleanup.php | 392 -- srcs/phpmyadmin/libraries/classes/Replication.php | 190 - .../libraries/classes/ReplicationGui.php | 602 --- srcs/phpmyadmin/libraries/classes/Response.php | 614 --- srcs/phpmyadmin/libraries/classes/Rte/Events.php | 680 --- srcs/phpmyadmin/libraries/classes/Rte/Export.php | 168 - srcs/phpmyadmin/libraries/classes/Rte/Footer.php | 160 - srcs/phpmyadmin/libraries/classes/Rte/General.php | 118 - srcs/phpmyadmin/libraries/classes/Rte/Routines.php | 1743 ------ srcs/phpmyadmin/libraries/classes/Rte/RteList.php | 518 -- srcs/phpmyadmin/libraries/classes/Rte/Triggers.php | 527 -- srcs/phpmyadmin/libraries/classes/Rte/Words.php | 89 - srcs/phpmyadmin/libraries/classes/Sanitize.php | 469 -- .../phpmyadmin/libraries/classes/SavedSearches.php | 466 -- srcs/phpmyadmin/libraries/classes/Scripts.php | 164 - .../phpmyadmin/libraries/classes/Server/Plugin.php | 274 - .../libraries/classes/Server/Plugins.php | 74 - .../libraries/classes/Server/Privileges.php | 5649 ------------------- .../phpmyadmin/libraries/classes/Server/Select.php | 128 - .../libraries/classes/Server/Status/Data.php | 430 -- .../libraries/classes/Server/Status/Monitor.php | 546 -- .../libraries/classes/Server/UserGroups.php | 390 -- srcs/phpmyadmin/libraries/classes/Server/Users.php | 64 - srcs/phpmyadmin/libraries/classes/Session.php | 234 - .../libraries/classes/Setup/ConfigGenerator.php | 184 - .../libraries/classes/Setup/FormProcessing.php | 77 - srcs/phpmyadmin/libraries/classes/Setup/Index.php | 198 - srcs/phpmyadmin/libraries/classes/Sql.php | 2328 -------- srcs/phpmyadmin/libraries/classes/SqlQueryForm.php | 457 -- .../phpmyadmin/libraries/classes/StorageEngine.php | 465 -- srcs/phpmyadmin/libraries/classes/SubPartition.php | 182 - srcs/phpmyadmin/libraries/classes/SysInfo.php | 73 - srcs/phpmyadmin/libraries/classes/SysInfoBase.php | 50 - srcs/phpmyadmin/libraries/classes/SysInfoLinux.php | 103 - srcs/phpmyadmin/libraries/classes/SysInfoSunOS.php | 81 - srcs/phpmyadmin/libraries/classes/SysInfoWINNT.php | 135 - .../libraries/classes/SystemDatabase.php | 137 - srcs/phpmyadmin/libraries/classes/Table.php | 2771 ---------- .../libraries/classes/TablePartitionDefinition.php | 200 - srcs/phpmyadmin/libraries/classes/Template.php | 142 - srcs/phpmyadmin/libraries/classes/Theme.php | 387 -- srcs/phpmyadmin/libraries/classes/ThemeManager.php | 417 -- srcs/phpmyadmin/libraries/classes/Tracker.php | 942 ---- srcs/phpmyadmin/libraries/classes/Tracking.php | 1320 ----- .../libraries/classes/Transformations.php | 485 -- .../libraries/classes/Twig/CoreExtension.php | 41 - .../libraries/classes/Twig/I18n/NodeTrans.php | 171 - .../classes/Twig/I18n/TokenParserTrans.php | 85 - .../libraries/classes/Twig/I18nExtension.php | 45 - .../libraries/classes/Twig/MessageExtension.php | 54 - .../libraries/classes/Twig/PluginsExtension.php | 52 - .../libraries/classes/Twig/RelationExtension.php | 71 - .../libraries/classes/Twig/SanitizeExtension.php | 64 - .../classes/Twig/ServerPrivilegesExtension.php | 51 - .../classes/Twig/StorageEngineExtension.php | 37 - .../libraries/classes/Twig/TableExtension.php | 36 - .../libraries/classes/Twig/TrackerExtension.php | 36 - .../classes/Twig/TransformationsExtension.php | 48 - .../libraries/classes/Twig/UrlExtension.php | 52 - .../libraries/classes/Twig/UtilExtension.php | 212 - srcs/phpmyadmin/libraries/classes/TwoFactor.php | 303 -- srcs/phpmyadmin/libraries/classes/Types.php | 875 --- srcs/phpmyadmin/libraries/classes/Url.php | 274 - srcs/phpmyadmin/libraries/classes/UserPassword.php | 286 - .../libraries/classes/UserPreferences.php | 287 - .../libraries/classes/UserPreferencesHeader.php | 148 - srcs/phpmyadmin/libraries/classes/Util.php | 4975 ----------------- .../libraries/classes/Utils/HttpRequest.php | 260 - .../libraries/classes/VersionInformation.php | 239 - srcs/phpmyadmin/libraries/classes/ZipExtension.php | 299 - 399 files changed, 135387 deletions(-) delete mode 100644 srcs/phpmyadmin/libraries/classes/Advisor.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Bookmark.php delete mode 100644 srcs/phpmyadmin/libraries/classes/BrowseForeigners.php delete mode 100644 srcs/phpmyadmin/libraries/classes/CentralColumns.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Charsets.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Charsets/Charset.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Charsets/Collation.php delete mode 100644 srcs/phpmyadmin/libraries/classes/CheckUserPrivileges.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/ConfigFile.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Descriptions.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Form.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/FormDisplay.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/FormDisplayTemplate.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/BaseForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/BaseFormList.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Page/BrowseForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Page/DbStructureForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Page/EditForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Page/ExportForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Page/ImportForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Page/NaviForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Page/PageFormList.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Page/SqlForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Page/TableStructureForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ConfigForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ExportForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/FeaturesForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ImportForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/MainForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/NaviForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ServersForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/SetupFormList.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/SqlForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/User/ExportForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/User/FeaturesForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/User/ImportForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/User/MainForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/User/NaviForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/User/SqlForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Forms/User/UserFormList.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/PageSettings.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/ServerConfigChecks.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/SpecialSchemaLinks.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Config/Validator.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Console.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/AbstractController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/AjaxController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/BrowseForeignersController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Database/AbstractController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Database/CentralColumnsController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Database/DataDictionaryController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Database/EventsController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Database/MultiTableQueryController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Database/RoutinesController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Database/SqlController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Database/StructureController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Database/TriggersController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/HomeController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/BinlogController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/CollationsController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/DatabasesController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/EnginesController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/PluginsController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/ReplicationController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/SqlController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/AbstractController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/AdvisorController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/MonitorController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/ProcessesController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/QueriesController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/StatusController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/VariablesController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Server/VariablesController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Setup/AbstractController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Setup/ConfigController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Setup/FormController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Setup/HomeController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Setup/ServersController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Table/AbstractController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Table/ChartController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Table/GisVisualizationController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Table/IndexesController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Table/RelationController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Table/SearchController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Table/SqlController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/Table/StructureController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Controllers/TransformationOverviewController.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Core.php delete mode 100644 srcs/phpmyadmin/libraries/classes/CreateAddField.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Database/DatabaseList.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Database/Designer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Database/Designer/Common.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Database/Designer/DesignerTable.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Database/MultiTableQuery.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Database/Qbe.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Database/Search.php delete mode 100644 srcs/phpmyadmin/libraries/classes/DatabaseInterface.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Dbi/DbiExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Dbi/DbiMysqli.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Di/Migration.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Display/ChangePassword.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Display/CreateTable.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Display/Error.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Display/Export.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Display/GitRevision.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Display/Import.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Display/ImportAjax.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Display/Results.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Encoding.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Engines/Bdb.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Engines/Berkeleydb.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Engines/Binlog.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Engines/Innobase.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Engines/Innodb.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Engines/Memory.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Engines/Merge.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Engines/MrgMyisam.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Engines/Myisam.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Engines/Ndbcluster.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Engines/Pbxt.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Engines/PerformanceSchema.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Error.php delete mode 100644 srcs/phpmyadmin/libraries/classes/ErrorHandler.php delete mode 100644 srcs/phpmyadmin/libraries/classes/ErrorReport.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Export.php delete mode 100644 srcs/phpmyadmin/libraries/classes/File.php delete mode 100644 srcs/phpmyadmin/libraries/classes/FileListing.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Font.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Footer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Gis/GisFactory.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Gis/GisGeometry.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Gis/GisGeometryCollection.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Gis/GisLineString.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Gis/GisMultiLineString.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Gis/GisMultiPoint.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Gis/GisMultiPolygon.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Gis/GisPoint.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Gis/GisPolygon.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Gis/GisVisualization.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Header.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Import.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Index.php delete mode 100644 srcs/phpmyadmin/libraries/classes/IndexColumn.php delete mode 100644 srcs/phpmyadmin/libraries/classes/InsertEdit.php delete mode 100644 srcs/phpmyadmin/libraries/classes/InternalRelations.php delete mode 100644 srcs/phpmyadmin/libraries/classes/IpAllowDeny.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Language.php delete mode 100644 srcs/phpmyadmin/libraries/classes/LanguageManager.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Linter.php delete mode 100644 srcs/phpmyadmin/libraries/classes/ListAbstract.php delete mode 100644 srcs/phpmyadmin/libraries/classes/ListDatabase.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Logging.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Menu.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Message.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Mime.php delete mode 100644 srcs/phpmyadmin/libraries/classes/MultSubmits.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Navigation.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/NavigationTree.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/NodeFactory.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/Node.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumn.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumnContainer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabase.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChild.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChildContainer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEvent.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEventContainer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunction.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunctionContainer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndex.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndexContainer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedure.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedureContainer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTable.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTableContainer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTrigger.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTriggerContainer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeView.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeViewContainer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Normalization.php delete mode 100644 srcs/phpmyadmin/libraries/classes/OpenDocument.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Operations.php delete mode 100644 srcs/phpmyadmin/libraries/classes/OutputBuffering.php delete mode 100644 srcs/phpmyadmin/libraries/classes/ParseAnalyze.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Partition.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Pdf.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationConfig.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationCookie.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationHttp.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationSignon.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/AuthenticationPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCodegen.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCsv.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportExcel.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportHtmlword.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportJson.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportLatex.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportMediawiki.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOds.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOdt.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPdf.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPhparray.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportSql.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportTexytext.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportXml.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportYaml.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/Pdf.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/TableProperty.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Export/README delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/ExportPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/IOTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/AbstractImportCsv.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportCsv.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportLdi.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportMediawiki.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportOds.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportShp.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportSql.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportXml.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/README delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/ShapeFileImport.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadApc.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadNoplugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadProgress.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadSession.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/ImportPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/Dia.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/DiaRelationSchema.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/RelationStatsDia.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/TableStatsDia.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/Eps.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/EpsRelationSchema.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/RelationStatsEps.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/TableStatsEps.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/ExportRelationSchema.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/Pdf.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/RelationStatsPdf.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/TableStatsPdf.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/RelationStats.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaDia.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaEps.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaPdf.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaSvg.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/RelationStatsSvg.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/Svg.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/SvgRelationSchema.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/TableStatsSvg.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/TableStats.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/SchemaPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/Bool2TextTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/CodeMirrorEditorTransformationPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/DateFormatTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/DownloadTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/ExternalTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/FormattedTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/HexTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/ImageLinkTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/ImageUploadTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/InlineTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/LongToIPv4TransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/PreApPendTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/RegexValidationTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/SQLTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/SubstringTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/TextFileUploadTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/TextImageLinkTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/TextLinkTransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Image_JPEG_Upload.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Text_Plain_FileUpload.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Text_Plain_Iptobinary.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Text_Plain_JsonEditor.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Text_Plain_RegexValidation.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Text_Plain_SqlEditor.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Text_Plain_XmlEditor.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Application_Octetstream_Download.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Application_Octetstream_Hex.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Image_JPEG_Inline.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Image_JPEG_Link.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Image_PNG_Inline.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Octetstream_Sql.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Binarytoip.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Bool2Text.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Dateformat.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_External.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Formatted.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Imagelink.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Json.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Sql.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Xml.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/README delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/TEMPLATE delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/TEMPLATE_ABSTRACT delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Text_Plain_Link.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Text_Plain_Longtoipv4.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Text_Plain_PreApPend.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Text_Plain_Substring.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/TransformationsInterface.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/TransformationsPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Application.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Invalid.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Key.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Simple.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/TwoFactorPlugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/UploadInterface.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/Groups/OptionsPropertyMainGroup.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/Groups/OptionsPropertyRootGroup.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/Groups/OptionsPropertySubgroup.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/Items/BoolPropertyItem.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/Items/DocPropertyItem.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/Items/HiddenPropertyItem.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/Items/MessageOnlyPropertyItem.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/Items/NumberPropertyItem.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/Items/RadioPropertyItem.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/Items/SelectPropertyItem.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/Items/TextPropertyItem.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/OptionsPropertyGroup.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/OptionsPropertyItem.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Options/OptionsPropertyOneItem.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Plugins/ExportPluginProperties.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Plugins/ImportPluginProperties.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Plugins/PluginPropertyItem.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/Plugins/SchemaPluginProperties.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Properties/PropertyItem.php delete mode 100644 srcs/phpmyadmin/libraries/classes/RecentFavoriteTable.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Relation.php delete mode 100644 srcs/phpmyadmin/libraries/classes/RelationCleanup.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Replication.php delete mode 100644 srcs/phpmyadmin/libraries/classes/ReplicationGui.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Response.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Rte/Events.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Rte/Export.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Rte/Footer.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Rte/General.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Rte/Routines.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Rte/RteList.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Rte/Triggers.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Rte/Words.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Sanitize.php delete mode 100644 srcs/phpmyadmin/libraries/classes/SavedSearches.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Scripts.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Server/Plugin.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Server/Plugins.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Server/Privileges.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Server/Select.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Server/Status/Data.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Server/Status/Monitor.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Server/UserGroups.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Server/Users.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Session.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Setup/ConfigGenerator.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Setup/FormProcessing.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Setup/Index.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Sql.php delete mode 100644 srcs/phpmyadmin/libraries/classes/SqlQueryForm.php delete mode 100644 srcs/phpmyadmin/libraries/classes/StorageEngine.php delete mode 100644 srcs/phpmyadmin/libraries/classes/SubPartition.php delete mode 100644 srcs/phpmyadmin/libraries/classes/SysInfo.php delete mode 100644 srcs/phpmyadmin/libraries/classes/SysInfoBase.php delete mode 100644 srcs/phpmyadmin/libraries/classes/SysInfoLinux.php delete mode 100644 srcs/phpmyadmin/libraries/classes/SysInfoSunOS.php delete mode 100644 srcs/phpmyadmin/libraries/classes/SysInfoWINNT.php delete mode 100644 srcs/phpmyadmin/libraries/classes/SystemDatabase.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Table.php delete mode 100644 srcs/phpmyadmin/libraries/classes/TablePartitionDefinition.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Template.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Theme.php delete mode 100644 srcs/phpmyadmin/libraries/classes/ThemeManager.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Tracker.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Tracking.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Transformations.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/CoreExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/I18n/NodeTrans.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/I18n/TokenParserTrans.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/I18nExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/MessageExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/PluginsExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/RelationExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/SanitizeExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/ServerPrivilegesExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/StorageEngineExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/TableExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/TrackerExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/TransformationsExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/UrlExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Twig/UtilExtension.php delete mode 100644 srcs/phpmyadmin/libraries/classes/TwoFactor.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Types.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Url.php delete mode 100644 srcs/phpmyadmin/libraries/classes/UserPassword.php delete mode 100644 srcs/phpmyadmin/libraries/classes/UserPreferences.php delete mode 100644 srcs/phpmyadmin/libraries/classes/UserPreferencesHeader.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Util.php delete mode 100644 srcs/phpmyadmin/libraries/classes/Utils/HttpRequest.php delete mode 100644 srcs/phpmyadmin/libraries/classes/VersionInformation.php delete mode 100644 srcs/phpmyadmin/libraries/classes/ZipExtension.php (limited to 'srcs/phpmyadmin/libraries/classes') diff --git a/srcs/phpmyadmin/libraries/classes/Advisor.php b/srcs/phpmyadmin/libraries/classes/Advisor.php deleted file mode 100644 index 6dad8b6..0000000 --- a/srcs/phpmyadmin/libraries/classes/Advisor.php +++ /dev/null @@ -1,707 +0,0 @@ -dbi = $dbi; - $this->expression = $expression; - /* - * Register functions for ExpressionLanguage, we intentionally - * do not implement support for compile as we do not use it. - */ - $this->expression->register( - 'round', - function () { - }, - function ($arguments, $num) { - return round($num); - } - ); - $this->expression->register( - 'substr', - function () { - }, - function ($arguments, $string, $start, $length) { - return substr($string, $start, $length); - } - ); - $this->expression->register( - 'preg_match', - function () { - }, - function ($arguments, $pattern, $subject) { - return preg_match($pattern, $subject); - } - ); - $this->expression->register( - 'ADVISOR_bytime', - function () { - }, - function ($arguments, $num, $precision) { - return self::byTime($num, $precision); - } - ); - $this->expression->register( - 'ADVISOR_timespanFormat', - function () { - }, - function ($arguments, $seconds) { - return self::timespanFormat((int) $seconds); - } - ); - $this->expression->register( - 'ADVISOR_formatByteDown', - function () { - }, - function ($arguments, $value, $limes = 6, $comma = 0) { - return self::formatByteDown($value, $limes, $comma); - } - ); - $this->expression->register( - 'fired', - function () { - }, - function ($arguments, $value) { - if (! isset($this->runResult['fired'])) { - return 0; - } - - // Did matching rule fire? - foreach ($this->runResult['fired'] as $rule) { - if ($rule['id'] == $value) { - return '1'; - } - } - - return '0'; - } - ); - /* Some global variables for advisor */ - $this->globals = [ - 'PMA_MYSQL_INT_VERSION' => $this->dbi->getVersion(), - ]; - } - - /** - * Get variables - * - * @return mixed - */ - public function getVariables() - { - return $this->variables; - } - - /** - * Set variables - * - * @param array $variables Variables - * - * @return Advisor - */ - public function setVariables(array $variables): self - { - $this->variables = $variables; - - return $this; - } - - /** - * Set a variable and its value - * - * @param string|int $variable Variable to set - * @param mixed $value Value to set - * - * @return Advisor - */ - public function setVariable($variable, $value): self - { - $this->variables[$variable] = $value; - - return $this; - } - - /** - * Get parseResult - * - * @return mixed - */ - public function getParseResult() - { - return $this->parseResult; - } - - /** - * Set parseResult - * - * @param array $parseResult Parse result - * - * @return Advisor - */ - public function setParseResult(array $parseResult): self - { - $this->parseResult = $parseResult; - - return $this; - } - - /** - * Get runResult - * - * @return mixed - */ - public function getRunResult() - { - return $this->runResult; - } - - /** - * Set runResult - * - * @param array $runResult Run result - * - * @return Advisor - */ - public function setRunResult(array $runResult): self - { - $this->runResult = $runResult; - - return $this; - } - - /** - * Parses and executes advisor rules - * - * @return array with run and parse results - */ - public function run(): array - { - // HowTo: A simple Advisory system in 3 easy steps. - - // Step 1: Get some variables to evaluate on - $this->setVariables( - array_merge( - $this->dbi->fetchResult('SHOW GLOBAL STATUS', 0, 1), - $this->dbi->fetchResult('SHOW GLOBAL VARIABLES', 0, 1) - ) - ); - - // Add total memory to variables as well - $sysinfo = SysInfo::get(); - $memory = $sysinfo->memory(); - $this->variables['system_memory'] - = isset($memory['MemTotal']) ? $memory['MemTotal'] : 0; - - $ruleFiles = $this->defineRulesFiles(); - - // Step 2: Read and parse the list of rules - $parsedResults = []; - foreach ($ruleFiles as $ruleFile) { - $parsedResults[] = $this->parseRulesFile($ruleFile); - } - $this->setParseResult(array_merge_recursive(...$parsedResults)); - - // Step 3: Feed the variables to the rules and let them fire. Sets - // $runResult - $this->runRules(); - - return [ - 'parse' => ['errors' => $this->parseResult['errors']], - 'run' => $this->runResult, - ]; - } - - /** - * Stores current error in run results. - * - * @param string $description description of an error. - * @param Throwable $exception exception raised - * - * @return void - */ - public function storeError(string $description, Throwable $exception): void - { - $this->runResult['errors'][] = $description - . ' ' - . sprintf( - __('Error when evaluating: %s'), - $exception->getMessage() - ); - } - - /** - * Executes advisor rules - * - * @return boolean - */ - public function runRules(): bool - { - $this->setRunResult( - [ - 'fired' => [], - 'notfired' => [], - 'unchecked' => [], - 'errors' => [], - ] - ); - - 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 - */ - public static function escapePercent(string $str): string - { - return preg_replace('/%( |,|\.|$|\(|\)|<|>)/', '%%\1', $str); - } - - /** - * Wrapper function for translating. - * - * @param string $str the string - * @param string $param the parameters - * - * @return string - * @throws Exception - */ - public function translate(string $str, ?string $param = null): string - { - $string = _gettext(self::escapePercent($str)); - if ($param !== null) { - $params = $this->ruleExprEvaluate('[' . $param . ']'); - } else { - $params = []; - } - return vsprintf($string, $params); - } - - /** - * Splits justification to text and formula. - * - * @param array $rule the rule - * - * @return string[] - */ - public static function splitJustification(array $rule): array - { - $jst = preg_split('/\s*\|\s*/', $rule['justification'], 2); - if (count($jst) > 1) { - return [ - $jst[0], - $jst[1], - ]; - } - return [$rule['justification']]; - } - - /** - * Adds a rule to the result list - * - * @param string $type type of rule - * @param array $rule rule itself - * - * @return void - * @throws Exception - */ - public function addRule(string $type, array $rule): void - { - switch ($type) { - case 'notfired': - case 'fired': - $jst = self::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_callback( - '/\{([a-z_0-9]+)\}/Ui', - [ - $this, - 'replaceVariable', - ], - $this->translate($rule['recommendation']) - ); - - // Replaces external Links with Core::linkURL() generated links - $rule['recommendation'] = preg_replace_callback( - '#href=("|\')(https?://[^\1]+)\1#i', - [ - $this, - 'replaceLinkURL', - ], - $rule['recommendation'] - ); - break; - } - - $this->runResult[$type][] = $rule; - } - - /** - * Defines the rules files to use - * - * @return array - */ - protected function defineRulesFiles(): array - { - $isMariaDB = false !== strpos($this->getVariables()['version'], 'MariaDB'); - $ruleFiles = [self::GENERIC_RULES_FILE]; - // If MariaDB (= not MySQL) OR MYSQL < 8.0.3, add another rules file. - if ($isMariaDB || $this->globals['PMA_MYSQL_INT_VERSION'] < 80003) { - $ruleFiles[] = self::BEFORE_MYSQL80003_RULES_FILE; - } - return $ruleFiles; - } - - /** - * Callback for wrapping links with Core::linkURL - * - * @param array $matches List of matched elements form preg_replace_callback - * - * @return string Replacement value - */ - private function replaceLinkURL(array $matches): string - { - return 'href="' . Core::linkURL($matches[2]) . '" target="_blank" rel="noopener noreferrer"'; - } - - /** - * Callback for wrapping variable edit links - * - * @param array $matches List of matched elements form preg_replace_callback - * - * @return string Replacement value - */ - private function replaceVariable(array $matches): string - { - return '' . htmlspecialchars($matches[1]) . ''; - } - - /** - * Runs a code expression, replacing variable names with their respective - * values - * - * @param string $expr expression to evaluate - * - * @return mixed result of evaluated expression - * - * @throws Exception - */ - public function ruleExprEvaluate(string $expr) - { - // Actually evaluate the code - // This can throw exception - $value = $this->expression->evaluate( - $expr, - array_merge($this->variables, $this->globals) - ); - - return $value; - } - - /** - * Reads the rule file into an array, throwing errors messages on syntax - * errors. - * - * @param string $filename Name of file to parse - * - * @return array with parsed data - */ - public static function parseRulesFile(string $filename): array - { - $file = file($filename, FILE_IGNORE_NEW_LINES); - - $errors = []; - $rules = []; - $lines = []; - - if ($file === false) { - $errors[] = sprintf( - __('Error in reading file: The file \'%s\' does not exist or is not readable!'), - $filename - ); - return [ - 'rules' => $rules, - 'lines' => $lines, - 'errors' => $errors, - ]; - } - - $ruleSyntax = [ - '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] = ['name' => $match[1]]; - $lines[$ruleNo] = ['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; - } elseif ($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]] = rtrim( - mb_substr($line, 1) - ); - $lines[$ruleNo][$ruleSyntax[$ruleLine]] = $i + 1; - ++$ruleLine; - } - - // Rule complete - if ($ruleLine == $numRules) { - $ruleLine = -1; - } - } - - return [ - 'rules' => $rules, - 'lines' => $lines, - 'errors' => $errors, - ]; - } - - /** - * Formats interval like 10 per hour - * - * @param float $num number to format - * @param integer $precision required precision - * - * @return string formatted string - */ - public static function byTime(float $num, int $precision): string - { - if ($num >= 1) { // per second - $per = __('per second'); - } elseif ($num * 60 >= 1) { // per minute - $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 = '<' . pow(10, -$precision); - } - - return "$num $per"; - } - - /** - * Wrapper for PhpMyAdmin\Util::timespanFormat - * - * This function is used when evaluating advisory_rules.txt - * - * @param int $seconds the timespan - * - * @return string the formatted value - */ - public static function timespanFormat(int $seconds): string - { - return Util::timespanFormat($seconds); - } - - /** - * Wrapper around PhpMyAdmin\Util::formatByteDown - * - * This function is used when evaluating advisory_rules.txt - * - * @param double|string $value the value to format - * @param int $limes the sensitiveness - * @param int $comma the number of decimals to retain - * - * @return string the formatted value with unit - */ - public static function formatByteDown($value, int $limes = 6, int $comma = 0): string - { - return implode(' ', Util::formatByteDown($value, $limes, $comma)); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Bookmark.php b/srcs/phpmyadmin/libraries/classes/Bookmark.php deleted file mode 100644 index 7dc1302..0000000 --- a/srcs/phpmyadmin/libraries/classes/Bookmark.php +++ /dev/null @@ -1,395 +0,0 @@ -dbi = $dbi; - $this->user = $user; - } - - /** - * Returns the ID of the bookmark - * - * @return int - */ - public function getId(): int - { - return (int) $this->_id; - } - - /** - * Returns the database of the bookmark - * - * @return string - */ - public function getDatabase(): string - { - return $this->_database; - } - - /** - * Returns the user whom the bookmark belongs to - * - * @return string - */ - public function getUser(): string - { - return $this->_user; - } - - /** - * Returns the label of the bookmark - * - * @return string - */ - public function getLabel(): string - { - return $this->_label; - } - - /** - * Returns the query - * - * @return string - */ - public function getQuery(): string - { - return $this->_query; - } - - /** - * Adds a bookmark - * - * @return boolean whether the INSERT succeeds or not - * - * @access public - */ - public function save(): bool - { - $cfgBookmark = self::getParams($this->user); - if (empty($cfgBookmark)) { - return false; - } - - $query = "INSERT INTO " . Util::backquote($cfgBookmark['db']) - . "." . Util::backquote($cfgBookmark['table']) - . " (id, dbase, user, query, label) VALUES (NULL, " - . "'" . $this->dbi->escapeString($this->_database) . "', " - . "'" . $this->dbi->escapeString($this->_user) . "', " - . "'" . $this->dbi->escapeString($this->_query) . "', " - . "'" . $this->dbi->escapeString($this->_label) . "')"; - return $this->dbi->query($query, DatabaseInterface::CONNECT_CONTROL); - } - - /** - * Deletes a bookmark - * - * @return bool true if successful - * - * @access public - */ - public function delete(): bool - { - $cfgBookmark = self::getParams($this->user); - if (empty($cfgBookmark)) { - return false; - } - - $query = "DELETE FROM " . Util::backquote($cfgBookmark['db']) - . "." . Util::backquote($cfgBookmark['table']) - . " WHERE id = " . $this->_id; - return $this->dbi->tryQuery($query, DatabaseInterface::CONNECT_CONTROL); - } - - /** - * Returns the number of variables in a bookmark - * - * @return int number of variables - */ - public function getVariableCount(): int - { - $matches = []; - preg_match_all("/\[VARIABLE[0-9]*\]/", $this->_query, $matches, PREG_SET_ORDER); - return count($matches); - } - - /** - * Replace the placeholders in the bookmark query with variables - * - * @param array $variables array of variables - * - * @return string query with variables applied - */ - public function applyVariables(array $variables): string - { - // remove comments that encloses a variable placeholder - $query = preg_replace( - '|/\*(.*\[VARIABLE[0-9]*\].*)\*/|imsU', - '${1}', - $this->_query - ); - // replace variable placeholders with values - $number_of_variables = $this->getVariableCount(); - for ($i = 1; $i <= $number_of_variables; $i++) { - $var = ''; - if (! empty($variables[$i])) { - $var = $this->dbi->escapeString($variables[$i]); - } - $query = str_replace('[VARIABLE' . $i . ']', $var, $query); - // backward compatibility - if ($i == 1) { - $query = str_replace('[VARIABLE]', $var, $query); - } - } - return $query; - } - - /** - * Defines the bookmark parameters for the current user - * - * @param string $user Current user - * - * @return array|bool the bookmark parameters for the current user - * @access public - */ - public static function getParams(string $user) - { - static $cfgBookmark = null; - - if (null !== $cfgBookmark) { - return $cfgBookmark; - } - - $relation = new Relation($GLOBALS['dbi']); - $cfgRelation = $relation->getRelationsParam(); - if ($cfgRelation['bookmarkwork']) { - $cfgBookmark = [ - 'user' => $user, - 'db' => $cfgRelation['db'], - 'table' => $cfgRelation['bookmark'], - ]; - } else { - $cfgBookmark = false; - } - - return $cfgBookmark; - } - - /** - * Creates a Bookmark object from the parameters - * - * @param DatabaseInterface $dbi DatabaseInterface object - * @param string $user Current user - * @param array $bkm_fields the properties of the bookmark to add; here, - * $bkm_fields['bkm_sql_query'] is urlencoded - * @param boolean $all_users whether to make the bookmark - * available for all users - * - * @return Bookmark|false - */ - public static function createBookmark( - DatabaseInterface $dbi, - string $user, - array $bkm_fields, - bool $all_users = false - ) { - if (! (isset($bkm_fields['bkm_sql_query']) - && strlen($bkm_fields['bkm_sql_query']) > 0 - && isset($bkm_fields['bkm_label']) - && strlen($bkm_fields['bkm_label']) > 0) - ) { - return false; - } - - $bookmark = new Bookmark($dbi, $user); - $bookmark->_database = $bkm_fields['bkm_database']; - $bookmark->_label = $bkm_fields['bkm_label']; - $bookmark->_query = $bkm_fields['bkm_sql_query']; - $bookmark->_user = $all_users ? '' : $bkm_fields['bkm_user']; - - return $bookmark; - } - - /** - * Gets the list of bookmarks defined for the current database - * - * @param DatabaseInterface $dbi DatabaseInterface object - * @param string $user Current user - * @param string|bool $db the current database name or false - * - * @return Bookmark[] the bookmarks list - * - * @access public - */ - public static function getList( - DatabaseInterface $dbi, - string $user, - $db = false - ): array { - $cfgBookmark = self::getParams($user); - if (empty($cfgBookmark)) { - return []; - } - - $query = "SELECT * FROM " . Util::backquote($cfgBookmark['db']) - . "." . Util::backquote($cfgBookmark['table']) - . " WHERE ( `user` = ''" - . " OR `user` = '" . $dbi->escapeString($cfgBookmark['user']) . "' )"; - if ($db !== false) { - $query .= " AND dbase = '" . $dbi->escapeString($db) . "'"; - } - $query .= " ORDER BY label ASC"; - - $result = $dbi->fetchResult( - $query, - null, - null, - DatabaseInterface::CONNECT_CONTROL, - DatabaseInterface::QUERY_STORE - ); - - if (! empty($result)) { - $bookmarks = []; - foreach ($result as $row) { - $bookmark = new Bookmark($dbi, $user); - $bookmark->_id = $row['id']; - $bookmark->_database = $row['dbase']; - $bookmark->_user = $row['user']; - $bookmark->_label = $row['label']; - $bookmark->_query = $row['query']; - $bookmarks[] = $bookmark; - } - - return $bookmarks; - } - - return []; - } - - /** - * Retrieve a specific bookmark - * - * @param DatabaseInterface $dbi DatabaseInterface object - * @param string $user Current user - * @param string $db the current database name - * @param mixed $id an identifier of the bookmark to get - * @param string $id_field which field to look up the identifier - * @param boolean $action_bookmark_all true: get all bookmarks regardless - * of the owning user - * @param boolean $exact_user_match whether to ignore bookmarks with no user - * - * @return Bookmark the bookmark - * - * @access public - * - */ - public static function get( - DatabaseInterface $dbi, - string $user, - string $db, - $id, - string $id_field = 'id', - bool $action_bookmark_all = false, - bool $exact_user_match = false - ): ?self { - $cfgBookmark = self::getParams($user); - if (empty($cfgBookmark)) { - return null; - } - - $query = "SELECT * FROM " . Util::backquote($cfgBookmark['db']) - . "." . Util::backquote($cfgBookmark['table']) - . " WHERE dbase = '" . $dbi->escapeString($db) . "'"; - if (! $action_bookmark_all) { - $query .= " AND (user = '" - . $dbi->escapeString($cfgBookmark['user']) . "'"; - if (! $exact_user_match) { - $query .= " OR user = ''"; - } - $query .= ")"; - } - $query .= " AND " . Util::backquote($id_field) - . " = '" . $dbi->escapeString((string) $id) . "' LIMIT 1"; - - $result = $dbi->fetchSingleRow($query, 'ASSOC', DatabaseInterface::CONNECT_CONTROL); - if (! empty($result)) { - $bookmark = new Bookmark($dbi, $user); - $bookmark->_id = $result['id']; - $bookmark->_database = $result['dbase']; - $bookmark->_user = $result['user']; - $bookmark->_label = $result['label']; - $bookmark->_query = $result['query']; - return $bookmark; - } - - return null; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/BrowseForeigners.php b/srcs/phpmyadmin/libraries/classes/BrowseForeigners.php deleted file mode 100644 index 18bc30a..0000000 --- a/srcs/phpmyadmin/libraries/classes/BrowseForeigners.php +++ /dev/null @@ -1,361 +0,0 @@ -limitChars = $limitChars; - $this->maxRows = $maxRows; - $this->repeatCells = $repeatCells; - $this->showAll = $showAll; - $this->themeImage = $themeImage; - $this->template = $template; - } - - /** - * Function to get html for one relational key - * - * @param integer $horizontal_count the current horizontal count - * @param string $header table header - * @param array $keys all the keys - * @param integer $indexByKeyname index by keyname - * @param array $descriptions descriptions - * @param integer $indexByDescription index by description - * @param string $current_value current value on the edit form - * - * @return array the generated html - */ - private function getHtmlForOneKey( - int $horizontal_count, - string $header, - array $keys, - int $indexByKeyname, - array $descriptions, - int $indexByDescription, - string $current_value - ): array { - $horizontal_count++; - $output = ''; - - // whether the key name corresponds to the selected value in the form - $rightKeynameIsSelected = false; - $leftKeynameIsSelected = false; - - if ($this->repeatCells > 0 && $horizontal_count > $this->repeatCells) { - $output .= $header; - $horizontal_count = 0; - } - - // key names and descriptions for the left section, - // sorted by key names - $leftKeyname = $keys[$indexByKeyname]; - list( - $leftDescription, - $leftDescriptionTitle - ) = $this->getDescriptionAndTitle($descriptions[$indexByKeyname]); - - // key names and descriptions for the right section, - // sorted by descriptions - $rightKeyname = $keys[$indexByDescription]; - list( - $rightDescription, - $rightDescriptionTitle - ) = $this->getDescriptionAndTitle($descriptions[$indexByDescription]); - - $indexByDescription++; - - if (! empty($current_value)) { - $rightKeynameIsSelected = $rightKeyname == $current_value; - $leftKeynameIsSelected = $leftKeyname == $current_value; - } - - $output .= ''; - - $output .= $this->template->render('table/browse_foreigners/column_element', [ - 'keyname' => $leftKeyname, - 'description' => $leftDescription, - 'title' => $leftDescriptionTitle, - 'is_selected' => $leftKeynameIsSelected, - 'nowrap' => true, - ]); - $output .= $this->template->render('table/browse_foreigners/column_element', [ - 'keyname' => $leftKeyname, - 'description' => $leftDescription, - 'title' => $leftDescriptionTitle, - 'is_selected' => $leftKeynameIsSelected, - 'nowrap' => false, - ]); - - $output .= '' - . ''; - - $output .= $this->template->render('table/browse_foreigners/column_element', [ - 'keyname' => $rightKeyname, - 'description' => $rightDescription, - 'title' => $rightDescriptionTitle, - 'is_selected' => $rightKeynameIsSelected, - 'nowrap' => false, - ]); - $output .= $this->template->render('table/browse_foreigners/column_element', [ - 'keyname' => $rightKeyname, - 'description' => $rightDescription, - 'title' => $rightDescriptionTitle, - 'is_selected' => $rightKeynameIsSelected, - 'nowrap' => true, - ]); - - $output .= ''; - - return [ - $output, - $horizontal_count, - $indexByDescription, - ]; - } - - /** - * Function to get html for relational field selection - * - * @param string $db current database - * @param string $table current table - * @param string $field field - * @param array $foreignData foreign column data - * @param string|null $fieldkey field key - * @param string $current_value current columns's value - * - * @return string - */ - public function getHtmlForRelationalFieldSelection( - string $db, - string $table, - string $field, - array $foreignData, - ?string $fieldkey, - string $current_value - ): string { - $gotopage = $this->getHtmlForGotoPage($foreignData); - $foreignShowAll = $this->template->render('table/browse_foreigners/show_all', [ - 'foreign_data' => $foreignData, - 'show_all' => $this->showAll, - 'max_rows' => $this->maxRows, - ]); - - $output = '
' - . '
' - . Url::getHiddenInputs($db, $table) - . '' - . ''; - - if (isset($_POST['rownumber'])) { - $output .= ''; - } - $filter_value = (isset($_POST['foreign_filter']) - ? htmlspecialchars($_POST['foreign_filter']) - : ''); - $output .= '' - . '' - . '' - . '' - . '' - . '' . $gotopage . '' - . '' . $foreignShowAll . '' - . '
' - . '
'; - - $output .= ''; - - if (! is_array($foreignData['disp_row'])) { - $output .= '' - . '
'; - - return $output; - } - - $header = ' - ' . __('Keyname') . ' - ' . __('Description') . ' - - ' . __('Description') . ' - ' . __('Keyname') . ' - '; - - $output .= '' . $header . '' . "\n" - . '' . $header . '' . "\n" - . '' . "\n"; - - $descriptions = []; - $keys = []; - foreach ($foreignData['disp_row'] as $relrow) { - if ($foreignData['foreign_display'] != false) { - $descriptions[] = $relrow[$foreignData['foreign_display']]; - } else { - $descriptions[] = ''; - } - - $keys[] = $relrow[$foreignData['foreign_field']]; - } - - asort($keys); - - $horizontal_count = 0; - $indexByDescription = 0; - - foreach ($keys as $indexByKeyname => $value) { - list( - $html, - $horizontal_count, - $indexByDescription - ) = $this->getHtmlForOneKey( - $horizontal_count, - $header, - $keys, - $indexByKeyname, - $descriptions, - $indexByDescription, - $current_value - ); - $output .= $html; - } - - $output .= '' - . ''; - - return $output; - } - - /** - * Get the description (possibly truncated) and the title - * - * @param string $description the key name's description - * - * @return array the new description and title - */ - private function getDescriptionAndTitle(string $description): array - { - if (mb_strlen($description) <= $this->limitChars) { - $description = htmlspecialchars( - $description - ); - $descriptionTitle = ''; - } else { - $descriptionTitle = htmlspecialchars( - $description - ); - $description = htmlspecialchars( - mb_substr( - $description, - 0, - $this->limitChars - ) - . '...' - ); - } - return [ - $description, - $descriptionTitle, - ]; - } - - /** - * Function to get html for the goto page option - * - * @param array|null $foreignData foreign data - * - * @return string - */ - private function getHtmlForGotoPage(?array $foreignData): string - { - $gotopage = ''; - isset($_POST['pos']) ? $pos = $_POST['pos'] : $pos = 0; - if ($foreignData === null || ! is_array($foreignData['disp_row'])) { - return $gotopage; - } - - $pageNow = @floor($pos / $this->maxRows) + 1; - $nbTotalPage = @ceil($foreignData['the_total'] / $this->maxRows); - - if ($foreignData['the_total'] > $this->maxRows) { - $gotopage = Util::pageselector( - 'pos', - $this->maxRows, - $pageNow, - $nbTotalPage, - 200, - 5, - 5, - 20, - 10, - __('Page number:') - ); - } - - return $gotopage; - } - - /** - * Function to get foreign limit - * - * @param string|null $foreignShowAll foreign navigation - * - * @return string - */ - public function getForeignLimit(?string $foreignShowAll): ?string - { - if (isset($foreignShowAll) && $foreignShowAll == __('Show all')) { - return null; - } - isset($_POST['pos']) ? $pos = $_POST['pos'] : $pos = 0; - return 'LIMIT ' . $pos . ', ' . $this->maxRows . ' '; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/CentralColumns.php b/srcs/phpmyadmin/libraries/classes/CentralColumns.php deleted file mode 100644 index 9e11db0..0000000 --- a/srcs/phpmyadmin/libraries/classes/CentralColumns.php +++ /dev/null @@ -1,1207 +0,0 @@ -dbi = $dbi; - - $this->user = $GLOBALS['cfg']['Server']['user']; - $this->maxRows = (int) $GLOBALS['cfg']['MaxRows']; - $this->charEditing = $GLOBALS['cfg']['CharEditing']; - $this->disableIs = (bool) $GLOBALS['cfg']['Server']['DisableIS']; - - $this->relation = new Relation($this->dbi); - $this->template = new Template(); - } - - /** - * Defines the central_columns parameters for the current user - * - * @return array|bool the central_columns parameters for the current user - * @access public - */ - public function getParams() - { - static $cfgCentralColumns = null; - - if (null !== $cfgCentralColumns) { - return $cfgCentralColumns; - } - - $cfgRelation = $this->relation->getRelationsParam(); - - if ($cfgRelation['centralcolumnswork']) { - $cfgCentralColumns = [ - 'user' => $this->user, - 'db' => $cfgRelation['db'], - 'table' => $cfgRelation['central_columns'], - ]; - } else { - $cfgCentralColumns = false; - } - - return $cfgCentralColumns; - } - - /** - * get $num columns of given database from central columns list - * starting at offset $from - * - * @param string $db selected database - * @param int $from starting offset of first result - * @param int $num maximum number of results to return - * - * @return array list of $num columns present in central columns list - * starting at offset $from for the given database - */ - public function getColumnsList(string $db, int $from = 0, int $num = 25): array - { - $cfgCentralColumns = $this->getParams(); - if (empty($cfgCentralColumns)) { - return []; - } - $pmadb = $cfgCentralColumns['db']; - $this->dbi->selectDb($pmadb, DatabaseInterface::CONNECT_CONTROL); - $central_list_table = $cfgCentralColumns['table']; - //get current values of $db from central column list - if ($num == 0) { - $query = 'SELECT * FROM ' . Util::backquote($central_list_table) . ' ' - . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\';'; - } else { - $query = 'SELECT * FROM ' . Util::backquote($central_list_table) . ' ' - . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\' ' - . 'LIMIT ' . $from . ', ' . $num . ';'; - } - $has_list = (array) $this->dbi->fetchResult( - $query, - null, - null, - DatabaseInterface::CONNECT_CONTROL - ); - $this->handleColumnExtra($has_list); - return $has_list; - } - - /** - * Get the number of columns present in central list for given db - * - * @param string $db current database - * - * @return int number of columns in central list of columns for $db - */ - public function getCount(string $db): int - { - $cfgCentralColumns = $this->getParams(); - if (empty($cfgCentralColumns)) { - return 0; - } - $pmadb = $cfgCentralColumns['db']; - $this->dbi->selectDb($pmadb, DatabaseInterface::CONNECT_CONTROL); - $central_list_table = $cfgCentralColumns['table']; - $query = 'SELECT count(db_name) FROM ' . - Util::backquote($central_list_table) . ' ' - . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\';'; - $res = $this->dbi->fetchResult( - $query, - null, - null, - DatabaseInterface::CONNECT_CONTROL - ); - if (isset($res[0])) { - return (int) $res[0]; - } - - return 0; - } - - /** - * return the existing columns in central list among the given list of columns - * - * @param string $db the selected database - * @param string $cols comma separated list of given columns - * @param boolean $allFields set if need all the fields of existing columns, - * otherwise only column_name is returned - * - * @return array list of columns in central columns among given set of columns - */ - private function findExistingColNames( - string $db, - string $cols, - bool $allFields = false - ): array { - $cfgCentralColumns = $this->getParams(); - if (empty($cfgCentralColumns)) { - return []; - } - $pmadb = $cfgCentralColumns['db']; - $this->dbi->selectDb($pmadb, DatabaseInterface::CONNECT_CONTROL); - $central_list_table = $cfgCentralColumns['table']; - if ($allFields) { - $query = 'SELECT * FROM ' . Util::backquote($central_list_table) . ' ' - . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\' AND col_name IN (' . $cols . ');'; - $has_list = (array) $this->dbi->fetchResult( - $query, - null, - null, - DatabaseInterface::CONNECT_CONTROL - ); - $this->handleColumnExtra($has_list); - } else { - $query = 'SELECT col_name FROM ' - . Util::backquote($central_list_table) . ' ' - . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\' AND col_name IN (' . $cols . ');'; - $has_list = (array) $this->dbi->fetchResult( - $query, - null, - null, - DatabaseInterface::CONNECT_CONTROL - ); - } - - return $has_list; - } - - /** - * return error message to be displayed if central columns - * configuration storage is not completely configured - * - * @return Message - */ - private function configErrorMessage(): Message - { - return Message::error( - __( - 'The configuration storage is not ready for the central list' - . ' of columns feature.' - ) - ); - } - - /** - * build the insert query for central columns list given PMA storage - * db, central_columns table, column name and corresponding definition to be added - * - * @param string $column column to add into central list - * @param array $def list of attributes of the column being added - * @param string $db PMA configuration storage database name - * @param string $central_list_table central columns configuration storage table name - * - * @return string query string to insert the given column - * with definition into central list - */ - private function getInsertQuery( - string $column, - array $def, - string $db, - string $central_list_table - ): string { - $type = ""; - $length = 0; - $attribute = ""; - if (isset($def['Type'])) { - $extracted_columnspec = Util::extractColumnSpec($def['Type']); - $attribute = trim($extracted_columnspec['attribute']); - $type = $extracted_columnspec['type']; - $length = $extracted_columnspec['spec_in_brackets']; - } - if (isset($def['Attribute'])) { - $attribute = $def['Attribute']; - } - $collation = isset($def['Collation']) ? $def['Collation'] : ""; - $isNull = $def['Null'] == "NO" ? '0' : '1'; - $extra = isset($def['Extra']) ? $def['Extra'] : ""; - $default = isset($def['Default']) ? $def['Default'] : ""; - return 'INSERT INTO ' - . Util::backquote($central_list_table) . ' ' - . 'VALUES ( \'' . $this->dbi->escapeString($db) . '\' ,' - . '\'' . $this->dbi->escapeString($column) . '\',\'' - . $this->dbi->escapeString($type) . '\',' - . '\'' . $this->dbi->escapeString((string) $length) . '\',\'' - . $this->dbi->escapeString($collation) . '\',' - . '\'' . $this->dbi->escapeString($isNull) . '\',' - . '\'' . implode(',', [$extra, $attribute]) - . '\',\'' . $this->dbi->escapeString($default) . '\');'; - } - - /** - * If $isTable is true then unique columns from given tables as $field_select - * are added to central list otherwise the $field_select is considered as - * list of columns and these columns are added to central list if not already added - * - * @param array $field_select if $isTable is true selected tables list - * otherwise selected columns list - * @param bool $isTable if passed array is of tables or columns - * @param string $table if $isTable is false, then table name to - * which columns belong - * - * @return true|Message - */ - public function syncUniqueColumns( - array $field_select, - bool $isTable = true, - ?string $table = null - ) { - $cfgCentralColumns = $this->getParams(); - if (empty($cfgCentralColumns)) { - return $this->configErrorMessage(); - } - $db = $_POST['db']; - $pmadb = $cfgCentralColumns['db']; - $central_list_table = $cfgCentralColumns['table']; - $this->dbi->selectDb($db); - $existingCols = []; - $cols = ""; - $insQuery = []; - $fields = []; - $message = true; - if ($isTable) { - foreach ($field_select as $table) { - $fields[$table] = (array) $this->dbi->getColumns( - $db, - $table, - null, - true - ); - foreach ($fields[$table] as $field => $def) { - $cols .= "'" . $this->dbi->escapeString($field) . "',"; - } - } - - $has_list = $this->findExistingColNames($db, trim($cols, ',')); - foreach ($field_select as $table) { - foreach ($fields[$table] as $field => $def) { - if (! in_array($field, $has_list)) { - $has_list[] = $field; - $insQuery[] = $this->getInsertQuery( - $field, - $def, - $db, - $central_list_table - ); - } else { - $existingCols[] = "'" . $field . "'"; - } - } - } - } else { - if ($table === null) { - $table = $_POST['table']; - } - foreach ($field_select as $column) { - $cols .= "'" . $this->dbi->escapeString($column) . "',"; - } - $has_list = $this->findExistingColNames($db, trim($cols, ',')); - foreach ($field_select as $column) { - if (! in_array($column, $has_list)) { - $has_list[] = $column; - $field = (array) $this->dbi->getColumns( - $db, - $table, - $column, - true - ); - $insQuery[] = $this->getInsertQuery( - $column, - $field, - $db, - $central_list_table - ); - } else { - $existingCols[] = "'" . $column . "'"; - } - } - } - if (! empty($existingCols)) { - $existingCols = implode(",", array_unique($existingCols)); - $message = Message::notice( - sprintf( - __( - 'Could not add %1$s as they already exist in central list!' - ), - htmlspecialchars($existingCols) - ) - ); - $message->addMessage( - Message::notice( - "Please remove them first " - . "from central list if you want to update above columns" - ) - ); - } - $this->dbi->selectDb($pmadb, DatabaseInterface::CONNECT_CONTROL); - if (! empty($insQuery)) { - foreach ($insQuery as $query) { - if (! $this->dbi->tryQuery($query, DatabaseInterface::CONNECT_CONTROL)) { - $message = Message::error(__('Could not add columns!')); - $message->addMessage( - Message::rawError( - $this->dbi->getError(DatabaseInterface::CONNECT_CONTROL) - ) - ); - break; - } - } - } - return $message; - } - - /** - * if $isTable is true it removes all columns of given tables as $field_select from - * central columns list otherwise $field_select is columns list and it removes - * given columns if present in central list - * - * @param string $database Database name - * @param array $field_select if $isTable selected list of tables otherwise - * selected list of columns to remove from central list - * @param bool $isTable if passed array is of tables or columns - * - * @return true|Message - */ - public function deleteColumnsFromList( - string $database, - array $field_select, - bool $isTable = true - ) { - $cfgCentralColumns = $this->getParams(); - if (empty($cfgCentralColumns)) { - return $this->configErrorMessage(); - } - $pmadb = $cfgCentralColumns['db']; - $central_list_table = $cfgCentralColumns['table']; - $this->dbi->selectDb($database); - $message = true; - $colNotExist = []; - $fields = []; - if ($isTable) { - $cols = ''; - foreach ($field_select as $table) { - $fields[$table] = (array) $this->dbi->getColumnNames( - $database, - $table - ); - foreach ($fields[$table] as $col_select) { - $cols .= '\'' . $this->dbi->escapeString($col_select) . '\','; - } - } - $cols = trim($cols, ','); - $has_list = $this->findExistingColNames($database, $cols); - foreach ($field_select as $table) { - foreach ($fields[$table] as $column) { - if (! in_array($column, $has_list)) { - $colNotExist[] = "'" . $column . "'"; - } - } - } - } else { - $cols = ''; - foreach ($field_select as $col_select) { - $cols .= '\'' . $this->dbi->escapeString($col_select) . '\','; - } - $cols = trim($cols, ','); - $has_list = $this->findExistingColNames($database, $cols); - foreach ($field_select as $column) { - if (! in_array($column, $has_list)) { - $colNotExist[] = "'" . $column . "'"; - } - } - } - if (! empty($colNotExist)) { - $colNotExist = implode(",", array_unique($colNotExist)); - $message = Message::notice( - sprintf( - __( - 'Couldn\'t remove Column(s) %1$s ' - . 'as they don\'t exist in central columns list!' - ), - htmlspecialchars($colNotExist) - ) - ); - } - $this->dbi->selectDb($pmadb, DatabaseInterface::CONNECT_CONTROL); - - $query = 'DELETE FROM ' . Util::backquote($central_list_table) . ' ' - . 'WHERE db_name = \'' . $this->dbi->escapeString($database) . '\' AND col_name IN (' . $cols . ');'; - - if (! $this->dbi->tryQuery($query, DatabaseInterface::CONNECT_CONTROL)) { - $message = Message::error(__('Could not remove columns!')); - $message->addHtml('
' . htmlspecialchars($cols) . '
'); - $message->addMessage( - Message::rawError( - $this->dbi->getError(DatabaseInterface::CONNECT_CONTROL) - ) - ); - } - return $message; - } - - /** - * Make the columns of given tables consistent with central list of columns. - * Updates only those columns which are not being referenced. - * - * @param string $db current database - * @param array $selected_tables list of selected tables. - * - * @return true|Message - */ - public function makeConsistentWithList( - string $db, - array $selected_tables - ) { - $message = true; - foreach ($selected_tables as $table) { - $query = 'ALTER TABLE ' . Util::backquote($table); - $has_list = $this->getFromTable($db, $table, true); - $this->dbi->selectDb($db); - foreach ($has_list as $column) { - $column_status = $this->relation->checkChildForeignReferences( - $db, - $table, - $column['col_name'] - ); - //column definition can only be changed if - //it is not referenced by another column - if ($column_status['isEditable']) { - $query .= ' MODIFY ' . Util::backquote($column['col_name']) . ' ' - . $this->dbi->escapeString($column['col_type']); - if ($column['col_length']) { - $query .= '(' . $column['col_length'] . ')'; - } - - $query .= ' ' . $column['col_attribute']; - if ($column['col_isNull']) { - $query .= ' NULL'; - } else { - $query .= ' NOT NULL'; - } - - $query .= ' ' . $column['col_extra']; - if ($column['col_default']) { - if ($column['col_default'] != 'CURRENT_TIMESTAMP' - && $column['col_default'] != 'current_timestamp()') { - $query .= ' DEFAULT \'' . $this->dbi->escapeString( - (string) $column['col_default'] - ) . '\''; - } else { - $query .= ' DEFAULT ' . $this->dbi->escapeString( - $column['col_default'] - ); - } - } - $query .= ','; - } - } - $query = trim($query, " ,") . ";"; - if (! $this->dbi->tryQuery($query)) { - if ($message === true) { - $message = Message::error( - $this->dbi->getError() - ); - } else { - $message->addText( - $this->dbi->getError(), - '
' - ); - } - } - } - return $message; - } - - /** - * return the columns present in central list of columns for a given - * table of a given database - * - * @param string $db given database - * @param string $table given table - * @param boolean $allFields set if need all the fields of existing columns, - * otherwise only column_name is returned - * - * @return array columns present in central list from given table of given db. - */ - public function getFromTable( - string $db, - string $table, - bool $allFields = false - ): array { - $cfgCentralColumns = $this->getParams(); - if (empty($cfgCentralColumns)) { - return []; - } - $this->dbi->selectDb($db); - $fields = (array) $this->dbi->getColumnNames( - $db, - $table - ); - $cols = ''; - foreach ($fields as $col_select) { - $cols .= '\'' . $this->dbi->escapeString((string) $col_select) . '\','; - } - $cols = trim($cols, ','); - $has_list = $this->findExistingColNames($db, $cols, $allFields); - if (! empty($has_list)) { - return (array) $has_list; - } - - return []; - } - - /** - * update a column in central columns list if a edit is requested - * - * @param string $db current database - * @param string $orig_col_name original column name before edit - * @param string $col_name new column name - * @param string $col_type new column type - * @param string $col_attribute new column attribute - * @param string $col_length new column length - * @param int $col_isNull value 1 if new column isNull is true, 0 otherwise - * @param string $collation new column collation - * @param string $col_extra new column extra property - * @param string $col_default new column default value - * - * @return true|Message - */ - public function updateOneColumn( - string $db, - string $orig_col_name, - string $col_name, - string $col_type, - string $col_attribute, - string $col_length, - int $col_isNull, - string $collation, - string $col_extra, - string $col_default - ) { - $cfgCentralColumns = $this->getParams(); - if (empty($cfgCentralColumns)) { - return $this->configErrorMessage(); - } - $centralTable = $cfgCentralColumns['table']; - $this->dbi->selectDb($cfgCentralColumns['db'], DatabaseInterface::CONNECT_CONTROL); - if ($orig_col_name == "") { - $def = []; - $def['Type'] = $col_type; - if ($col_length) { - $def['Type'] .= '(' . $col_length . ')'; - } - $def['Collation'] = $collation; - $def['Null'] = $col_isNull ? __('YES') : __('NO'); - $def['Extra'] = $col_extra; - $def['Attribute'] = $col_attribute; - $def['Default'] = $col_default; - $query = $this->getInsertQuery($col_name, $def, $db, $centralTable); - } else { - $query = 'UPDATE ' . Util::backquote($centralTable) - . ' SET col_type = \'' . $this->dbi->escapeString($col_type) . '\'' - . ', col_name = \'' . $this->dbi->escapeString($col_name) . '\'' - . ', col_length = \'' . $this->dbi->escapeString($col_length) . '\'' - . ', col_isNull = ' . $col_isNull - . ', col_collation = \'' . $this->dbi->escapeString($collation) . '\'' - . ', col_extra = \'' - . implode(',', [$col_extra, $col_attribute]) . '\'' - . ', col_default = \'' . $this->dbi->escapeString($col_default) . '\'' - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\' ' - . 'AND col_name = \'' . $this->dbi->escapeString($orig_col_name) - . '\''; - } - if (! $this->dbi->tryQuery($query, DatabaseInterface::CONNECT_CONTROL)) { - return Message::error( - $this->dbi->getError(DatabaseInterface::CONNECT_CONTROL) - ); - } - return true; - } - - /** - * Update Multiple column in central columns list if a change is requested - * - * @param array $params Request parameters - * @return true|Message - */ - public function updateMultipleColumn(array $params) - { - $columnDefault = $params['field_default_type']; - $columnIsNull = []; - $columnExtra = []; - $numberCentralFields = count($params['orig_col_name']); - for ($i = 0; $i < $numberCentralFields; $i++) { - $columnIsNull[$i] = isset($params['field_null'][$i]) ? 1 : 0; - $columnExtra[$i] = $params['col_extra'][$i] ?? ''; - - if ($columnDefault[$i] === 'NONE') { - $columnDefault[$i] = ''; - } elseif ($columnDefault[$i] === 'USER_DEFINED') { - $columnDefault[$i] = $params['field_default_value'][$i]; - } - - $message = $this->updateOneColumn( - $params['db'], - $params['orig_col_name'][$i], - $params['field_name'][$i], - $params['field_type'][$i], - $params['field_attribute'][$i], - $params['field_length'][$i], - $columnIsNull[$i], - $params['field_collation'][$i], - $columnExtra[$i], - $columnDefault[$i] - ); - if (! is_bool($message)) { - return $message; - } - } - return true; - } - - /** - * Function generate and return the table header for - * multiple edit central columns page - * - * @param array $headers headers list - * - * @return string html for table header in central columns multi edit page - */ - private function getEditTableHeader(array $headers): string - { - return $this->template->render('database/central_columns/edit_table_header', [ - 'headers' => $headers, - ]); - } - - /** - * build html for editing a row in central columns table - * - * @param array $row array contains complete information of a - * particular row of central list table - * @param int $row_num position the row in the table - * - * @return string html of a particular row in the central columns table. - */ - private function getHtmlForEditTableRow(array $row, int $row_num): string - { - $tableHtml = '' - . '' - . '' - . $this->template->render('columns_definitions/column_name', [ - 'column_number' => $row_num, - 'ci' => 0, - 'ci_offset' => 0, - 'column_meta' => [ - 'Field' => $row['col_name'], - ], - 'cfg_relation' => [ - 'centralcolumnswork' => false, - ], - 'max_rows' => $this->maxRows, - ]) - . ''; - $tableHtml .= - '' - . $this->template->render('columns_definitions/column_type', [ - 'column_number' => $row_num, - 'ci' => 1, - 'ci_offset' => 0, - 'type_upper' => mb_strtoupper($row['col_type']), - 'column_meta' => [], - ]) - . ''; - $tableHtml .= - '' - . $this->template->render('columns_definitions/column_length', [ - 'column_number' => $row_num, - 'ci' => 2, - 'ci_offset' => 0, - 'length_values_input_size' => 8, - 'length_to_display' => $row['col_length'], - ]) - . ''; - $meta = []; - if (! isset($row['col_default']) || $row['col_default'] == '') { - $meta['DefaultType'] = 'NONE'; - } elseif ($row['col_default'] == 'CURRENT_TIMESTAMP' - || $row['col_default'] == 'current_timestamp()' - ) { - $meta['DefaultType'] = 'CURRENT_TIMESTAMP'; - } elseif ($row['col_default'] == 'NULL') { - $meta['DefaultType'] = $row['col_default']; - } else { - $meta['DefaultType'] = 'USER_DEFINED'; - $meta['DefaultValue'] = $row['col_default']; - } - $tableHtml .= - '' - . $this->template->render('columns_definitions/column_default', [ - 'column_number' => $row_num, - 'ci' => 3, - 'ci_offset' => 0, - 'type_upper' => mb_strtoupper((string) $row['col_default']), - 'column_meta' => $meta, - 'char_editing' => $this->charEditing, - ]) - . ''; - $tableHtml .= ''; - $tableHtml .= '' . "\n"; - $tableHtml .= ''; - $tableHtml .= - '' - . $this->template->render('columns_definitions/column_attribute', [ - 'column_number' => $row_num, - 'ci' => 5, - 'ci_offset' => 0, - 'extracted_columnspec' => [ - 'attribute' => $row['col_attribute'], - ], - 'column_meta' => [], - 'submit_attribute' => false, - 'attribute_types' => $this->dbi->types->getAttributes(), - ]) - . ''; - $tableHtml .= - '' - . $this->template->render('columns_definitions/column_null', [ - 'column_number' => $row_num, - 'ci' => 6, - 'ci_offset' => 0, - 'column_meta' => [ - 'Null' => $row['col_isNull'], - ], - ]) - . ''; - - $tableHtml .= - '' - . $this->template->render('columns_definitions/column_extra', [ - 'column_number' => $row_num, - 'ci' => 7, - 'ci_offset' => 0, - 'column_meta' => ['Extra' => $row['col_extra']], - ]) - . ''; - $tableHtml .= ''; - return $tableHtml; - } - - /** - * get the list of columns in given database excluding - * the columns present in current table - * - * @param string $db selected database - * @param string $table current table name - * - * @return array encoded list of columns present in central list for the given - * database - */ - public function getListRaw(string $db, string $table): array - { - $cfgCentralColumns = $this->getParams(); - if (empty($cfgCentralColumns)) { - return []; - } - $centralTable = $cfgCentralColumns['table']; - if (empty($table) || $table == '') { - $query = 'SELECT * FROM ' . Util::backquote($centralTable) . ' ' - . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\';'; - } else { - $this->dbi->selectDb($db); - $columns = (array) $this->dbi->getColumnNames( - $db, - $table - ); - $cols = ''; - foreach ($columns as $col_select) { - $cols .= '\'' . $this->dbi->escapeString($col_select) . '\','; - } - $cols = trim($cols, ','); - $query = 'SELECT * FROM ' . Util::backquote($centralTable) . ' ' - . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\''; - if ($cols) { - $query .= ' AND col_name NOT IN (' . $cols . ')'; - } - $query .= ';'; - } - $this->dbi->selectDb($cfgCentralColumns['db'], DatabaseInterface::CONNECT_CONTROL); - $columns_list = (array) $this->dbi->fetchResult( - $query, - null, - null, - DatabaseInterface::CONNECT_CONTROL - ); - $this->handleColumnExtra($columns_list); - return $columns_list; - } - - /** - * Get HTML for "check all" check box with "with selected" dropdown - * - * @param string $pmaThemeImage pma theme image url - * @param string $text_dir url for text directory - * - * @return string - */ - public function getTableFooter(string $pmaThemeImage, string $text_dir): string - { - $html_output = $this->template->render('select_all', [ - 'pma_theme_image' => $pmaThemeImage, - 'text_dir' => $text_dir, - 'form_name' => 'tableslistcontainer', - ]); - $html_output .= Util::getButtonOrImage( - 'edit_central_columns', - 'mult_submit change_central_columns', - __('Edit'), - 'b_edit', - 'edit central columns' - ); - $html_output .= Util::getButtonOrImage( - 'delete_central_columns', - 'mult_submit', - __('Delete'), - 'b_drop', - 'remove_from_central_columns' - ); - return $html_output; - } - - /** - * function generate and return the table footer for - * multiple edit central columns page - * - * @return string html for table footer in central columns multi edit page - */ - private function getEditTableFooter(): string - { - return '
' - . '' - . '
'; - } - - /** - * Column `col_extra` is used to store both extra and attributes for a column. - * This method separates them. - * - * @param array $columns_list columns list - * - * @return void - */ - private function handleColumnExtra(array &$columns_list): void - { - foreach ($columns_list as &$row) { - $vals = explode(',', $row['col_extra']); - - if (in_array('BINARY', $vals)) { - $row['col_attribute'] = 'BINARY'; - } elseif (in_array('UNSIGNED', $vals)) { - $row['col_attribute'] = 'UNSIGNED'; - } elseif (in_array('UNSIGNED ZEROFILL', $vals)) { - $row['col_attribute'] = 'UNSIGNED ZEROFILL'; - } elseif (in_array('on update CURRENT_TIMESTAMP', $vals)) { - $row['col_attribute'] = 'on update CURRENT_TIMESTAMP'; - } else { - $row['col_attribute'] = ''; - } - - if (in_array('auto_increment', $vals)) { - $row['col_extra'] = 'auto_increment'; - } else { - $row['col_extra'] = ''; - } - } - } - - /** - * Get HTML for editing page central columns - * - * @param array $selected_fld Array containing the selected fields - * @param string $selected_db String containing the name of database - * - * @return string HTML for complete editing page for central columns - */ - public function getHtmlForEditingPage(array $selected_fld, string $selected_db): string - { - $html = '
'; - $header_cells = [ - __('Name'), - __('Type'), - __('Length/Values'), - __('Default'), - __('Collation'), - __('Attributes'), - __('Null'), - __('A_I'), - ]; - $html .= $this->getEditTableHeader($header_cells); - $selected_fld_safe = []; - foreach ($selected_fld as $key) { - $selected_fld_safe[] = $this->dbi->escapeString($key); - } - $columns_list = implode("','", $selected_fld_safe); - $columns_list = "'" . $columns_list . "'"; - $list_detail_cols = $this->findExistingColNames($selected_db, $columns_list, true); - $row_num = 0; - foreach ($list_detail_cols as $row) { - $tableHtmlRow = $this->getHtmlForEditTableRow( - $row, - $row_num - ); - $html .= $tableHtmlRow; - $row_num++; - } - $html .= ''; - $html .= $this->getEditTableFooter(); - $html .= '
'; - return $html; - } - - /** - * get number of columns of given database from central columns list - * starting at offset $from - * - * @param string $db selected database - * @param int $from starting offset of first result - * @param int $num maximum number of results to return - * - * @return int count of $num columns present in central columns list - * starting at offset $from for the given database - */ - public function getColumnsCount(string $db, int $from = 0, int $num = 25): int - { - $cfgCentralColumns = $this->getParams(); - if (empty($cfgCentralColumns)) { - return 0; - } - $pmadb = $cfgCentralColumns['db']; - $this->dbi->selectDb($pmadb, DatabaseInterface::CONNECT_CONTROL); - $central_list_table = $cfgCentralColumns['table']; - //get current values of $db from central column list - $query = 'SELECT COUNT(db_name) FROM ' . Util::backquote($central_list_table) . ' ' - . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\'' . - ($num === 0 ? '' : 'LIMIT ' . $from . ', ' . $num) . ';'; - $result = (array) $this->dbi->fetchResult( - $query, - null, - null, - DatabaseInterface::CONNECT_CONTROL - ); - - if (isset($result[0])) { - return (int) $result[0]; - } - - return -1; - } - - /** - * build dropdown select html to select column in selected table, - * include only columns which are not already in central list - * - * @param string $db current database to which selected table belongs - * @param string $selected_tbl selected table - * - * @return string html to select column - */ - public function getHtmlForColumnDropdown($db, $selected_tbl) - { - $existing_cols = $this->getFromTable($db, $selected_tbl); - $this->dbi->selectDb($db); - $columns = (array) $this->dbi->getColumnNames( - $db, - $selected_tbl - ); - $selectColHtml = ""; - foreach ($columns as $column) { - if (! in_array($column, $existing_cols)) { - $selectColHtml .= ''; - } - } - return $selectColHtml; - } - - /** - * build html for adding a new user defined column to central list - * - * @param string $db current database - * @param int $total_rows number of rows in central columns - * @param int $pos offset of first result with complete result set - * @param string $pmaThemeImage table footer theme image directorie - * @param string $text_dir table footer arrow direction - * - * @return string html of the form to let user add a new user defined column to the - * list - */ - public function getHtmlForMain( - string $db, - int $total_rows, - int $pos, - string $pmaThemeImage, - string $text_dir - ): string { - $max_rows = $this->maxRows; - $attribute_types = $this->dbi->types->getAttributes(); - - $tn_pageNow = ($pos / $this->maxRows) + 1; - $tn_nbTotalPage = ceil($total_rows / $this->maxRows); - $tn_page_selector = $tn_nbTotalPage > 1 ? Util::pageselector( - 'pos', - $this->maxRows, - $tn_pageNow, - $tn_nbTotalPage - ) : ''; - $this->dbi->selectDb($db); - $tables = $this->dbi->getTables($db); - $rows_list = $this->getColumnsList($db, $pos, $max_rows); - - $rows_meta = []; - $types_upper = []; - $row_num = 0; - foreach ($rows_list as $row) { - $rows_meta[$row_num] = []; - if (! isset($row['col_default']) || $row['col_default'] == '') { - $rows_meta[$row_num]['DefaultType'] = 'NONE'; - } else { - if ($row['col_default'] == 'CURRENT_TIMESTAMP' - || $row['col_default'] == 'current_timestamp()' - ) { - $rows_meta[$row_num]['DefaultType'] = 'CURRENT_TIMESTAMP'; - } elseif ($row['col_default'] == 'NULL') { - $rows_meta[$row_num]['DefaultType'] = $row['col_default']; - } else { - $rows_meta[$row_num]['DefaultType'] = 'USER_DEFINED'; - $rows_meta[$row_num]['DefaultValue'] = $row['col_default']; - } - } - $types_upper[$row_num] = mb_strtoupper((string) $row['col_type']); - $row_num++; - } - - $charsets = Charsets::getCharsets($this->dbi, $this->disableIs); - $collations = Charsets::getCollations($this->dbi, $this->disableIs); - $charsetsList = []; - /** @var Charset $charset */ - foreach ($charsets as $charset) { - $collationsList = []; - /** @var Collation $collation */ - foreach ($collations[$charset->getName()] as $collation) { - $collationsList[] = [ - 'name' => $collation->getName(), - 'description' => $collation->getDescription(), - ]; - } - $charsetsList[] = [ - 'name' => $charset->getName(), - 'description' => $charset->getDescription(), - 'collations' => $collationsList, - ]; - } - - return $this->template->render('database/central_columns/main', [ - "db" => $db, - "total_rows" => $total_rows, - "max_rows" => $max_rows, - "pos" => $pos, - "char_editing" => $this->charEditing, - "attribute_types" => $attribute_types, - "tn_nbTotalPage" => $tn_nbTotalPage, - "tn_page_selector" => $tn_page_selector, - "tables" => $tables, - "rows_list" => $rows_list, - "rows_meta" => $rows_meta, - "types_upper" => $types_upper, - "pmaThemeImage" => $pmaThemeImage, - "text_dir" => $text_dir, - 'charsets' => $charsetsList, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Charsets.php b/srcs/phpmyadmin/libraries/classes/Charsets.php deleted file mode 100644 index 740ab09..0000000 --- a/srcs/phpmyadmin/libraries/classes/Charsets.php +++ /dev/null @@ -1,210 +0,0 @@ - 'big5', - 'cp-866' => 'cp866', - 'euc-jp' => 'ujis', - 'euc-kr' => 'euckr', - 'gb2312' => 'gb2312', - 'gbk' => 'gbk', - 'iso-8859-1' => 'latin1', - 'iso-8859-2' => 'latin2', - 'iso-8859-7' => 'greek', - 'iso-8859-8' => 'hebrew', - 'iso-8859-8-i' => 'hebrew', - 'iso-8859-9' => 'latin5', - 'iso-8859-13' => 'latin7', - 'iso-8859-15' => 'latin1', - 'koi8-r' => 'koi8r', - 'shift_jis' => 'sjis', - 'tis-620' => 'tis620', - 'utf-8' => 'utf8', - 'windows-1250' => 'cp1250', - 'windows-1251' => 'cp1251', - 'windows-1252' => 'latin1', - 'windows-1256' => 'cp1256', - 'windows-1257' => 'cp1257', - ]; - - /** - * The charset for the server - * @var Charset|null - */ - private static $serverCharset = null; - - /** - * @var array - */ - private static $charsets = []; - - /** - * @var array> - */ - private static $collations = []; - - /** - * Loads charset data from the server - * - * @param DatabaseInterface $dbi DatabaseInterface instance - * @param boolean $disableIs Disable use of INFORMATION_SCHEMA - * - * @return void - */ - private static function loadCharsets(DatabaseInterface $dbi, bool $disableIs): void - { - /* Data already loaded */ - if (count(self::$charsets) > 0) { - return; - } - - if ($disableIs) { - $sql = 'SHOW CHARACTER SET'; - } else { - $sql = 'SELECT `CHARACTER_SET_NAME` AS `Charset`,' - . ' `DEFAULT_COLLATE_NAME` AS `Default collation`,' - . ' `DESCRIPTION` AS `Description`,' - . ' `MAXLEN` AS `Maxlen`' - . ' FROM `information_schema`.`CHARACTER_SETS`'; - } - $res = $dbi->query($sql); - - self::$charsets = []; - while ($row = $dbi->fetchAssoc($res)) { - self::$charsets[$row['Charset']] = Charset::fromServer($row); - } - $dbi->freeResult($res); - - ksort(self::$charsets, SORT_STRING); - } - - /** - * Loads collation data from the server - * - * @param DatabaseInterface $dbi DatabaseInterface instance - * @param boolean $disableIs Disable use of INFORMATION_SCHEMA - * - * @return void - */ - private static function loadCollations(DatabaseInterface $dbi, bool $disableIs): void - { - /* Data already loaded */ - if (count(self::$collations) > 0) { - return; - } - - if ($disableIs) { - $sql = 'SHOW COLLATION'; - } else { - $sql = 'SELECT `COLLATION_NAME` AS `Collation`,' - . ' `CHARACTER_SET_NAME` AS `Charset`,' - . ' `ID` AS `Id`,' - . ' `IS_DEFAULT` AS `Default`,' - . ' `IS_COMPILED` AS `Compiled`,' - . ' `SORTLEN` AS `Sortlen`' - . ' FROM `information_schema`.`COLLATIONS`'; - } - $res = $dbi->query($sql); - - self::$collations = []; - while ($row = $dbi->fetchAssoc($res)) { - self::$collations[$row['Charset']][$row['Collation']] = Collation::fromServer($row); - } - $dbi->freeResult($res); - - foreach (array_keys(self::$collations) as $charset) { - ksort(self::$collations[$charset], SORT_STRING); - } - } - - /** - * Get current server charset - * - * @param DatabaseInterface $dbi DatabaseInterface instance - * @param boolean $disableIs Disable use of INFORMATION_SCHEMA - * - * @return Charset - */ - public static function getServerCharset(DatabaseInterface $dbi, bool $disableIs): Charset - { - if (self::$serverCharset !== null) { - return self::$serverCharset; - } - self::loadCharsets($dbi, $disableIs); - $serverCharset = $dbi->getVariable('character_set_server'); - if (! is_string($serverCharset)) {// MySQL 5.7.8 fallback, issue #15614 - $serverCharset = $dbi->fetchValue("SELECT @@character_set_server;"); - } - self::$serverCharset = self::$charsets[$serverCharset]; - return self::$serverCharset; - } - - /** - * Get all server charsets - * - * @param DatabaseInterface $dbi DatabaseInterface instance - * @param boolean $disableIs Disable use of INFORMATION_SCHEMA - * - * @return array - */ - public static function getCharsets(DatabaseInterface $dbi, bool $disableIs): array - { - self::loadCharsets($dbi, $disableIs); - return self::$charsets; - } - - /** - * Get all server collations - * - * @param DatabaseInterface $dbi DatabaseInterface instance - * @param boolean $disableIs Disable use of INFORMATION_SCHEMA - * - * @return array - */ - public static function getCollations(DatabaseInterface $dbi, bool $disableIs): array - { - self::loadCollations($dbi, $disableIs); - return self::$collations; - } - - /** - * @param DatabaseInterface $dbi DatabaseInterface instance - * @param bool $disableIs Disable use of INFORMATION_SCHEMA - * @param string|null $name Collation name - * - * @return Collation|null - */ - public static function findCollationByName(DatabaseInterface $dbi, bool $disableIs, ?string $name): ?Collation - { - $pieces = explode('_', (string) $name); - if ($pieces === false || ! isset($pieces[0])) { - return null; - } - $charset = $pieces[0]; - $collations = self::getCollations($dbi, $disableIs); - return $collations[$charset][$name] ?? null; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Charsets/Charset.php b/srcs/phpmyadmin/libraries/classes/Charsets/Charset.php deleted file mode 100644 index 0b25790..0000000 --- a/srcs/phpmyadmin/libraries/classes/Charsets/Charset.php +++ /dev/null @@ -1,103 +0,0 @@ -name = $name; - $this->description = $description; - $this->defaultCollation = $defaultCollation; - $this->maxLength = $maxLength; - } - - /** - * @param array $state State obtained from the database server - * @return Charset - */ - public static function fromServer(array $state): self - { - return new self( - $state['Charset'] ?? '', - $state['Description'] ?? '', - $state['Default collation'] ?? '', - (int) ($state['Maxlen'] ?? 0) - ); - } - - /** - * @return string - */ - public function getName(): string - { - return $this->name; - } - - /** - * @return string - */ - public function getDescription(): string - { - return $this->description; - } - - /** - * @return string - */ - public function getDefaultCollation(): string - { - return $this->defaultCollation; - } - - /** - * @return int - */ - public function getMaxLength(): int - { - return $this->maxLength; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Charsets/Collation.php b/srcs/phpmyadmin/libraries/classes/Charsets/Collation.php deleted file mode 100644 index fa2b85f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Charsets/Collation.php +++ /dev/null @@ -1,549 +0,0 @@ -name = $name; - $this->charset = $charset; - $this->id = $id; - $this->isDefault = $isDefault; - $this->isCompiled = $isCompiled; - $this->sortLength = $sortLength; - $this->padAttribute = $padAttribute; - $this->description = $this->buildDescription(); - } - - /** - * @param array $state State obtained from the database server - * @return self - */ - public static function fromServer(array $state): self - { - return new self( - $state['Collation'] ?? '', - $state['Charset'] ?? '', - (int) ($state['Id'] ?? 0), - isset($state['Default']) && ($state['Default'] === 'Yes' || $state['Default'] === '1'), - isset($state['Compiled']) && ($state['Compiled'] === 'Yes' || $state['Compiled'] === '1'), - (int) ($state['Sortlen'] ?? 0), - $state['Pad_attribute'] ?? '' - ); - } - - /** - * @return string - */ - public function getName(): string - { - return $this->name; - } - - /** - * @return string - */ - public function getDescription(): string - { - return $this->description; - } - - /** - * @return string - */ - public function getCharset(): string - { - return $this->charset; - } - - /** - * @return int - */ - public function getId(): int - { - return $this->id; - } - - /** - * @return bool - */ - public function isDefault(): bool - { - return $this->isDefault; - } - - /** - * @return bool - */ - public function isCompiled(): bool - { - return $this->isCompiled; - } - - /** - * @return int - */ - public function getSortLength(): int - { - return $this->sortLength; - } - - /** - * @return string - */ - public function getPadAttribute(): string - { - return $this->padAttribute; - } - - /** - * Returns description for given collation - * - * @return string collation description - */ - private function buildDescription(): string - { - $parts = explode('_', $this->getName()); - - $name = __('Unknown'); - $variant = null; - $suffixes = []; - $unicode = false; - $unknown = false; - - $level = 0; - foreach ($parts as $part) { - if ($level == 0) { - /* Next will be language */ - $level = 1; - /* First should be charset */ - switch ($part) { - case 'binary': - $name = _pgettext('Collation', 'Binary'); - break; - // Unicode charsets - case 'utf8mb4': - $variant = 'UCA 4.0.0'; - // Fall through to other unicode - case 'ucs2': - case 'utf8': - case 'utf16': - case 'utf16le': - case 'utf16be': - case 'utf32': - $name = _pgettext('Collation', 'Unicode'); - $unicode = true; - break; - // West European charsets - case 'ascii': - case 'cp850': - case 'dec8': - case 'hp8': - case 'latin1': - case 'macroman': - $name = _pgettext('Collation', 'West European'); - break; - // Central European charsets - case 'cp1250': - case 'cp852': - case 'latin2': - case 'macce': - $name = _pgettext('Collation', 'Central European'); - break; - // Russian charsets - case 'cp866': - case 'koi8r': - $name = _pgettext('Collation', 'Russian'); - break; - // Chinese charsets - case 'gb2312': - case 'gbk': - $name = _pgettext('Collation', 'Simplified Chinese'); - break; - case 'big5': - $name = _pgettext('Collation', 'Traditional Chinese'); - break; - case 'gb18030': - $name = _pgettext('Collation', 'Chinese'); - $unicode = true; - break; - // Japanese charsets - case 'sjis': - case 'ujis': - case 'cp932': - case 'eucjpms': - $name = _pgettext('Collation', 'Japanese'); - break; - // Baltic charsets - case 'cp1257': - case 'latin7': - $name = _pgettext('Collation', 'Baltic'); - break; - // Other - case 'armscii8': - case 'armscii': - $name = _pgettext('Collation', 'Armenian'); - break; - case 'cp1251': - $name = _pgettext('Collation', 'Cyrillic'); - break; - case 'cp1256': - $name = _pgettext('Collation', 'Arabic'); - break; - case 'euckr': - $name = _pgettext('Collation', 'Korean'); - break; - case 'hebrew': - $name = _pgettext('Collation', 'Hebrew'); - break; - case 'geostd8': - $name = _pgettext('Collation', 'Georgian'); - break; - case 'greek': - $name = _pgettext('Collation', 'Greek'); - break; - case 'keybcs2': - $name = _pgettext('Collation', 'Czech-Slovak'); - break; - case 'koi8u': - $name = _pgettext('Collation', 'Ukrainian'); - break; - case 'latin5': - $name = _pgettext('Collation', 'Turkish'); - break; - case 'swe7': - $name = _pgettext('Collation', 'Swedish'); - break; - case 'tis620': - $name = _pgettext('Collation', 'Thai'); - break; - default: - $name = _pgettext('Collation', 'Unknown'); - $unknown = true; - break; - } - continue; - } - if ($level == 1) { - /* Next will be variant unless changed later */ - $level = 4; - /* Locale name or code */ - $found = true; - switch ($part) { - case 'general': - break; - case 'bulgarian': - case 'bg': - $name = _pgettext('Collation', 'Bulgarian'); - break; - case 'chinese': - case 'cn': - case 'zh': - if ($unicode) { - $name = _pgettext('Collation', 'Chinese'); - } - break; - case 'croatian': - case 'hr': - $name = _pgettext('Collation', 'Croatian'); - break; - case 'czech': - case 'cs': - $name = _pgettext('Collation', 'Czech'); - break; - case 'danish': - case 'da': - $name = _pgettext('Collation', 'Danish'); - break; - case 'english': - case 'en': - $name = _pgettext('Collation', 'English'); - break; - case 'esperanto': - case 'eo': - $name = _pgettext('Collation', 'Esperanto'); - break; - case 'estonian': - case 'et': - $name = _pgettext('Collation', 'Estonian'); - break; - case 'german1': - $name = _pgettext('Collation', 'German (dictionary order)'); - break; - case 'german2': - $name = _pgettext('Collation', 'German (phone book order)'); - break; - case 'german': - case 'de': - /* Name is set later */ - $level = 2; - break; - case 'hungarian': - case 'hu': - $name = _pgettext('Collation', 'Hungarian'); - break; - case 'icelandic': - case 'is': - $name = _pgettext('Collation', 'Icelandic'); - break; - case 'japanese': - case 'ja': - $name = _pgettext('Collation', 'Japanese'); - break; - case 'la': - $name = _pgettext('Collation', 'Classical Latin'); - break; - case 'latvian': - case 'lv': - $name = _pgettext('Collation', 'Latvian'); - break; - case 'lithuanian': - case 'lt': - $name = _pgettext('Collation', 'Lithuanian'); - break; - case 'korean': - case 'ko': - $name = _pgettext('Collation', 'Korean'); - break; - case 'myanmar': - case 'my': - $name = _pgettext('Collation', 'Burmese'); - break; - case 'persian': - $name = _pgettext('Collation', 'Persian'); - break; - case 'polish': - case 'pl': - $name = _pgettext('Collation', 'Polish'); - break; - case 'roman': - $name = _pgettext('Collation', 'West European'); - break; - case 'romanian': - case 'ro': - $name = _pgettext('Collation', 'Romanian'); - break; - case 'ru': - $name = _pgettext('Collation', 'Russian'); - break; - case 'si': - case 'sinhala': - $name = _pgettext('Collation', 'Sinhalese'); - break; - case 'slovak': - case 'sk': - $name = _pgettext('Collation', 'Slovak'); - break; - case 'slovenian': - case 'sl': - $name = _pgettext('Collation', 'Slovenian'); - break; - case 'spanish': - $name = _pgettext('Collation', 'Spanish (modern)'); - break; - case 'es': - /* Name is set later */ - $level = 3; - break; - case 'spanish2': - $name = _pgettext('Collation', 'Spanish (traditional)'); - break; - case 'swedish': - case 'sv': - $name = _pgettext('Collation', 'Swedish'); - break; - case 'thai': - case 'th': - $name = _pgettext('Collation', 'Thai'); - break; - case 'turkish': - case 'tr': - $name = _pgettext('Collation', 'Turkish'); - break; - case 'ukrainian': - case 'uk': - $name = _pgettext('Collation', 'Ukrainian'); - break; - case 'vietnamese': - case 'vi': - $name = _pgettext('Collation', 'Vietnamese'); - break; - case 'unicode': - if ($unknown) { - $name = _pgettext('Collation', 'Unicode'); - } - break; - default: - $found = false; - } - if ($found) { - continue; - } - // Not parsed token, fall to next level - } - if ($level == 2) { - /* Next will be variant */ - $level = 4; - /* Germal variant */ - if ($part == 'pb') { - $name = _pgettext('Collation', 'German (phone book order)'); - continue; - } - $name = _pgettext('Collation', 'German (dictionary order)'); - // Not parsed token, fall to next level - } - if ($level == 3) { - /* Next will be variant */ - $level = 4; - /* Spanish variant */ - if ($part == 'trad') { - $name = _pgettext('Collation', 'Spanish (traditional)'); - continue; - } - $name = _pgettext('Collation', 'Spanish (modern)'); - // Not parsed token, fall to next level - } - if ($level == 4) { - /* Next will be suffix */ - $level = 5; - /* Variant */ - $found = true; - switch ($part) { - case '0900': - $variant = 'UCA 9.0.0'; - break; - case '520': - $variant = 'UCA 5.2.0'; - break; - case 'mysql561': - $variant = 'MySQL 5.6.1'; - break; - case 'mysql500': - $variant = 'MySQL 5.0.0'; - break; - default: - $found = false; - } - if ($found) { - continue; - } - // Not parsed token, fall to next level - } - if ($level == 5) { - /* Suffixes */ - switch ($part) { - case 'ci': - $suffixes[] = _pgettext('Collation variant', 'case-insensitive'); - break; - case 'cs': - $suffixes[] = _pgettext('Collation variant', 'case-sensitive'); - break; - case 'ai': - $suffixes[] = _pgettext('Collation variant', 'accent-insensitive'); - break; - case 'as': - $suffixes[] = _pgettext('Collation variant', 'accent-sensitive'); - break; - case 'ks': - $suffixes[] = _pgettext('Collation variant', 'kana-sensitive'); - break; - case 'w2': - case 'l2': - $suffixes[] = _pgettext('Collation variant', 'multi-level'); - break; - case 'bin': - $suffixes[] = _pgettext('Collation variant', 'binary'); - break; - case 'nopad': - $suffixes[] = _pgettext('Collation variant', 'no-pad'); - break; - } - } - } - - $result = $name; - if ($variant !== null) { - $result .= ' (' . $variant . ')'; - } - if (count($suffixes) > 0) { - $result .= ', ' . implode(', ', $suffixes); - } - return $result; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/CheckUserPrivileges.php b/srcs/phpmyadmin/libraries/classes/CheckUserPrivileges.php deleted file mode 100644 index 0614675..0000000 --- a/srcs/phpmyadmin/libraries/classes/CheckUserPrivileges.php +++ /dev/null @@ -1,372 +0,0 @@ -dbi = $dbi; - } - - /** - * Extracts details from a result row of a SHOW GRANT query - * - * @param string $row grant row - * - * @return array - */ - public function getItemsFromShowGrantsRow(string $row): array - { - $db_name_offset = mb_strpos($row, ' ON ') + 4; - - $tblname_end_offset = mb_strpos($row, ' TO '); - $tblname_start_offset = false; - - if (($__tblname_start_offset = mb_strpos($row, '`.', $db_name_offset)) - && $__tblname_start_offset - < $tblname_end_offset) { - $tblname_start_offset = $__tblname_start_offset + 1; - } - - if (! $tblname_start_offset) { - $tblname_start_offset = mb_strpos($row, '.', $db_name_offset); - } - - $show_grants_dbname = mb_substr( - $row, - $db_name_offset, - $tblname_start_offset - $db_name_offset - ); - - $show_grants_dbname = Util::unQuote($show_grants_dbname, '`'); - - $show_grants_str = mb_substr( - $row, - 6, - mb_strpos($row, ' ON ') - 6 - ); - - $show_grants_tblname = mb_substr( - $row, - $tblname_start_offset + 1, - $tblname_end_offset - $tblname_start_offset - 1 - ); - $show_grants_tblname = Util::unQuote($show_grants_tblname, '`'); - - return [ - $show_grants_str, - $show_grants_dbname, - $show_grants_tblname, - ]; - } - - /** - * Check if user has required privileges for - * performing 'Adjust privileges' operations - * - * @param string $show_grants_str string containing grants for user - * @param string $show_grants_dbname name of db extracted from grant string - * @param string $show_grants_tblname name of table extracted from grant string - * - * @return void - */ - public function checkRequiredPrivilegesForAdjust( - string $show_grants_str, - string $show_grants_dbname, - string $show_grants_tblname - ): void { - // '... ALL PRIVILEGES ON *.* ...' OR '... ALL PRIVILEGES ON `mysql`.* ..' - // OR - // SELECT, INSERT, UPDATE, DELETE .... ON *.* OR `mysql`.* - if ($show_grants_str == 'ALL' - || $show_grants_str == 'ALL PRIVILEGES' - || (mb_strpos( - $show_grants_str, - 'SELECT, INSERT, UPDATE, DELETE' - ) !== false) - ) { - if ($show_grants_dbname == '*' - && $show_grants_tblname == '*' - ) { - $GLOBALS['col_priv'] = true; - $GLOBALS['db_priv'] = true; - $GLOBALS['proc_priv'] = true; - $GLOBALS['table_priv'] = true; - - if ($show_grants_str == 'ALL PRIVILEGES' - || $show_grants_str == 'ALL' - ) { - $GLOBALS['is_reload_priv'] = true; - } - } - - // check for specific tables in `mysql` db - // Ex. '... ALL PRIVILEGES on `mysql`.`columns_priv` .. ' - if ($show_grants_dbname == 'mysql') { - switch ($show_grants_tblname) { - case "columns_priv": - $GLOBALS['col_priv'] = true; - break; - case "db": - $GLOBALS['db_priv'] = true; - break; - case "procs_priv": - $GLOBALS['proc_priv'] = true; - break; - case "tables_priv": - $GLOBALS['table_priv'] = true; - break; - case "*": - $GLOBALS['col_priv'] = true; - $GLOBALS['db_priv'] = true; - $GLOBALS['proc_priv'] = true; - $GLOBALS['table_priv'] = true; - break; - default: - } - } - } - } - - /** - * sets privilege information extracted from SHOW GRANTS result - * - * Detection for some CREATE privilege. - * - * Since MySQL 4.1.2, we can easily detect current user's grants using $userlink - * (no control user needed) and we don't have to try any other method for - * detection - * - * @todo fix to get really all privileges, not only explicitly defined for this user - * from MySQL manual: (https://dev.mysql.com/doc/refman/5.0/en/show-grants.html) - * SHOW GRANTS displays only the privileges granted explicitly to the named - * account. Other privileges might be available to the account, but they are not - * displayed. For example, if an anonymous account exists, the named account - * might be able to use its privileges, but SHOW GRANTS will not display them. - * - * @return void - */ - private function analyseShowGrant(): void - { - if (Util::cacheExists('is_create_db_priv')) { - $GLOBALS['is_create_db_priv'] = Util::cacheGet( - 'is_create_db_priv' - ); - $GLOBALS['is_reload_priv'] = Util::cacheGet( - 'is_reload_priv' - ); - $GLOBALS['db_to_create'] = Util::cacheGet( - 'db_to_create' - ); - $GLOBALS['dbs_where_create_table_allowed'] = Util::cacheGet( - 'dbs_where_create_table_allowed' - ); - $GLOBALS['dbs_to_test'] = Util::cacheGet( - 'dbs_to_test' - ); - - $GLOBALS['db_priv'] = Util::cacheGet( - 'db_priv' - ); - $GLOBALS['col_priv'] = Util::cacheGet( - 'col_priv' - ); - $GLOBALS['table_priv'] = Util::cacheGet( - 'table_priv' - ); - $GLOBALS['proc_priv'] = Util::cacheGet( - 'proc_priv' - ); - - return; - } - - // defaults - $GLOBALS['is_create_db_priv'] = false; - $GLOBALS['is_reload_priv'] = false; - $GLOBALS['db_to_create'] = ''; - $GLOBALS['dbs_where_create_table_allowed'] = []; - $GLOBALS['dbs_to_test'] = $this->dbi->getSystemSchemas(); - $GLOBALS['proc_priv'] = false; - $GLOBALS['db_priv'] = false; - $GLOBALS['col_priv'] = false; - $GLOBALS['table_priv'] = false; - - $rs_usr = $this->dbi->tryQuery('SHOW GRANTS'); - - if (! $rs_usr) { - return; - } - - $re0 = '(^|(\\\\\\\\)+|[^\\\\])'; // non-escaped wildcards - $re1 = '(^|[^\\\\])(\\\)+'; // escaped wildcards - - while ($row = $this->dbi->fetchRow($rs_usr)) { - list( - $show_grants_str, - $show_grants_dbname, - $show_grants_tblname - ) = $this->getItemsFromShowGrantsRow($row[0]); - - if ($show_grants_dbname == '*') { - if ($show_grants_str != 'USAGE') { - $GLOBALS['dbs_to_test'] = false; - } - } elseif ($GLOBALS['dbs_to_test'] !== false) { - $GLOBALS['dbs_to_test'][] = $show_grants_dbname; - } - - if (mb_strpos($show_grants_str, 'RELOAD') !== false) { - $GLOBALS['is_reload_priv'] = true; - } - - // check for the required privileges for adjust - $this->checkRequiredPrivilegesForAdjust( - $show_grants_str, - $show_grants_dbname, - $show_grants_tblname - ); - - /** - * @todo if we find CREATE VIEW but not CREATE, do not offer - * the create database dialog box - */ - if ($show_grants_str == 'ALL' - || $show_grants_str == 'ALL PRIVILEGES' - || $show_grants_str == 'CREATE' - || strpos($show_grants_str, 'CREATE,') !== false - ) { - if ($show_grants_dbname == '*') { - // a global CREATE privilege - $GLOBALS['is_create_db_priv'] = true; - $GLOBALS['is_reload_priv'] = true; - $GLOBALS['db_to_create'] = ''; - $GLOBALS['dbs_where_create_table_allowed'][] = '*'; - // @todo we should not break here, cause GRANT ALL *.* - // could be revoked by a later rule like GRANT SELECT ON db.* - break; - } else { - // this array may contain wildcards - $GLOBALS['dbs_where_create_table_allowed'][] = $show_grants_dbname; - - $dbname_to_test = Util::backquote($show_grants_dbname); - - if ($GLOBALS['is_create_db_priv']) { - // no need for any more tests if we already know this - continue; - } - - // does this db exist? - if ((preg_match('/' . $re0 . '%|_/', $show_grants_dbname) - && ! preg_match('/\\\\%|\\\\_/', $show_grants_dbname)) - || (! $this->dbi->tryQuery( - 'USE ' . preg_replace( - '/' . $re1 . '(%|_)/', - '\\1\\3', - $dbname_to_test - ) - ) - && mb_substr($this->dbi->getError(), 1, 4) != 1044) - ) { - /** - * Do not handle the underscore wildcard - * (this case must be rare anyway) - */ - $GLOBALS['db_to_create'] = preg_replace( - '/' . $re0 . '%/', - '\\1', - $show_grants_dbname - ); - $GLOBALS['db_to_create'] = preg_replace( - '/' . $re1 . '(%|_)/', - '\\1\\3', - $GLOBALS['db_to_create'] - ); - $GLOBALS['is_create_db_priv'] = true; - - /** - * @todo collect $GLOBALS['db_to_create'] into an array, - * to display a drop-down in the "Create database" dialog - */ - // we don't break, we want all possible databases - //break; - } // end if - } // end elseif - } // end if - } // end while - - $this->dbi->freeResult($rs_usr); - - // must also cacheUnset() them in - // PhpMyAdmin\Plugins\Auth\AuthenticationCookie - Util::cacheSet('is_create_db_priv', $GLOBALS['is_create_db_priv']); - Util::cacheSet('is_reload_priv', $GLOBALS['is_reload_priv']); - Util::cacheSet('db_to_create', $GLOBALS['db_to_create']); - Util::cacheSet( - 'dbs_where_create_table_allowed', - $GLOBALS['dbs_where_create_table_allowed'] - ); - Util::cacheSet('dbs_to_test', $GLOBALS['dbs_to_test']); - - Util::cacheSet('proc_priv', $GLOBALS['proc_priv']); - Util::cacheSet('table_priv', $GLOBALS['table_priv']); - Util::cacheSet('col_priv', $GLOBALS['col_priv']); - Util::cacheSet('db_priv', $GLOBALS['db_priv']); - } - - /** - * Get user's global privileges and some db-specific privileges - * - * @return void - */ - public function getPrivileges(): void - { - $username = ''; - - $current = $this->dbi->getCurrentUserAndHost(); - if (! empty($current)) { - list($username, ) = $current; - } - - // If MySQL is started with --skip-grant-tables - if ($username === '') { - $GLOBALS['is_create_db_priv'] = true; - $GLOBALS['is_reload_priv'] = true; - $GLOBALS['db_to_create'] = ''; - $GLOBALS['dbs_where_create_table_allowed'] = ['*']; - $GLOBALS['dbs_to_test'] = false; - $GLOBALS['db_priv'] = true; - $GLOBALS['col_priv'] = true; - $GLOBALS['table_priv'] = true; - $GLOBALS['proc_priv'] = true; - } else { - $this->analyseShowGrant(); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config.php b/srcs/phpmyadmin/libraries/classes/Config.php deleted file mode 100644 index 0002462..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config.php +++ /dev/null @@ -1,1813 +0,0 @@ -settings = ['is_setup' => false]; - - // functions need to refresh in case of config file changed goes in - // PhpMyAdmin\Config::load() - $this->load($source); - - // other settings, independent from config file, comes in - $this->checkSystem(); - - $this->base_settings = $this->settings; - } - - /** - * sets system and application settings - * - * @return void - */ - public function checkSystem(): void - { - $this->set('PMA_VERSION', '5.0.1'); - /* Major version */ - $this->set( - 'PMA_MAJOR_VERSION', - implode('.', array_slice(explode('.', $this->get('PMA_VERSION'), 3), 0, 2)) - ); - - $this->checkWebServerOs(); - $this->checkWebServer(); - $this->checkGd2(); - $this->checkClient(); - $this->checkUpload(); - $this->checkUploadSize(); - $this->checkOutputCompression(); - } - - /** - * whether to use gzip output compression or not - * - * @return void - */ - public function checkOutputCompression(): void - { - // 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); - } - - // enable output-buffering (if set to 'auto') - if (strtolower((string) $this->get('OBGzip')) == 'auto') { - $this->set('OBGzip', true); - } - } - - /** - * Sets the client platform based on user agent - * - * @param string $user_agent the user agent - * - * @return void - */ - private function _setClientPlatform(string $user_agent): void - { - if (mb_strstr($user_agent, 'Win')) { - $this->set('PMA_USR_OS', 'Win'); - } elseif (mb_strstr($user_agent, 'Mac')) { - $this->set('PMA_USR_OS', 'Mac'); - } elseif (mb_strstr($user_agent, 'Linux')) { - $this->set('PMA_USR_OS', 'Linux'); - } elseif (mb_strstr($user_agent, 'Unix')) { - $this->set('PMA_USR_OS', 'Unix'); - } elseif (mb_strstr($user_agent, 'OS/2')) { - $this->set('PMA_USR_OS', 'OS/2'); - } else { - $this->set('PMA_USR_OS', 'Other'); - } - } - - /** - * Determines platform (OS), browser and version of the user - * Based on a phpBuilder article: - * - * @see http://www.phpbuilder.net/columns/tim20000821.php - * - * @return void - */ - public function checkClient(): void - { - if (Core::getenv('HTTP_USER_AGENT')) { - $HTTP_USER_AGENT = Core::getenv('HTTP_USER_AGENT'); - } else { - $HTTP_USER_AGENT = ''; - } - - // 1. Platform - $this->_setClientPlatform($HTTP_USER_AGENT); - - // 2. browser and version - // (must check everything else before Mozilla) - - $is_mozilla = preg_match( - '@Mozilla/([0-9]\.[0-9]{1,2})@', - $HTTP_USER_AGENT, - $mozilla_version - ); - - 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( - '@(MS)?IE ([0-9]{1,2}\.[0-9]{1,2})@', - $HTTP_USER_AGENT, - $log_version - )) { - $this->set('PMA_USR_BROWSER_VER', $log_version[2]); - $this->set('PMA_USR_BROWSER_AGENT', 'IE'); - } elseif (preg_match( - '@Trident/(7)\.0@', - $HTTP_USER_AGENT, - $log_version - )) { - $this->set('PMA_USR_BROWSER_VER', intval($log_version[1]) + 4); - $this->set('PMA_USR_BROWSER_AGENT', 'IE'); - } elseif (preg_match( - '@OmniWeb/([0-9]{1,3})@', - $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 ($is_mozilla - && preg_match('@Chrome/([0-9.]*)@', $HTTP_USER_AGENT, $log_version) - ) { - $this->set('PMA_USR_BROWSER_VER', $log_version[1]); - $this->set('PMA_USR_BROWSER_AGENT', 'CHROME'); - // newer Safari - } elseif ($is_mozilla - && preg_match('@Version/(.*) Safari@', $HTTP_USER_AGENT, $log_version) - ) { - $this->set( - 'PMA_USR_BROWSER_VER', - $log_version[1] - ); - $this->set('PMA_USR_BROWSER_AGENT', 'SAFARI'); - // older Safari - } elseif ($is_mozilla - && preg_match('@Safari/([0-9]*)@', $HTTP_USER_AGENT, $log_version) - ) { - $this->set( - 'PMA_USR_BROWSER_VER', - $mozilla_version[1] . '.' . $log_version[1] - ); - $this->set('PMA_USR_BROWSER_AGENT', 'SAFARI'); - // Firefox - } elseif (! mb_strstr($HTTP_USER_AGENT, 'compatible') - && preg_match('@Firefox/([\w.]+)@', $HTTP_USER_AGENT, $log_version) - ) { - $this->set( - 'PMA_USR_BROWSER_VER', - $log_version[1] - ); - $this->set('PMA_USR_BROWSER_AGENT', 'FIREFOX'); - } 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 ($is_mozilla) { - $this->set('PMA_USR_BROWSER_VER', $mozilla_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 - */ - public function checkGd2(): void - { - if ($this->get('GD2Available') == 'yes') { - $this->set('PMA_IS_GD2', 1); - return; - } - - if ($this->get('GD2Available') == 'no') { - $this->set('PMA_IS_GD2', 0); - return; - } - - if (! function_exists('imagecreatetruecolor')) { - $this->set('PMA_IS_GD2', 0); - return; - } - - if (function_exists('gd_info')) { - $gd_nfo = gd_info(); - if (mb_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 - */ - public function checkWebServer(): void - { - // some versions return Microsoft-IIS, some Microsoft/IIS - // we could use a preg_match() but it's slower - if (Core::getenv('SERVER_SOFTWARE') - && false !== stripos(Core::getenv('SERVER_SOFTWARE'), 'Microsoft') - && false !== stripos(Core::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 - */ - public function checkWebServerOs(): void - { - // Default to Unix or Equiv - $this->set('PMA_IS_WINDOWS', 0); - // If PHP_OS is defined then continue - if (defined('PHP_OS')) { - if (false !== stripos(PHP_OS, 'win') && false === stripos(PHP_OS, 'darwin')) { - // Is it some version of Windows - $this->set('PMA_IS_WINDOWS', 1); - } elseif (false !== stripos(PHP_OS, 'OS/2')) { - // Is it OS/2 (No file permissions like Windows) - $this->set('PMA_IS_WINDOWS', 1); - } - } - } - - /** - * detects if Git revision - * @param string $git_location (optional) verified git directory - * @return boolean - */ - public function isGitRevision(&$git_location = null): bool - { - // PMA config check - if (! $this->get('ShowGitRevision')) { - return false; - } - - // caching - if (isset($_SESSION['is_git_revision']) - && array_key_exists('git_location', $_SESSION) - ) { - // Define location using cached value - $git_location = $_SESSION['git_location']; - return $_SESSION['is_git_revision']; - } - - // find out if there is a .git folder - // or a .git file (--separate-git-dir) - $git = '.git'; - if (is_dir($git)) { - if (@is_file($git . '/config')) { - $git_location = $git; - } else { - $_SESSION['git_location'] = null; - $_SESSION['is_git_revision'] = false; - return false; - } - } elseif (is_file($git)) { - $contents = file_get_contents($git); - $gitmatch = []; - // Matches expected format - if (! preg_match( - '/^gitdir: (.*)$/', - $contents, - $gitmatch - )) { - $_SESSION['git_location'] = null; - $_SESSION['is_git_revision'] = false; - return false; - } elseif (@is_dir($gitmatch[1])) { - //Detected git external folder location - $git_location = $gitmatch[1]; - } else { - $_SESSION['git_location'] = null; - $_SESSION['is_git_revision'] = false; - return false; - } - } else { - $_SESSION['git_location'] = null; - $_SESSION['is_git_revision'] = false; - return false; - } - // Define session for caching - $_SESSION['git_location'] = $git_location; - $_SESSION['is_git_revision'] = true; - return true; - } - - /** - * detects Git revision, if running inside repo - * - * @return void - */ - public function checkGitRevision(): void - { - // find out if there is a .git folder - $git_folder = ''; - if (! $this->isGitRevision($git_folder)) { - $this->set('PMA_VERSION_GIT', 0); - return; - } - - if (! $ref_head = @file_get_contents($git_folder . '/HEAD')) { - $this->set('PMA_VERSION_GIT', 0); - return; - } - - if ($common_dir_contents = @file_get_contents($git_folder . '/commondir')) { - $git_folder = $git_folder . DIRECTORY_SEPARATOR . trim($common_dir_contents); - } - - $branch = false; - // are we on any branch? - if (false !== strpos($ref_head, '/')) { - // remove ref: prefix - $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)) { - $hash = @file_get_contents($ref_file); - if (! $hash) { - $this->set('PMA_VERSION_GIT', 0); - return; - } - $hash = trim($hash); - } else { - // deal with packed refs - $packed_refs = @file_get_contents($git_folder . '/packed-refs'); - if (! $packed_refs) { - $this->set('PMA_VERSION_GIT', 0); - return; - } - // split file to lines - $ref_lines = explode(PHP_EOL, $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)) { - $this->set('PMA_VERSION_GIT', 0); - // Could not find ref - return; - } - } - } else { - $hash = trim($ref_head); - } - - $commit = false; - if (! preg_match('/^[0-9a-f]{40}$/i', $hash)) { - $commit = false; - } elseif (isset($_SESSION['PMA_VERSION_COMMITDATA_' . $hash])) { - $commit = $_SESSION['PMA_VERSION_COMMITDATA_' . $hash]; - } elseif (function_exists('gzuncompress')) { - $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)) { - $this->set('PMA_VERSION_GIT', 0); - return; - } - $commit = explode("\0", gzuncompress($commit), 2); - $commit = explode("\n", $commit[1]); - $_SESSION['PMA_VERSION_COMMITDATA_' . $hash] = $commit; - } else { - $pack_names = []; - // work with packed data - $packs_file = $git_folder . '/objects/info/packs'; - if (@file_exists($packs_file) - && $packs = @file_get_contents($packs_file) - ) { - // 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 - $dirIterator = new DirectoryIterator( - $git_folder . '/objects/pack' - ); - foreach ($dirIterator 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 - $index_data = @file_get_contents( - $git_folder . '/objects/pack/' . $index_name - ); - if (! $index_data) { - 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 - $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); - } - } - } - - $httpRequest = new HttpRequest(); - - // check if commit exists in Github - if ($commit !== false - && isset($_SESSION['PMA_VERSION_REMOTECOMMIT_' . $hash]) - ) { - $is_remote_commit = $_SESSION['PMA_VERSION_REMOTECOMMIT_' . $hash]; - } else { - $link = 'https://www.phpmyadmin.net/api/commit/' . $hash . '/'; - $is_found = $httpRequest->create($link, 'GET'); - 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://www.phpmyadmin.net/api/tree/' . $branch . '/'; - $is_found = $httpRequest->create($link, 'GET', true); - 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 = [ - 'name' => '', - 'email' => '', - 'date' => '', - ]; - $committer = [ - 'name' => '', - 'email' => '', - 'date' => '', - ]; - - do { - $dataline = array_shift($commit); - $datalinearr = explode(' ', $dataline, 2); - $linetype = $datalinearr[0]; - if (in_array($linetype, ['author', 'committer'])) { - $user = $datalinearr[1]; - preg_match('/([^<]+)<([^>]+)> ([0-9]+)( [^ ]+)?/', $user, $user); - $user2 = [ - 'name' => trim($user[1]), - 'email' => trim($user[2]), - 'date' => date('Y-m-d H:i:s', (int) $user[3]), - ]; - if (isset($user[4])) { - $user2['date'] .= $user[4]; - } - $$linetype = $user2; - } - } while ($dataline != ''); - $message = trim(implode(' ', $commit)); - } elseif (isset($commit_json) && isset($commit_json->author) && isset($commit_json->committer) && isset($commit_json->message)) { - $author = [ - 'name' => $commit_json->author->name, - 'email' => $commit_json->author->email, - 'date' => $commit_json->author->date, - ]; - $committer = [ - 'name' => $commit_json->committer->name, - 'email' => $commit_json->committer->email, - 'date' => $commit_json->committer->date, - ]; - $message = trim($commit_json->message); - } else { - $this->set('PMA_VERSION_GIT', 0); - 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); - } - - /** - * loads default values from default source - * - * @return boolean success - */ - public function loadDefaults(): bool - { - $cfg = []; - if (! @file_exists($this->default_source)) { - $this->error_config_default_file = true; - return false; - } - $canUseErrorReporting = function_exists('error_reporting'); - $oldErrorReporting = null; - if ($canUseErrorReporting) { - $oldErrorReporting = error_reporting(0); - } - ob_start(); - $GLOBALS['pma_config_loading'] = true; - $eval_result = include $this->default_source; - $GLOBALS['pma_config_loading'] = false; - ob_end_clean(); - if ($canUseErrorReporting) { - error_reporting($oldErrorReporting); - } - - if ($eval_result === false) { - $this->error_config_default_file = true; - return false; - } - - $this->default_source_mtime = filemtime($this->default_source); - - $this->default_server = $cfg['Servers'][1]; - unset($cfg['Servers']); - - $this->default = $cfg; - $this->settings = array_replace_recursive($this->settings, $cfg); - - $this->error_config_default_file = false; - - return true; - } - - /** - * loads configuration from $source, usually the config file - * should be called on object creation - * - * @param string $source config file - * - * @return bool - */ - public function load(?string $source = null): bool - { - $this->loadDefaults(); - - if (null !== $source) { - $this->setSource($source); - } - - if (! $this->checkConfigSource()) { - return false; - } - - $cfg = []; - - /** - * Parses the configuration file, we throw away any errors or - * output. - */ - $canUseErrorReporting = function_exists('error_reporting'); - $oldErrorReporting = null; - if ($canUseErrorReporting) { - $oldErrorReporting = error_reporting(0); - } - ob_start(); - $GLOBALS['pma_config_loading'] = true; - $eval_result = include $this->getSource(); - $GLOBALS['pma_config_loading'] = false; - ob_end_clean(); - if ($canUseErrorReporting) { - error_reporting($oldErrorReporting); - } - - if ($eval_result === false) { - $this->error_config_file = true; - } else { - $this->error_config_file = false; - $this->source_mtime = filemtime($this->getSource()); - } - - /** - * Ignore keys with / as we do not use these - * - * These can be confusing for user configuration layer as it - * flatten array using / and thus don't see difference between - * $cfg['Export/method'] and $cfg['Export']['method'], while rest - * of thre code uses the setting only in latter form. - * - * This could be removed once we consistently handle both values - * in the functional code as well. - * - * It could use array_filter(...ARRAY_FILTER_USE_KEY), but it's not - * supported on PHP 5.5 and HHVM. - */ - $matched_keys = array_filter( - array_keys($cfg), - function ($key) { - return strpos($key, '/') === false; - } - ); - - $cfg = array_intersect_key($cfg, array_flip($matched_keys)); - - /** - * Backward compatibility code - */ - if (! empty($cfg['DefaultTabTable'])) { - $cfg['DefaultTabTable'] = str_replace( - [ - 'tbl_properties.php', - '_properties', - ], - [ - 'tbl_sql.php', - '', - ], - $cfg['DefaultTabTable'] - ); - } - if (! empty($cfg['DefaultTabDatabase'])) { - $cfg['DefaultTabDatabase'] = str_replace( - [ - 'db_details.php', - '_details', - ], - [ - 'db_sql.php', - '', - ], - $cfg['DefaultTabDatabase'] - ); - } - - $this->settings = array_replace_recursive($this->settings, $cfg); - - return true; - } - - /** - * Sets the connection collation - * - * @return void - */ - private function _setConnectionCollation(): void - { - $collation_connection = $this->get('DefaultConnectionCollation'); - if (! empty($collation_connection) - && $collation_connection != $GLOBALS['collation_connection'] - ) { - $GLOBALS['dbi']->setCollation($collation_connection); - } - } - - /** - * Loads user preferences and merges them with current config - * must be called after control connection has been established - * - * @return void - */ - public function loadUserPreferences(): void - { - $userPreferences = new UserPreferences(); - // index.php should load these settings, so that phpmyadmin.css.php - // will have everything available 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 - ) { - $prefs = $userPreferences->load(); - $_SESSION['cache'][$cache_key]['userprefs'] - = $userPreferences->apply($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'] - ); - - // load config array - $this->settings = array_replace_recursive($this->settings, $config_data); - $GLOBALS['cfg'] = array_replace_recursive($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 - /** @var ThemeManager $tmanager */ - $tmanager = ThemeManager::getInstance(); - 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 language - if ($this->issetCookie('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'])) { - $language = LanguageManager::getInstance()->getLanguage( - $config_data['lang'] - ); - if ($language !== false) { - $language->activate(); - $this->setCookie('pma_lang', $language->getCode()); - } - } - } - - // set connection collation - $this->_setConnectionCollation(); - } - - /** - * 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|null $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 true|Message - */ - public function setUserValue( - ?string $cookie_name, - string $cfg_path, - $new_cfg_value, - $default_value = null - ) { - $userPreferences = new UserPreferences(); - $result = true; - // use permanent user preferences if possible - $prefs_type = $this->get('user_preferences'); - if ($prefs_type) { - if ($default_value === null) { - $default_value = Core::arrayRead($cfg_path, $this->default); - } - $result = $userPreferences->persistOption($cfg_path, $new_cfg_value, $default_value); - } - if ($prefs_type != 'db' && $cookie_name) { - // fall back to cookies - if ($default_value === null) { - $default_value = Core::arrayRead($cfg_path, $this->settings); - } - $this->setCookie($cookie_name, $new_cfg_value, $default_value); - } - Core::arrayWrite($cfg_path, $GLOBALS['cfg'], $new_cfg_value); - Core::arrayWrite($cfg_path, $this->settings, $new_cfg_value); - return $result; - } - - /** - * Reads value stored by {@link setUserValue()} - * - * @param string $cookie_name cookie name - * @param mixed $cfg_value config value - * - * @return mixed - */ - public function getUserValue(string $cookie_name, $cfg_value) - { - $cookie_exists = isset($_COOKIE) && ! empty($this->getCookie($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); - } - } elseif ($cookie_exists) { - return $this->getCookie($cookie_name); - } - // return value from $cfg array - return $cfg_value; - } - - /** - * set source - * - * @param string $source source - * - * @return void - */ - public function setSource(string $source): void - { - $this->source = trim($source); - } - - /** - * check config source - * - * @return boolean whether source is valid or not - */ - public function checkConfigSource(): bool - { - 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; - Core::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 - */ - public function checkPermissions(): void - { - // Check for permissions (on platforms that support it): - if ($this->get('CheckConfigurationPermissions') && @file_exists($this->getSource())) { - $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; - Core::fatalError( - __( - 'Wrong permissions on configuration file, ' - . 'should not be world writable!' - ) - ); - } - } - } - } - - /** - * Checks for errors - * (must be called after config.inc.php has been merged) - * - * @return void - */ - public function checkErrors(): void - { - if ($this->error_config_default_file) { - Core::fatalError( - sprintf( - __('Could not load default configuration from: %1$s'), - $this->default_source - ) - ); - } - - if ($this->error_config_file) { - $error = '[strong]' . __('Failed to read configuration file!') . '[/strong]' - . '[br][br]' - . __( - 'This usually means there is a syntax error in it, ' - . 'please check any errors shown below.' - ) - . '[br][br]' - . '[conferr]'; - trigger_error($error, E_USER_ERROR); - } - } - - /** - * returns specific config setting - * - * @param string $setting config setting - * - * @return mixed value - */ - public function get(string $setting) - { - if (isset($this->settings[$setting])) { - return $this->settings[$setting]; - } - return null; - } - - /** - * sets configuration variable - * - * @param string $setting configuration option - * @param mixed $value new value for configuration option - * - * @return void - */ - public function set(string $setting, $value): void - { - 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 - */ - public function getSource(): string - { - return $this->source; - } - - /** - * returns a unique value to force a CSS reload if either the config - * or the theme changes - * - * @return int Summary of unix timestamps, to be unique on theme parameters - * change - */ - public function getThemeUniqueValue(): int - { - return (int) ( - $this->source_mtime + - $this->default_source_mtime + - $this->get('user_preferences_mtime') + - $GLOBALS['PMA_Theme']->mtime_info + - $GLOBALS['PMA_Theme']->filesize_info - ); - } - - /** - * checks if upload is enabled - * - * @return void - */ - public function checkUpload(): void - { - if (! ini_get('file_uploads')) { - $this->set('enable_upload', false); - return; - } - - $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); - } - } - - /** - * Maximum upload size as limited by PHP - * Used with permission from Moodle (https://moodle.org/) by Martin Dougiamas - * - * this section generates $max_upload_size in bytes - * - * @return void - */ - public function checkUploadSize(): void - { - if (! $filesize = ini_get('upload_max_filesize')) { - $filesize = "5M"; - } - - if ($postsize = ini_get('post_max_size')) { - $this->set( - 'max_upload_size', - min(Core::getRealSize($filesize), Core::getRealSize($postsize)) - ); - } else { - $this->set('max_upload_size', Core::getRealSize($filesize)); - } - } - - /** - * Checks if protocol is https - * - * This function checks if the https protocol on the active connection. - * - * @return bool - */ - public function isHttps(): bool - { - if (null !== $this->get('is_https')) { - return $this->get('is_https'); - } - - $url = $this->get('PmaAbsoluteUri'); - - $is_https = false; - if (! empty($url) && parse_url($url, PHP_URL_SCHEME) === 'https') { - $is_https = true; - } elseif (strtolower(Core::getenv('HTTP_SCHEME')) == 'https') { - $is_https = true; - } elseif (strtolower(Core::getenv('HTTPS')) == 'on') { - $is_https = true; - } elseif (substr(strtolower(Core::getenv('REQUEST_URI')), 0, 6) == 'https:') { - $is_https = true; - } elseif (strtolower(Core::getenv('HTTP_HTTPS_FROM_LB')) == 'on') { - // A10 Networks load balancer - $is_https = true; - } elseif (strtolower(Core::getenv('HTTP_FRONT_END_HTTPS')) == 'on') { - $is_https = true; - } elseif (strtolower(Core::getenv('HTTP_X_FORWARDED_PROTO')) == 'https') { - $is_https = true; - } elseif (strtolower(Core::getenv('HTTP_CLOUDFRONT_FORWARDED_PROTO')) === 'https') { - // Amazon CloudFront, issue #15621 - $is_https = true; - } elseif (Core::getenv('SERVER_PORT') == 443) { - $is_https = true; - } - - $this->set('is_https', $is_https); - - return $is_https; - } - - /** - * Get phpMyAdmin root path - * - * @return string - */ - public function getRootPath(): string - { - static $cookie_path = null; - - if (null !== $cookie_path && ! defined('TESTSUITE')) { - return $cookie_path; - } - - $url = $this->get('PmaAbsoluteUri'); - - if (! empty($url)) { - $path = parse_url($url, PHP_URL_PATH); - if (! empty($path)) { - if (substr($path, -1) != '/') { - return $path . '/'; - } - return $path; - } - } - - $parsed_url = parse_url($GLOBALS['PMA_PHP_SELF']); - - $parts = explode( - '/', - rtrim(str_replace('\\', '/', $parsed_url['path']), '/') - ); - - /* Remove filename */ - if (substr($parts[count($parts) - 1], -4) == '.php') { - $parts = array_slice($parts, 0, count($parts) - 1); - } - - /* Remove extra path from javascript calls */ - if (defined('PMA_PATH_TO_BASEDIR')) { - $parts = array_slice($parts, 0, count($parts) - 1); - } - - $parts[] = ''; - - return implode('/', $parts); - } - - /** - * enables backward compatibility - * - * @return void - */ - public function enableBc(): void - { - $GLOBALS['cfg'] = $this->settings; - $GLOBALS['default_server'] = $this->default_server; - unset($this->default_server); - $GLOBALS['is_upload'] = $this->get('enable_upload'); - $GLOBALS['max_upload_size'] = $this->get('max_upload_size'); - $GLOBALS['is_https'] = $this->get('is_https'); - - $defines = [ - 'PMA_VERSION', - 'PMA_MAJOR_VERSION', - 'PMA_THEME_VERSION', - 'PMA_THEME_GENERATION', - 'PMA_IS_WINDOWS', - '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)); - } - } - } - - /** - * removes cookie - * - * @param string $cookieName name of cookie to remove - * - * @return boolean result of setcookie() - */ - public function removeCookie(string $cookieName): bool - { - $httpCookieName = $this->getCookieName($cookieName); - - if ($this->issetCookie($cookieName)) { - unset($_COOKIE[$httpCookieName]); - } - if (defined('TESTSUITE')) { - return true; - } - return setcookie( - $httpCookieName, - '', - time() - 3600, - $this->getRootPath(), - '', - $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() - */ - public function setCookie( - string $cookie, - $value, - ?string $default = null, - ?int $validity = null, - bool $httponly = true - ): bool { - if (strlen($value) > 0 && null !== $default && $value === $default - ) { - // default value is used - if ($this->issetCookie($cookie)) { - // remove cookie - return $this->removeCookie($cookie); - } - return false; - } - - if (strlen($value) === 0 && $this->issetCookie($cookie)) { - // remove cookie, value is empty - return $this->removeCookie($cookie); - } - - $httpCookieName = $this->getCookieName($cookie); - - if (! $this->issetCookie($cookie) || $this->getCookie($cookie) !== $value) { - // set cookie with new value - /* Calculate cookie validity */ - if ($validity === null) { - /* Valid for one month */ - $validity = time() + 2592000; - } elseif ($validity == 0) { - /* Valid for session */ - $validity = 0; - } else { - $validity = time() + $validity; - } - if (defined('TESTSUITE')) { - $_COOKIE[$httpCookieName] = $value; - return true; - } - return setcookie( - $httpCookieName, - $value, - $validity, - $this->getRootPath(), - '', - $this->isHttps(), - $httponly - ); - } - - // cookie has already $value as value - return true; - } - - /** - * get cookie - * - * @param string $cookieName The name of the cookie to get - * - * @return mixed result of getCookie() - */ - public function getCookie(string $cookieName) - { - if (isset($_COOKIE[$this->getCookieName($cookieName)])) { - return $_COOKIE[$this->getCookieName($cookieName)]; - } else { - return null; - } - } - - /** - * Get the real cookie name - * - * @param string $cookieName The name of the cookie - * @return string - */ - public function getCookieName(string $cookieName): string - { - return $cookieName . ( ($this->isHttps()) ? '_https' : '' ); - } - - /** - * isset cookie - * - * @param string $cookieName The name of the cookie to check - * - * @return bool result of issetCookie() - */ - public function issetCookie(string $cookieName): bool - { - return isset($_COOKIE[$this->getCookieName($cookieName)]); - } - - /** - * Error handler to catch fatal errors when loading configuration - * file - * - * @return void - */ - public static function fatalErrorHandler(): void - { - if (! isset($GLOBALS['pma_config_loading']) - || ! $GLOBALS['pma_config_loading'] - ) { - return; - } - - $error = error_get_last(); - if ($error === null) { - return; - } - - Core::fatalError( - sprintf( - 'Failed to load phpMyAdmin configuration (%s:%s): %s', - Error::relPath($error['file']), - $error['line'], - $error['message'] - ) - ); - } - - /** - * Wrapper for footer/header rendering - * - * @param string $filename File to check and render - * @param string $id Div ID - * - * @return string - */ - private static function _renderCustom(string $filename, string $id): string - { - $retval = ''; - if (@file_exists($filename)) { - $retval .= '
'; - ob_start(); - include $filename; - $retval .= ob_get_contents(); - ob_end_clean(); - $retval .= '
'; - } - return $retval; - } - - /** - * Renders user configured footer - * - * @return string - */ - public static function renderFooter(): string - { - return self::_renderCustom(CUSTOM_FOOTER_FILE, 'pma_footer'); - } - - /** - * Renders user configured footer - * - * @return string - */ - public static function renderHeader(): string - { - return self::_renderCustom(CUSTOM_HEADER_FILE, 'pma_header'); - } - - /** - * Returns temporary dir path - * - * @param string $name Directory name - * - * @return string|null - */ - public function getTempDir(string $name): ?string - { - static $temp_dir = []; - - if (isset($temp_dir[$name]) && ! defined('TESTSUITE')) { - return $temp_dir[$name]; - } - - $path = $this->get('TempDir'); - if (empty($path)) { - $path = null; - } else { - $path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $name; - if (! @is_dir($path)) { - @mkdir($path, 0770, true); - } - if (! @is_dir($path) || ! @is_writable($path)) { - $path = null; - } - } - - $temp_dir[$name] = $path; - return $path; - } - - /** - * Returns temporary directory - * - * @return string|null - */ - public function getUploadTempDir(): ?string - { - // First try configured temp dir - // Fallback to PHP upload_tmp_dir - $dirs = [ - $this->getTempDir('upload'), - ini_get('upload_tmp_dir'), - sys_get_temp_dir(), - ]; - - foreach ($dirs as $dir) { - if (! empty($dir) && @is_writable($dir)) { - return realpath($dir); - } - } - - return null; - } - - /** - * Selects server based on request parameters. - * - * @return integer - */ - public function selectServer(): int - { - $request = empty($_REQUEST['server']) ? 0 : $_REQUEST['server']; - - /** - * Lookup server by name - * (see FAQ 4.8) - */ - if (! is_numeric($request)) { - foreach ($this->settings['Servers'] as $i => $server) { - $verboseToLower = mb_strtolower($server['verbose']); - $serverToLower = mb_strtolower($request); - if ($server['host'] == $request - || $server['verbose'] == $request - || $verboseToLower == $serverToLower - || md5($verboseToLower) === $serverToLower - ) { - $request = $i; - break; - } - } - if (is_string($request)) { - $request = 0; - } - } - - /** - * If no server is selected, make sure that $this->settings['Server'] is empty (so - * that nothing will work), and skip server authentication. - * We do NOT exit here, but continue on without logging into any server. - * This way, the welcome page will still come up (with no server info) and - * present a choice of servers in the case that there are multiple servers - * and '$this->settings['ServerDefault'] = 0' is set. - */ - - if (is_numeric($request) && ! empty($request) && ! empty($this->settings['Servers'][$request])) { - $server = $request; - $this->settings['Server'] = $this->settings['Servers'][$server]; - } else { - if (! empty($this->settings['Servers'][$this->settings['ServerDefault']])) { - $server = $this->settings['ServerDefault']; - $this->settings['Server'] = $this->settings['Servers'][$server]; - } else { - $server = 0; - $this->settings['Server'] = []; - } - } - - return (int) $server; - } - - /** - * Checks whether Servers configuration is valid and possibly apply fixups. - * - * @return void - */ - public function checkServers(): void - { - // Do we have some server? - if (! isset($this->settings['Servers']) || count($this->settings['Servers']) === 0) { - // No server => create one with defaults - $this->settings['Servers'] = [1 => $this->default_server]; - } else { - // We have server(s) => apply default configuration - $new_servers = []; - - foreach ($this->settings['Servers'] as $server_index => $each_server) { - // Detect wrong configuration - if (! is_int($server_index) || $server_index < 1) { - trigger_error( - sprintf(__('Invalid server index: %s'), $server_index), - E_USER_ERROR - ); - } - - $each_server = array_merge($this->default_server, $each_server); - - // Final solution to bug #582890 - // If we are using a socket connection - // and there is nothing in the verbose server name - // or the host field, then generate a name for the server - // in the form of "Server 2", localized of course! - if (empty($each_server['host']) && empty($each_server['verbose'])) { - $each_server['verbose'] = sprintf(__('Server %d'), $server_index); - } - - $new_servers[$server_index] = $each_server; - } - $this->settings['Servers'] = $new_servers; - } - } -} - -if (! defined('TESTSUITE')) { - register_shutdown_function([Config::class, 'fatalErrorHandler']); -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/ConfigFile.php b/srcs/phpmyadmin/libraries/classes/Config/ConfigFile.php deleted file mode 100644 index 1e053dd..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/ConfigFile.php +++ /dev/null @@ -1,531 +0,0 @@ -_defaultCfg; - include ROOT_PATH . 'libraries/config.default.php'; - - // load additional config information - $this->_cfgDb = include ROOT_PATH . 'libraries/config.values.php'; - - // apply default values overrides - if (count($this->_cfgDb['_overrides'])) { - foreach ($this->_cfgDb['_overrides'] as $path => $value) { - Core::arrayWrite($path, $cfg, $value); - } - } - - $this->_baseCfg = $baseConfig; - $this->_isInSetup = $baseConfig === null; - $this->_id = 'ConfigFile' . $GLOBALS['server']; - if (! isset($_SESSION[$this->_id])) { - $_SESSION[$this->_id] = []; - } - } - - /** - * Sets names of config options which will be placed in config file even if - * they are set to their default values (use only full paths) - * - * @param array $keys the names of the config options - * - * @return void - */ - public function setPersistKeys(array $keys) - { - // checking key presence is much faster than searching so move values - // to keys - $this->_persistKeys = array_flip($keys); - } - - /** - * Returns flipped array set by {@link setPersistKeys()} - * - * @return array - */ - public function getPersistKeysMap() - { - return $this->_persistKeys; - } - - /** - * By default ConfigFile allows setting of all configuration keys, use - * this method to set up a filter on {@link set()} method - * - * @param array|null $keys array of allowed keys or null to remove filter - * - * @return void - */ - public function setAllowedKeys($keys) - { - if ($keys === null) { - $this->_setFilter = null; - return; - } - // checking key presence is much faster than searching so move values - // to keys - $this->_setFilter = array_flip($keys); - } - - /** - * Sets path mapping for updating config in - * {@link updateWithGlobalConfig()} or reading - * by {@link getConfig()} or {@link getConfigArray()} - * - * @param array $mapping Contains the mapping of "Server/config options" - * to "Server/1/config options" - * - * @return void - */ - public function setCfgUpdateReadMapping(array $mapping) - { - $this->_cfgUpdateReadMapping = $mapping; - } - - /** - * Resets configuration data - * - * @return void - */ - public function resetConfigData() - { - $_SESSION[$this->_id] = []; - } - - /** - * Sets configuration data (overrides old data) - * - * @param array $cfg Configuration options - * - * @return void - */ - public function setConfigData(array $cfg) - { - $_SESSION[$this->_id] = $cfg; - } - - /** - * Sets config value - * - * @param string $path Path - * @param mixed $value Value - * @param string $canonicalPath Canonical path - * - * @return void - */ - public function set($path, $value, $canonicalPath = null) - { - if ($canonicalPath === null) { - $canonicalPath = $this->getCanonicalPath($path); - } - // apply key whitelist - if ($this->_setFilter !== null - && ! isset($this->_setFilter[$canonicalPath]) - ) { - return; - } - // if the path isn't protected it may be removed - if (isset($this->_persistKeys[$canonicalPath])) { - Core::arrayWrite($path, $_SESSION[$this->_id], $value); - return; - } - - $defaultValue = $this->getDefault($canonicalPath); - $removePath = $value === $defaultValue; - if ($this->_isInSetup) { - // remove if it has a default value or is empty - $removePath = $removePath - || (empty($value) && empty($defaultValue)); - } else { - // get original config values not overwritten by user - // preferences to allow for overwriting options set in - // config.inc.php with default values - $instanceDefaultValue = Core::arrayRead( - $canonicalPath, - $this->_baseCfg - ); - // remove if it has a default value and base config (config.inc.php) - // uses default value - $removePath = $removePath - && ($instanceDefaultValue === $defaultValue); - } - if ($removePath) { - Core::arrayRemove($path, $_SESSION[$this->_id]); - return; - } - - Core::arrayWrite($path, $_SESSION[$this->_id], $value); - } - - /** - * Flattens multidimensional array, changes indices to paths - * (eg. 'key/subkey'). - * Used as array_walk() callback. - * - * @param mixed $value Value - * @param mixed $key Key - * @param mixed $prefix Prefix - * - * @return void - */ - private function _flattenArray($value, $key, $prefix) - { - // no recursion for numeric arrays - if (is_array($value) && ! isset($value[0])) { - $prefix .= $key . '/'; - array_walk($value, [$this, '_flattenArray'], $prefix); - } else { - $this->_flattenArrayResult[$prefix . $key] = $value; - } - } - - /** - * Returns default config in a flattened array - * - * @return array - */ - public function getFlatDefaultConfig() - { - $this->_flattenArrayResult = []; - array_walk($this->_defaultCfg, [$this, '_flattenArray'], ''); - $flatConfig = $this->_flattenArrayResult; - $this->_flattenArrayResult = null; - return $flatConfig; - } - - /** - * Updates config with values read from given array - * (config will contain differences to defaults from config.defaults.php). - * - * @param array $cfg Configuration - * - * @return void - */ - public function updateWithGlobalConfig(array $cfg) - { - // load config array and flatten it - $this->_flattenArrayResult = []; - array_walk($cfg, [$this, '_flattenArray'], ''); - $flatConfig = $this->_flattenArrayResult; - $this->_flattenArrayResult = null; - - // save values map for translating a few user preferences paths, - // should be complemented by code reading from generated config - // to perform inverse mapping - foreach ($flatConfig as $path => $value) { - if (isset($this->_cfgUpdateReadMapping[$path])) { - $path = $this->_cfgUpdateReadMapping[$path]; - } - $this->set($path, $value, $path); - } - } - - /** - * Returns config value or $default if it's not set - * - * @param string $path Path of config file - * @param mixed $default Default values - * - * @return mixed - */ - public function get($path, $default = null) - { - return Core::arrayRead($path, $_SESSION[$this->_id], $default); - } - - /** - * Returns default config value or $default it it's not set ie. it doesn't - * exist in config.default.php ($cfg) and config.values.php - * ($_cfg_db['_overrides']) - * - * @param string $canonicalPath Canonical path - * @param mixed $default Default value - * - * @return mixed - */ - public function getDefault($canonicalPath, $default = null) - { - return Core::arrayRead($canonicalPath, $this->_defaultCfg, $default); - } - - /** - * Returns config value, if it's not set uses the default one; returns - * $default if the path isn't set and doesn't contain a default value - * - * @param string $path Path - * @param mixed $default Default value - * - * @return mixed - */ - public function getValue($path, $default = null) - { - $v = Core::arrayRead($path, $_SESSION[$this->_id], null); - if ($v !== null) { - return $v; - } - $path = $this->getCanonicalPath($path); - return $this->getDefault($path, $default); - } - - /** - * Returns canonical path - * - * @param string $path Path - * - * @return string - */ - public function getCanonicalPath($path) - { - return preg_replace('#^Servers/([\d]+)/#', 'Servers/1/', $path); - } - - /** - * Returns config database entry for $path - * - * @param string $path path of the variable in config db - * @param mixed $default default value - * - * @return mixed - */ - public function getDbEntry($path, $default = null) - { - return Core::arrayRead($path, $this->_cfgDb, $default); - } - - /** - * Returns server count - * - * @return int - */ - public function getServerCount() - { - return isset($_SESSION[$this->_id]['Servers']) - ? count($_SESSION[$this->_id]['Servers']) - : 0; - } - - /** - * Returns server list - * - * @return array|null - */ - public function getServers() - { - return isset($_SESSION[$this->_id]['Servers']) - ? $_SESSION[$this->_id]['Servers'] - : null; - } - - /** - * Returns DSN of given server - * - * @param integer $server server index - * - * @return string - */ - public function getServerDSN($server) - { - if (! isset($_SESSION[$this->_id]['Servers'][$server])) { - return ''; - } - - $path = 'Servers/' . $server; - $dsn = 'mysqli://'; - if ($this->getValue("$path/auth_type") == 'config') { - $dsn .= $this->getValue("$path/user"); - if (! empty($this->getValue("$path/password"))) { - $dsn .= ':***'; - } - $dsn .= '@'; - } - if ($this->getValue("$path/host") != 'localhost') { - $dsn .= $this->getValue("$path/host"); - $port = $this->getValue("$path/port"); - if ($port) { - $dsn .= ':' . $port; - } - } else { - $dsn .= $this->getValue("$path/socket"); - } - return $dsn; - } - - /** - * Returns server name - * - * @param int $id server index - * - * @return string - */ - public function getServerName($id) - { - if (! isset($_SESSION[$this->_id]['Servers'][$id])) { - return ''; - } - $verbose = $this->get("Servers/$id/verbose"); - if (! empty($verbose)) { - return $verbose; - } - $host = $this->get("Servers/$id/host"); - return empty($host) ? 'localhost' : $host; - } - - /** - * Removes server - * - * @param int $server server index - * - * @return void - */ - public function removeServer($server) - { - if (! isset($_SESSION[$this->_id]['Servers'][$server])) { - return; - } - $lastServer = $this->getServerCount(); - - for ($i = $server; $i < $lastServer; $i++) { - $_SESSION[$this->_id]['Servers'][$i] - = $_SESSION[$this->_id]['Servers'][$i + 1]; - } - unset($_SESSION[$this->_id]['Servers'][$lastServer]); - - if (isset($_SESSION[$this->_id]['ServerDefault']) - && $_SESSION[$this->_id]['ServerDefault'] == $lastServer - ) { - unset($_SESSION[$this->_id]['ServerDefault']); - } - } - - /** - * Returns configuration array (full, multidimensional format) - * - * @return array - */ - public function getConfig() - { - $c = $_SESSION[$this->_id]; - foreach ($this->_cfgUpdateReadMapping as $mapTo => $mapFrom) { - // if the key $c exists in $map_to - if (Core::arrayRead($mapTo, $c) !== null) { - Core::arrayWrite($mapTo, $c, Core::arrayRead($mapFrom, $c)); - Core::arrayRemove($mapFrom, $c); - } - } - return $c; - } - - /** - * Returns configuration array (flat format) - * - * @return array - */ - public function getConfigArray() - { - $this->_flattenArrayResult = []; - array_walk($_SESSION[$this->_id], [$this, '_flattenArray'], ''); - $c = $this->_flattenArrayResult; - $this->_flattenArrayResult = null; - - $persistKeys = array_diff( - array_keys($this->_persistKeys), - array_keys($c) - ); - foreach ($persistKeys as $k) { - $c[$k] = $this->getDefault($this->getCanonicalPath($k)); - } - - foreach ($this->_cfgUpdateReadMapping as $mapTo => $mapFrom) { - if (! isset($c[$mapFrom])) { - continue; - } - $c[$mapTo] = $c[$mapFrom]; - unset($c[$mapFrom]); - } - return $c; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Descriptions.php b/srcs/phpmyadmin/libraries/classes/Config/Descriptions.php deleted file mode 100644 index 22e7c1f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Descriptions.php +++ /dev/null @@ -1,934 +0,0 @@ - __('If enabled, user can enter any MySQL server in login form for cookie auth.'), - 'AllowArbitraryServer_name' => __('Allow login to any MySQL server'), - 'ArbitraryServerRegexp_desc' => __( - 'Restricts the MySQL servers the user can enter when a login to an arbitrary ' - . 'MySQL server is enabled by matching the IP or hostname of the MySQL server ' . - 'to the given regular expression.' - ), - 'ArbitraryServerRegexp_name' => __('Restrict login to MySQL server'), - 'AllowThirdPartyFraming_desc' => __( - 'Enabling this allows a page located on a different domain to call phpMyAdmin ' - . 'inside a frame, and is a potential [strong]security hole[/strong] allowing ' - . 'cross-frame scripting (XSS) attacks.' - ), - 'AllowThirdPartyFraming_name' => __('Allow third party framing'), - 'AllowUserDropDatabase_name' => __('Show "Drop database" link to normal users'), - 'blowfish_secret_desc' => __( - 'Secret passphrase used for encrypting cookies in [kbd]cookie[/kbd] ' - . 'authentication.' - ), - 'blowfish_secret_name' => __('Blowfish secret'), - 'BrowseMarkerEnable_desc' => __('Highlight selected rows.'), - 'BrowseMarkerEnable_name' => __('Row marker'), - 'BrowsePointerEnable_desc' => __('Highlight row pointed by the mouse cursor.'), - 'BrowsePointerEnable_name' => __('Highlight pointer'), - 'BZipDump_desc' => __( - 'Enable bzip2 compression for' - . ' import operations.' - ), - 'BZipDump_name' => __('Bzip2'), - 'CharEditing_desc' => __( - 'Defines which type of editing controls should be used for CHAR and VARCHAR ' - . 'columns; [kbd]input[/kbd] - allows limiting of input length, ' - . '[kbd]textarea[/kbd] - allows newlines in columns.' - ), - 'CharEditing_name' => __('CHAR columns editing'), - 'CodemirrorEnable_desc' => __( - 'Use user-friendly editor for editing SQL queries ' - . '(CodeMirror) with syntax highlighting and ' - . 'line numbers.' - ), - 'CodemirrorEnable_name' => __('Enable CodeMirror'), - 'LintEnable_desc' => __( - 'Find any errors in the query before executing it.' - . ' Requires CodeMirror to be enabled.' - ), - 'LintEnable_name' => __('Enable linter'), - 'MinSizeForInputField_desc' => __( - 'Defines the minimum size for input fields generated for CHAR and VARCHAR ' - . 'columns.' - ), - 'MinSizeForInputField_name' => __('Minimum size for input field'), - 'MaxSizeForInputField_desc' => __( - 'Defines the maximum size for input fields generated for CHAR and VARCHAR ' - . 'columns.' - ), - 'MaxSizeForInputField_name' => __('Maximum size for input field'), - 'CharTextareaCols_desc' => __('Number of columns for CHAR/VARCHAR textareas.'), - 'CharTextareaCols_name' => __('CHAR textarea columns'), - 'CharTextareaRows_desc' => __('Number of rows for CHAR/VARCHAR textareas.'), - 'CharTextareaRows_name' => __('CHAR textarea rows'), - 'CheckConfigurationPermissions_name' => __('Check config file permissions'), - 'CompressOnFly_desc' => __( - 'Compress gzip exports on the fly without the need for much memory; if ' - . 'you encounter problems with created gzip files disable this feature.' - ), - 'CompressOnFly_name' => __('Compress on the fly'), - 'Confirm_desc' => __( - 'Whether a warning ("Are your really sure…") should be displayed ' - . 'when you\'re about to lose data.' - ), - 'Confirm_name' => __('Confirm DROP queries'), - 'DBG_sql_desc' => __('Log SQL queries and their execution time, to be displayed in the console'), - 'DBG_sql_name' => __('Debug SQL'), - 'DefaultTabDatabase_desc' => __('Tab that is displayed when entering a database.'), - 'DefaultTabDatabase_name' => __('Default database tab'), - 'DefaultTabServer_desc' => __('Tab that is displayed when entering a server.'), - 'DefaultTabServer_name' => __('Default server tab'), - 'DefaultTabTable_desc' => __('Tab that is displayed when entering a table.'), - 'DefaultTabTable_name' => __('Default table tab'), - 'EnableAutocompleteForTablesAndColumns_desc' => __('Autocomplete of the table and column names in the SQL queries.'), - 'EnableAutocompleteForTablesAndColumns_name' => __('Enable autocomplete for table and column names'), - 'HideStructureActions_desc' => __('Whether the table structure actions should be hidden.'), - 'ShowColumnComments_name' => __('Show column comments'), - 'ShowColumnComments_desc' => __('Whether column comments should be shown in table structure view'), - 'HideStructureActions_name' => __('Hide table structure actions'), - 'DefaultTransformations_Hex_name' => __('Default transformations for Hex'), - 'DefaultTransformations_Hex_desc' => __('Values for options list for default transformations. These will be overwritten if transformation is filled in at table structure page.'), - 'DefaultTransformations_Substring_name' => __('Default transformations for Substring'), - 'DefaultTransformations_Substring_desc' => __('Values for options list for default transformations. These will be overwritten if transformation is filled in at table structure page.'), - 'DefaultTransformations_Bool2Text_name' => __('Default transformations for Bool2Text'), - 'DefaultTransformations_Bool2Text_desc' => __('Values for options list for default transformations. These will be overwritten if transformation is filled in at table structure page.'), - 'DefaultTransformations_External_name' => __('Default transformations for External'), - 'DefaultTransformations_External_desc' => __('Values for options list for default transformations. These will be overwritten if transformation is filled in at table structure page.'), - 'DefaultTransformations_PreApPend_name' => __('Default transformations for PreApPend'), - 'DefaultTransformations_PreApPend_desc' => __('Values for options list for default transformations. These will be overwritten if transformation is filled in at table structure page.'), - 'DefaultTransformations_DateFormat_name' => __('Default transformations for DateFormat'), - 'DefaultTransformations_DateFormat_desc' => __('Values for options list for default transformations. These will be overwritten if transformation is filled in at table structure page.'), - 'DefaultTransformations_Inline_name' => __('Default transformations for Inline'), - 'DefaultTransformations_Inline_desc' => __('Values for options list for default transformations. These will be overwritten if transformation is filled in at table structure page.'), - 'DefaultTransformations_TextImageLink_name' => __('Default transformations for TextImageLink'), - 'DefaultTransformations_TextImageLink_desc' => __('Values for options list for default transformations. These will be overwritten if transformation is filled in at table structure page.'), - 'DefaultTransformations_TextLink_name' => __('Default transformations for TextLink'), - 'DefaultTransformations_TextLink_desc' => __('Values for options list for default transformations. These will be overwritten if transformation is filled in at table structure page.'), - - 'DisplayServersList_desc' => __('Show server listing as a list instead of a drop down.'), - 'DisplayServersList_name' => __('Display servers as a list'), - 'DisableMultiTableMaintenance_desc' => __( - 'Disable the table maintenance mass operations, like optimizing or repairing ' - . 'the selected tables of a database.' - ), - 'DisableMultiTableMaintenance_name' => __('Disable multi table maintenance'), - 'ExecTimeLimit_desc' => __( - 'Set the number of seconds a script is allowed to run ([kbd]0[/kbd] for no ' - . 'limit).' - ), - 'ExecTimeLimit_name' => __('Maximum execution time'), - 'Export_lock_tables_name' => sprintf( - __('Use %s statement'), - htmlspecialchars('LOCK TABLES') - ), - 'Export_asfile_name' => __('Save as file'), - 'Export_charset_name' => __('Character set of the file'), - 'Export_codegen_format_name' => __('Format'), - 'Export_compression_name' => __('Compression'), - 'Export_csv_columns_name' => __('Put columns names in the first row'), - 'Export_csv_enclosed_name' => __('Columns enclosed with'), - 'Export_csv_escaped_name' => __('Columns escaped with'), - 'Export_csv_null_name' => __('Replace NULL with'), - 'Export_csv_removeCRLF_name' => __('Remove CRLF characters within columns'), - 'Export_csv_separator_name' => __('Columns terminated with'), - 'Export_csv_terminated_name' => __('Lines terminated with'), - 'Export_excel_columns_name' => __('Put columns names in the first row'), - 'Export_excel_edition_name' => __('Excel edition'), - 'Export_excel_null_name' => __('Replace NULL with'), - 'Export_excel_removeCRLF_name' => __('Remove CRLF characters within columns'), - 'Export_file_template_database_name' => __('Database name template'), - 'Export_file_template_server_name' => __('Server name template'), - 'Export_file_template_table_name' => __('Table name template'), - 'Export_format_name' => __('Format'), - 'Export_htmlword_columns_name' => __('Put columns names in the first row'), - 'Export_htmlword_null_name' => __('Replace NULL with'), - 'Export_htmlword_structure_or_data_name' => __('Dump table'), - 'Export_latex_caption_name' => __('Include table caption'), - 'Export_latex_columns_name' => __('Put columns names in the first row'), - 'Export_latex_comments_name' => __('Comments'), - 'Export_latex_data_caption_name' => __('Table caption'), - 'Export_latex_data_continued_caption_name' => __('Continued table caption'), - 'Export_latex_data_label_name' => __('Label key'), - 'Export_latex_mime_name' => __('Media (MIME) type'), - 'Export_latex_null_name' => __('Replace NULL with'), - 'Export_latex_relation_name' => __('Relationships'), - 'Export_latex_structure_caption_name' => __('Table caption'), - 'Export_latex_structure_continued_caption_name' => __('Continued table caption'), - 'Export_latex_structure_label_name' => __('Label key'), - 'Export_latex_structure_or_data_name' => __('Dump table'), - 'Export_method_name' => __('Export method'), - 'Export_ods_columns_name' => __('Put columns names in the first row'), - 'Export_ods_null_name' => __('Replace NULL with'), - 'Export_odt_columns_name' => __('Put columns names in the first row'), - 'Export_odt_comments_name' => __('Comments'), - 'Export_odt_mime_name' => __('Media (MIME) type'), - 'Export_odt_null_name' => __('Replace NULL with'), - 'Export_odt_relation_name' => __('Relationships'), - 'Export_odt_structure_or_data_name' => __('Dump table'), - 'Export_onserver_name' => __('Save on server'), - 'Export_onserver_overwrite_name' => __('Overwrite existing file(s)'), - 'Export_as_separate_files_name' => __('Export as separate files'), - 'Export_quick_export_onserver_name' => __('Save on server'), - 'Export_quick_export_onserver_overwrite_name' => __('Overwrite existing file(s)'), - 'Export_remember_file_template_name' => __('Remember file name template'), - 'Export_sql_auto_increment_name' => __('Add AUTO_INCREMENT value'), - 'Export_sql_backquotes_name' => __('Enclose table and column names with backquotes'), - 'Export_sql_compatibility_name' => __('SQL compatibility mode'), - 'Export_sql_dates_name' => __('Creation/Update/Check dates'), - 'Export_sql_delayed_name' => __('Use delayed inserts'), - 'Export_sql_disable_fk_name' => __('Disable foreign key checks'), - 'Export_sql_views_as_tables_name' => __('Export views as tables'), - 'Export_sql_metadata_name' => __('Export related metadata from phpMyAdmin configuration storage'), - 'Export_sql_create_database_name' => sprintf(__('Add %s'), 'CREATE DATABASE / USE'), - 'Export_sql_drop_database_name' => sprintf(__('Add %s'), 'DROP DATABASE'), - 'Export_sql_drop_table_name' => sprintf( - __('Add %s'), - 'DROP TABLE / VIEW / PROCEDURE / FUNCTION / EVENT / TRIGGER' - ), - 'Export_sql_create_table_name' => sprintf(__('Add %s'), 'CREATE TABLE'), - 'Export_sql_create_view_name' => sprintf(__('Add %s'), 'CREATE VIEW'), - 'Export_sql_create_trigger_name' => sprintf(__('Add %s'), 'CREATE TRIGGER'), - 'Export_sql_hex_for_binary_name' => __('Use hexadecimal for BINARY & BLOB'), - 'Export_sql_if_not_exists_name' => __( - 'Add IF NOT EXISTS (less efficient as indexes will be generated during' - . ' table creation)' - ), - 'Export_sql_view_current_user' => __('Exclude definition of current user'), - 'Export_sql_or_replace_view_name' => sprintf(__('%s view'), 'OR REPLACE'), - 'Export_sql_ignore_name' => __('Use ignore inserts'), - 'Export_sql_include_comments_name' => __('Comments'), - 'Export_sql_insert_syntax_name' => __('Syntax to use when inserting data'), - 'Export_sql_max_query_size_name' => __('Maximal length of created query'), - 'Export_sql_mime_name' => __('Media (MIME) type'), - 'Export_sql_procedure_function_name' => sprintf(__('Add %s'), 'CREATE PROCEDURE / FUNCTION / EVENT'), - 'Export_sql_relation_name' => __('Relationships'), - 'Export_sql_structure_or_data_name' => __('Dump table'), - 'Export_sql_type_name' => __('Export type'), - 'Export_sql_use_transaction_name' => __('Enclose export in a transaction'), - 'Export_sql_utc_time_name' => __('Export time in UTC'), - 'Export_texytext_columns_name' => __('Put columns names in the first row'), - 'Export_texytext_null_name' => __('Replace NULL with'), - 'Export_texytext_structure_or_data_name' => __('Dump table'), - 'ForeignKeyDropdownOrder_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.' - ), - 'ForeignKeyDropdownOrder_name' => __('Foreign key dropdown order'), - 'ForeignKeyMaxLimit_desc' => __('A dropdown will be used if fewer items are present.'), - 'ForeignKeyMaxLimit_name' => __('Foreign key limit'), - 'DefaultForeignKeyChecks_desc' => __('Default value for foreign key checks checkbox for some queries.'), - 'DefaultForeignKeyChecks_name' => __('Foreign key checks'), - 'Form_Browse_name' => __('Browse mode'), - 'Form_Browse_desc' => __('Customize browse mode.'), - 'Form_CodeGen_name' => 'CodeGen', - 'Form_CodeGen_desc' => __('Customize default options.'), - 'Form_Csv_name' => __('CSV'), - 'Form_Csv_desc' => __('Customize default options.'), - 'Form_Developer_name' => __('Developer'), - 'Form_Developer_desc' => __('Settings for phpMyAdmin developers.'), - 'Form_Edit_name' => __('Edit mode'), - 'Form_Edit_desc' => __('Customize edit mode.'), - 'Form_Export_defaults_name' => __('Export defaults'), - 'Form_Export_defaults_desc' => __('Customize default export options.'), - 'Form_General_name' => __('General'), - 'Form_General_desc' => __('Set some commonly used options.'), - 'Form_Import_defaults_name' => __('Import defaults'), - 'Form_Import_defaults_desc' => __('Customize default common import options.'), - 'Form_Import_export_name' => __('Import / export'), - 'Form_Import_export_desc' => __('Set import and export directories and compression options.'), - 'Form_Latex_name' => __('LaTeX'), - 'Form_Latex_desc' => __('Customize default options.'), - 'Form_Navi_databases_name' => __('Databases'), - 'Form_Navi_databases_desc' => __('Databases display options.'), - 'Form_Navi_panel_name' => __('Navigation panel'), - 'Form_Navi_panel_desc' => __('Customize appearance of the navigation panel.'), - 'Form_Navi_tree_name' => __('Navigation tree'), - 'Form_Navi_tree_desc' => __('Customize the navigation tree.'), - 'Form_Navi_servers_name' => __('Servers'), - 'Form_Navi_servers_desc' => __('Servers display options.'), - 'Form_Navi_tables_name' => __('Tables'), - 'Form_Navi_tables_desc' => __('Tables display options.'), - 'Form_Main_panel_name' => __('Main panel'), - 'Form_Microsoft_Office_name' => __('Microsoft Office'), - 'Form_Microsoft_Office_desc' => __('Customize default options.'), - 'Form_Open_Document_name' => 'OpenDocument', - 'Form_Open_Document_desc' => __('Customize default options.'), - 'Form_Other_core_settings_name' => __('Other core settings'), - 'Form_Other_core_settings_desc' => __('Settings that didn\'t fit anywhere else.'), - 'Form_Page_titles_name' => __('Page titles'), - 'Form_Page_titles_desc' => __( - 'Specify browser\'s title bar text. Refer to ' - . '[doc@faq6-27]documentation[/doc] for magic strings that can be used ' - . 'to get special values.' - ), - 'Form_Security_name' => __('Security'), - 'Form_Security_desc' => __( - 'Please note that phpMyAdmin is just a user interface and its features do not ' - . 'limit MySQL.' - ), - 'Form_Server_name' => __('Basic settings'), - 'Form_Server_auth_name' => __('Authentication'), - 'Form_Server_auth_desc' => __('Authentication settings.'), - 'Form_Server_config_name' => __('Server configuration'), - 'Form_Server_config_desc' => __( - 'Advanced server configuration, do not change these options unless you know ' - . 'what they are for.' - ), - 'Form_Server_desc' => __('Enter server connection parameters.'), - 'Form_Server_pmadb_name' => __('Configuration storage'), - 'Form_Server_pmadb_desc' => __( - 'Configure phpMyAdmin configuration storage to gain access to additional ' - . 'features, see [doc@linked-tables]phpMyAdmin configuration storage[/doc] in ' - . 'documentation.' - ), - 'Form_Server_tracking_name' => __('Changes tracking'), - 'Form_Server_tracking_desc' => __( - 'Tracking of changes made in database. Requires the phpMyAdmin configuration ' - . 'storage.' - ), - 'Form_Sql_name' => __('SQL'), - 'Form_Sql_box_name' => __('SQL Query box'), - 'Form_Sql_box_desc' => __('Customize links shown in SQL Query boxes.'), - 'Form_Sql_desc' => __('Customize default options.'), - 'Form_Sql_queries_name' => __('SQL queries'), - 'Form_Sql_queries_desc' => __('SQL queries settings.'), - 'Form_Startup_name' => __('Startup'), - 'Form_Startup_desc' => __('Customize startup page.'), - 'Form_DbStructure_name' => __('Database structure'), - 'Form_DbStructure_desc' => __('Choose which details to show in the database structure (list of tables).'), - 'Form_TableStructure_name' => __('Table structure'), - 'Form_TableStructure_desc' => __('Settings for the table structure (list of columns).'), - 'Form_Tabs_name' => __('Tabs'), - 'Form_Tabs_desc' => __('Choose how you want tabs to work.'), - 'Form_DisplayRelationalSchema_name' => __('Display relational schema'), - 'Form_DisplayRelationalSchema_desc' => '', - 'PDFDefaultPageSize_name' => __('Paper size'), - 'PDFDefaultPageSize_desc' => '', - 'Form_Databases_name' => __('Databases'), - 'Form_Text_fields_name' => __('Text fields'), - 'Form_Text_fields_desc' => __('Customize text input fields.'), - 'Form_Texy_name' => __('Texy! text'), - 'Form_Texy_desc' => __('Customize default options'), - 'Form_Warnings_name' => __('Warnings'), - 'Form_Warnings_desc' => __('Disable some of the warnings shown by phpMyAdmin.'), - 'Form_Console_name' => __('Console'), - 'GZipDump_desc' => __( - 'Enable gzip compression for import ' - . 'and export operations.' - ), - 'GZipDump_name' => __('GZip'), - 'IconvExtraParams_name' => __('Extra parameters for iconv'), - 'IgnoreMultiSubmitErrors_desc' => __( - 'If enabled, phpMyAdmin continues computing multiple-statement queries even if ' - . 'one of the queries failed.' - ), - 'IgnoreMultiSubmitErrors_name' => __('Ignore multiple statement errors'), - 'Import_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.' - ), - 'enable_drag_drop_import_name' => __('Enable drag and drop import'), - 'enable_drag_drop_import_desc' => __('Uncheck the checkbox to disable drag and drop import'), - 'Import_allow_interrupt_name' => __('Partial import: allow interrupt'), - 'Import_charset_name' => __('Character set of the file'), - 'Import_csv_col_names_name' => __('Lines terminated with'), - 'Import_csv_enclosed_name' => __('Columns enclosed with'), - 'Import_csv_escaped_name' => __('Columns escaped with'), - 'Import_csv_ignore_name' => __('Do not abort on INSERT error'), - 'Import_csv_replace_name' => __('Add ON DUPLICATE KEY UPDATE'), - 'Import_csv_replace_desc' => __('Update data when duplicate keys found on import'), - 'Import_csv_terminated_name' => __('Columns terminated with'), - 'Import_format_desc' => __( - 'Default format; be aware that this list depends on location (database, table) ' - . 'and only SQL is always available.' - ), - 'Import_format_name' => __('Format of imported file'), - 'Import_ldi_enclosed_name' => __('Columns enclosed with'), - 'Import_ldi_escaped_name' => __('Columns escaped with'), - 'Import_ldi_ignore_name' => __('Do not abort on INSERT error'), - 'Import_ldi_local_option_name' => __('Use LOCAL keyword'), - 'Import_ldi_replace_name' => __('Add ON DUPLICATE KEY UPDATE'), - 'Import_ldi_replace_desc' => __('Update data when duplicate keys found on import'), - 'Import_ldi_terminated_name' => __('Columns terminated with'), - 'Import_ods_col_names_name' => __('Column names in first row'), - 'Import_ods_empty_rows_name' => __('Do not import empty rows'), - 'Import_ods_recognize_currency_name' => __('Import currencies ($5.00 to 5.00)'), - 'Import_ods_recognize_percentages_name' => __('Import percentages as proper decimals (12.00% to .12)'), - 'Import_skip_queries_desc' => __('Number of queries to skip from start.'), - 'Import_skip_queries_name' => __('Partial import: skip queries'), - 'Import_sql_compatibility_name' => __('SQL compatibility mode'), - 'Import_sql_no_auto_value_on_zero_name' => __('Do not use AUTO_INCREMENT for zero values'), - 'Import_sql_read_as_multibytes_name' => __('Read as multibytes'), - 'InitialSlidersState_name' => __('Initial state for sliders'), - 'InsertRows_desc' => __('How many rows can be inserted at one time.'), - 'InsertRows_name' => __('Number of inserted rows'), - 'LimitChars_desc' => __('Maximum number of characters shown in any non-numeric column on browse view.'), - 'LimitChars_name' => __('Limit column characters'), - 'LoginCookieDeleteAll_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.' - ), - 'LoginCookieDeleteAll_name' => __('Delete all cookies on logout'), - 'LoginCookieRecall_desc' => __( - 'Define whether the previous login should be recalled or not in ' - . '[kbd]cookie[/kbd] authentication mode.' - ), - 'LoginCookieRecall_name' => __('Recall user name'), - 'LoginCookieStore_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.' - ), - 'LoginCookieStore_name' => __('Login cookie store'), - 'LoginCookieValidity_desc' => __('Define how long (in seconds) a login cookie is valid.'), - 'LoginCookieValidity_name' => __('Login cookie validity'), - 'LongtextDoubleTextarea_desc' => __('Double size of textarea for LONGTEXT columns.'), - 'LongtextDoubleTextarea_name' => __('Bigger textarea for LONGTEXT'), - 'MaxCharactersInDisplayedSQL_desc' => __('Maximum number of characters used when a SQL query is displayed.'), - 'MaxCharactersInDisplayedSQL_name' => __('Maximum displayed SQL length'), - 'MaxDbList_cmt' => __('Users cannot set a higher value'), - 'MaxDbList_desc' => __('Maximum number of databases displayed in database list.'), - 'MaxDbList_name' => __('Maximum databases'), - 'FirstLevelNavigationItems_desc' => __( - 'The number of items that can be displayed on each page on the first level' - . ' of the navigation tree.' - ), - 'FirstLevelNavigationItems_name' => __('Maximum items on first level'), - 'MaxNavigationItems_desc' => __('The number of items that can be displayed on each page of the navigation tree.'), - 'MaxNavigationItems_name' => __('Maximum items in branch'), - 'MaxRows_desc' => __( - 'Number of rows displayed when browsing a result set. If the result set ' - . 'contains more rows, "Previous" and "Next" links will be ' - . 'shown.' - ), - 'MaxRows_name' => __('Maximum number of rows to display'), - 'MaxTableList_cmt' => __('Users cannot set a higher value'), - 'MaxTableList_desc' => __('Maximum number of tables displayed in table list.'), - 'MaxTableList_name' => __('Maximum tables'), - 'MemoryLimit_desc' => __( - 'The number of bytes a script is allowed to allocate, eg. [kbd]32M[/kbd] ' - . '([kbd]-1[/kbd] for no limit and [kbd]0[/kbd] for no change).' - ), - 'MemoryLimit_name' => __('Memory limit'), - 'ShowDatabasesNavigationAsTree_desc' => __('In the navigation panel, replaces the database tree with a selector'), - 'ShowDatabasesNavigationAsTree_name' => __('Show databases navigation as tree'), - 'NavigationWidth_name' => __('Navigation panel width'), - 'NavigationWidth_desc' => __('Set to 0 to collapse navigation panel.'), - 'NavigationLinkWithMainPanel_desc' => __('Link with main panel by highlighting the current database or table.'), - 'NavigationLinkWithMainPanel_name' => __('Link with main panel'), - 'NavigationDisplayLogo_desc' => __('Show logo in navigation panel.'), - 'NavigationDisplayLogo_name' => __('Display logo'), - 'NavigationLogoLink_desc' => __('URL where logo in the navigation panel will point to.'), - 'NavigationLogoLink_name' => __('Logo link URL'), - 'NavigationLogoLinkWindow_desc' => __( - 'Open the linked page in the main window ([kbd]main[/kbd]) or in a new one ' - . '([kbd]new[/kbd]).' - ), - 'NavigationLogoLinkWindow_name' => __('Logo link target'), - 'NavigationDisplayServers_desc' => __('Display server choice at the top of the navigation panel.'), - 'NavigationDisplayServers_name' => __('Display servers selection'), - 'NavigationTreeDefaultTabTable_name' => __('Target for quick access icon'), - 'NavigationTreeDefaultTabTable2_name' => __('Target for second quick access icon'), - 'NavigationTreeDisplayItemFilterMinimum_desc' => __( - 'Defines the minimum number of items (tables, views, routines and events) to ' - . 'display a filter box.' - ), - 'NavigationTreeDisplayItemFilterMinimum_name' => __('Minimum number of items to display the filter box'), - 'NavigationTreeDisplayDbFilterMinimum_name' => __('Minimum number of databases to display the database filter box'), - 'NavigationTreeEnableGrouping_desc' => __( - 'Group items in the navigation tree (determined by the separator defined in ' . - 'the Databases and Tables tabs above).' - ), - 'NavigationTreeEnableGrouping_name' => __('Group items in the tree'), - 'NavigationTreeDbSeparator_desc' => __('String that separates databases into different tree levels.'), - 'NavigationTreeDbSeparator_name' => __('Database tree separator'), - 'NavigationTreeTableSeparator_desc' => __('String that separates tables into different tree levels.'), - 'NavigationTreeTableSeparator_name' => __('Table tree separator'), - 'NavigationTreeTableLevel_name' => __('Maximum table tree depth'), - 'NavigationTreePointerEnable_desc' => __('Highlight server under the mouse cursor.'), - 'NavigationTreePointerEnable_name' => __('Enable highlighting'), - 'NavigationTreeEnableExpansion_desc' => __('Whether to offer the possibility of tree expansion in the navigation panel.'), - 'NavigationTreeEnableExpansion_name' => __('Enable navigation tree expansion'), - 'NavigationTreeShowTables_name' => __('Show tables in tree'), - 'NavigationTreeShowTables_desc' => __('Whether to show tables under database in the navigation tree'), - 'NavigationTreeShowViews_name' => __('Show views in tree'), - 'NavigationTreeShowViews_desc' => __('Whether to show views under database in the navigation tree'), - 'NavigationTreeShowFunctions_name' => __('Show functions in tree'), - 'NavigationTreeShowFunctions_desc' => __('Whether to show functions under database in the navigation tree'), - 'NavigationTreeShowProcedures_name' => __('Show procedures in tree'), - 'NavigationTreeShowProcedures_desc' => __('Whether to show procedures under database in the navigation tree'), - 'NavigationTreeShowEvents_name' => __('Show events in tree'), - 'NavigationTreeShowEvents_desc' => __('Whether to show events under database in the navigation tree'), - 'NavigationTreeAutoexpandSingleDb_name' => __('Expand single database'), - 'NavigationTreeAutoexpandSingleDb_desc' => __('Whether to expand single database in the navigation tree automatically.'), - 'NumRecentTables_desc' => __('Maximum number of recently used tables; set 0 to disable.'), - 'NumFavoriteTables_desc' => __('Maximum number of favorite tables; set 0 to disable.'), - 'NumRecentTables_name' => __('Recently used tables'), - 'NumFavoriteTables_name' => __('Favorite tables'), - 'RowActionLinks_desc' => __('These are Edit, Copy and Delete links.'), - 'RowActionLinks_name' => __('Where to show the table row links'), - 'RowActionLinksWithoutUnique_desc' => __('Whether to show row links even in the absence of a unique key.'), - 'RowActionLinksWithoutUnique_name' => __('Show row links anyway'), - 'DisableShortcutKeys_name' => __('Disable shortcut keys'), - 'DisableShortcutKeys_desc' => __('Disable shortcut keys'), - 'NaturalOrder_desc' => __('Use natural order for sorting table and database names.'), - 'NaturalOrder_name' => __('Natural order'), - 'TableNavigationLinksMode_desc' => __('Use only icons, only text or both.'), - 'TableNavigationLinksMode_name' => __('Table navigation bar'), - 'OBGzip_desc' => __('Use GZip output buffering for increased speed in HTTP transfers.'), - 'OBGzip_name' => __('GZip output buffering'), - 'Order_desc' => __( - '[kbd]SMART[/kbd] - i.e. descending order for columns of type TIME, DATE, ' - . 'DATETIME and TIMESTAMP, ascending order otherwise.' - ), - 'Order_name' => __('Default sorting order'), - 'PersistentConnections_desc' => __('Use persistent connections to MySQL databases.'), - 'PersistentConnections_name' => __('Persistent connections'), - 'PmaNoRelation_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.' - ), - 'PmaNoRelation_DisableWarning_name' => __('Missing phpMyAdmin configuration storage tables'), - 'ReservedWordDisableWarning_desc' => __( - 'Disable the default warning that is displayed on the Structure page if column ' - . 'names in a table are reserved MySQL words.' - ), - 'ReservedWordDisableWarning_name' => __('MySQL reserved word warning'), - 'TabsMode_desc' => __('Use only icons, only text or both.'), - 'TabsMode_name' => __('How to display the menu tabs'), - 'ActionLinksMode_desc' => __('Use only icons, only text or both.'), - 'ActionLinksMode_name' => __('How to display various action links'), - 'ProtectBinary_desc' => __('Disallow BLOB and BINARY columns from editing.'), - 'ProtectBinary_name' => __('Protect binary columns'), - 'QueryHistoryDB_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).' - ), - 'QueryHistoryDB_name' => __('Permanent query history'), - 'QueryHistoryMax_cmt' => __('Users cannot set a higher value'), - 'QueryHistoryMax_desc' => __('How many queries are kept in history.'), - 'QueryHistoryMax_name' => __('Query history length'), - 'RecodingEngine_desc' => __('Select which functions will be used for character set conversion.'), - 'RecodingEngine_name' => __('Recoding engine'), - 'RememberSorting_desc' => __('When browsing tables, the sorting of each table is remembered.'), - 'RememberSorting_name' => __('Remember table\'s sorting'), - 'TablePrimaryKeyOrder_desc' => __('Default sort order for tables with a primary key.'), - 'TablePrimaryKeyOrder_name' => __('Primary key default sort order'), - 'RepeatCells_desc' => __('Repeat the headers every X cells, [kbd]0[/kbd] deactivates this feature.'), - 'RepeatCells_name' => __('Repeat headers'), - 'GridEditing_name' => __('Grid editing: trigger action'), - 'RelationalDisplay_name' => __('Relational display'), - 'RelationalDisplay_desc' => __('For display Options'), - 'SaveCellsAtOnce_name' => __('Grid editing: save all edited cells at once'), - 'SaveDir_desc' => __('Directory where exports can be saved on server.'), - 'SaveDir_name' => __('Save directory'), - 'Servers_AllowDeny_order_desc' => __('Leave blank if not used.'), - 'Servers_AllowDeny_order_name' => __('Host authorization order'), - 'Servers_AllowDeny_rules_desc' => __('Leave blank for defaults.'), - 'Servers_AllowDeny_rules_name' => __('Host authorization rules'), - 'Servers_AllowNoPassword_name' => __('Allow logins without a password'), - 'Servers_AllowRoot_name' => __('Allow root login'), - 'Servers_SessionTimeZone_name' => __('Session timezone'), - 'Servers_SessionTimeZone_desc' => __( - 'Sets the effective timezone; possibly different than the one from your ' - . 'database server' - ), - 'Servers_auth_http_realm_desc' => __('HTTP Basic Auth Realm name to display when doing HTTP Auth.'), - 'Servers_auth_http_realm_name' => __('HTTP Realm'), - 'Servers_auth_type_desc' => __('Authentication method to use.'), - 'Servers_auth_type_name' => __('Authentication type'), - 'Servers_bookmarktable_desc' => __( - 'Leave blank for no [doc@bookmarks@]bookmark[/doc] ' - . 'support, suggested: [kbd]pma__bookmark[/kbd]' - ), - 'Servers_bookmarktable_name' => __('Bookmark table'), - 'Servers_column_info_desc' => __( - 'Leave blank for no column comments/media (MIME) types, suggested: ' - . '[kbd]pma__column_info[/kbd].' - ), - 'Servers_column_info_name' => __('Column information table'), - 'Servers_compress_desc' => __('Compress connection to MySQL server.'), - 'Servers_compress_name' => __('Compress connection'), - 'Servers_controlpass_name' => __('Control user password'), - 'Servers_controluser_desc' => __( - 'A special MySQL user configured with limited permissions, more information ' - . 'available on [doc@linked-tables]documentation[/doc].' - ), - 'Servers_controluser_name' => __('Control user'), - 'Servers_controlhost_desc' => __( - 'An alternate host to hold the configuration storage; leave blank to use the ' - . 'already defined host.' - ), - 'Servers_controlhost_name' => __('Control host'), - 'Servers_controlport_desc' => __( - 'An alternate port to connect to the host that holds the configuration storage; ' - . 'leave blank to use the default port, or the already defined port, if the ' - . 'controlhost equals host.' - ), - 'Servers_controlport_name' => __('Control port'), - 'Servers_hide_db_desc' => __('Hide databases matching regular expression (PCRE).'), - 'Servers_DisableIS_desc' => __( - 'More information on [a@https://github.com/phpmyadmin/phpmyadmin/issues/8970]phpMyAdmin ' - . 'issue tracker[/a] and [a@https://bugs.mysql.com/19588]MySQL Bugs[/a]' - ), - 'Servers_DisableIS_name' => __('Disable use of INFORMATION_SCHEMA'), - 'Servers_hide_db_name' => __('Hide databases'), - 'Servers_history_desc' => __( - 'Leave blank for no SQL query history support, suggested: ' - . '[kbd]pma__history[/kbd].' - ), - 'Servers_history_name' => __('SQL query history table'), - 'Servers_host_desc' => __('Hostname where MySQL server is running.'), - 'Servers_host_name' => __('Server hostname'), - 'Servers_LogoutURL_name' => __('Logout URL'), - 'Servers_MaxTableUiprefs_desc' => __( - 'Limits number of table preferences which are stored in database, the oldest ' - . 'records are automatically removed.' - ), - 'Servers_MaxTableUiprefs_name' => __('Maximal number of table preferences to store'), - 'Servers_savedsearches_name' => __('QBE saved searches table'), - 'Servers_savedsearches_desc' => __( - 'Leave blank for no QBE saved searches support, suggested: ' - . '[kbd]pma__savedsearches[/kbd].' - ), - 'Servers_export_templates_name' => __('Export templates table'), - 'Servers_export_templates_desc' => __( - 'Leave blank for no export template support, suggested: ' - . '[kbd]pma__export_templates[/kbd].' - ), - 'Servers_central_columns_name' => __('Central columns table'), - 'Servers_central_columns_desc' => __( - 'Leave blank for no central columns support, suggested: ' - . '[kbd]pma__central_columns[/kbd].' - ), - 'Servers_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].' - ), - 'Servers_only_db_name' => __('Show only listed databases'), - 'Servers_password_desc' => __('Leave empty if not using config auth.'), - 'Servers_password_name' => __('Password for config auth'), - 'Servers_pdf_pages_desc' => __('Leave blank for no PDF schema support, suggested: [kbd]pma__pdf_pages[/kbd].'), - 'Servers_pdf_pages_name' => __('PDF schema: pages table'), - 'Servers_pmadb_desc' => __( - 'Database used for relations, bookmarks, and PDF features. See ' - . '[doc@linked-tables]pmadb[/doc] for complete information. ' - . 'Leave blank for no support. Suggested: [kbd]phpmyadmin[/kbd].' - ), - 'Servers_pmadb_name' => __('Database name'), - 'Servers_port_desc' => __('Port on which MySQL server is listening, leave empty for default.'), - 'Servers_port_name' => __('Server port'), - 'Servers_recent_desc' => __( - 'Leave blank for no "persistent" recently used tables across sessions, ' - . 'suggested: [kbd]pma__recent[/kbd].' - ), - 'Servers_recent_name' => __('Recently used table'), - 'Servers_favorite_desc' => __( - 'Leave blank for no "persistent" favorite tables across sessions, ' - . 'suggested: [kbd]pma__favorite[/kbd].' - ), - 'Servers_favorite_name' => __('Favorites table'), - 'Servers_relation_desc' => __( - 'Leave blank for no ' - . '[doc@relations@]relation-links[/doc] support, ' - . 'suggested: [kbd]pma__relation[/kbd].' - ), - 'Servers_relation_name' => __('Relation table'), - 'Servers_SignonSession_desc' => __( - 'See [doc@authentication-modes]authentication ' - . 'types[/doc] for an example.' - ), - 'Servers_SignonSession_name' => __('Signon session name'), - 'Servers_SignonURL_name' => __('Signon URL'), - 'Servers_socket_desc' => __('Socket on which MySQL server is listening, leave empty for default.'), - 'Servers_socket_name' => __('Server socket'), - 'Servers_ssl_desc' => __('Enable SSL for connection to MySQL server.'), - 'Servers_ssl_name' => __('Use SSL'), - 'Servers_table_coords_desc' => __('Leave blank for no PDF schema support, suggested: [kbd]pma__table_coords[/kbd].'), - 'Servers_table_coords_name' => __('Designer and PDF schema: table coordinates'), - 'Servers_table_info_desc' => __( - 'Table to describe the display columns, leave blank for no support; ' - . 'suggested: [kbd]pma__table_info[/kbd].' - ), - 'Servers_table_info_name' => __('Display columns table'), - 'Servers_table_uiprefs_desc' => __( - 'Leave blank for no "persistent" tables\' UI preferences across sessions, ' - . 'suggested: [kbd]pma__table_uiprefs[/kbd].' - ), - 'Servers_table_uiprefs_name' => __('UI preferences table'), - 'Servers_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.' - ), - 'Servers_tracking_add_drop_database_name' => __('Add DROP DATABASE'), - 'Servers_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.' - ), - 'Servers_tracking_add_drop_table_name' => __('Add DROP TABLE'), - 'Servers_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.' - ), - 'Servers_tracking_add_drop_view_name' => __('Add DROP VIEW'), - 'Servers_tracking_default_statements_desc' => __('Defines the list of statements the auto-creation uses for new versions.'), - 'Servers_tracking_default_statements_name' => __('Statements to track'), - 'Servers_tracking_desc' => __( - 'Leave blank for no SQL query tracking support, suggested: ' - . '[kbd]pma__tracking[/kbd].' - ), - 'Servers_tracking_name' => __('SQL query tracking table'), - 'Servers_tracking_version_auto_create_desc' => __( - 'Whether the tracking mechanism creates versions for tables and views ' - . 'automatically.' - ), - 'Servers_tracking_version_auto_create_name' => __('Automatically create versions'), - 'Servers_userconfig_desc' => __( - 'Leave blank for no user preferences storage in database, suggested: ' - . '[kbd]pma__userconfig[/kbd].' - ), - 'Servers_userconfig_name' => __('User preferences storage table'), - 'Servers_users_desc' => __( - 'Both this table and the user groups table are required to enable the ' . - 'configurable menus feature; leaving either one of them blank will disable ' . - 'this feature, suggested: [kbd]pma__users[/kbd].' - ), - 'Servers_users_name' => __('Users table'), - 'Servers_usergroups_desc' => __( - 'Both this table and the users table are required to enable the configurable ' . - 'menus feature; leaving either one of them blank will disable this feature, ' . - 'suggested: [kbd]pma__usergroups[/kbd].' - ), - 'Servers_usergroups_name' => __('User groups table'), - 'Servers_navigationhiding_desc' => __( - 'Leave blank to disable the feature to hide and show navigation items, ' . - 'suggested: [kbd]pma__navigationhiding[/kbd].' - ), - 'Servers_navigationhiding_name' => __('Hidden navigation items table'), - 'Servers_user_desc' => __('Leave empty if not using config auth.'), - 'Servers_user_name' => __('User for config auth'), - 'Servers_verbose_desc' => __( - 'A user-friendly description of this server. Leave blank to display the ' . - 'hostname instead.' - ), - 'Servers_verbose_name' => __('Verbose name of this server'), - 'ShowAll_desc' => __('Whether a user should be displayed a "show all (rows)" button.'), - 'ShowAll_name' => __('Allow to display all the rows'), - 'ShowChgPassword_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.' - ), - 'ShowChgPassword_name' => __('Show password change form'), - 'ShowCreateDb_name' => __('Show create database form'), - 'ShowDbStructureComment_desc' => __('Show or hide a column displaying the comments for all tables.'), - 'ShowDbStructureComment_name' => __('Show table comments'), - 'ShowDbStructureCreation_desc' => __('Show or hide a column displaying the Creation timestamp for all tables.'), - 'ShowDbStructureCreation_name' => __('Show creation timestamp'), - 'ShowDbStructureLastUpdate_desc' => __('Show or hide a column displaying the Last update timestamp for all tables.'), - 'ShowDbStructureLastUpdate_name' => __('Show last update timestamp'), - 'ShowDbStructureLastCheck_desc' => __('Show or hide a column displaying the Last check timestamp for all tables.'), - 'ShowDbStructureLastCheck_name' => __('Show last check timestamp'), - 'ShowDbStructureCharset_desc' => __('Show or hide a column displaying the charset for all tables.'), - 'ShowDbStructureCharset_name' => __('Show table charset'), - 'ShowFieldTypesInDataEditView_desc' => __( - 'Defines whether or not type fields should be initially displayed in ' . - 'edit/insert mode.' - ), - 'ShowFieldTypesInDataEditView_name' => __('Show field types'), - 'ShowFunctionFields_desc' => __('Display the function fields in edit/insert mode.'), - 'ShowFunctionFields_name' => __('Show function fields'), - 'ShowHint_desc' => __('Whether to show hint or not.'), - 'ShowHint_name' => __('Show hint'), - 'ShowPhpInfo_desc' => __( - 'Shows link to [a@https://php.net/manual/function.phpinfo.php]phpinfo()[/a] ' . - 'output.' - ), - 'ShowPhpInfo_name' => __('Show phpinfo() link'), - 'ShowServerInfo_name' => __('Show detailed MySQL server information'), - 'ShowSQL_desc' => __('Defines whether SQL queries generated by phpMyAdmin should be displayed.'), - 'ShowSQL_name' => __('Show SQL queries'), - 'RetainQueryBox_desc' => __('Defines whether the query box should stay on-screen after its submission.'), - 'RetainQueryBox_name' => __('Retain query box'), - 'ShowStats_desc' => __('Allow to display database and table statistics (eg. space usage).'), - 'ShowStats_name' => __('Show statistics'), - 'SkipLockedTables_desc' => __('Mark used tables and make it possible to show databases with locked tables.'), - 'SkipLockedTables_name' => __('Skip locked tables'), - 'SQLQuery_Edit_name' => __('Edit'), - 'SQLQuery_Explain_name' => __('Explain SQL'), - 'SQLQuery_Refresh_name' => __('Refresh'), - 'SQLQuery_ShowAsPHP_name' => __('Create PHP code'), - 'SuhosinDisableWarning_desc' => __( - 'Disable the default warning that is displayed on the main page if Suhosin is ' . - 'detected.' - ), - 'SuhosinDisableWarning_name' => __('Suhosin warning'), - 'LoginCookieValidityDisableWarning_desc' => __( - 'Disable the default warning that is displayed on the main page if the value ' . - 'of the PHP setting session.gc_maxlifetime is less than the value of ' . - '`LoginCookieValidity`.' - ), - 'LoginCookieValidityDisableWarning_name' => __('Login cookie validity warning'), - 'TextareaCols_desc' => __( - 'Textarea size (columns) in edit mode, this value will be emphasized for SQL ' . - 'query textareas (*2).' - ), - 'TextareaCols_name' => __('Textarea columns'), - 'TextareaRows_desc' => __( - 'Textarea size (rows) in edit mode, this value will be emphasized for SQL ' . - 'query textareas (*2).' - ), - 'TextareaRows_name' => __('Textarea rows'), - 'TitleDatabase_desc' => __('Title of browser window when a database is selected.'), - 'TitleDatabase_name' => __('Database'), - 'TitleDefault_desc' => __('Title of browser window when nothing is selected.'), - 'TitleDefault_name' => __('Default title'), - 'TitleServer_desc' => __('Title of browser window when a server is selected.'), - 'TitleServer_name' => __('Server'), - 'TitleTable_desc' => __('Title of browser window when a table is selected.'), - 'TitleTable_name' => __('Table'), - 'TrustedProxies_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].' - ), - 'TrustedProxies_name' => __('List of trusted proxies for IP allow/deny'), - 'UploadDir_desc' => __('Directory on server where you can upload files for import.'), - 'UploadDir_name' => __('Upload directory'), - 'UseDbSearch_desc' => __('Allow for searching inside the entire database.'), - 'UseDbSearch_name' => __('Use database search'), - 'UserprefsDeveloperTab_desc' => __( - 'When disabled, users cannot set any of the options below, regardless of the ' . - 'checkbox on the right.' - ), - 'UserprefsDeveloperTab_name' => __('Enable the Developer tab in settings'), - 'VersionCheck_desc' => __('Enables check for latest version on main phpMyAdmin page.'), - 'VersionCheck_name' => __('Version check'), - 'ProxyUrl_desc' => __( - 'The url of the proxy to be used when retrieving the information about the ' . - 'latest version of phpMyAdmin or when submitting error reports. You need this ' . - 'if the server where phpMyAdmin is installed does not have direct access to ' . - 'the internet. The format is: "hostname:portnumber".' - ), - 'ProxyUrl_name' => __('Proxy url'), - 'ProxyUser_desc' => __( - 'The username for authenticating with the proxy. By default, no ' . - 'authentication is performed. If a username is supplied, Basic ' . - 'Authentication will be performed. No other types of authentication are ' . - 'currently supported.' - ), - 'ProxyUser_name' => __('Proxy username'), - 'ProxyPass_desc' => __('The password for authenticating with the proxy.'), - 'ProxyPass_name' => __('Proxy password'), - - 'ZipDump_desc' => __('Enable ZIP compression for import and export operations.'), - 'ZipDump_name' => __('ZIP'), - 'CaptchaLoginPublicKey_desc' => __('Enter your public key for your domain reCaptcha service.'), - 'CaptchaLoginPublicKey_name' => __('Public key for reCaptcha'), - 'CaptchaLoginPrivateKey_desc' => __('Enter your private key for your domain reCaptcha service.'), - 'CaptchaLoginPrivateKey_name' => __('Private key for reCaptcha'), - - 'SendErrorReports_desc' => __('Choose the default action when sending error reports.'), - 'SendErrorReports_name' => __('Send error reports'), - - 'ConsoleEnterExecutes_desc' => __( - 'Queries are executed by pressing Enter (instead of Ctrl+Enter). New lines ' . - 'will be inserted with Shift+Enter.' - ), - 'ConsoleEnterExecutes_name' => __('Enter executes queries in console'), - - 'ZeroConf_desc' => __( - 'Enable Zero Configuration mode which lets you setup phpMyAdmin ' - . 'configuration storage tables automatically.' - ), - 'ZeroConf_name' => __('Enable Zero Configuration mode'), - 'Console_StartHistory_name' => __('Show query history at start'), - 'Console_AlwaysExpand_name' => __('Always expand query messages'), - 'Console_CurrentQuery_name' => __('Show current browsing query'), - 'Console_EnterExecutes_name' => __('Execute queries on Enter and insert new line with Shift + Enter'), - 'Console_DarkTheme_name' => __('Switch to dark theme'), - 'Console_Height_name' => __('Console height'), - 'Console_Mode_name' => __('Console mode'), - 'Console_GroupQueries_name' => __('Group queries'), - 'Console_Order_name' => __('Order'), - 'Console_OrderBy_name' => __('Order by'), - 'DefaultConnectionCollation_name' => __('Server connection collation'), - ]; - - $key = $path . '_' . $type; - - return $descriptions[$key] ?? null; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Form.php b/srcs/phpmyadmin/libraries/classes/Config/Form.php deleted file mode 100644 index 8c1cbc5..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Form.php +++ /dev/null @@ -1,238 +0,0 @@ -index = $index; - $this->_configFile = $cf; - $this->loadForm($formName, $form); - } - - /** - * Returns type of given option - * - * @param string $optionName path or field name - * - * @return string|null one of: boolean, integer, double, string, select, array - */ - public function getOptionType($optionName) - { - $key = ltrim( - mb_substr( - $optionName, - (int) mb_strrpos($optionName, '/') - ), - '/' - ); - return isset($this->_fieldsTypes[$key]) - ? $this->_fieldsTypes[$key] - : null; - } - - /** - * Returns allowed values for select fields - * - * @param string $optionPath Option path - * - * @return array - */ - public function getOptionValueList($optionPath) - { - $value = $this->_configFile->getDbEntry($optionPath); - if ($value === null) { - trigger_error("$optionPath - select options not defined", E_USER_ERROR); - return []; - } - if (! is_array($value)) { - trigger_error("$optionPath - not a static value list", E_USER_ERROR); - return []; - } - // convert array('#', 'a', 'b') to array('a', 'b') - if (isset($value[0]) && $value[0] === '#') { - // remove first element ('#') - array_shift($value); - // $value has keys and value names, return it - return $value; - } - - // convert value list array('a', 'b') to array('a' => 'a', 'b' => 'b') - $hasStringKeys = false; - $keys = []; - for ($i = 0, $nb = count($value); $i < $nb; $i++) { - if (! isset($value[$i])) { - $hasStringKeys = true; - break; - } - $keys[] = is_bool($value[$i]) ? (int) $value[$i] : $value[$i]; - } - if (! $hasStringKeys) { - $value = array_combine($keys, $value); - } - - // $value has keys and value names, return it - return $value; - } - - /** - * array_walk callback function, reads path of form fields from - * array (see docs for \PhpMyAdmin\Config\Forms\BaseForm::getForms) - * - * @param mixed $value Value - * @param mixed $key Key - * @param mixed $prefix Prefix - * - * @return void - */ - private function _readFormPathsCallback($value, $key, $prefix) - { - static $groupCounter = 0; - - if (is_array($value)) { - $prefix .= $key . '/'; - array_walk($value, [$this, '_readFormPathsCallback'], $prefix); - return; - } - - if (! is_int($key)) { - $this->default[$prefix . $key] = $value; - $value = $key; - } - // add unique id to group ends - if ($value == ':group:end') { - $value .= ':' . $groupCounter++; - } - $this->fields[] = $prefix . $value; - } - - /** - * Reads form paths to {@link $fields} - * - * @param array $form Form - * - * @return void - */ - protected function readFormPaths(array $form) - { - // flatten form fields' paths and save them to $fields - $this->fields = []; - array_walk($form, [$this, '_readFormPathsCallback'], ''); - - // $this->fields is an array of the form: [0..n] => 'field path' - // change numeric indexes to contain field names (last part of the path) - $paths = $this->fields; - $this->fields = []; - foreach ($paths as $path) { - $key = ltrim( - mb_substr($path, (int) mb_strrpos($path, '/')), - '/' - ); - $this->fields[$key] = $path; - } - // now $this->fields is an array of the form: 'field name' => 'field path' - } - - /** - * Reads fields' types to $this->_fieldsTypes - * - * @return void - */ - protected function readTypes() - { - $cf = $this->_configFile; - foreach ($this->fields as $name => $path) { - if (mb_strpos((string) $name, ':group:') === 0) { - $this->_fieldsTypes[$name] = 'group'; - continue; - } - $v = $cf->getDbEntry($path); - if ($v !== null) { - $type = is_array($v) ? 'select' : $v; - } else { - $type = gettype($cf->getDefault($path)); - } - $this->_fieldsTypes[$name] = $type; - } - } - - /** - * Reads form settings and prepares class to work with given subset of - * config file - * - * @param string $formName Form name - * @param array $form Form - * - * @return void - */ - public function loadForm($formName, array $form) - { - $this->name = $formName; - $this->readFormPaths($form); - $this->readTypes(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/FormDisplay.php b/srcs/phpmyadmin/libraries/classes/Config/FormDisplay.php deleted file mode 100644 index 500706c..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/FormDisplay.php +++ /dev/null @@ -1,924 +0,0 @@ -formDisplayTemplate = new FormDisplayTemplate($GLOBALS['PMA_Config']); - $this->_jsLangStrings = [ - 'error_nan_p' => __('Not a positive number!'), - 'error_nan_nneg' => __('Not a non-negative number!'), - 'error_incorrect_port' => __('Not a valid port number!'), - 'error_invalid_value' => __('Incorrect value!'), - 'error_value_lte' => __('Value must be less than or equal to %s!'), - ]; - $this->_configFile = $cf; - // initialize validators - Validator::getValidators($this->_configFile); - } - - /** - * Returns {@link ConfigFile} associated with this instance - * - * @return ConfigFile - */ - public function getConfigFile() - { - return $this->_configFile; - } - - /** - * Registers form in form manager - * - * @param string $formName Form name - * @param array $form Form data - * @param int $serverId 0 if new server, validation; >= 1 if editing a server - * - * @return void - */ - public function registerForm($formName, array $form, $serverId = null) - { - $this->_forms[$formName] = new Form( - $formName, - $form, - $this->_configFile, - $serverId - ); - $this->_isValidated = false; - foreach ($this->_forms[$formName]->fields as $path) { - $workPath = $serverId === null - ? $path - : str_replace('Servers/1/', "Servers/$serverId/", $path); - $this->_systemPaths[$workPath] = $path; - $this->_translatedPaths[$workPath] = str_replace('/', '-', $workPath); - } - } - - /** - * Processes forms, returns true on successful save - * - * @param bool $allowPartialSave allows for partial form saving - * on failed validation - * @param bool $checkFormSubmit whether check for $_POST['submit_save'] - * - * @return boolean whether processing was successful - */ - public function process($allowPartialSave = true, $checkFormSubmit = true) - { - if ($checkFormSubmit && ! isset($_POST['submit_save'])) { - return false; - } - - // save forms - if (count($this->_forms) > 0) { - return $this->save(array_keys($this->_forms), $allowPartialSave); - } - return false; - } - - /** - * Runs validation for all registered forms - * - * @return void - */ - private function _validate() - { - if ($this->_isValidated) { - return; - } - - $paths = []; - $values = []; - foreach ($this->_forms as $form) { - /** @var Form $form */ - $paths[] = $form->name; - // collect values and paths - foreach ($form->fields as $path) { - $workPath = array_search($path, $this->_systemPaths); - $values[$path] = $this->_configFile->getValue($workPath); - $paths[] = $path; - } - } - - // run validation - $errors = Validator::validate( - $this->_configFile, - $paths, - $values, - false - ); - - // change error keys from canonical paths to work paths - if (is_array($errors) && count($errors) > 0) { - $this->_errors = []; - foreach ($errors as $path => $errorList) { - $workPath = array_search($path, $this->_systemPaths); - // field error - if (! $workPath) { - // form error, fix path - $workPath = $path; - } - $this->_errors[$workPath] = $errorList; - } - } - $this->_isValidated = true; - } - - /** - * Outputs HTML for the forms under the menu tab - * - * @param bool $showRestoreDefault whether to show "restore default" - * button besides the input field - * @param array $jsDefault stores JavaScript code - * to be displayed - * @param array $js will be updated with javascript code - * @param bool $showButtons whether show submit and reset button - * - * @return string - */ - private function _displayForms( - $showRestoreDefault, - array &$jsDefault, - array &$js, - $showButtons - ) { - $htmlOutput = ''; - $validators = Validator::getValidators($this->_configFile); - - foreach ($this->_forms as $form) { - /** @var Form $form */ - $formErrors = isset($this->_errors[$form->name]) - ? $this->_errors[$form->name] : null; - $htmlOutput .= $this->formDisplayTemplate->displayFieldsetTop( - Descriptions::get("Form_{$form->name}"), - Descriptions::get("Form_{$form->name}", 'desc'), - $formErrors, - ['id' => $form->name] - ); - - foreach ($form->fields as $field => $path) { - $workPath = array_search($path, $this->_systemPaths); - $translatedPath = $this->_translatedPaths[$workPath]; - // always true/false for user preferences display - // otherwise null - $userPrefsAllow = isset($this->_userprefsKeys[$path]) - ? ! isset($this->_userprefsDisallow[$path]) - : null; - // display input - $htmlOutput .= $this->_displayFieldInput( - $form, - $field, - $path, - $workPath, - $translatedPath, - $showRestoreDefault, - $userPrefsAllow, - $jsDefault - ); - // register JS validators for this field - if (isset($validators[$path])) { - $this->formDisplayTemplate->addJsValidate($translatedPath, $validators[$path], $js); - } - } - $htmlOutput .= $this->formDisplayTemplate->displayFieldsetBottom($showButtons); - } - return $htmlOutput; - } - - /** - * Outputs HTML for forms - * - * @param bool $tabbedForm if true, use a form with tabs - * @param bool $showRestoreDefault whether show "restore default" button - * besides the input field - * @param bool $showButtons whether show submit and reset button - * @param string $formAction action attribute for the form - * @param array|null $hiddenFields array of form hidden fields (key: field - * name) - * - * @return string HTML for forms - */ - public function getDisplay( - $tabbedForm = false, - $showRestoreDefault = false, - $showButtons = true, - $formAction = null, - $hiddenFields = null - ) { - static $jsLangSent = false; - - $htmlOutput = ''; - - $js = []; - $jsDefault = []; - - $htmlOutput .= $this->formDisplayTemplate->displayFormTop($formAction, 'post', $hiddenFields); - - if ($tabbedForm) { - $tabs = []; - foreach ($this->_forms as $form) { - $tabs[$form->name] = Descriptions::get("Form_$form->name"); - } - $htmlOutput .= $this->formDisplayTemplate->displayTabsTop($tabs); - } - - // validate only when we aren't displaying a "new server" form - $isNewServer = false; - foreach ($this->_forms as $form) { - /** @var Form $form */ - if ($form->index === 0) { - $isNewServer = true; - break; - } - } - if (! $isNewServer) { - $this->_validate(); - } - - // user preferences - $this->_loadUserprefsInfo(); - - // display forms - $htmlOutput .= $this->_displayForms( - $showRestoreDefault, - $jsDefault, - $js, - $showButtons - ); - - if ($tabbedForm) { - $htmlOutput .= $this->formDisplayTemplate->displayTabsBottom(); - } - $htmlOutput .= $this->formDisplayTemplate->displayFormBottom(); - - // if not already done, send strings used for validation to JavaScript - if (! $jsLangSent) { - $jsLangSent = true; - $jsLang = []; - foreach ($this->_jsLangStrings as $strName => $strValue) { - $jsLang[] = "'$strName': '" . Sanitize::jsFormat($strValue, false) . '\''; - } - $js[] = "$.extend(Messages, {\n\t" - . implode(",\n\t", $jsLang) . '})'; - } - - $js[] = "$.extend(defaultValues, {\n\t" - . implode(",\n\t", $jsDefault) . '})'; - $htmlOutput .= $this->formDisplayTemplate->displayJavascript($js); - - return $htmlOutput; - } - - /** - * Prepares data for input field display and outputs HTML code - * - * @param Form $form Form object - * @param string $field field name as it appears in $form - * @param string $systemPath field path, eg. Servers/1/verbose - * @param string $workPath work path, eg. Servers/4/verbose - * @param string $translatedPath work path changed so that it can be - * used as XHTML id - * @param bool $showRestoreDefault whether show "restore default" button - * besides the input field - * @param bool|null $userPrefsAllow whether user preferences are enabled - * for this field (null - no support, - * true/false - enabled/disabled) - * @param array $jsDefault array which stores JavaScript code - * to be displayed - * - * @return string|null HTML for input field - */ - private function _displayFieldInput( - Form $form, - $field, - $systemPath, - $workPath, - $translatedPath, - $showRestoreDefault, - $userPrefsAllow, - array &$jsDefault - ) { - $name = Descriptions::get($systemPath); - $description = Descriptions::get($systemPath, 'desc'); - - $value = $this->_configFile->get($workPath); - $valueDefault = $this->_configFile->getDefault($systemPath); - $valueIsDefault = false; - if ($value === null || $value === $valueDefault) { - $value = $valueDefault; - $valueIsDefault = true; - } - - $opts = [ - 'doc' => $this->getDocLink($systemPath), - 'show_restore_default' => $showRestoreDefault, - 'userprefs_allow' => $userPrefsAllow, - 'userprefs_comment' => Descriptions::get($systemPath, 'cmt'), - ]; - if (isset($form->default[$systemPath])) { - $opts['setvalue'] = (string) $form->default[$systemPath]; - } - - if (isset($this->_errors[$workPath])) { - $opts['errors'] = $this->_errors[$workPath]; - } - - $type = ''; - switch ($form->getOptionType($field)) { - case 'string': - $type = 'text'; - break; - case 'short_string': - $type = 'short_text'; - break; - case 'double': - case 'integer': - $type = 'number_text'; - break; - case 'boolean': - $type = 'checkbox'; - break; - case 'select': - $type = 'select'; - $opts['values'] = $form->getOptionValueList($form->fields[$field]); - break; - case 'array': - $type = 'list'; - $value = (array) $value; - $valueDefault = (array) $valueDefault; - break; - case 'group': - // :group:end is changed to :group:end:{unique id} in Form class - $htmlOutput = ''; - if (mb_substr($field, 7, 4) != 'end:') { - $htmlOutput .= $this->formDisplayTemplate->displayGroupHeader( - mb_substr($field, 7) - ); - } else { - $this->formDisplayTemplate->displayGroupFooter(); - } - return $htmlOutput; - case 'NULL': - trigger_error("Field $systemPath has no type", E_USER_WARNING); - return null; - } - - // detect password fields - if ($type === 'text' - && (mb_substr($translatedPath, -9) === '-password' - || mb_substr($translatedPath, -4) === 'pass' - || mb_substr($translatedPath, -4) === 'Pass') - ) { - $type = 'password'; - } - - // TrustedProxies requires changes before displaying - if ($systemPath == 'TrustedProxies') { - foreach ($value as $ip => &$v) { - if (! preg_match('/^-\d+$/', $ip)) { - $v = $ip . ': ' . $v; - } - } - } - $this->_setComments($systemPath, $opts); - - // send default value to form's JS - $jsLine = '\'' . $translatedPath . '\': '; - switch ($type) { - case 'text': - case 'short_text': - case 'number_text': - case 'password': - $jsLine .= '\'' . Sanitize::escapeJsString($valueDefault) . '\''; - break; - case 'checkbox': - $jsLine .= $valueDefault ? 'true' : 'false'; - break; - case 'select': - $valueDefaultJs = is_bool($valueDefault) - ? (int) $valueDefault - : $valueDefault; - $jsLine .= '[\'' . Sanitize::escapeJsString($valueDefaultJs) . '\']'; - break; - case 'list': - $jsLine .= '\'' . Sanitize::escapeJsString(implode("\n", $valueDefault)) - . '\''; - break; - } - $jsDefault[] = $jsLine; - - return $this->formDisplayTemplate->displayInput( - $translatedPath, - $name, - $type, - $value, - $description, - $valueIsDefault, - $opts - ); - } - - /** - * Displays errors - * - * @return string|null HTML for errors - */ - public function displayErrors() - { - $this->_validate(); - if (count($this->_errors) === 0) { - return null; - } - - $htmlOutput = ''; - - foreach ($this->_errors as $systemPath => $errorList) { - if (isset($this->_systemPaths[$systemPath])) { - $name = Descriptions::get($this->_systemPaths[$systemPath]); - } else { - $name = Descriptions::get('Form_' . $systemPath); - } - $htmlOutput .= $this->formDisplayTemplate->displayErrors($name, $errorList); - } - - return $htmlOutput; - } - - /** - * Reverts erroneous fields to their default values - * - * @return void - */ - public function fixErrors() - { - $this->_validate(); - if (count($this->_errors) === 0) { - return; - } - - $cf = $this->_configFile; - foreach (array_keys($this->_errors) as $workPath) { - if (! isset($this->_systemPaths[$workPath])) { - continue; - } - $canonicalPath = $this->_systemPaths[$workPath]; - $cf->set($workPath, $cf->getDefault($canonicalPath)); - } - } - - /** - * Validates select field and casts $value to correct type - * - * @param string $value Current value - * @param array $allowed List of allowed values - * - * @return bool - */ - private function _validateSelect(&$value, array $allowed) - { - $valueCmp = is_bool($value) - ? (int) $value - : $value; - foreach ($allowed as $vk => $v) { - // equality comparison only if both values are numeric or not numeric - // (allows to skip 0 == 'string' equalling to true) - // or identity (for string-string) - if (($vk == $value && ! (is_numeric($valueCmp) xor is_numeric($vk))) - || $vk === $value - ) { - // keep boolean value as boolean - if (! is_bool($value)) { - settype($value, gettype($vk)); - } - return true; - } - } - return false; - } - - /** - * Validates and saves form data to session - * - * @param array|string $forms array of form names - * @param bool $allowPartialSave allows for partial form saving on - * failed validation - * - * @return boolean true on success (no errors and all saved) - */ - public function save($forms, $allowPartialSave = true) - { - $result = true; - $forms = (array) $forms; - - $values = []; - $toSave = []; - $isSetupScript = $GLOBALS['PMA_Config']->get('is_setup'); - if ($isSetupScript) { - $this->_loadUserprefsInfo(); - } - - $this->_errors = []; - foreach ($forms as $formName) { - /** @var Form $form */ - if (isset($this->_forms[$formName])) { - $form = $this->_forms[$formName]; - } else { - continue; - } - // get current server id - $changeIndex = $form->index === 0 - ? $this->_configFile->getServerCount() + 1 - : false; - // grab POST values - foreach ($form->fields as $field => $systemPath) { - $workPath = array_search($systemPath, $this->_systemPaths); - $key = $this->_translatedPaths[$workPath]; - $type = $form->getOptionType($field); - - // skip groups - if ($type == 'group') { - continue; - } - - // ensure the value is set - if (! isset($_POST[$key])) { - // checkboxes aren't set by browsers if they're off - if ($type == 'boolean') { - $_POST[$key] = false; - } else { - $this->_errors[$form->name][] = sprintf( - __('Missing data for %s'), - '' . Descriptions::get($systemPath) . '' - ); - $result = false; - continue; - } - } - - // user preferences allow/disallow - if ($isSetupScript - && isset($this->_userprefsKeys[$systemPath]) - ) { - if (isset($this->_userprefsDisallow[$systemPath]) - && isset($_POST[$key . '-userprefs-allow']) - ) { - unset($this->_userprefsDisallow[$systemPath]); - } elseif (! isset($_POST[$key . '-userprefs-allow'])) { - $this->_userprefsDisallow[$systemPath] = true; - } - } - - // cast variables to correct type - switch ($type) { - case 'double': - $_POST[$key] = Util::requestString($_POST[$key]); - settype($_POST[$key], 'float'); - break; - case 'boolean': - case 'integer': - if ($_POST[$key] !== '') { - $_POST[$key] = Util::requestString($_POST[$key]); - settype($_POST[$key], $type); - } - break; - case 'select': - $successfullyValidated = $this->_validateSelect( - $_POST[$key], - $form->getOptionValueList($systemPath) - ); - if (! $successfullyValidated) { - $this->_errors[$workPath][] = __('Incorrect value!'); - $result = false; - // "continue" for the $form->fields foreach-loop - continue 2; - } - break; - case 'string': - case 'short_string': - $_POST[$key] = Util::requestString($_POST[$key]); - break; - case 'array': - // eliminate empty values and ensure we have an array - $postValues = is_array($_POST[$key]) - ? $_POST[$key] - : explode("\n", $_POST[$key]); - $_POST[$key] = []; - $this->_fillPostArrayParameters($postValues, $key); - break; - } - - // now we have value with proper type - $values[$systemPath] = $_POST[$key]; - if ($changeIndex !== false) { - $workPath = str_replace( - "Servers/$form->index/", - "Servers/$changeIndex/", - $workPath - ); - } - $toSave[$workPath] = $systemPath; - } - } - - // save forms - if (! $allowPartialSave && ! empty($this->_errors)) { - // don't look for non-critical errors - $this->_validate(); - return $result; - } - - foreach ($toSave as $workPath => $path) { - // TrustedProxies requires changes before saving - if ($path == 'TrustedProxies') { - $proxies = []; - $i = 0; - foreach ($values[$path] as $value) { - $matches = []; - $match = preg_match( - "/^(.+):(?:[ ]?)(\\w+)$/", - $value, - $matches - ); - if ($match) { - // correct 'IP: HTTP header' pair - $ip = trim($matches[1]); - $proxies[$ip] = trim($matches[2]); - } else { - // save also incorrect values - $proxies["-$i"] = $value; - $i++; - } - } - $values[$path] = $proxies; - } - $this->_configFile->set($workPath, $values[$path], $path); - } - if ($isSetupScript) { - $this->_configFile->set( - 'UserprefsDisallow', - array_keys($this->_userprefsDisallow) - ); - } - - // don't look for non-critical errors - $this->_validate(); - - return $result; - } - - /** - * Tells whether form validation failed - * - * @return boolean - */ - public function hasErrors() - { - return count($this->_errors) > 0; - } - - - /** - * Returns link to documentation - * - * @param string $path Path to documentation - * - * @return string - */ - public function getDocLink($path) - { - $test = mb_substr($path, 0, 6); - if ($test == 'Import' || $test == 'Export') { - return ''; - } - return Util::getDocuLink( - 'config', - 'cfg_' . $this->_getOptName($path) - ); - } - - /** - * Changes path so it can be used in URLs - * - * @param string $path Path - * - * @return string - */ - private function _getOptName($path) - { - return str_replace(['Servers/1/', '/'], ['Servers/', '_'], $path); - } - - /** - * Fills out {@link userprefs_keys} and {@link userprefs_disallow} - * - * @return void - */ - private function _loadUserprefsInfo() - { - if ($this->_userprefsKeys !== null) { - return; - } - - $this->_userprefsKeys = array_flip(UserFormList::getFields()); - // read real config for user preferences display - $userPrefsDisallow = $GLOBALS['PMA_Config']->get('is_setup') - ? $this->_configFile->get('UserprefsDisallow', []) - : $GLOBALS['cfg']['UserprefsDisallow']; - $this->_userprefsDisallow = array_flip($userPrefsDisallow); - } - - /** - * Sets field comments and warnings based on current environment - * - * @param string $systemPath Path to settings - * @param array $opts Chosen options - * - * @return void - */ - private function _setComments($systemPath, array &$opts) - { - // RecodingEngine - mark unavailable types - if ($systemPath == 'RecodingEngine') { - $comment = ''; - if (! function_exists('iconv')) { - $opts['values']['iconv'] .= ' (' . __('unavailable') . ')'; - $comment = sprintf( - __('"%s" requires %s extension'), - 'iconv', - 'iconv' - ); - } - if (! function_exists('recode_string')) { - $opts['values']['recode'] .= ' (' . __('unavailable') . ')'; - $comment .= ($comment ? ", " : '') . sprintf( - __('"%s" requires %s extension'), - 'recode', - 'recode' - ); - } - /* mbstring is always there thanks to polyfill */ - $opts['comment'] = $comment; - $opts['comment_warning'] = true; - } - // ZipDump, GZipDump, BZipDump - check function availability - if ($systemPath == 'ZipDump' - || $systemPath == 'GZipDump' - || $systemPath == 'BZipDump' - ) { - $comment = ''; - $funcs = [ - 'ZipDump' => [ - 'zip_open', - 'gzcompress', - ], - 'GZipDump' => [ - 'gzopen', - 'gzencode', - ], - 'BZipDump' => [ - 'bzopen', - 'bzcompress', - ], - ]; - if (! function_exists($funcs[$systemPath][0])) { - $comment = sprintf( - __( - 'Compressed import will not work due to missing function %s.' - ), - $funcs[$systemPath][0] - ); - } - if (! function_exists($funcs[$systemPath][1])) { - $comment .= ($comment ? '; ' : '') . sprintf( - __( - 'Compressed export will not work due to missing function %s.' - ), - $funcs[$systemPath][1] - ); - } - $opts['comment'] = $comment; - $opts['comment_warning'] = true; - } - if (! $GLOBALS['PMA_Config']->get('is_setup')) { - if ($systemPath == 'MaxDbList' || $systemPath == 'MaxTableList' - || $systemPath == 'QueryHistoryMax' - ) { - $opts['comment'] = sprintf( - __('maximum %s'), - $GLOBALS['cfg'][$systemPath] - ); - } - } - } - - /** - * Copy items of an array to $_POST variable - * - * @param array $postValues List of parameters - * @param string $key Array key - * - * @return void - */ - private function _fillPostArrayParameters(array $postValues, $key) - { - foreach ($postValues as $v) { - $v = Util::requestString($v); - if ($v !== '') { - $_POST[$key][] = $v; - } - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/FormDisplayTemplate.php b/srcs/phpmyadmin/libraries/classes/Config/FormDisplayTemplate.php deleted file mode 100644 index 07663b8..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/FormDisplayTemplate.php +++ /dev/null @@ -1,526 +0,0 @@ -config = $config; - $this->template = new Template(); - } - - /** - * Displays top part of the form - * - * @param string $action default: $_SERVER['REQUEST_URI'] - * @param string $method 'post' or 'get' - * @param array|null $hiddenFields array of form hidden fields (key: field name) - * - * @return string - */ - public function displayFormTop( - $action = null, - $method = 'post', - $hiddenFields = null - ): string { - static $hasCheckPageRefresh = false; - - if ($action === null) { - $action = $_SERVER['REQUEST_URI']; - } - if ($method != 'post') { - $method = 'get'; - } - $htmlOutput = '
'; - $htmlOutput .= ''; - // we do validation on page refresh when browser remembers field values, - // add a field with known value which will be used for checks - if (! $hasCheckPageRefresh) { - $hasCheckPageRefresh = true; - $htmlOutput .= '' . "\n"; - } - $htmlOutput .= Url::getHiddenInputs('', '', 0, 'server') . "\n"; - $htmlOutput .= Url::getHiddenFields((array) $hiddenFields, '', true); - return $htmlOutput; - } - - /** - * Displays form tabs which are given by an array indexed by fieldset id - * ({@link self::displayFieldsetTop}), with values being tab titles. - * - * @param array $tabs tab names - * - * @return string - */ - public function displayTabsTop(array $tabs): string - { - $items = []; - foreach ($tabs as $tabId => $tabName) { - $items[] = [ - 'content' => htmlspecialchars($tabName), - 'url' => [ - 'href' => '#' . $tabId, - ], - ]; - } - - $htmlOutput = $this->template->render('list/unordered', [ - 'class' => 'tabs responsivetable', - 'items' => $items, - ]); - $htmlOutput .= '
'; - $htmlOutput .= '
'; - return $htmlOutput; - } - - /** - * Displays top part of a fieldset - * - * @param string $title title of fieldset - * @param string $description description shown on top of fieldset - * @param array|null $errors error messages to display - * @param array $attributes optional extra attributes of fieldset - * - * @return string - */ - public function displayFieldsetTop( - $title = '', - $description = '', - $errors = null, - array $attributes = [] - ): string { - $this->group = 0; - - $attributes = array_merge(['class' => 'optbox'], $attributes); - - return $this->template->render('config/form_display/fieldset_top', [ - 'attributes' => $attributes, - 'title' => $title, - 'description' => $description, - 'errors' => $errors, - ]); - } - - /** - * Displays input field - * - * $opts keys: - * o doc - (string) documentation link - * o errors - error array - * o setvalue - (string) shows button allowing to set predefined value - * o show_restore_default - (boolean) whether show "restore default" button - * o userprefs_allow - whether user preferences are enabled for this field - * (null - no support, true/false - enabled/disabled) - * o userprefs_comment - (string) field comment - * o values - key - value pairs for '; - break; - case 'password': - $htmlOutput .= ''; - break; - case 'short_text': - // As seen in the reporting server (#15042) we sometimes receive - // an array here. No clue about its origin nor content, so let's avoid - // a notice on htmlspecialchars(). - if (! is_array($value)) { - $htmlOutput .= ''; - } - break; - case 'number_text': - $htmlOutput .= ''; - break; - case 'checkbox': - $htmlOutput .= ''; - break; - case 'select': - $htmlOutput .= ''; - break; - case 'list': - $htmlOutput .= ''; - break; - } - if ($isSetupScript - && isset($opts['userprefs_comment']) - && $opts['userprefs_comment'] - ) { - $htmlOutput .= '' - . $icons['tblops'] . ''; - } - if (isset($opts['setvalue']) && $opts['setvalue']) { - $htmlOutput .= '' . $icons['edit'] . ''; - } - if (isset($opts['show_restore_default']) && $opts['show_restore_default']) { - $htmlOutput .= '' . $icons['reload'] . ''; - } - // this must match with displayErrors() in scripts/config.js - if ($hasErrors) { - $htmlOutput .= "\n
"; - foreach ($opts['errors'] as $error) { - $htmlOutput .= '
' . htmlspecialchars($error) . '
'; - } - $htmlOutput .= '
'; - } - $htmlOutput .= ''; - if ($isSetupScript && isset($opts['userprefs_allow'])) { - $htmlOutput .= ''; - $htmlOutput .= 'group++; - if ($headerText === '') { - return ''; - } - $colspan = $this->config->get('is_setup') ? 3 : 2; - - return $this->template->render('config/form_display/group_header', [ - 'group' => $this->group, - 'colspan' => $colspan, - 'header_text' => $headerText, - ]); - } - - /** - * Display group footer - * - * @return void - */ - public function displayGroupFooter(): void - { - $this->group--; - } - - /** - * Displays bottom part of a fieldset - * - * @param bool $showButtons Whether show submit and reset button - * - * @return string - */ - public function displayFieldsetBottom(bool $showButtons = true): string - { - return $this->template->render('config/form_display/fieldset_bottom', [ - 'show_buttons' => $showButtons, - 'is_setup' => $this->config->get('is_setup'), - ]); - } - - /** - * Closes form tabs - * - * @return string - */ - public function displayTabsBottom(): string - { - return $this->template->render('config/form_display/tabs_bottom'); - } - - /** - * Displays bottom part of the form - * - * @return string - */ - public function displayFormBottom(): string - { - return $this->template->render('config/form_display/form_bottom'); - } - - /** - * Appends JS validation code to $js_array - * - * @param string $fieldId ID of field to validate - * @param string|array $validators validators callback - * @param array $jsArray will be updated with javascript code - * - * @return void - */ - public function addJsValidate($fieldId, $validators, array &$jsArray): void - { - foreach ((array) $validators as $validator) { - $validator = (array) $validator; - $vName = array_shift($validator); - $vArgs = []; - foreach ($validator as $arg) { - $vArgs[] = Sanitize::escapeJsString($arg); - } - $vArgs = $vArgs ? ", ['" . implode("', '", $vArgs) . "']" : ''; - $jsArray[] = "registerFieldValidator('$fieldId', '$vName', true$vArgs)"; - } - } - - /** - * Displays JavaScript code - * - * @param array $jsArray lines of javascript code - * - * @return string - */ - public function displayJavascript(array $jsArray): string - { - if (empty($jsArray)) { - return ''; - } - - return $this->template->render('javascript/display', [ - 'js_array' => $jsArray, - ]); - } - - /** - * Displays error list - * - * @param string $name Name of item with errors - * @param array $errorList List of errors to show - * - * @return string HTML for errors - */ - public function displayErrors($name, array $errorList): string - { - return $this->template->render('config/form_display/errors', [ - 'name' => $name, - 'error_list' => $errorList, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/BaseForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/BaseForm.php deleted file mode 100644 index 2049070..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/BaseForm.php +++ /dev/null @@ -1,89 +0,0 @@ -= 1 if editing a server - */ - public function __construct(ConfigFile $cf, $serverId = null) - { - parent::__construct($cf); - foreach (static::getForms() as $formName => $form) { - $this->registerForm($formName, $form, $serverId); - } - } - - /** - * List of available forms, each form is described as an array of fields to display. - * Fields MUST have their counterparts in the $cfg array. - * - * To define form field, use the notation below: - * $forms['Form group']['Form name'] = array('Option/path'); - * - * 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' - * - * @todo This should be abstract, but that does not work in PHP 5 - * - * @return array - */ - public static function getForms() - { - return []; - } - - /** - * Returns list of fields used in the form. - * - * @return string[] - */ - public static function getFields() - { - $names = []; - foreach (static::getForms() as $form) { - foreach ($form as $k => $v) { - $names[] = is_int($k) ? $v : $k; - } - } - return $names; - } - - /** - * Returns name of the form - * - * @todo This should be abstract, but that does not work in PHP 5 - * - * @return string - */ - public static function getName() - { - return ''; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/BaseFormList.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/BaseFormList.php deleted file mode 100644 index f4a5d32..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/BaseFormList.php +++ /dev/null @@ -1,150 +0,0 @@ -_forms = []; - foreach (static::$all as $form) { - $class = static::get($form); - $this->_forms[] = new $class($cf); - } - } - - /** - * Processes forms, returns true on successful save - * - * @param bool $allowPartialSave allows for partial form saving - * on failed validation - * @param bool $checkFormSubmit whether check for $_POST['submit_save'] - * - * @return boolean whether processing was successful - */ - public function process($allowPartialSave = true, $checkFormSubmit = true) - { - $ret = true; - foreach ($this->_forms as $form) { - $ret = $ret && $form->process($allowPartialSave, $checkFormSubmit); - } - return $ret; - } - - /** - * Displays errors - * - * @return string HTML for errors - */ - public function displayErrors() - { - $ret = ''; - foreach ($this->_forms as $form) { - $ret .= $form->displayErrors(); - } - return $ret; - } - - /** - * Reverts erroneous fields to their default values - * - * @return void - */ - public function fixErrors() - { - foreach ($this->_forms as $form) { - $form->fixErrors(); - } - } - - /** - * Tells whether form validation failed - * - * @return boolean - */ - public function hasErrors() - { - $ret = false; - foreach ($this->_forms as $form) { - $ret = $ret || $form->hasErrors(); - } - return $ret; - } - - /** - * Returns list of fields used in the form. - * - * @return string[] - */ - public static function getFields() - { - $names = []; - foreach (static::$all as $form) { - $class = static::get($form); - $names = array_merge($names, $class::getFields()); - } - return $names; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/Page/BrowseForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/Page/BrowseForm.php deleted file mode 100644 index eee578a..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/Page/BrowseForm.php +++ /dev/null @@ -1,30 +0,0 @@ - MainForm::getForms()['Browse'], - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/Page/DbStructureForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/Page/DbStructureForm.php deleted file mode 100644 index 4f9a8e4..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/Page/DbStructureForm.php +++ /dev/null @@ -1,30 +0,0 @@ - MainForm::getForms()['DbStructure'], - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/Page/EditForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/Page/EditForm.php deleted file mode 100644 index ad2fd46..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/Page/EditForm.php +++ /dev/null @@ -1,32 +0,0 @@ - MainForm::getForms()['Edit'], - 'Text_fields' => FeaturesForm::getForms()['Text_fields'], - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/Page/ExportForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/Page/ExportForm.php deleted file mode 100644 index 584b2fd..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/Page/ExportForm.php +++ /dev/null @@ -1,18 +0,0 @@ - MainForm::getForms()['TableStructure'], - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ConfigForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ConfigForm.php deleted file mode 100644 index 6fd4515..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ConfigForm.php +++ /dev/null @@ -1,32 +0,0 @@ - [ - 'DefaultLang', - 'ServerDefault', - ], - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ExportForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ExportForm.php deleted file mode 100644 index adf7ce4..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ExportForm.php +++ /dev/null @@ -1,18 +0,0 @@ - ':group', - 'IconvExtraParams', - ':group:end', - 'ZipDump', - 'GZipDump', - 'BZipDump', - 'CompressOnFly', - ]; - $result['Security'] = [ - 'blowfish_secret', - 'CheckConfigurationPermissions', - 'TrustedProxies', - 'AllowUserDropDatabase', - 'AllowArbitraryServer', - 'ArbitraryServerRegexp', - 'LoginCookieRecall', - 'LoginCookieStore', - 'LoginCookieDeleteAll', - 'CaptchaLoginPublicKey', - 'CaptchaLoginPrivateKey', - ]; - $result['Developer'] = [ - 'UserprefsDeveloperTab', - 'DBG/sql', - ]; - $result['Other_core_settings'] = [ - 'OBGzip', - 'PersistentConnections', - 'ExecTimeLimit', - 'MemoryLimit', - 'UseDbSearch', - 'ProxyUrl', - 'ProxyUser', - 'ProxyPass', - 'AllowThirdPartyFraming', - 'ZeroConf', - ]; - return $result; - // phpcs:enable - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ImportForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ImportForm.php deleted file mode 100644 index 06adf35..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/ImportForm.php +++ /dev/null @@ -1,18 +0,0 @@ - [ - 'Servers' => [ - 1 => [ - 'verbose', - 'host', - 'port', - 'socket', - 'ssl', - 'compress', - ], - ], - ], - 'Server_auth' => [ - 'Servers' => [ - 1 => [ - 'auth_type', - ':group:' . __('Config authentication'), - 'user', - 'password', - ':group:end', - ':group:' . __('HTTP authentication'), - 'auth_http_realm', - ':group:end', - ':group:' . __('Signon authentication'), - 'SignonSession', - 'SignonURL', - 'LogoutURL', - ], - ], - ], - 'Server_config' => [ - 'Servers' => [ - 1 => [ - 'only_db', - 'hide_db', - 'AllowRoot', - 'AllowNoPassword', - 'DisableIS', - 'AllowDeny/order', - 'AllowDeny/rules', - 'SessionTimeZone', - ], - ], - ], - 'Server_pmadb' => [ - 'Servers' => [ - 1 => [ - 'pmadb' => 'phpmyadmin', - 'controlhost', - 'controlport', - 'controluser', - 'controlpass', - 'bookmarktable' => 'pma__bookmark', - 'relation' => 'pma__relation', - 'userconfig' => 'pma__userconfig', - 'users' => 'pma__users', - 'usergroups' => 'pma__usergroups', - 'navigationhiding' => 'pma__navigationhiding', - 'table_info' => 'pma__table_info', - 'column_info' => 'pma__column_info', - 'history' => 'pma__history', - 'recent' => 'pma__recent', - 'favorite' => 'pma__favorite', - 'table_uiprefs' => 'pma__table_uiprefs', - 'tracking' => 'pma__tracking', - 'table_coords' => 'pma__table_coords', - 'pdf_pages' => 'pma__pdf_pages', - 'savedsearches' => 'pma__savedsearches', - 'central_columns' => 'pma__central_columns', - 'designer_settings' => 'pma__designer_settings', - 'export_templates' => 'pma__export_templates', - 'MaxTableUiprefs' => 100, - ], - ], - ], - 'Server_tracking' => [ - 'Servers' => [ - 1 => [ - 'tracking_version_auto_create', - 'tracking_default_statements', - 'tracking_add_drop_view', - 'tracking_add_drop_table', - 'tracking_add_drop_database', - ], - ], - ], - ]; - // phpcs:enable - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/SetupFormList.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/SetupFormList.php deleted file mode 100644 index 91edb27..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/Setup/SetupFormList.php +++ /dev/null @@ -1,37 +0,0 @@ - [ - 'Export/method', - ':group:' . __('Quick'), - 'Export/quick_export_onserver', - 'Export/quick_export_onserver_overwrite', - ':group:end', - ':group:' . __('Custom'), - 'Export/format', - 'Export/compression', - 'Export/charset', - 'Export/lock_tables', - 'Export/as_separate_files', - 'Export/asfile' => ':group', - 'Export/onserver', - 'Export/onserver_overwrite', - ':group:end', - 'Export/file_template_table', - 'Export/file_template_database', - 'Export/file_template_server', - ], - 'Sql' => [ - '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_views_as_tables', - 'Export/sql_metadata', - 'Export/sql_compatibility', - 'Export/sql_structure_or_data', - ':group:' . __('Structure'), - 'Export/sql_drop_database', - 'Export/sql_create_database', - 'Export/sql_drop_table', - 'Export/sql_create_table' => ':group', - 'Export/sql_if_not_exists', - 'Export/sql_auto_increment', - ':group:end', - 'Export/sql_create_view' => ':group', - 'Export/sql_view_current_user', - 'Export/sql_or_replace_view', - ':group:end', - 'Export/sql_procedure_function', - 'Export/sql_create_trigger', - '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_binary', - 'Export/sql_utc_time', - ], - 'CodeGen' => [ - 'Export/codegen_format', - ], - 'Csv' => [ - ':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', - ], - 'Latex' => [ - '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', - ], - 'Microsoft_Office' => [ - ':group:' . __('Microsoft Word 2000'), - 'Export/htmlword_structure_or_data', - 'Export/htmlword_null', - 'Export/htmlword_columns', - ], - 'Open_Document' => [ - ':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', - ], - 'Texy' => [ - 'Export/texytext_structure_or_data', - ':group:' . __('Data'), - 'Export/texytext_null', - 'Export/texytext_columns', - ], - ]; - // phpcs:enable - } - - /** - * @return string - */ - public static function getName() - { - return __('Export'); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/User/FeaturesForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/User/FeaturesForm.php deleted file mode 100644 index 58d3c24..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/User/FeaturesForm.php +++ /dev/null @@ -1,95 +0,0 @@ - [ - 'VersionCheck', - 'NaturalOrder', - 'InitialSlidersState', - 'SkipLockedTables', - 'DisableMultiTableMaintenance', - 'ShowHint', - 'SendErrorReports', - 'ConsoleEnterExecutes', - 'DisableShortcutKeys', - ], - 'Databases' => [ - 'Servers/1/only_db', // saves to Server/only_db - 'Servers/1/hide_db', // saves to Server/hide_db - 'MaxDbList', - 'MaxTableList', - 'DefaultConnectionCollation', - ], - 'Text_fields' => [ - 'CharEditing', - 'MinSizeForInputField', - 'MaxSizeForInputField', - 'CharTextareaCols', - 'CharTextareaRows', - 'TextareaCols', - 'TextareaRows', - 'LongtextDoubleTextarea', - ], - 'Page_titles' => [ - 'TitleDefault', - 'TitleTable', - 'TitleDatabase', - 'TitleServer', - ], - 'Warnings' => [ - 'PmaNoRelation_DisableWarning', - 'SuhosinDisableWarning', - 'LoginCookieValidityDisableWarning', - 'ReservedWordDisableWarning', - ], - 'Console' => [ - 'Console/Mode', - 'Console/StartHistory', - 'Console/AlwaysExpand', - 'Console/CurrentQuery', - 'Console/EnterExecutes', - 'Console/DarkTheme', - 'Console/Height', - 'Console/GroupQueries', - 'Console/OrderBy', - 'Console/Order', - ], - ]; - // skip Developer form if no setting is available - if ($GLOBALS['cfg']['UserprefsDeveloperTab']) { - $result['Developer'] = [ - 'DBG/sql', - ]; - } - return $result; - } - - /** - * @return string - */ - public static function getName() - { - return __('Features'); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/User/ImportForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/User/ImportForm.php deleted file mode 100644 index c447567..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/User/ImportForm.php +++ /dev/null @@ -1,73 +0,0 @@ - [ - 'Import/format', - 'Import/charset', - 'Import/allow_interrupt', - 'Import/skip_queries', - 'enable_drag_drop_import', - ], - 'Sql' => [ - 'Import/sql_compatibility', - 'Import/sql_no_auto_value_on_zero', - 'Import/sql_read_as_multibytes', - ], - 'Csv' => [ - ':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', - ], - 'Open_Document' => [ - ':group:' . __('OpenDocument Spreadsheet'), - 'Import/ods_col_names', - 'Import/ods_empty_rows', - 'Import/ods_recognize_percentages', - 'Import/ods_recognize_currency', - ], - - ]; - } - - /** - * @return string - */ - public static function getName() - { - return __('Import'); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/User/MainForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/User/MainForm.php deleted file mode 100644 index 907bbaa..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/User/MainForm.php +++ /dev/null @@ -1,98 +0,0 @@ - [ - 'ShowCreateDb', - 'ShowStats', - 'ShowServerInfo', - ], - 'DbStructure' => [ - 'ShowDbStructureCharset', - 'ShowDbStructureComment', - 'ShowDbStructureCreation', - 'ShowDbStructureLastUpdate', - 'ShowDbStructureLastCheck', - ], - 'TableStructure' => [ - 'HideStructureActions', - 'ShowColumnComments', - ':group:' . __('Default transformations'), - 'DefaultTransformations/Hex', - 'DefaultTransformations/Substring', - 'DefaultTransformations/Bool2Text', - 'DefaultTransformations/External', - 'DefaultTransformations/PreApPend', - 'DefaultTransformations/DateFormat', - 'DefaultTransformations/Inline', - 'DefaultTransformations/TextImageLink', - 'DefaultTransformations/TextLink', - ':group:end', - ], - 'Browse' => [ - 'TableNavigationLinksMode', - 'ActionLinksMode', - 'ShowAll', - 'MaxRows', - 'Order', - 'BrowsePointerEnable', - 'BrowseMarkerEnable', - 'GridEditing', - 'SaveCellsAtOnce', - 'RepeatCells', - 'LimitChars', - 'RowActionLinks', - 'RowActionLinksWithoutUnique', - 'TablePrimaryKeyOrder', - 'RememberSorting', - 'RelationalDisplay', - ], - 'Edit' => [ - 'ProtectBinary', - 'ShowFunctionFields', - 'ShowFieldTypesInDataEditView', - 'InsertRows', - 'ForeignKeyDropdownOrder', - 'ForeignKeyMaxLimit', - ], - 'Tabs' => [ - 'TabsMode', - 'DefaultTabServer', - 'DefaultTabDatabase', - 'DefaultTabTable', - ], - 'DisplayRelationalSchema' => [ - 'PDFDefaultPageSize', - ], - ]; - } - - /** - * @return string - */ - public static function getName() - { - return __('Main panel'); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/User/NaviForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/User/NaviForm.php deleted file mode 100644 index e2d373c..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/User/NaviForm.php +++ /dev/null @@ -1,74 +0,0 @@ - [ - 'ShowDatabasesNavigationAsTree', - 'NavigationLinkWithMainPanel', - 'NavigationDisplayLogo', - 'NavigationLogoLink', - 'NavigationLogoLinkWindow', - 'NavigationTreePointerEnable', - 'FirstLevelNavigationItems', - 'NavigationTreeDisplayItemFilterMinimum', - 'NumRecentTables', - 'NumFavoriteTables', - 'NavigationWidth', - ], - 'Navi_tree' => [ - 'MaxNavigationItems', - 'NavigationTreeEnableGrouping', - 'NavigationTreeEnableExpansion', - 'NavigationTreeShowTables', - 'NavigationTreeShowViews', - 'NavigationTreeShowFunctions', - 'NavigationTreeShowProcedures', - 'NavigationTreeShowEvents', - 'NavigationTreeAutoexpandSingleDb', - ], - 'Navi_servers' => [ - 'NavigationDisplayServers', - 'DisplayServersList', - ], - 'Navi_databases' => [ - 'NavigationTreeDisplayDbFilterMinimum', - 'NavigationTreeDbSeparator', - ], - 'Navi_tables' => [ - 'NavigationTreeDefaultTabTable', - 'NavigationTreeDefaultTabTable2', - 'NavigationTreeTableSeparator', - 'NavigationTreeTableLevel', - ], - ]; - } - - /** - * @return string - */ - public static function getName() - { - return __('Navigation panel'); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/User/SqlForm.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/User/SqlForm.php deleted file mode 100644 index 3d8ac7a..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/User/SqlForm.php +++ /dev/null @@ -1,54 +0,0 @@ - [ - 'ShowSQL', - 'Confirm', - 'QueryHistoryMax', - 'IgnoreMultiSubmitErrors', - 'MaxCharactersInDisplayedSQL', - 'RetainQueryBox', - 'CodemirrorEnable', - 'LintEnable', - 'EnableAutocompleteForTablesAndColumns', - 'DefaultForeignKeyChecks', - ], - 'Sql_box' => [ - 'SQLQuery/Edit', - 'SQLQuery/Explain', - 'SQLQuery/ShowAsPHP', - 'SQLQuery/Refresh', - ], - ]; - } - - /** - * @return string - */ - public static function getName() - { - return __('SQL queries'); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Forms/User/UserFormList.php b/srcs/phpmyadmin/libraries/classes/Config/Forms/User/UserFormList.php deleted file mode 100644 index 92294ed..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Forms/User/UserFormList.php +++ /dev/null @@ -1,35 +0,0 @@ -userPreferences = new UserPreferences(); - - $formClass = PageFormList::get($formGroupName); - if ($formClass === null) { - return; - } - - if (isset($_REQUEST['printview']) && $_REQUEST['printview'] == '1') { - return; - } - - if (! empty($elemId)) { - $this->_elemId = $elemId; - } - $this->_groupName = $formGroupName; - - $cf = new ConfigFile($GLOBALS['PMA_Config']->base_settings); - $this->userPreferences->pageInit($cf); - - $formDisplay = new $formClass($cf); - - // Process form - $error = null; - if (isset($_POST['submit_save']) - && $_POST['submit_save'] == $formGroupName - ) { - $this->_processPageSettings($formDisplay, $cf, $error); - } - - // Display forms - $this->_HTML = $this->_getPageSettingsDisplay($formDisplay, $error); - } - - /** - * Process response to form - * - * @param FormDisplay $formDisplay Form - * @param ConfigFile $cf Configuration file - * @param Message|null $error Error message - * - * @return void - */ - private function _processPageSettings(&$formDisplay, &$cf, &$error) - { - if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) { - // save settings - $result = $this->userPreferences->save($cf->getConfigArray()); - if ($result === true) { - // reload page - $response = Response::getInstance(); - Core::sendHeaderLocation( - $response->getFooter()->getSelfUrl() - ); - exit; - } else { - $error = $result; - } - } - } - - /** - * Store errors in _errorHTML - * - * @param FormDisplay $formDisplay Form - * @param Message|null $error Error message - * - * @return void - */ - private function _storeError(&$formDisplay, &$error) - { - $retval = ''; - if ($error) { - $retval .= $error->getDisplay(); - } - if ($formDisplay->hasErrors()) { - // form has errors - $retval .= '
' - . '' . __( - 'Cannot save settings, submitted configuration form contains ' - . 'errors!' - ) . '' - . $formDisplay->displayErrors() - . '
'; - } - $this->_errorHTML = $retval; - } - - /** - * Display page-related settings - * - * @param FormDisplay $formDisplay Form - * @param Message $error Error message - * - * @return string - */ - private function _getPageSettingsDisplay(&$formDisplay, &$error) - { - $response = Response::getInstance(); - - $retval = ''; - - $this->_storeError($formDisplay, $error); - - $retval .= '
'; - $retval .= '
'; - $retval .= $formDisplay->getDisplay( - true, - true, - false, - $response->getFooter()->getSelfUrl(), - [ - 'submit_save' => $this->_groupName, - ] - ); - $retval .= '
'; - $retval .= '
'; - - return $retval; - } - - /** - * Get HTML output - * - * @return string - */ - public function getHTML() - { - return $this->_HTML; - } - - /** - * Get error HTML output - * - * @return string - */ - public function getErrorHTML() - { - return $this->_errorHTML; - } - - /** - * Group to show for Page-related settings - * @param string $formGroupName The name of config form group to display - * @return PageSettings - */ - public static function showGroup($formGroupName) - { - $object = new PageSettings($formGroupName); - - $response = Response::getInstance(); - $response->addHTML($object->getErrorHTML()); - $response->addHTML($object->getHTML()); - - return $object; - } - - /** - * Get HTML for navigation settings - * @return string - */ - public static function getNaviSettings() - { - $object = new PageSettings('Navi', 'pma_navigation_settings'); - - $response = Response::getInstance(); - $response->addHTML($object->getErrorHTML()); - return $object->getHTML(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/ServerConfigChecks.php b/srcs/phpmyadmin/libraries/classes/Config/ServerConfigChecks.php deleted file mode 100644 index 1b0ac9d..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/ServerConfigChecks.php +++ /dev/null @@ -1,583 +0,0 @@ -cfg = $cfg; - } - - /** - * Perform config checks - * - * @return void - */ - public function performConfigChecks() - { - $blowfishSecret = $this->cfg->get('blowfish_secret'); - $blowfishSecretSet = false; - $cookieAuthUsed = false; - - list($cookieAuthUsed, $blowfishSecret, $blowfishSecretSet) - = $this->performConfigChecksServers( - $cookieAuthUsed, - $blowfishSecret, - $blowfishSecretSet - ); - - $this->performConfigChecksCookieAuthUsed( - $cookieAuthUsed, - $blowfishSecretSet, - $blowfishSecret - ); - - // - // $cfg['AllowArbitraryServer'] - // should be disabled - // - if ($this->cfg->getValue('AllowArbitraryServer')) { - $sAllowArbitraryServerWarn = sprintf( - __( - 'This %soption%s should be disabled as it allows attackers to ' - . 'bruteforce login to any MySQL server. If you feel this is necessary, ' - . 'use %srestrict login to MySQL server%s or %strusted proxies list%s. ' - . 'However, IP-based protection with trusted proxies list may not be ' - . 'reliable if your IP belongs to an ISP where thousands of users, ' - . 'including you, are connected to.' - ), - '[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]', - '[/a]', - '[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]', - '[/a]', - '[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]', - '[/a]' - ); - SetupIndex::messagesSet( - 'notice', - 'AllowArbitraryServer', - Descriptions::get('AllowArbitraryServer'), - Sanitize::sanitizeMessage($sAllowArbitraryServerWarn) - ); - } - - $this->performConfigChecksLoginCookie(); - - $sDirectoryNotice = __( - 'This value should be double checked to ensure that this directory is ' - . 'neither world accessible nor readable or writable by other users on ' - . 'your server.' - ); - - // - // $cfg['SaveDir'] - // should not be world-accessible - // - if ($this->cfg->getValue('SaveDir') != '') { - SetupIndex::messagesSet( - 'notice', - 'SaveDir', - Descriptions::get('SaveDir'), - Sanitize::sanitizeMessage($sDirectoryNotice) - ); - } - - // - // $cfg['TempDir'] - // should not be world-accessible - // - if ($this->cfg->getValue('TempDir') != '') { - SetupIndex::messagesSet( - 'notice', - 'TempDir', - Descriptions::get('TempDir'), - Sanitize::sanitizeMessage($sDirectoryNotice) - ); - } - - $this->performConfigChecksZips(); - } - - /** - * Check config of servers - * - * @param boolean $cookieAuthUsed Cookie auth is used - * @param string $blowfishSecret Blowfish secret - * @param boolean $blowfishSecretSet Blowfish secret set - * - * @return array - */ - protected function performConfigChecksServers( - $cookieAuthUsed, - $blowfishSecret, - $blowfishSecretSet - ) { - $serverCnt = $this->cfg->getServerCount(); - for ($i = 1; $i <= $serverCnt; $i++) { - $cookieAuthServer - = ($this->cfg->getValue("Servers/$i/auth_type") == 'cookie'); - $cookieAuthUsed |= $cookieAuthServer; - $serverName = $this->performConfigChecksServersGetServerName( - $this->cfg->getServerName($i), - $i - ); - $serverName = htmlspecialchars($serverName); - - list($blowfishSecret, $blowfishSecretSet) - = $this->performConfigChecksServersSetBlowfishSecret( - $blowfishSecret, - $cookieAuthServer, - $blowfishSecretSet - ); - - // - // $cfg['Servers'][$i]['ssl'] - // should be enabled if possible - // - if (! $this->cfg->getValue("Servers/$i/ssl")) { - $title = Descriptions::get('Servers/1/ssl') . " ($serverName)"; - SetupIndex::messagesSet( - 'notice', - "Servers/$i/ssl", - $title, - __( - 'You should use SSL connections if your database server ' - . 'supports it.' - ) - ); - } - $sSecurityInfoMsg = Sanitize::sanitizeMessage(sprintf( - __( - 'If you feel this is necessary, use additional protection settings - ' - . '%1$shost authentication%2$s settings and %3$strusted proxies list%4%s. ' - . 'However, IP-based protection may not be reliable if your IP belongs ' - . 'to an ISP where thousands of users, including you, are connected to.' - ), - '[a@' . Url::getCommon(['page' => 'servers', 'mode' => 'edit', 'id' => $i]) . '#tab_Server_config]', - '[/a]', - '[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]', - '[/a]' - )); - - // - // $cfg['Servers'][$i]['auth_type'] - // warn about full user credentials if 'auth_type' is 'config' - // - if ($this->cfg->getValue("Servers/$i/auth_type") == 'config' - && $this->cfg->getValue("Servers/$i/user") != '' - && $this->cfg->getValue("Servers/$i/password") != '' - ) { - $title = Descriptions::get('Servers/1/auth_type') - . " ($serverName)"; - SetupIndex::messagesSet( - 'notice', - "Servers/$i/auth_type", - $title, - Sanitize::sanitizeMessage(sprintf( - __( - 'You set the [kbd]config[/kbd] authentication type and included ' - . 'username and password for auto-login, which is not a desirable ' - . 'option for live hosts. Anyone who knows or guesses your phpMyAdmin ' - . 'URL can directly access your phpMyAdmin panel. Set %1$sauthentication ' - . 'type%2$s to [kbd]cookie[/kbd] or [kbd]http[/kbd].' - ), - '[a@' . Url::getCommon(['page' => 'servers', 'mode' => 'edit', 'id' => $i]) . '#tab_Server]', - '[/a]' - )) - . ' ' . $sSecurityInfoMsg - ); - } - - // - // $cfg['Servers'][$i]['AllowRoot'] - // $cfg['Servers'][$i]['AllowNoPassword'] - // serious security flaw - // - if ($this->cfg->getValue("Servers/$i/AllowRoot") - && $this->cfg->getValue("Servers/$i/AllowNoPassword") - ) { - $title = Descriptions::get('Servers/1/AllowNoPassword') - . " ($serverName)"; - SetupIndex::messagesSet( - 'notice', - "Servers/$i/AllowNoPassword", - $title, - __('You allow for connecting to the server without a password.') - . ' ' . $sSecurityInfoMsg - ); - } - } - return [ - $cookieAuthUsed, - $blowfishSecret, - $blowfishSecretSet, - ]; - } - - /** - * Set blowfish secret - * - * @param string $blowfishSecret Blowfish secret - * @param boolean $cookieAuthServer Cookie auth is used - * @param boolean $blowfishSecretSet Blowfish secret set - * - * @return array - */ - protected function performConfigChecksServersSetBlowfishSecret( - $blowfishSecret, - $cookieAuthServer, - $blowfishSecretSet - ) { - if ($cookieAuthServer && $blowfishSecret === null) { - $blowfishSecretSet = true; - $this->cfg->set('blowfish_secret', Util::generateRandom(32)); - } - return [ - $blowfishSecret, - $blowfishSecretSet, - ]; - } - - /** - * Define server name - * - * @param string $serverName Server name - * @param int $serverId Server id - * - * @return string Server name - */ - protected function performConfigChecksServersGetServerName( - $serverName, - $serverId - ) { - if ($serverName == 'localhost') { - $serverName .= " [$serverId]"; - return $serverName; - } - return $serverName; - } - - /** - * Perform config checks for zip part. - * - * @return void - */ - protected function performConfigChecksZips() - { - $this->performConfigChecksServerGZipdump(); - $this->performConfigChecksServerBZipdump(); - $this->performConfigChecksServersZipdump(); - } - - /** - * Perform config checks for zip part. - * - * @return void - */ - protected function performConfigChecksServersZipdump() - { - // - // $cfg['ZipDump'] - // requires zip_open in import - // - if ($this->cfg->getValue('ZipDump') && ! $this->functionExists('zip_open')) { - SetupIndex::messagesSet( - 'error', - 'ZipDump_import', - Descriptions::get('ZipDump'), - Sanitize::sanitizeMessage(sprintf( - __( - '%sZip decompression%s requires functions (%s) which are unavailable ' - . 'on this system.' - ), - '[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Import_export]', - '[/a]', - 'zip_open' - )) - ); - } - - // - // $cfg['ZipDump'] - // requires gzcompress in export - // - if ($this->cfg->getValue('ZipDump') && ! $this->functionExists('gzcompress')) { - SetupIndex::messagesSet( - 'error', - 'ZipDump_export', - Descriptions::get('ZipDump'), - Sanitize::sanitizeMessage(sprintf( - __( - '%sZip compression%s requires functions (%s) which are unavailable on ' - . 'this system.' - ), - '[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Import_export]', - '[/a]', - 'gzcompress' - )) - ); - } - } - - /** - * Check config of servers - * - * @param boolean $cookieAuthUsed Cookie auth is used - * @param boolean $blowfishSecretSet Blowfish secret set - * @param string $blowfishSecret Blowfish secret - * - * @return void - */ - protected function performConfigChecksCookieAuthUsed( - $cookieAuthUsed, - $blowfishSecretSet, - $blowfishSecret - ) { - // - // $cfg['blowfish_secret'] - // it's required for 'cookie' authentication - // - if ($cookieAuthUsed) { - if ($blowfishSecretSet) { - // 'cookie' auth used, blowfish_secret was generated - SetupIndex::messagesSet( - 'notice', - 'blowfish_secret_created', - Descriptions::get('blowfish_secret'), - Sanitize::sanitizeMessage(__( - 'You didn\'t have blowfish secret set and have enabled ' - . '[kbd]cookie[/kbd] authentication, so a key was automatically ' - . 'generated for you. It is used to encrypt cookies; you don\'t need to ' - . 'remember it.' - )) - ); - } else { - $blowfishWarnings = []; - // check length - if (strlen($blowfishSecret) < 32) { - // too short key - $blowfishWarnings[] = __( - 'Key is too short, it should have at least 32 characters.' - ); - } - // check used characters - $hasDigits = (bool) preg_match('/\d/', $blowfishSecret); - $hasChars = (bool) preg_match('/\S/', $blowfishSecret); - $hasNonword = (bool) preg_match('/\W/', $blowfishSecret); - if (! $hasDigits || ! $hasChars || ! $hasNonword) { - $blowfishWarnings[] = Sanitize::sanitizeMessage( - __( - 'Key should contain letters, numbers [em]and[/em] ' - . 'special characters.' - ) - ); - } - if (! empty($blowfishWarnings)) { - SetupIndex::messagesSet( - 'error', - 'blowfish_warnings' . count($blowfishWarnings), - Descriptions::get('blowfish_secret'), - implode('
', $blowfishWarnings) - ); - } - } - } - } - - /** - * Check configuration for login cookie - * - * @return void - */ - protected function performConfigChecksLoginCookie() - { - // - // $cfg['LoginCookieValidity'] - // value greater than session.gc_maxlifetime will cause - // random session invalidation after that time - $loginCookieValidity = $this->cfg->getValue('LoginCookieValidity'); - if ($loginCookieValidity > ini_get('session.gc_maxlifetime') - ) { - SetupIndex::messagesSet( - 'error', - 'LoginCookieValidity', - Descriptions::get('LoginCookieValidity'), - Sanitize::sanitizeMessage(sprintf( - __( - '%1$sLogin cookie validity%2$s greater than %3$ssession.gc_maxlifetime%4$s may ' - . 'cause random session invalidation (currently session.gc_maxlifetime ' - . 'is %5$d).' - ), - '[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]', - '[/a]', - '[a@' . Core::getPHPDocLink('session.configuration.php#ini.session.gc-maxlifetime') . ']', - '[/a]', - ini_get('session.gc_maxlifetime') - )) - ); - } - - // - // $cfg['LoginCookieValidity'] - // should be at most 1800 (30 min) - // - if ($loginCookieValidity > 1800) { - SetupIndex::messagesSet( - 'notice', - 'LoginCookieValidity', - Descriptions::get('LoginCookieValidity'), - Sanitize::sanitizeMessage(sprintf( - __( - '%sLogin cookie validity%s should be set to 1800 seconds (30 minutes) ' - . 'at most. Values larger than 1800 may pose a security risk such as ' - . 'impersonation.' - ), - '[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]', - '[/a]' - )) - ); - } - - // - // $cfg['LoginCookieValidity'] - // $cfg['LoginCookieStore'] - // LoginCookieValidity must be less or equal to LoginCookieStore - // - if (($this->cfg->getValue('LoginCookieStore') != 0) - && ($loginCookieValidity > $this->cfg->getValue('LoginCookieStore')) - ) { - SetupIndex::messagesSet( - 'error', - 'LoginCookieValidity', - Descriptions::get('LoginCookieValidity'), - Sanitize::sanitizeMessage(sprintf( - __( - 'If using [kbd]cookie[/kbd] authentication and %sLogin cookie store%s ' - . 'is not 0, %sLogin cookie validity%s must be set to a value less or ' - . 'equal to it.' - ), - '[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]', - '[/a]', - '[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Security]', - '[/a]' - )) - ); - } - } - - /** - * Check GZipDump configuration - * - * @return void - */ - protected function performConfigChecksServerBZipdump() - { - // - // $cfg['BZipDump'] - // requires bzip2 functions - // - if ($this->cfg->getValue('BZipDump') - && (! $this->functionExists('bzopen') || ! $this->functionExists('bzcompress')) - ) { - $functions = $this->functionExists('bzopen') - ? '' : - 'bzopen'; - $functions .= $this->functionExists('bzcompress') - ? '' - : ($functions ? ', ' : '') . 'bzcompress'; - SetupIndex::messagesSet( - 'error', - 'BZipDump', - Descriptions::get('BZipDump'), - Sanitize::sanitizeMessage( - sprintf( - __( - '%1$sBzip2 compression and decompression%2$s requires functions (%3$s) which ' - . 'are unavailable on this system.' - ), - '[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Import_export]', - '[/a]', - $functions - ) - ) - ); - } - } - - /** - * Check GZipDump configuration - * - * @return void - */ - protected function performConfigChecksServerGZipdump() - { - // - // $cfg['GZipDump'] - // requires zlib functions - // - if ($this->cfg->getValue('GZipDump') - && (! $this->functionExists('gzopen') || ! $this->functionExists('gzencode')) - ) { - SetupIndex::messagesSet( - 'error', - 'GZipDump', - Descriptions::get('GZipDump'), - Sanitize::sanitizeMessage(sprintf( - __( - '%1$sGZip compression and decompression%2$s requires functions (%3$s) which ' - . 'are unavailable on this system.' - ), - '[a@' . Url::getCommon(['page' => 'form', 'formset' => 'Features']) . '#tab_Import_export]', - '[/a]', - 'gzencode' - )) - ); - } - } - - /** - * Wrapper around function_exists to allow mock in test - * - * @param string $name Function name - * - * @return boolean - */ - protected function functionExists($name) - { - return function_exists($name); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/SpecialSchemaLinks.php b/srcs/phpmyadmin/libraries/classes/Config/SpecialSchemaLinks.php deleted file mode 100644 index e0af136..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/SpecialSchemaLinks.php +++ /dev/null @@ -1,478 +0,0 @@ - array( - * // Table name - * 'db' => array( - * // Column name - * 'user' => array( - * // Main url param (can be an array where represent sql) - * 'link_param' => 'username', - * // Other url params - * 'link_dependancy_params' => array( - * 0 => array( - * // URL parameter name - * // (can be array where url param has static value) - * 'param_info' => 'hostname', - * // Column name related to url param - * 'column_name' => 'host' - * ) - * ), - * // Page to link - * 'default_page' => './server_privileges.php' - * ) - * ) - * ) - * ); - * - * @return array - */ - public static function get(): array - { - global $cfg; - - $defaultPage = './' . Util::getScriptNameForOption( - $cfg['DefaultTabTable'], - 'table' - ); - - return [ - 'mysql' => [ - 'columns_priv' => [ - 'user' => [ - 'link_param' => 'username', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'hostname', - 'column_name' => 'host', - ], - ], - 'default_page' => './server_privileges.php', - ], - 'table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'Db', - ], - ], - 'default_page' => $defaultPage, - ], - 'column_name' => [ - 'link_param' => 'field', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'Db', - ], - 1 => [ - 'param_info' => 'table', - 'column_name' => 'Table_name', - ], - ], - 'default_page' => './tbl_structure.php?change_column=1', - ], - ], - 'db' => [ - 'user' => [ - 'link_param' => 'username', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'hostname', - 'column_name' => 'host', - ], - ], - 'default_page' => './server_privileges.php', - ], - ], - 'event' => [ - 'name' => [ - 'link_param' => 'item_name', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'db', - ], - ], - 'default_page' => './db_events.php?edit_item=1', - ], - - ], - 'innodb_index_stats' => [ - 'table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'database_name', - ], - ], - 'default_page' => $defaultPage, - ], - 'index_name' => [ - 'link_param' => 'index', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'database_name', - ], - 1 => [ - 'param_info' => 'table', - 'column_name' => 'table_name', - ], - ], - 'default_page' => './tbl_structure.php', - ], - ], - 'innodb_table_stats' => [ - 'table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'database_name', - ], - ], - 'default_page' => $defaultPage, - ], - ], - 'proc' => [ - 'name' => [ - 'link_param' => 'item_name', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'db', - ], - 1 => [ - 'param_info' => 'item_type', - 'column_name' => 'type', - ], - ], - 'default_page' => './db_routines.php?edit_item=1', - ], - 'specific_name' => [ - 'link_param' => 'item_name', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'db', - ], - 1 => [ - 'param_info' => 'item_type', - 'column_name' => 'type', - ], - ], - 'default_page' => './db_routines.php?edit_item=1', - ], - ], - 'proc_priv' => [ - 'user' => [ - 'link_param' => 'username', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'hostname', - 'column_name' => 'Host', - ], - ], - 'default_page' => './server_privileges.php', - ], - 'routine_name' => [ - 'link_param' => 'item_name', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'Db', - ], - 1 => [ - 'param_info' => 'item_type', - 'column_name' => 'Routine_type', - ], - ], - 'default_page' => './db_routines.php?edit_item=1', - ], - ], - 'proxies_priv' => [ - 'user' => [ - 'link_param' => 'username', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'hostname', - 'column_name' => 'Host', - ], - ], - 'default_page' => './server_privileges.php', - ], - ], - 'tables_priv' => [ - 'user' => [ - 'link_param' => 'username', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'hostname', - 'column_name' => 'Host', - ], - ], - 'default_page' => './server_privileges.php', - ], - 'table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'Db', - ], - ], - 'default_page' => $defaultPage, - ], - ], - 'user' => [ - 'user' => [ - 'link_param' => 'username', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'hostname', - 'column_name' => 'host', - ], - ], - 'default_page' => './server_privileges.php', - ], - ], - ], - 'information_schema' => [ - 'columns' => [ - 'table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'table_schema', - ], - ], - 'default_page' => $defaultPage, - ], - 'column_name' => [ - 'link_param' => 'field', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'table_schema', - ], - 1 => [ - 'param_info' => 'table', - 'column_name' => 'table_name', - ], - ], - 'default_page' => './tbl_structure.php?change_column=1', - ], - ], - 'key_column_usage' => [ - 'table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'constraint_schema', - ], - ], - 'default_page' => $defaultPage, - ], - 'column_name' => [ - 'link_param' => 'field', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'table_schema', - ], - 1 => [ - 'param_info' => 'table', - 'column_name' => 'table_name', - ], - ], - 'default_page' => './tbl_structure.php?change_column=1', - ], - 'referenced_table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'referenced_table_schema', - ], - ], - 'default_page' => $defaultPage, - ], - 'referenced_column_name' => [ - 'link_param' => 'field', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'referenced_table_schema', - ], - 1 => [ - 'param_info' => 'table', - 'column_name' => 'referenced_table_name', - ], - ], - 'default_page' => './tbl_structure.php?change_column=1', - ], - ], - 'partitions' => [ - 'table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'table_schema', - ], - ], - 'default_page' => $defaultPage, - ], - ], - 'processlist' => [ - 'user' => [ - 'link_param' => 'username', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'hostname', - 'column_name' => 'host', - ], - ], - 'default_page' => './server_privileges.php', - ], - ], - 'referential_constraints' => [ - 'table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'constraint_schema', - ], - ], - 'default_page' => $defaultPage, - ], - 'referenced_table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'constraint_schema', - ], - ], - 'default_page' => $defaultPage, - ], - ], - 'routines' => [ - 'routine_name' => [ - 'link_param' => 'item_name', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'routine_schema', - ], - 1 => [ - 'param_info' => 'item_type', - 'column_name' => 'routine_type', - ], - ], - 'default_page' => './db_routines.php', - ], - ], - 'schemata' => [ - 'schema_name' => [ - 'link_param' => 'db', - 'default_page' => $defaultPage, - ], - ], - 'statistics' => [ - 'table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'table_schema', - ], - ], - 'default_page' => $defaultPage, - ], - 'column_name' => [ - 'link_param' => 'field', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'table_schema', - ], - 1 => [ - 'param_info' => 'table', - 'column_name' => 'table_name', - ], - ], - 'default_page' => './tbl_structure.php?change_column=1', - ], - ], - 'tables' => [ - 'table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'table_schema', - ], - ], - 'default_page' => $defaultPage, - ], - ], - 'table_constraints' => [ - 'table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'table_schema', - ], - ], - 'default_page' => $defaultPage, - ], - ], - 'views' => [ - 'table_name' => [ - 'link_param' => 'table', - 'link_dependancy_params' => [ - 0 => [ - 'param_info' => 'db', - 'column_name' => 'table_schema', - ], - ], - 'default_page' => $defaultPage, - ], - ], - ], - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Config/Validator.php b/srcs/phpmyadmin/libraries/classes/Config/Validator.php deleted file mode 100644 index 8294a90..0000000 --- a/srcs/phpmyadmin/libraries/classes/Config/Validator.php +++ /dev/null @@ -1,594 +0,0 @@ -getDbEntry('_validators', []); - if ($GLOBALS['PMA_Config']->get('is_setup')) { - return $validators; - } - - // not in setup script: load additional validators for user - // preferences we need original config values not overwritten - // by user preferences, creating a new PhpMyAdmin\Config instance is a - // better idea than hacking into its code - $uvs = $cf->getDbEntry('_userValidators', []); - foreach ($uvs as $field => $uvList) { - $uvList = (array) $uvList; - foreach ($uvList as &$uv) { - if (! is_array($uv)) { - continue; - } - for ($i = 1, $nb = count($uv); $i < $nb; $i++) { - if (mb_substr($uv[$i], 0, 6) == 'value:') { - $uv[$i] = Core::arrayRead( - mb_substr($uv[$i], 6), - $GLOBALS['PMA_Config']->base_settings - ); - } - } - } - $validators[$field] = isset($validators[$field]) - ? array_merge((array) $validators[$field], $uvList) - : $uvList; - } - 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 document - * o false - when no validators match name(s) given by $validator_id - * - * @param ConfigFile $cf Config file instance - * @param string|array $validatorId 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 - */ - public static function validate( - ConfigFile $cf, - $validatorId, - array &$values, - $isPostSource - ) { - // find validators - $validatorId = (array) $validatorId; - $validators = static::getValidators($cf); - $vids = []; - foreach ($validatorId 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 = []; - $keyMap = []; - foreach ($values as $k => $v) { - $k2 = $isPostSource ? str_replace('-', '/', $k) : $k; - $k2 = mb_strpos($k2, '/') - ? $cf->getCanonicalPath($k2) - : $k2; - $keyMap[$k2] = $k; - $arguments[$k2] = $v; - } - - // validate - $result = []; - foreach ($vids as $vid) { - // call appropriate validation functions - foreach ((array) $validators[$vid] as $validator) { - $vdef = (array) $validator; - $vname = array_shift($vdef); - $vname = 'PhpMyAdmin\Config\Validator::' . $vname; - $args = array_merge([$vid, &$arguments], $vdef); - $r = call_user_func_array($vname, $args); - - // merge results - if (! is_array($r)) { - continue; - } - - foreach ($r as $key => $errorList) { - // skip empty values if $isPostSource is false - if (! $isPostSource && empty($errorList)) { - continue; - } - if (! isset($result[$key])) { - $result[$key] = []; - } - $result[$key] = array_merge( - $result[$key], - (array) $errorList - ); - } - } - } - - // restore original paths - $newResult = []; - foreach ($result as $k => $v) { - $k2 = isset($keyMap[$k]) ? $keyMap[$k] : $k; - if (is_array($v)) { - $newResult[$k2] = array_map('htmlspecialchars', $v); - } else { - $newResult[$k2] = htmlspecialchars($v); - } - } - return empty($newResult) ? true : $newResult; - } - - /** - * Test database connection - * - * @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 $errorKey key to use in return array - * - * @return bool|array - */ - public static function testDBConnection( - $host, - $port, - $socket, - $user, - $pass = null, - $errorKey = 'Server' - ) { - if ($GLOBALS['cfg']['DBG']['demo']) { - // Connection test disabled on the demo server! - return true; - } - - $error = null; - $host = Core::sanitizeMySQLHost($host); - - error_clear_last(); - - if (DatabaseInterface::checkDbExtension('mysqli')) { - $socket = empty($socket) ? null : $socket; - $port = empty($port) ? null : $port; - $extension = 'mysqli'; - } else { - $socket = empty($socket) ? null : ':' . ($socket[0] == '/' ? '' : '/') . $socket; - $port = empty($port) ? null : ':' . $port; - $extension = 'mysql'; - } - - if ($extension == 'mysql') { - $conn = @mysql_connect($host . $port . $socket, $user, $pass); - if (! $conn) { - $error = __('Could not connect to the database server!'); - } else { - mysql_close($conn); - } - } else { - $conn = @mysqli_connect($host, $user, $pass, null, $port, $socket); - if (! $conn) { - $error = __('Could not connect to the database server!'); - } else { - mysqli_close($conn); - } - } - if ($error !== null) { - $lastError = error_get_last(); - if ($lastError !== null) { - $error .= ' - ' . $lastError['message']; - } - } - return $error === null ? true : [$errorKey => $error]; - } - - /** - * Validate server config - * - * @param string $path path to config, not used - * keep this parameter since the method is invoked using - * reflection along with other similar methods - * @param array $values config values - * - * @return array - */ - public static function validateServer($path, array $values) - { - $result = [ - 'Server' => '', - 'Servers/1/user' => '', - 'Servers/1/SignonSession' => '', - 'Servers/1/SignonURL' => '', - ]; - $error = false; - if (empty($values['Servers/1/auth_type'])) { - $values['Servers/1/auth_type'] = ''; - $result['Servers/1/auth_type'] = __('Invalid authentication type!'); - $error = true; - } - if ($values['Servers/1/auth_type'] == 'config' - && empty($values['Servers/1/user']) - ) { - $result['Servers/1/user'] = __( - 'Empty username while using [kbd]config[/kbd] 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 [kbd]signon[/kbd] 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 [kbd]signon[/kbd] authentication ' - . 'method!' - ); - $error = true; - } - - if (! $error && $values['Servers/1/auth_type'] == 'config') { - $password = ''; - if (! empty($values['Servers/1/password'])) { - $password = $values['Servers/1/password']; - } - $test = static::testDBConnection( - empty($values['Servers/1/host']) ? '' : $values['Servers/1/host'], - empty($values['Servers/1/port']) ? '' : $values['Servers/1/port'], - empty($values['Servers/1/socket']) ? '' : $values['Servers/1/socket'], - empty($values['Servers/1/user']) ? '' : $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 - * keep this parameter since the method is invoked using - * reflection along with other similar methods - * @param array $values config values - * - * @return array - */ - public static function validatePMAStorage($path, array $values) - { - $result = [ - 'Server_pmadb' => '', - 'Servers/1/controluser' => '', - 'Servers/1/controlpass' => '', - ]; - $error = false; - - if (empty($values['Servers/1/pmadb'])) { - return $result; - } - - $result = []; - if (empty($values['Servers/1/controluser'])) { - $result['Servers/1/controluser'] = __( - 'Empty phpMyAdmin control user while using phpMyAdmin configuration ' - . 'storage!' - ); - $error = true; - } - if (empty($values['Servers/1/controlpass'])) { - $result['Servers/1/controlpass'] = __( - 'Empty phpMyAdmin control user password while using phpMyAdmin ' - . 'configuration storage!' - ); - $error = true; - } - if (! $error) { - $test = static::testDBConnection( - empty($values['Servers/1/host']) ? '' : $values['Servers/1/host'], - empty($values['Servers/1/port']) ? '' : $values['Servers/1/port'], - empty($values['Servers/1/socket']) ? '' : $values['Servers/1/socket'], - empty($values['Servers/1/controluser']) ? '' : $values['Servers/1/controluser'], - empty($values['Servers/1/controlpass']) ? '' : $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 - */ - public static function validateRegex($path, array $values) - { - $result = [$path => '']; - - if (empty($values[$path])) { - return $result; - } - - error_clear_last(); - - $matches = []; - // in libraries/ListDatabase.php _checkHideDatabase(), - // a '/' is used as the delimiter for hide_db - @preg_match('/' . Util::requestString($values[$path]) . '/', '', $matches); - - $currentError = error_get_last(); - - if ($currentError !== null) { - $error = preg_replace('/^preg_match\(\): /', '', $currentError['message']); - return [$path => $error]; - } - - return $result; - } - - /** - * Validates TrustedProxies field - * - * @param string $path path to config - * @param array $values config values - * - * @return array - */ - public static function validateTrustedProxies($path, array $values) - { - $result = [$path => []]; - - if (empty($values[$path])) { - return $result; - } - - if (is_array($values[$path]) || is_object($values[$path])) { - // value already processed by FormDisplay::save - $lines = []; - foreach ($values[$path] as $ip => $v) { - $v = Util::requestString($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 = []; - // we catch anything that may (or may not) be an IP - if (! preg_match("/^(.+):(?:[ ]?)\\w+$/", $line, $matches)) { - $result[$path][] = __('Incorrect value:') . ' ' - . htmlspecialchars($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 $allowNegative allow negative values - * @param bool $allowZero allow zero - * @param int $maxValue max allowed value - * @param string $errorString error message string - * - * @return string empty string if test is successful - */ - public static function validateNumber( - $path, - array $values, - $allowNegative, - $allowZero, - $maxValue, - $errorString - ) { - if (empty($values[$path])) { - return ''; - } - - $value = Util::requestString($values[$path]); - - if (intval($value) != $value - || (! $allowNegative && $value < 0) - || (! $allowZero && $value == 0) - || $value > $maxValue - ) { - return $errorString; - } - - return ''; - } - - /** - * Validates port number - * - * @param string $path path to config - * @param array $values config values - * - * @return array - */ - public static function validatePortNumber($path, array $values) - { - return [ - $path => static::validateNumber( - $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 - */ - public static function validatePositiveNumber($path, array $values) - { - return [ - $path => static::validateNumber( - $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 - */ - public static function validateNonNegativeNumber($path, array $values) - { - return [ - $path => static::validateNumber( - $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 regular expression to match - * - * @return array|string - */ - public static function validateByRegex($path, array $values, $regex) - { - if (! isset($values[$path])) { - return ''; - } - $result = preg_match($regex, Util::requestString($values[$path])); - return [$path => $result ? '' : __('Incorrect value!')]; - } - - /** - * Validates upper bound for numeric inputs - * - * @param string $path path to config - * @param array $values config values - * @param int $maxValue maximal allowed value - * - * @return array - */ - public static function validateUpperBound($path, array $values, $maxValue) - { - $result = $values[$path] <= $maxValue; - return [ - $path => $result ? '' : sprintf( - __('Value must be less than or equal to %s!'), - $maxValue - ), - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Console.php b/srcs/phpmyadmin/libraries/classes/Console.php deleted file mode 100644 index 50ac77a..0000000 --- a/srcs/phpmyadmin/libraries/classes/Console.php +++ /dev/null @@ -1,158 +0,0 @@ -_isEnabled = true; - $this->relation = new Relation($GLOBALS['dbi']); - $this->template = new Template(); - } - - /** - * Set the ajax flag to indicate whether - * we are servicing an ajax request - * - * @param bool $isAjax Whether we are servicing an ajax request - * - * @return void - */ - public function setAjax(bool $isAjax): void - { - $this->_isAjax = $isAjax; - } - - /** - * Disables the rendering of the footer - * - * @return void - */ - public function disable(): void - { - $this->_isEnabled = false; - } - - /** - * Renders the bookmark content - * - * @access public - * @return string - */ - public static function getBookmarkContent(): string - { - $template = new Template(); - $cfgBookmark = Bookmark::getParams($GLOBALS['cfg']['Server']['user']); - if ($cfgBookmark) { - $bookmarks = Bookmark::getList( - $GLOBALS['dbi'], - $GLOBALS['cfg']['Server']['user'] - ); - $count_bookmarks = count($bookmarks); - if ($count_bookmarks > 0) { - $welcomeMessage = sprintf( - _ngettext( - 'Showing %1$d bookmark (both private and shared)', - 'Showing %1$d bookmarks (both private and shared)', - $count_bookmarks - ), - $count_bookmarks - ); - } else { - $welcomeMessage = __('No bookmarks'); - } - unset($count_bookmarks, $private_message, $shared_message); - return $template->render('console/bookmark_content', [ - 'welcome_message' => $welcomeMessage, - 'bookmarks' => $bookmarks, - ]); - } - return ''; - } - - /** - * Returns the list of JS scripts required by console - * - * @return array list of scripts - */ - public function getScripts(): array - { - return ['console.js']; - } - - /** - * Renders the console - * - * @access public - * @return string - */ - public function getDisplay(): string - { - if ((! $this->_isAjax) && $this->_isEnabled) { - $cfgBookmark = Bookmark::getParams( - $GLOBALS['cfg']['Server']['user'] - ); - - $image = Util::getImage('console', __('SQL Query Console')); - $_sql_history = $this->relation->getHistory( - $GLOBALS['cfg']['Server']['user'] - ); - $bookmarkContent = static::getBookmarkContent(); - - return $this->template->render('console/display', [ - 'cfg_bookmark' => $cfgBookmark, - 'image' => $image, - 'sql_history' => $_sql_history, - 'bookmark_content' => $bookmarkContent, - ]); - } - return ''; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/AbstractController.php b/srcs/phpmyadmin/libraries/classes/Controllers/AbstractController.php deleted file mode 100644 index 601e79f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/AbstractController.php +++ /dev/null @@ -1,51 +0,0 @@ -response = $response; - $this->dbi = $dbi; - $this->template = $template; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/AjaxController.php b/srcs/phpmyadmin/libraries/classes/Controllers/AjaxController.php deleted file mode 100644 index 0662277..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/AjaxController.php +++ /dev/null @@ -1,97 +0,0 @@ -config = $config; - } - - /** - * @return array JSON - */ - public function databases(): array - { - global $dblist; - - return ['databases' => $dblist->databases]; - } - - /** - * @param array $params Request parameters - * @return array JSON - */ - public function tables(array $params): array - { - return ['tables' => $this->dbi->getTables($params['db'])]; - } - - /** - * @param array $params Request parameters - * @return array JSON - */ - public function columns(array $params): array - { - return [ - 'columns' => $this->dbi->getColumnNames( - $params['db'], - $params['table'] - ), - ]; - } - - /** - * @param array $params Request parameters - * @return array JSON - */ - public function getConfig(array $params): array - { - return ['value' => $this->config->get($params['key'])]; - } - - /** - * @param array $params Request parameters - * @return true|Message - */ - public function setConfig(array $params) - { - return $this->config->setUserValue( - null, - $params['key'], - json_decode($params['value']) - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/BrowseForeignersController.php b/srcs/phpmyadmin/libraries/classes/Controllers/BrowseForeignersController.php deleted file mode 100644 index 24441cd..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/BrowseForeignersController.php +++ /dev/null @@ -1,82 +0,0 @@ -browseForeigners = $browseForeigners; - $this->relation = $relation; - } - - /** - * @param array $params Request parameters - * @return string HTML - */ - public function index(array $params): string - { - $foreigners = $this->relation->getForeigners( - $params['db'], - $params['table'] - ); - $foreignLimit = $this->browseForeigners->getForeignLimit( - $params['foreign_showAll'] - ); - $foreignData = $this->relation->getForeignData( - $foreigners, - $params['field'], - true, - $params['foreign_filter'] ?? '', - $foreignLimit ?? null, - true - ); - - return $this->browseForeigners->getHtmlForRelationalFieldSelection( - $params['db'], - $params['table'], - $params['field'], - $foreignData, - $params['fieldkey'] ?? '', - $params['data'] ?? '' - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Database/AbstractController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Database/AbstractController.php deleted file mode 100644 index 31b752b..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Database/AbstractController.php +++ /dev/null @@ -1,42 +0,0 @@ -db = $db; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Database/CentralColumnsController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Database/CentralColumnsController.php deleted file mode 100644 index 97798ea..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Database/CentralColumnsController.php +++ /dev/null @@ -1,195 +0,0 @@ -centralColumns = $centralColumns; - } - - /** - * @param array $params Request parameters - * @return string HTML - */ - public function index(array $params): string - { - global $pmaThemeImage, $text_dir; - - if (! empty($params['total_rows']) - && Core::isValid($params['total_rows'], 'integer') - ) { - $totalRows = (int) $params['total_rows']; - } else { - $totalRows = $this->centralColumns->getCount($this->db); - } - - $pos = 0; - if (Core::isValid($params['pos'], 'integer')) { - $pos = (int) $params['pos']; - } - - return $this->centralColumns->getHtmlForMain( - $this->db, - $totalRows, - $pos, - $pmaThemeImage, - $text_dir - ); - } - - /** - * @param array $params Request parameters - * @return array JSON - */ - public function getColumnList(array $params): array - { - return $this->centralColumns->getListRaw( - $this->db, - $params['cur_table'] ?? '' - ); - } - - /** - * @param array $params Request parameters - * @return string HTML - */ - public function populateColumns(array $params): string - { - return $this->centralColumns->getHtmlForColumnDropdown( - $this->db, - $params['selectedTable'] - ); - } - - /** - * @param array $params Request parameters - * @return true|Message - */ - public function editSave(array $params) - { - $columnDefault = $params['col_default']; - if ($columnDefault === 'NONE' && $params['col_default_sel'] !== 'USER_DEFINED') { - $columnDefault = ''; - } - return $this->centralColumns->updateOneColumn( - $this->db, - $params['orig_col_name'], - $params['col_name'], - $params['col_type'], - $params['col_attribute'], - $params['col_length'], - isset($params['col_isNull']) ? 1 : 0, - $params['collation'], - $params['col_extra'] ?? '', - $columnDefault - ); - } - - /** - * @param array $params Request parameters - * @return true|Message - */ - public function addNewColumn(array $params) - { - $columnDefault = $params['col_default']; - if ($columnDefault === 'NONE' && $params['col_default_sel'] !== 'USER_DEFINED') { - $columnDefault = ''; - } - return $this->centralColumns->updateOneColumn( - $this->db, - '', - $params['col_name'], - $params['col_type'], - $params['col_attribute'], - $params['col_length'], - isset($params['col_isNull']) ? 1 : 0, - $params['collation'], - $params['col_extra'] ?? '', - $columnDefault - ); - } - - /** - * @param array $params Request parameters - * @return true|Message - */ - public function addColumn(array $params) - { - return $this->centralColumns->syncUniqueColumns( - [$params['column-select']], - false, - $params['table-select'] - ); - } - - /** - * @param array $params Request parameters - * @return string HTML - */ - public function editPage(array $params): string - { - return $this->centralColumns->getHtmlForEditingPage( - $params['selected_fld'], - $params['db'] - ); - } - - /** - * @param array $params Request parameters - * @return true|Message - */ - public function updateMultipleColumn(array $params) - { - return $this->centralColumns->updateMultipleColumn($params); - } - - /** - * @param array $params Request parameters - * @return true|Message - */ - public function deleteSave(array $params) - { - $name = []; - parse_str($params['col_name'], $name); - return $this->centralColumns->deleteColumnsFromList( - $params['db'], - $name['selected_fld'], - false - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Database/DataDictionaryController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Database/DataDictionaryController.php deleted file mode 100644 index ba424b6..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Database/DataDictionaryController.php +++ /dev/null @@ -1,156 +0,0 @@ -relation = $relation; - $this->transformations = $transformations; - } - - /** - * @return string HTML - */ - public function index(): string - { - $cfgRelation = $this->relation->getRelationsParam(); - - $comment = $this->relation->getDbComment($this->db); - - $this->dbi->selectDb($this->db); - $tablesNames = $this->dbi->getTables($this->db); - - $tables = []; - foreach ($tablesNames as $tableName) { - $showComment = (string) $this->dbi->getTable( - $this->db, - $tableName - )->getStatusInfo('TABLE_COMMENT'); - - list(, $primaryKeys, , ) = Util::processIndexData( - $this->dbi->getTableIndexes($this->db, $tableName) - ); - - list($foreigners, $hasRelation) = $this->relation->getRelationsAndStatus( - ! empty($cfgRelation['relation']), - $this->db, - $tableName - ); - - $columnsComments = $this->relation->getComments($this->db, $tableName); - - $columns = $this->dbi->getColumns($this->db, $tableName); - $rows = []; - foreach ($columns as $row) { - $extractedColumnSpec = Util::extractColumnSpec($row['Type']); - - $relation = ''; - if ($hasRelation) { - $foreigner = $this->relation->searchColumnInForeigners( - $foreigners, - $row['Field'] - ); - if ($foreigner !== false && $foreigner !== []) { - $relation = $foreigner['foreign_table']; - $relation .= ' -> '; - $relation .= $foreigner['foreign_field']; - } - } - - $mime = ''; - if ($cfgRelation['mimework']) { - $mimeMap = $this->transformations->getMime( - $this->db, - $tableName, - true - ); - if (isset($mimeMap[$row['Field']])) { - $mime = str_replace( - '_', - '/', - $mimeMap[$row['Field']]['mimetype'] - ); - } - } - - $rows[$row['Field']] = [ - 'name' => $row['Field'], - 'has_primary_key' => isset($primaryKeys[$row['Field']]), - 'type' => $extractedColumnSpec['type'], - 'print_type' => $extractedColumnSpec['print_type'], - 'is_nullable' => $row['Null'] !== '' && $row['Null'] !== 'NO', - 'default' => $row['Default'] ?? null, - 'comment' => $columnsComments[$row['Field']] ?? '', - 'mime' => $mime, - 'relation' => $relation, - ]; - } - - $indexesTable = ''; - if (count(Index::getFromTable($tableName, $this->db)) > 0) { - $indexesTable = Index::getHtmlForIndexes( - $tableName, - $this->db, - true - ); - } - - $tables[$tableName] = [ - 'name' => $tableName, - 'comment' => $showComment, - 'has_relation' => $hasRelation, - 'has_mime' => $cfgRelation['mimework'], - 'columns' => $rows, - 'indexes_table' => $indexesTable, - ]; - } - - return $this->template->render('database/data_dictionary/index', [ - 'database' => $this->db, - 'comment' => $comment, - 'tables' => $tables, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Database/EventsController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Database/EventsController.php deleted file mode 100644 index e2b0121..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Database/EventsController.php +++ /dev/null @@ -1,43 +0,0 @@ -dbi); - $events->main(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Database/MultiTableQueryController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Database/MultiTableQueryController.php deleted file mode 100644 index b4e1375..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Database/MultiTableQueryController.php +++ /dev/null @@ -1,61 +0,0 @@ -dbi, $template, $this->db); - - return $queryInstance->getFormHtml(); - } - - /** - * @param array $params Request parameters - * @return void - */ - public function displayResults(array $params): void - { - global $pmaThemeImage; - - MultiTableQuery::displayResults( - $params['sql_query'], - $params['db'], - $pmaThemeImage - ); - } - - /** - * @param array $params Request parameters - * @return array JSON - */ - public function table(array $params): array - { - $constrains = $this->dbi->getForeignKeyConstrains( - $params['db'], - $params['tables'] - ); - - return ['foreignKeyConstrains' => $constrains]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Database/RoutinesController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Database/RoutinesController.php deleted file mode 100644 index 4106ccc..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Database/RoutinesController.php +++ /dev/null @@ -1,44 +0,0 @@ -dbi); - $routines->main($params['type']); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Database/SqlController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Database/SqlController.php deleted file mode 100644 index 963f5bc..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Database/SqlController.php +++ /dev/null @@ -1,49 +0,0 @@ -getHtml( - true, - false, - isset($params['delimiter']) - ? htmlspecialchars($params['delimiter']) - : ';' - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Database/StructureController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Database/StructureController.php deleted file mode 100644 index 5407f19..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Database/StructureController.php +++ /dev/null @@ -1,1088 +0,0 @@ -relation = $relation; - $this->replication = $replication; - } - - /** - * Retrieves database information for further use - * - * @param string $subPart Page part name - * - * @return void - */ - private function getDatabaseInfo(string $subPart): void - { - list( - $tables, - $numTables, - $totalNumTables, - , - $isShowStats, - $dbIsSystemSchema, - , - , - $position - ) = Util::getDbInfo($this->db, $subPart); - - $this->tables = $tables; - $this->numTables = $numTables; - $this->position = $position; - $this->dbIsSystemSchema = $dbIsSystemSchema; - $this->totalNumTables = $totalNumTables; - $this->isShowStats = $isShowStats; - } - - /** - * Index action - * - * @param array $params Request parameters - * @return string HTML - */ - public function index(array $params): string - { - global $cfg; - - // Drops/deletes/etc. multiple tables if required - if ((! empty($params['submit_mult']) && isset($params['selected_tbl'])) - || isset($params['mult_btn']) - ) { - $this->multiSubmitAction(); - } - - // Gets the database structure - $this->getDatabaseInfo('_structure'); - - // Checks if there are any tables to be shown on current page. - // If there are no tables, the user is redirected to the last page - // having any. - if ($this->totalNumTables > 0 && $this->position > $this->totalNumTables) { - $uri = './db_structure.php' . Url::getCommonRaw([ - 'db' => $this->db, - 'pos' => max(0, $this->totalNumTables - $cfg['MaxTableList']), - 'reload' => 1, - ]); - Core::sendHeaderLocation($uri); - } - - include_once ROOT_PATH . 'libraries/replication.inc.php'; - - PageSettings::showGroup('DbStructure'); - - if ($this->numTables > 0) { - $urlParams = [ - 'pos' => $this->position, - 'db' => $this->db, - ]; - if (isset($params['sort'])) { - $urlParams['sort'] = $params['sort']; - } - if (isset($params['sort_order'])) { - $urlParams['sort_order'] = $params['sort_order']; - } - $listNavigator = Util::getListNavigator( - $this->totalNumTables, - $this->position, - $urlParams, - 'db_structure.php', - 'frame_content', - $cfg['MaxTableList'] - ); - - $tableList = $this->displayTableList(); - } - - $createTable = ''; - if (empty($this->dbIsSystemSchema)) { - $createTable = CreateTable::getHtml($this->db); - } - - return $this->template->render('database/structure/index', [ - 'database' => $this->db, - 'has_tables' => $this->numTables > 0, - 'list_navigator_html' => $listNavigator ?? '', - 'table_list_html' => $tableList ?? '', - 'is_system_schema' => ! empty($this->dbIsSystemSchema), - 'create_table_html' => $createTable, - ]); - } - - /** - * Add or remove favorite tables - * - * @param array $params Request parameters - * @return array|null JSON - */ - public function addRemoveFavoriteTablesAction(array $params): ?array - { - global $cfg; - - $favoriteInstance = RecentFavoriteTable::getInstance('favorite'); - if (isset($params['favoriteTables'])) { - $favoriteTables = json_decode($params['favoriteTables'], true); - } else { - $favoriteTables = []; - } - // Required to keep each user's preferences separate. - $user = sha1($cfg['Server']['user']); - - // Request for Synchronization of favorite tables. - if (isset($params['sync_favorite_tables'])) { - $cfgRelation = $this->relation->getRelationsParam(); - if ($cfgRelation['favoritework']) { - return $this->synchronizeFavoriteTables($favoriteInstance, $user, $favoriteTables); - } - return null; - } - $changes = true; - $titles = Util::buildActionTitles(); - $favoriteTable = $params['favorite_table']; - $alreadyFavorite = $this->checkFavoriteTable($favoriteTable); - - if (isset($params['remove_favorite'])) { - if ($alreadyFavorite) { - // If already in favorite list, remove it. - $favoriteInstance->remove($this->db, $favoriteTable); - $alreadyFavorite = false; // for favorite_anchor template - } - } elseif (isset($params['add_favorite'])) { - if (! $alreadyFavorite) { - $numTables = count($favoriteInstance->getTables()); - if ($numTables == $cfg['NumFavoriteTables']) { - $changes = false; - } else { - // Otherwise add to favorite list. - $favoriteInstance->add($this->db, $favoriteTable); - $alreadyFavorite = true; // for favorite_anchor template - } - } - } - - $favoriteTables[$user] = $favoriteInstance->getTables(); - - $json = []; - $json['changes'] = $changes; - if (! $changes) { - $json['message'] = $this->template->render('components/error_message', [ - 'msg' => __("Favorite List is full!"), - ]); - return $json; - } - // Check if current table is already in favorite list. - $favoriteParams = [ - 'db' => $this->db, - 'ajax_request' => true, - 'favorite_table' => $favoriteTable, - ($alreadyFavorite ? 'remove' : 'add') . '_favorite' => true, - ]; - - $json['user'] = $user; - $json['favoriteTables'] = json_encode($favoriteTables); - $json['list'] = $favoriteInstance->getHtmlList(); - $json['anchor'] = $this->template->render('database/structure/favorite_anchor', [ - 'table_name_hash' => md5($favoriteTable), - 'db_table_name_hash' => md5($this->db . "." . $favoriteTable), - 'fav_params' => $favoriteParams, - 'already_favorite' => $alreadyFavorite, - 'titles' => $titles, - ]); - - return $json; - } - - /** - * Handles request for real row count on database level view page. - * - * @param array $params Request parameters - * @return array JSON - */ - public function handleRealRowCountRequestAction(array $params): array - { - // If there is a request to update all table's row count. - if (! isset($params['real_row_count_all'])) { - // Get the real row count for the table. - $realRowCount = $this->dbi - ->getTable($this->db, (string) $params['table']) - ->getRealRowCountTable(); - // Format the number. - $realRowCount = Util::formatNumber($realRowCount, 0); - - return ['real_row_count' => $realRowCount]; - } - - // Array to store the results. - $realRowCountAll = []; - // Iterate over each table and fetch real row count. - foreach ($this->tables as $table) { - $rowCount = $this->dbi - ->getTable($this->db, $table['TABLE_NAME']) - ->getRealRowCountTable(); - $realRowCountAll[] = [ - 'table' => $table['TABLE_NAME'], - 'row_count' => $rowCount, - ]; - } - - return ['real_row_count_all' => json_encode($realRowCountAll)]; - } - - /** - * Handles actions related to multiple tables - * - * @return void - */ - public function multiSubmitAction(): void - { - $action = 'db_structure.php'; - $err_url = 'db_structure.php' . Url::getCommon( - ['db' => $this->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 ROOT_PATH . 'libraries/mult_submits.inc.php'; - } - if (empty($_POST['message'])) { - $_POST['message'] = Message::success(); - } - } - - /** - * Displays the list of tables - * - * @return string HTML - */ - protected function displayTableList(): string - { - $html = ''; - - // filtering - $html .= $this->template->render('filter', ['filter_value' => '']); - - $i = $sum_entries = 0; - $overhead_check = false; - $create_time_all = ''; - $update_time_all = ''; - $check_time_all = ''; - $num_columns = $GLOBALS['cfg']['PropertiesNumColumns'] > 1 - ? ceil($this->numTables / $GLOBALS['cfg']['PropertiesNumColumns']) + 1 - : 0; - $row_count = 0; - $sum_size = 0; - $overhead_size = 0; - - $hidden_fields = []; - $overall_approx_rows = false; - $structure_table_rows = []; - foreach ($this->tables as $keyname => $current_table) { - // Get valid statistics whatever is the table type - - $drop_query = ''; - $drop_message = ''; - $overhead = ''; - $input_class = ['checkall']; - - $table_is_view = false; - // Sets parameters for links - $tbl_url_query = Url::getCommon( - [ - 'db' => $this->db, - 'table' => $current_table['TABLE_NAME'], - ] - ); - // 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) - = $this->getStuffForEngineTypeTable( - $current_table, - $sum_size, - $overhead_size - ); - - $curTable = $this->dbi - ->getTable($this->db, $current_table['TABLE_NAME']); - if (! $curTable->isMerge()) { - $sum_entries += $current_table['TABLE_ROWS']; - } - - $collationDefinition = '---'; - if (isset($current_table['Collation'])) { - $tableCollation = Charsets::findCollationByName( - $this->dbi, - $GLOBALS['cfg']['Server']['DisableIS'], - $current_table['Collation'] - ); - if ($tableCollation !== null) { - $collationDefinition = '' - . $tableCollation->getName() . ''; - } - } - - if ($this->isShowStats) { - $overhead = '-'; - if ($formatted_overhead != '') { - $overhead = '' - . '' . $formatted_overhead . ' ' - . '' . $overhead_unit . '' - . '' . "\n"; - $overhead_check = true; - $input_class[] = 'tbl-overhead'; - } - } - - if ($GLOBALS['cfg']['ShowDbStructureCharset']) { - $charset = ''; - if (isset($tableCollation)) { - $charset = $tableCollation->getCharset(); - } - } - - if ($GLOBALS['cfg']['ShowDbStructureCreation']) { - $create_time = isset($current_table['Create_time']) - ? $current_table['Create_time'] : ''; - if ($create_time - && (! $create_time_all - || $create_time < $create_time_all) - ) { - $create_time_all = $create_time; - } - } - - if ($GLOBALS['cfg']['ShowDbStructureLastUpdate']) { - $update_time = isset($current_table['Update_time']) - ? $current_table['Update_time'] : ''; - if ($update_time - && (! $update_time_all - || $update_time < $update_time_all) - ) { - $update_time_all = $update_time; - } - } - - if ($GLOBALS['cfg']['ShowDbStructureLastCheck']) { - $check_time = isset($current_table['Check_time']) - ? $current_table['Check_time'] : ''; - if ($check_time - && (! $check_time_all - || $check_time < $check_time_all) - ) { - $check_time_all = $check_time; - } - } - - $truename = $current_table['TABLE_NAME']; - - $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. - */ - $may_have_rows = $current_table['TABLE_ROWS'] > 0 || $table_is_view; - $titles = Util::buildActionTitles(); - - if (! $this->dbIsSystemSchema) { - $drop_query = sprintf( - 'DROP %s %s', - $table_is_view || $current_table['ENGINE'] == null ? 'VIEW' - : 'TABLE', - Util::backquote( - $current_table['TABLE_NAME'] - ) - ); - $drop_message = sprintf( - ($table_is_view || $current_table['ENGINE'] == null - ? __('View %s has been dropped.') - : __('Table %s has been dropped.')), - str_replace( - ' ', - ' ', - htmlspecialchars($current_table['TABLE_NAME']) - ) - ); - } - - if ($num_columns > 0 - && $this->numTables > $num_columns - && ($row_count % $num_columns) == 0 - ) { - $row_count = 1; - - $html .= $this->template->render('database/structure/table_header', [ - 'db' => $this->db, - 'db_is_system_schema' => $this->dbIsSystemSchema, - 'replication' => $GLOBALS['replication_info']['slave']['status'], - 'properties_num_columns' => $GLOBALS['cfg']['PropertiesNumColumns'], - 'is_show_stats' => $GLOBALS['is_show_stats'], - 'show_charset' => $GLOBALS['cfg']['ShowDbStructureCharset'], - 'show_comment' => $GLOBALS['cfg']['ShowDbStructureComment'], - 'show_creation' => $GLOBALS['cfg']['ShowDbStructureCreation'], - 'show_last_update' => $GLOBALS['cfg']['ShowDbStructureLastUpdate'], - 'show_last_check' => $GLOBALS['cfg']['ShowDbStructureLastCheck'], - 'num_favorite_tables' => $GLOBALS['cfg']['NumFavoriteTables'], - 'structure_table_rows' => $structure_table_rows, - ]); - $structure_table_rows = []; - } - - list($approx_rows, $show_superscript) = $this->isRowCountApproximated( - $current_table, - $table_is_view - ); - - list($do, $ignored) = $this->getReplicationStatus($truename); - - $structure_table_rows[] = [ - 'table_name_hash' => md5($current_table['TABLE_NAME']), - 'db_table_name_hash' => md5($this->db . '.' . $current_table['TABLE_NAME']), - 'db' => $this->db, - 'curr' => $i, - 'input_class' => implode(' ', $input_class), - 'table_is_view' => $table_is_view, - 'current_table' => $current_table, - 'browse_table_title' => $may_have_rows ? $titles['Browse'] : $titles['NoBrowse'], - 'search_table_title' => $may_have_rows ? $titles['Search'] : $titles['NoSearch'], - 'browse_table_label_title' => htmlspecialchars($current_table['TABLE_COMMENT']), - 'browse_table_label_truename' => $truename, - 'empty_table_sql_query' => urlencode( - 'TRUNCATE ' . Util::backquote( - $current_table['TABLE_NAME'] - ) - ), - 'empty_table_message_to_show' => urlencode( - sprintf( - __('Table %s has been emptied.'), - htmlspecialchars( - $current_table['TABLE_NAME'] - ) - ) - ), - 'empty_table_title' => $may_have_rows ? $titles['Empty'] : $titles['NoEmpty'], - 'tracking_icon' => $this->getTrackingIcon($truename), - 'server_slave_status' => $GLOBALS['replication_info']['slave']['status'], - 'tbl_url_query' => $tbl_url_query, - 'db_is_system_schema' => $this->dbIsSystemSchema, - 'titles' => $titles, - 'drop_query' => $drop_query, - 'drop_message' => $drop_message, - 'collation' => $collationDefinition, - 'formatted_size' => $formatted_size, - 'unit' => $unit, - 'overhead' => $overhead, - 'create_time' => isset($create_time) && $create_time - ? Util::localisedDate(strtotime($create_time)) : '-', - 'update_time' => isset($update_time) && $update_time - ? Util::localisedDate(strtotime($update_time)) : '-', - 'check_time' => isset($check_time) && $check_time - ? Util::localisedDate(strtotime($check_time)) : '-', - 'charset' => isset($charset) - ? $charset : '', - 'is_show_stats' => $this->isShowStats, - 'ignored' => $ignored, - 'do' => $do, - 'approx_rows' => $approx_rows, - 'show_superscript' => $show_superscript, - 'already_favorite' => $this->checkFavoriteTable( - $current_table['TABLE_NAME'] - ), - 'num_favorite_tables' => $GLOBALS['cfg']['NumFavoriteTables'], - 'properties_num_columns' => $GLOBALS['cfg']['PropertiesNumColumns'], - 'limit_chars' => $GLOBALS['cfg']['LimitChars'], - 'show_charset' => $GLOBALS['cfg']['ShowDbStructureCharset'], - 'show_comment' => $GLOBALS['cfg']['ShowDbStructureComment'], - 'show_creation' => $GLOBALS['cfg']['ShowDbStructureCreation'], - 'show_last_update' => $GLOBALS['cfg']['ShowDbStructureLastUpdate'], - 'show_last_check' => $GLOBALS['cfg']['ShowDbStructureLastCheck'], - ]; - - $overall_approx_rows = $overall_approx_rows || $approx_rows; - } - - $databaseCollation = []; - $databaseCharset = ''; - $collation = Charsets::findCollationByName( - $this->dbi, - $GLOBALS['cfg']['Server']['DisableIS'], - $this->dbi->getDbCollation($this->db) - ); - if ($collation !== null) { - $databaseCollation = [ - 'name' => $collation->getName(), - 'description' => $collation->getDescription(), - ]; - $databaseCharset = $collation->getCharset(); - } - - // table form - $html .= $this->template->render('database/structure/table_header', [ - 'db' => $this->db, - 'db_is_system_schema' => $this->dbIsSystemSchema, - 'replication' => $GLOBALS['replication_info']['slave']['status'], - 'properties_num_columns' => $GLOBALS['cfg']['PropertiesNumColumns'], - 'is_show_stats' => $GLOBALS['is_show_stats'], - 'show_charset' => $GLOBALS['cfg']['ShowDbStructureCharset'], - 'show_comment' => $GLOBALS['cfg']['ShowDbStructureComment'], - 'show_creation' => $GLOBALS['cfg']['ShowDbStructureCreation'], - 'show_last_update' => $GLOBALS['cfg']['ShowDbStructureLastUpdate'], - 'show_last_check' => $GLOBALS['cfg']['ShowDbStructureLastCheck'], - 'num_favorite_tables' => $GLOBALS['cfg']['NumFavoriteTables'], - 'structure_table_rows' => $structure_table_rows, - 'body_for_table_summary' => [ - 'num_tables' => $this->numTables, - 'server_slave_status' => $GLOBALS['replication_info']['slave']['status'], - 'db_is_system_schema' => $this->dbIsSystemSchema, - 'sum_entries' => $sum_entries, - 'database_collation' => $databaseCollation, - 'is_show_stats' => $this->isShowStats, - 'database_charset' => $databaseCharset, - 'sum_size' => $sum_size, - 'overhead_size' => $overhead_size, - 'create_time_all' => $create_time_all ? Util::localisedDate(strtotime($create_time_all)) : '-', - 'update_time_all' => $update_time_all ? Util::localisedDate(strtotime($update_time_all)) : '-', - 'check_time_all' => $check_time_all ? Util::localisedDate(strtotime($check_time_all)) : '-', - 'approx_rows' => $overall_approx_rows, - 'num_favorite_tables' => $GLOBALS['cfg']['NumFavoriteTables'], - 'db' => $GLOBALS['db'], - 'properties_num_columns' => $GLOBALS['cfg']['PropertiesNumColumns'], - 'dbi' => $this->dbi, - 'show_charset' => $GLOBALS['cfg']['ShowDbStructureCharset'], - 'show_comment' => $GLOBALS['cfg']['ShowDbStructureComment'], - 'show_creation' => $GLOBALS['cfg']['ShowDbStructureCreation'], - 'show_last_update' => $GLOBALS['cfg']['ShowDbStructureLastUpdate'], - 'show_last_check' => $GLOBALS['cfg']['ShowDbStructureLastCheck'], - ], - 'check_all_tables' => [ - 'pma_theme_image' => $GLOBALS['pmaThemeImage'], - 'text_dir' => $GLOBALS['text_dir'], - 'overhead_check' => $overhead_check, - 'db_is_system_schema' => $this->dbIsSystemSchema, - 'hidden_fields' => $hidden_fields, - 'disable_multi_table' => $GLOBALS['cfg']['DisableMultiTableMaintenance'], - 'central_columns_work' => $GLOBALS['cfgRelation']['centralcolumnswork'], - ], - ]); - - return $html; - } - - /** - * Returns the tracking icon if the table is tracked - * - * @param string $table table name - * - * @return string HTML for tracking icon - */ - protected function getTrackingIcon(string $table): string - { - $tracking_icon = ''; - if (Tracker::isActive()) { - $is_tracked = Tracker::isTracked($this->db, $table); - if ($is_tracked - || Tracker::getVersion($this->db, $table) > 0 - ) { - $tracking_icon = $this->template->render('database/structure/tracking_icon', [ - 'db' => $this->db, - 'table' => $table, - 'is_tracked' => $is_tracked, - ]); - } - } - return $tracking_icon; - } - - /** - * Returns whether the row count is approximated - * - * @param array $current_table array containing details about the table - * @param boolean $table_is_view whether the table is a view - * - * @return array - */ - protected function isRowCountApproximated( - array $current_table, - bool $table_is_view - ): array { - $approx_rows = false; - $show_superscript = ''; - - // there is a null value in the ENGINE - // - when the table needs to be repaired, or - // - when it's a view - // so ensure that we'll display "in use" below for a table - // that needs to be repaired - if (isset($current_table['TABLE_ROWS']) - && ($current_table['ENGINE'] != null || $table_is_view) - ) { - // InnoDB/TokuDB table: we did not get an accurate row count - $approx_rows = ! $table_is_view - && in_array($current_table['ENGINE'], ['InnoDB', 'TokuDB']) - && ! $current_table['COUNTED']; - - if ($table_is_view - && $current_table['TABLE_ROWS'] >= $GLOBALS['cfg']['MaxExactCountViews'] - ) { - $approx_rows = true; - $show_superscript = Util::showHint( - Sanitize::sanitizeMessage( - sprintf( - __( - 'This view has at least this number of ' - . 'rows. Please refer to %sdocumentation%s.' - ), - '[doc@cfg_MaxExactCountViews]', - '[/doc]' - ) - ) - ); - } - } - - return [ - $approx_rows, - $show_superscript, - ]; - } - - /** - * Returns the replication status of the table. - * - * @param string $table table name - * - * @return array - */ - protected function getReplicationStatus(string $table): array - { - $do = $ignored = false; - if ($GLOBALS['replication_info']['slave']['status']) { - $nbServSlaveDoDb = count( - $GLOBALS['replication_info']['slave']['Do_DB'] - ); - $nbServSlaveIgnoreDb = count( - $GLOBALS['replication_info']['slave']['Ignore_DB'] - ); - $searchDoDBInTruename = array_search( - $table, - $GLOBALS['replication_info']['slave']['Do_DB'] - ); - $searchDoDBInDB = array_search( - $this->db, - $GLOBALS['replication_info']['slave']['Do_DB'] - ); - - $do = (is_string($searchDoDBInTruename) && strlen($searchDoDBInTruename) > 0) - || (is_string($searchDoDBInDB) && strlen($searchDoDBInDB) > 0) - || ($nbServSlaveDoDb == 0 && $nbServSlaveIgnoreDb == 0) - || $this->hasTable( - $GLOBALS['replication_info']['slave']['Wild_Do_Table'], - $table - ); - - $searchDb = array_search( - $this->db, - $GLOBALS['replication_info']['slave']['Ignore_DB'] - ); - $searchTable = array_search( - $table, - $GLOBALS['replication_info']['slave']['Ignore_Table'] - ); - $ignored = (is_string($searchTable) && strlen($searchTable) > 0) - || (is_string($searchDb) && strlen($searchDb) > 0) - || $this->hasTable( - $GLOBALS['replication_info']['slave']['Wild_Ignore_Table'], - $table - ); - } - - return [ - $do, - $ignored, - ]; - } - - /** - * Synchronize favorite tables - * - * - * @param RecentFavoriteTable $favoriteInstance Instance of this class - * @param string $user The user hash - * @param array $favoriteTables Existing favorites - * - * @return array - */ - protected function synchronizeFavoriteTables( - RecentFavoriteTable $favoriteInstance, - string $user, - array $favoriteTables - ): array { - $favoriteInstanceTables = $favoriteInstance->getTables(); - - if (empty($favoriteInstanceTables) - && isset($favoriteTables[$user]) - ) { - foreach ($favoriteTables[$user] as $key => $value) { - $favoriteInstance->add($value['db'], $value['table']); - } - } - $favoriteTables[$user] = $favoriteInstance->getTables(); - - $json = [ - 'favoriteTables' => json_encode($favoriteTables), - 'list' => $favoriteInstance->getHtmlList(), - ]; - $serverId = $GLOBALS['server']; - // Set flag when localStorage and pmadb(if present) are in sync. - $_SESSION['tmpval']['favorites_synced'][$serverId] = true; - - return $json; - } - - /** - * Function to check if a table is already in favorite list. - * - * @param string $currentTable current table - * - * @return bool - */ - protected function checkFavoriteTable(string $currentTable): bool - { - // ensure $_SESSION['tmpval']['favoriteTables'] is initialized - RecentFavoriteTable::getInstance('favorite'); - foreach ($_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] as $value) { - if ($value['db'] == $this->db && $value['table'] == $currentTable) { - return true; - } - } - return false; - } - - /** - * Find table with truename - * - * @param array $db DB to look into - * @param string $truename Table name - * - * @return bool - */ - protected function hasTable(array $db, $truename) - { - foreach ($db as $db_table) { - if ($this->db == $this->replication->extractDbOrTable($db_table) - && preg_match( - '@^' . - preg_quote(mb_substr($this->replication->extractDbOrTable($db_table, 'table'), 0, -1), '@') . '@', - $truename - ) - ) { - return true; - } - } - return false; - } - - /** - * Get the value set for ENGINE table, - * - * @param array $current_table current table - * @param integer $sum_size total table size - * @param integer $overhead_size overhead size - * - * @return array - * @internal param bool $table_is_view whether table is view or not - */ - protected function getStuffForEngineTypeTable( - array $current_table, - $sum_size, - $overhead_size - ) { - $formatted_size = '-'; - $unit = ''; - $formatted_overhead = ''; - $overhead_unit = ''; - $table_is_view = false; - - switch ($current_table['ENGINE']) { - // MyISAM, ISAM or Heap table: Row count, data size and index size - // are accurate; data size is accurate for ARCHIVE - case 'MyISAM': - case 'ISAM': - case 'HEAP': - case 'MEMORY': - case 'ARCHIVE': - case 'Aria': - case 'Maria': - list($current_table, $formatted_size, $unit, $formatted_overhead, - $overhead_unit, $overhead_size, $sum_size) - = $this->getValuesForAriaTable( - $current_table, - $sum_size, - $overhead_size, - $formatted_size, - $unit, - $formatted_overhead, - $overhead_unit - ); - break; - case 'InnoDB': - case 'PBMS': - case 'TokuDB': - // InnoDB table: Row count is not accurate but data and index sizes are. - // PBMS table in Drizzle: TABLE_ROWS is taken from table cache, - // so it may be unavailable - list($current_table, $formatted_size, $unit, $sum_size) - = $this->getValuesForInnodbTable( - $current_table, - $sum_size - ); - break; - // Mysql 5.0.x (and lower) uses MRG_MyISAM - // and MySQL 5.1.x (and higher) uses MRG_MYISAM - // Both are aliases for MERGE - case 'MRG_MyISAM': - case 'MRG_MYISAM': - case 'MERGE': - case 'BerkeleyDB': - // Merge or BerkleyDB table: Only row count is accurate. - if ($this->isShowStats) { - $formatted_size = ' - '; - $unit = ''; - } - break; - // for a view, the ENGINE is sometimes reported as null, - // or on some servers it's reported as "SYSTEM VIEW" - case null: - case 'SYSTEM VIEW': - // possibly a view, do nothing - break; - default: - // Unknown table type. - if ($this->isShowStats) { - $formatted_size = __('unknown'); - $unit = ''; - } - } // end switch - - if ($current_table['TABLE_TYPE'] == 'VIEW' - || $current_table['TABLE_TYPE'] == 'SYSTEM VIEW' - ) { - // countRecords() takes care of $cfg['MaxExactCountViews'] - $current_table['TABLE_ROWS'] = $this->dbi - ->getTable($this->db, $current_table['TABLE_NAME']) - ->countRecords(true); - $table_is_view = true; - } - - return [ - $current_table, - $formatted_size, - $unit, - $formatted_overhead, - $overhead_unit, - $overhead_size, - $table_is_view, - $sum_size, - ]; - } - - /** - * Get values for ARIA/MARIA tables - * - * @param array $current_table current table - * @param integer $sum_size sum size - * @param integer $overhead_size overhead size - * @param integer $formatted_size formatted size - * @param string $unit unit - * @param integer $formatted_overhead overhead formatted - * @param string $overhead_unit overhead unit - * - * @return array - */ - protected function getValuesForAriaTable( - array $current_table, - $sum_size, - $overhead_size, - $formatted_size, - $unit, - $formatted_overhead, - $overhead_unit - ) { - if ($this->dbIsSystemSchema) { - $current_table['Rows'] = $this->dbi - ->getTable($this->db, $current_table['Name']) - ->countRecords(); - } - - if ($this->isShowStats) { - $tblsize = $current_table['Data_length'] - + $current_table['Index_length']; - $sum_size += $tblsize; - list($formatted_size, $unit) = Util::formatByteDown( - $tblsize, - 3, - $tblsize > 0 ? 1 : 0 - ); - if (isset($current_table['Data_free']) - && $current_table['Data_free'] > 0 - ) { - list($formatted_overhead, $overhead_unit) - = Util::formatByteDown( - $current_table['Data_free'], - 3, - ($current_table['Data_free'] > 0 ? 1 : 0) - ); - $overhead_size += $current_table['Data_free']; - } - } - return [ - $current_table, - $formatted_size, - $unit, - $formatted_overhead, - $overhead_unit, - $overhead_size, - $sum_size, - ]; - } - - /** - * Get values for InnoDB table - * - * @param array $current_table current table - * @param integer $sum_size sum size - * - * @return array - */ - protected function getValuesForInnodbTable( - array $current_table, - $sum_size - ) { - $formatted_size = $unit = ''; - - if ((in_array($current_table['ENGINE'], ['InnoDB', 'TokuDB']) - && $current_table['TABLE_ROWS'] < $GLOBALS['cfg']['MaxExactCount']) - || ! isset($current_table['TABLE_ROWS']) - ) { - $current_table['COUNTED'] = true; - $current_table['TABLE_ROWS'] = $this->dbi - ->getTable($this->db, $current_table['TABLE_NAME']) - ->countRecords(true); - } else { - $current_table['COUNTED'] = false; - } - - if ($this->isShowStats) { - $tblsize = $current_table['Data_length'] - + $current_table['Index_length']; - $sum_size += $tblsize; - list($formatted_size, $unit) = Util::formatByteDown( - $tblsize, - 3, - ($tblsize > 0 ? 1 : 0) - ); - } - - return [ - $current_table, - $formatted_size, - $unit, - $sum_size, - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Database/TriggersController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Database/TriggersController.php deleted file mode 100644 index fd47457..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Database/TriggersController.php +++ /dev/null @@ -1,43 +0,0 @@ -dbi); - $triggers->main(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/HomeController.php b/srcs/phpmyadmin/libraries/classes/Controllers/HomeController.php deleted file mode 100644 index c0fe1ba..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/HomeController.php +++ /dev/null @@ -1,517 +0,0 @@ -config = $config; - $this->themeManager = $themeManager; - } - - - /** - * @return string HTML - */ - public function index(): string - { - global $cfg, $server, $collation_connection, $message; - - $languageManager = LanguageManager::getInstance(); - - if (! empty($message)) { - $displayMessage = Util::getMessage($message); - unset($message); - } - if (isset($_SESSION['partial_logout'])) { - $partialLogout = Message::success(__( - 'You were logged out from one server, to logout completely ' - . 'from phpMyAdmin, you need to logout from all servers.' - ))->getDisplay(); - unset($_SESSION['partial_logout']); - } - - $syncFavoriteTables = RecentFavoriteTable::getInstance('favorite') - ->getHtmlSyncFavoriteTables(); - - $hasServer = $server > 0 || count($cfg['Servers']) > 1; - if ($hasServer) { - $hasServerSelection = $cfg['ServerDefault'] == 0 - || (! $cfg['NavigationDisplayServers'] - && (count($cfg['Servers']) > 1 - || ($server == 0 && count($cfg['Servers']) === 1))); - if ($hasServerSelection) { - $serverSelection = Select::render(true, true); - } - - if ($server > 0) { - $checkUserPrivileges = new CheckUserPrivileges($this->dbi); - $checkUserPrivileges->getPrivileges(); - - if (($cfg['Server']['auth_type'] != 'config') && $cfg['ShowChgPassword']) { - $changePassword = $this->template->render('list/item', [ - 'content' => Util::getImage('s_passwd') . ' ' . __( - 'Change password' - ), - 'id' => 'li_change_password', - 'class' => 'no_bullets', - 'url' => [ - 'href' => 'user_password.php' . Url::getCommon(), - 'target' => null, - 'id' => 'change_password_anchor', - 'class' => 'ajax', - ], - 'mysql_help_page' => null, - ]); - } - - $charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']); - $collations = Charsets::getCollations($this->dbi, $cfg['Server']['DisableIS']); - $charsetsList = []; - /** @var Charset $charset */ - foreach ($charsets as $charset) { - $collationsList = []; - /** @var Collation $collation */ - foreach ($collations[$charset->getName()] as $collation) { - $collationsList[] = [ - 'name' => $collation->getName(), - 'description' => $collation->getDescription(), - 'is_selected' => $collation_connection === $collation->getName(), - ]; - } - $charsetsList[] = [ - 'name' => $charset->getName(), - 'description' => $charset->getDescription(), - 'collations' => $collationsList, - ]; - } - - $userPreferences = $this->template->render('list/item', [ - 'content' => Util::getImage('b_tblops') . ' ' . __( - 'More settings' - ), - 'id' => 'li_user_preferences', - 'class' => 'no_bullets', - 'url' => [ - 'href' => 'prefs_manage.php' . Url::getCommon(), - 'target' => null, - 'id' => null, - 'class' => null, - ], - 'mysql_help_page' => null, - ]); - } - } - - $languageSelector = ''; - if (empty($cfg['Lang']) && $languageManager->hasChoice()) { - $languageSelector = $languageManager->getSelectorDisplay($this->template); - } - - $themeSelection = ''; - if ($cfg['ThemeManager']) { - $themeSelection = $this->themeManager->getHtmlSelectBox(); - } - - $databaseServer = []; - if ($server > 0 && $cfg['ShowServerInfo']) { - $hostInfo = ''; - if (! empty($cfg['Server']['verbose'])) { - $hostInfo .= $cfg['Server']['verbose']; - if ($cfg['ShowServerInfo']) { - $hostInfo .= ' ('; - } - } - if ($cfg['ShowServerInfo'] || empty($cfg['Server']['verbose'])) { - $hostInfo .= $this->dbi->getHostInfo(); - } - if (! empty($cfg['Server']['verbose']) && $cfg['ShowServerInfo']) { - $hostInfo .= ')'; - } - - $serverCharset = Charsets::getServerCharset($this->dbi, $cfg['Server']['DisableIS']); - $databaseServer = [ - 'host' => $hostInfo, - 'type' => Util::getServerType(), - 'connection' => Util::getServerSSL(), - 'version' => $this->dbi->getVersionString() . ' - ' . $this->dbi->getVersionComment(), - 'protocol' => $this->dbi->getProtoInfo(), - 'user' => $this->dbi->fetchValue('SELECT USER();'), - 'charset' => $serverCharset->getDescription() . ' (' . $serverCharset->getName() . ')', - ]; - } - - $webServer = []; - if ($cfg['ShowServerInfo']) { - $webServer['software'] = $_SERVER['SERVER_SOFTWARE']; - - if ($server > 0) { - $clientVersion = $this->dbi->getClientInfo(); - if (preg_match('#\d+\.\d+\.\d+#', $clientVersion)) { - $clientVersion = 'libmysql - ' . $clientVersion; - } - - $webServer['database'] = $clientVersion; - $webServer['php_extensions'] = Util::listPHPExtensions(); - $webServer['php_version'] = PHP_VERSION; - } - } - if ($cfg['ShowPhpInfo']) { - $phpInfo = $this->template->render('list/item', [ - 'content' => __('Show PHP information'), - 'id' => 'li_phpinfo', - 'class' => null, - 'url' => [ - 'href' => 'phpinfo.php' . Url::getCommon(), - 'target' => '_blank', - 'id' => null, - 'class' => null, - ], - 'mysql_help_page' => null, - ]); - } - - $relation = new Relation($this->dbi); - if ($server > 0) { - $cfgRelation = $relation->getRelationsParam(); - if (! $cfgRelation['allworks'] - && $cfg['PmaNoRelation_DisableWarning'] == false - ) { - $messageText = __( - 'The phpMyAdmin configuration storage is not completely ' - . 'configured, some extended features have been deactivated. ' - . '%sFind out why%s. ' - ); - if ($cfg['ZeroConf'] == true) { - $messageText .= '
' . - __( - 'Or alternately go to \'Operations\' tab of any database ' - . 'to set it up there.' - ); - } - $messageInstance = Message::notice($messageText); - $messageInstance->addParamHtml(''); - $messageInstance->addParamHtml(''); - /* Show error if user has configured something, notice elsewhere */ - if (! empty($cfg['Servers'][$server]['pmadb'])) { - $messageInstance->isError(true); - } - $configStorageMessage = $messageInstance->getDisplay(); - } - } - - $this->checkRequirements(); - - return $this->template->render('home/index', [ - 'message' => $displayMessage ?? '', - 'partial_logout' => $partialLogout ?? '', - 'is_git_revision' => $this->config->isGitRevision(), - 'server' => $server, - 'sync_favorite_tables' => $syncFavoriteTables, - 'has_server' => $hasServer, - 'is_demo' => $cfg['DBG']['demo'], - 'has_server_selection' => $hasServerSelection ?? false, - 'server_selection' => $serverSelection ?? '', - 'change_password' => $changePassword ?? '', - 'charsets' => $charsetsList ?? [], - 'language_selector' => $languageSelector, - 'theme_selection' => $themeSelection, - 'user_preferences' => $userPreferences ?? '', - 'database_server' => $databaseServer, - 'web_server' => $webServer, - 'php_info' => $phpInfo ?? '', - 'is_version_checked' => $cfg['VersionCheck'], - 'phpmyadmin_version' => PMA_VERSION, - 'config_storage_message' => $configStorageMessage ?? '', - ]); - } - - /** - * @param array $params Request parameters - * @return void - */ - public function setTheme(array $params): void - { - $this->themeManager->setActiveTheme($params['set_theme']); - $this->themeManager->setThemeCookie(); - - $userPreferences = new UserPreferences(); - $preferences = $userPreferences->load(); - $preferences['config_data']['ThemeDefault'] = $params['set_theme']; - $userPreferences->save($preferences['config_data']); - } - - /** - * @param array $params Request parameters - * @return void - */ - public function setCollationConnection(array $params): void - { - $this->config->setUserValue( - null, - 'DefaultConnectionCollation', - $params['collation_connection'], - 'utf8mb4_unicode_ci' - ); - } - - /** - * @return array JSON - */ - public function reloadRecentTablesList(): array - { - return [ - 'list' => RecentFavoriteTable::getInstance('recent')->getHtmlList(), - ]; - } - - /** - * @return string HTML - */ - public function gitRevision(): string - { - return (new GitRevision( - $this->response, - $this->config, - $this->template - ))->display(); - } - - /** - * @return void - */ - private function checkRequirements(): void - { - global $cfg, $server, $lang; - - /** - * mbstring is used for handling multibytes 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 - ); - } - - /** - * Missing functionality - */ - if (! extension_loaded('curl') && ! ini_get('allow_url_fopen')) { - trigger_error( - __( - 'The curl extension was not found and allow_url_fopen is ' - . 'disabled. Due to this some features such as error reporting ' - . 'or version check are disabled.' - ) - ); - } - - if ($cfg['LoginCookieValidityDisableWarning'] == false) { - /** - * Check whether session.gc_maxlifetime limits session validity. - */ - $gc_time = (int) ini_get('session.gc_maxlifetime'); - if ($gc_time < $cfg['LoginCookieValidity']) { - trigger_error( - __( - 'Your PHP parameter [a@https://secure.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 might expire sooner ' . - 'than configured in phpMyAdmin.' - ), - E_USER_WARNING - ); - } - } - - /** - * Check whether LoginCookieValidity is limited by LoginCookieStore. - */ - if ($cfg['LoginCookieStore'] != 0 - && $cfg['LoginCookieStore'] < $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 - ); - } - - /** - * Warning if using the default MySQL controluser account - */ - if ($server != 0 - && isset($cfg['Server']['controluser']) && $cfg['Server']['controluser'] == 'pma' - && isset($cfg['Server']['controlpass']) && $cfg['Server']['controlpass'] == 'pmapass' - ) { - trigger_error( - __( - 'Your server is running with default values for the ' . - 'controluser and password (controlpass) and is open to ' . - 'intrusion; you really should fix this security weakness' . - ' by changing the password for controluser \'pma\'.' - ), - E_USER_WARNING - ); - } - - /** - * Check if user does not have defined blowfish secret and it is being used. - */ - if (! empty($_SESSION['encryption_key'])) { - if (empty($cfg['blowfish_secret'])) { - trigger_error( - __( - 'The configuration file now needs a secret passphrase (blowfish_secret).' - ), - E_USER_WARNING - ); - } elseif (strlen($cfg['blowfish_secret']) < 32) { - trigger_error( - __( - 'The secret passphrase in configuration (blowfish_secret) is too short.' - ), - E_USER_WARNING - ); - } - } - - /** - * Check for existence of config directory which should not exist in - * production environment. - */ - if (@file_exists(ROOT_PATH . 'config')) { - trigger_error( - __( - 'Directory [code]config[/code], which is used by the setup script, ' . - 'still exists in your phpMyAdmin directory. It is strongly ' . - 'recommended to remove it once phpMyAdmin has been configured. ' . - 'Otherwise the security of your server may be compromised by ' . - 'unauthorized people downloading your configuration.' - ), - E_USER_WARNING - ); - } - - /** - * Warning about Suhosin only if its simulation mode is not enabled - */ - if ($cfg['SuhosinDisableWarning'] == false - && ini_get('suhosin.request.max_value_length') - && ini_get('suhosin.simulation') == '0' - ) { - trigger_error( - sprintf( - __( - 'Server running with Suhosin. Please refer ' . - 'to %sdocumentation%s for possible issues.' - ), - '[doc@faq1-38]', - '[/doc]' - ), - E_USER_WARNING - ); - } - - /* Missing template cache */ - if ($this->config->getTempDir('twig') === null) { - trigger_error( - sprintf( - __( - 'The $cfg[\'TempDir\'] (%s) is not accessible. ' . - 'phpMyAdmin is not able to cache templates and will ' . - 'be slow because of this.' - ), - $this->config->get('TempDir') - ), - E_USER_WARNING - ); - } - - /** - * Warning about incomplete translations. - * - * The data file is created while creating release by ./scripts/remove-incomplete-mo - */ - if (@file_exists(ROOT_PATH . 'libraries/language_stats.inc.php')) { - include ROOT_PATH . 'libraries/language_stats.inc.php'; - /* - * This message is intentionally not translated, because we're - * handling incomplete translations here and focus on english - * speaking users. - */ - if (isset($GLOBALS['language_stats'][$lang]) - && $GLOBALS['language_stats'][$lang] < $cfg['TranslationWarningThreshold'] - ) { - trigger_error( - 'You are using an incomplete translation, please help to make it ' - . 'better by [a@https://www.phpmyadmin.net/translate/' - . '@_blank]contributing[/a].', - E_USER_NOTICE - ); - } - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/BinlogController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/BinlogController.php deleted file mode 100644 index 859559c..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/BinlogController.php +++ /dev/null @@ -1,149 +0,0 @@ -binaryLogs = $this->dbi->fetchResult( - 'SHOW MASTER LOGS', - 'Log_name', - null, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - } - - /** - * Index action - * - * @param array $params Request params - * - * @return string - */ - public function indexAction(array $params): string - { - global $cfg, $pmaThemeImage; - - include_once ROOT_PATH . 'libraries/server_common.inc.php'; - - $position = ! empty($params['pos']) ? (int) $params['pos'] : 0; - - $urlParams = []; - if (isset($params['log']) - && array_key_exists($params['log'], $this->binaryLogs) - ) { - $urlParams['log'] = $params['log']; - } - - $isFullQuery = false; - if (! empty($params['is_full_query'])) { - $isFullQuery = true; - $urlParams['is_full_query'] = 1; - } - - $sqlQuery = $this->getSqlQuery( - $params['log'] ?? '', - $position, - (int) $cfg['MaxRows'] - ); - $result = $this->dbi->query($sqlQuery); - - $numRows = 0; - if (isset($result) && $result) { - $numRows = $this->dbi->numRows($result); - } - - $previousParams = $urlParams; - $fullQueriesParams = $urlParams; - $nextParams = $urlParams; - if ($position > 0) { - $fullQueriesParams['pos'] = $position; - if ($position > $cfg['MaxRows']) { - $previousParams['pos'] = $position - $cfg['MaxRows']; - } - } - $fullQueriesParams['is_full_query'] = 1; - if ($isFullQuery) { - unset($fullQueriesParams['is_full_query']); - } - if ($numRows >= $cfg['MaxRows']) { - $nextParams['pos'] = $position + $cfg['MaxRows']; - } - - $values = []; - while ($value = $this->dbi->fetchAssoc($result)) { - $values[] = $value; - } - - return $this->template->render('server/binlog/index', [ - 'url_params' => $urlParams, - 'binary_logs' => $this->binaryLogs, - 'log' => $params['log'], - 'sql_message' => Util::getMessage(Message::success(), $sqlQuery), - 'values' => $values, - 'has_previous' => $position > 0, - 'has_next' => $numRows >= $cfg['MaxRows'], - 'previous_params' => $previousParams, - 'full_queries_params' => $fullQueriesParams, - 'next_params' => $nextParams, - 'has_icons' => Util::showIcons('TableNavigationLinksMode'), - 'is_full_query' => $isFullQuery, - 'image_path' => $pmaThemeImage, - ]); - } - - /** - * @param string $log Binary log file name - * @param int $position Position to display - * @param int $maxRows Maximum number of rows - * - * @return string - */ - private function getSqlQuery( - string $log, - int $position, - int $maxRows - ): string { - $sqlQuery = 'SHOW BINLOG EVENTS'; - if (! empty($log)) { - $sqlQuery .= ' IN \'' . $log . '\''; - } - $sqlQuery .= ' LIMIT ' . $position . ', ' . $maxRows; - - return $sqlQuery; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/CollationsController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/CollationsController.php deleted file mode 100644 index 2d806e8..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/CollationsController.php +++ /dev/null @@ -1,100 +0,0 @@ -charsets = $charsets ?? Charsets::getCharsets( - $this->dbi, - $cfg['Server']['DisableIS'] - ); - $this->collations = $collations ?? Charsets::getCollations( - $this->dbi, - $cfg['Server']['DisableIS'] - ); - } - - /** - * Index action - * - * @return string HTML - */ - public function indexAction(): string - { - include_once ROOT_PATH . 'libraries/server_common.inc.php'; - - $charsets = []; - /** @var Charset $charset */ - foreach ($this->charsets as $charset) { - $charsetCollations = []; - /** @var Collation $collation */ - foreach ($this->collations[$charset->getName()] as $collation) { - $charsetCollations[] = [ - 'name' => $collation->getName(), - 'description' => $collation->getDescription(), - 'is_default' => $collation->isDefault(), - ]; - } - - $charsets[] = [ - 'name' => $charset->getName(), - 'description' => $charset->getDescription(), - 'collations' => $charsetCollations, - ]; - } - - return $this->template->render('server/collations/index', [ - 'charsets' => $charsets, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/DatabasesController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/DatabasesController.php deleted file mode 100644 index a601137..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/DatabasesController.php +++ /dev/null @@ -1,424 +0,0 @@ -setSortDetails($params['sort_by'], $params['sort_order']); - $this->hasStatistics = ! empty($params['statistics']); - $this->position = ! empty($params['pos']) ? (int) $params['pos'] : 0; - - /** - * Gets the databases list - */ - if ($server > 0) { - $this->databases = $this->dbi->getDatabasesFull( - null, - $this->hasStatistics, - DatabaseInterface::CONNECT_USER, - $this->sortBy, - $this->sortOrder, - $this->position, - true - ); - $this->databaseCount = count($dblist->databases); - } - - $urlParams = [ - 'statistics' => $this->hasStatistics, - 'pos' => $this->position, - 'sort_by' => $this->sortBy, - 'sort_order' => $this->sortOrder, - ]; - - $databases = $this->getDatabases($replication_types ?? []); - - $charsetsList = []; - if ($cfg['ShowCreateDb'] && $is_create_db_priv) { - $charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']); - $collations = Charsets::getCollations($this->dbi, $cfg['Server']['DisableIS']); - $serverCollation = $this->dbi->getServerCollation(); - /** @var Charset $charset */ - foreach ($charsets as $charset) { - $collationsList = []; - /** @var Collation $collation */ - foreach ($collations[$charset->getName()] as $collation) { - $collationsList[] = [ - 'name' => $collation->getName(), - 'description' => $collation->getDescription(), - 'is_selected' => $serverCollation === $collation->getName(), - ]; - } - $charsetsList[] = [ - 'name' => $charset->getName(), - 'description' => $charset->getDescription(), - 'collations' => $collationsList, - ]; - } - } - - $headerStatistics = $this->getStatisticsColumns(); - - return $this->template->render('server/databases/index', [ - 'is_create_database_shown' => $cfg['ShowCreateDb'], - 'has_create_database_privileges' => $is_create_db_priv, - 'has_statistics' => $this->hasStatistics, - 'database_to_create' => $db_to_create, - 'databases' => $databases['databases'], - 'total_statistics' => $databases['total_statistics'], - 'header_statistics' => $headerStatistics, - 'charsets' => $charsetsList, - 'database_count' => $this->databaseCount, - 'pos' => $this->position, - 'url_params' => $urlParams, - 'max_db_list' => $cfg['MaxDbList'], - 'has_master_replication' => $replication_info['master']['status'], - 'has_slave_replication' => $replication_info['slave']['status'], - 'is_drop_allowed' => $this->dbi->isSuperuser() || $cfg['AllowUserDropDatabase'], - 'default_tab_database' => $cfg['DefaultTabDatabase'], - 'pma_theme_image' => $pmaThemeImage, - 'text_dir' => $text_dir, - ]); - } - - /** - * Handles creating a new database - * - * @param array $params Request parameters - * - * @return array JSON - */ - public function createDatabaseAction(array $params): array - { - global $cfg, $db; - - // lower_case_table_names=1 `DB` becomes `db` - if ($this->dbi->getLowerCaseNames() === '1') { - $params['new_db'] = mb_strtolower( - $params['new_db'] - ); - } - - /** - * Builds and executes the db creation sql query - */ - $sqlQuery = 'CREATE DATABASE ' . Util::backquote($params['new_db']); - if (! empty($params['db_collation'])) { - list($databaseCharset) = explode('_', $params['db_collation']); - $charsets = Charsets::getCharsets( - $this->dbi, - $cfg['Server']['DisableIS'] - ); - $collations = Charsets::getCollations( - $this->dbi, - $cfg['Server']['DisableIS'] - ); - if (in_array($databaseCharset, array_keys($charsets)) - && in_array($params['db_collation'], array_keys($collations[$databaseCharset])) - ) { - $sqlQuery .= ' DEFAULT' - . Util::getCharsetQueryPart($params['db_collation']); - } - } - $sqlQuery .= ';'; - - $result = $this->dbi->tryQuery($sqlQuery); - - if (! $result) { - // avoid displaying the not-created db name in header or navi panel - $db = ''; - - $message = Message::rawError($this->dbi->getError()); - $json = ['message' => $message]; - - $this->response->setRequestStatus(false); - } else { - $db = $params['new_db']; - - $message = Message::success(__('Database %1$s has been created.')); - $message->addParam($params['new_db']); - - $json = [ - 'message' => $message, - 'sql_query' => Util::getMessage(null, $sqlQuery, 'success'), - 'url_query' => Util::getScriptNameForOption( - $cfg['DefaultTabDatabase'], - 'database' - ) . Url::getCommon(['db' => $params['new_db']]), - ]; - } - - return $json; - } - - /** - * Handles dropping multiple databases - * - * @param array $params Request parameters - * - * @return array JSON - */ - public function dropDatabasesAction(array $params): array - { - global $submit_mult, $mult_btn, $selected; - - if (! isset($params['selected_dbs'])) { - $message = Message::error(__('No databases selected.')); - } else { - $action = 'server_databases.php'; - $err_url = $action . Url::getCommon(); - - $submit_mult = 'drop_db'; - $mult_btn = __('Yes'); - - include ROOT_PATH . 'libraries/mult_submits.inc.php'; - - if (empty($message)) { // no error message - $numberOfDatabases = count($selected); - $message = Message::success( - _ngettext( - '%1$d database has been dropped successfully.', - '%1$d databases have been dropped successfully.', - $numberOfDatabases - ) - ); - $message->addParam($numberOfDatabases); - } - } - - $json = []; - if ($message instanceof Message) { - $json = ['message' => $message]; - $this->response->setRequestStatus($message->isSuccess()); - } - - return $json; - } - - /** - * Extracts parameters sort order and sort by - * - * @param string|null $sortBy sort by - * @param string|null $sortOrder sort order - * - * @return void - */ - private function setSortDetails(?string $sortBy, ?string $sortOrder): void - { - if (empty($sortBy)) { - $this->sortBy = 'SCHEMA_NAME'; - } else { - $sortByWhitelist = [ - 'SCHEMA_NAME', - 'DEFAULT_COLLATION_NAME', - 'SCHEMA_TABLES', - 'SCHEMA_TABLE_ROWS', - 'SCHEMA_DATA_LENGTH', - 'SCHEMA_INDEX_LENGTH', - 'SCHEMA_LENGTH', - 'SCHEMA_DATA_FREE', - ]; - $this->sortBy = 'SCHEMA_NAME'; - if (in_array($sortBy, $sortByWhitelist)) { - $this->sortBy = $sortBy; - } - } - - $this->sortOrder = 'asc'; - if (isset($sortOrder) - && mb_strtolower($sortOrder) === 'desc' - ) { - $this->sortOrder = 'desc'; - } - } - - /** - * Returns database list - * - * @param array $replicationTypes replication types - * - * @return array - */ - private function getDatabases(array $replicationTypes): array - { - global $cfg, $replication_info; - - $databases = []; - $totalStatistics = $this->getStatisticsColumns(); - foreach ($this->databases as $database) { - $replication = [ - 'master' => [ - 'status' => $replication_info['master']['status'], - ], - 'slave' => [ - 'status' => $replication_info['slave']['status'], - ], - ]; - foreach ($replicationTypes as $type) { - if ($replication_info[$type]['status']) { - $key = array_search( - $database["SCHEMA_NAME"], - $replication_info[$type]['Ignore_DB'] - ); - if (strlen((string) $key) > 0) { - $replication[$type]['is_replicated'] = false; - } else { - $key = array_search( - $database["SCHEMA_NAME"], - $replication_info[$type]['Do_DB'] - ); - - if (strlen((string) $key) > 0 - || count($replication_info[$type]['Do_DB']) === 0 - ) { - // if ($key != null) did not work for index "0" - $replication[$type]['is_replicated'] = true; - } - } - } - } - - $statistics = $this->getStatisticsColumns(); - if ($this->hasStatistics) { - foreach (array_keys($statistics) as $key) { - $statistics[$key]['raw'] = $database[$key] ?? null; - $totalStatistics[$key]['raw'] += (int) $database[$key] ?? 0; - } - } - - $databases[$database['SCHEMA_NAME']] = [ - 'name' => $database['SCHEMA_NAME'], - 'collation' => [], - 'statistics' => $statistics, - 'replication' => $replication, - 'is_system_schema' => $this->dbi->isSystemSchema( - $database['SCHEMA_NAME'], - true - ), - ]; - $collation = Charsets::findCollationByName( - $this->dbi, - $cfg['Server']['DisableIS'], - $database['DEFAULT_COLLATION_NAME'] - ); - if ($collation !== null) { - $databases[$database['SCHEMA_NAME']]['collation'] = [ - 'name' => $collation->getName(), - 'description' => $collation->getDescription(), - ]; - } - } - - return [ - 'databases' => $databases, - 'total_statistics' => $totalStatistics, - ]; - } - - /** - * Prepares the statistics columns - * - * @return array - */ - private function getStatisticsColumns(): array - { - return [ - 'SCHEMA_TABLES' => [ - 'title' => __('Tables'), - 'format' => 'number', - 'raw' => 0, - ], - 'SCHEMA_TABLE_ROWS' => [ - 'title' => __('Rows'), - 'format' => 'number', - 'raw' => 0, - ], - 'SCHEMA_DATA_LENGTH' => [ - 'title' => __('Data'), - 'format' => 'byte', - 'raw' => 0, - ], - 'SCHEMA_INDEX_LENGTH' => [ - 'title' => __('Indexes'), - 'format' => 'byte', - 'raw' => 0, - ], - 'SCHEMA_LENGTH' => [ - 'title' => __('Total'), - 'format' => 'byte', - 'raw' => 0, - ], - 'SCHEMA_DATA_FREE' => [ - 'title' => __('Overhead'), - 'format' => 'byte', - 'raw' => 0, - ], - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/EnginesController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/EnginesController.php deleted file mode 100644 index 1170551..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/EnginesController.php +++ /dev/null @@ -1,69 +0,0 @@ -template->render('server/engines/index', [ - 'engines' => StorageEngine::getStorageEngines(), - ]); - } - - /** - * Displays details about a given Storage Engine - * - * @param array $params Request params - * - * @return string - */ - public function show(array $params): string - { - require ROOT_PATH . 'libraries/server_common.inc.php'; - - $page = $params['page'] ?? ''; - - $engine = []; - if (StorageEngine::isValid($params['engine'])) { - $storageEngine = StorageEngine::getEngine($params['engine']); - $engine = [ - 'engine' => $params['engine'], - 'title' => $storageEngine->getTitle(), - 'help_page' => $storageEngine->getMysqlHelpPage(), - 'comment' => $storageEngine->getComment(), - 'info_pages' => $storageEngine->getInfoPages(), - 'support' => $storageEngine->getSupportInformationMessage(), - 'variables' => $storageEngine->getHtmlVariables(), - 'page' => ! empty($page) ? $storageEngine->getPage($page) : '', - ]; - } - - return $this->template->render('server/engines/show', [ - 'engine' => $engine, - 'page' => $page, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/PluginsController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/PluginsController.php deleted file mode 100644 index dce48a6..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/PluginsController.php +++ /dev/null @@ -1,77 +0,0 @@ -plugins = $plugins; - } - - /** - * Index action - * - * @return string - */ - public function index(): string - { - include ROOT_PATH . 'libraries/server_common.inc.php'; - - $header = $this->response->getHeader(); - $scripts = $header->getScripts(); - $scripts->addFile('vendor/jquery/jquery.tablesorter.js'); - $scripts->addFile('server/plugins.js'); - - $plugins = []; - $serverPlugins = $this->plugins->getAll(); - foreach ($serverPlugins as $plugin) { - $plugins[$plugin->getType()][] = $plugin->toArray(); - } - ksort($plugins); - - $cleanTypes = []; - foreach (array_keys($plugins) as $type) { - $cleanTypes[$type] = preg_replace( - '/[^a-z]/', - '', - mb_strtolower($type) - ); - } - return $this->template->render('server/plugins/index', [ - 'plugins' => $plugins, - 'clean_types' => $cleanTypes, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/ReplicationController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/ReplicationController.php deleted file mode 100644 index dd48411..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/ReplicationController.php +++ /dev/null @@ -1,72 +0,0 @@ -getHtmlForErrorMessage(); - - if ($replication_info['master']['status']) { - $masterReplicationHtml = $replicationGui->getHtmlForMasterReplication(); - } - - if (isset($params['mr_configure'])) { - $masterConfigurationHtml = $replicationGui->getHtmlForMasterConfiguration(); - } else { - if (! isset($params['repl_clear_scr'])) { - $slaveConfigurationHtml = $replicationGui->getHtmlForSlaveConfiguration( - $replication_info['slave']['status'], - $server_slave_replication - ); - } - if (isset($params['sl_configure'])) { - $changeMasterHtml = $replicationGui->getHtmlForReplicationChangeMaster('slave_changemaster'); - } - } - - return $this->template->render('server/replication/index', [ - 'url_params' => $url_params, - 'is_super_user' => $this->dbi->isSuperuser(), - 'error_messages' => $errorMessages, - 'is_master' => $replication_info['master']['status'], - 'master_configure' => $params['mr_configure'], - 'slave_configure' => $params['sl_configure'], - 'clear_screen' => $params['repl_clear_scr'], - 'master_replication_html' => $masterReplicationHtml ?? '', - 'master_configuration_html' => $masterConfigurationHtml ?? '', - 'slave_configuration_html' => $slaveConfigurationHtml ?? '', - 'change_master_html' => $changeMasterHtml ?? '', - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/SqlController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/SqlController.php deleted file mode 100644 index fd9ead6..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/SqlController.php +++ /dev/null @@ -1,34 +0,0 @@ -getHtml(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/AbstractController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/AbstractController.php deleted file mode 100644 index 8d4b51d..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/AbstractController.php +++ /dev/null @@ -1,42 +0,0 @@ -data = $data; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/AdvisorController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/AdvisorController.php deleted file mode 100644 index 5b93b0e..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/AdvisorController.php +++ /dev/null @@ -1,60 +0,0 @@ -advisor = $advisor; - } - - /** - * @return string - */ - public function index(): string - { - $data = ''; - if ($this->data->dataLoaded) { - $data = json_encode($this->advisor->run()); - } - - return $this->template->render('server/status/advisor/index', [ - 'data' => $data, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/MonitorController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/MonitorController.php deleted file mode 100644 index 1d2cadc..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/MonitorController.php +++ /dev/null @@ -1,146 +0,0 @@ -monitor = $monitor; - } - - /** - * @return string HTML - */ - public function index(): string - { - $form = [ - 'server_time' => microtime(true) * 1000, - 'server_os' => SysInfo::getOs(), - 'is_superuser' => $this->dbi->isSuperuser(), - 'server_db_isLocal' => $this->data->db_isLocal, - ]; - - $javascriptVariableNames = []; - foreach ($this->data->status as $name => $value) { - if (is_numeric($value)) { - $javascriptVariableNames[] = $name; - } - } - - return $this->template->render('server/status/monitor/index', [ - 'image_path' => $GLOBALS['pmaThemeImage'], - 'javascript_variable_names' => $javascriptVariableNames, - 'form' => $form, - ]); - } - - /** - * @param array $params Request parameters - * @return array JSON - */ - public function chartingData(array $params): array - { - $json = []; - $json['message'] = $this->monitor->getJsonForChartingData( - $params['requiredData'] ?? '' - ); - - return $json; - } - - /** - * @param array $params Request parameters - * @return array JSON - */ - public function logDataTypeSlow(array $params): array - { - $json = []; - $json['message'] = $this->monitor->getJsonForLogDataTypeSlow( - (int) $params['time_start'], - (int) $params['time_end'] - ); - - return $json; - } - - /** - * @param array $params Request parameters - * @return array JSON - */ - public function logDataTypeGeneral(array $params): array - { - $json = []; - $json['message'] = $this->monitor->getJsonForLogDataTypeGeneral( - (int) $params['time_start'], - (int) $params['time_end'], - (bool) $params['limitTypes'], - (bool) $params['removeVariables'] - ); - - return $json; - } - - /** - * @param array $params Request parameters - * @return array JSON - */ - public function loggingVars(array $params): array - { - $json = []; - $json['message'] = $this->monitor->getJsonForLoggingVars( - $params['varName'], - $params['varValue'] - ); - - return $json; - } - - /** - * @param array $params Request parameters - * @return array JSON - */ - public function queryAnalyzer(array $params): array - { - $json = []; - $json['message'] = $this->monitor->getJsonForQueryAnalyzer( - $params['database'] ?? '', - $params['query'] ?? '' - ); - - return $json; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/ProcessesController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/ProcessesController.php deleted file mode 100644 index 9817e1b..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/ProcessesController.php +++ /dev/null @@ -1,240 +0,0 @@ - true, - 'full' => $params['full'] ?? '', - 'column_name' => $params['column_name'] ?? '', - 'order_by_field' => $params['order_by_field'] ?? '', - 'sort_order' => $params['sort_order'] ?? '', - ]; - - $serverProcessList = $this->getList($params); - - return $this->template->render('server/status/processes/index', [ - 'url_params' => $urlParams, - 'is_checked' => $isChecked, - 'server_process_list' => $serverProcessList, - ]); - } - - /** - * Only sends the process list table - * - * @param array $params Request parameters - * @return string - */ - public function refresh(array $params): string - { - return $this->getList($params); - } - - /** - * @param array $params Request parameters - * @return array - */ - public function kill(array $params): array - { - $kill = (int) $params['kill']; - $query = $this->dbi->getKillQuery($kill); - - if ($this->dbi->tryQuery($query)) { - $message = Message::success( - __('Thread %s was successfully killed.') - ); - $this->response->setRequestStatus(true); - } else { - $message = Message::error( - __( - 'phpMyAdmin was unable to kill thread %s.' - . ' It probably has already been closed.' - ) - ); - $this->response->setRequestStatus(false); - } - $message->addParam($kill); - - $json = []; - $json['message'] = $message; - - return $json; - } - - /** - * @param array $params Request parameters - * @return string - */ - private function getList(array $params): string - { - $urlParams = []; - - $showFullSql = ! empty($params['full']); - if ($showFullSql) { - $urlParams['full'] = ''; - } else { - $urlParams['full'] = 1; - } - - // This array contains display name and real column name of each - // sortable column in the table - $sortableColumns = [ - [ - 'column_name' => __('ID'), - 'order_by_field' => 'Id', - ], - [ - 'column_name' => __('User'), - 'order_by_field' => 'User', - ], - [ - 'column_name' => __('Host'), - 'order_by_field' => 'Host', - ], - [ - 'column_name' => __('Database'), - 'order_by_field' => 'db', - ], - [ - 'column_name' => __('Command'), - 'order_by_field' => 'Command', - ], - [ - 'column_name' => __('Time'), - 'order_by_field' => 'Time', - ], - [ - 'column_name' => __('Status'), - 'order_by_field' => 'State', - ], - [ - 'column_name' => __('Progress'), - 'order_by_field' => 'Progress', - ], - [ - 'column_name' => __('SQL query'), - 'order_by_field' => 'Info', - ], - ]; - $sortableColCount = count($sortableColumns); - - $sqlQuery = $showFullSql - ? 'SHOW FULL PROCESSLIST' - : 'SHOW PROCESSLIST'; - if ((! empty($params['order_by_field']) - && ! empty($params['sort_order'])) - || ! empty($params['showExecuting']) - ) { - $urlParams['order_by_field'] = $params['order_by_field']; - $urlParams['sort_order'] = $params['sort_order']; - $urlParams['showExecuting'] = $params['showExecuting']; - $sqlQuery = 'SELECT * FROM `INFORMATION_SCHEMA`.`PROCESSLIST` '; - } - if (! empty($params['showExecuting'])) { - $sqlQuery .= ' WHERE state != "" '; - } - if (! empty($params['order_by_field']) && ! empty($params['sort_order'])) { - $sqlQuery .= ' ORDER BY ' - . Util::backquote($params['order_by_field']) - . ' ' . $params['sort_order']; - } - - $result = $this->dbi->query($sqlQuery); - - $columns = []; - foreach ($sortableColumns as $columnKey => $column) { - $is_sorted = ! empty($params['order_by_field']) - && ! empty($params['sort_order']) - && ($params['order_by_field'] == $column['order_by_field']); - - $column['sort_order'] = 'ASC'; - if ($is_sorted && $params['sort_order'] === 'ASC') { - $column['sort_order'] = 'DESC'; - } - if (isset($params['showExecuting'])) { - $column['showExecuting'] = 'on'; - } - - $columns[$columnKey] = [ - 'name' => $column['column_name'], - 'params' => $column, - 'is_sorted' => $is_sorted, - 'sort_order' => $column['sort_order'], - 'has_full_query' => false, - 'is_full' => false, - ]; - - if (0 === --$sortableColCount) { - $columns[$columnKey]['has_full_query'] = true; - if ($showFullSql) { - $columns[$columnKey]['is_full'] = true; - } - } - } - - $rows = []; - while ($process = $this->dbi->fetchAssoc($result)) { - // Array keys need to modify due to the way it has used - // to display column values - if ((! empty($params['order_by_field']) && ! empty($params['sort_order'])) - || ! empty($params['showExecuting']) - ) { - foreach (array_keys($process) as $key) { - $newKey = ucfirst(mb_strtolower($key)); - if ($newKey !== $key) { - $process[$newKey] = $process[$key]; - unset($process[$key]); - } - } - } - - $rows[] = [ - 'id' => $process['Id'], - 'user' => $process['User'], - 'host' => $process['Host'], - 'db' => ! isset($process['db']) || strlen($process['db']) === 0 ? '' : $process['db'], - 'command' => $process['Command'], - 'time' => $process['Time'], - 'state' => ! empty($process['State']) ? $process['State'] : '---', - 'progress' => ! empty($process['Progress']) ? $process['Progress'] : '---', - 'info' => ! empty($process['Info']) ? Util::formatSql( - $process['Info'], - ! $showFullSql - ) : '---', - ]; - } - - return $this->template->render('server/status/processes/list', [ - 'columns' => $columns, - 'rows' => $rows, - 'refresh_params' => $urlParams, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/QueriesController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/QueriesController.php deleted file mode 100644 index 76430d4..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/QueriesController.php +++ /dev/null @@ -1,75 +0,0 @@ -data->dataLoaded) { - $hourFactor = 3600 / $this->data->status['Uptime']; - $usedQueries = $this->data->used_queries; - $totalQueries = array_sum($usedQueries); - - $stats = [ - 'total' => $totalQueries, - 'per_hour' => $totalQueries * $hourFactor, - 'per_minute' => $totalQueries * 60 / $this->data->status['Uptime'], - 'per_second' => $totalQueries / $this->data->status['Uptime'], - ]; - - // reverse sort by value to show most used statements first - arsort($usedQueries); - - $chart = []; - $querySum = array_sum($usedQueries); - $otherSum = 0; - $queries = []; - foreach ($usedQueries as $key => $value) { - // For the percentage column, use Questions - Connections, because - // the number of connections is not an item of the Query types - // but is included in Questions. Then the total of the percentages is 100. - $name = str_replace(['Com_', '_'], ['', ' '], $key); - // Group together values that make out less than 2% into "Other", but only - // if we have more than 6 fractions already - if ($value < $querySum * 0.02 && count($chart) > 6) { - $otherSum += $value; - } else { - $chart[$name] = $value; - } - - $queries[$key] = [ - 'name' => $name, - 'value' => $value, - 'per_hour' => $value * $hourFactor, - 'percentage' => $value * 100 / $totalQueries, - ]; - } - - if ($otherSum > 0) { - $chart[__('Other')] = $otherSum; - } - } - - return $this->template->render('server/status/queries/index', [ - 'is_data_loaded' => $this->data->dataLoaded, - 'stats' => $stats ?? null, - 'queries' => $queries ?? [], - 'chart' => $chart ?? [], - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/StatusController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/StatusController.php deleted file mode 100644 index 53d78a3..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/StatusController.php +++ /dev/null @@ -1,260 +0,0 @@ -data->dataLoaded) { - $networkTraffic = implode( - ' ', - Util::formatByteDown( - $this->data->status['Bytes_received'] + $this->data->status['Bytes_sent'], - 3, - 1 - ) - ); - $uptime = Util::timespanFormat($this->data->status['Uptime']); - $startTime = Util::localisedDate($this->getStartTime()); - - $traffic = $this->getTrafficInfo(); - - $connections = $this->getConnectionsInfo(); - - // display replication information - if ($replication_info['master']['status'] - || $replication_info['slave']['status'] - ) { - $replication = $this->getReplicationInfo($replicationGui); - } - } - - return $this->template->render('server/status/status/index', [ - 'is_data_loaded' => $this->data->dataLoaded, - 'network_traffic' => $networkTraffic ?? null, - 'uptime' => $uptime ?? null, - 'start_time' => $startTime ?? null, - 'traffic' => $traffic, - 'connections' => $connections, - 'is_master' => $replication_info['master']['status'], - 'is_slave' => $replication_info['slave']['status'], - 'replication' => $replication, - ]); - } - - /** - * @return int - */ - private function getStartTime(): int - { - return (int) $this->dbi->fetchValue( - 'SELECT UNIX_TIMESTAMP() - ' . $this->data->status['Uptime'] - ); - } - - /** - * @return array - */ - private function getTrafficInfo(): array - { - $hourFactor = 3600 / $this->data->status['Uptime']; - - return [ - [ - 'name' => __('Received'), - 'number' => implode( - ' ', - Util::formatByteDown( - $this->data->status['Bytes_received'], - 3, - 1 - ) - ), - 'per_hour' => implode( - ' ', - Util::formatByteDown( - $this->data->status['Bytes_received'] * $hourFactor, - 3, - 1 - ) - ), - ], - [ - 'name' => __('Sent'), - 'number' => implode( - ' ', - Util::formatByteDown( - $this->data->status['Bytes_sent'], - 3, - 1 - ) - ), - 'per_hour' => implode( - ' ', - Util::formatByteDown( - $this->data->status['Bytes_sent'] * $hourFactor, - 3, - 1 - ) - ), - ], - [ - 'name' => __('Total'), - 'number' => implode( - ' ', - Util::formatByteDown( - $this->data->status['Bytes_received'] + $this->data->status['Bytes_sent'], - 3, - 1 - ) - ), - 'per_hour' => implode( - ' ', - Util::formatByteDown( - ($this->data->status['Bytes_received'] + $this->data->status['Bytes_sent']) * $hourFactor, - 3, - 1 - ) - ), - ], - ]; - } - - /** - * @return array - */ - private function getConnectionsInfo(): array - { - $hourFactor = 3600 / $this->data->status['Uptime']; - - $failedAttemptsPercentage = '---'; - $abortedPercentage = '---'; - if ($this->data->status['Connections'] > 0) { - $failedAttemptsPercentage = Util::formatNumber( - $this->data->status['Aborted_connects'] * 100 / $this->data->status['Connections'], - 0, - 2, - true - ) . '%'; - - $abortedPercentage = Util::formatNumber( - $this->data->status['Aborted_clients'] * 100 / $this->data->status['Connections'], - 0, - 2, - true - ) . '%'; - } - - return [ - [ - 'name' => __('Max. concurrent connections'), - 'number' => Util::formatNumber( - $this->data->status['Max_used_connections'], - 0 - ), - 'per_hour' => '---', - 'percentage' => '---', - ], - [ - 'name' => __('Failed attempts'), - 'number' => Util::formatNumber( - $this->data->status['Aborted_connects'], - 4, - 1, - true - ), - 'per_hour' => Util::formatNumber( - $this->data->status['Aborted_connects'] * $hourFactor, - 4, - 2, - true - ), - 'percentage' => $failedAttemptsPercentage, - ], - [ - 'name' => __('Aborted'), - 'number' => Util::formatNumber( - $this->data->status['Aborted_clients'], - 4, - 1, - true - ), - 'per_hour' => Util::formatNumber( - $this->data->status['Aborted_clients'] * $hourFactor, - 4, - 2, - true - ), - 'percentage' => $abortedPercentage, - ], - [ - 'name' => __('Total'), - 'number' => Util::formatNumber( - $this->data->status['Connections'], - 4, - 0 - ), - 'per_hour' => Util::formatNumber( - $this->data->status['Connections'] * $hourFactor, - 4, - 2 - ), - 'percentage' => Util::formatNumber(100, 0, 2) . '%', - ], - ]; - } - - /** - * @param ReplicationGui $replicationGui ReplicationGui instance - * - * @return string - */ - private function getReplicationInfo(ReplicationGui $replicationGui): string - { - global $replication_info, $replication_types; - - $output = ''; - foreach ($replication_types as $type) { - if (isset($replication_info[$type]['status']) - && $replication_info[$type]['status'] - ) { - $output .= $replicationGui->getHtmlForReplicationStatusTable($type); - } - } - - return $output; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/VariablesController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/VariablesController.php deleted file mode 100644 index a17f15f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/Status/VariablesController.php +++ /dev/null @@ -1,639 +0,0 @@ -flush($params['flush']); - } - - if ($this->data->dataLoaded) { - $categories = []; - foreach ($this->data->sections as $sectionId => $sectionName) { - if (isset($this->data->sectionUsed[$sectionId])) { - $categories[$sectionId] = [ - 'id' => $sectionId, - 'name' => $sectionName, - 'is_selected' => false, - ]; - if (! empty($params['filterCategory']) - && $params['filterCategory'] === $sectionId - ) { - $categories[$sectionId]['is_selected'] = true; - } - } - } - - $links = []; - foreach ($this->data->links as $sectionName => $sectionLinks) { - $links[$sectionName] = [ - 'name' => 'status_' . $sectionName, - 'links' => $sectionLinks, - ]; - } - - $descriptions = $this->getDescriptions(); - $alerts = $this->getAlerts(); - - $variables = []; - foreach ($this->data->status as $name => $value) { - $variables[$name] = [ - 'name' => $name, - 'value' => $value, - 'is_numeric' => is_numeric($value), - 'class' => $this->data->allocationMap[$name] ?? null, - 'doc' => '', - 'has_alert' => false, - 'is_alert' => false, - 'description' => $descriptions[$name] ?? '', - 'description_doc' => [], - ]; - - // Fields containing % are calculated, - // they can not be described in MySQL documentation - if (mb_strpos($name, '%') === false) { - $variables[$name]['doc'] = Util::linkToVarDocumentation( - $name, - $this->dbi->isMariaDB() - ); - } - - if (isset($alerts[$name])) { - $variables[$name]['has_alert'] = true; - if ($value > $alerts[$name]) { - $variables[$name]['is_alert'] = true; - } - } - - if (isset($this->data->links[$name])) { - foreach ($this->data->links[$name] as $linkName => $linkUrl) { - $variables[$name]['description_doc'][] = [ - 'name' => $linkName, - 'url' => $linkUrl, - ]; - } - } - } - } - - return $this->template->render('server/status/variables/index', [ - 'is_data_loaded' => $this->data->dataLoaded, - 'filter_text' => ! empty($params['filterText']) ? $params['filterText'] : '', - 'is_only_alerts' => ! empty($params['filterAlert']), - 'is_not_formatted' => ! empty($params['dontFormat']), - 'categories' => $categories ?? [], - 'links' => $links ?? [], - 'variables' => $variables ?? [], - ]); - } - - /** - * Flush status variables if requested - * - * @param string $flush Variable name - * @return void - */ - private function flush(string $flush): void - { - $flushCommands = [ - 'STATUS', - 'TABLES', - 'QUERY CACHE', - ]; - - if (in_array($flush, $flushCommands)) { - $this->dbi->query('FLUSH ' . $flush . ';'); - } - } - - /** - * @return array - */ - private function getAlerts(): array - { - // name => max value before alert - return [ - // lower is better - // variable => max value - 'Aborted_clients' => 0, - 'Aborted_connects' => 0, - - 'Binlog_cache_disk_use' => 0, - - 'Created_tmp_disk_tables' => 0, - - 'Handler_read_rnd' => 0, - 'Handler_read_rnd_next' => 0, - - 'Innodb_buffer_pool_pages_dirty' => 0, - 'Innodb_buffer_pool_reads' => 0, - 'Innodb_buffer_pool_wait_free' => 0, - 'Innodb_log_waits' => 0, - 'Innodb_row_lock_time_avg' => 10, // ms - 'Innodb_row_lock_time_max' => 50, // ms - 'Innodb_row_lock_waits' => 0, - - 'Slow_queries' => 0, - 'Delayed_errors' => 0, - 'Select_full_join' => 0, - 'Select_range_check' => 0, - 'Sort_merge_passes' => 0, - 'Opened_tables' => 0, - 'Table_locks_waited' => 0, - 'Qcache_lowmem_prunes' => 0, - - 'Qcache_free_blocks' => - isset($this->data->status['Qcache_total_blocks']) - ? $this->data->status['Qcache_total_blocks'] / 5 - : 0, - 'Slow_launch_threads' => 0, - - // depends on Key_read_requests - // normally lower then 1:0.01 - 'Key_reads' => isset($this->data->status['Key_read_requests']) - ? (0.01 * $this->data->status['Key_read_requests']) : 0, - // depends on Key_write_requests - // normally nearly 1:1 - 'Key_writes' => isset($this->data->status['Key_write_requests']) - ? (0.9 * $this->data->status['Key_write_requests']) : 0, - - 'Key_buffer_fraction' => 0.5, - - // alert if more than 95% of thread cache is in use - 'Threads_cached' => isset($this->data->variables['thread_cache_size']) - ? 0.95 * $this->data->variables['thread_cache_size'] : 0, - - // higher is better - // variable => min value - //'Handler read key' => '> ', - ]; - } - - /** - * Returns a list of variable descriptions - * - * @return array - */ - private function getDescriptions(): array - { - /** - * Messages are built using the message name - */ - return [ - 'Aborted_clients' => __( - 'The number of connections that were aborted because the client died' - . ' without closing the connection properly.' - ), - 'Aborted_connects' => __( - 'The number of failed attempts to connect to the MySQL server.' - ), - 'Binlog_cache_disk_use' => __( - 'The number of transactions that used the temporary binary log cache' - . ' but that exceeded the value of binlog_cache_size and used a' - . ' temporary file to store statements from the transaction.' - ), - 'Binlog_cache_use' => __( - 'The number of transactions that used the temporary binary log cache.' - ), - 'Connections' => __( - 'The number of connection attempts (successful or not)' - . ' to the MySQL server.' - ), - 'Created_tmp_disk_tables' => __( - 'The number of temporary tables on disk created automatically by' - . ' the server while executing statements. If' - . ' Created_tmp_disk_tables is big, you may want to increase the' - . ' tmp_table_size value to cause temporary tables to be' - . ' memory-based instead of disk-based.' - ), - 'Created_tmp_files' => __( - 'How many temporary files mysqld has created.' - ), - 'Created_tmp_tables' => __( - 'The number of in-memory temporary tables created automatically' - . ' by the server while executing statements.' - ), - 'Delayed_errors' => __( - 'The number of rows written with INSERT DELAYED for which some' - . ' error occurred (probably duplicate key).' - ), - 'Delayed_insert_threads' => __( - 'The number of INSERT DELAYED handler threads in use. Every' - . ' different table on which one uses INSERT DELAYED gets' - . ' its own thread.' - ), - 'Delayed_writes' => __( - 'The number of INSERT DELAYED rows written.' - ), - 'Flush_commands' => __( - 'The number of executed FLUSH statements.' - ), - 'Handler_commit' => __( - 'The number of internal COMMIT statements.' - ), - 'Handler_delete' => __( - 'The number of times a row was deleted from a table.' - ), - 'Handler_discover' => __( - 'The MySQL server can ask the NDB Cluster storage engine if it' - . ' knows about a table with a given name. This is called discovery.' - . ' Handler_discover indicates the number of time tables have been' - . ' discovered.' - ), - 'Handler_read_first' => __( - 'The number of times the first entry was read from an index. If this' - . ' is high, it suggests that the server is doing a lot of full' - . ' index scans; for example, SELECT col1 FROM foo, assuming that' - . ' col1 is indexed.' - ), - 'Handler_read_key' => __( - 'The number of requests to read a row based on a key. If this is' - . ' high, it is a good indication that your queries and tables' - . ' are properly indexed.' - ), - 'Handler_read_next' => __( - 'The number of requests to read the next row in key order. This is' - . ' incremented if you are querying an index column with a range' - . ' constraint or if you are doing an index scan.' - ), - 'Handler_read_prev' => __( - 'The number of requests to read the previous row in key order.' - . ' This read method is mainly used to optimize ORDER BY … DESC.' - ), - 'Handler_read_rnd' => __( - 'The number of requests to read a row based on a fixed position.' - . ' This is high if you are doing a lot of queries that require' - . ' sorting of the result. You probably have a lot of queries that' - . ' require MySQL to scan whole tables or you have joins that' - . ' don\'t use keys properly.' - ), - 'Handler_read_rnd_next' => __( - 'The number of requests to read the next row in the data file.' - . ' This is high if you are doing a lot of table scans. Generally' - . ' this suggests that your tables are not properly indexed or that' - . ' your queries are not written to take advantage of the indexes' - . ' you have.' - ), - 'Handler_rollback' => __( - 'The number of internal ROLLBACK statements.' - ), - 'Handler_update' => __( - 'The number of requests to update a row in a table.' - ), - 'Handler_write' => __( - 'The number of requests to insert a row in a table.' - ), - 'Innodb_buffer_pool_pages_data' => __( - 'The number of pages containing data (dirty or clean).' - ), - 'Innodb_buffer_pool_pages_dirty' => __( - 'The number of pages currently dirty.' - ), - 'Innodb_buffer_pool_pages_flushed' => __( - 'The number of buffer pool pages that have been requested' - . ' to be flushed.' - ), - 'Innodb_buffer_pool_pages_free' => __( - 'The number of free pages.' - ), - 'Innodb_buffer_pool_pages_latched' => __( - 'The number of latched pages in InnoDB buffer pool. These are pages' - . ' currently being read or written or that can\'t be flushed or' - . ' removed for some other reason.' - ), - 'Innodb_buffer_pool_pages_misc' => __( - 'The number of pages busy because they have been allocated for' - . ' administrative overhead such as row locks or the adaptive' - . ' hash index. This value can also be calculated as' - . ' Innodb_buffer_pool_pages_total - Innodb_buffer_pool_pages_free' - . ' - Innodb_buffer_pool_pages_data.' - ), - 'Innodb_buffer_pool_pages_total' => __( - 'Total size of buffer pool, in pages.' - ), - 'Innodb_buffer_pool_read_ahead_rnd' => __( - 'The number of "random" read-aheads InnoDB initiated. This happens' - . ' when a query is to scan a large portion of a table but in' - . ' random order.' - ), - 'Innodb_buffer_pool_read_ahead_seq' => __( - 'The number of sequential read-aheads InnoDB initiated. This' - . ' happens when InnoDB does a sequential full table scan.' - ), - 'Innodb_buffer_pool_read_requests' => __( - 'The number of logical read requests InnoDB has done.' - ), - 'Innodb_buffer_pool_reads' => __( - 'The number of logical reads that InnoDB could not satisfy' - . ' from buffer pool and had to do a single-page read.' - ), - 'Innodb_buffer_pool_wait_free' => __( - 'Normally, writes to the InnoDB buffer pool happen in the' - . ' background. However, if it\'s necessary to read or create a page' - . ' and no clean pages are available, it\'s necessary to wait for' - . ' pages to be flushed first. This counter counts instances of' - . ' these waits. If the buffer pool size was set properly, this' - . ' value should be small.' - ), - 'Innodb_buffer_pool_write_requests' => __( - 'The number writes done to the InnoDB buffer pool.' - ), - 'Innodb_data_fsyncs' => __( - 'The number of fsync() operations so far.' - ), - 'Innodb_data_pending_fsyncs' => __( - 'The current number of pending fsync() operations.' - ), - 'Innodb_data_pending_reads' => __( - 'The current number of pending reads.' - ), - 'Innodb_data_pending_writes' => __( - 'The current number of pending writes.' - ), - 'Innodb_data_read' => __( - 'The amount of data read so far, in bytes.' - ), - 'Innodb_data_reads' => __( - 'The total number of data reads.' - ), - 'Innodb_data_writes' => __( - 'The total number of data writes.' - ), - 'Innodb_data_written' => __( - 'The amount of data written so far, in bytes.' - ), - 'Innodb_dblwr_pages_written' => __( - 'The number of pages that have been written for' - . ' doublewrite operations.' - ), - 'Innodb_dblwr_writes' => __( - 'The number of doublewrite operations that have been performed.' - ), - 'Innodb_log_waits' => __( - 'The number of waits we had because log buffer was too small and' - . ' we had to wait for it to be flushed before continuing.' - ), - 'Innodb_log_write_requests' => __( - 'The number of log write requests.' - ), - 'Innodb_log_writes' => __( - 'The number of physical writes to the log file.' - ), - 'Innodb_os_log_fsyncs' => __( - 'The number of fsync() writes done to the log file.' - ), - 'Innodb_os_log_pending_fsyncs' => __( - 'The number of pending log file fsyncs.' - ), - 'Innodb_os_log_pending_writes' => __( - 'Pending log file writes.' - ), - 'Innodb_os_log_written' => __( - 'The number of bytes written to the log file.' - ), - 'Innodb_pages_created' => __( - 'The number of pages created.' - ), - 'Innodb_page_size' => __( - 'The compiled-in InnoDB page size (default 16KB). Many values are' - . ' counted in pages; the page size allows them to be easily' - . ' converted to bytes.' - ), - 'Innodb_pages_read' => __( - 'The number of pages read.' - ), - 'Innodb_pages_written' => __( - 'The number of pages written.' - ), - 'Innodb_row_lock_current_waits' => __( - 'The number of row locks currently being waited for.' - ), - 'Innodb_row_lock_time_avg' => __( - 'The average time to acquire a row lock, in milliseconds.' - ), - 'Innodb_row_lock_time' => __( - 'The total time spent in acquiring row locks, in milliseconds.' - ), - 'Innodb_row_lock_time_max' => __( - 'The maximum time to acquire a row lock, in milliseconds.' - ), - 'Innodb_row_lock_waits' => __( - 'The number of times a row lock had to be waited for.' - ), - 'Innodb_rows_deleted' => __( - 'The number of rows deleted from InnoDB tables.' - ), - 'Innodb_rows_inserted' => __( - 'The number of rows inserted in InnoDB tables.' - ), - 'Innodb_rows_read' => __( - 'The number of rows read from InnoDB tables.' - ), - 'Innodb_rows_updated' => __( - 'The number of rows updated in InnoDB tables.' - ), - 'Key_blocks_not_flushed' => __( - 'The number of key blocks in the key cache that have changed but' - . ' haven\'t yet been flushed to disk. It used to be known as' - . ' Not_flushed_key_blocks.' - ), - 'Key_blocks_unused' => __( - 'The number of unused blocks in the key cache. You can use this' - . ' value to determine how much of the key cache is in use.' - ), - 'Key_blocks_used' => __( - 'The number of used blocks in the key cache. This value is a' - . ' high-water mark that indicates the maximum number of blocks' - . ' that have ever been in use at one time.' - ), - 'Key_buffer_fraction_%' => __( - 'Percentage of used key cache (calculated value)' - ), - 'Key_read_requests' => __( - 'The number of requests to read a key block from the cache.' - ), - 'Key_reads' => __( - 'The number of physical reads of a key block from disk. If Key_reads' - . ' is big, then your key_buffer_size value is probably too small.' - . ' The cache miss rate can be calculated as' - . ' Key_reads/Key_read_requests.' - ), - 'Key_read_ratio_%' => __( - 'Key cache miss calculated as rate of physical reads compared' - . ' to read requests (calculated value)' - ), - 'Key_write_requests' => __( - 'The number of requests to write a key block to the cache.' - ), - 'Key_writes' => __( - 'The number of physical writes of a key block to disk.' - ), - 'Key_write_ratio_%' => __( - 'Percentage of physical writes compared' - . ' to write requests (calculated value)' - ), - 'Last_query_cost' => __( - 'The total cost of the last compiled query as computed by the query' - . ' optimizer. Useful for comparing the cost of different query' - . ' plans for the same query. The default value of 0 means that' - . ' no query has been compiled yet.' - ), - 'Max_used_connections' => __( - 'The maximum number of connections that have been in use' - . ' simultaneously since the server started.' - ), - 'Not_flushed_delayed_rows' => __( - 'The number of rows waiting to be written in INSERT DELAYED queues.' - ), - 'Opened_tables' => __( - 'The number of tables that have been opened. If opened tables is' - . ' big, your table cache value is probably too small.' - ), - 'Open_files' => __( - 'The number of files that are open.' - ), - 'Open_streams' => __( - 'The number of streams that are open (used mainly for logging).' - ), - 'Open_tables' => __( - 'The number of tables that are open.' - ), - 'Qcache_free_blocks' => __( - 'The number of free memory blocks in query cache. High numbers can' - . ' indicate fragmentation issues, which may be solved by issuing' - . ' a FLUSH QUERY CACHE statement.' - ), - 'Qcache_free_memory' => __( - 'The amount of free memory for query cache.' - ), - 'Qcache_hits' => __( - 'The number of cache hits.' - ), - 'Qcache_inserts' => __( - 'The number of queries added to the cache.' - ), - 'Qcache_lowmem_prunes' => __( - 'The number of queries that have been removed from the cache to' - . ' free up memory for caching new queries. This information can' - . ' help you tune the query cache size. The query cache uses a' - . ' least recently used (LRU) strategy to decide which queries' - . ' to remove from the cache.' - ), - 'Qcache_not_cached' => __( - 'The number of non-cached queries (not cachable, or not cached' - . ' due to the query_cache_type setting).' - ), - 'Qcache_queries_in_cache' => __( - 'The number of queries registered in the cache.' - ), - 'Qcache_total_blocks' => __( - 'The total number of blocks in the query cache.' - ), - 'Rpl_status' => __( - 'The status of failsafe replication (not yet implemented).' - ), - 'Select_full_join' => __( - 'The number of joins that do not use indexes. If this value is' - . ' not 0, you should carefully check the indexes of your tables.' - ), - 'Select_full_range_join' => __( - 'The number of joins that used a range search on a reference table.' - ), - 'Select_range_check' => __( - 'The number of joins without keys that check for key usage after' - . ' each row. (If this is not 0, you should carefully check the' - . ' indexes of your tables.)' - ), - 'Select_range' => __( - 'The number of joins that used ranges on the first table. (It\'s' - . ' normally not critical even if this is big.)' - ), - 'Select_scan' => __( - 'The number of joins that did a full scan of the first table.' - ), - 'Slave_open_temp_tables' => __( - 'The number of temporary tables currently' - . ' open by the slave SQL thread.' - ), - 'Slave_retried_transactions' => __( - 'Total (since startup) number of times the replication slave SQL' - . ' thread has retried transactions.' - ), - 'Slave_running' => __( - 'This is ON if this server is a slave that is connected to a master.' - ), - 'Slow_launch_threads' => __( - 'The number of threads that have taken more than slow_launch_time' - . ' seconds to create.' - ), - 'Slow_queries' => __( - 'The number of queries that have taken more than long_query_time' - . ' seconds.' - ), - 'Sort_merge_passes' => __( - 'The number of merge passes the sort algorithm has had to do.' - . ' If this value is large, you should consider increasing the' - . ' value of the sort_buffer_size system variable.' - ), - 'Sort_range' => __( - 'The number of sorts that were done with ranges.' - ), - 'Sort_rows' => __( - 'The number of sorted rows.' - ), - 'Sort_scan' => __( - 'The number of sorts that were done by scanning the table.' - ), - 'Table_locks_immediate' => __( - 'The number of times that a table lock was acquired immediately.' - ), - 'Table_locks_waited' => __( - 'The number of times that a table lock could not be acquired' - . ' immediately and a wait was needed. If this is high, and you have' - . ' performance problems, you should first optimize your queries,' - . ' and then either split your table or tables or use replication.' - ), - 'Threads_cached' => __( - 'The number of threads in the thread cache. The cache hit rate can' - . ' be calculated as Threads_created/Connections. If this value is' - . ' red you should raise your thread_cache_size.' - ), - 'Threads_connected' => __( - 'The number of currently open connections.' - ), - 'Threads_created' => __( - 'The number of threads created to handle connections. If' - . ' Threads_created is big, you may want to increase the' - . ' thread_cache_size value. (Normally this doesn\'t give a notable' - . ' performance improvement if you have a good thread' - . ' implementation.)' - ), - 'Threads_cache_hitrate_%' => __( - 'Thread cache hit rate (calculated value)' - ), - 'Threads_running' => __( - 'The number of threads that are not sleeping.' - ), - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Server/VariablesController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Server/VariablesController.php deleted file mode 100644 index ad10ec8..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Server/VariablesController.php +++ /dev/null @@ -1,238 +0,0 @@ -response->getHeader(); - $scripts = $header->getScripts(); - $scripts->addFile('server/variables.js'); - - $variables = []; - $serverVarsResult = $this->dbi->tryQuery('SHOW SESSION VARIABLES;'); - if ($serverVarsResult !== false) { - $serverVarsSession = []; - while ($arr = $this->dbi->fetchRow($serverVarsResult)) { - $serverVarsSession[$arr[0]] = $arr[1]; - } - $this->dbi->freeResult($serverVarsResult); - - $serverVars = $this->dbi->fetchResult('SHOW GLOBAL VARIABLES;', 0, 1); - - // list of static (i.e. non-editable) system variables - $staticVariables = KBSearch::getStaticVariables(); - - foreach ($serverVars as $name => $value) { - $hasSessionValue = isset($serverVarsSession[$name]) - && $serverVarsSession[$name] !== $value; - $docLink = Util::linkToVarDocumentation( - $name, - $this->dbi->isMariaDB(), - str_replace('_', ' ', $name) - ); - - list($formattedValue, $isEscaped) = $this->formatVariable($name, $value); - if ($hasSessionValue) { - list($sessionFormattedValue, ) = $this->formatVariable( - $name, - $serverVarsSession[$name] - ); - } - - $variables[] = [ - 'name' => $name, - 'is_editable' => ! in_array(strtolower($name), $staticVariables), - 'doc_link' => $docLink, - 'value' => $formattedValue, - 'is_escaped' => $isEscaped, - 'has_session_value' => $hasSessionValue, - 'session_value' => $sessionFormattedValue ?? null, - ]; - } - } - - return $this->template->render('server/variables/index', [ - 'variables' => $variables, - 'filter_value' => $filterValue, - 'is_superuser' => $this->dbi->isSuperuser(), - 'is_mariadb' => $this->dbi->isMariaDB(), - ]); - } - - /** - * Handle the AJAX request for a single variable value - * - * @param array $params Request parameters - * - * @return array - */ - public function getValue(array $params): array - { - // Send with correct charset - header('Content-Type: text/html; charset=UTF-8'); - // Do not use double quotes inside the query to avoid a problem - // when server is running in ANSI_QUOTES sql_mode - $varValue = $this->dbi->fetchSingleRow( - 'SHOW GLOBAL VARIABLES WHERE Variable_name=\'' - . $this->dbi->escapeString($params['varName']) . '\';', - 'NUM' - ); - - $json = []; - try { - $type = KBSearch::getVariableType($params['varName']); - if ($type === 'byte') { - $json['message'] = implode( - ' ', - Util::formatByteDown($varValue[1], 3, 3) - ); - } else { - throw new KBException("Not a type=byte"); - } - } catch (KBException $e) { - $json['message'] = $varValue[1]; - } - - return $json; - } - - /** - * Handle the AJAX request for setting value for a single variable - * - * @param array $params Request parameters - * - * @return array - */ - public function setValue(array $params): array - { - $value = $params['varValue']; - $matches = []; - try { - $type = KBSearch::getVariableType($params['varName']); - if ($type === 'byte' && preg_match( - '/^\s*(\d+(\.\d+)?)\s*(mb|kb|mib|kib|gb|gib)\s*$/i', - $value, - $matches - )) { - $exp = [ - 'kb' => 1, - 'kib' => 1, - 'mb' => 2, - 'mib' => 2, - 'gb' => 3, - 'gib' => 3, - ]; - $value = floatval($matches[1]) * pow( - 1024, - $exp[mb_strtolower($matches[3])] - ); - } else { - throw new KBException("Not a type=byte or regex not matching"); - } - } catch (KBException $e) { - $value = $this->dbi->escapeString($value); - } - - if (! is_numeric($value)) { - $value = "'" . $value . "'"; - } - - $json = []; - if (! preg_match("/[^a-zA-Z0-9_]+/", $params['varName']) - && $this->dbi->query( - 'SET GLOBAL ' . $params['varName'] . ' = ' . $value - ) - ) { - // Some values are rounded down etc. - $varValue = $this->dbi->fetchSingleRow( - 'SHOW GLOBAL VARIABLES WHERE Variable_name="' - . $this->dbi->escapeString($params['varName']) - . '";', - 'NUM' - ); - list($formattedValue, $isHtmlFormatted) = $this->formatVariable( - $params['varName'], - $varValue[1] - ); - - if ($isHtmlFormatted === false) { - $json['variable'] = htmlspecialchars($formattedValue); - } else { - $json['variable'] = $formattedValue; - } - } else { - $this->response->setRequestStatus(false); - $json['error'] = __('Setting variable failed'); - } - - return $json; - } - - /** - * Format Variable - * - * @param string $name variable name - * @param integer $value variable value - * - * @return array formatted string and bool if string is HTML formatted - */ - private function formatVariable($name, $value) - { - $isHtmlFormatted = false; - $formattedValue = $value; - - if (is_numeric($value)) { - try { - $type = KBSearch::getVariableType($name); - if ($type === 'byte') { - $isHtmlFormatted = true; - $formattedValue = '' - . htmlspecialchars( - implode(' ', Util::formatByteDown($value, 3, 3)) - ) - . ''; - } else { - throw new KBException("Not a type=byte or regex not matching"); - } - } catch (KBException $e) { - $formattedValue = Util::formatNumber($value, 0); - } - } - - return [ - $formattedValue, - $isHtmlFormatted, - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Setup/AbstractController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Setup/AbstractController.php deleted file mode 100644 index 8dae377..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Setup/AbstractController.php +++ /dev/null @@ -1,70 +0,0 @@ -config = $config; - $this->template = $template; - } - - /** - * @return array - */ - protected function getPages(): array - { - $ignored = [ - 'Config', - 'Servers', - ]; - $pages = []; - foreach (SetupFormList::getAll() as $formset) { - if (in_array($formset, $ignored)) { - continue; - } - /** @var BaseForm $formClass */ - $formClass = SetupFormList::get($formset); - - $pages[$formset] = [ - 'name' => $formClass::getName(), - 'formset' => $formset, - ]; - } - - return $pages; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Setup/ConfigController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Setup/ConfigController.php deleted file mode 100644 index f6e37a2..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Setup/ConfigController.php +++ /dev/null @@ -1,55 +0,0 @@ -getPages(); - - $formDisplayTemplate = new FormDisplayTemplate($GLOBALS['PMA_Config']); - - $formTop = $formDisplayTemplate->displayFormTop('config.php'); - $fieldsetTop = $formDisplayTemplate->displayFieldsetTop( - 'config.inc.php', - '', - null, - ['class' => 'simple'] - ); - $formBottom = $formDisplayTemplate->displayFieldsetBottom(false); - $fieldsetBottom = $formDisplayTemplate->displayFormBottom(); - - $config = ConfigGenerator::getConfigFile($this->config); - - return $this->template->render('setup/config/index', [ - 'formset' => $params['formset'] ?? '', - 'pages' => $pages, - 'form_top_html' => $formTop, - 'fieldset_top_html' => $fieldsetTop, - 'form_bottom_html' => $formBottom, - 'fieldset_bottom_html' => $fieldsetBottom, - 'eol' => Core::ifSetOr($params['eol'], 'unix'), - 'config' => $config, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Setup/FormController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Setup/FormController.php deleted file mode 100644 index c2caf01..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Setup/FormController.php +++ /dev/null @@ -1,50 +0,0 @@ -getPages(); - - $formset = Core::isValid($params['formset'], 'scalar') ? $params['formset'] : null; - - /** @var BaseForm $formClass */ - $formClass = SetupFormList::get($formset); - if ($formClass === null) { - Core::fatalError(__('Incorrect form specified!')); - } - - ob_start(); - FormProcessing::process(new $formClass($this->config)); - $page = ob_get_clean(); - - return $this->template->render('setup/form/index', [ - 'formset' => $params['formset'] ?? '', - 'pages' => $pages, - 'name' => $formClass::getName(), - 'page' => $page, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Setup/HomeController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Setup/HomeController.php deleted file mode 100644 index 37e3ea2..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Setup/HomeController.php +++ /dev/null @@ -1,228 +0,0 @@ -getPages(); - - // Handle done action info - $actionDone = Core::isValid($params['action_done'], 'scalar') ? $params['action_done'] : null; - $actionDone = preg_replace('/[^a-z_]/', '', $actionDone); - - // message handling - Index::messagesBegin(); - - // Check phpMyAdmin version - if (isset($params['version_check'])) { - Index::versionCheck(); - } - - // Perform various security, compatibility and consistency checks - $configChecker = new ServerConfigChecks($this->config); - $configChecker->performConfigChecks(); - - $text = __( - 'You are not using a secure connection; all data (including potentially ' - . 'sensitive information, like passwords) is transferred unencrypted!' - ); - $text .= ' '; - $text .= __( - 'If your server is also configured to accept HTTPS requests ' - . 'follow this link to use a secure connection.' - ); - $text .= ''; - Index::messagesSet('notice', 'no_https', __('Insecure connection'), $text); - - // Check for done action info and set notice message if present - switch ($actionDone) { - case 'config_saved': - /* Use uniqid to display this message every time configuration is saved */ - Index::messagesSet( - 'notice', - uniqid('config_saved'), - __('Configuration saved.'), - Sanitize::sanitizeMessage( - __( - 'Configuration saved to file config/config.inc.php in phpMyAdmin ' - . 'top level directory, copy it to top level one and delete ' - . 'directory config to use it.' - ) - ) - ); - break; - case 'config_not_saved': - /* Use uniqid to display this message every time configuration is saved */ - Index::messagesSet( - 'notice', - uniqid('config_not_saved'), - __('Configuration not saved!'), - Sanitize::sanitizeMessage( - __( - 'Please create web server writable folder [em]config[/em] in ' - . 'phpMyAdmin top level directory as described in ' - . '[doc@setup_script]documentation[/doc]. Otherwise you will be ' - . 'only able to download or display it.' - ) - ) - ); - break; - default: - break; - } - - Index::messagesEnd(); - $messages = Index::messagesShowHtml(); - - $formDisplay = new FormDisplay($this->config); - - $defaultLanguageOptions = [ - 'doc' => $formDisplay->getDocLink('DefaultLang'), - 'values' => [], - 'values_escaped' => true, - ]; - - // prepare unfiltered language list - $sortedLanguages = LanguageManager::getInstance()->sortedLanguages(); - $languages = []; - foreach ($sortedLanguages as $language) { - $languages[] = [ - 'code' => $language->getCode(), - 'name' => $language->getName(), - 'is_active' => $language->isActive(), - ]; - $defaultLanguageOptions['values'][$language->getCode()] = $language->getName(); - } - - $serverDefaultOptions = [ - 'doc' => $formDisplay->getDocLink('ServerDefault'), - 'values' => [], - 'values_disabled' => [], - ]; - - $servers = []; - if ($this->config->getServerCount() > 0) { - $serverDefaultOptions['values']['0'] = __('let the user choose'); - $serverDefaultOptions['values']['-'] = '------------------------------'; - if ($this->config->getServerCount() === 1) { - $serverDefaultOptions['values_disabled'][] = '0'; - } - $serverDefaultOptions['values_disabled'][] = '-'; - - foreach ($this->config->getServers() as $id => $server) { - $servers[$id] = [ - 'id' => $id, - 'name' => $this->config->getServerName($id), - 'auth_type' => $this->config->getValue("Servers/$id/auth_type"), - 'dsn' => $this->config->getServerDSN($id), - 'params' => [ - 'token' => $_SESSION[' PMA_token '], - 'edit' => [ - 'page' => 'servers', - 'mode' => 'edit', - 'id' => $id, - ], - 'remove' => [ - 'page' => 'servers', - 'mode' => 'remove', - 'id' => $id, - ], - ], - ]; - $serverDefaultOptions['values'][(string) $id] = $this->config->getServerName($id) . " [$id]"; - } - } else { - $serverDefaultOptions['values']['1'] = __('- none -'); - $serverDefaultOptions['values_escaped'] = true; - } - - $formDisplayTemplate = new FormDisplayTemplate($GLOBALS['PMA_Config']); - $serversFormTopHtml = $formDisplayTemplate->displayFormTop( - 'index.php', - 'get', - [ - 'page' => 'servers', - 'mode' => 'add', - ] - ); - $configFormTopHtml = $formDisplayTemplate->displayFormTop('config.php'); - $formBottomHtml = $formDisplayTemplate->displayFormBottom(); - - $defaultLanguageInput = $formDisplayTemplate->displayInput( - 'DefaultLang', - __('Default language'), - 'select', - $this->config->getValue('DefaultLang'), - '', - true, - $defaultLanguageOptions - ); - $serverDefaultInput = $formDisplayTemplate->displayInput( - 'ServerDefault', - __('Default server'), - 'select', - $this->config->getValue('ServerDefault'), - '', - true, - $serverDefaultOptions - ); - - $eolOptions = [ - 'values' => [ - 'unix' => 'UNIX / Linux (\n)', - 'win' => 'Windows (\r\n)', - ], - 'values_escaped' => true, - ]; - $eol = Core::ifSetOr($_SESSION['eol'], (PMA_IS_WINDOWS ? 'win' : 'unix')); - $eolInput = $formDisplayTemplate->displayInput( - 'eol', - __('End of line'), - 'select', - $eol, - '', - true, - $eolOptions - ); - - return $this->template->render('setup/home/index', [ - 'formset' => $params['formset'] ?? '', - 'languages' => $languages, - 'messages' => $messages, - 'servers_form_top_html' => $serversFormTopHtml, - 'config_form_top_html' => $configFormTopHtml, - 'form_bottom_html' => $formBottomHtml, - 'server_count' => $this->config->getServerCount(), - 'servers' => $servers, - 'default_language_input' => $defaultLanguageInput, - 'server_default_input' => $serverDefaultInput, - 'eol_input' => $eolInput, - 'pages' => $pages, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Setup/ServersController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Setup/ServersController.php deleted file mode 100644 index eedb94e..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Setup/ServersController.php +++ /dev/null @@ -1,66 +0,0 @@ -getPages(); - - $id = Core::isValid($params['id'], 'numeric') ? (int) $params['id'] : null; - $hasServer = ! empty($id) && $this->config->get("Servers/$id") !== null; - - if (! $hasServer && ($params['mode'] !== 'revert' && $params['mode'] !== 'edit')) { - $id = 0; - } - - ob_start(); - FormProcessing::process(new ServersForm($this->config, $id)); - $page = ob_get_clean(); - - return $this->template->render('setup/servers/index', [ - 'formset' => $params['formset'] ?? '', - 'pages' => $pages, - 'has_server' => $hasServer, - 'mode' => $params['mode'], - 'server_id' => $id, - 'server_dsn' => $this->config->getServerDSN($id), - 'page' => $page, - ]); - } - - /** - * @param array $params Request parameters - * @return void - */ - public function destroy(array $params): void - { - $id = Core::isValid($params['id'], 'numeric') ? (int) $params['id'] : null; - - $hasServer = ! empty($id) && $this->config->get("Servers/$id") !== null; - - if ($hasServer) { - $this->config->removeServer($id); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Table/AbstractController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Table/AbstractController.php deleted file mode 100644 index 35f01ac..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Table/AbstractController.php +++ /dev/null @@ -1,54 +0,0 @@ -db = $db; - $this->table = $table; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Table/ChartController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Table/ChartController.php deleted file mode 100644 index b2c4176..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Table/ChartController.php +++ /dev/null @@ -1,261 +0,0 @@ -sql_query = $sql_query; - $this->url_query = $url_query; - $this->cfg = $cfg; - } - - /** - * Execute the query and return the result - * - * @return void - */ - public function indexAction() - { - $response = Response::getInstance(); - if ($response->isAjax() - && isset($_REQUEST['pos']) - && isset($_REQUEST['session_max_rows']) - ) { - $this->ajaxAction(); - return; - } - - // Throw error if no sql query is set - if (! isset($this->sql_query) || $this->sql_query == '') { - $this->response->setRequestStatus(false); - $this->response->addHTML( - Message::error(__('No SQL query was set to fetch data.')) - ); - return; - } - - $this->response->getHeader()->getScripts()->addFiles( - [ - 'chart.js', - 'table/chart.js', - 'vendor/jqplot/jquery.jqplot.js', - 'vendor/jqplot/plugins/jqplot.barRenderer.js', - 'vendor/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js', - 'vendor/jqplot/plugins/jqplot.canvasTextRenderer.js', - 'vendor/jqplot/plugins/jqplot.categoryAxisRenderer.js', - 'vendor/jqplot/plugins/jqplot.dateAxisRenderer.js', - 'vendor/jqplot/plugins/jqplot.pointLabels.js', - 'vendor/jqplot/plugins/jqplot.pieRenderer.js', - 'vendor/jqplot/plugins/jqplot.enhancedPieLegendRenderer.js', - 'vendor/jqplot/plugins/jqplot.highlighter.js', - ] - ); - - /** - * Extract values for common work - * @todo Extract common files - */ - $db = &$this->db; - $table = &$this->table; - $url_params = []; - - /** - * Runs common work - */ - if (strlen($this->table) > 0) { - $url_params['goto'] = Util::getScriptNameForOption( - $this->cfg['DefaultTabTable'], - 'table' - ); - $url_params['back'] = 'tbl_sql.php'; - include ROOT_PATH . 'libraries/tbl_common.inc.php'; - $this->dbi->selectDb($GLOBALS['db']); - } elseif (strlen($this->db) > 0) { - $url_params['goto'] = Util::getScriptNameForOption( - $this->cfg['DefaultTabDatabase'], - 'database' - ); - $url_params['back'] = 'sql.php'; - include ROOT_PATH . 'libraries/db_common.inc.php'; - } else { - $url_params['goto'] = Util::getScriptNameForOption( - $this->cfg['DefaultTabServer'], - 'server' - ); - $url_params['back'] = 'sql.php'; - include ROOT_PATH . 'libraries/server_common.inc.php'; - } - - $data = []; - - $result = $this->dbi->tryQuery($this->sql_query); - $fields_meta = $this->dbi->getFieldsMeta($result); - while ($row = $this->dbi->fetchAssoc($result)) { - $data[] = $row; - } - - $keys = array_keys($data[0]); - - $numeric_types = [ - 'int', - 'real', - ]; - $numeric_column_count = 0; - foreach ($keys as $idx => $key) { - if (in_array($fields_meta[$idx]->type, $numeric_types)) { - $numeric_column_count++; - } - } - - if ($numeric_column_count == 0) { - $this->response->setRequestStatus(false); - $this->response->addJSON( - 'message', - __('No numeric columns present in the table to plot.') - ); - return; - } - - $url_params['db'] = $this->db; - $url_params['reload'] = 1; - - /** - * Displays the page - */ - $this->response->addHTML( - $this->template->render('table/chart/tbl_chart', [ - 'url_query' => $this->url_query, - 'url_params' => $url_params, - 'keys' => $keys, - 'fields_meta' => $fields_meta, - 'numeric_types' => $numeric_types, - 'numeric_column_count' => $numeric_column_count, - 'sql_query' => $this->sql_query, - ]) - ); - } - - /** - * Handle ajax request - * - * @return void - */ - public function ajaxAction() - { - /** - * Extract values for common work - * @todo Extract common files - */ - $db = &$this->db; - $table = &$this->table; - - if (strlen($this->table) > 0 && strlen($this->db) > 0) { - include ROOT_PATH . 'libraries/tbl_common.inc.php'; - } - - $parser = new Parser($this->sql_query); - /** - * @var SelectStatement $statement - */ - $statement = $parser->statements[0]; - if (empty($statement->limit)) { - $statement->limit = new Limit( - $_REQUEST['session_max_rows'], - $_REQUEST['pos'] - ); - } else { - $start = $statement->limit->offset + $_REQUEST['pos']; - $rows = min( - $_REQUEST['session_max_rows'], - $statement->limit->rowCount - $_REQUEST['pos'] - ); - $statement->limit = new Limit($rows, $start); - } - $sql_with_limit = $statement->build(); - - $data = []; - $result = $this->dbi->tryQuery($sql_with_limit); - while ($row = $this->dbi->fetchAssoc($result)) { - $data[] = $row; - } - - if (empty($data)) { - $this->response->setRequestStatus(false); - $this->response->addJSON('message', __('No data to display')); - return; - } - $sanitized_data = []; - - foreach ($data as $data_row_number => $data_row) { - $tmp_row = []; - foreach ($data_row as $data_column => $data_value) { - $escaped_value = $data_value === null ? null : htmlspecialchars($data_value); - $tmp_row[htmlspecialchars($data_column)] = $escaped_value; - } - $sanitized_data[] = $tmp_row; - } - $this->response->setRequestStatus(true); - $this->response->addJSON('message', null); - $this->response->addJSON('chartData', json_encode($sanitized_data)); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Table/GisVisualizationController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Table/GisVisualizationController.php deleted file mode 100644 index 18e844f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Table/GisVisualizationController.php +++ /dev/null @@ -1,227 +0,0 @@ -sql_query = $sql_query; - $this->url_params = $url_params; - $this->url_params['goto'] = $goto; - $this->url_params['back'] = $back; - $this->visualizationSettings = $visualizationSettings; - } - - /** - * Save to file - * - * @return void - */ - public function saveToFileAction() - { - $this->response->disable(); - $file_name = $this->visualizationSettings['spatialColumn']; - $save_format = $_GET['fileFormat']; - $this->visualization->toFile($file_name, $save_format); - } - - /** - * Index - * - * @return void - */ - public function indexAction() - { - // Throw error if no sql query is set - if (! isset($this->sql_query) || $this->sql_query == '') { - $this->response->setRequestStatus(false); - $this->response->addHTML( - Message::error(__('No SQL query was set to fetch data.')) - ); - return; - } - - // Execute the query and return the result - $result = $this->dbi->tryQuery($this->sql_query); - // Get the meta data of results - $meta = $this->dbi->getFieldsMeta($result); - - // Find the candidate fields for label column and spatial column - $labelCandidates = []; - $spatialCandidates = []; - foreach ($meta as $column_meta) { - if ($column_meta->type == 'geometry') { - $spatialCandidates[] = $column_meta->name; - } else { - $labelCandidates[] = $column_meta->name; - } - } - - // Get settings if any posted - if (Core::isValid($_POST['visualizationSettings'], 'array')) { - $this->visualizationSettings = $_POST['visualizationSettings']; - } - - // Check mysql version - $this->visualizationSettings['mysqlVersion'] = $this->dbi->getVersion(); - - if (! isset($this->visualizationSettings['labelColumn']) - && isset($labelCandidates[0]) - ) { - $this->visualizationSettings['labelColumn'] = ''; - } - - // If spatial column is not set, use first geometric column as spatial column - if (! isset($this->visualizationSettings['spatialColumn'])) { - $this->visualizationSettings['spatialColumn'] = $spatialCandidates[0]; - } - - // Convert geometric columns from bytes to text. - $pos = isset($_GET['pos']) ? $_GET['pos'] - : $_SESSION['tmpval']['pos']; - if (isset($_GET['session_max_rows'])) { - $rows = $_GET['session_max_rows']; - } else { - if ($_SESSION['tmpval']['max_rows'] != 'all') { - $rows = $_SESSION['tmpval']['max_rows']; - } else { - $rows = $GLOBALS['cfg']['MaxRows']; - } - } - $this->visualization = GisVisualization::get( - $this->sql_query, - $this->visualizationSettings, - $rows, - $pos - ); - - if (isset($_GET['saveToFile'])) { - $this->saveToFileAction(); - return; - } - - $this->response->getHeader()->getScripts()->addFiles( - [ - 'vendor/openlayers/OpenLayers.js', - 'vendor/jquery/jquery.svg.js', - 'table/gis_visualization.js', - ] - ); - - // If all the rows contain SRID, use OpenStreetMaps on the initial loading. - if (! isset($_POST['displayVisualization'])) { - if ($this->visualization->hasSrid()) { - $this->visualizationSettings['choice'] = 'useBaseLayer'; - } else { - unset($this->visualizationSettings['choice']); - } - } - - $this->visualization->setUserSpecifiedSettings($this->visualizationSettings); - if ($this->visualizationSettings != null) { - foreach ($this->visualization->getSettings() as $setting => $val) { - if (! isset($this->visualizationSettings[$setting])) { - $this->visualizationSettings[$setting] = $val; - } - } - } - - /** - * Displays the page - */ - $this->url_params['sql_query'] = $this->sql_query; - $downloadUrl = 'tbl_gis_visualization.php' . Url::getCommon( - array_merge( - $this->url_params, - [ - 'saveToFile' => true, - 'session_max_rows' => $rows, - 'pos' => $pos, - ] - ) - ); - $html = $this->template->render('table/gis_visualization/gis_visualization', [ - 'url_params' => $this->url_params, - 'download_url' => $downloadUrl, - 'label_candidates' => $labelCandidates, - 'spatial_candidates' => $spatialCandidates, - 'visualization_settings' => $this->visualizationSettings, - 'sql_query' => $this->sql_query, - 'visualization' => $this->visualization->toImage('svg'), - 'draw_ol' => $this->visualization->asOl(), - 'pma_theme_image' => $GLOBALS['pmaThemeImage'], - ]); - - $this->response->addHTML($html); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Table/IndexesController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Table/IndexesController.php deleted file mode 100644 index cdbfbb9..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Table/IndexesController.php +++ /dev/null @@ -1,179 +0,0 @@ -index = $index; - } - - /** - * Index - * - * @return void - */ - public function indexAction() - { - if (isset($_POST['do_save_data'])) { - $this->doSaveDataAction(); - return; - } // end builds the new index - - $this->displayFormAction(); - } - - /** - * Display the form to edit/create an index - * - * @return void - */ - public function displayFormAction() - { - $this->dbi->selectDb($GLOBALS['db']); - $add_fields = 0; - if (isset($_POST['index']) && is_array($_POST['index'])) { - // coming already from form - if (isset($_POST['index']['columns']['names'])) { - $add_fields = count($_POST['index']['columns']['names']) - - $this->index->getColumnCount(); - } - if (isset($_POST['add_fields'])) { - $add_fields += $_POST['added_fields']; - } - } elseif (isset($_POST['create_index'])) { - $add_fields = $_POST['added_fields']; - } // end preparing form values - - // Get fields and stores their name/type - if (isset($_POST['create_edit_table'])) { - $fields = json_decode($_POST['columns'], true); - $index_params = [ - 'Non_unique' => $_POST['index']['Index_choice'] == 'UNIQUE' - ? '0' : '1', - ]; - $this->index->set($index_params); - $add_fields = count($fields); - } else { - $fields = $this->dbi->getTable($this->db, $this->table) - ->getNameAndTypeOfTheColumns(); - } - - $form_params = [ - 'db' => $this->db, - 'table' => $this->table, - ]; - - if (isset($_POST['create_index'])) { - $form_params['create_index'] = 1; - } elseif (isset($_POST['old_index'])) { - $form_params['old_index'] = $_POST['old_index']; - } elseif (isset($_POST['index'])) { - $form_params['old_index'] = $_POST['index']; - } - - $this->response->getHeader()->getScripts()->addFile('indexes.js'); - - $this->response->addHTML( - $this->template->render('table/index_form', [ - 'fields' => $fields, - 'index' => $this->index, - 'form_params' => $form_params, - 'add_fields' => $add_fields, - 'create_edit_table' => isset($_POST['create_edit_table']), - 'default_sliders_state' => $GLOBALS['cfg']['InitialSlidersState'], - ]) - ); - } - - /** - * Process the data from the edit/create index form, - * run the query to build the new index - * and moves back to "tbl_sql.php" - * - * @return void - */ - public function doSaveDataAction() - { - $error = false; - - $sql_query = $this->dbi->getTable($this->db, $this->table) - ->getSqlQueryForIndexCreateOrEdit($this->index, $error); - - // If there is a request for SQL previewing. - if (isset($_POST['preview_sql'])) { - $this->response->addJSON( - 'sql_data', - $this->template->render('preview_sql', ['query_data' => $sql_query]) - ); - } elseif (! $error) { - $this->dbi->query($sql_query); - $response = Response::getInstance(); - if ($response->isAjax()) { - $message = Message::success( - __('Table %1$s has been altered successfully.') - ); - $message->addParam($this->table); - $this->response->addJSON( - 'message', - Util::getMessage($message, $sql_query, 'success') - ); - $this->response->addJSON( - 'index_table', - Index::getHtmlForIndexes( - $this->table, - $this->db - ) - ); - } else { - include ROOT_PATH . 'tbl_structure.php'; - } - } else { - $this->response->setRequestStatus(false); - $this->response->addJSON('message', $error); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Table/RelationController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Table/RelationController.php deleted file mode 100644 index 558842c..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Table/RelationController.php +++ /dev/null @@ -1,398 +0,0 @@ -options_array = $options_array; - $this->cfgRelation = $cfgRelation; - $this->tbl_storage_engine = $tbl_storage_engine; - $this->existrel = $existrel; - $this->existrel_foreign = $existrel_foreign; - $this->upd_query = $upd_query; - $this->relation = $relation; - } - - /** - * Index - * - * @return void - */ - public function indexAction() - { - // Send table of column names to populate corresponding dropdowns depending - // on the current selection - if (isset($_POST['getDropdownValues']) - && $_POST['getDropdownValues'] === 'true' - ) { - // if both db and table are selected - if (isset($_POST['foreignTable'])) { - $this->getDropdownValueForTableAction(); - } else { // if only the db is selected - $this->getDropdownValueForDbAction(); - } - return; - } - - $this->response->getHeader()->getScripts()->addFiles( - [ - 'table/relation.js', - 'indexes.js', - ] - ); - - // Set the database - $this->dbi->selectDb($this->db); - - // updates for Internal relations - if (isset($_POST['destination_db']) && $this->cfgRelation['relwork']) { - $this->updateForInternalRelationAction(); - } - - // updates for foreign keys - $this->updateForForeignKeysAction(); - - // Updates for display field - if ($this->cfgRelation['displaywork'] && isset($_POST['display_field'])) { - $this->updateForDisplayField(); - } - - // If we did an update, refresh our data - if (isset($_POST['destination_db']) && $this->cfgRelation['relwork']) { - $this->existrel = $this->relation->getForeigners( - $this->db, - $this->table, - '', - 'internal' - ); - } - if (isset($_POST['destination_foreign_db']) - && Util::isForeignKeySupported($this->tbl_storage_engine) - ) { - $this->existrel_foreign = $this->relation->getForeigners( - $this->db, - $this->table, - '', - 'foreign' - ); - } - - /** - * Dialog - */ - // Now find out the columns of our $table - // need to use DatabaseInterface::QUERY_STORE with $this->dbi->numRows() - // in mysqli - $columns = $this->dbi->getColumns($this->db, $this->table); - - $column_array = []; - $column_hash_array = []; - $column_array[''] = ''; - foreach ($columns as $column) { - if (strtoupper($this->tbl_storage_engine) == 'INNODB' - || ! empty($column['Key']) - ) { - $column_array[$column['Field']] = $column['Field']; - $column_hash_array[$column['Field']] = md5($column['Field']); - } - } - if ($GLOBALS['cfg']['NaturalOrder']) { - uksort($column_array, 'strnatcasecmp'); - } - - // common form - $engine = $this->dbi->getTable($this->db, $this->table)->getStorageEngine(); - $foreignKeySupported = Util::isForeignKeySupported($this->tbl_storage_engine); - $this->response->addHTML( - $this->template->render('table/relation/common_form', [ - 'is_foreign_key_supported' => Util::isForeignKeySupported($engine), - 'db' => $this->db, - 'table' => $this->table, - 'cfg_relation' => $this->cfgRelation, - 'tbl_storage_engine' => $this->tbl_storage_engine, - 'existrel' => isset($this->existrel) ? $this->existrel : [], - 'existrel_foreign' => is_array($this->existrel_foreign) && array_key_exists('foreign_keys_data', $this->existrel_foreign) - ? $this->existrel_foreign['foreign_keys_data'] : [], - 'options_array' => $this->options_array, - 'column_array' => $column_array, - 'column_hash_array' => $column_hash_array, - 'save_row' => array_values($columns), - 'url_params' => $GLOBALS['url_params'], - 'databases' => $GLOBALS['dblist']->databases, - 'dbi' => $this->dbi, - 'default_sliders_state' => $GLOBALS['cfg']['InitialSlidersState'], - 'foreignKeySupported' => $foreignKeySupported, - 'displayIndexesHtml' => $foreignKeySupported ? Index::getHtmlForDisplayIndexes() : null, - ]) - ); - } - - /** - * Update for display field - * - * @return void - */ - public function updateForDisplayField() - { - if ($this->upd_query->updateDisplayField( - $_POST['display_field'], - $this->cfgRelation - ) - ) { - $this->response->addHTML( - Util::getMessage( - __('Display column was successfully updated.'), - '', - 'success' - ) - ); - } - } - - /** - * Update for FK - * - * @return void - */ - public function updateForForeignKeysAction() - { - $multi_edit_columns_name = isset($_POST['foreign_key_fields_name']) - ? $_POST['foreign_key_fields_name'] - : null; - $preview_sql_data = ''; - $seen_error = false; - - // (for now, one index name only; we keep the definitions if the - // foreign db is not the same) - if (isset($_POST['destination_foreign_db']) - && isset($_POST['destination_foreign_table']) - && isset($_POST['destination_foreign_column'])) { - list($html, $preview_sql_data, $display_query, $seen_error) - = $this->upd_query->updateForeignKeys( - $_POST['destination_foreign_db'], - $multi_edit_columns_name, - $_POST['destination_foreign_table'], - $_POST['destination_foreign_column'], - $this->options_array, - $this->table, - is_array($this->existrel_foreign) && array_key_exists('foreign_keys_data', $this->existrel_foreign) - ? $this->existrel_foreign['foreign_keys_data'] : [] - ); - $this->response->addHTML($html); - } - - // If there is a request for SQL previewing. - if (isset($_POST['preview_sql'])) { - Core::previewSQL($preview_sql_data); - } - - if (! empty($display_query) && ! $seen_error) { - $GLOBALS['display_query'] = $display_query; - $this->response->addHTML( - Util::getMessage( - __('Your SQL query has been executed successfully.'), - null, - 'success' - ) - ); - } - } - - /** - * Update for internal relation - * - * @return void - */ - public function updateForInternalRelationAction() - { - $multi_edit_columns_name = isset($_POST['fields_name']) - ? $_POST['fields_name'] - : null; - - if ($this->upd_query->updateInternalRelations( - $multi_edit_columns_name, - $_POST['destination_db'], - $_POST['destination_table'], - $_POST['destination_column'], - $this->cfgRelation, - isset($this->existrel) ? $this->existrel : null - ) - ) { - $this->response->addHTML( - Util::getMessage( - __('Internal relationships were successfully updated.'), - '', - 'success' - ) - ); - } - } - - /** - * Send table columns for foreign table dropdown - * - * @return void - * - */ - public function getDropdownValueForTableAction() - { - $foreignTable = $_POST['foreignTable']; - $table_obj = $this->dbi->getTable($_POST['foreignDb'], $foreignTable); - // Since views do not have keys defined on them provide the full list of - // columns - if ($table_obj->isView()) { - $columnList = $table_obj->getColumns(false, false); - } else { - $columnList = $table_obj->getIndexedColumns(false, false); - } - $columns = []; - foreach ($columnList as $column) { - $columns[] = htmlspecialchars($column); - } - if ($GLOBALS['cfg']['NaturalOrder']) { - usort($columns, 'strnatcasecmp'); - } - $this->response->addJSON('columns', $columns); - - // @todo should be: $server->db($db)->table($table)->primary() - $primary = Index::getPrimary($foreignTable, $_POST['foreignDb']); - if (false === $primary) { - return; - } - - $this->response->addJSON('primary', array_keys($primary->getColumns())); - } - - /** - * Send database selection values for dropdown - * - * @return void - * - */ - public function getDropdownValueForDbAction() - { - $tables = []; - $foreign = isset($_POST['foreign']) && $_POST['foreign'] === 'true'; - - if ($foreign) { - $query = 'SHOW TABLE STATUS FROM ' - . Util::backquote($_POST['foreignDb']); - $tables_rs = $this->dbi->query( - $query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - - while ($row = $this->dbi->fetchArray($tables_rs)) { - if (isset($row['Engine']) - && mb_strtoupper($row['Engine']) == $this->tbl_storage_engine - ) { - $tables[] = htmlspecialchars($row['Name']); - } - } - } else { - $query = 'SHOW TABLES FROM ' - . Util::backquote($_POST['foreignDb']); - $tables_rs = $this->dbi->query( - $query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - while ($row = $this->dbi->fetchArray($tables_rs)) { - $tables[] = htmlspecialchars($row[0]); - } - } - if ($GLOBALS['cfg']['NaturalOrder']) { - usort($tables, 'strnatcasecmp'); - } - $this->response->addJSON('tables', $tables); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Table/SearchController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Table/SearchController.php deleted file mode 100644 index 3f2ceae..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Table/SearchController.php +++ /dev/null @@ -1,1244 +0,0 @@ -url_query = $url_query; - $this->_searchType = $searchType; - $this->_columnNames = []; - $this->_columnNullFlags = []; - $this->_columnTypes = []; - $this->_columnCollations = []; - $this->_geomColumnFlag = false; - $this->_foreigners = []; - $this->relation = $relation; - // Loads table's information - $this->_loadTableInfo(); - $this->_connectionCharSet = $this->dbi->fetchValue( - "SELECT @@character_set_connection" - ); - } - - /** - * 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 = $this->dbi->getColumns( - $this->db, - $this->table, - null, - true - ); - // Get details about the geometry functions - $geom_types = 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 = str_ireplace("BINARY", '', $type); - } - $type = str_ireplace("ZEROFILL", '', $type); - $type = str_ireplace("UNSIGNED", '', $type); - $type = mb_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 = $this->relation->getForeigners($this->db, $this->table); - } - - /** - * Index action - * - * @return void - */ - public function indexAction() - { - global $goto; - switch ($this->_searchType) { - case 'replace': - if (isset($_POST['find'])) { - $this->findAction(); - - return; - } - $this->response - ->getHeader() - ->getScripts() - ->addFile('table/find_replace.js'); - - if (isset($_POST['replace'])) { - $this->replaceAction(); - } - - // Displays the find and replace form - $this->displaySelectionFormAction(); - break; - - case 'normal': - $this->response->getHeader() - ->getScripts() - ->addFiles( - [ - 'makegrid.js', - 'sql.js', - 'table/select.js', - 'table/change.js', - 'vendor/jquery/jquery.uitablefilter.js', - 'gis_data_editor.js', - ] - ); - - if (isset($_POST['range_search'])) { - $this->rangeSearchAction(); - - return; - } - - /** - * No selection criteria received -> display the selection form - */ - if (! isset($_POST['columnsToDisplay']) - && ! isset($_POST['displayAllColumns']) - ) { - $this->displaySelectionFormAction(); - } else { - $this->doSelectionAction(); - } - break; - - case 'zoom': - $this->response->getHeader() - ->getScripts() - ->addFiles( - [ - 'makegrid.js', - 'sql.js', - 'vendor/jqplot/jquery.jqplot.js', - 'vendor/jqplot/plugins/jqplot.canvasTextRenderer.js', - 'vendor/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js', - 'vendor/jqplot/plugins/jqplot.dateAxisRenderer.js', - 'vendor/jqplot/plugins/jqplot.highlighter.js', - 'vendor/jqplot/plugins/jqplot.cursor.js', - 'table/zoom_plot_jqplot.js', - 'table/change.js', - ] - ); - - /** - * Handle AJAX request for data row on point select - * - * @var boolean Object containing parameters for the POST request - */ - if (isset($_POST['get_data_row']) - && $_POST['get_data_row'] == true - ) { - $this->getDataRowAction(); - - return; - } - /** - * Handle AJAX request for changing field information - * (value,collation,operators,field values) in input form - * - * @var boolean Object containing parameters for the POST request - */ - if (isset($_POST['change_tbl_info']) - && $_POST['change_tbl_info'] == true - ) { - $this->changeTableInfoAction(); - - return; - } - - //Set default datalabel if not selected - if (! isset($_POST['zoom_submit']) || $_POST['dataLabel'] == '') { - $dataLabel = $this->relation->getDisplayField($this->db, $this->table); - } else { - $dataLabel = $_POST['dataLabel']; - } - - // Displays the zoom search form - $this->displaySelectionFormAction($dataLabel); - - /* - * Handle the input criteria and generate the query result - * Form for displaying query results - */ - if (isset($_POST['zoom_submit']) - && $_POST['criteriaColumnNames'][0] != 'pma_null' - && $_POST['criteriaColumnNames'][1] != 'pma_null' - && $_POST['criteriaColumnNames'][0] != $_POST['criteriaColumnNames'][1] - ) { - if (! isset($goto)) { - $goto = Util::getScriptNameForOption( - $GLOBALS['cfg']['DefaultTabTable'], - 'table' - ); - } - $this->zoomSubmitAction($dataLabel, $goto); - } - break; - } - } - - /** - * Zoom submit action - * - * @param string $dataLabel Data label - * @param string $goto Goto - * - * @return void - */ - public function zoomSubmitAction($dataLabel, $goto) - { - //Query generation part - $sql_query = $this->_buildSqlQuery(); - $sql_query .= ' LIMIT ' . $_POST['maxPlotLimit']; - - //Query execution part - $result = $this->dbi->query( - $sql_query . ";", - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - $fields_meta = $this->dbi->getFieldsMeta($result); - $data = []; - while ($row = $this->dbi->fetchAssoc($result)) { - //Need a row with indexes as 0,1,2 for the getUniqueCondition - // hence using a temporary array - $tmpRow = []; - foreach ($row as $val) { - $tmpRow[] = $val; - } - //Get unique condition on each row (will be needed for row update) - $uniqueCondition = Util::getUniqueCondition( - $result, // handle - count($this->_columnNames), // fields_cnt - $fields_meta, // fields_meta - $tmpRow, // row - true, // force_unique - false, // restrict_to_table - null // analyzed_sql_results - ); - //Append it to row array as where_clause - $row['where_clause'] = $uniqueCondition[0]; - - $tmpData = [ - $_POST['criteriaColumnNames'][0] => - $row[$_POST['criteriaColumnNames'][0]], - $_POST['criteriaColumnNames'][1] => - $row[$_POST['criteriaColumnNames'][1]], - 'where_clause' => $uniqueCondition[0], - ]; - $tmpData[$dataLabel] = $dataLabel ? $row[$dataLabel] : ''; - $data[] = $tmpData; - } - unset($tmpData); - - //Displays form for point data and scatter plot - $titles = [ - 'Browse' => Util::getIcon( - 'b_browse', - __('Browse foreign values') - ), - ]; - $column_names_hashes = []; - - foreach ($this->_columnNames as $columnName) { - $column_names_hashes[$columnName] = md5($columnName); - } - - $this->response->addHTML( - $this->template->render('table/search/zoom_result_form', [ - 'db' => $this->db, - 'table' => $this->table, - 'column_names' => $this->_columnNames, - 'column_names_hashes' => $column_names_hashes, - 'foreigners' => $this->_foreigners, - 'column_null_flags' => $this->_columnNullFlags, - 'column_types' => $this->_columnTypes, - 'titles' => $titles, - 'goto' => $goto, - 'data' => $data, - 'data_json' => json_encode($data), - 'zoom_submit' => isset($_POST['zoom_submit']), - 'foreign_max_limit' => $GLOBALS['cfg']['ForeignKeyMaxLimit'], - ]) - ); - } - - /** - * Change table info action - * - * @return void - */ - public function changeTableInfoAction() - { - $field = $_POST['field']; - if ($field == 'pma_null') { - $this->response->addJSON('field_type', ''); - $this->response->addJSON('field_collation', ''); - $this->response->addJSON('field_operators', ''); - $this->response->addJSON('field_value', ''); - return; - } - $key = array_search($field, $this->_columnNames); - $search_index - = (isset($_POST['it']) && is_numeric($_POST['it']) - ? intval($_POST['it']) : 0); - - $properties = $this->getColumnProperties($search_index, $key); - $this->response->addJSON( - 'field_type', - htmlspecialchars($properties['type']) - ); - $this->response->addJSON('field_collation', $properties['collation']); - $this->response->addJSON('field_operators', $properties['func']); - $this->response->addJSON('field_value', $properties['value']); - } - - /** - * Get data row action - * - * @return void - */ - public function getDataRowAction() - { - $extra_data = []; - $row_info_query = 'SELECT * FROM `' . $_POST['db'] . '`.`' - . $_POST['table'] . '` WHERE ' . $_POST['where_clause']; - $result = $this->dbi->query( - $row_info_query . ";", - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - $fields_meta = $this->dbi->getFieldsMeta($result); - while ($row = $this->dbi->fetchAssoc($result)) { - // for bit fields we need to convert them to printable form - $i = 0; - foreach ($row as $col => $val) { - if ($fields_meta[$i]->type == 'bit') { - $row[$col] = Util::printableBitValue( - (int) $val, - (int) $fields_meta[$i]->length - ); - } - $i++; - } - $extra_data['row_info'] = $row; - } - $this->response->addJSON($extra_data); - } - - /** - * Do selection action - * - * @return void - */ - public function doSelectionAction() - { - /** - * Selection criteria have been submitted -> do the work - */ - $sql_query = $this->_buildSqlQuery(); - - /** - * Add this to ensure following procedures included running correctly. - */ - $sql = new Sql(); - $sql->executeQueryAndSendQueryResponse( - null, // analyzed_sql_results - false, // is_gotofile - $this->db, // db - $this->table, // table - null, // find_real_end - null, // sql_query_for_bookmark - null, // extra_data - null, // message_to_show - null, // message - null, // sql_data - $GLOBALS['goto'], // goto - $GLOBALS['pmaThemeImage'], // pmaThemeImage - null, // disp_query - null, // disp_message - null, // query_type - $sql_query, // sql_query - null, // selectedTables - null // complete_query - ); - } - - /** - * Display selection form action - * - * @param string $dataLabel Data label - * - * @return void - */ - public function displaySelectionFormAction($dataLabel = null) - { - global $goto; - $this->url_query .= '&goto=tbl_select.php&back=tbl_select.php'; - if (! isset($goto)) { - $goto = Util::getScriptNameForOption( - $GLOBALS['cfg']['DefaultTabTable'], - 'table' - ); - } - // Displays the table search form - $this->response->addHTML( - $this->template->render('secondary_tabs', [ - 'url_params' => [ - 'db' => $this->db, - 'table' => $this->table, - ], - 'sub_tabs' => $this->_getSubTabs(), - ]) - ); - - $column_names = $this->_columnNames; - $column_types = $this->_columnTypes; - $types = []; - if ($this->_searchType == 'replace') { - $num_cols = count($column_names); - for ($i = 0; $i < $num_cols; $i++) { - $types[$column_names[$i]] = preg_replace('@\\(.*@s', '', $column_types[$i]); - } - } - - $criteria_column_names = isset($_POST['criteriaColumnNames']) ? $_POST['criteriaColumnNames'] : null; - $keys = []; - for ($i = 0; $i < 4; $i++) { - if (isset($criteria_column_names[$i])) { - if ($criteria_column_names[$i] != 'pma_null') { - $keys[$criteria_column_names[$i]] = array_search($criteria_column_names[$i], $column_names); - } - } - } - - $this->response->addHTML( - $this->template->render('table/search/selection_form', [ - 'search_type' => $this->_searchType, - 'db' => $this->db, - 'table' => $this->table, - 'goto' => $goto, - 'self' => $this, - 'geom_column_flag' => $this->_geomColumnFlag, - 'column_names' => $column_names, - 'column_types' => $column_types, - 'types' => $types, - 'column_collations' => $this->_columnCollations, - 'data_label' => $dataLabel, - 'keys' => $keys, - 'criteria_column_names' => $criteria_column_names, - 'default_sliders_state' => $GLOBALS['cfg']['InitialSlidersState'], - 'criteria_column_types' => isset($_POST['criteriaColumnTypes']) ? $_POST['criteriaColumnTypes'] : null, - 'sql_types' => $this->dbi->types, - 'max_rows' => intval($GLOBALS['cfg']['MaxRows']), - 'max_plot_limit' => ! empty($_POST['maxPlotLimit']) - ? intval($_POST['maxPlotLimit']) - : intval($GLOBALS['cfg']['maxRowPlotLimit']), - ]) - ); - } - - /** - * Range search action - * - * @return void - */ - public function rangeSearchAction() - { - $min_max = $this->getColumnMinMax($_POST['column']); - $this->response->addJSON('column_data', $min_max); - } - - /** - * Find action - * - * @return void - */ - public function findAction() - { - $useRegex = array_key_exists('useRegex', $_POST) - && $_POST['useRegex'] == 'on'; - - $preview = $this->getReplacePreview( - $_POST['columnIndex'], - $_POST['find'], - $_POST['replaceWith'], - $useRegex, - $this->_connectionCharSet - ); - $this->response->addJSON('preview', $preview); - } - - /** - * Replace action - * - * @return void - */ - public function replaceAction() - { - $this->replace( - $_POST['columnIndex'], - $_POST['findString'], - $_POST['replaceWith'], - $_POST['useRegex'], - $this->_connectionCharSet - ); - $this->response->addHTML( - Util::getMessage( - __('Your SQL query has been executed successfully.'), - null, - 'success' - ) - ); - } - - /** - * Returns HTML for previewing strings found and their replacements - * - * @param int $columnIndex index of the column - * @param string $find string to find in the column - * @param string $replaceWith string to replace with - * @param boolean $useRegex to use Regex replace or not - * @param string $charSet character set of the connection - * - * @return string HTML for previewing strings found and their replacements - */ - public function getReplacePreview( - $columnIndex, - $find, - $replaceWith, - $useRegex, - $charSet - ) { - $column = $this->_columnNames[$columnIndex]; - if ($useRegex) { - $result = $this->_getRegexReplaceRows( - $columnIndex, - $find, - $replaceWith, - $charSet - ); - } else { - $sql_query = "SELECT " - . Util::backquote($column) . "," - . " REPLACE(" - . Util::backquote($column) . ", '" . $find . "', '" - . $replaceWith - . "')," - . " COUNT(*)" - . " FROM " . Util::backquote($this->db) - . "." . Util::backquote($this->table) - . " WHERE " . Util::backquote($column) - . " LIKE '%" . $find . "%' COLLATE " . $charSet . "_bin"; // here we - // change the collation of the 2nd operand to a case sensitive - // binary collation to make sure that the comparison - // is case sensitive - $sql_query .= " GROUP BY " . Util::backquote($column) - . " ORDER BY " . Util::backquote($column) . " ASC"; - - $result = $this->dbi->fetchResult($sql_query, 0); - } - - return $this->template->render('table/search/replace_preview', [ - 'db' => $this->db, - 'table' => $this->table, - 'column_index' => $columnIndex, - 'find' => $find, - 'replace_with' => $replaceWith, - 'use_regex' => $useRegex, - 'result' => $result, - ]); - } - - /** - * Finds and returns Regex pattern and their replacements - * - * @param int $columnIndex index of the column - * @param string $find string to find in the column - * @param string $replaceWith string to replace with - * @param string $charSet character set of the connection - * - * @return array|bool Array containing original values, replaced values and count - */ - private function _getRegexReplaceRows( - $columnIndex, - $find, - $replaceWith, - $charSet - ) { - $column = $this->_columnNames[$columnIndex]; - $sql_query = "SELECT " - . Util::backquote($column) . "," - . " 1," // to add an extra column that will have replaced value - . " COUNT(*)" - . " FROM " . Util::backquote($this->db) - . "." . Util::backquote($this->table) - . " WHERE " . Util::backquote($column) - . " RLIKE '" . $this->dbi->escapeString($find) . "' COLLATE " - . $charSet . "_bin"; // here we - // change the collation of the 2nd operand to a case sensitive - // binary collation to make sure that the comparison is case sensitive - $sql_query .= " GROUP BY " . Util::backquote($column) - . " ORDER BY " . Util::backquote($column) . " ASC"; - - $result = $this->dbi->fetchResult($sql_query, 0); - - if (is_array($result)) { - /* Iterate over possible delimiters to get one */ - $delimiters = [ - '/', - '@', - '#', - '~', - '!', - '$', - '%', - '^', - '&', - '_', - ]; - $found = false; - for ($i = 0, $l = count($delimiters); $i < $l; $i++) { - if (strpos($find, $delimiters[$i]) === false) { - $found = true; - break; - } - } - if (! $found) { - return false; - } - $find = $delimiters[$i] . $find . $delimiters[$i]; - foreach ($result as $index => $row) { - $result[$index][1] = preg_replace( - $find, - $replaceWith, - $row[0] - ); - } - } - return $result; - } - - /** - * Replaces a given string in a column with a give replacement - * - * @param int $columnIndex index of the column - * @param string $find string to find in the column - * @param string $replaceWith string to replace with - * @param boolean $useRegex to use Regex replace or not - * @param string $charSet character set of the connection - * - * @return void - */ - public function replace( - $columnIndex, - $find, - $replaceWith, - $useRegex, - $charSet - ) { - $column = $this->_columnNames[$columnIndex]; - if ($useRegex) { - $toReplace = $this->_getRegexReplaceRows( - $columnIndex, - $find, - $replaceWith, - $charSet - ); - $sql_query = "UPDATE " . Util::backquote($this->table) - . " SET " . Util::backquote($column) . " = CASE"; - if (is_array($toReplace)) { - foreach ($toReplace as $row) { - $sql_query .= "\n WHEN " . Util::backquote($column) - . " = '" . $this->dbi->escapeString($row[0]) - . "' THEN '" . $this->dbi->escapeString($row[1]) . "'"; - } - } - $sql_query .= " END" - . " WHERE " . Util::backquote($column) - . " RLIKE '" . $this->dbi->escapeString($find) . "' COLLATE " - . $charSet . "_bin"; // here we - // change the collation of the 2nd operand to a case sensitive - // binary collation to make sure that the comparison - // is case sensitive - } else { - $sql_query = "UPDATE " . Util::backquote($this->table) - . " SET " . Util::backquote($column) . " =" - . " REPLACE(" - . Util::backquote($column) . ", '" . $find . "', '" - . $replaceWith - . "')" - . " WHERE " . Util::backquote($column) - . " LIKE '%" . $find . "%' COLLATE " . $charSet . "_bin"; // here we - // change the collation of the 2nd operand to a case sensitive - // binary collation to make sure that the comparison - // is case sensitive - } - $this->dbi->query( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - $GLOBALS['sql_query'] = $sql_query; - } - - /** - * Finds minimum and maximum value of a given column. - * - * @param string $column Column name - * - * @return array - */ - public function getColumnMinMax($column) - { - $sql_query = 'SELECT MIN(' . Util::backquote($column) . ') AS `min`, ' - . 'MAX(' . Util::backquote($column) . ') AS `max` ' - . 'FROM ' . Util::backquote($this->db) . '.' - . Util::backquote($this->table); - - return $this->dbi->fetchSingleRow($sql_query); - } - - /** - * Returns an array with necessary configurations to create - * sub-tabs in the table_select page. - * - * @return array Array containing configuration (icon, text, link, id, args) - * of sub-tabs - */ - private function _getSubTabs() - { - $subtabs = []; - $subtabs['search']['icon'] = 'b_search'; - $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_select'; - $subtabs['zoom']['link'] = 'tbl_zoom_select.php'; - $subtabs['zoom']['text'] = __('Zoom search'); - $subtabs['zoom']['id'] = 'zoom_search_id'; - - $subtabs['replace']['icon'] = 'b_find_replace'; - $subtabs['replace']['link'] = 'tbl_find_replace.php'; - $subtabs['replace']['text'] = __('Find and replace'); - $subtabs['replace']['id'] = 'find_replace_id'; - - return $subtabs; - } - - /** - * Builds the sql search query from the post parameters - * - * @return string the generated SQL query - */ - private 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( - ', ', - Util::backquote($_POST['columnsToDisplay']) - ); - } // end if - - $sql_query .= ' FROM ' - . 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 ' - . Util::backquote($_POST['orderByColumn']) - . ' ' . $_POST['order']; - } // end if - return $sql_query; - } - - /** - * Provides a column's type, collation, operators list, and criteria 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 containing column's properties - */ - public function getColumnProperties($search_index, $column_index) - { - $selected_operator = (isset($_POST['criteriaColumnOperators'][$search_index]) - ? $_POST['criteriaColumnOperators'][$search_index] : ''); - $entered_value = (isset($_POST['criteriaValues']) - ? $_POST['criteriaValues'] : ''); - $titles = [ - 'Browse' => Util::getIcon( - 'b_browse', - __('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 - $typeOperators = $this->dbi->types->getTypeOperatorsHtml( - preg_replace('@\(.*@s', '', $this->_columnTypes[$column_index]), - $this->_columnNullFlags[$column_index], - $selected_operator - ); - $func = $this->template->render('table/search/column_comparison_operators', [ - 'search_index' => $search_index, - 'type_operators' => $typeOperators, - ]); - //Gets link to browse foreign data(if any) and criteria inputbox - $foreignData = $this->relation->getForeignData( - $this->_foreigners, - $this->_columnNames[$column_index], - false, - '', - '' - ); - $value = $this->template->render('table/search/input_box', [ - 'str' => '', - 'column_type' => (string) $type, - 'column_id' => 'fieldID_', - 'in_zoom_search_edit' => false, - 'foreigners' => $this->_foreigners, - 'column_name' => $this->_columnNames[$column_index], - 'column_name_hash' => md5($this->_columnNames[$column_index]), - 'foreign_data' => $foreignData, - 'table' => $this->table, - 'column_index' => $search_index, - 'foreign_max_limit' => $GLOBALS['cfg']['ForeignKeyMaxLimit'], - 'criteria_values' => $entered_value, - 'db' => $this->db, - 'titles' => $titles, - 'in_fbs' => true, - ]); - return [ - 'type' => $type, - 'collation' => $collation, - 'func' => $func, - 'value' => $value, - ]; - } - - /** - * 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']) - && ! isset($_POST['geom_func']) - ) { - return ''; - } - - // else continue to form the where clause from column criteria values - $fullWhereClause = []; - foreach ($_POST['criteriaColumnOperators'] as $column_index => $operator) { - $unaryFlag = $this->dbi->types->isUnaryOperator($operator); - $tmp_geom_func = isset($_POST['geom_func'][$column_index]) - ? $_POST['geom_func'][$column_index] : null; - - $whereClause = $this->_getWhereClause( - $_POST['criteriaValues'][$column_index], - $_POST['criteriaColumnNames'][$column_index], - $_POST['criteriaColumnTypes'][$column_index], - $operator, - $unaryFlag, - $tmp_geom_func - ); - - if ($whereClause) { - $fullWhereClause[] = $whereClause; - } - } // end foreach - - if (! empty($fullWhereClause)) { - return ' WHERE ' . implode(' AND ', $fullWhereClause); - } - return ''; - } - - /** - * 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 = '\'' - . $this->dbi->escapeString($criteriaValues[0]) . '\''; - for ($e = 1; $e < $enum_selected_count; $e++) { - $enum_where .= ', \'' - . $this->dbi->escapeString($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 = [ - 'IsEmpty' => 1, - 'IsSimple' => 1, - 'IsRing' => 1, - 'IsClosed' => 1, - ]; - $where = ''; - - // Get details about the geometry functions - $geom_funcs = Util::getGISFunctions($types, true, false); - - // If the function takes multiple parameters - if (strpos($func_type, "IS NULL") !== false || strpos($func_type, "IS NOT NULL") !== false) { - return Util::backquote($names) . " " . $func_type; - } elseif ($geom_funcs[$geom_func]['params'] > 1) { - // create gis data from the criteria input - $gis_data = Util::createGISData($criteriaValues, $this->dbi->getVersion()); - return $geom_func . '(' . Util::backquote($names) - . ', ' . $gis_data . ')'; - } - - // New output type is the output type of the function being applied - $type = $geom_funcs[$geom_func]['type']; - $geom_function_applied = $geom_func - . '(' . Util::backquote($names) . ')'; - - // If the where clause is something like 'IsEmpty(`spatial_col_name`)' - if (isset($geom_unary_functions[$geom_func]) - && trim($criteriaValues) == '' - ) { - $where = $geom_function_applied; - } elseif (in_array($type, Util::getGISDatatypes()) - && ! empty($criteriaValues) - ) { - // create gis data from the criteria input - $gis_data = Util::createGISData($criteriaValues, $this->dbi->getVersion()); - $where = $geom_function_applied . " " . $func_type . " " . $gis_data; - } elseif (strlen($criteriaValues) > 0) { - $where = $geom_function_applied . " " - . $func_type . " '" . $criteriaValues . "'"; - } - 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 $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, - $func_type, - $unaryFlag, - $geom_func = null - ) { - // If geometry function is set - if (! empty($geom_func)) { - return $this->_getGeomWhereClause( - $criteriaValues, - $names, - $func_type, - $types, - $geom_func - ); - } - - $backquoted_name = Util::backquote($names); - $where = ''; - if ($unaryFlag) { - $where = $backquoted_name . ' ' . $func_type; - } elseif (strncasecmp($types, 'enum', 4) == 0 && (! empty($criteriaValues) || $criteriaValues[0] === '0')) { - $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) - || mb_strpos(' ' . $func_type, 'LIKE') - ) { - $quot = '\''; - } else { - $quot = ''; - } - - // LIKE %...% - if ($func_type == 'LIKE %...%') { - $func_type = 'LIKE'; - $criteriaValues = '%' . $criteriaValues . '%'; - } - if ($func_type == 'REGEXP ^...$') { - $func_type = 'REGEXP'; - $criteriaValues = '^' . $criteriaValues . '$'; - } - - if ('IN (...)' != $func_type - && 'NOT IN (...)' != $func_type - && 'BETWEEN' != $func_type - && 'NOT BETWEEN' != $func_type - ) { - return $backquoted_name . ' ' . $func_type . ' ' . $quot - . $this->dbi->escapeString($criteriaValues) . $quot; - } - $func_type = str_replace(' (...)', '', $func_type); - - //Don't explode if this is already an array - //(Case for (NOT) IN/BETWEEN.) - if (is_array($criteriaValues)) { - $values = $criteriaValues; - } else { - $values = explode(',', $criteriaValues); - } - // quote values one by one - $emptyKey = false; - foreach ($values as $key => &$value) { - if ('' === $value) { - $emptyKey = $key; - $value = 'NULL'; - continue; - } - $value = $quot . $this->dbi->escapeString(trim($value)) - . $quot; - } - - if ('BETWEEN' == $func_type || 'NOT BETWEEN' == $func_type) { - $where = $backquoted_name . ' ' . $func_type . ' ' - . (isset($values[0]) ? $values[0] : '') - . ' AND ' . (isset($values[1]) ? $values[1] : ''); - } else { //[NOT] IN - if (false !== $emptyKey) { - unset($values[$emptyKey]); - } - $wheres = []; - if (! empty($values)) { - $wheres[] = $backquoted_name . ' ' . $func_type - . ' (' . implode(',', $values) . ')'; - } - if (false !== $emptyKey) { - $wheres[] = $backquoted_name . ' IS NULL'; - } - $where = implode(' OR ', $wheres); - if (1 < count($wheres)) { - $where = '(' . $where . ')'; - } - } - } // end if - - return $where; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Table/SqlController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Table/SqlController.php deleted file mode 100644 index a3975ac..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Table/SqlController.php +++ /dev/null @@ -1,53 +0,0 @@ -getHtml( - $params['sql_query'] ?? true, - false, - isset($params['delimiter']) - ? htmlspecialchars($params['delimiter']) - : ';' - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/Table/StructureController.php b/srcs/phpmyadmin/libraries/classes/Controllers/Table/StructureController.php deleted file mode 100644 index 7f59013..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/Table/StructureController.php +++ /dev/null @@ -1,1648 +0,0 @@ -_db_is_system_schema = $db_is_system_schema; - $this->_url_query = Url::getCommonRaw(['db' => $db, 'table' => $table]); - $this->_tbl_is_view = $tbl_is_view; - $this->_tbl_storage_engine = $tbl_storage_engine; - $this->_table_info_num_rows = $table_info_num_rows; - $this->_tbl_collation = $tbl_collation; - $this->_showtable = $showtable; - $this->table_obj = $this->dbi->getTable($this->db, $this->table); - - $this->createAddField = $createAddField; - $this->relation = $relation; - $this->transformations = $transformations; - } - - /** - * Index action - * - * @param ContainerBuilder $containerBuilder ContainerBuilder instance - * - * @return void - */ - public function indexAction(ContainerBuilder $containerBuilder): void - { - global $sql_query; - - PageSettings::showGroup('TableStructure'); - - $checkUserPrivileges = new CheckUserPrivileges($this->dbi); - $checkUserPrivileges->getPrivileges(); - - $this->response->getHeader()->getScripts()->addFiles( - [ - 'table/structure.js', - 'indexes.js', - ] - ); - - /** - * Handle column moving - */ - if (isset($_POST['move_columns']) - && is_array($_POST['move_columns']) - && $this->response->isAjax() - ) { - $this->moveColumns(); - return; - } - - /** - * handle MySQL reserved words columns check - */ - if (isset($_POST['reserved_word_check'])) { - if ($GLOBALS['cfg']['ReservedWordDisableWarning'] === false) { - $columns_names = $_POST['field_name']; - $reserved_keywords_names = []; - foreach ($columns_names as $column) { - if (Context::isKeyword(trim($column), true)) { - $reserved_keywords_names[] = trim($column); - } - } - if (Context::isKeyword(trim($this->table), true)) { - $reserved_keywords_names[] = trim($this->table); - } - if (count($reserved_keywords_names) === 0) { - $this->response->setRequestStatus(false); - } - $this->response->addJSON( - 'message', - sprintf( - _ngettext( - 'The name \'%s\' is a MySQL reserved keyword.', - 'The names \'%s\' are MySQL reserved keywords.', - count($reserved_keywords_names) - ), - implode(',', $reserved_keywords_names) - ) - ); - } else { - $this->response->setRequestStatus(false); - } - return; - } - /** - * A click on Change has been made for one column - */ - if (isset($_GET['change_column'])) { - $this->displayHtmlForColumnChange(null, 'tbl_structure.php', $containerBuilder); - return; - } - - /** - * Adding or editing partitioning of the table - */ - if (isset($_POST['edit_partitioning']) - && ! isset($_POST['save_partitioning']) - ) { - $this->displayHtmlForPartitionChange(); - return; - } - - /** - * handle multiple field commands if required - * - * submit_mult_*_x comes from IE if is used - */ - $submit_mult = $this->getMultipleFieldCommandType(); - - if (! empty($submit_mult)) { - if (isset($_POST['selected_fld'])) { - if ($submit_mult == 'browse') { - // browsing the table displaying only selected columns - $this->displayTableBrowseForSelectedColumns( - $GLOBALS['goto'], - $GLOBALS['pmaThemeImage'] - ); - } else { - // handle multiple field commands - // handle confirmation of deleting multiple columns - $action = 'tbl_structure.php'; - $GLOBALS['selected'] = $_POST['selected_fld']; - list( - $what_ret, $query_type_ret, $is_unset_submit_mult, - $mult_btn_ret, $centralColsError - ) - = $this->getDataForSubmitMult( - $submit_mult, - $_POST['selected_fld'], - $action, - $containerBuilder - ); - //update the existing variables - // todo: refactor mult_submits.inc.php such as - // below globals are not needed anymore - if (isset($what_ret)) { - $GLOBALS['what'] = $what_ret; - global $what; - } - if (isset($query_type_ret)) { - $GLOBALS['query_type'] = $query_type_ret; - global $query_type; - } - if ($is_unset_submit_mult) { - unset($submit_mult); - } - if (isset($mult_btn_ret)) { - $GLOBALS['mult_btn'] = $mult_btn_ret; - global $mult_btn; - } - include ROOT_PATH . 'libraries/mult_submits.inc.php'; - /** - * if $submit_mult == 'change', execution will have stopped - * at this point - */ - if (empty($message)) { - $message = Message::success(); - } - $this->response->addHTML( - Util::getMessage($message, $sql_query) - ); - } - } else { - $this->response->setRequestStatus(false); - $message = Message::error(__('No column selected.')); - $this->response->addJSON('message', $message); - } - } - - /** - * Modifications have been submitted -> updates the table - */ - if (isset($_POST['do_save_data'])) { - $regenerate = $this->updateColumns(); - if (! $regenerate) { - // continue to show the table's structure - unset($_POST['selected']); - } - } - - /** - * Modifications to the partitioning have been submitted -> updates the table - */ - if (isset($_POST['save_partitioning'])) { - $this->updatePartitioning(); - } - - /** - * Adding indexes - */ - if (isset($_POST['add_key']) - || isset($_POST['partition_maintenance']) - ) { - //todo: set some variables for sql.php include, to be eliminated - //after refactoring sql.php - $db = $this->db; - $table = $this->table; - $sql_query = $GLOBALS['sql_query']; - $cfg = $GLOBALS['cfg']; - $pmaThemeImage = $GLOBALS['pmaThemeImage']; - include ROOT_PATH . 'sql.php'; - $GLOBALS['reload'] = true; - } - - /** - * Gets the relation settings - */ - $cfgRelation = $this->relation->getRelationsParam(); - - /** - * Runs common work - */ - // set db, table references, for require_once that follows - // got to be eliminated in long run - $db = &$this->db; - $table = &$this->table; - $url_params = []; - include_once ROOT_PATH . 'libraries/tbl_common.inc.php'; - $this->_db_is_system_schema = $db_is_system_schema; - $this->_url_query = Url::getCommonRaw([ - 'db' => $db, - 'table' => $table, - 'goto' => 'tbl_structure.php', - 'back' => 'tbl_structure.php', - ]); - /* The url_params array is initialized in above include */ - $url_params['goto'] = 'tbl_structure.php'; - $url_params['back'] = 'tbl_structure.php'; - - // 2. Gets table keys and retains them - // @todo should be: $server->db($db)->table($table)->primary() - $primary = Index::getPrimary($this->table, $this->db); - $columns_with_index = $this->dbi - ->getTable($this->db, $this->table) - ->getColumnsWithIndex( - Index::UNIQUE | Index::INDEX | Index::SPATIAL - | Index::FULLTEXT - ); - $columns_with_unique_index = $this->dbi - ->getTable($this->db, $this->table) - ->getColumnsWithIndex(Index::UNIQUE); - - // 3. Get fields - $fields = (array) $this->dbi->getColumns( - $this->db, - $this->table, - null, - true - ); - - //display table structure - $this->response->addHTML( - $this->displayStructure( - $cfgRelation, - $columns_with_unique_index, - $url_params, - $primary, - $fields, - $columns_with_index - ) - ); - } - - /** - * Moves columns in the table's structure based on $_REQUEST - * - * @return void - */ - protected function moveColumns() - { - $this->dbi->selectDb($this->db); - - /* - * load the definitions for all columns - */ - $columns = $this->dbi->getColumnsFull($this->db, $this->table); - $column_names = array_keys($columns); - $changes = []; - - // @see https://mariadb.com/kb/en/library/changes-improvements-in-mariadb-102/#information-schema - $usesLiteralNull = $this->dbi->isMariaDB() && $this->dbi->getVersion() >= 100200; - $defaultNullValue = $usesLiteralNull ? 'NULL' : null; - // move columns from first to last - for ($i = 0, $l = count($_POST['move_columns']); $i < $l; $i++) { - $column = $_POST['move_columns'][$i]; - // is this column already correctly placed? - if ($column_names[$i] == $column) { - continue; - } - - // it is not, let's move it to index $i - $data = $columns[$column]; - $extracted_columnspec = Util::extractColumnSpec($data['Type']); - if (isset($data['Extra']) - && $data['Extra'] == 'on update CURRENT_TIMESTAMP' - ) { - $extracted_columnspec['attribute'] = $data['Extra']; - unset($data['Extra']); - } - $current_timestamp = ($data['Type'] == 'timestamp' - || $data['Type'] == 'datetime') - && ($data['Default'] == 'CURRENT_TIMESTAMP' - || $data['Default'] == 'current_timestamp()'); - - // @see https://mariadb.com/kb/en/library/information-schema-columns-table/#examples - if ($data['Null'] === 'YES' && in_array($data['Default'], [$defaultNullValue, null])) { - $default_type = 'NULL'; - } elseif ($current_timestamp) { - $default_type = 'CURRENT_TIMESTAMP'; - } elseif ($data['Default'] === null) { - $default_type = 'NONE'; - } else { - $default_type = 'USER_DEFINED'; - } - - $virtual = [ - 'VIRTUAL', - 'PERSISTENT', - 'VIRTUAL GENERATED', - 'STORED GENERATED', - ]; - $data['Virtuality'] = ''; - $data['Expression'] = ''; - if (isset($data['Extra']) && in_array($data['Extra'], $virtual)) { - $data['Virtuality'] = str_replace(' GENERATED', '', $data['Extra']); - $expressions = $this->table_obj->getColumnGenerationExpression($column); - $data['Expression'] = $expressions[$column]; - } - - $changes[] = 'CHANGE ' . Table::generateAlter( - $column, - $column, - mb_strtoupper($extracted_columnspec['type']), - $extracted_columnspec['spec_in_brackets'], - $extracted_columnspec['attribute'], - isset($data['Collation']) ? $data['Collation'] : '', - $data['Null'] === 'YES' ? 'YES' : 'NO', - $default_type, - $current_timestamp ? '' : $data['Default'], - isset($data['Extra']) && $data['Extra'] !== '' ? $data['Extra'] - : false, - isset($data['COLUMN_COMMENT']) && $data['COLUMN_COMMENT'] !== '' - ? $data['COLUMN_COMMENT'] : false, - $data['Virtuality'], - $data['Expression'], - $i === 0 ? '-first' : $column_names[$i - 1] - ); - // update current column_names array, first delete old position - for ($j = 0, $ll = count($column_names); $j < $ll; $j++) { - if ($column_names[$j] == $column) { - unset($column_names[$j]); - } - } - // insert moved column - array_splice($column_names, $i, 0, $column); - } - if (empty($changes) && ! isset($_REQUEST['preview_sql'])) { // should never happen - $this->response->setRequestStatus(false); - return; - } - // query for moving the columns - $sql_query = sprintf( - 'ALTER TABLE %s %s', - Util::backquote($this->table), - implode(', ', $changes) - ); - - if (isset($_REQUEST['preview_sql'])) { // preview sql - $this->response->addJSON( - 'sql_data', - $this->template->render('preview_sql', [ - 'query_data' => $sql_query, - ]) - ); - } else { // move column - $this->dbi->tryQuery($sql_query); - $tmp_error = $this->dbi->getError(); - if ($tmp_error) { - $this->response->setRequestStatus(false); - $this->response->addJSON('message', Message::error($tmp_error)); - } else { - $message = Message::success( - __('The columns have been moved successfully.') - ); - $this->response->addJSON('message', $message); - $this->response->addJSON('columns', $column_names); - } - } - } - - /** - * Displays HTML for changing one or more columns - * - * @param array $selected the selected columns - * @param string $action target script to call - * @param ContainerBuilder $containerBuilder Container builder instance (Used in tbl_columns_definition_form.inc.php) - * - * @return void - */ - protected function displayHtmlForColumnChange($selected, $action, ContainerBuilder $containerBuilder) - { - // $selected comes from mult_submits.inc.php - if (empty($selected)) { - $selected[] = $_REQUEST['field']; - $selected_cnt = 1; - } else { // from a multiple submit - $selected_cnt = count($selected); - } - - /** - * @todo optimize in case of multiple fields to modify - */ - $fields_meta = []; - for ($i = 0; $i < $selected_cnt; $i++) { - $value = $this->dbi->getColumns( - $this->db, - $this->table, - $this->dbi->escapeString($selected[$i]), - true - ); - if (count($value) === 0) { - $message = Message::error( - __('Failed to get description of column %s!') - ); - $message->addParam($selected[$i]); - $this->response->addHTML($message); - } else { - $fields_meta[] = $value; - } - } - $num_fields = count($fields_meta); - // set these globals because tbl_columns_definition_form.inc.php - // verifies them - // @todo: refactor tbl_columns_definition_form.inc.php so that it uses - // protected function params - $GLOBALS['action'] = $action; - $GLOBALS['num_fields'] = $num_fields; - - /** - * Form for changing properties. - */ - $checkUserPrivileges = new CheckUserPrivileges($this->dbi); - $checkUserPrivileges->getPrivileges(); - - include ROOT_PATH . 'libraries/tbl_columns_definition_form.inc.php'; - } - - /** - * Displays HTML for partition change - * - * @return void - */ - protected function displayHtmlForPartitionChange() - { - $partitionDetails = null; - if (! isset($_POST['partition_by'])) { - $partitionDetails = $this->_extractPartitionDetails(); - } - - $partitionDetails = TablePartitionDefinition::getDetails($partitionDetails); - $this->response->addHTML( - $this->template->render('table/structure/partition_definition_form', [ - 'db' => $this->db, - 'table' => $this->table, - 'partition_details' => $partitionDetails, - ]) - ); - } - - /** - * Extracts partition details from CREATE TABLE statement - * - * @return array[]|null array of partition details - */ - private function _extractPartitionDetails() - { - $createTable = (new Table($this->table, $this->db))->showCreate(); - if (! $createTable) { - return null; - } - - $parser = new Parser($createTable); - /** - * @var CreateStatement $stmt - */ - $stmt = $parser->statements[0]; - - $partitionDetails = []; - - $partitionDetails['partition_by'] = ''; - $partitionDetails['partition_expr'] = ''; - $partitionDetails['partition_count'] = ''; - - if (! empty($stmt->partitionBy)) { - $openPos = strpos($stmt->partitionBy, "("); - $closePos = strrpos($stmt->partitionBy, ")"); - - $partitionDetails['partition_by'] - = trim(substr($stmt->partitionBy, 0, $openPos)); - $partitionDetails['partition_expr'] - = trim(substr($stmt->partitionBy, $openPos + 1, $closePos - ($openPos + 1))); - if (isset($stmt->partitionsNum)) { - $count = $stmt->partitionsNum; - } else { - $count = count($stmt->partitions); - } - $partitionDetails['partition_count'] = $count; - } - - $partitionDetails['subpartition_by'] = ''; - $partitionDetails['subpartition_expr'] = ''; - $partitionDetails['subpartition_count'] = ''; - - if (! empty($stmt->subpartitionBy)) { - $openPos = strpos($stmt->subpartitionBy, "("); - $closePos = strrpos($stmt->subpartitionBy, ")"); - - $partitionDetails['subpartition_by'] - = trim(substr($stmt->subpartitionBy, 0, $openPos)); - $partitionDetails['subpartition_expr'] - = trim(substr($stmt->subpartitionBy, $openPos + 1, $closePos - ($openPos + 1))); - if (isset($stmt->subpartitionsNum)) { - $count = $stmt->subpartitionsNum; - } else { - $count = count($stmt->partitions[0]->subpartitions); - } - $partitionDetails['subpartition_count'] = $count; - } - - // Only LIST and RANGE type parameters allow subpartitioning - $partitionDetails['can_have_subpartitions'] - = $partitionDetails['partition_count'] > 1 - && ($partitionDetails['partition_by'] == 'RANGE' - || $partitionDetails['partition_by'] == 'RANGE COLUMNS' - || $partitionDetails['partition_by'] == 'LIST' - || $partitionDetails['partition_by'] == 'LIST COLUMNS'); - - // Values are specified only for LIST and RANGE type partitions - $partitionDetails['value_enabled'] = isset($partitionDetails['partition_by']) - && ($partitionDetails['partition_by'] == 'RANGE' - || $partitionDetails['partition_by'] == 'RANGE COLUMNS' - || $partitionDetails['partition_by'] == 'LIST' - || $partitionDetails['partition_by'] == 'LIST COLUMNS'); - - $partitionDetails['partitions'] = []; - - for ($i = 0, $iMax = (int) $partitionDetails['partition_count']; $i < $iMax; $i++) { - if (! isset($stmt->partitions[$i])) { - $partitionDetails['partitions'][$i] = [ - 'name' => 'p' . $i, - 'value_type' => '', - 'value' => '', - 'engine' => '', - 'comment' => '', - 'data_directory' => '', - 'index_directory' => '', - 'max_rows' => '', - 'min_rows' => '', - 'tablespace' => '', - 'node_group' => '', - ]; - } else { - $p = $stmt->partitions[$i]; - $type = $p->type; - $expr = trim((string) $p->expr, '()'); - if ($expr == 'MAXVALUE') { - $type .= ' MAXVALUE'; - $expr = ''; - } - $partitionDetails['partitions'][$i] = [ - 'name' => $p->name, - 'value_type' => $type, - 'value' => $expr, - 'engine' => $p->options->has('ENGINE', true), - 'comment' => trim((string) $p->options->has('COMMENT', true), "'"), - 'data_directory' => trim((string) $p->options->has('DATA DIRECTORY', true), "'"), - 'index_directory' => trim((string) $p->options->has('INDEX_DIRECTORY', true), "'"), - 'max_rows' => $p->options->has('MAX_ROWS', true), - 'min_rows' => $p->options->has('MIN_ROWS', true), - 'tablespace' => $p->options->has('TABLESPACE', true), - 'node_group' => $p->options->has('NODEGROUP', true), - ]; - } - - $partition =& $partitionDetails['partitions'][$i]; - $partition['prefix'] = 'partitions[' . $i . ']'; - - if ($partitionDetails['subpartition_count'] > 1) { - $partition['subpartition_count'] = $partitionDetails['subpartition_count']; - $partition['subpartitions'] = []; - - for ($j = 0, $jMax = (int) $partitionDetails['subpartition_count']; $j < $jMax; $j++) { - if (! isset($stmt->partitions[$i]->subpartitions[$j])) { - $partition['subpartitions'][$j] = [ - 'name' => $partition['name'] . '_s' . $j, - 'engine' => '', - 'comment' => '', - 'data_directory' => '', - 'index_directory' => '', - 'max_rows' => '', - 'min_rows' => '', - 'tablespace' => '', - 'node_group' => '', - ]; - } else { - $sp = $stmt->partitions[$i]->subpartitions[$j]; - $partition['subpartitions'][$j] = [ - 'name' => $sp->name, - 'engine' => $sp->options->has('ENGINE', true), - 'comment' => trim($sp->options->has('COMMENT', true), "'"), - 'data_directory' => trim($sp->options->has('DATA DIRECTORY', true), "'"), - 'index_directory' => trim($sp->options->has('INDEX_DIRECTORY', true), "'"), - 'max_rows' => $sp->options->has('MAX_ROWS', true), - 'min_rows' => $sp->options->has('MIN_ROWS', true), - 'tablespace' => $sp->options->has('TABLESPACE', true), - 'node_group' => $sp->options->has('NODEGROUP', true), - ]; - } - - $subpartition =& $partition['subpartitions'][$j]; - $subpartition['prefix'] = 'partitions[' . $i . ']' - . '[subpartitions][' . $j . ']'; - } - } - } - - return $partitionDetails; - } - - /** - * Update the table's partitioning based on $_REQUEST - * - * @return void - */ - protected function updatePartitioning() - { - $sql_query = "ALTER TABLE " . Util::backquote($this->table) . " " - . $this->createAddField->getPartitionsDefinition(); - - // Execute alter query - $result = $this->dbi->tryQuery($sql_query); - - if ($result !== false) { - $message = Message::success( - __('Table %1$s has been altered successfully.') - ); - $message->addParam($this->table); - $this->response->addHTML( - Util::getMessage($message, $sql_query, 'success') - ); - } else { - $this->response->setRequestStatus(false); - $this->response->addJSON( - 'message', - Message::rawError( - __('Query error') . ':
' . $this->dbi->getError() - ) - ); - } - } - - /** - * Function to get the type of command for multiple field handling - * - * @return string|null - */ - protected function getMultipleFieldCommandType() - { - $types = [ - 'change', - 'drop', - 'primary', - 'index', - 'unique', - 'spatial', - 'fulltext', - 'browse', - ]; - - foreach ($types as $type) { - if (isset($_POST['submit_mult_' . $type . '_x'])) { - return $type; - } - } - - if (isset($_POST['submit_mult'])) { - return $_POST['submit_mult']; - } elseif (isset($_POST['mult_btn']) - && $_POST['mult_btn'] == __('Yes') - ) { - if (isset($_POST['selected'])) { - $_POST['selected_fld'] = $_POST['selected']; - } - return 'row_delete'; - } - - return null; - } - - /** - * Function to display table browse for selected columns - * - * @param string $goto goto page url - * @param string $pmaThemeImage URI of the pma theme image - * - * @return void - */ - protected function displayTableBrowseForSelectedColumns($goto, $pmaThemeImage) - { - $GLOBALS['active_page'] = 'sql.php'; - $fields = []; - foreach ($_POST['selected_fld'] as $sval) { - $fields[] = Util::backquote($sval); - } - $sql_query = sprintf( - 'SELECT %s FROM %s.%s', - implode(', ', $fields), - Util::backquote($this->db), - Util::backquote($this->table) - ); - - // Parse and analyze the query - $db = &$this->db; - list( - $analyzed_sql_results, - $db, - ) = ParseAnalyze::sqlQuery($sql_query, $db); - // @todo: possibly refactor - extract($analyzed_sql_results); - - $sql = new Sql(); - $this->response->addHTML( - $sql->executeQueryAndGetQueryResponse( - isset($analyzed_sql_results) ? $analyzed_sql_results : '', - false, // is_gotofile - $this->db, // db - $this->table, // table - null, // find_real_end - null, // sql_query_for_bookmark - null, // extra_data - null, // message_to_show - null, // message - null, // sql_data - $goto, // goto - $pmaThemeImage, // pmaThemeImage - null, // disp_query - null, // disp_message - null, // query_type - $sql_query, // sql_query - null, // selectedTables - null // complete_query - ) - ); - } - - /** - * Update the table's structure based on $_REQUEST - * - * @return boolean true if error occurred - * - */ - protected function updateColumns() - { - $err_url = 'tbl_structure.php' . Url::getCommon( - [ - 'db' => $this->db, - 'table' => $this->table, - ] - ); - $regenerate = false; - $field_cnt = count($_POST['field_name']); - $changes = []; - $adjust_privileges = []; - $columns_with_index = $this->dbi - ->getTable($this->db, $this->table) - ->getColumnsWithIndex( - Index::PRIMARY | Index::UNIQUE - ); - for ($i = 0; $i < $field_cnt; $i++) { - if (! $this->columnNeedsAlterTable($i)) { - continue; - } - - $changes[] = 'CHANGE ' . Table::generateAlter( - Util::getValueByKey($_POST, "field_orig.${i}", ''), - $_POST['field_name'][$i], - $_POST['field_type'][$i], - $_POST['field_length'][$i], - $_POST['field_attribute'][$i], - Util::getValueByKey($_POST, "field_collation.${i}", ''), - Util::getValueByKey($_POST, "field_null.${i}", 'NO'), - $_POST['field_default_type'][$i], - $_POST['field_default_value'][$i], - Util::getValueByKey($_POST, "field_extra.${i}", false), - Util::getValueByKey($_POST, "field_comments.${i}", ''), - Util::getValueByKey($_POST, "field_virtuality.${i}", ''), - Util::getValueByKey($_POST, "field_expression.${i}", ''), - Util::getValueByKey($_POST, "field_move_to.${i}", ''), - $columns_with_index - ); - - // find the remembered sort expression - $sorted_col = $this->table_obj->getUiProp( - Table::PROP_SORTED_COLUMN - ); - // if the old column name is part of the remembered sort expression - if (mb_strpos( - (string) $sorted_col, - Util::backquote($_POST['field_orig'][$i]) - ) !== false) { - // delete the whole remembered sort expression - $this->table_obj->removeUiProp(Table::PROP_SORTED_COLUMN); - } - - if (isset($_POST['field_adjust_privileges'][$i]) - && ! empty($_POST['field_adjust_privileges'][$i]) - && $_POST['field_orig'][$i] != $_POST['field_name'][$i] - ) { - $adjust_privileges[$_POST['field_orig'][$i]] - = $_POST['field_name'][$i]; - } - } // end for - - if (count($changes) > 0 || isset($_POST['preview_sql'])) { - // Builds the primary keys statements and updates the table - $key_query = ''; - /** - * this is a little bit more complex - * - * @todo if someone selects A_I when altering a column we need to check: - * - no other column with A_I - * - the column has an index, if not create one - * - */ - - // To allow replication, we first select the db to use - // and then run queries on this db. - if (! $this->dbi->selectDb($this->db)) { - Util::mysqlDie( - $this->dbi->getError(), - 'USE ' . Util::backquote($this->db) . ';', - false, - $err_url - ); - } - $sql_query = 'ALTER TABLE ' . Util::backquote($this->table) . ' '; - $sql_query .= implode(', ', $changes) . $key_query; - $sql_query .= ';'; - - // If there is a request for SQL previewing. - if (isset($_POST['preview_sql'])) { - Core::previewSQL(count($changes) > 0 ? $sql_query : ''); - } - - $columns_with_index = $this->dbi - ->getTable($this->db, $this->table) - ->getColumnsWithIndex( - Index::PRIMARY | Index::UNIQUE | Index::INDEX - | Index::SPATIAL | Index::FULLTEXT - ); - - $changedToBlob = []; - // While changing the Column Collation - // First change to BLOB - for ($i = 0; $i < $field_cnt; $i++) { - if (isset($_POST['field_collation'][$i]) - && isset($_POST['field_collation_orig'][$i]) - && $_POST['field_collation'][$i] !== $_POST['field_collation_orig'][$i] - && ! in_array($_POST['field_orig'][$i], $columns_with_index) - ) { - $secondary_query = 'ALTER TABLE ' . Util::backquote( - $this->table - ) - . ' CHANGE ' . Util::backquote( - $_POST['field_orig'][$i] - ) - . ' ' . Util::backquote($_POST['field_orig'][$i]) - . ' BLOB'; - - if (isset($_POST['field_virtuality'][$i]) - && isset($_POST['field_expression'][$i])) { - if ($_POST['field_virtuality'][$i]) { - $secondary_query .= ' AS (' . $_POST['field_expression'][$i] . ') ' - . $_POST['field_virtuality'][$i]; - } - } - - $secondary_query .= ';'; - - $this->dbi->query($secondary_query); - $changedToBlob[$i] = true; - } else { - $changedToBlob[$i] = false; - } - } - - // Then make the requested changes - $result = $this->dbi->tryQuery($sql_query); - - if ($result !== false) { - $changed_privileges = $this->adjustColumnPrivileges( - $adjust_privileges - ); - - if ($changed_privileges) { - $message = Message::success( - __( - 'Table %1$s has been altered successfully. Privileges ' . - 'have been adjusted.' - ) - ); - } else { - $message = Message::success( - __('Table %1$s has been altered successfully.') - ); - } - $message->addParam($this->table); - - $this->response->addHTML( - Util::getMessage($message, $sql_query, 'success') - ); - } else { - // An error happened while inserting/updating a table definition - - // Save the Original Error - $orig_error = $this->dbi->getError(); - $changes_revert = []; - - // Change back to Original Collation and data type - for ($i = 0; $i < $field_cnt; $i++) { - if ($changedToBlob[$i]) { - $changes_revert[] = 'CHANGE ' . Table::generateAlter( - Util::getValueByKey($_POST, "field_orig.${i}", ''), - $_POST['field_name'][$i], - $_POST['field_type_orig'][$i], - $_POST['field_length_orig'][$i], - $_POST['field_attribute_orig'][$i], - Util::getValueByKey($_POST, "field_collation_orig.${i}", ''), - Util::getValueByKey($_POST, "field_null_orig.${i}", 'NO'), - $_POST['field_default_type_orig'][$i], - $_POST['field_default_value_orig'][$i], - Util::getValueByKey($_POST, "field_extra_orig.${i}", false), - Util::getValueByKey($_POST, "field_comments_orig.${i}", ''), - Util::getValueByKey($_POST, "field_virtuality_orig.${i}", ''), - Util::getValueByKey($_POST, "field_expression_orig.${i}", ''), - Util::getValueByKey($_POST, "field_move_to_orig.${i}", '') - ); - } - } - - $revert_query = 'ALTER TABLE ' . Util::backquote($this->table) - . ' '; - $revert_query .= implode(', ', $changes_revert) . ''; - $revert_query .= ';'; - - // Column reverted back to original - $this->dbi->query($revert_query); - - $this->response->setRequestStatus(false); - $this->response->addJSON( - 'message', - Message::rawError( - __('Query error') . ':
' . $orig_error - ) - ); - $regenerate = true; - } - } - - // update field names in relation - if (isset($_POST['field_orig']) && is_array($_POST['field_orig'])) { - foreach ($_POST['field_orig'] as $fieldindex => $fieldcontent) { - if ($_POST['field_name'][$fieldindex] != $fieldcontent) { - $this->relation->renameField( - $this->db, - $this->table, - $fieldcontent, - $_POST['field_name'][$fieldindex] - ); - } - } - } - - // update mime types - if (isset($_POST['field_mimetype']) - && is_array($_POST['field_mimetype']) - && $GLOBALS['cfg']['BrowseMIME'] - ) { - foreach ($_POST['field_mimetype'] as $fieldindex => $mimetype) { - if (isset($_POST['field_name'][$fieldindex]) - && strlen($_POST['field_name'][$fieldindex]) > 0 - ) { - $this->transformations->setMime( - $this->db, - $this->table, - $_POST['field_name'][$fieldindex], - $mimetype, - $_POST['field_transformation'][$fieldindex], - $_POST['field_transformation_options'][$fieldindex], - $_POST['field_input_transformation'][$fieldindex], - $_POST['field_input_transformation_options'][$fieldindex] - ); - } - } - } - return $regenerate; - } - - /** - * Adjusts the Privileges for all the columns whose names have changed - * - * @param array $adjust_privileges assoc array of old col names mapped to new - * cols - * - * @return boolean boolean whether at least one column privileges - * adjusted - */ - protected function adjustColumnPrivileges(array $adjust_privileges) - { - $changed = false; - - if (Util::getValueByKey($GLOBALS, 'col_priv', false) - && Util::getValueByKey($GLOBALS, 'is_reload_priv', false) - ) { - $this->dbi->selectDb('mysql'); - - // For Column specific privileges - foreach ($adjust_privileges as $oldCol => $newCol) { - $this->dbi->query( - sprintf( - 'UPDATE %s SET Column_name = "%s" - WHERE Db = "%s" - AND Table_name = "%s" - AND Column_name = "%s";', - Util::backquote('columns_priv'), - $newCol, - $this->db, - $this->table, - $oldCol - ) - ); - - // i.e. if atleast one column privileges adjusted - $changed = true; - } - - if ($changed) { - // Finally FLUSH the new privileges - $this->dbi->query("FLUSH PRIVILEGES;"); - } - } - - return $changed; - } - - /** - * Verifies if some elements of a column have changed - * - * @param integer $i column index in the request - * - * @return boolean true if we need to generate ALTER TABLE - * - */ - protected function columnNeedsAlterTable($i) - { - // these two fields are checkboxes so might not be part of the - // request; therefore we define them to avoid notices below - if (! isset($_POST['field_null'][$i])) { - $_POST['field_null'][$i] = 'NO'; - } - if (! isset($_POST['field_extra'][$i])) { - $_POST['field_extra'][$i] = ''; - } - - // field_name does not follow the convention (corresponds to field_orig) - if ($_POST['field_name'][$i] != $_POST['field_orig'][$i]) { - return true; - } - - $fields = [ - 'field_attribute', - 'field_collation', - 'field_comments', - 'field_default_value', - 'field_default_type', - 'field_extra', - 'field_length', - 'field_null', - 'field_type', - ]; - foreach ($fields as $field) { - if ($_POST[$field][$i] != $_POST[$field . '_orig'][$i]) { - return true; - } - } - return ! empty($_POST['field_move_to'][$i]); - } - - /** - * Displays the table structure ('show table' works correct since 3.23.03) - * - * @param array $cfgRelation current relation parameters - * @param array $columns_with_unique_index Columns with unique index - * @param mixed $url_params Contains an associative - * array with url params - * @param Index|false $primary_index primary index or false if - * no one exists - * @param array $fields Fields - * @param array $columns_with_index Columns with index - * - * @return string - */ - protected function displayStructure( - array $cfgRelation, - array $columns_with_unique_index, - $url_params, - $primary_index, - array $fields, - array $columns_with_index - ) { - // prepare comments - $comments_map = []; - $mime_map = []; - - if ($GLOBALS['cfg']['ShowPropertyComments']) { - $comments_map = $this->relation->getComments($this->db, $this->table); - if ($cfgRelation['mimework'] && $GLOBALS['cfg']['BrowseMIME']) { - $mime_map = $this->transformations->getMime($this->db, $this->table, true); - } - } - $centralColumns = new CentralColumns($this->dbi); - $central_list = $centralColumns->getFromTable( - $this->db, - $this->table - ); - $columns_list = []; - - $titles = [ - 'Change' => Util::getIcon('b_edit', __('Change')), - 'Drop' => Util::getIcon('b_drop', __('Drop')), - 'NoDrop' => Util::getIcon('b_drop', __('Drop')), - 'Primary' => Util::getIcon('b_primary', __('Primary')), - 'Index' => Util::getIcon('b_index', __('Index')), - 'Unique' => Util::getIcon('b_unique', __('Unique')), - 'Spatial' => Util::getIcon('b_spatial', __('Spatial')), - 'IdxFulltext' => Util::getIcon('b_ftext', __('Fulltext')), - 'NoPrimary' => Util::getIcon('bd_primary', __('Primary')), - 'NoIndex' => Util::getIcon('bd_index', __('Index')), - 'NoUnique' => Util::getIcon('bd_unique', __('Unique')), - 'NoSpatial' => Util::getIcon('bd_spatial', __('Spatial')), - 'NoIdxFulltext' => Util::getIcon('bd_ftext', __('Fulltext')), - 'DistinctValues' => Util::getIcon('b_browse', __('Distinct values')), - ]; - - $edit_view_url = ''; - if ($this->_tbl_is_view && ! $this->_db_is_system_schema) { - $edit_view_url = Url::getCommon([ - 'db' => $this->db, - 'table' => $this->table, - ]); - } - - /** - * Displays Space usage and row statistics - */ - // BEGIN - Calc Table Space - // Get valid statistics whatever is the table type - if ($GLOBALS['cfg']['ShowStats']) { - //get table stats in HTML format - $tablestats = $this->getTableStats(); - //returning the response in JSON format to be used by Ajax - $this->response->addJSON('tableStat', $tablestats); - } - // END - Calc Table Space - - $hideStructureActions = false; - if ($GLOBALS['cfg']['HideStructureActions'] === true) { - $hideStructureActions = true; - } - - // logic removed from Template - $rownum = 0; - $columns_list = []; - $attributes = []; - $displayed_fields = []; - $row_comments = []; - $extracted_columnspecs = []; - $collations = []; - foreach ($fields as &$field) { - $rownum += 1; - $columns_list[] = $field['Field']; - - $extracted_columnspecs[$rownum] = Util::extractColumnSpec($field['Type']); - $attributes[$rownum] = $extracted_columnspecs[$rownum]['attribute']; - if (strpos($field['Extra'], 'on update CURRENT_TIMESTAMP') !== false) { - $attributes[$rownum] = 'on update CURRENT_TIMESTAMP'; - } - - $displayed_fields[$rownum] = new stdClass(); - $displayed_fields[$rownum]->text = $field['Field']; - $displayed_fields[$rownum]->icon = ""; - $row_comments[$rownum] = ''; - - if (isset($comments_map[$field['Field']])) { - $displayed_fields[$rownum]->comment = $comments_map[$field['Field']]; - $row_comments[$rownum] = $comments_map[$field['Field']]; - } - - if ($primary_index && $primary_index->hasColumn($field['Field'])) { - $displayed_fields[$rownum]->icon .= - Util::getImage('b_primary', __('Primary')); - } - - if (in_array($field['Field'], $columns_with_index)) { - $displayed_fields[$rownum]->icon .= - Util::getImage('bd_primary', __('Index')); - } - - $collation = Charsets::findCollationByName( - $this->dbi, - $GLOBALS['cfg']['Server']['DisableIS'], - $field['Collation'] ?? '' - ); - if ($collation !== null) { - $collations[$collation->getName()] = [ - 'name' => $collation->getName(), - 'description' => $collation->getDescription(), - ]; - } - } - - $engine = $this->table_obj->getStorageEngine(); - return $this->template->render('table/structure/display_structure', [ - 'url_params' => [ - 'db' => $this->db, - 'table' => $this->table, - ], - 'collations' => $collations, - 'is_foreign_key_supported' => Util::isForeignKeySupported($engine), - 'displayIndexesHtml' => Index::getHtmlForDisplayIndexes(), - 'cfg_relation' => $this->relation->getRelationsParam(), - 'hide_structure_actions' => $hideStructureActions, - 'db' => $this->db, - 'table' => $this->table, - 'db_is_system_schema' => $this->_db_is_system_schema, - 'tbl_is_view' => $this->_tbl_is_view, - 'mime_map' => $mime_map, - 'url_query' => $this->_url_query, - 'titles' => $titles, - 'tbl_storage_engine' => $this->_tbl_storage_engine, - 'primary' => $primary_index, - 'columns_with_unique_index' => $columns_with_unique_index, - 'edit_view_url' => $edit_view_url, - 'columns_list' => $columns_list, - 'table_stats' => isset($tablestats) ? $tablestats : null, - 'fields' => $fields, - 'extracted_columnspecs' => $extracted_columnspecs, - 'columns_with_index' => $columns_with_index, - 'central_list' => $central_list, - 'comments_map' => $comments_map, - 'browse_mime' => $GLOBALS['cfg']['BrowseMIME'], - 'show_column_comments' => $GLOBALS['cfg']['ShowColumnComments'], - 'show_stats' => $GLOBALS['cfg']['ShowStats'], - 'relation_commwork' => $GLOBALS['cfgRelation']['commwork'], - 'relation_mimework' => $GLOBALS['cfgRelation']['mimework'], - 'central_columns_work' => $GLOBALS['cfgRelation']['centralcolumnswork'], - 'mysql_int_version' => $this->dbi->getVersion(), - 'is_mariadb' => $this->dbi->isMariaDB(), - 'pma_theme_image' => $GLOBALS['pmaThemeImage'], - 'text_dir' => $GLOBALS['text_dir'], - 'is_active' => Tracker::isActive(), - 'have_partitioning' => Partition::havePartitioning(), - 'partitions' => Partition::getPartitions($this->db, $this->table), - 'partition_names' => Partition::getPartitionNames($this->db, $this->table), - 'default_sliders_state' => $GLOBALS['cfg']['InitialSlidersState'], - 'attributes' => $attributes, - 'displayed_fields' => $displayed_fields, - 'row_comments' => $row_comments, - ]); - } - - /** - * Get HTML snippet for display table statistics - * - * @return string - */ - protected function getTableStats() - { - if (empty($this->_showtable)) { - $this->_showtable = $this->dbi->getTable( - $this->db, - $this->table - )->getStatusInfo(null, true); - } - - if (empty($this->_showtable['Data_length'])) { - $this->_showtable['Data_length'] = 0; - } - if (empty($this->_showtable['Index_length'])) { - $this->_showtable['Index_length'] = 0; - } - - $is_innodb = (isset($this->_showtable['Type']) - && $this->_showtable['Type'] == 'InnoDB'); - - $mergetable = $this->table_obj->isMerge(); - - // this is to display for example 261.2 MiB instead of 268k KiB - $max_digits = 3; - $decimals = 1; - list($data_size, $data_unit) = Util::formatByteDown( - $this->_showtable['Data_length'], - $max_digits, - $decimals - ); - if ($mergetable === false) { - list($index_size, $index_unit) = Util::formatByteDown( - $this->_showtable['Index_length'], - $max_digits, - $decimals - ); - } - if (isset($this->_showtable['Data_free'])) { - list($free_size, $free_unit) = Util::formatByteDown( - $this->_showtable['Data_free'], - $max_digits, - $decimals - ); - list($effect_size, $effect_unit) = Util::formatByteDown( - $this->_showtable['Data_length'] - + $this->_showtable['Index_length'] - - $this->_showtable['Data_free'], - $max_digits, - $decimals - ); - } else { - list($effect_size, $effect_unit) = Util::formatByteDown( - $this->_showtable['Data_length'] - + $this->_showtable['Index_length'], - $max_digits, - $decimals - ); - } - list($tot_size, $tot_unit) = Util::formatByteDown( - $this->_showtable['Data_length'] + $this->_showtable['Index_length'], - $max_digits, - $decimals - ); - if ($this->_table_info_num_rows > 0) { - list($avg_size, $avg_unit) = Util::formatByteDown( - ($this->_showtable['Data_length'] - + $this->_showtable['Index_length']) - / $this->_showtable['Rows'], - 6, - 1 - ); - } else { - $avg_size = $avg_unit = ''; - } - /** @var Innodb $innodbEnginePlugin */ - $innodbEnginePlugin = StorageEngine::getEngine('Innodb'); - $innodb_file_per_table = $innodbEnginePlugin->supportsFilePerTable(); - - $engine = $this->dbi->getTable($this->db, $this->table)->getStorageEngine(); - - $tableCollation = []; - $collation = Charsets::findCollationByName( - $this->dbi, - $GLOBALS['cfg']['Server']['DisableIS'], - $this->_tbl_collation - ); - if ($collation !== null) { - $tableCollation = [ - 'name' => $collation->getName(), - 'description' => $collation->getDescription(), - ]; - } - return $this->template->render('table/structure/display_table_stats', [ - 'url_params' => [ - 'db' => $GLOBALS['db'], - 'table' => $GLOBALS['table'], - ], - 'is_foreign_key_supported' => Util::isForeignKeySupported($engine), - 'cfg_relation' => $this->relation->getRelationsParam(), - 'showtable' => $this->_showtable, - 'table_info_num_rows' => $this->_table_info_num_rows, - 'tbl_is_view' => $this->_tbl_is_view, - 'db_is_system_schema' => $this->_db_is_system_schema, - 'tbl_storage_engine' => $this->_tbl_storage_engine, - 'url_query' => $this->_url_query, - 'table_collation' => $tableCollation, - 'is_innodb' => $is_innodb, - 'mergetable' => $mergetable, - 'avg_size' => isset($avg_size) ? $avg_size : null, - 'avg_unit' => isset($avg_unit) ? $avg_unit : null, - 'data_size' => $data_size, - 'data_unit' => $data_unit, - 'index_size' => isset($index_size) ? $index_size : null, - 'index_unit' => isset($index_unit) ? $index_unit : null, - 'innodb_file_per_table' => $innodb_file_per_table, - 'free_size' => isset($free_size) ? $free_size : null, - 'free_unit' => isset($free_unit) ? $free_unit : null, - 'effect_size' => $effect_size, - 'effect_unit' => $effect_unit, - 'tot_size' => $tot_size, - 'tot_unit' => $tot_unit, - 'table' => $GLOBALS['table'], - ]); - } - - /** - * Gets table primary key - * - * @return string - */ - protected function getKeyForTablePrimary() - { - $this->dbi->selectDb($this->db); - $result = $this->dbi->query( - 'SHOW KEYS FROM ' . Util::backquote($this->table) . ';' - ); - $primary = ''; - while ($row = $this->dbi->fetchAssoc($result)) { - // Backups the list of primary keys - if ($row['Key_name'] == 'PRIMARY') { - $primary .= $row['Column_name'] . ', '; - } - } // end while - $this->dbi->freeResult($result); - - return $primary; - } - - /** - * Get List of information for Submit Mult - * - * @param string $submit_mult mult_submit type - * @param array $selected the selected columns - * @param string $action action type - * @param ContainerBuilder $containerBuilder Container builder instance - * - * @return array - */ - protected function getDataForSubmitMult($submit_mult, $selected, $action, ContainerBuilder $containerBuilder) - { - $centralColumns = new CentralColumns($this->dbi); - $what = null; - $query_type = null; - $is_unset_submit_mult = false; - $mult_btn = null; - $centralColsError = null; - switch ($submit_mult) { - case 'drop': - $what = 'drop_fld'; - break; - case 'primary': - // Gets table primary key - $primary = $this->getKeyForTablePrimary(); - if (empty($primary)) { - // no primary key, so we can safely create new - $is_unset_submit_mult = true; - $query_type = 'primary_fld'; - $mult_btn = __('Yes'); - } else { - // primary key exists, so lets as user - $what = 'primary_fld'; - } - break; - case 'index': - $is_unset_submit_mult = true; - $query_type = 'index_fld'; - $mult_btn = __('Yes'); - break; - case 'unique': - $is_unset_submit_mult = true; - $query_type = 'unique_fld'; - $mult_btn = __('Yes'); - break; - case 'spatial': - $is_unset_submit_mult = true; - $query_type = 'spatial_fld'; - $mult_btn = __('Yes'); - break; - case 'ftext': - $is_unset_submit_mult = true; - $query_type = 'fulltext_fld'; - $mult_btn = __('Yes'); - break; - case 'add_to_central_columns': - $centralColsError = $centralColumns->syncUniqueColumns( - $selected, - false - ); - break; - case 'remove_from_central_columns': - $centralColsError = $centralColumns->deleteColumnsFromList( - $_POST['db'], - $selected, - false - ); - break; - case 'change': - $this->displayHtmlForColumnChange($selected, $action, $containerBuilder); - // execution stops here but PhpMyAdmin\Response correctly finishes - // the rendering - exit; - case 'browse': - // this should already be handled by tbl_structure.php - } - - return [ - $what, - $query_type, - $is_unset_submit_mult, - $mult_btn, - $centralColsError, - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Controllers/TransformationOverviewController.php b/srcs/phpmyadmin/libraries/classes/Controllers/TransformationOverviewController.php deleted file mode 100644 index 621961f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Controllers/TransformationOverviewController.php +++ /dev/null @@ -1,80 +0,0 @@ -transformations = $transformations; - } - - /** - * @return string HTML - */ - public function indexAction(): string - { - $types = $this->transformations->getAvailableMimeTypes(); - - $mimeTypes = []; - foreach ($types['mimetype'] as $mimeType) { - $mimeTypes[] = [ - 'name' => $mimeType, - 'is_empty' => isset($types['empty_mimetype'][$mimeType]), - ]; - } - - $transformations = [ - 'transformation' => [], - 'input_transformation' => [], - ]; - - foreach (array_keys($transformations) as $type) { - foreach ($types[$type] as $key => $transformation) { - $transformations[$type][] = [ - 'name' => $transformation, - 'description' => $this->transformations->getDescription( - $types[$type . '_file'][$key] - ), - ]; - } - } - - return $this->template->render('transformation_overview', [ - 'mime_types' => $mimeTypes, - 'transformations' => $transformations, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Core.php b/srcs/phpmyadmin/libraries/classes/Core.php deleted file mode 100644 index 581afbc..0000000 --- a/srcs/phpmyadmin/libraries/classes/Core.php +++ /dev/null @@ -1,1302 +0,0 @@ - - * // $_REQUEST['db'] not set - * echo Core::ifSetOr($_REQUEST['db'], ''); // '' - * // $_POST['sql_query'] not set - * echo Core::ifSetOr($_POST['sql_query']); // null - * // $cfg['EnableFoo'] not set - * echo Core::ifSetOr($cfg['EnableFoo'], false, 'boolean'); // false - * echo Core::ifSetOr($cfg['EnableFoo']); // null - * // $cfg['EnableFoo'] set to 1 - * echo Core::ifSetOr($cfg['EnableFoo'], false, 'boolean'); // false - * echo Core::ifSetOr($cfg['EnableFoo'], false, 'similar'); // 1 - * echo Core::ifSetOr($cfg['EnableFoo'], false); // 1 - * // $cfg['EnableFoo'] set to true - * echo Core::ifSetOr($cfg['EnableFoo'], 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 self::isValid() - */ - public static function ifSetOr(&$var, $default = null, $type = 'similar') - { - if (! self::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 representation - * - '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; - * Core::isValid($_REQUEST['doit'], 'identical', 'true'); // false - * // $_REQUEST['doit'] = 'true'; - * Core::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 https://secure.php.net/gettype - */ - public static function isValid(&$var, $type = 'length', $compare = null): bool - { - 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 aliases 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 strlen((string) $var) > 0; - } - return $is_scalar; - } - - if ($type === 'numeric') { - return is_numeric($var); - } - - return gettype($var) === $type; - } - - /** - * 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 - */ - public static function securePath(string $path): string - { - // change .. to . - return preg_replace('@\.\.*@', '.', $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 - * - * @return void - */ - public static function fatalError( - string $error_message, - $message_args = null - ): void { - /* 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); - } - - /* - * Avoid using Response class as config does not have to be loaded yet - * (this can happen on early fatal error) - */ - if (isset($GLOBALS['dbi']) && $GLOBALS['dbi'] !== null && isset($GLOBALS['PMA_Config']) && $GLOBALS['PMA_Config']->get('is_setup') === false && Response::getInstance()->isAjax()) { - $response = Response::getInstance(); - $response->setRequestStatus(false); - $response->addJSON('message', Message::error($error_message)); - } elseif (! empty($_REQUEST['ajax_request'])) { - // Generate JSON manually - self::headerJSON(); - echo json_encode( - [ - 'success' => false, - 'message' => Message::error($error_message)->getDisplay(), - ] - ); - } else { - $error_message = strtr($error_message, ['
' => '[br]']); - $error_header = __('Error'); - $lang = isset($GLOBALS['lang']) ? $GLOBALS['lang'] : 'en'; - $dir = isset($GLOBALS['text_dir']) ? $GLOBALS['text_dir'] : 'ltr'; - - echo DisplayError::display(new Template(), $lang, $dir, $error_header, $error_message); - } - if (! defined('TESTSUITE')) { - exit; - } - } - - /** - * Returns a link to the PHP documentation - * - * @param string $target anchor in documentation - * - * @return string the URL - * - * @access public - */ - public static function getPHPDocLink(string $target): string - { - /* List of PHP documentation translations */ - $php_doc_languages = [ - '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 self::linkURL('https://secure.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 message. - * - * @return void - */ - public static function warnMissingExtension( - string $extension, - bool $fatal = false, - string $extra = '' - ): void { - /* 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 = self::getPHPDocLink('book.' . $extension . '.php'); - $message = sprintf( - $message, - '[a@' . $doclink . '@Documentation][em]' . $extension . '[/em][/a]' - ); - if ($extra != '') { - $message .= ' ' . $extra; - } - if ($fatal) { - self::fatalError($message); - return; - } - - $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 - */ - public static function getTableCount(string $db): int - { - $tables = $GLOBALS['dbi']->tryQuery( - 'SHOW TABLES FROM ' . Util::backquote($db) . ';', - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - if ($tables) { - $num_tables = $GLOBALS['dbi']->numRows($tables); - $GLOBALS['dbi']->freeResult($tables); - } else { - $num_tables = 0; - } - - return $num_tables; - } - - /** - * Converts numbers like 10M into bytes - * Used with permission from Moodle (https://moodle.org) by Martin Dougiamas - * (renamed with PMA prefix to avoid double definition when embedded - * in Moodle) - * - * @param string|int $size size (Default = 0) - * - * @return integer - */ - public static function getRealSize($size = 0): int - { - if (! $size) { - return 0; - } - - $binaryprefixes = [ - 'T' => 1099511627776, - 't' => 1099511627776, - 'G' => 1073741824, - 'g' => 1073741824, - 'M' => 1048576, - 'm' => 1048576, - 'K' => 1024, - 'k' => 1024, - ]; - - if (preg_match('/^([0-9]+)([KMGT])/i', $size, $matches)) { - return $matches[1] * $binaryprefixes[$matches[2]]; - } - - return (int) $size; - } // end getRealSize() - - /** - * Checks given $page against given $whitelist and returns true if valid - * it optionally ignores query parameters in $page (script.php?ignored) - * - * @param string $page page to check - * @param array $whitelist whitelist to check page against - * @param boolean $include whether the page is going to be included - * - * @return boolean whether $page is valid or not (in $whitelist or not) - */ - public static function checkPageValidity(&$page, array $whitelist = [], $include = false): bool - { - if (empty($whitelist)) { - $whitelist = self::$goto_whitelist; - } - if (empty($page)) { - return false; - } - - if (in_array($page, $whitelist)) { - return true; - } - if ($include) { - return false; - } - - $_page = mb_substr( - $page, - 0, - mb_strpos($page . '?', '?') - ); - if (in_array($_page, $whitelist)) { - return true; - } - - $_page = urldecode($page); - $_page = mb_substr( - $_page, - 0, - mb_strpos($_page . '?', '?') - ); - if (in_array($_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 - */ - public static function getenv(string $var_name): string - { - if (isset($_SERVER[$var_name])) { - return (string) $_SERVER[$var_name]; - } - - if (isset($_ENV[$var_name])) { - return (string) $_ENV[$var_name]; - } - - if (getenv($var_name)) { - return getenv($var_name); - } - - if (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 void - */ - public static function sendHeaderLocation(string $uri, bool $use_refresh = false): void - { - if ($GLOBALS['PMA_Config']->get('PMA_IS_IIS') && mb_strlen($uri) > 600) { - Response::getInstance()->disable(); - - $template = new Template(); - echo $template->render('header_location', ['uri' => $uri]); - - return; - } - - /* - * Avoid relative path redirect problems in case user entered URL - * like /phpmyadmin/index.php/ which some web servers happily accept. - */ - if ($uri[0] == '.') { - $uri = $GLOBALS['PMA_Config']->getRootPath() . substr($uri, 2); - } - - $response = Response::getInstance(); - - session_write_close(); - if ($response->headersSent()) { - trigger_error( - 'Core::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 ($GLOBALS['PMA_Config']->get('PMA_IS_IIS') && $use_refresh) { - $response->header('Refresh: 0; ' . $uri); - } else { - $response->header('Location: ' . $uri); - } - } - - /** - * Outputs application/json headers. This includes no caching. - * - * @return void - */ - public static function headerJSON(): void - { - if (defined('TESTSUITE')) { - return; - } - // No caching - self::noCacheHeader(); - // MIME type - header('Content-Type: application/json; charset=UTF-8'); - // Disable content sniffing in browser - // This is needed in case we include HTML in JSON, browser might assume it's - // html to display - header('X-Content-Type-Options: nosniff'); - } - - /** - * Outputs headers to prevent caching in browser (and on the way). - * - * @return void - */ - public static function noCacheHeader(): void - { - if (defined('TESTSUITE')) { - return; - } - // rfc2616 - Section 14.21 - header('Expires: ' . gmdate(DATE_RFC1123)); - // HTTP/1.1 - header( - 'Cache-Control: no-store, no-cache, must-revalidate,' - . ' pre-check=0, post-check=0, max-age=0' - ); - - 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: ' . gmdate(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 - */ - public static function downloadHeader( - string $filename, - string $mimetype, - int $length = 0, - bool $no_cache = true - ): void { - if ($no_cache) { - self::noCacheHeader(); - } - /* Replace all possibly dangerous chars in filename */ - $filename = Sanitize::sanitizeFilename($filename); - if (! empty($filename)) { - header('Content-Description: File Transfer'); - header('Content-Disposition: attachment; filename="' . $filename . '"'); - } - header('Content-Type: ' . $mimetype); - // inform the server that compression has been done, - // to avoid a double compression (for example with Apache + mod_deflate) - $notChromeOrLessThan43 = PMA_USR_BROWSER_AGENT != 'CHROME' // see bug #4942 - || (PMA_USR_BROWSER_AGENT == 'CHROME' && PMA_USR_BROWSER_VER < 43); - if (strpos($mimetype, 'gzip') !== false && $notChromeOrLessThan43) { - header('Content-Encoding: gzip'); - } - 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 array - * @param array $array the array - * @param mixed $default default value - * - * @return mixed array element or $default - */ - public static function arrayRead(string $path, array $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 - */ - public static function arrayWrite(string $path, array &$array, $value): void - { - $keys = explode('/', $path); - $last_key = array_pop($keys); - $a =& $array; - foreach ($keys as $key) { - if (! isset($a[$key])) { - $a[$key] = []; - } - $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 - */ - public static function arrayRemove(string $path, array &$array): void - { - $keys = explode('/', $path); - $keys_last = array_pop($keys); - $path = []; - $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. - */ - public static function linkURL(string $url): string - { - if (! preg_match('#^https?://#', $url)) { - return $url; - } - - $params = []; - $params['url'] = $url; - - $url = Url::getCommon($params); - //strip off token and such sensitive information. Just keep url. - $arr = parse_url($url); - parse_str($arr["query"], $vars); - $query = http_build_query(["url" => $vars["url"]]); - - if ($GLOBALS['PMA_Config'] !== null && $GLOBALS['PMA_Config']->get('is_setup')) { - $url = '../url.php?' . $query; - } else { - $url = './url.php?' . $query; - } - - return $url; - } - - /** - * Checks whether domain of URL is whitelisted domain or not. - * Use only for URLs of external sites. - * - * @param string $url URL of external site. - * - * @return boolean True: if domain of $url is allowed domain, - * False: otherwise. - */ - public static function isAllowedDomain(string $url): bool - { - $arr = parse_url($url); - // We need host to be set - if (! isset($arr['host']) || strlen($arr['host']) == 0) { - return false; - } - // We do not want these to be present - $blocked = [ - 'user', - 'pass', - 'port', - ]; - foreach ($blocked as $part) { - if (isset($arr[$part]) && strlen((string) $arr[$part]) != 0) { - return false; - } - } - $domain = $arr["host"]; - $domainWhiteList = [ - /* Include current domain */ - $_SERVER['SERVER_NAME'], - /* phpMyAdmin domains */ - 'wiki.phpmyadmin.net', - 'www.phpmyadmin.net', - 'phpmyadmin.net', - 'demo.phpmyadmin.net', - 'docs.phpmyadmin.net', - /* mysql.com domains */ - 'dev.mysql.com', - 'bugs.mysql.com', - /* mariadb domains */ - 'mariadb.org', - 'mariadb.com', - /* php.net domains */ - 'php.net', - 'secure.php.net', - /* Github domains*/ - 'github.com', - 'www.github.com', - /* Percona domains */ - 'www.percona.com', - /* Following are doubtful ones. */ - 'mysqldatabaseadministration.blogspot.com', - ]; - - return in_array($domain, $domainWhiteList); - } - - /** - * Replace some html-unfriendly stuff - * - * @param string $buffer String to process - * - * @return string Escaped and cleaned up text suitable for html - */ - public static function mimeDefaultFunction(string $buffer): string - { - $buffer = htmlspecialchars($buffer); - $buffer = str_replace(' ', '  ', $buffer); - return preg_replace("@((\015\012)|(\015)|(\012))@", '
' . "\n", $buffer); - } - - /** - * Displays SQL query before executing. - * - * @param array|string $query_data Array containing queries or query itself - * - * @return void - */ - public static function previewSQL($query_data): void - { - $retval = '
'; - if (empty($query_data)) { - $retval .= __('No change'); - } elseif (is_array($query_data)) { - foreach ($query_data as $query) { - $retval .= Util::formatSql($query); - } - } else { - $retval .= Util::formatSql($query_data); - } - $retval .= '
'; - $response = Response::getInstance(); - $response->addJSON('sql_data', $retval); - exit; - } - - /** - * recursively check if variable is empty - * - * @param mixed $value the variable - * - * @return bool true if empty - */ - public static function emptyRecursive($value): bool - { - $empty = true; - if (is_array($value)) { - array_walk_recursive( - $value, - function ($item) use (&$empty) { - $empty = $empty && empty($item); - } - ); - } else { - $empty = empty($value); - } - return $empty; - } - - /** - * Creates some globals from $_POST variables matching a pattern - * - * @param array $post_patterns The patterns to search for - * - * @return void - */ - public static function setPostAsGlobal(array $post_patterns): void - { - foreach (array_keys($_POST) as $post_key) { - foreach ($post_patterns as $one_post_pattern) { - if (preg_match($one_post_pattern, $post_key)) { - Migration::getInstance()->setGlobal($post_key, $_POST[$post_key]); - } - } - } - } - - /** - * Creates some globals from $_REQUEST - * - * @param string $param db|table - * - * @return void - */ - public static function setGlobalDbOrTable(string $param): void - { - $value = ''; - if (self::isValid($_REQUEST[$param])) { - $value = $_REQUEST[$param]; - } - Migration::getInstance()->setGlobal($param, $value); - Migration::getInstance()->setGlobal('url_params', [$param => $value] + $GLOBALS['url_params']); - } - - /** - * PATH_INFO could be compromised if set, so remove it from PHP_SELF - * and provide a clean PHP_SELF here - * - * @return void - */ - public static function cleanupPathInfo(): void - { - global $PMA_PHP_SELF; - - $PMA_PHP_SELF = self::getenv('PHP_SELF'); - if (empty($PMA_PHP_SELF)) { - $PMA_PHP_SELF = urldecode(self::getenv('REQUEST_URI')); - } - $_PATH_INFO = self::getenv('PATH_INFO'); - if (! empty($_PATH_INFO) && ! empty($PMA_PHP_SELF)) { - $question_pos = mb_strpos($PMA_PHP_SELF, '?'); - if ($question_pos != false) { - $PMA_PHP_SELF = mb_substr($PMA_PHP_SELF, 0, $question_pos); - } - $path_info_pos = mb_strrpos($PMA_PHP_SELF, $_PATH_INFO); - if ($path_info_pos !== false) { - $path_info_part = mb_substr($PMA_PHP_SELF, $path_info_pos, mb_strlen($_PATH_INFO)); - if ($path_info_part == $_PATH_INFO) { - $PMA_PHP_SELF = mb_substr($PMA_PHP_SELF, 0, $path_info_pos); - } - } - } - - $path = []; - foreach (explode('/', $PMA_PHP_SELF) as $part) { - // ignore parts that have no value - if (empty($part) || $part === '.') { - continue; - } - - if ($part !== '..') { - // cool, we found a new part - $path[] = $part; - } elseif (count($path) > 0) { - // going back up? sure - array_pop($path); - } - // Here we intentionall ignore case where we go too up - // as there is nothing sane to do - } - - $PMA_PHP_SELF = htmlspecialchars('/' . implode('/', $path)); - } - - /** - * Checks that required PHP extensions are there. - * @return void - */ - public static function checkExtensions(): void - { - /** - * Warning about mbstring. - */ - if (! function_exists('mb_detect_encoding')) { - self::warnMissingExtension('mbstring'); - } - - /** - * We really need this one! - */ - if (! function_exists('preg_replace')) { - self::warnMissingExtension('pcre', true); - } - - /** - * JSON is required in several places. - */ - if (! function_exists('json_encode')) { - self::warnMissingExtension('json', true); - } - - /** - * ctype is required for Twig. - */ - if (! function_exists('ctype_alpha')) { - self::warnMissingExtension('ctype', true); - } - - /** - * hash is required for cookie authentication. - */ - if (! function_exists('hash_hmac')) { - self::warnMissingExtension('hash', true); - } - } - - /** - * Gets the "true" IP address of the current user - * - * @return string|bool the ip of the user - * - * @access private - */ - public static function getIp() - { - /* Get the address of user */ - if (empty($_SERVER['REMOTE_ADDR'])) { - /* We do not know remote IP */ - return false; - } - - $direct_ip = $_SERVER['REMOTE_ADDR']; - - /* Do we trust this IP as a proxy? If yes we will use it's header. */ - if (! isset($GLOBALS['cfg']['TrustedProxies'][$direct_ip])) { - /* Return true IP */ - return $direct_ip; - } - - /** - * Parse header in form: - * X-Forwarded-For: client, proxy1, proxy2 - */ - // Get header content - $value = self::getenv($GLOBALS['cfg']['TrustedProxies'][$direct_ip]); - // Grab first element what is client adddress - $value = explode(',', $value)[0]; - // checks that the header contains only one IP address, - $is_ip = filter_var($value, FILTER_VALIDATE_IP); - - if ($is_ip !== false) { - // True IP behind a proxy - return $value; - } - - // We could not parse header - return false; - } // end of the 'getIp()' function - - /** - * Sanitizes MySQL hostname - * - * * strips p: prefix(es) - * - * @param string $name User given hostname - * - * @return string - */ - public static function sanitizeMySQLHost(string $name): string - { - while (strtolower(substr($name, 0, 2)) == 'p:') { - $name = substr($name, 2); - } - - return $name; - } - - /** - * Sanitizes MySQL username - * - * * strips part behind null byte - * - * @param string $name User given username - * - * @return string - */ - public static function sanitizeMySQLUser(string $name): string - { - $position = strpos($name, chr(0)); - if ($position !== false) { - return substr($name, 0, $position); - } - return $name; - } - - /** - * Safe unserializer wrapper - * - * It does not unserialize data containing objects - * - * @param string $data Data to unserialize - * - * @return mixed - */ - public static function safeUnserialize(string $data) - { - if (! is_string($data)) { - return null; - } - - /* validate serialized data */ - $length = strlen($data); - $depth = 0; - for ($i = 0; $i < $length; $i++) { - $value = $data[$i]; - - switch ($value) { - case '}': - /* end of array */ - if ($depth <= 0) { - return null; - } - $depth--; - break; - case 's': - /* string */ - // parse sting length - $strlen = intval(substr($data, $i + 2)); - // string start - $i = strpos($data, ':', $i + 2); - if ($i === false) { - return null; - } - // skip string, quotes and ; - $i += 2 + $strlen + 1; - if ($data[$i] != ';') { - return null; - } - break; - - case 'b': - case 'i': - case 'd': - /* bool, integer or double */ - // skip value to sepearator - $i = strpos($data, ';', $i); - if ($i === false) { - return null; - } - break; - case 'a': - /* array */ - // find array start - $i = strpos($data, '{', $i); - if ($i === false) { - return null; - } - // remember nesting - $depth++; - break; - case 'N': - /* null */ - // skip to end - $i = strpos($data, ';', $i); - if ($i === false) { - return null; - } - break; - default: - /* any other elements are not wanted */ - return null; - } - } - - // check unterminated arrays - if ($depth > 0) { - return null; - } - - return unserialize($data); - } - - /** - * Applies changes to PHP configuration. - * - * @return void - */ - public static function configure(): void - { - /** - * Set utf-8 encoding for PHP - */ - ini_set('default_charset', 'utf-8'); - mb_internal_encoding('utf-8'); - - /** - * Set precision to sane value, with higher values - * things behave slightly unexpectedly, for example - * round(1.2, 2) returns 1.199999999999999956. - */ - ini_set('precision', '14'); - - /** - * check timezone setting - * this could produce an E_WARNING - but only once, - * if not done here it will produce E_WARNING on every date/time function - */ - date_default_timezone_set(@date_default_timezone_get()); - } - - /** - * Check whether PHP configuration matches our needs. - * - * @return void - */ - public static function checkConfiguration(): void - { - /** - * As we try to handle charsets by ourself, mbstring overloads just - * break it, see bug 1063821. - * - * We specifically use empty here as we are looking for anything else than - * empty value or 0. - */ - if (extension_loaded('mbstring') && ! empty(ini_get('mbstring.func_overload'))) { - self::fatalError( - __( - 'You have enabled mbstring.func_overload in your PHP ' - . 'configuration. This option is incompatible with phpMyAdmin ' - . 'and might cause some data to be corrupted!' - ) - ); - } - - /** - * The ini_set and ini_get functions can be disabled using - * disable_functions but we're relying quite a lot of them. - */ - if (! function_exists('ini_get') || ! function_exists('ini_set')) { - self::fatalError( - __( - 'The ini_get and/or ini_set functions are disabled in php.ini. ' - . 'phpMyAdmin requires these functions!' - ) - ); - } - } - - /** - * Checks request and fails with fatal error if something problematic is found - * - * @return void - */ - public static function checkRequest(): void - { - if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) { - self::fatalError(__("GLOBALS overwrite attempt")); - } - - /** - * protect against possible exploits - there is no need to have so much variables - */ - if (count($_REQUEST) > 1000) { - self::fatalError(__('possible exploit')); - } - } - - /** - * Sign the sql query using hmac using the session token - * - * @param string $sqlQuery The sql query - * @return string - */ - public static function signSqlQuery($sqlQuery) - { - /** @var array $cfg */ - global $cfg; - return hash_hmac('sha256', $sqlQuery, $_SESSION[' HMAC_secret '] . $cfg['blowfish_secret']); - } - - /** - * Check that the sql query has a valid hmac signature - * - * @param string $sqlQuery The sql query - * @param string $signature The Signature to check - * @return bool - */ - public static function checkSqlQuerySignature($sqlQuery, $signature) - { - /** @var array $cfg */ - global $cfg; - $hmac = hash_hmac('sha256', $sqlQuery, $_SESSION[' HMAC_secret '] . $cfg['blowfish_secret']); - return hash_equals($hmac, $signature); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/CreateAddField.php b/srcs/phpmyadmin/libraries/classes/CreateAddField.php deleted file mode 100644 index 1020f10..0000000 --- a/srcs/phpmyadmin/libraries/classes/CreateAddField.php +++ /dev/null @@ -1,555 +0,0 @@ -dbi = $dbi; - } - - /** - * Transforms the radio button field_key into 4 arrays - * - * @return array An array of arrays which represents column keys for each index type - */ - private function getIndexedColumns(): array - { - $fieldCount = count($_POST['field_name']); - $fieldPrimary = json_decode($_POST['primary_indexes'], true); - $fieldIndex = json_decode($_POST['indexes'], true); - $fieldUnique = json_decode($_POST['unique_indexes'], true); - $fieldFullText = json_decode($_POST['fulltext_indexes'], true); - $fieldSpatial = json_decode($_POST['spatial_indexes'], true); - - return [ - $fieldCount, - $fieldPrimary, - $fieldIndex, - $fieldUnique, - $fieldFullText, - $fieldSpatial, - ]; - } - - /** - * Initiate the column creation statement according to the table creation or - * add columns to a existing table - * - * @param int $fieldCount number of columns - * @param boolean $isCreateTable true if requirement is to get the statement - * for table creation - * - * @return array An array of initial sql statements - * according to the request - */ - private function buildColumnCreationStatement( - int $fieldCount, - bool $isCreateTable = true - ): array { - $definitions = []; - $previousField = -1; - for ($i = 0; $i < $fieldCount; ++$i) { - // '0' is also empty for php :-( - if (strlen($_POST['field_name'][$i]) === 0) { - continue; - } - - $definition = $this->getStatementPrefix($isCreateTable) . - Table::generateFieldSpec( - trim($_POST['field_name'][$i]), - $_POST['field_type'][$i], - $_POST['field_length'][$i], - $_POST['field_attribute'][$i], - isset($_POST['field_collation'][$i]) - ? $_POST['field_collation'][$i] - : '', - isset($_POST['field_null'][$i]) - ? $_POST['field_null'][$i] - : 'NO', - $_POST['field_default_type'][$i], - $_POST['field_default_value'][$i], - isset($_POST['field_extra'][$i]) - ? $_POST['field_extra'][$i] - : false, - isset($_POST['field_comments'][$i]) - ? $_POST['field_comments'][$i] - : '', - isset($_POST['field_virtuality'][$i]) - ? $_POST['field_virtuality'][$i] - : '', - isset($_POST['field_expression'][$i]) - ? $_POST['field_expression'][$i] - : '' - ); - - $definition .= $this->setColumnCreationStatementSuffix( - $previousField, - $isCreateTable - ); - $previousField = $i; - $definitions[] = $definition; - } // end for - - return $definitions; - } - - /** - * Set column creation suffix according to requested position of the new column - * - * @param int $previousField previous field for ALTER statement - * @param bool $isCreateTable true if requirement is to get the statement - * for table creation - * - * @return string suffix - */ - private function setColumnCreationStatementSuffix( - int $previousField, - bool $isCreateTable = true - ): string { - // no suffix is needed if request is a table creation - $sqlSuffix = ' '; - if ($isCreateTable) { - return $sqlSuffix; - } - - if ((string) $_POST['field_where'] === 'last') { - return $sqlSuffix; - } - - // Only the first field can be added somewhere other than at the end - if ($previousField == -1) { - if ((string) $_POST['field_where'] === 'first') { - $sqlSuffix .= ' FIRST'; - } elseif (! empty($_POST['after_field'])) { - $sqlSuffix .= ' AFTER ' - . Util::backquote($_POST['after_field']); - } - } else { - $sqlSuffix .= ' AFTER ' - . Util::backquote( - $_POST['field_name'][$previousField] - ); - } - - return $sqlSuffix; - } - - /** - * Create relevant index statements - * - * @param array $index an array of index columns - * @param string $indexChoice index choice that which represents - * the index type of $indexed_fields - * @param boolean $isCreateTable true if requirement is to get the statement - * for table creation - * - * @return array an array of sql statements for indexes - */ - private function buildIndexStatements( - array $index, - string $indexChoice, - bool $isCreateTable = true - ): array { - $statement = []; - if (! count($index)) { - return $statement; - } - - $sqlQuery = $this->getStatementPrefix($isCreateTable) - . ' ' . $indexChoice; - - if (! empty($index['Key_name']) && $index['Key_name'] != 'PRIMARY') { - $sqlQuery .= ' ' . Util::backquote($index['Key_name']); - } - - $indexFields = []; - foreach ($index['columns'] as $key => $column) { - $indexFields[$key] = Util::backquote( - $_POST['field_name'][$column['col_index']] - ); - if ($column['size']) { - $indexFields[$key] .= '(' . $column['size'] . ')'; - } - } - - $sqlQuery .= ' (' . implode(', ', $indexFields) . ')'; - - $keyBlockSizes = $index['Key_block_size']; - if (! empty($keyBlockSizes)) { - $sqlQuery .= " KEY_BLOCK_SIZE = " - . $this->dbi->escapeString($keyBlockSizes); - } - - // specifying index type is allowed only for primary, unique and index only - $type = $index['Index_type']; - if ($index['Index_choice'] != 'SPATIAL' - && $index['Index_choice'] != 'FULLTEXT' - && in_array($type, Index::getIndexTypes()) - ) { - $sqlQuery .= ' USING ' . $type; - } - - $parser = $index['Parser']; - if ($index['Index_choice'] == 'FULLTEXT' && ! empty($parser)) { - $sqlQuery .= " WITH PARSER " . $this->dbi->escapeString($parser); - } - - $comment = $index['Index_comment']; - if (! empty($comment)) { - $sqlQuery .= " COMMENT '" . $this->dbi->escapeString($comment) - . "'"; - } - - $statement[] = $sqlQuery; - - return $statement; - } - - /** - * Statement prefix for the buildColumnCreationStatement() - * - * @param boolean $isCreateTable true if requirement is to get the statement - * for table creation - * - * @return string prefix - */ - private function getStatementPrefix(bool $isCreateTable = true): string - { - $sqlPrefix = " "; - if (! $isCreateTable) { - $sqlPrefix = ' ADD '; - } - return $sqlPrefix; - } - - /** - * Merge index definitions for one type of index - * - * @param array $definitions the index definitions to merge to - * @param boolean $isCreateTable true if requirement is to get the statement - * for table creation - * @param array $indexedColumns the columns for one type of index - * @param string $indexKeyword the index keyword to use in the definition - * - * @return array - */ - private function mergeIndexStatements( - array $definitions, - bool $isCreateTable, - array $indexedColumns, - string $indexKeyword - ): array { - foreach ($indexedColumns as $index) { - $statements = $this->buildIndexStatements( - $index, - " " . $indexKeyword . " ", - $isCreateTable - ); - $definitions = array_merge($definitions, $statements); - } - return $definitions; - } - - /** - * Returns sql statement according to the column and index specifications as - * requested - * - * @param boolean $isCreateTable true if requirement is to get the statement - * for table creation - * - * @return string sql statement - */ - private function getColumnCreationStatements(bool $isCreateTable = true): string - { - $sqlStatement = ""; - list( - $fieldCount, - $fieldPrimary, - $fieldIndex, - $fieldUnique, - $fieldFullText, - $fieldSpatial - ) = $this->getIndexedColumns(); - $definitions = $this->buildColumnCreationStatement( - $fieldCount, - $isCreateTable - ); - - // Builds the PRIMARY KEY statements - $primaryKeyStatements = $this->buildIndexStatements( - isset($fieldPrimary[0]) ? $fieldPrimary[0] : [], - " PRIMARY KEY ", - $isCreateTable - ); - $definitions = array_merge($definitions, $primaryKeyStatements); - - // Builds the INDEX statements - $definitions = $this->mergeIndexStatements( - $definitions, - $isCreateTable, - $fieldIndex, - "INDEX" - ); - - // Builds the UNIQUE statements - $definitions = $this->mergeIndexStatements( - $definitions, - $isCreateTable, - $fieldUnique, - "UNIQUE" - ); - - // Builds the FULLTEXT statements - $definitions = $this->mergeIndexStatements( - $definitions, - $isCreateTable, - $fieldFullText, - "FULLTEXT" - ); - - // Builds the SPATIAL statements - $definitions = $this->mergeIndexStatements( - $definitions, - $isCreateTable, - $fieldSpatial, - "SPATIAL" - ); - - if (count($definitions)) { - $sqlStatement = implode(', ', $definitions); - } - return preg_replace('@, $@', '', $sqlStatement); - } - - /** - * Returns the partitioning clause - * - * @return string partitioning clause - */ - public function getPartitionsDefinition(): string - { - $sqlQuery = ""; - if (! empty($_POST['partition_by']) - && ! empty($_POST['partition_expr']) - && ! empty($_POST['partition_count']) - && $_POST['partition_count'] > 1 - ) { - $sqlQuery .= " PARTITION BY " . $_POST['partition_by'] - . " (" . $_POST['partition_expr'] . ")" - . " PARTITIONS " . $_POST['partition_count']; - } - - if (! empty($_POST['subpartition_by']) - && ! empty($_POST['subpartition_expr']) - && ! empty($_POST['subpartition_count']) - && $_POST['subpartition_count'] > 1 - ) { - $sqlQuery .= " SUBPARTITION BY " . $_POST['subpartition_by'] - . " (" . $_POST['subpartition_expr'] . ")" - . " SUBPARTITIONS " . $_POST['subpartition_count']; - } - - if (! empty($_POST['partitions'])) { - $partitions = []; - foreach ($_POST['partitions'] as $partition) { - $partitions[] = $this->getPartitionDefinition($partition); - } - $sqlQuery .= " (" . implode(", ", $partitions) . ")"; - } - - return $sqlQuery; - } - - /** - * Returns the definition of a partition/subpartition - * - * @param array $partition array of partition/subpartition detiails - * @param boolean $isSubPartition whether a subpartition - * - * @return string partition/subpartition definition - */ - private function getPartitionDefinition( - array $partition, - bool $isSubPartition = false - ): string { - $sqlQuery = " " . ($isSubPartition ? "SUB" : "") . "PARTITION "; - $sqlQuery .= $partition['name']; - - if (! empty($partition['value_type'])) { - $sqlQuery .= " VALUES " . $partition['value_type']; - - if ($partition['value_type'] != 'LESS THAN MAXVALUE') { - $sqlQuery .= " (" . $partition['value'] . ")"; - } - } - - if (! empty($partition['engine'])) { - $sqlQuery .= " ENGINE = " . $partition['engine']; - } - if (! empty($partition['comment'])) { - $sqlQuery .= " COMMENT = '" . $partition['comment'] . "'"; - } - if (! empty($partition['data_directory'])) { - $sqlQuery .= " DATA DIRECTORY = '" . $partition['data_directory'] . "'"; - } - if (! empty($partition['index_directory'])) { - $sqlQuery .= " INDEX_DIRECTORY = '" . $partition['index_directory'] . "'"; - } - if (! empty($partition['max_rows'])) { - $sqlQuery .= " MAX_ROWS = " . $partition['max_rows']; - } - if (! empty($partition['min_rows'])) { - $sqlQuery .= " MIN_ROWS = " . $partition['min_rows']; - } - if (! empty($partition['tablespace'])) { - $sqlQuery .= " TABLESPACE = " . $partition['tablespace']; - } - if (! empty($partition['node_group'])) { - $sqlQuery .= " NODEGROUP = " . $partition['node_group']; - } - - if (! empty($partition['subpartitions'])) { - $subpartitions = []; - foreach ($partition['subpartitions'] as $subpartition) { - $subpartitions[] = $this->getPartitionDefinition( - $subpartition, - true - ); - } - $sqlQuery .= " (" . implode(", ", $subpartitions) . ")"; - } - - return $sqlQuery; - } - - /** - * Function to get table creation sql query - * - * @param string $db database name - * @param string $table table name - * - * @return string - */ - public function getTableCreationQuery(string $db, string $table): string - { - // get column addition statements - $sqlStatement = $this->getColumnCreationStatements(true); - - // Builds the 'create table' statement - $sqlQuery = 'CREATE TABLE ' . Util::backquote($db) . '.' - . Util::backquote(trim($table)) . ' (' . $sqlStatement . ')'; - - // Adds table type, character set, comments and partition definition - if (! empty($_POST['tbl_storage_engine']) - && ($_POST['tbl_storage_engine'] != 'Default') - ) { - $sqlQuery .= ' ENGINE = ' . $_POST['tbl_storage_engine']; - } - if (! empty($_POST['tbl_collation'])) { - $sqlQuery .= Util::getCharsetQueryPart($_POST['tbl_collation']); - } - if (! empty($_POST['connection']) - && ! empty($_POST['tbl_storage_engine']) - && $_POST['tbl_storage_engine'] == 'FEDERATED' - ) { - $sqlQuery .= " CONNECTION = '" - . $this->dbi->escapeString($_POST['connection']) . "'"; - } - if (! empty($_POST['comment'])) { - $sqlQuery .= ' COMMENT = \'' - . $this->dbi->escapeString($_POST['comment']) . '\''; - } - $sqlQuery .= $this->getPartitionsDefinition(); - $sqlQuery .= ';'; - - return $sqlQuery; - } - - /** - * Function to get the number of fields for the table creation form - * - * @return int - */ - public function getNumberOfFieldsFromRequest(): int - { - // Limit to 4096 fields (MySQL maximal value) - $mysqlLimit = 4096; - - if (isset($_POST['submit_num_fields'])) { // adding new fields - $numberOfFields = intval($_POST['orig_num_fields']) + intval($_POST['added_fields']); - } elseif (isset($_POST['orig_num_fields'])) { // retaining existing fields - $numberOfFields = intval($_POST['orig_num_fields']); - } elseif (isset($_POST['num_fields']) - && intval($_POST['num_fields']) > 0 - ) { // new table with specified number of fields - $numberOfFields = intval($_POST['num_fields']); - } else { // new table with unspecified number of fields - $numberOfFields = 4; - } - - return min($numberOfFields, $mysqlLimit); - } - - /** - * Function to execute the column creation statement - * - * @param string $db current database - * @param string $table current table - * @param string $errorUrl error page url - * - * @return array - */ - public function tryColumnCreationQuery( - string $db, - string $table, - string $errorUrl - ): array { - // get column addition statements - $sqlStatement = $this->getColumnCreationStatements(false); - - // To allow replication, we first select the db to use and then run queries - // on this db. - if (! $this->dbi->selectDb($db)) { - Util::mysqlDie( - $this->dbi->getError(), - 'USE ' . Util::backquote($db), - false, - $errorUrl - ); - } - $sqlQuery = 'ALTER TABLE ' . - Util::backquote($table) . ' ' . $sqlStatement . ';'; - // If there is a request for SQL previewing. - if (isset($_POST['preview_sql'])) { - Core::previewSQL($sqlQuery); - } - return [ - $this->dbi->tryQuery($sqlQuery), - $sqlQuery, - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Database/DatabaseList.php b/srcs/phpmyadmin/libraries/classes/Database/DatabaseList.php deleted file mode 100644 index a9d3889..0000000 --- a/srcs/phpmyadmin/libraries/classes/Database/DatabaseList.php +++ /dev/null @@ -1,60 +0,0 @@ -getDatabaseList(); - } - - return null; - } - - /** - * Accessor to PMA::$databases - * - * @return ListDatabase - */ - public function getDatabaseList() - { - if (null === $this->databases) { - $this->databases = new ListDatabase(); - } - - return $this->databases; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Database/Designer.php b/srcs/phpmyadmin/libraries/classes/Database/Designer.php deleted file mode 100644 index f9d6775..0000000 --- a/srcs/phpmyadmin/libraries/classes/Database/Designer.php +++ /dev/null @@ -1,407 +0,0 @@ -dbi = $dbi; - $this->relation = $relation; - $this->template = $template; - } - - /** - * Function to get html for displaying the page edit/delete form - * - * @param string $db database name - * @param string $operation 'edit' or 'delete' depending on the operation - * - * @return string html content - */ - public function getHtmlForEditOrDeletePages($db, $operation) - { - $cfgRelation = $this->relation->getRelationsParam(); - return $this->template->render('database/designer/edit_delete_pages', [ - 'db' => $db, - 'operation' => $operation, - 'pdfwork' => $cfgRelation['pdfwork'], - 'pages' => $this->getPageIdsAndNames($db), - ]); - } - - /** - * Function to get html for displaying the page save as form - * - * @param string $db database name - * - * @return string html content - */ - public function getHtmlForPageSaveAs($db) - { - $cfgRelation = $this->relation->getRelationsParam(); - return $this->template->render('database/designer/page_save_as', [ - 'db' => $db, - 'pdfwork' => $cfgRelation['pdfwork'], - 'pages' => $this->getPageIdsAndNames($db), - ]); - } - - /** - * Retrieve IDs and names of schema pages - * - * @param string $db database name - * - * @return array array of schema page id and names - */ - private function getPageIdsAndNames($db) - { - $result = []; - $cfgRelation = $this->relation->getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return $result; - } - - $page_query = "SELECT `page_nr`, `page_descr` FROM " - . Util::backquote($cfgRelation['db']) . "." - . Util::backquote($cfgRelation['pdf_pages']) - . " WHERE db_name = '" . $this->dbi->escapeString($db) . "'" - . " ORDER BY `page_descr`"; - $page_rs = $this->relation->queryAsControlUser( - $page_query, - false, - DatabaseInterface::QUERY_STORE - ); - - while ($curr_page = $this->dbi->fetchAssoc($page_rs)) { - $result[intval($curr_page['page_nr'])] = $curr_page['page_descr']; - } - return $result; - } - - /** - * Function to get html for displaying the schema export - * - * @param string $db database name - * @param int $page the page to be exported - * - * @return string - */ - public function getHtmlForSchemaExport($db, $page) - { - /* Scan for schema plugins */ - /** @var SchemaPlugin[] $export_list */ - $export_list = Plugins::getPlugins( - "schema", - 'libraries/classes/Plugins/Schema/', - null - ); - - /* Fail if we didn't find any schema plugin */ - if (empty($export_list)) { - return Message::error( - __('Could not load schema plugins, please check your installation!') - )->getDisplay(); - } - - return $this->template->render('database/designer/schema_export', [ - 'db' => $db, - 'page' => $page, - 'export_list' => $export_list, - ]); - } - - /** - * Returns array of stored values of Designer Settings - * - * @return array stored values - */ - private function getSideMenuParamsArray() - { - $params = []; - - $cfgRelation = $this->relation->getRelationsParam(); - - if ($cfgRelation['designersettingswork']) { - $query = 'SELECT `settings_data` FROM ' - . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['designer_settings']) - . ' WHERE ' . Util::backquote('username') . ' = "' - . $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['user']) - . '";'; - - $result = $this->dbi->fetchSingleRow($query); - - $params = json_decode((string) $result['settings_data'], true); - } - - return $params; - } - - /** - * Returns class names for various buttons on Designer Side Menu - * - * @return array class names of various buttons - */ - public function returnClassNamesFromMenuButtons() - { - $classes_array = []; - $params_array = $this->getSideMenuParamsArray(); - - if (isset($params_array['angular_direct']) - && $params_array['angular_direct'] == 'angular' - ) { - $classes_array['angular_direct'] = 'M_butt_Selected_down'; - } else { - $classes_array['angular_direct'] = 'M_butt'; - } - - if (isset($params_array['snap_to_grid']) - && $params_array['snap_to_grid'] == 'on' - ) { - $classes_array['snap_to_grid'] = 'M_butt_Selected_down'; - } else { - $classes_array['snap_to_grid'] = 'M_butt'; - } - - if (isset($params_array['pin_text']) - && $params_array['pin_text'] == 'true' - ) { - $classes_array['pin_text'] = 'M_butt_Selected_down'; - } else { - $classes_array['pin_text'] = 'M_butt'; - } - - if (isset($params_array['relation_lines']) - && $params_array['relation_lines'] == 'false' - ) { - $classes_array['relation_lines'] = 'M_butt_Selected_down'; - } else { - $classes_array['relation_lines'] = 'M_butt'; - } - - if (isset($params_array['small_big_all']) - && $params_array['small_big_all'] == 'v' - ) { - $classes_array['small_big_all'] = 'M_butt_Selected_down'; - } else { - $classes_array['small_big_all'] = 'M_butt'; - } - - if (isset($params_array['side_menu']) - && $params_array['side_menu'] == 'true' - ) { - $classes_array['side_menu'] = 'M_butt_Selected_down'; - } else { - $classes_array['side_menu'] = 'M_butt'; - } - - return $classes_array; - } - - /** - * Get HTML to display tables on designer page - * - * @param string $db The database name from the request - * @param DesignerTable[] $designerTables The designer tables - * @param array $tab_pos tables positions - * @param int $display_page page number of the selected page - * @param array $tab_column table column info - * @param array $tables_all_keys all indices - * @param array $tables_pk_or_unique_keys unique or primary indices - * - * @return string html - */ - public function getDatabaseTables( - string $db, - array $designerTables, - array $tab_pos, - $display_page, - array $tab_column, - array $tables_all_keys, - array $tables_pk_or_unique_keys - ) { - $columns_type = []; - foreach ($designerTables as $designerTable) { - $table_name = $designerTable->getDbTableString(); - $limit = count($tab_column[$table_name]['COLUMN_ID']); - for ($j = 0; $j < $limit; $j++) { - $table_column_name = $table_name . '.' . $tab_column[$table_name]['COLUMN_NAME'][$j]; - if (isset($tables_pk_or_unique_keys[$table_column_name])) { - $columns_type[$table_column_name] = 'designer/FieldKey_small'; - } else { - $columns_type[$table_column_name] = 'designer/Field_small'; - if (false !== strpos($tab_column[$table_name]['TYPE'][$j], 'char') - || false !== strpos($tab_column[$table_name]['TYPE'][$j], 'text')) { - $columns_type[$table_column_name] .= '_char'; - } elseif (false !== strpos($tab_column[$table_name]['TYPE'][$j], 'int') - || false !== strpos($tab_column[$table_name]['TYPE'][$j], 'float') - || false !== strpos($tab_column[$table_name]['TYPE'][$j], 'double') - || false !== strpos($tab_column[$table_name]['TYPE'][$j], 'decimal')) { - $columns_type[$table_column_name] .= '_int'; - } elseif (false !== strpos($tab_column[$table_name]['TYPE'][$j], 'date') - || false !== strpos($tab_column[$table_name]['TYPE'][$j], 'time') - || false !== strpos($tab_column[$table_name]['TYPE'][$j], 'year')) { - $columns_type[$table_column_name] .= '_date'; - } - } - } - } - return $this->template->render('database/designer/database_tables', [ - 'db' => $GLOBALS['db'], - 'get_db' => $db, - 'has_query' => isset($_REQUEST['query']), - 'tab_pos' => $tab_pos, - 'display_page' => $display_page, - 'tab_column' => $tab_column, - 'tables_all_keys' => $tables_all_keys, - 'tables_pk_or_unique_keys' => $tables_pk_or_unique_keys, - 'tables' => $designerTables, - 'columns_type' => $columns_type, - 'theme' => $GLOBALS['PMA_Theme'], - ]); - } - - - /** - * Returns HTML for Designer page - * - * @param string $db database in use - * @param string $getDb database in url - * @param DesignerTable[] $designerTables The designer tables - * @param array $scriptTables array on foreign key support for each table - * @param array $scriptContr initialization data array - * @param DesignerTable[] $scriptDisplayField displayed tables in designer with their display fields - * @param int $displayPage page number of the selected page - * @param boolean $hasQuery whether this is visual query builder - * @param string $selectedPage name of the selected page - * @param array $paramsArray array with class name for various buttons on side menu - * @param array|null $tabPos table positions - * @param array $tabColumn table column info - * @param array $tablesAllKeys all indices - * @param array $tablesPkOrUniqueKeys unique or primary indices - * - * @return string html - */ - public function getHtmlForMain( - string $db, - string $getDb, - array $designerTables, - array $scriptTables, - array $scriptContr, - array $scriptDisplayField, - $displayPage, - $hasQuery, - $selectedPage, - array $paramsArray, - ?array $tabPos, - array $tabColumn, - array $tablesAllKeys, - array $tablesPkOrUniqueKeys - ): string { - $cfgRelation = $this->relation->getRelationsParam(); - $columnsType = []; - foreach ($designerTables as $designerTable) { - $tableName = $designerTable->getDbTableString(); - $limit = count($tabColumn[$tableName]['COLUMN_ID']); - for ($j = 0; $j < $limit; $j++) { - $tableColumnName = $tableName . '.' . $tabColumn[$tableName]['COLUMN_NAME'][$j]; - if (isset($tablesPkOrUniqueKeys[$tableColumnName])) { - $columnsType[$tableColumnName] = 'designer/FieldKey_small'; - } else { - $columnsType[$tableColumnName] = 'designer/Field_small'; - if (false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'char') - || false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'text')) { - $columnsType[$tableColumnName] .= '_char'; - } elseif (false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'int') - || false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'float') - || false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'double') - || false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'decimal')) { - $columnsType[$tableColumnName] .= '_int'; - } elseif (false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'date') - || false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'time') - || false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'year')) { - $columnsType[$tableColumnName] .= '_date'; - } - } - } - } - - $displayedFields = []; - foreach ($scriptDisplayField as $designerTable) { - if ($designerTable->getDisplayField() !== null) { - $displayedFields[$designerTable->getTableName()] = $designerTable->getDisplayField(); - } - } - - $designerConfig = new stdClass(); - $designerConfig->db = $db; - $designerConfig->scriptTables = $scriptTables; - $designerConfig->scriptContr = $scriptContr; - $designerConfig->server = $GLOBALS['server']; - $designerConfig->scriptDisplayField = $displayedFields; - $designerConfig->displayPage = (int) $displayPage; - $designerConfig->tablesEnabled = $cfgRelation['pdfwork']; - - return $this->template->render('database/designer/main', [ - 'db' => $db, - 'get_db' => $getDb, - 'designer_config' => json_encode($designerConfig), - 'display_page' => (int) $displayPage, - 'has_query' => $hasQuery, - 'selected_page' => $selectedPage, - 'params_array' => $paramsArray, - 'theme' => $GLOBALS['PMA_Theme'], - 'tab_pos' => $tabPos, - 'tab_column' => $tabColumn, - 'tables_all_keys' => $tablesAllKeys, - 'tables_pk_or_unique_keys' => $tablesPkOrUniqueKeys, - 'designerTables' => $designerTables, - 'columns_type' => $columnsType, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Database/Designer/Common.php b/srcs/phpmyadmin/libraries/classes/Database/Designer/Common.php deleted file mode 100644 index b80f323..0000000 --- a/srcs/phpmyadmin/libraries/classes/Database/Designer/Common.php +++ /dev/null @@ -1,830 +0,0 @@ -dbi = $dbi; - $this->relation = $relation; - } - - /** - * Retrieves table info and returns it - * - * @param string $db (optional) Filter only a DB ($table is required if you use $db) - * @param string $table (optional) Filter only a table ($db is now required) - * @return DesignerTable[] with table info - */ - public function getTablesInfo(string $db = null, string $table = null): array - { - $designerTables = []; - $db = ($db === null) ? $GLOBALS['db'] : $db; - // seems to be needed later - $this->dbi->selectDb($db); - if ($db === null && $table === null) { - $tables = $this->dbi->getTablesFull($db); - } else { - $tables = $this->dbi->getTablesFull($db, $table); - } - - foreach ($tables as $one_table) { - $DF = $this->relation->getDisplayField($db, $one_table['TABLE_NAME']); - $DF = is_string($DF) ? $DF : ''; - $DF = ($DF !== '') ? $DF : null; - $designerTables[] = new DesignerTable( - $db, - $one_table['TABLE_NAME'], - is_string($one_table['ENGINE']) ? $one_table['ENGINE'] : '', - $DF - ); - } - - return $designerTables; - } - - /** - * Retrieves table column info - * - * @param DesignerTable[] $designerTables The designer tables - * @return array table column nfo - */ - public function getColumnsInfo(array $designerTables): array - { - //$this->dbi->selectDb($GLOBALS['db']); - $tabColumn = []; - - foreach ($designerTables as $designerTable) { - $fieldsRs = $this->dbi->query( - $this->dbi->getColumnsSql( - $designerTable->getDatabaseName(), - $designerTable->getTableName(), - null, - true - ), - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - $j = 0; - while ($row = $this->dbi->fetchAssoc($fieldsRs)) { - if (! isset($tabColumn[$designerTable->getDbTableString()])) { - $tabColumn[$designerTable->getDbTableString()] = []; - } - $tabColumn[$designerTable->getDbTableString()]['COLUMN_ID'][$j] = $j; - $tabColumn[$designerTable->getDbTableString()]['COLUMN_NAME'][$j] = $row['Field']; - $tabColumn[$designerTable->getDbTableString()]['TYPE'][$j] = $row['Type']; - $tabColumn[$designerTable->getDbTableString()]['NULLABLE'][$j] = $row['Null']; - $j++; - } - } - - return $tabColumn; - } - - /** - * Returns JavaScript code for initializing vars - * - * @param DesignerTable[] $designerTables The designer tables - * @return array JavaScript code - */ - public function getScriptContr(array $designerTables): array - { - $this->dbi->selectDb($GLOBALS['db']); - $con = []; - $con["C_NAME"] = []; - $i = 0; - $alltab_rs = $this->dbi->query( - 'SHOW TABLES FROM ' . Util::backquote($GLOBALS['db']), - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - while ($val = @$this->dbi->fetchRow($alltab_rs)) { - $row = $this->relation->getForeigners($GLOBALS['db'], $val[0], '', 'internal'); - - if ($row !== false) { - foreach ($row as $field => $value) { - $con['C_NAME'][$i] = ''; - $con['DTN'][$i] = rawurlencode($GLOBALS['db'] . "." . $val[0]); - $con['DCN'][$i] = rawurlencode($field); - $con['STN'][$i] = rawurlencode( - $value['foreign_db'] . "." . $value['foreign_table'] - ); - $con['SCN'][$i] = rawurlencode($value['foreign_field']); - $i++; - } - } - $row = $this->relation->getForeigners($GLOBALS['db'], $val[0], '', 'foreign'); - - // We do not have access to the foreign keys if he user has partial access to the columns - if ($row !== false && isset($row['foreign_keys_data'])) { - foreach ($row['foreign_keys_data'] as $one_key) { - foreach ($one_key['index_list'] as $index => $one_field) { - $con['C_NAME'][$i] = rawurlencode($one_key['constraint']); - $con['DTN'][$i] = rawurlencode($GLOBALS['db'] . "." . $val[0]); - $con['DCN'][$i] = rawurlencode($one_field); - $con['STN'][$i] = rawurlencode( - (isset($one_key['ref_db_name']) ? - $one_key['ref_db_name'] : $GLOBALS['db']) - . "." . $one_key['ref_table_name'] - ); - $con['SCN'][$i] = rawurlencode($one_key['ref_index_list'][$index]); - $i++; - } - } - } - } - - $tableDbNames = []; - foreach ($designerTables as $designerTable) { - $tableDbNames[] = $designerTable->getDbTableString(); - } - - $ti = 0; - $retval = []; - 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] = []; - $retval[$ti][$c_name_i] = []; - if (in_array($dtn_i, $tableDbNames) && in_array($con['STN'][$i], $tableDbNames)) { - $retval[$ti][$c_name_i][$dtn_i] = []; - $retval[$ti][$c_name_i][$dtn_i][$con['DCN'][$i]] = [ - 0 => $con['STN'][$i], - 1 => $con['SCN'][$i], - ]; - } - $ti++; - } - return $retval; - } - - /** - * Returns UNIQUE and PRIMARY indices - * - * @param DesignerTable[] $designerTables The designer tables - * @return array unique or primary indices - */ - public function getPkOrUniqueKeys(array $designerTables): array - { - return $this->getAllKeys($designerTables, true); - } - - /** - * Returns all indices - * - * @param DesignerTable[] $designerTables The designer tables - * @param bool $unique_only whether to include only unique ones - * - * @return array indices - */ - public function getAllKeys(array $designerTables, bool $unique_only = false): array - { - $keys = []; - - foreach ($designerTables as $designerTable) { - $schema = $designerTable->getDatabaseName(); - // for now, take into account only the first index segment - foreach (Index::getFromTable($designerTable->getTableName(), $schema) as $index) { - if ($unique_only && ! $index->isUnique()) { - continue; - } - $columns = $index->getColumns(); - foreach ($columns as $column_name => $dummy) { - $keys[$schema . '.' . $designerTable->getTableName() . '.' . $column_name] = 1; - } - } - } - return $keys; - } - - /** - * Return j_tab and h_tab arrays - * - * @param DesignerTable[] $designerTables The designer tables - * @return array - */ - public function getScriptTabs(array $designerTables): array - { - $retval = [ - 'j_tabs' => [], - 'h_tabs' => [], - ]; - - foreach ($designerTables as $designerTable) { - $key = rawurlencode($designerTable->getDbTableString()); - $retval['j_tabs'][$key] = $designerTable->supportsForeignkeys() ? 1 : 0; - $retval['h_tabs'][$key] = 1; - } - - return $retval; - } - - /** - * Returns table positions of a given pdf page - * - * @param int $pg pdf page id - * - * @return array|null of table positions - */ - public function getTablePositions($pg): ?array - { - $cfgRelation = $this->relation->getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return []; - } - - $query = " - SELECT CONCAT_WS('.', `db_name`, `table_name`) AS `name`, - `db_name` as `dbName`, `table_name` as `tableName`, - `x` AS `X`, - `y` AS `Y`, - 1 AS `V`, - 1 AS `H` - FROM " . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['table_coords']) . " - WHERE pdf_page_number = " . intval($pg); - - return $this->dbi->fetchResult( - $query, - 'name', - null, - DatabaseInterface::CONNECT_CONTROL, - DatabaseInterface::QUERY_STORE - ); - } - - /** - * Returns page name of a given pdf page - * - * @param int $pg pdf page id - * - * @return string|null table name - */ - public function getPageName($pg) - { - $cfgRelation = $this->relation->getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return null; - } - - $query = "SELECT `page_descr`" - . " FROM " . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['pdf_pages']) - . " WHERE " . Util::backquote('page_nr') . " = " . intval($pg); - $page_name = $this->dbi->fetchResult( - $query, - null, - null, - DatabaseInterface::CONNECT_CONTROL, - DatabaseInterface::QUERY_STORE - ); - return ( is_array($page_name) && isset($page_name[0]) ) ? $page_name[0] : null; - } - - /** - * Deletes a given pdf page and its corresponding coordinates - * - * @param int $pg page id - * - * @return boolean success/failure - */ - public function deletePage($pg) - { - $cfgRelation = $this->relation->getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return false; - } - - $query = "DELETE FROM " . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['table_coords']) - . " WHERE " . Util::backquote('pdf_page_number') . " = " . intval($pg); - $success = $this->relation->queryAsControlUser( - $query, - true, - DatabaseInterface::QUERY_STORE - ); - - if ($success) { - $query = "DELETE FROM " . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['pdf_pages']) - . " WHERE " . Util::backquote('page_nr') . " = " . intval($pg); - $success = $this->relation->queryAsControlUser( - $query, - true, - DatabaseInterface::QUERY_STORE - ); - } - - return (bool) $success; - } - - /** - * Returns the id of the default pdf page of the database. - * Default page is the one which has the same name as the database. - * - * @param string $db database - * - * @return int|null id of the default pdf page for the database - */ - public function getDefaultPage($db): ?int - { - $cfgRelation = $this->relation->getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return -1; - } - - $query = "SELECT `page_nr`" - . " FROM " . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['pdf_pages']) - . " WHERE `db_name` = '" . $this->dbi->escapeString($db) . "'" - . " AND `page_descr` = '" . $this->dbi->escapeString($db) . "'"; - - $default_page_no = $this->dbi->fetchResult( - $query, - null, - null, - DatabaseInterface::CONNECT_CONTROL, - DatabaseInterface::QUERY_STORE - ); - - if (is_array($default_page_no) && isset($default_page_no[0])) { - return intval($default_page_no[0]); - } - return -1; - } - - /** - * Get the id of the page to load. If a default page exists it will be returned. - * If no such exists, returns the id of the first page of the database. - * - * @param string $db database - * - * @return int id of the page to load - */ - public function getLoadingPage($db) - { - $cfgRelation = $this->relation->getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return -1; - } - - $page_no = -1; - - $default_page_no = $this->getDefaultPage($db); - if ($default_page_no != -1) { - $page_no = $default_page_no; - } else { - $query = "SELECT MIN(`page_nr`)" - . " FROM " . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['pdf_pages']) - . " WHERE `db_name` = '" . $this->dbi->escapeString($db) . "'"; - - $min_page_no = $this->dbi->fetchResult( - $query, - null, - null, - DatabaseInterface::CONNECT_CONTROL, - DatabaseInterface::QUERY_STORE - ); - if (is_array($min_page_no) && isset($min_page_no[0])) { - $page_no = $min_page_no[0]; - } - } - return intval($page_no); - } - - /** - * Creates a new page and returns its auto-incrementing id - * - * @param string $pageName name of the page - * @param string $db name of the database - * - * @return int|null - */ - public function createNewPage($pageName, $db) - { - $cfgRelation = $this->relation->getRelationsParam(); - if ($cfgRelation['pdfwork']) { - return $this->relation->createPage( - $pageName, - $cfgRelation, - $db - ); - } - return null; - } - - /** - * Saves positions of table(s) of a given pdf page - * - * @param int $pg pdf page id - * - * @return boolean success/failure - */ - public function saveTablePositions($pg) - { - $pageId = $this->dbi->escapeString($pg); - - $db = $this->dbi->escapeString($_POST['db']); - - $cfgRelation = $this->relation->getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return false; - } - - $query = "DELETE FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote( - $cfgRelation['table_coords'] - ) - . " WHERE `pdf_page_number` = '" . $pageId . "'"; - - $res = $this->relation->queryAsControlUser( - $query, - true, - DatabaseInterface::QUERY_STORE - ); - - if (! $res) { - return (bool) $res; - } - - foreach ($_POST['t_h'] as $key => $value) { - $DB = $_POST['t_db'][$key]; - $TAB = $_POST['t_tbl'][$key]; - if (! $value) { - continue; - } - - $query = "INSERT INTO " - . Util::backquote($cfgRelation['db']) . "." - . Util::backquote($cfgRelation['table_coords']) - . " (`db_name`, `table_name`, `pdf_page_number`, `x`, `y`)" - . " VALUES (" - . "'" . $this->dbi->escapeString($DB) . "', " - . "'" . $this->dbi->escapeString($TAB) . "', " - . "'" . $pageId . "', " - . "'" . $this->dbi->escapeString($_POST['t_x'][$key]) . "', " - . "'" . $this->dbi->escapeString($_POST['t_y'][$key]) . "')"; - - $res = $this->relation->queryAsControlUser( - $query, - true, - DatabaseInterface::QUERY_STORE - ); - } - - return (bool) $res; - } - - /** - * Saves the display field for a table. - * - * @param string $db database name - * @param string $table table name - * @param string $field display field name - * - * @return array - */ - public function saveDisplayField($db, $table, $field) - { - $cfgRelation = $this->relation->getRelationsParam(); - if (! $cfgRelation['displaywork']) { - return [ - false, - _pgettext( - 'phpMyAdmin configuration storage is not configured for "Display Features" on designer when user tries to set a display field.', - 'phpMyAdmin configuration storage is not configured for "Display Features".' - ), - ]; - } - - $upd_query = new Table($table, $db, $this->dbi); - $upd_query->updateDisplayField($field, $cfgRelation); - - return [ - true, - null, - ]; - } - - /** - * Adds a new foreign relation - * - * @param string $db database name - * @param string $T1 foreign table - * @param string $F1 foreign field - * @param string $T2 master table - * @param string $F2 master field - * @param string $on_delete on delete action - * @param string $on_update on update action - * @param string $DB1 database - * @param string $DB2 database - * - * @return array array of success/failure and message - */ - public function addNewRelation($db, $T1, $F1, $T2, $F2, $on_delete, $on_update, $DB1, $DB2) - { - $tables = $this->dbi->getTablesFull($DB1, $T1); - $type_T1 = mb_strtoupper($tables[$T1]['ENGINE']); - $tables = $this->dbi->getTablesFull($DB2, $T2); - $type_T2 = mb_strtoupper($tables[$T2]['ENGINE']); - - // native foreign key - if (Util::isForeignKeySupported($type_T1) - && Util::isForeignKeySupported($type_T2) - && $type_T1 == $type_T2 - ) { - // relation exists? - $existrel_foreign = $this->relation->getForeigners($DB2, $T2, '', 'foreign'); - $foreigner = $this->relation->searchColumnInForeigners($existrel_foreign, $F2); - if ($foreigner - && isset($foreigner['constraint']) - ) { - return [ - false, - __('Error: relationship already exists.'), - ]; - } - // note: in InnoDB, the index does not requires to be on a PRIMARY - // or UNIQUE key - // improve: check all other requirements for InnoDB relations - $result = $this->dbi->query( - 'SHOW INDEX FROM ' . Util::backquote($DB1) - . '.' . Util::backquote($T1) . ';' - ); - - // will be use to emphasis prim. keys in the table view - $index_array1 = []; - while ($row = $this->dbi->fetchAssoc($result)) { - $index_array1[$row['Column_name']] = 1; - } - $this->dbi->freeResult($result); - - $result = $this->dbi->query( - 'SHOW INDEX FROM ' . Util::backquote($DB2) - . '.' . Util::backquote($T2) . ';' - ); - // will be used to emphasis prim. keys in the table view - $index_array2 = []; - while ($row = $this->dbi->fetchAssoc($result)) { - $index_array2[$row['Column_name']] = 1; - } - $this->dbi->freeResult($result); - - if (! empty($index_array1[$F1]) && ! empty($index_array2[$F2])) { - $upd_query = 'ALTER TABLE ' . Util::backquote($DB2) - . '.' . Util::backquote($T2) - . ' ADD FOREIGN KEY (' - . Util::backquote($F2) . ')' - . ' REFERENCES ' - . Util::backquote($DB1) . '.' - . Util::backquote($T1) . '(' - . Util::backquote($F1) . ')'; - - if ($on_delete != 'nix') { - $upd_query .= ' ON DELETE ' . $on_delete; - } - if ($on_update != 'nix') { - $upd_query .= ' ON UPDATE ' . $on_update; - } - $upd_query .= ';'; - if ($this->dbi->tryQuery($upd_query)) { - return [ - true, - __('FOREIGN KEY relationship has been added.'), - ]; - } - - $error = $this->dbi->getError(); - return [ - false, - __('Error: FOREIGN KEY relationship could not be added!') - . "
" . $error, - ]; - } - - return [ - false, - __('Error: Missing index on column(s).'), - ]; - } - - // internal (pmadb) relation - if ($GLOBALS['cfgRelation']['relwork'] == false) { - return [ - false, - __('Error: Relational features are disabled!'), - ]; - } - - // no need to recheck if the keys are primary or unique at this point, - // this was checked on the interface part - - $q = "INSERT INTO " - . Util::backquote($GLOBALS['cfgRelation']['db']) - . "." - . Util::backquote($GLOBALS['cfgRelation']['relation']) - . "(master_db, master_table, master_field, " - . "foreign_db, foreign_table, foreign_field)" - . " values(" - . "'" . $this->dbi->escapeString($DB2) . "', " - . "'" . $this->dbi->escapeString($T2) . "', " - . "'" . $this->dbi->escapeString($F2) . "', " - . "'" . $this->dbi->escapeString($DB1) . "', " - . "'" . $this->dbi->escapeString($T1) . "', " - . "'" . $this->dbi->escapeString($F1) . "')"; - - if ($this->relation->queryAsControlUser($q, false, DatabaseInterface::QUERY_STORE) - ) { - return [ - true, - __('Internal relationship has been added.'), - ]; - } - - $error = $this->dbi->getError(DatabaseInterface::CONNECT_CONTROL); - return [ - false, - __('Error: Internal relationship could not be added!') - . "
" . $error, - ]; - } - - /** - * Removes a foreign relation - * - * @param string $T1 foreign db.table - * @param string $F1 foreign field - * @param string $T2 master db.table - * @param string $F2 master field - * - * @return array array of success/failure and message - */ - public function removeRelation($T1, $F1, $T2, $F2) - { - list($DB1, $T1) = explode(".", $T1); - list($DB2, $T2) = explode(".", $T2); - - $tables = $this->dbi->getTablesFull($DB1, $T1); - $type_T1 = mb_strtoupper($tables[$T1]['ENGINE']); - $tables = $this->dbi->getTablesFull($DB2, $T2); - $type_T2 = mb_strtoupper($tables[$T2]['ENGINE']); - - if (Util::isForeignKeySupported($type_T1) - && Util::isForeignKeySupported($type_T2) - && $type_T1 == $type_T2 - ) { - // InnoDB - $existrel_foreign = $this->relation->getForeigners($DB2, $T2, '', 'foreign'); - $foreigner = $this->relation->searchColumnInForeigners($existrel_foreign, $F2); - - if (isset($foreigner['constraint'])) { - $upd_query = 'ALTER TABLE ' . Util::backquote($DB2) - . '.' . Util::backquote($T2) . ' DROP FOREIGN KEY ' - . Util::backquote($foreigner['constraint']) . ';'; - if ($this->dbi->query($upd_query)) { - return [ - true, - __('FOREIGN KEY relationship has been removed.'), - ]; - } - - $error = $this->dbi->getError(); - return [ - false, - __('Error: FOREIGN KEY relationship could not be removed!') - . "
" . $error, - ]; - } - } - - // internal relations - $delete_query = "DELETE FROM " - . Util::backquote($GLOBALS['cfgRelation']['db']) . "." - . $GLOBALS['cfgRelation']['relation'] . " WHERE " - . "master_db = '" . $this->dbi->escapeString($DB2) . "'" - . " AND master_table = '" . $this->dbi->escapeString($T2) . "'" - . " AND master_field = '" . $this->dbi->escapeString($F2) . "'" - . " AND foreign_db = '" . $this->dbi->escapeString($DB1) . "'" - . " AND foreign_table = '" . $this->dbi->escapeString($T1) . "'" - . " AND foreign_field = '" . $this->dbi->escapeString($F1) . "'"; - - $result = $this->relation->queryAsControlUser( - $delete_query, - false, - DatabaseInterface::QUERY_STORE - ); - - if (! $result) { - $error = $this->dbi->getError(DatabaseInterface::CONNECT_CONTROL); - return [ - false, - __('Error: Internal relationship could not be removed!') . "
" . $error, - ]; - } - - return [ - true, - __('Internal relationship has been removed.'), - ]; - } - - /** - * Save value for a designer setting - * - * @param string $index setting - * @param string $value value - * - * @return bool whether the operation succeeded - */ - public function saveSetting($index, $value) - { - $cfgRelation = $this->relation->getRelationsParam(); - $success = true; - if ($cfgRelation['designersettingswork']) { - $cfgDesigner = [ - 'user' => $GLOBALS['cfg']['Server']['user'], - 'db' => $cfgRelation['db'], - 'table' => $cfgRelation['designer_settings'], - ]; - - $orig_data_query = "SELECT settings_data" - . " FROM " . Util::backquote($cfgDesigner['db']) - . "." . Util::backquote($cfgDesigner['table']) - . " WHERE username = '" - . $this->dbi->escapeString($cfgDesigner['user']) . "';"; - - $orig_data = $this->dbi->fetchSingleRow( - $orig_data_query, - 'ASSOC', - DatabaseInterface::CONNECT_CONTROL - ); - - if (! empty($orig_data)) { - $orig_data = json_decode($orig_data['settings_data'], true); - $orig_data[$index] = $value; - $orig_data = json_encode($orig_data); - - $save_query = "UPDATE " - . Util::backquote($cfgDesigner['db']) - . "." . Util::backquote($cfgDesigner['table']) - . " SET settings_data = '" . $orig_data . "'" - . " WHERE username = '" - . $this->dbi->escapeString($cfgDesigner['user']) . "';"; - - $success = $this->relation->queryAsControlUser($save_query); - } else { - $save_data = [$index => $value]; - - $query = "INSERT INTO " - . Util::backquote($cfgDesigner['db']) - . "." . Util::backquote($cfgDesigner['table']) - . " (username, settings_data)" - . " VALUES('" . $this->dbi->escapeString($cfgDesigner['user']) - . "', '" . json_encode($save_data) . "');"; - - $success = $this->relation->queryAsControlUser($query); - } - } - - return (bool) $success; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Database/Designer/DesignerTable.php b/srcs/phpmyadmin/libraries/classes/Database/Designer/DesignerTable.php deleted file mode 100644 index a4c1c6f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Database/Designer/DesignerTable.php +++ /dev/null @@ -1,103 +0,0 @@ -databaseName = $databaseName; - $this->tableName = $tableName; - $this->tableEngine = $tableEngine; - $this->displayField = $displayField; - } - - /** - * The table engine supports or not foreign keys - * - * @return bool - */ - public function supportsForeignkeys(): bool - { - return Util::isForeignKeySupported($this->tableEngine); - } - - /** - * Get the database name - * - * @return string - */ - public function getDatabaseName(): string - { - return $this->databaseName; - } - - /** - * Get the table name - * - * @return string - */ - public function getTableName(): string - { - return $this->tableName; - } - - /** - * Get the table engine - * - * @return string - */ - public function getTableEngine(): string - { - return $this->tableEngine; - } - - /** - * Get the displayed field - * - * @return string - */ - public function getDisplayField() - { - return $this->displayField; - } - - /** - * Get the db and table separated with a dot - * - * @return string - */ - public function getDbTableString(): string - { - return $this->databaseName . '.' . $this->tableName; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Database/MultiTableQuery.php b/srcs/phpmyadmin/libraries/classes/Database/MultiTableQuery.php deleted file mode 100644 index b9fa888..0000000 --- a/srcs/phpmyadmin/libraries/classes/Database/MultiTableQuery.php +++ /dev/null @@ -1,145 +0,0 @@ -dbi = $dbi; - $this->db = $dbName; - $this->defaultNoOfColumns = $defaultNoOfColumns; - - $this->template = $template; - - $this->tables = $this->dbi->getTables($this->db); - } - - /** - * Get Multi-Table query page HTML - * - * @return string Multi-Table query page HTML - */ - public function getFormHtml() - { - $tables = []; - foreach ($this->tables as $table) { - $tables[$table]['hash'] = md5($table); - $tables[$table]['columns'] = array_keys( - $this->dbi->getColumns($this->db, $table) - ); - } - return $this->template->render('database/multi_table_query/form', [ - 'db' => $this->db, - 'tables' => $tables, - 'default_no_of_columns' => $this->defaultNoOfColumns, - ]); - } - - /** - * Displays multi-table query results - * - * @param string $sqlQuery The query to parse - * @param string $db The current database - * @param string $pmaThemeImage Uri of the PMA theme image - * - * @return void - */ - public static function displayResults($sqlQuery, $db, $pmaThemeImage) - { - list( - $analyzedSqlResults, - $db, - ) = ParseAnalyze::sqlQuery($sqlQuery, $db); - - extract($analyzedSqlResults); - $goto = 'db_multi_table_query.php'; - $sql = new Sql(); - $sql->executeQueryAndSendQueryResponse( - null, // analyzed_sql_results - false, // is_gotofile - $db, // db - null, // table - null, // find_real_end - null, // sql_query_for_bookmark - see below - null, // extra_data - null, // message_to_show - null, // message - null, // sql_data - $goto, // goto - $pmaThemeImage, // pmaThemeImage - null, // disp_query - null, // disp_message - null, // query_type - $sqlQuery, // sql_query - null, // selectedTables - null // complete_query - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Database/Qbe.php b/srcs/phpmyadmin/libraries/classes/Database/Qbe.php deleted file mode 100644 index 27116d0..0000000 --- a/srcs/phpmyadmin/libraries/classes/Database/Qbe.php +++ /dev/null @@ -1,1963 +0,0 @@ -_db = $dbname; - $this->_savedSearchList = $savedSearchList; - $this->_currentSearch = $currentSearch; - $this->dbi = $dbi; - $this->relation = $relation; - $this->template = $template; - - $this->_loadCriterias(); - // Sets criteria parameters - $this->_setSearchParams(); - $this->_setCriteriaTablesAndColumns(); - } - - /** - * Initialize criterias - * - * @return static - */ - private function _loadCriterias() - { - if (null === $this->_currentSearch - || null === $this->_currentSearch->getCriterias() - ) { - return $this; - } - - $criterias = $this->_currentSearch->getCriterias(); - $_POST = $criterias + $_POST; - - return $this; - } - - /** - * Getter for current search - * - * @return SavedSearches - */ - private function _getCurrentSearch() - { - return $this->_currentSearch; - } - - /** - * Sets search parameters - * - * @return void - */ - private function _setSearchParams() - { - $criteriaColumnCount = $this->_initializeCriteriasCount(); - - $this->_criteriaColumnInsert = Core::ifSetOr( - $_POST['criteriaColumnInsert'], - null, - 'array' - ); - $this->_criteriaColumnDelete = Core::ifSetOr( - $_POST['criteriaColumnDelete'], - null, - 'array' - ); - - $this->_prev_criteria = isset($_POST['prev_criteria']) - ? $_POST['prev_criteria'] - : []; - $this->_criteria = isset($_POST['criteria']) - ? $_POST['criteria'] - : array_fill(0, $criteriaColumnCount, ''); - - $this->_criteriaRowInsert = isset($_POST['criteriaRowInsert']) - ? $_POST['criteriaRowInsert'] - : array_fill(0, $criteriaColumnCount, ''); - $this->_criteriaRowDelete = isset($_POST['criteriaRowDelete']) - ? $_POST['criteriaRowDelete'] - : array_fill(0, $criteriaColumnCount, ''); - $this->_criteriaAndOrRow = isset($_POST['criteriaAndOrRow']) - ? $_POST['criteriaAndOrRow'] - : array_fill(0, $criteriaColumnCount, ''); - $this->_criteriaAndOrColumn = isset($_POST['criteriaAndOrColumn']) - ? $_POST['criteriaAndOrColumn'] - : array_fill(0, $criteriaColumnCount, ''); - // sets minimum width - $this->_form_column_width = 12; - $this->_formColumns = []; - $this->_formSorts = []; - $this->_formShows = []; - $this->_formCriterions = []; - $this->_formAndOrRows = []; - $this->_formAndOrCols = []; - } - - /** - * Sets criteria tables and columns - * - * @return void - */ - private function _setCriteriaTablesAndColumns() - { - // The tables list sent by a previously submitted form - if (Core::isValid($_POST['TableList'], 'array')) { - foreach ($_POST['TableList'] as $each_table) { - $this->_criteriaTables[$each_table] = ' selected="selected"'; - } - } // end if - $all_tables = $this->dbi->query( - 'SHOW TABLES FROM ' . Util::backquote($this->_db) . ';', - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - $all_tables_count = $this->dbi->numRows($all_tables); - if (0 == $all_tables_count) { - Message::error(__('No tables found in database.'))->display(); - exit; - } - // The tables list gets from MySQL - while (list($table) = $this->dbi->fetchRow($all_tables)) { - $columns = $this->dbi->getColumns($this->_db, $table); - - if (empty($this->_criteriaTables[$table]) - && ! empty($_POST['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 = Util::backquote($table); - $this->_columnNames[] = $each_table . '.*'; - foreach ($columns as $each_column) { - $each_column = $each_table . '.' - . Util::backquote($each_column['Field']); - $this->_columnNames[] = $each_column; - // increase the width if necessary - $this->_form_column_width = max( - mb_strlen($each_column), - $this->_form_column_width - ); - } // end foreach - } // end if - } // end while - $this->dbi->freeResult($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 string HTML for select options - */ - private function _showColumnSelectCell($column_number, $selected = '') - { - return $this->template->render('database/qbe/column_select_cell', [ - 'column_number' => $column_number, - 'column_names' => $this->_columnNames, - 'selected' => $selected, - ]); - } - - /** - * Provides select options list containing sort options (ASC/DESC) - * - * @param integer $columnNumber Column Number (0,1,2) or more - * @param string $selected Selected criteria 'ASC' or 'DESC' - * - * @return string HTML for select options - */ - private function _getSortSelectCell( - $columnNumber, - $selected = '' - ) { - return $this->template->render('database/qbe/sort_select_cell', [ - 'real_width' => $this->_realwidth, - 'column_number' => $columnNumber, - 'selected' => $selected, - ]); - } - - /** - * Provides select options list containing sort order - * - * @param integer $columnNumber Column Number (0,1,2) or more - * @param integer $sortOrder Sort order - * - * @return string HTML for select options - */ - private function _getSortOrderSelectCell($columnNumber, $sortOrder) - { - $totalColumnCount = $this->_getNewColumnCount(); - return $this->template->render('database/qbe/sort_order_select_cell', [ - 'total_column_count' => $totalColumnCount, - 'column_number' => $columnNumber, - 'sort_order' => $sortOrder, - ]); - } - - /** - * Returns the new column count after adding and removing columns as instructed - * - * @return int new column count - */ - private function _getNewColumnCount() - { - $totalColumnCount = $this->_criteria_column_count; - if (! empty($this->_criteriaColumnInsert)) { - $totalColumnCount += count($this->_criteriaColumnInsert); - } - if (! empty($this->_criteriaColumnDelete)) { - $totalColumnCount -= count($this->_criteriaColumnDelete); - } - return $totalColumnCount; - } - - /** - * Provides search form's row containing column select options - * - * @return string 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($_POST['criteriaColumn'][$column_index])) { - $selected = $_POST['criteriaColumn'][$column_index]; - $this->_formColumns[$new_column_count] - = $_POST['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 column aliases - * - * @return string HTML for search table's row - */ - private function _getColumnAliasRow() - { - $html_output = ''; - $html_output .= '' . __('Alias:') . ''; - $new_column_count = 0; - - for ($colInd = 0; $colInd < $this->_criteria_column_count; $colInd++) { - if (! empty($this->_criteriaColumnInsert) - && isset($this->_criteriaColumnInsert[$colInd]) - && $this->_criteriaColumnInsert[$colInd] == 'on' - ) { - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - $new_column_count++; - } // end if - - if (! empty($this->_criteriaColumnDelete) - && isset($this->_criteriaColumnDelete[$colInd]) - && $this->_criteriaColumnDelete[$colInd] == 'on' - ) { - continue; - } - - $tmp_alias = ''; - if (! empty($_POST['criteriaAlias'][$colInd])) { - $tmp_alias - = $this->_formAliases[$new_column_count] - = $_POST['criteriaAlias'][$colInd]; - }// end if - - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - $new_column_count++; - } // end for - $html_output .= ''; - return $html_output; - } - - /** - * Provides search form's row containing sort(ASC/DESC) select options - * - * @return string HTML for search table's row - */ - private function _getSortRow() - { - $html_output = ''; - $html_output .= '' . __('Sort:') . ''; - $new_column_count = 0; - - for ($colInd = 0; $colInd < $this->_criteria_column_count; $colInd++) { - if (! empty($this->_criteriaColumnInsert) - && isset($this->_criteriaColumnInsert[$colInd]) - && $this->_criteriaColumnInsert[$colInd] == 'on' - ) { - $html_output .= $this->_getSortSelectCell($new_column_count); - $new_column_count++; - } // end if - - if (! empty($this->_criteriaColumnDelete) - && isset($this->_criteriaColumnDelete[$colInd]) - && $this->_criteriaColumnDelete[$colInd] == 'on' - ) { - continue; - } - // If they have chosen all fields using the * selector, - // then sorting is not available, Fix for Bug #570698 - if (isset($_POST['criteriaSort'][$colInd]) - && isset($_POST['criteriaColumn'][$colInd]) - && mb_substr($_POST['criteriaColumn'][$colInd], -2) == '.*' - ) { - $_POST['criteriaSort'][$colInd] = ''; - } //end if - - $selected = ''; - if (isset($_POST['criteriaSort'][$colInd])) { - $this->_formSorts[$new_column_count] - = $_POST['criteriaSort'][$colInd]; - - if ($_POST['criteriaSort'][$colInd] == 'ASC') { - $selected = 'ASC'; - } elseif ($_POST['criteriaSort'][$colInd] == 'DESC') { - $selected = 'DESC'; - } - } else { - $this->_formSorts[$new_column_count] = ''; - } - - $html_output .= $this->_getSortSelectCell( - $new_column_count, - $selected - ); - $new_column_count++; - } // end for - $html_output .= ''; - return $html_output; - } - - /** - * Provides search form's row containing sort order - * - * @return string HTML for search table's row - */ - private function _getSortOrder() - { - $html_output = ''; - $html_output .= '' . __('Sort order:') . ''; - $new_column_count = 0; - - for ($colInd = 0; $colInd < $this->_criteria_column_count; $colInd++) { - if (! empty($this->_criteriaColumnInsert) - && isset($this->_criteriaColumnInsert[$colInd]) - && $this->_criteriaColumnInsert[$colInd] == 'on' - ) { - $html_output .= $this->_getSortOrderSelectCell( - $new_column_count, - null - ); - $new_column_count++; - } // end if - - if (! empty($this->_criteriaColumnDelete) - && isset($this->_criteriaColumnDelete[$colInd]) - && $this->_criteriaColumnDelete[$colInd] == 'on' - ) { - continue; - } - - $sortOrder = null; - if (! empty($_POST['criteriaSortOrder'][$colInd])) { - $sortOrder - = $this->_formSortOrders[$new_column_count] - = $_POST['criteriaSortOrder'][$colInd]; - } - - $html_output .= $this->_getSortOrderSelectCell( - $new_column_count, - $sortOrder - ); - $new_column_count++; - } // end for - $html_output .= ''; - return $html_output; - } - - /** - * Provides search form's row containing SHOW checkboxes - * - * @return string 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($_POST['criteriaShow'][$column_index])) { - $checked_options = ' checked="checked"'; - $this->_formShows[$new_column_count] - = $_POST['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 string 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; - } - $tmp_criteria = ''; - 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->_formCriterions[$new_column_count] = $tmp_criteria; - } else { - $this->_formCriterions[$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 string HTML for footer options - */ - private function _getFootersOptions($type) - { - return $this->template->render('database/qbe/footer_options', [ - 'type' => $type, - ]); - } - - /** - * Provides search form table's footer options - * - * @return string 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 string 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|null $selected Selected criteria column name - * @param bool $last_column Whether this is the last column - * - * @return string HTML for modification cell - */ - private function _getAndOrColCell( - $column_number, - $selected = null, - $last_column = false - ) { - $html_output = ''; - if (! $last_column) { - $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 string 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->_formAndOrCols[$new_column_count] - = $this->_criteriaAndOrColumn[$column_index]; - } - $checked_options = []; - 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, - $column_index + 1 == $this->_criteria_column_count - ); - $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 array $checked_options If checked - * - * @return string HTML - */ - private function _getInsDelAndOrCell($row_index, array $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 - * - * @return string HTML table rows - */ - private function _getInputboxRow($new_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' - ) { - $orFieldName = '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 string HTML table rows - */ - private function _getInsDelAndOrCriteriaRows() - { - $html_output = ''; - $new_row_count = 0; - $checked_options = []; - 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 - ); - $new_row_count++; - $html_output .= ''; - } // end if - if (isset($this->_criteriaRowDelete[$row_index]) - && $this->_criteriaRowDelete[$row_index] == 'on' - ) { - continue; - } - if (isset($this->_criteriaAndOrRow[$row_index])) { - $this->_formAndOrRows[$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 - ); - $new_row_count++; - $html_output .= ''; - } // end for - $this->_new_row_count = $new_row_count; - return $html_output; - } - - /** - * Provides SELECT clause for building SQL query - * - * @return string Select clause - */ - private function _getSelectClause() - { - $select_clause = ''; - $select_clauses = []; - for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) { - if (! empty($this->_formColumns[$column_index]) - && isset($this->_formShows[$column_index]) - && $this->_formShows[$column_index] == 'on' - ) { - $select = $this->_formColumns[$column_index]; - if (! empty($this->_formAliases[$column_index])) { - $select .= " AS " - . Util::backquote($this->_formAliases[$column_index]); - } - $select_clauses[] = $select; - } - } // end for - if (! empty($select_clauses)) { - $select_clause = 'SELECT ' - . htmlspecialchars(implode(", ", $select_clauses)) . "\n"; - } - return $select_clause; - } - - /** - * Provides WHERE clause for building SQL query - * - * @return string 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->_formColumns[$column_index]) - && ! empty($this->_formCriterions[$column_index]) - && $column_index - && isset($last_where) - && isset($this->_formAndOrCols) - ) { - $where_clause .= ' ' - . mb_strtoupper($this->_formAndOrCols[$last_where]) - . ' '; - } - if (! empty($this->_formColumns[$column_index]) - && ! empty($this->_formCriterions[$column_index]) - ) { - $where_clause .= '(' . $this->_formColumns[$column_index] . ' ' - . $this->_formCriterions[$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->_formAndOrRows)) { - $this->_formAndOrRows = []; - } - 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->_formColumns[$column_index]) - && ! empty($_POST['Or' . $row_index][$column_index]) - && $column_index - ) { - $qry_orwhere .= ' ' - . mb_strtoupper( - $this->_formAndOrCols[$last_orwhere] - ) - . ' '; - } - if (! empty($this->_formColumns[$column_index]) - && ! empty($_POST['Or' . $row_index][$column_index]) - ) { - $qry_orwhere .= '(' . $this->_formColumns[$column_index] - . ' ' - . $_POST['Or' . $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" - . mb_strtoupper( - isset($this->_formAndOrRows[$row_index]) - ? $this->_formAndOrRows[$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 string Order By clause - */ - private function _getOrderByClause() - { - $orderby_clause = ''; - $orderby_clauses = []; - - // Create copy of instance variables - $columns = $this->_formColumns; - $sort = $this->_formSorts; - $sortOrder = $this->_formSortOrders; - if (! empty($sortOrder) - && count($sortOrder) == count($sort) - && count($sortOrder) == count($columns) - ) { - // Sort all three arrays based on sort order - array_multisort($sortOrder, $sort, $columns); - } - - 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($columns[$column_index]) - && empty($sort[$column_index]) - ) { - continue; - } - - if (mb_substr($columns[$column_index], -2) == '.*') { - continue; - } - - if (! empty($sort[$column_index])) { - $orderby_clauses[] = $columns[$column_index] . ' ' - . $sort[$column_index]; - } - } // end for - if (! empty($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 $search_tables Tables involved in the search - * @param array $search_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( - array $search_tables, - array $search_columns, - array $where_clause_columns - ) { - $unique_columns = []; - $index_columns = []; - - foreach ($search_tables as $table) { - $indexes = $this->dbi->getTableIndexes($this->_db, $table); - foreach ($indexes as $index) { - $column = $table . '.' . $index['Column_name']; - if (isset($search_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 [ - 'unique' => $unique_columns, - 'index' => $index_columns, - ]; - } - - /** - * Provides UNIQUE columns and INDEX columns present in criteria tables - * - * @param array $search_tables Tables involved in the search - * @param array $search_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( - array $search_tables, - array $search_columns, - array $where_clause_columns - ) { - $this->dbi->selectDb($this->_db); - - // Get unique columns and index columns - $indexes = $this->_getIndexes( - $search_tables, - $search_columns, - $where_clause_columns - ); - $unique_columns = $indexes['unique']; - $index_columns = $indexes['index']; - - list($candidate_columns, $needsort) - = $this->_getLeftJoinColumnCandidatesBest( - $search_tables, - $where_clause_columns, - $unique_columns, - $index_columns - ); - - // 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) { - return $candidate_columns; - } - - $very_good = []; - $still_good = []; - foreach ($candidate_columns as $column => $is_where) { - $table = explode('.', $column); - $table = $table[0]; - if ($is_where == 'Y') { - $very_good[$column] = $table; - } else { - $still_good[$column] = $table; - } - } - if (count($very_good) > 0) { - $candidate_columns = $very_good; - // Candidates restricted in index+where - } else { - $candidate_columns = $still_good; - // None of the candidates where in a where-clause - } - - return $candidate_columns; - } - - /** - * Provides the main table to form the LEFT JOIN clause - * - * @param array $search_tables Tables involved in the search - * @param array $search_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( - array $search_tables, - array $search_columns, - array $where_clause_columns, - array $where_clause_tables - ) { - if (count($where_clause_tables) === 1) { - // If there is exactly one column that has a decent where-clause - // we will just use this - return key($where_clause_tables); - } - - // 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( - $search_tables, - $search_columns, - $where_clause_columns - ); - - // Generally, we need to display all the rows of foreign (referenced) - // table, whether they have any matching row in child table or not. - // So we select candidate tables which are foreign tables. - $foreign_tables = []; - foreach ($candidate_columns as $one_table) { - $foreigners = $this->relation->getForeigners($this->_db, $one_table); - foreach ($foreigners as $key => $foreigner) { - if ($key != 'foreign_keys_data') { - if (in_array($foreigner['foreign_table'], $candidate_columns)) { - $foreign_tables[$foreigner['foreign_table']] - = $foreigner['foreign_table']; - } - continue; - } - foreach ($foreigner as $one_key) { - if (in_array($one_key['ref_table_name'], $candidate_columns)) { - $foreign_tables[$one_key['ref_table_name']] - = $one_key['ref_table_name']; - } - } - } - } - if (count($foreign_tables)) { - $candidate_columns = $foreign_tables; - } - - // 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)) { - // Only one single candidate - return reset($candidate_columns); - } - - // Of course we only want to check each table once - $checked_tables = $candidate_columns; - $tsize = []; - $maxsize = -1; - $result = ''; - foreach ($candidate_columns as $table) { - if ($checked_tables[$table] != 1) { - $_table = new Table($table, $this->_db); - $tsize[$table] = $_table->countRecords(); - $checked_tables[$table] = 1; - } - if ($tsize[$table] > $maxsize) { - $maxsize = $tsize[$table]; - $result = $table; - } - } - // Return largest table - return $result; - } - - /** - * Provides columns and tables that have valid where clause criteria - * - * @return array - */ - private function _getWhereClauseTablesAndColumns() - { - $where_clause_columns = []; - $where_clause_tables = []; - - // Now we need all tables that we have in the where clause - for ($column_index = 0, $nb = count($this->_criteria); $column_index < $nb; $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 (mb_substr($this->_criteria[$column_index], 0, 1) == '=' - || false !== stripos($this->_criteria[$column_index], 'is') - ) { - $where_clause_columns[$column] = $column; - $where_clause_tables[$table] = $table; - } - } // end if - } // end for - return [ - 'where_clause_tables' => $where_clause_tables, - 'where_clause_columns' => $where_clause_columns, - ]; - } - - /** - * Provides FROM clause for building SQL query - * - * @param array $formColumns List of selected columns in the form - * - * @return string FROM clause - */ - private function _getFromClause(array $formColumns) - { - $from_clause = ''; - if (empty($formColumns)) { - return $from_clause; - } - - // Initialize some variables - $search_tables = $search_columns = []; - - // We only start this if we have fields, otherwise it would be dumb - foreach ($formColumns as $value) { - $parts = explode('.', $value); - if (! empty($parts[0]) && ! empty($parts[1])) { - $table = str_replace('`', '', $parts[0]); - $search_tables[$table] = $table; - $search_columns[] = $table . '.' . str_replace( - '`', - '', - $parts[1] - ); - } - } // end while - - // Create LEFT JOINS out of Relations - $from_clause = $this->_getJoinForFromClause( - $search_tables, - $search_columns - ); - - // 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)) { - // Create cartesian product - $from_clause = implode( - ', ', - array_map([Util::class, 'backquote'], $search_tables) - ); - } - - return $from_clause; - } - - /** - * Formulates the WHERE clause by JOINing tables - * - * @param array $searchTables Tables involved in the search - * @param array $searchColumns Columns involved in the search - * - * @return string table name - */ - private function _getJoinForFromClause(array $searchTables, array $searchColumns) - { - // $relations[master_table][foreign_table] => clause - $relations = []; - - // Fill $relations with inter table relationship data - foreach ($searchTables as $oneTable) { - $this->_loadRelationsForTable($relations, $oneTable); - } - - // Get tables and columns with valid where clauses - $validWhereClauses = $this->_getWhereClauseTablesAndColumns(); - $whereClauseTables = $validWhereClauses['where_clause_tables']; - $whereClauseColumns = $validWhereClauses['where_clause_columns']; - - // Get master table - $master = $this->_getMasterTable( - $searchTables, - $searchColumns, - $whereClauseColumns, - $whereClauseTables - ); - - // Will include master tables and all tables that can be combined into - // a cluster by their relation - $finalized = []; - if (strlen($master) > 0) { - // Add master tables - $finalized[$master] = ''; - } - // Fill the $finalized array with JOIN clauses for each table - $this->_fillJoinClauses($finalized, $relations, $searchTables); - - // JOIN clause - $join = ''; - - // Tables that can not be combined with the table cluster - // which includes master table - $unfinalized = array_diff($searchTables, array_keys($finalized)); - if (count($unfinalized) > 0) { - // We need to look for intermediary tables to JOIN unfinalized tables - // Heuristic to chose intermediary tables is to look for tables - // having relationships with unfinalized tables - foreach ($unfinalized as $oneTable) { - $references = $this->relation->getChildReferences($this->_db, $oneTable); - foreach ($references as $column => $columnReferences) { - foreach ($columnReferences as $reference) { - // Only from this schema - if ($reference['table_schema'] != $this->_db) { - continue; - } - - $table = $reference['table_name']; - - $this->_loadRelationsForTable($relations, $table); - - // Make copies - $tempFinalized = $finalized; - $tempSearchTables = $searchTables; - $tempSearchTables[] = $table; - - // Try joining with the added table - $this->_fillJoinClauses( - $tempFinalized, - $relations, - $tempSearchTables - ); - - $tempUnfinalized = array_diff( - $tempSearchTables, - array_keys($tempFinalized) - ); - // Take greedy approach. - // If the unfinalized count drops we keep the new table - // and switch temporary varibles with the original ones - if (count($tempUnfinalized) < count($unfinalized)) { - $finalized = $tempFinalized; - $searchTables = $tempSearchTables; - } - - // We are done if no unfinalized tables anymore - if (count($tempUnfinalized) === 0) { - break 3; - } - } - } - } - - $unfinalized = array_diff($searchTables, array_keys($finalized)); - // If there are still unfinalized tables - if (count($unfinalized) > 0) { - // Add these tables as cartesian product before joined tables - $join .= implode( - ', ', - array_map([Util::class, 'backquote'], $unfinalized) - ); - } - } - - $first = true; - // Add joined tables - foreach ($finalized as $table => $clause) { - if ($first) { - if (! empty($join)) { - $join .= ", "; - } - $join .= Util::backquote($table); - $first = false; - } else { - $join .= "\n LEFT JOIN " . Util::backquote( - $table - ) . " ON " . $clause; - } - } - - return $join; - } - - /** - * Loads relations for a given table into the $relations array - * - * @param array $relations array of relations - * @param string $oneTable the table - * - * @return void - */ - private function _loadRelationsForTable(array &$relations, $oneTable) - { - $relations[$oneTable] = []; - - $foreigners = $this->relation->getForeigners($GLOBALS['db'], $oneTable); - foreach ($foreigners as $field => $foreigner) { - // Foreign keys data - if ($field == 'foreign_keys_data') { - foreach ($foreigner as $oneKey) { - $clauses = []; - // There may be multiple column relations - foreach ($oneKey['index_list'] as $index => $oneField) { - $clauses[] - = Util::backquote($oneTable) . "." - . Util::backquote($oneField) . " = " - . Util::backquote($oneKey['ref_table_name']) . "." - . Util::backquote($oneKey['ref_index_list'][$index]); - } - // Combine multiple column relations with AND - $relations[$oneTable][$oneKey['ref_table_name']] - = implode(" AND ", $clauses); - } - } else { // Internal relations - $relations[$oneTable][$foreigner['foreign_table']] - = Util::backquote($oneTable) . "." - . Util::backquote($field) . " = " - . Util::backquote($foreigner['foreign_table']) . "." - . Util::backquote($foreigner['foreign_field']); - } - } - } - - /** - * Fills the $finalized arrays with JOIN clauses for each of the tables - * - * @param array $finalized JOIN clauses for each table - * @param array $relations Relations among tables - * @param array $searchTables Tables involved in the search - * - * @return void - */ - private function _fillJoinClauses(array &$finalized, array $relations, array $searchTables) - { - while (true) { - $added = false; - foreach ($searchTables as $masterTable) { - $foreignData = $relations[$masterTable]; - foreach ($foreignData as $foreignTable => $clause) { - if (! isset($finalized[$masterTable]) - && isset($finalized[$foreignTable]) - ) { - $finalized[$masterTable] = $clause; - $added = true; - } elseif (! isset($finalized[$foreignTable]) - && isset($finalized[$masterTable]) - && in_array($foreignTable, $searchTables) - ) { - $finalized[$foreignTable] = $clause; - $added = true; - } - if ($added) { - // We are done if all tables are in $finalized - if (count($finalized) == count($searchTables)) { - return; - } - } - } - } - // If no new tables were added during this iteration, break; - if (! $added) { - return; - } - } - } - - /** - * Provides the generated SQL query - * - * @param array $formColumns List of selected columns in the form - * - * @return string SQL query - */ - private function _getSQLQuery(array $formColumns) - { - $sql_query = ''; - // get SELECT clause - $sql_query .= $this->_getSelectClause(); - // get FROM clause - $from_clause = $this->_getFromClause($formColumns); - 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 - * - * @return string QBE form - */ - public function getSelectionForm() - { - $html_output = ''; - $html_output .= '
'; - $html_output .= '
'; - - if ($GLOBALS['cfgRelation']['savedsearcheswork']) { - $html_output .= $this->_getSavedSearchesField(); - } - - $html_output .= '
'; - $html_output .= ''; - // Get table's elements - $html_output .= $this->_getColumnNamesRow(); - $html_output .= $this->_getColumnAliasRow(); - $html_output .= $this->_getShowRow(); - $html_output .= $this->_getSortRow(); - $html_output .= $this->_getSortOrder(); - $html_output .= $this->_getCriteriaInputboxRow(); - $html_output .= $this->_getInsDelAndOrCriteriaRows(); - $html_output .= $this->_getModifyColumnsRow(); - $html_output .= '
'; - $this->_new_row_count--; - $url_params = []; - $url_params['db'] = $this->_db; - $url_params['criteriaColumnCount'] = $this->_new_column_count; - $url_params['rows'] = $this->_new_row_count; - $html_output .= Url::getHiddenInputs($url_params); - $html_output .= '
'; - $html_output .= '
'; - $html_output .= '
'; - // get footers - $html_output .= $this->_getTableFooters(); - // get tables select list - $html_output .= $this->_getTablesList(); - $html_output .= ''; - $html_output .= '
'; - $html_output .= Url::getHiddenInputs(['db' => $this->_db]); - // get SQL query - $html_output .= '
'; - $html_output .= '
'; - $html_output .= '' - . sprintf( - __('SQL query on database %s:'), - 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; - } - - /** - * Get fields to display - * - * @return string - */ - private function _getSavedSearchesField() - { - $html_output = __('Saved bookmarked search:'); - $html_output .= ' '; - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - if (null !== $currentSearchId) { - $html_output .= ''; - $html_output .= ''; - } - - return $html_output; - } - - /** - * Initialize _criteria_column_count - * - * @return int Previous number of columns - */ - private function _initializeCriteriasCount(): int - { - // sets column count - $criteriaColumnCount = Core::ifSetOr( - $_POST['criteriaColumnCount'], - 3, - 'numeric' - ); - $criteriaColumnAdd = Core::ifSetOr( - $_POST['criteriaColumnAdd'], - 0, - 'numeric' - ); - $this->_criteria_column_count = max( - $criteriaColumnCount + $criteriaColumnAdd, - 0 - ); - - // sets row count - $rows = Core::ifSetOr($_POST['rows'], 0, 'numeric'); - $criteriaRowAdd = Core::ifSetOr($_POST['criteriaRowAdd'], 0, 'numeric'); - $this->_criteria_row_count = min( - 100, - max($rows + $criteriaRowAdd, 0) - ); - - return (int) $criteriaColumnCount; - } - - /** - * Get best - * - * @param array $search_tables Tables involved in the search - * @param array|null $where_clause_columns Columns with where clause - * @param array|null $unique_columns Unique columns - * @param array|null $index_columns Indexed columns - * - * @return array - */ - private function _getLeftJoinColumnCandidatesBest( - array $search_tables, - ?array $where_clause_columns, - ?array $unique_columns, - ?array $index_columns - ) { - // now we want to find the best. - if (isset($unique_columns) && count($unique_columns) > 0) { - $candidate_columns = $unique_columns; - $needsort = 1; - return [ - $candidate_columns, - $needsort, - ]; - } elseif (isset($index_columns) && count($index_columns) > 0) { - $candidate_columns = $index_columns; - $needsort = 1; - return [ - $candidate_columns, - $needsort, - ]; - } elseif (isset($where_clause_columns) && count($where_clause_columns) > 0) { - $candidate_columns = $where_clause_columns; - $needsort = 0; - return [ - $candidate_columns, - $needsort, - ]; - } - - $candidate_columns = $search_tables; - $needsort = 0; - return [ - $candidate_columns, - $needsort, - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Database/Search.php b/srcs/phpmyadmin/libraries/classes/Database/Search.php deleted file mode 100644 index 3f1b250..0000000 --- a/srcs/phpmyadmin/libraries/classes/Database/Search.php +++ /dev/null @@ -1,347 +0,0 @@ -db = $db; - $this->dbi = $dbi; - $this->searchTypes = [ - '1' => __('at least one of the words'), - '2' => __('all of the words'), - '3' => __('the exact phrase as substring'), - '4' => __('the exact phrase as whole field'), - '5' => __('as regular expression'), - ]; - $this->template = $template; - // Sets criteria parameters - $this->setSearchParams(); - } - - /** - * Sets search parameters - * - * @return void - */ - private function setSearchParams() - { - $this->tablesNamesOnly = $this->dbi->getTables($this->db); - - if (empty($_POST['criteriaSearchType']) - || ! is_string($_POST['criteriaSearchType']) - || ! array_key_exists( - $_POST['criteriaSearchType'], - $this->searchTypes - ) - ) { - $this->criteriaSearchType = 1; - unset($_POST['submit_search']); - } else { - $this->criteriaSearchType = (int) $_POST['criteriaSearchType']; - $this->searchTypeDescription - = $this->searchTypes[$_POST['criteriaSearchType']]; - } - - if (empty($_POST['criteriaSearchString']) - || ! is_string($_POST['criteriaSearchString']) - ) { - $this->criteriaSearchString = ''; - unset($_POST['submit_search']); - } else { - $this->criteriaSearchString = $_POST['criteriaSearchString']; - } - - $this->criteriaTables = []; - if (empty($_POST['criteriaTables']) - || ! is_array($_POST['criteriaTables']) - ) { - unset($_POST['submit_search']); - } else { - $this->criteriaTables = array_intersect( - $_POST['criteriaTables'], - $this->tablesNamesOnly - ); - } - - if (empty($_POST['criteriaColumnName']) - || ! is_string($_POST['criteriaColumnName']) - ) { - unset($this->criteriaColumnName); - } else { - $this->criteriaColumnName = $this->dbi->escapeString( - $_POST['criteriaColumnName'] - ); - } - } - - /** - * Builds the SQL search query - * - * @param string $table The table name - * - * @return array 3 SQL queries (for count, display and delete results) - * - * @todo can we make use of fulltextsearch IN BOOLEAN MODE for this? - * PMA_backquote - * DatabaseInterface::freeResult - * DatabaseInterface::fetchAssoc - * $GLOBALS['db'] - * explode - * count - * strlen - */ - private function getSearchSqls($table) - { - // Statement types - $sqlstr_select = 'SELECT'; - $sqlstr_delete = 'DELETE'; - // Table to use - $sqlstr_from = ' FROM ' - . Util::backquote($GLOBALS['db']) . '.' - . Util::backquote($table); - // Gets where clause for the query - $where_clause = $this->getWhereClause($table); - // Builds complete queries - $sql = []; - $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 building SQL query - * - * @param string $table The table name - * - * @return string The generated where clause - */ - private function getWhereClause($table) - { - // Columns to select - $allColumns = $this->dbi->getColumns($GLOBALS['db'], $table); - $likeClauses = []; - // Based on search type, decide like/regex & '%'/'' - $like_or_regex = (($this->criteriaSearchType == 5) ? 'REGEXP' : 'LIKE'); - $automatic_wildcard = (($this->criteriaSearchType < 4) ? '%' : ''); - // For "as regular expression" (search option 5), LIKE won't be used - // Usage example: If user is searching for a literal $ in a regexp search, - // he should enter \$ as the value. - $criteriaSearchStringEscaped = $this->dbi->escapeString( - $this->criteriaSearchString - ); - // Extract search words or pattern - $search_words = (($this->criteriaSearchType > 2) - ? [$criteriaSearchStringEscaped] - : explode(' ', $criteriaSearchStringEscaped)); - - foreach ($search_words as $search_word) { - // Eliminates empty values - if (strlen($search_word) === 0) { - continue; - } - $likeClausesPerColumn = []; - // for each column in the table - foreach ($allColumns as $column) { - if (! isset($this->criteriaColumnName) - || strlen($this->criteriaColumnName) === 0 - || $column['Field'] == $this->criteriaColumnName - ) { - $column = 'CONVERT(' . 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() - { - $resultTotal = 0; - $rows = []; - // For each table selected as search criteria - foreach ($this->criteriaTables as $eachTable) { - // Gets the SQL statements - $newSearchSqls = $this->getSearchSqls($eachTable); - // Executes the "COUNT" statement - $resultCount = intval($this->dbi->fetchValue( - $newSearchSqls['select_count'] - )); - $resultTotal += $resultCount; - // Gets the result row's HTML for a table - $rows[] = [ - 'table' => htmlspecialchars($eachTable), - 'new_search_sqls' => $newSearchSqls, - 'result_count' => $resultCount, - ]; - } - - return $this->template->render('database/search/results', [ - 'db' => $this->db, - 'rows' => $rows, - 'result_total' => $resultTotal, - 'criteria_tables' => $this->criteriaTables, - 'criteria_search_string' => htmlspecialchars($this->criteriaSearchString), - 'search_type_description' => $this->searchTypeDescription, - ]); - } - - /** - * Provides the main search form's html - * - * @return string HTML for selection form - */ - public function getMainHtml() - { - $choices = [ - '1' => $this->searchTypes[1] . ' ' - . Util::showHint( - __('Words are separated by a space character (" ").') - ), - '2' => $this->searchTypes[2] . ' ' - . Util::showHint( - __('Words are separated by a space character (" ").') - ), - '3' => $this->searchTypes[3], - '4' => $this->searchTypes[4], - '5' => $this->searchTypes[5] . ' ' . Util::showMySQLDocu('Regexp'), - ]; - return $this->template->render('database/search/main', [ - 'db' => $this->db, - 'choices' => $choices, - 'criteria_search_string' => $this->criteriaSearchString, - 'criteria_search_type' => $this->criteriaSearchType, - 'criteria_tables' => $this->criteriaTables, - 'tables_names_only' => $this->tablesNamesOnly, - 'criteria_column_name' => isset($this->criteriaColumnName) - ? $this->criteriaColumnName : null, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/DatabaseInterface.php b/srcs/phpmyadmin/libraries/classes/DatabaseInterface.php deleted file mode 100644 index 3e12302..0000000 --- a/srcs/phpmyadmin/libraries/classes/DatabaseInterface.php +++ /dev/null @@ -1,3187 +0,0 @@ -_extension = $ext; - $this->_links = []; - if (defined('TESTSUITE')) { - $this->_links[DatabaseInterface::CONNECT_USER] = 1; - $this->_links[DatabaseInterface::CONNECT_CONTROL] = 2; - } - $this->_table_cache = []; - $this->_current_user = []; - $this->types = new Types($this); - $this->relation = new Relation($this); - } - - /** - * Checks whether database extension is loaded - * - * @param string $extension mysql extension to check - * - * @return bool - */ - public static function checkDbExtension(string $extension = 'mysqli'): bool - { - return function_exists($extension . '_connect'); - } - - /** - * runs a query - * - * @param string $query SQL query to execute - * @param mixed $link optional database link to use - * @param int $options optional query options - * @param bool $cache_affected_rows whether to cache affected rows - * - * @return mixed - */ - public function query( - string $query, - $link = DatabaseInterface::CONNECT_USER, - int $options = 0, - bool $cache_affected_rows = true - ) { - $res = $this->tryQuery($query, $link, $options, $cache_affected_rows) - or Util::mysqlDie($this->getError($link), $query); - - return $res; - } - - /** - * Get a cached value from table cache. - * - * @param array $contentPath Array of the name of the target value - * @param mixed $default Return value on cache miss - * - * @return mixed cached value or default - */ - public function getCachedTableContent(array $contentPath, $default = null) - { - return Util::getValueByKey($this->_table_cache, $contentPath, $default); - } - - /** - * Set an item in table cache using dot notation. - * - * @param array $contentPath Array with the target path - * @param mixed $value Target value - * - * @return void - */ - public function cacheTableContent(array $contentPath, $value): void - { - $loc = &$this->_table_cache; - - if (! isset($contentPath)) { - $loc = $value; - return; - } - - while (count($contentPath) > 1) { - $key = array_shift($contentPath); - - // If the key doesn't exist at this depth, we will just create an empty - // array to hold the next value, allowing us to create the arrays to hold - // final values at the correct depth. Then we'll keep digging into the - // array. - if (! isset($loc[$key]) || ! is_array($loc[$key])) { - $loc[$key] = []; - } - $loc = &$loc[$key]; - } - - $loc[array_shift($contentPath)] = $value; - } - - /** - * Clear the table cache. - * - * @return void - */ - public function clearTableCache(): void - { - $this->_table_cache = []; - } - - /** - * Caches table data so Table does not require to issue - * SHOW TABLE STATUS again - * - * @param array $tables information for tables of some databases - * @param string|bool $table table name - * - * @return void - */ - private function _cacheTableData(array $tables, $table): void - { - // 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 that consists only of numbers - - foreach ($tables as $one_database => $its_tables) { - if (isset($this->_table_cache[$one_database])) { - // the + operator does not do the intended effect - // when the cache for one table already exists - if ($table - && isset($this->_table_cache[$one_database][$table]) - ) { - unset($this->_table_cache[$one_database][$table]); - } - $this->_table_cache[$one_database] - += $tables[$one_database]; - } else { - $this->_table_cache[$one_database] = $tables[$one_database]; - } - } - } - - /** - * Stores query data into session data for debugging purposes - * - * @param string $query Query text - * @param mixed $link link type - * @param object|boolean $result Query result - * @param integer|float $time Time to execute query - * - * @return void - */ - private function _dbgQuery(string $query, $link, $result, $time): void - { - $dbgInfo = []; - $error_message = $this->getError($link); - if ($result == false && is_string($error_message)) { - $dbgInfo['error'] - = '' - . htmlspecialchars($error_message) . ''; - } - $dbgInfo['query'] = htmlspecialchars($query); - $dbgInfo['time'] = $time; - // Get and slightly format backtrace, this is used - // in the javascript console. - // Strip call to _dbgQuery - $dbgInfo['trace'] = Error::processBacktrace( - array_slice(debug_backtrace(), 1) - ); - $dbgInfo['hash'] = md5($query); - - $_SESSION['debug']['queries'][] = $dbgInfo; - } - - /** - * runs a query and returns the result - * - * @param string $query query to run - * @param mixed $link link type - * @param integer $options query options - * @param bool $cache_affected_rows whether to cache affected row - * - * @return mixed - */ - public function tryQuery( - string $query, - $link = DatabaseInterface::CONNECT_USER, - int $options = 0, - bool $cache_affected_rows = true - ) { - $debug = isset($GLOBALS['cfg']['DBG']) ? $GLOBALS['cfg']['DBG']['sql'] : false; - if (! isset($this->_links[$link])) { - return false; - } - - if ($debug) { - $time = microtime(true); - } - - $result = $this->_extension->realQuery($query, $this->_links[$link], $options); - - if ($cache_affected_rows) { - $GLOBALS['cached_affected_rows'] = $this->affectedRows($link, false); - } - - if ($debug) { - $time = microtime(true) - $time; - $this->_dbgQuery($query, $link, $result, $time); - if ($GLOBALS['cfg']['DBG']['sqllog']) { - $warningsCount = ''; - if (($options & DatabaseInterface::QUERY_STORE) == DatabaseInterface::QUERY_STORE) { - if (isset($this->_links[$link]->warning_count)) { - $warningsCount = $this->_links[$link]->warning_count; - } - } - - openlog('phpMyAdmin', LOG_NDELAY | LOG_PID, LOG_USER); - - syslog( - LOG_INFO, - 'SQL[' . basename($_SERVER['SCRIPT_NAME']) . ']: ' - . sprintf('%0.3f', $time) . '(W:' . $warningsCount . ') > ' . $query - ); - closelog(); - } - } - - if ($result !== false && Tracker::isActive()) { - Tracker::handleQuery($query); - } - - return $result; - } - - /** - * Run multi query statement and return results - * - * @param string $multiQuery multi query statement to execute - * @param int $linkIndex index of the opened database link - * - * @return mysqli_result[]|boolean (false) - */ - public function tryMultiQuery( - string $multiQuery = '', - $linkIndex = DatabaseInterface::CONNECT_USER - ) { - if (! isset($this->_links[$linkIndex])) { - return false; - } - return $this->_extension->realMultiQuery($this->_links[$linkIndex], $multiQuery); - } - - /** - * 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 - */ - public function getTables(string $database, $link = DatabaseInterface::CONNECT_USER): array - { - $tables = $this->fetchResult( - 'SHOW TABLES FROM ' . Util::backquote($database) . ';', - null, - 0, - $link, - self::QUERY_STORE - ); - if ($GLOBALS['cfg']['NaturalOrder']) { - usort($tables, 'strnatcasecmp'); - } - return $tables; - } - - - /** - * returns - * - * @param string $database name of database - * @param array $tables list of tables to search for for relations - * @param int $link mysql link resource|object - * - * @return array array of found foreign keys - */ - public function getForeignKeyConstrains(string $database, array $tables, $link = DatabaseInterface::CONNECT_USER): array - { - $tablesListForQuery = ''; - foreach ($tables as $table) { - $tablesListForQuery .= "'" . $this->escapeString($table) . "',"; - } - $tablesListForQuery = rtrim($tablesListForQuery, ','); - - $foreignKeyConstrains = $this->fetchResult( - "SELECT" - . " TABLE_NAME," - . " COLUMN_NAME," - . " REFERENCED_TABLE_NAME," - . " REFERENCED_COLUMN_NAME" - . " FROM information_schema.key_column_usage" - . " WHERE referenced_table_name IS NOT NULL" - . " AND TABLE_SCHEMA = '" . $this->escapeString($database) . "'" - . " AND TABLE_NAME IN (" . $tablesListForQuery . ")" - . " AND REFERENCED_TABLE_NAME IN (" . $tablesListForQuery . ");", - null, - null, - $link, - self::QUERY_STORE - ); - return $foreignKeyConstrains; - } - - /** - * returns a segment of the SQL WHERE clause regarding table name and type - * - * @param array|string $table table(s) - * @param boolean $tbl_is_group $table is a table group - * @param string $table_type whether table or view - * - * @return string a segment of the WHERE clause - */ - private function _getTableCondition( - $table, - bool $tbl_is_group, - ?string $table_type - ): string { - // get table information from information_schema - if ($table) { - if (is_array($table)) { - $sql_where_table = 'AND t.`TABLE_NAME` ' - . Util::getCollateForIS() . ' IN (\'' - . implode( - '\', \'', - array_map( - [ - $this, - 'escapeString', - ], - $table - ) - ) - . '\')'; - } elseif (true === $tbl_is_group) { - $sql_where_table = 'AND t.`TABLE_NAME` LIKE \'' - . Util::escapeMysqlWildcards( - $this->escapeString($table) - ) - . '%\''; - } else { - $sql_where_table = 'AND t.`TABLE_NAME` ' - . Util::getCollateForIS() . ' = \'' - . $this->escapeString($table) . '\''; - } - } else { - $sql_where_table = ''; - } - - if ($table_type) { - if ($table_type == 'view') { - $sql_where_table .= " AND t.`TABLE_TYPE` NOT IN ('BASE TABLE', 'SYSTEM VERSIONED')"; - } elseif ($table_type == 'table') { - $sql_where_table .= " AND t.`TABLE_TYPE` IN ('BASE TABLE', 'SYSTEM VERSIONED')"; - } - } - return $sql_where_table; - } - - /** - * returns the beginning of the SQL statement to fetch the list of tables - * - * @param string[] $this_databases databases to list - * @param string $sql_where_table additional condition - * - * @return string the SQL statement - */ - private function _getSqlForTablesFull($this_databases, string $sql_where_table): string - { - return ' - 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` ' . Util::getCollateForIS() . ' - IN (\'' . implode("', '", $this_databases) . '\') - ' . $sql_where_table; - } - - /** - * 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 - * - * - * $dbi->getTablesFull('my_database'); - * $dbi->getTablesFull('my_database', 'my_table')); - * $dbi->getTablesFull('my_database', 'my_tables_', true)); - * - * - * @param string $database database - * @param string|array $table table name(s) - * @param boolean $tbl_is_group $table is a table group - * @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) - * @param string $table_type whether table or view - * @param mixed $link link type - * - * @todo move into Table - * - * @return array list of tables in given db(s) - */ - public function getTablesFull( - string $database, - $table = '', - bool $tbl_is_group = false, - int $limit_offset = 0, - $limit_count = false, - string $sort_by = 'Name', - string $sort_order = 'ASC', - ?string $table_type = null, - $link = DatabaseInterface::CONNECT_USER - ): array { - if (true === $limit_count) { - $limit_count = $GLOBALS['cfg']['MaxTableList']; - } - // prepare and check parameters - if (! is_array($database)) { - $databases = [$database]; - } else { - $databases = $database; - } - - $tables = []; - - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $sql_where_table = $this->_getTableCondition( - $table, - $tbl_is_group, - $table_type - ); - - // 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( - [ - $this, - 'escapeString', - ], - $databases - ); - - $sql = $this->_getSqlForTablesFull($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 = $this->fetchResult( - $sql, - [ - 'TABLE_SCHEMA', - 'TABLE_NAME', - ], - null, - $link - ); - - 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; - } - } elseif ($sort_by == 'Data_length') { - // Size = Data_length + Index_length - foreach ($tables as $one_database_name => $one_database_tables) { - uasort( - $one_database_tables, - function ($a, $b) { - $aLength = $a['Data_length'] + $a['Index_length']; - $bLength = $b['Data_length'] + $b['Index_length']; - return $aLength <=> $bLength; - } - ); - - 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)) { - foreach ($databases as $each_database) { - if ($table || (true === $tbl_is_group) || ! empty($table_type)) { - $sql = 'SHOW TABLE STATUS FROM ' - . Util::backquote($each_database) - . ' WHERE'; - $needAnd = false; - if ($table || (true === $tbl_is_group)) { - if (is_array($table)) { - $sql .= ' `Name` IN (\'' - . implode( - '\', \'', - array_map( - [ - $this, - 'escapeString', - ], - $table, - $link - ) - ) . '\')'; - } else { - $sql .= " `Name` LIKE '" - . Util::escapeMysqlWildcards( - $this->escapeString($table, $link) - ) - . "%'"; - } - $needAnd = true; - } - if (! empty($table_type)) { - if ($needAnd) { - $sql .= " AND"; - } - if ($table_type == 'view') { - $sql .= " `Comment` = 'VIEW'"; - } elseif ($table_type == 'table') { - $sql .= " `Comment` != 'VIEW'"; - } - } - } else { - $sql = 'SHOW TABLE STATUS FROM ' - . Util::backquote($each_database); - } - - $each_tables = $this->fetchResult($sql, 'Name', null, $link); - - // 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 (! empty($$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 (! 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']; - } - - // Compatibility with INFORMATION_SCHEMA output - $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'; - } elseif ($each_database == 'information_schema') { - $each_tables[$table_name]['TABLE_TYPE'] = 'SYSTEM 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 Table does not require to issue SHOW TABLE STATUS again - $this->_cacheTableData($tables, $table); - - if (is_array($database)) { - return $tables; - } - - if (isset($tables[$database])) { - return $tables[$database]; - } - - if (isset($tables[mb_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` - // see https://github.com/phpmyadmin/phpmyadmin/issues/8402 - return $tables[mb_strtolower($database)]; - } - - return $tables; - } - - /** - * Get VIEWs in a particular database - * - * @param string $db Database name to look in - * - * @return array Set of VIEWs inside the database - */ - public function getVirtualTables(string $db): array - { - $tables_full = $this->getTablesFull($db); - $views = []; - - foreach ($tables_full as $table => $tmp) { - $_table = $this->getTable($db, (string) $table); - if ($_table->isView()) { - $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 integer $link link type - * @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 ListDatabase? - * - * @return array - */ - public function getDatabasesFull( - ?string $database = null, - bool $force_stats = false, - $link = DatabaseInterface::CONNECT_USER, - string $sort_by = 'SCHEMA_NAME', - string $sort_order = 'ASC', - int $limit_offset = 0, - $limit_count = false - ): array { - $sort_order = strtoupper($sort_order); - - if (true === $limit_count) { - $limit_count = $GLOBALS['cfg']['MaxDbList']; - } - - $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 (! empty($database)) { - $sql_where_schema = 'WHERE `SCHEMA_NAME` LIKE \'' - . $this->escapeString($database, $link) . '\''; - } else { - $sql_where_schema = ''; - } - - $sql = 'SELECT *, - CAST(BIN_NAME AS CHAR CHARACTER SET utf8) AS SCHEMA_NAME - FROM ('; - $sql .= 'SELECT - BINARY s.SCHEMA_NAME AS BIN_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(IF(t.ENGINE <> \'InnoDB\', t.DATA_FREE, 0)) - 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, s.DEFAULT_COLLATION_NAME - ORDER BY '; - if ($sort_by == 'SCHEMA_NAME' - || $sort_by == 'DEFAULT_COLLATION_NAME' - ) { - $sql .= 'BINARY '; - } - $sql .= Util::backquote($sort_by) - . ' ' . $sort_order - . $limit; - $sql .= ') a'; - - $databases = $this->fetchResult($sql, 'SCHEMA_NAME', null, $link); - - $mysql_error = $this->getError($link); - if (! count($databases) && $GLOBALS['errno']) { - 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['dblist']->databases - ); - foreach ($drops as $drop) { - unset($databases[$drop]); - } - } else { - $databases = []; - foreach ($GLOBALS['dblist']->databases as $database_name) { - // Compatibility with INFORMATION_SCHEMA output - $databases[$database_name]['SCHEMA_NAME'] = $database_name; - - $databases[$database_name]['DEFAULT_COLLATION_NAME'] - = $this->getDbCollation($database_name); - - if (! $force_stats) { - continue; - } - - // 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 = $this->query( - 'SHOW TABLE STATUS FROM ' - . Util::backquote($database_name) . ';' - ); - - if ($res === false) { - unset($res); - continue; - } - - while ($row = $this->fetchAssoc($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']; - } - $this->freeResult($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, - [ - self::class, - '_usortComparisonCallback', - ] - ); - 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; - } - - /** - * usort comparison callback - * - * @param array $a first argument to sort - * @param array $b second argument to sort - * - * @return int a value representing whether $a should be before $b in the - * sorted array or not - * - * @access private - */ - private static function _usortComparisonCallback($a, $b): int - { - 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']] - ); - } - - /** - * returns detailed array with all columns for sql - * - * @param string $sql_query target SQL query to get columns - * @param array $view_columns alias for columns - * - * @return array - */ - public function getColumnMapFromSql(string $sql_query, array $view_columns = []): array - { - $result = $this->tryQuery($sql_query); - - if ($result === false) { - return []; - } - - $meta = $this->getFieldsMeta( - $result - ); - - $nbFields = count($meta); - if ($nbFields <= 0) { - return []; - } - - $column_map = []; - $nbColumns = count($view_columns); - - for ($i = 0; $i < $nbFields; $i++) { - $map = []; - $map['table_name'] = $meta[$i]->table; - $map['refering_column'] = $meta[$i]->name; - - if ($nbColumns > 1) { - $map['real_column'] = $view_columns[$i]; - } - - $column_map[] = $map; - } - - return $column_map; - } - - /** - * 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 - */ - public function getColumnsFull( - ?string $database = null, - ?string $table = null, - ?string $column = null, - $link = DatabaseInterface::CONNECT_USER - ): array { - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $sql_wheres = []; - $array_keys = []; - - // get columns information from information_schema - if (null !== $database) { - $sql_wheres[] = '`TABLE_SCHEMA` = \'' - . $this->escapeString($database, $link) . '\' '; - } else { - $array_keys[] = 'TABLE_SCHEMA'; - } - if (null !== $table) { - $sql_wheres[] = '`TABLE_NAME` = \'' - . $this->escapeString($table, $link) . '\' '; - } else { - $array_keys[] = 'TABLE_NAME'; - } - if (null !== $column) { - $sql_wheres[] = '`COLUMN_NAME` = \'' - . $this->escapeString($column, $link) . '\' '; - } else { - $array_keys[] = 'COLUMN_NAME'; - } - - // for PMA bc: - // `[SCHEMA_FIELD_NAME]` AS `[SHOW_FULL_COLUMNS_FIELD_NAME]` - $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); - } - return $this->fetchResult($sql, $array_keys, null, $link); - } - - $columns = []; - if (null === $database) { - foreach ($GLOBALS['dblist']->databases as $database) { - $columns[$database] = $this->getColumnsFull( - $database, - null, - null, - $link - ); - } - return $columns; - } elseif (null === $table) { - $tables = $this->getTables($database); - foreach ($tables as $table) { - $columns[$table] = $this->getColumnsFull( - $database, - $table, - null, - $link - ); - } - return $columns; - } - $sql = 'SHOW FULL COLUMNS FROM ' - . Util::backquote($database) . '.' . Util::backquote($table); - if (null !== $column) { - $sql .= " LIKE '" . $this->escapeString($column, $link) . "'"; - } - - $columns = $this->fetchResult($sql, 'Field', null, $link); - $ordinal_position = 1; - foreach ($columns as $column_name => $each_column) { - // Compatibility with INFORMATION_SCHEMA output - $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; - $colType = $columns[$column_name]['COLUMN_TYPE']; - $colType = is_string($colType) ? $colType : ''; - $colTypePosComa = strpos($colType, '('); - $colTypePosComa = $colTypePosComa !== false ? $colTypePosComa : strlen($colType); - $columns[$column_name]['DATA_TYPE'] - = substr( - $colType, - 0, - $colTypePosComa - ); - /** - * @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; - $colCollation = $columns[$column_name]['COLLATION_NAME']; - $colCollation = is_string($colCollation) ? $colCollation : ''; - $colCollationPosUnderscore = strpos($colCollation, '_'); - $colCollationPosUnderscore = $colCollationPosUnderscore !== false ? $colCollationPosUnderscore : strlen($colCollation); - $columns[$column_name]['CHARACTER_SET_NAME'] - = substr( - $colCollation, - 0, - $colCollationPosUnderscore - ); - - $ordinal_position++; - } - - if (null !== $column) { - return reset($columns); - } - - return $columns; - } - - /** - * Returns SQL query for fetching columns for a table - * - * The 'Key' column is not calculated properly, use $dbi->getColumns() - * 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 getColumns() - * - * @return string - */ - public function getColumnsSql( - string $database, - string $table, - ?string $column = null, - bool $full = false - ): string { - $sql = 'SHOW ' . ($full ? 'FULL' : '') . ' COLUMNS FROM ' - . Util::backquote($database) . '.' . Util::backquote($table) - . ($column !== null ? "LIKE '" - . $this->escapeString($column) . "'" : ''); - - 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 integer $link link type - * - * @return array array indexed by column names or, - * if $column is given, flat array description - */ - public function getColumns( - string $database, - string $table, - ?string $column = null, - bool $full = false, - $link = DatabaseInterface::CONNECT_USER - ): array { - $sql = $this->getColumnsSql($database, $table, $column, $full); - $fields = $this->fetchResult($sql, 'Field', null, $link); - if (! is_array($fields) || count($fields) === 0) { - return []; - } - // Check if column is a part of multiple-column index and set its 'Key'. - $indexes = Index::getFromTable($table, $database); - foreach ($fields as $field => $field_data) { - if (! empty($field_data['Key'])) { - continue; - } - - foreach ($indexes as $index) { - /** @var Index $index */ - if (! $index->hasColumn($field)) { - continue; - } - - $index_columns = $index->getColumns(); - if ($index_columns[$field]->getSeqInIndex() > 1) { - if ($index->isUnique()) { - $fields[$field]['Key'] = 'UNI'; - } else { - $fields[$field]['Key'] = 'MUL'; - } - } - } - } - - 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 - */ - public function getColumnNames( - string $database, - string $table, - $link = DatabaseInterface::CONNECT_USER - ): ?array { - $sql = $this->getColumnsSql($database, $table); - // We only need the 'Field' column which contains the table's column names - $fields = array_keys($this->fetchResult($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 retrieved - * @param string $where additional conditions for WHERE - * - * @return string SQL for getting indexes - */ - public function getTableIndexesSql( - string $database, - string $table, - ?string $where = null - ): string { - $sql = 'SHOW INDEXES FROM ' . Util::backquote($database) . '.' - . Util::backquote($table); - if ($where) { - $sql .= ' 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 - */ - public function getTableIndexes( - string $database, - string $table, - $link = DatabaseInterface::CONNECT_USER - ): array { - $sql = $this->getTableIndexesSql($database, $table); - $indexes = $this->fetchResult($sql, null, null, $link); - - if (! is_array($indexes) || count($indexes) < 1) { - return []; - } - return $indexes; - } - - /** - * returns value of given mysql server variable - * - * @param string $var mysql server variable name - * @param int $type DatabaseInterface::GETVAR_SESSION | - * DatabaseInterface::GETVAR_GLOBAL - * @param mixed $link mysql link resource|object - * - * @return mixed value for mysql server variable - */ - public function getVariable( - string $var, - int $type = self::GETVAR_SESSION, - $link = DatabaseInterface::CONNECT_USER - ) { - switch ($type) { - case self::GETVAR_SESSION: - $modifier = ' SESSION'; - break; - case self::GETVAR_GLOBAL: - $modifier = ' GLOBAL'; - break; - default: - $modifier = ''; - } - return $this->fetchValue( - 'SHOW' . $modifier . ' VARIABLES LIKE \'' . $var . '\';', - 0, - 1, - $link - ); - } - - /** - * Sets new value for a variable if it is different from the current value - * - * @param string $var variable name - * @param string $value value to set - * @param mixed $link mysql link resource|object - * - * @return bool whether query was a successful - */ - public function setVariable( - string $var, - string $value, - $link = DatabaseInterface::CONNECT_USER - ): bool { - $current_value = $this->getVariable( - $var, - self::GETVAR_SESSION, - $link - ); - if ($current_value == $value) { - return true; - } - - return $this->query("SET " . $var . " = " . $value . ';', $link); - } - - /** - * Convert version string to integer. - * - * @param string $version MySQL server version - * - * @return int - */ - public static function versionToInt(string $version): int - { - $match = explode('.', $version); - return (int) sprintf('%d%02d%02d', $match[0], $match[1], intval($match[2])); - } - - /** - * Function called just after a connection to the MySQL database server has - * been established. It sets the connection collation, and determines the - * version of MySQL which is running. - * - * @return void - */ - public function postConnect(): void - { - $version = $this->fetchSingleRow( - 'SELECT @@version, @@version_comment', - 'ASSOC', - DatabaseInterface::CONNECT_USER - ); - - if ($version) { - $this->_version_str = isset($version['@@version']) ? $version['@@version'] : ''; - $this->_version_int = self::versionToInt($this->_version_str); - $this->_version_comment = isset($version['@@version_comment']) ? $version['@@version_comment'] : ''; - if (stripos($this->_version_str, 'mariadb') !== false) { - $this->_is_mariadb = true; - } - if (stripos($this->_version_comment, 'percona') !== false) { - $this->_is_percona = true; - } - } - - if ($this->_version_int > 50503) { - $default_charset = 'utf8mb4'; - $default_collation = 'utf8mb4_general_ci'; - } else { - $default_charset = 'utf8'; - $default_collation = 'utf8_general_ci'; - } - $GLOBALS['collation_connection'] = $default_collation; - $GLOBALS['charset_connection'] = $default_charset; - $this->query( - "SET NAMES '$default_charset' COLLATE '$default_collation';", - DatabaseInterface::CONNECT_USER, - self::QUERY_STORE - ); - - /* Locale for messages */ - $locale = LanguageManager::getInstance()->getCurrentLanguage()->getMySQLLocale(); - if (! empty($locale)) { - $this->query( - "SET lc_messages = '" . $locale . "';", - DatabaseInterface::CONNECT_USER, - self::QUERY_STORE - ); - } - - // Set timezone for the session, if required. - if ($GLOBALS['cfg']['Server']['SessionTimeZone'] != '') { - $sql_query_tz = 'SET ' . Util::backquote('time_zone') . ' = ' - . '\'' - . $this->escapeString($GLOBALS['cfg']['Server']['SessionTimeZone']) - . '\''; - - if (! $this->tryQuery($sql_query_tz)) { - $error_message_tz = sprintf( - __( - 'Unable to use timezone "%1$s" for server %2$d. ' - . 'Please check your configuration setting for ' - . '[em]$cfg[\'Servers\'][%3$d][\'SessionTimeZone\'][/em]. ' - . 'phpMyAdmin is currently using the default time zone ' - . 'of the database server.' - ), - $GLOBALS['cfg']['Server']['SessionTimeZone'], - $GLOBALS['server'], - $GLOBALS['server'] - ); - - trigger_error($error_message_tz, E_USER_WARNING); - } - } - - /* Loads closest context to this version. */ - Context::loadClosest( - ($this->_is_mariadb ? 'MariaDb' : 'MySql') . $this->_version_int - ); - - /** - * the DatabaseList class as a stub for the ListDatabase class - */ - $GLOBALS['dblist'] = new DatabaseList(); - } - - /** - * Sets collation connection for user link - * - * @param string $collation collation to set - * - * @return void - */ - public function setCollation(string $collation): void - { - $charset = $GLOBALS['charset_connection']; - /* Automatically adjust collation if not supported by server */ - if ($charset == 'utf8' && strncmp('utf8mb4_', $collation, 8) == 0) { - $collation = 'utf8_' . substr($collation, 8); - } - $result = $this->tryQuery( - "SET collation_connection = '" - . $this->escapeString($collation, DatabaseInterface::CONNECT_USER) - . "';", - DatabaseInterface::CONNECT_USER, - self::QUERY_STORE - ); - if ($result === false) { - trigger_error( - __('Failed to set configured collation connection!'), - E_USER_WARNING - ); - } else { - $GLOBALS['collation_connection'] = $collation; - } - } - - /** - * This function checks and initialises the phpMyAdmin configuration - * storage state before it is used into session cache. - * - * @return void - */ - public function initRelationParamsCache() - { - if (strlen($GLOBALS['db'])) { - $cfgRelation = $this->relation->getRelationsParam(); - if (empty($cfgRelation['db'])) { - $this->relation->fixPmaTables($GLOBALS['db'], false); - } - } - $cfgRelation = $this->relation->getRelationsParam(); - if (empty($cfgRelation['db']) && isset($GLOBALS['dblist'])) { - if ($GLOBALS['dblist']->databases->exists('phpmyadmin')) { - $this->relation->fixPmaTables('phpmyadmin', false); - } - } - } - - /** - * Function called just after a connection to the MySQL database server has - * been established. It sets the connection collation, and determines the - * version of MySQL which is running. - * - * @return void - */ - public function postConnectControl(): void - { - // If Zero configuration mode enabled, check PMA tables in current db. - if ($GLOBALS['cfg']['ZeroConf'] == true) { - /** - * the DatabaseList class as a stub for the ListDatabase class - */ - $GLOBALS['dblist'] = new DatabaseList(); - - $this->initRelationParamsCache(); - } - } - - /** - * 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 = $dbi->fetchValue($sql); - * // produces - * // $user_name = 'John Doe' - * - * - * @param string $query The query to execute - * @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 integer $link link type - * - * @return mixed value of first field in first row from result - * or false if not found - */ - public function fetchValue( - string $query, - int $row_number = 0, - $field = 0, - $link = DatabaseInterface::CONNECT_USER - ) { - $value = false; - - $result = $this->tryQuery( - $query, - $link, - self::QUERY_STORE, - false - ); - if ($result === false) { - return false; - } - - // return false if result is empty or false - // or requested row is larger than rows in result - if ($this->numRows($result) < ($row_number + 1)) { - return $value; - } - - // if $field is an integer use non associative mysql fetch function - if (is_int($field)) { - $fetch_function = 'fetchRow'; - } else { - $fetch_function = 'fetchAssoc'; - } - - // get requested row - for ($i = 0; $i <= $row_number; $i++) { - $row = $this->$fetch_function($result); - } - $this->freeResult($result); - - // return requested field - if (isset($row[$field])) { - $value = $row[$field]; - } - - return $value; - } - - /** - * returns only the first row from the result - * - * - * $sql = 'SELECT * FROM `user` WHERE `id` = 123'; - * $user = $dbi->fetchSingleRow($sql); - * // produces - * // $user = array('id' => 123, 'name' => 'John Doe') - * - * - * @param string $query The query to execute - * @param string $type NUM|ASSOC|BOTH returned array should either numeric - * associative or both - * @param integer $link link type - * - * @return array|boolean first row from result - * or false if result is empty - */ - public function fetchSingleRow( - string $query, - string $type = 'ASSOC', - $link = DatabaseInterface::CONNECT_USER - ) { - $result = $this->tryQuery( - $query, - $link, - self::QUERY_STORE, - false - ); - if ($result === false) { - return false; - } - - // return false if result is empty or false - if (! $this->numRows($result)) { - return false; - } - - switch ($type) { - case 'NUM': - $fetch_function = 'fetchRow'; - break; - case 'ASSOC': - $fetch_function = 'fetchAssoc'; - break; - case 'BOTH': - default: - $fetch_function = 'fetchArray'; - break; - } - - $row = $this->$fetch_function($result); - $this->freeResult($result); - return $row; - } - - /** - * Returns row or element of a row - * - * @param array $row Row to process - * @param string|null|int $value Which column to return - * - * @return mixed - */ - private function _fetchValue(array $row, $value) - { - if ($value === null) { - return $row; - } - - return $row[$value]; - } - - /** - * returns all rows in the resultset in one array - * - * - * $sql = 'SELECT * FROM `user`'; - * $users = $dbi->fetchResult($sql); - * // produces - * // $users[] = array('id' => 123, 'name' => 'John Doe') - * - * $sql = 'SELECT `id`, `name` FROM `user`'; - * $users = $dbi->fetchResult($sql, 'id'); - * // produces - * // $users['123'] = array('id' => 123, 'name' => 'John Doe') - * - * $sql = 'SELECT `id`, `name` FROM `user`'; - * $users = $dbi->fetchResult($sql, 0); - * // produces - * // $users['123'] = array(0 => 123, 1 => 'John Doe') - * - * $sql = 'SELECT `id`, `name` FROM `user`'; - * $users = $dbi->fetchResult($sql, 'id', 'name'); - * // or - * $users = $dbi->fetchResult($sql, 0, 1); - * // produces - * // $users['123'] = 'John Doe' - * - * $sql = 'SELECT `name` FROM `user`'; - * $users = $dbi->fetchResult($sql); - * // produces - * // $users[] = 'John Doe' - * - * $sql = 'SELECT `group`, `name` FROM `user`' - * $users = $dbi->fetchResult($sql, array('group', null), 'name'); - * // produces - * // $users['admin'][] = 'John Doe' - * - * $sql = 'SELECT `group`, `name` FROM `user`' - * $users = $dbi->fetchResult($sql, array('group', 'name'), 'id'); - * // produces - * // $users['admin']['John Doe'] = '123' - * - * - * @param string $query query to execute - * @param string|integer|array $key field-name or offset - * used as key for array - * or array of those - * @param string|integer $value value-name or offset - * used as value for array - * @param integer $link link type - * @param integer $options query options - * - * @return array resultrows or values indexed by $key - */ - public function fetchResult( - string $query, - $key = null, - $value = null, - $link = DatabaseInterface::CONNECT_USER, - int $options = 0 - ) { - $resultrows = []; - - $result = $this->tryQuery($query, $link, $options, false); - - // return empty array if result is empty or false - if ($result === false) { - return $resultrows; - } - - $fetch_function = 'fetchAssoc'; - - // no nested array if only one field is in result - if (null === $key && 1 === $this->numFields($result)) { - $value = 0; - $fetch_function = 'fetchRow'; - } - - // if $key is an integer use non associative mysql fetch function - if (is_int($key)) { - $fetch_function = 'fetchRow'; - } - - if (null === $key) { - while ($row = $this->$fetch_function($result)) { - $resultrows[] = $this->_fetchValue($row, $value); - } - } else { - if (is_array($key)) { - while ($row = $this->$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]] = []; - } - $result_target =& $result_target[$row[$key_index]]; - } - $result_target = $this->_fetchValue($row, $value); - } - } else { - while ($row = $this->$fetch_function($result)) { - $resultrows[$row[$key]] = $this->_fetchValue($row, $value); - } - } - } - - $this->freeResult($result); - return $resultrows; - } - - /** - * Get supported SQL compatibility modes - * - * @return array supported SQL compatibility modes - */ - public function getCompatibilities(): array - { - $compats = ['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 integer $link link type - * - * @return array warnings - */ - public function getWarnings($link = DatabaseInterface::CONNECT_USER): array - { - return $this->fetchResult('SHOW WARNINGS', null, null, $link); - } - - /** - * returns an array of PROCEDURE or FUNCTION names for a db - * - * @param string $db db name - * @param string $which PROCEDURE | FUNCTION - * @param integer $link link type - * - * @return array the procedure names or function names - */ - public function getProceduresOrFunctions( - string $db, - string $which, - $link = DatabaseInterface::CONNECT_USER - ): array { - $shows = $this->fetchResult( - 'SHOW ' . $which . ' STATUS;', - null, - null, - $link - ); - $result = []; - 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 integer $link link type - * - * @return string|null the definition - */ - public function getDefinition( - string $db, - string $which, - string $name, - $link = DatabaseInterface::CONNECT_USER - ): ?string { - $returned_field = [ - 'PROCEDURE' => 'Create Procedure', - 'FUNCTION' => 'Create Function', - 'EVENT' => 'Create Event', - 'VIEW' => 'Create View', - ]; - $query = 'SHOW CREATE ' . $which . ' ' - . Util::backquote($db) . '.' - . Util::backquote($name); - $result = $this->fetchValue($query, 0, $returned_field[$which], $link); - return is_string($result) ? $result : null; - } - - /** - * returns details about the PROCEDUREs or FUNCTIONs for a specific database - * or details about a specific routine - * - * @param string $db db name - * @param string $which PROCEDURE | FUNCTION or null for both - * @param string $name name of the routine (to fetch a specific routine) - * - * @return array information about ROCEDUREs or FUNCTIONs - */ - public function getRoutines( - string $db, - ?string $which = null, - string $name = '' - ): array { - $routines = []; - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $query = "SELECT" - . " `ROUTINE_SCHEMA` AS `Db`," - . " `SPECIFIC_NAME` AS `Name`," - . " `ROUTINE_TYPE` AS `Type`," - . " `DEFINER` AS `Definer`," - . " `LAST_ALTERED` AS `Modified`," - . " `CREATED` AS `Created`," - . " `SECURITY_TYPE` AS `Security_type`," - . " `ROUTINE_COMMENT` AS `Comment`," - . " `CHARACTER_SET_CLIENT` AS `character_set_client`," - . " `COLLATION_CONNECTION` AS `collation_connection`," - . " `DATABASE_COLLATION` AS `Database Collation`," - . " `DTD_IDENTIFIER`" - . " FROM `information_schema`.`ROUTINES`" - . " WHERE `ROUTINE_SCHEMA` " . Util::getCollateForIS() - . " = '" . $this->escapeString($db) . "'"; - if (Core::isValid($which, ['FUNCTION', 'PROCEDURE'])) { - $query .= " AND `ROUTINE_TYPE` = '" . $which . "'"; - } - if (! empty($name)) { - $query .= " AND `SPECIFIC_NAME`" - . " = '" . $this->escapeString($name) . "'"; - } - $result = $this->fetchResult($query); - if (! empty($result)) { - $routines = $result; - } - } else { - if ($which == 'FUNCTION' || $which == null) { - $query = "SHOW FUNCTION STATUS" - . " WHERE `Db` = '" . $this->escapeString($db) . "'"; - if (! empty($name)) { - $query .= " AND `Name` = '" - . $this->escapeString($name) . "'"; - } - $result = $this->fetchResult($query); - if (! empty($result)) { - $routines = array_merge($routines, $result); - } - } - if ($which == 'PROCEDURE' || $which == null) { - $query = "SHOW PROCEDURE STATUS" - . " WHERE `Db` = '" . $this->escapeString($db) . "'"; - if (! empty($name)) { - $query .= " AND `Name` = '" - . $this->escapeString($name) . "'"; - } - $result = $this->fetchResult($query); - if (! empty($result)) { - $routines = array_merge($routines, $result); - } - } - } - - $ret = []; - foreach ($routines as $routine) { - $one_result = []; - $one_result['db'] = $routine['Db']; - $one_result['name'] = $routine['Name']; - $one_result['type'] = $routine['Type']; - $one_result['definer'] = $routine['Definer']; - $one_result['returns'] = isset($routine['DTD_IDENTIFIER']) - ? $routine['DTD_IDENTIFIER'] : ""; - $ret[] = $one_result; - } - - // Sort results by name - $name = []; - foreach ($ret as $value) { - $name[] = $value['name']; - } - array_multisort($name, SORT_ASC, $ret); - - return $ret; - } - - /** - * returns details about the EVENTs for a specific database - * - * @param string $db db name - * @param string $name event name - * - * @return array information about EVENTs - */ - public function getEvents(string $db, string $name = ''): array - { - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $query = "SELECT" - . " `EVENT_SCHEMA` AS `Db`," - . " `EVENT_NAME` AS `Name`," - . " `DEFINER` AS `Definer`," - . " `TIME_ZONE` AS `Time zone`," - . " `EVENT_TYPE` AS `Type`," - . " `EXECUTE_AT` AS `Execute at`," - . " `INTERVAL_VALUE` AS `Interval value`," - . " `INTERVAL_FIELD` AS `Interval field`," - . " `STARTS` AS `Starts`," - . " `ENDS` AS `Ends`," - . " `STATUS` AS `Status`," - . " `ORIGINATOR` AS `Originator`," - . " `CHARACTER_SET_CLIENT` AS `character_set_client`," - . " `COLLATION_CONNECTION` AS `collation_connection`, " - . "`DATABASE_COLLATION` AS `Database Collation`" - . " FROM `information_schema`.`EVENTS`" - . " WHERE `EVENT_SCHEMA` " . Util::getCollateForIS() - . " = '" . $this->escapeString($db) . "'"; - if (! empty($name)) { - $query .= " AND `EVENT_NAME`" - . " = '" . $this->escapeString($name) . "'"; - } - } else { - $query = "SHOW EVENTS FROM " . Util::backquote($db); - if (! empty($name)) { - $query .= " AND `Name` = '" - . $this->escapeString($name) . "'"; - } - } - - $result = []; - if ($events = $this->fetchResult($query)) { - foreach ($events as $event) { - $one_result = []; - $one_result['name'] = $event['Name']; - $one_result['type'] = $event['Type']; - $one_result['status'] = $event['Status']; - $result[] = $one_result; - } - } - - // Sort results by name - $name = []; - foreach ($result as $value) { - $name[] = $value['name']; - } - array_multisort($name, SORT_ASC, $result); - - return $result; - } - - /** - * 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) - */ - public function getTriggers(string $db, string $table = '', $delimiter = '//') - { - $result = []; - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $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 EVENT_OBJECT_SCHEMA ' . Util::getCollateForIS() . '=' - . ' \'' . $this->escapeString($db) . '\''; - - if (! empty($table)) { - $query .= " AND EVENT_OBJECT_TABLE " . Util::getCollateForIS() - . " = '" . $this->escapeString($table) . "';"; - } - } else { - $query = "SHOW TRIGGERS FROM " . Util::backquote($db); - if (! empty($table)) { - $query .= " LIKE '" . $this->escapeString($table) . "';"; - } - } - - if ($triggers = $this->fetchResult($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 = []; - $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'] = 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 ' . Util::backquote($trigger['EVENT_OBJECT_TABLE']) - . "\n" . ' FOR EACH ROW ' - . $trigger['ACTION_STATEMENT'] . "\n" . $delimiter . "\n"; - - $result[] = $one_result; - } - } - - // Sort results by name - $name = []; - 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 - */ - public static function formatError(int $error_number, string $error_message): string - { - $error_message = htmlspecialchars($error_message); - - $error = '#' . ((string) $error_number); - $separator = ' — '; - - if ($error_number == 2002) { - $error .= ' - ' . $error_message; - $error .= $separator; - $error .= __( - 'The server is not responding (or the local server\'s socket' - . ' is not correctly configured).' - ); - } elseif ($error_number == 2003) { - $error .= ' - ' . $error_message; - $error .= $separator . __('The server is not responding.'); - } elseif ($error_number == 1698) { - $error .= ' - ' . $error_message; - $error .= $separator . ''; - $error .= __('Logout and try as another user.') . ''; - } elseif ($error_number == 1005) { - if (strpos($error_message, 'errno: 13') !== false) { - $error .= ' - ' . $error_message; - $error .= $separator - . __( - 'Please check privileges of directory containing database.' - ); - } else { - /* InnoDB constraints, see - * https://dev.mysql.com/doc/refman/5.0/en/ - * innodb-foreign-key-constraints.html - */ - $error .= ' - ' . $error_message . - ' (' . __('Details…') . ')'; - } - } else { - $error .= ' - ' . $error_message; - } - - return $error; - } - - /** - * gets the current user with host - * - * @return string the current user i.e. user@host - */ - public function getCurrentUser(): string - { - if (Util::cacheExists('mysql_cur_user')) { - return Util::cacheGet('mysql_cur_user'); - } - $user = $this->fetchValue('SELECT CURRENT_USER();'); - if ($user !== false) { - Util::cacheSet('mysql_cur_user', $user); - return $user; - } - return '@'; - } - - /** - * Checks if current user is superuser - * - * @return bool Whether user is a superuser - */ - public function isSuperuser(): bool - { - return self::isUserType('super'); - } - - /** - * Checks if current user has global create user/grant privilege - * or is a superuser (i.e. SELECT on mysql.users) - * while caching the result in session. - * - * @param string $type type of user to check for - * i.e. 'create', 'grant', 'super' - * - * @return bool Whether user is a given type of user - */ - public function isUserType(string $type): bool - { - if (Util::cacheExists('is_' . $type . 'user')) { - return Util::cacheGet('is_' . $type . 'user'); - } - - // when connection failed we don't have a $userlink - if (! isset($this->_links[DatabaseInterface::CONNECT_USER])) { - return false; - } - - // checking if user is logged in - if ($type === 'logged') { - return true; - } - - if (! $GLOBALS['cfg']['Server']['DisableIS'] || $type === 'super') { - // Prepare query for each user type check - $query = ''; - if ($type === 'super') { - $query = 'SELECT 1 FROM mysql.user LIMIT 1'; - } elseif ($type === 'create') { - list($user, $host) = $this->getCurrentUserAndHost(); - $query = "SELECT 1 FROM `INFORMATION_SCHEMA`.`USER_PRIVILEGES` " - . "WHERE `PRIVILEGE_TYPE` = 'CREATE USER' AND " - . "'''" . $user . "''@''" . $host . "''' LIKE `GRANTEE` LIMIT 1"; - } elseif ($type === 'grant') { - list($user, $host) = $this->getCurrentUserAndHost(); - $query = "SELECT 1 FROM (" - . "SELECT `GRANTEE`, `IS_GRANTABLE` FROM " - . "`INFORMATION_SCHEMA`.`COLUMN_PRIVILEGES` UNION " - . "SELECT `GRANTEE`, `IS_GRANTABLE` FROM " - . "`INFORMATION_SCHEMA`.`TABLE_PRIVILEGES` UNION " - . "SELECT `GRANTEE`, `IS_GRANTABLE` FROM " - . "`INFORMATION_SCHEMA`.`SCHEMA_PRIVILEGES` UNION " - . "SELECT `GRANTEE`, `IS_GRANTABLE` FROM " - . "`INFORMATION_SCHEMA`.`USER_PRIVILEGES`) t " - . "WHERE `IS_GRANTABLE` = 'YES' AND " - . "'''" . $user . "''@''" . $host . "''' LIKE `GRANTEE` LIMIT 1"; - } - - $is = false; - $result = $this->tryQuery( - $query, - self::CONNECT_USER, - self::QUERY_STORE - ); - if ($result) { - $is = (bool) $this->numRows($result); - } - $this->freeResult($result); - } else { - $is = false; - $grants = $this->fetchResult( - "SHOW GRANTS FOR CURRENT_USER();", - null, - null, - self::CONNECT_USER, - self::QUERY_STORE - ); - if ($grants) { - foreach ($grants as $grant) { - if ($type === 'create') { - if (strpos($grant, "ALL PRIVILEGES ON *.*") !== false - || strpos($grant, "CREATE USER") !== false - ) { - $is = true; - break; - } - } elseif ($type === 'grant') { - if (strpos($grant, "WITH GRANT OPTION") !== false) { - $is = true; - break; - } - } - } - } - } - - Util::cacheSet('is_' . $type . 'user', $is); - return $is; - } - - /** - * Get the current user and host - * - * @return array array of username and hostname - */ - public function getCurrentUserAndHost(): array - { - if (count($this->_current_user) === 0) { - $user = $this->getCurrentUser(); - $this->_current_user = explode("@", $user); - } - return $this->_current_user; - } - - /** - * Returns value for lower_case_table_names variable - * - * @return string|bool - */ - public function getLowerCaseNames() - { - if ($this->_lower_case_table_names === null) { - $this->_lower_case_table_names = $this->fetchValue( - "SELECT @@lower_case_table_names" - ); - } - return $this->_lower_case_table_names; - } - - /** - * Get the list of system schemas - * - * @return array list of system schemas - */ - public function getSystemSchemas(): array - { - $schemas = [ - 'information_schema', - 'performance_schema', - 'mysql', - 'sys', - ]; - $systemSchemas = []; - foreach ($schemas as $schema) { - if ($this->isSystemSchema($schema, true)) { - $systemSchemas[] = $schema; - } - } - return $systemSchemas; - } - - /** - * Checks whether given schema is a system schema - * - * @param string $schema_name Name of schema (database) to test - * @param bool $testForMysqlSchema Whether 'mysql' schema should - * be treated the same as IS and DD - * - * @return bool - */ - public function isSystemSchema( - string $schema_name, - bool $testForMysqlSchema = false - ): bool { - $schema_name = strtolower($schema_name); - return $schema_name == 'information_schema' - || $schema_name == 'performance_schema' - || ($schema_name == 'mysql' && $testForMysqlSchema) - || $schema_name == 'sys'; - } - - /** - * Return connection parameters for the database server - * - * @param integer $mode Connection mode on of CONNECT_USER, CONNECT_CONTROL - * or CONNECT_AUXILIARY. - * @param array|null $server Server information like host/port/socket/persistent - * - * @return array user, host and server settings array - */ - public function getConnectionParams(int $mode, ?array $server = null): array - { - global $cfg; - - $user = null; - $password = null; - - if ($mode == DatabaseInterface::CONNECT_USER) { - $user = $cfg['Server']['user']; - $password = $cfg['Server']['password']; - $server = $cfg['Server']; - } elseif ($mode == DatabaseInterface::CONNECT_CONTROL) { - $user = $cfg['Server']['controluser']; - $password = $cfg['Server']['controlpass']; - - $server = []; - - if (! empty($cfg['Server']['controlhost'])) { - $server['host'] = $cfg['Server']['controlhost']; - } else { - $server['host'] = $cfg['Server']['host']; - } - // Share the settings if the host is same - if ($server['host'] == $cfg['Server']['host']) { - $shared = [ - 'port', - 'socket', - 'compress', - 'ssl', - 'ssl_key', - 'ssl_cert', - 'ssl_ca', - 'ssl_ca_path', - 'ssl_ciphers', - 'ssl_verify', - ]; - foreach ($shared as $item) { - if (isset($cfg['Server'][$item])) { - $server[$item] = $cfg['Server'][$item]; - } - } - } - // Set configured port - if (! empty($cfg['Server']['controlport'])) { - $server['port'] = $cfg['Server']['controlport']; - } - // Set any configuration with control_ prefix - foreach ($cfg['Server'] as $key => $val) { - if (substr($key, 0, 8) === 'control_') { - $server[substr($key, 8)] = $val; - } - } - } else { - if ($server === null) { - return [ - null, - null, - null, - ]; - } - if (isset($server['user'])) { - $user = $server['user']; - } - if (isset($server['password'])) { - $password = $server['password']; - } - } - - // Perform sanity checks on some variables - if (empty($server['port'])) { - $server['port'] = 0; - } else { - $server['port'] = intval($server['port']); - } - if (empty($server['socket'])) { - $server['socket'] = null; - } - if (empty($server['host'])) { - $server['host'] = 'localhost'; - } - if (! isset($server['ssl'])) { - $server['ssl'] = false; - } - if (! isset($server['compress'])) { - $server['compress'] = false; - } - - return [ - $user, - $password, - $server, - ]; - } - - /** - * connects to the database server - * - * @param integer $mode Connection mode on of CONNECT_USER, CONNECT_CONTROL - * or CONNECT_AUXILIARY. - * @param array|null $server Server information like host/port/socket/persistent - * @param integer $target How to store connection link, defaults to $mode - * - * @return mixed false on error or a connection object on success - */ - public function connect(int $mode, ?array $server = null, ?int $target = null) - { - list($user, $password, $server) = $this->getConnectionParams($mode, $server); - - if ($target === null) { - $target = $mode; - } - - if ($user === null || $password === null) { - trigger_error( - __('Missing connection parameters!'), - E_USER_WARNING - ); - return false; - } - - // Do not show location and backtrace for connection errors - $GLOBALS['error_handler']->setHideLocation(true); - $result = $this->_extension->connect( - $user, - $password, - $server - ); - $GLOBALS['error_handler']->setHideLocation(false); - - if ($result) { - $this->_links[$target] = $result; - /* Run post connect for user connections */ - if ($target == DatabaseInterface::CONNECT_USER) { - $this->postConnect(); - } - return $result; - } - - if ($mode == DatabaseInterface::CONNECT_CONTROL) { - trigger_error( - __( - 'Connection for controluser as defined in your ' - . 'configuration failed.' - ), - E_USER_WARNING - ); - return false; - } elseif ($mode == DatabaseInterface::CONNECT_AUXILIARY) { - // Do not go back to main login if connection failed - // (currently used only in unit testing) - return false; - } - - return $result; - } - - /** - * selects given database - * - * @param string $dbname database name to select - * @param integer $link link type - * - * @return boolean - */ - public function selectDb(string $dbname, $link = DatabaseInterface::CONNECT_USER): bool - { - if (! isset($this->_links[$link])) { - return false; - } - return $this->_extension->selectDb($dbname, $this->_links[$link]); - } - - /** - * returns array of rows with associative and numeric keys from $result - * - * @param object $result result set identifier - * - * @return array - */ - public function fetchArray($result) - { - return $this->_extension->fetchArray($result); - } - - /** - * returns array of rows with associative keys from $result - * - * @param object $result result set identifier - * - * @return array|bool - */ - public function fetchAssoc($result) - { - return $this->_extension->fetchAssoc($result); - } - - /** - * returns array of rows with numeric keys from $result - * - * @param object $result result set identifier - * - * @return array|bool - */ - public function fetchRow($result) - { - return $this->_extension->fetchRow($result); - } - - /** - * Adjusts the result pointer to an arbitrary row in the result - * - * @param object $result database result - * @param integer $offset offset to seek - * - * @return bool true on success, false on failure - */ - public function dataSeek($result, int $offset): bool - { - return $this->_extension->dataSeek($result, $offset); - } - - /** - * Frees memory associated with the result - * - * @param object $result database result - * - * @return void - */ - public function freeResult($result): void - { - $this->_extension->freeResult($result); - } - - /** - * Check if there are any more query results from a multi query - * - * @param integer $link link type - * - * @return bool true or false - */ - public function moreResults($link = DatabaseInterface::CONNECT_USER): bool - { - if (! isset($this->_links[$link])) { - return false; - } - return $this->_extension->moreResults($this->_links[$link]); - } - - /** - * Prepare next result from multi_query - * - * @param integer $link link type - * - * @return bool true or false - */ - public function nextResult($link = DatabaseInterface::CONNECT_USER): bool - { - if (! isset($this->_links[$link])) { - return false; - } - return $this->_extension->nextResult($this->_links[$link]); - } - - /** - * Store the result returned from multi query - * - * @param integer $link link type - * - * @return mixed false when empty results / result set when not empty - */ - public function storeResult($link = DatabaseInterface::CONNECT_USER) - { - if (! isset($this->_links[$link])) { - return false; - } - return $this->_extension->storeResult($this->_links[$link]); - } - - /** - * Returns a string representing the type of connection used - * - * @param integer $link link type - * - * @return string|bool type of connection used - */ - public function getHostInfo($link = DatabaseInterface::CONNECT_USER) - { - if (! isset($this->_links[$link])) { - return false; - } - return $this->_extension->getHostInfo($this->_links[$link]); - } - - /** - * Returns the version of the MySQL protocol used - * - * @param integer $link link type - * - * @return int|bool version of the MySQL protocol used - */ - public function getProtoInfo($link = DatabaseInterface::CONNECT_USER) - { - if (! isset($this->_links[$link])) { - return false; - } - return $this->_extension->getProtoInfo($this->_links[$link]); - } - - /** - * returns a string that represents the client library version - * - * @param integer $link link type - * - * @return string MySQL client library version - */ - public function getClientInfo($link = DatabaseInterface::CONNECT_USER): string - { - if (! isset($this->_links[$link])) { - return ''; - } - return $this->_extension->getClientInfo($this->_links[$link]); - } - - /** - * returns last error message or false if no errors occurred - * - * @param integer $link link type - * - * @return string|bool error or false - */ - public function getError($link = DatabaseInterface::CONNECT_USER) - { - if (! isset($this->_links[$link])) { - return false; - } - return $this->_extension->getError($this->_links[$link]); - } - - /** - * returns the number of rows returned by last query - * - * @param object $result result set identifier - * - * @return string|int - */ - public function numRows($result) - { - return $this->_extension->numRows($result); - } - - /** - * returns last inserted auto_increment id for given $link - * or $GLOBALS['userlink'] - * - * @param integer $link link type - * - * @return int|boolean - */ - public function insertId($link = DatabaseInterface::CONNECT_USER) - { - // 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() - // - // 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 $this->fetchValue('SELECT LAST_INSERT_ID();', 0, 0, $link); - } - - /** - * returns the number of rows affected by last query - * - * @param integer $link link type - * @param bool $get_from_cache whether to retrieve from cache - * - * @return int|boolean - */ - public function affectedRows( - $link = DatabaseInterface::CONNECT_USER, - bool $get_from_cache = true - ) { - if (! isset($this->_links[$link])) { - return false; - } - - if ($get_from_cache) { - return $GLOBALS['cached_affected_rows']; - } - - return $this->_extension->affectedRows($this->_links[$link]); - } - - /** - * returns metainfo for fields in $result - * - * @param object $result result set identifier - * - * @return mixed meta info for fields in $result - */ - public function getFieldsMeta($result) - { - $result = $this->_extension->getFieldsMeta($result); - - if ($this->getLowerCaseNames() === '2') { - /** - * Fixup orgtable for lower_case_table_names = 2 - * - * In this setup MySQL server reports table name lower case - * but we still need to operate on original case to properly - * match existing strings - */ - foreach ($result as $value) { - if (strlen($value->orgtable) !== 0 && - mb_strtolower($value->orgtable) === mb_strtolower($value->table)) { - $value->orgtable = $value->table; - } - } - } - - return $result; - } - - /** - * return number of fields in given $result - * - * @param object $result result set identifier - * - * @return int field count - */ - public function numFields($result): int - { - return $this->_extension->numFields($result); - } - - /** - * returns the length of the given field $i in $result - * - * @param object $result result set identifier - * @param int $i field - * - * @return int|bool length of field - */ - public function fieldLen($result, int $i) - { - return $this->_extension->fieldLen($result, $i); - } - - /** - * returns name of $i. field in $result - * - * @param object $result result set identifier - * @param int $i field - * - * @return string name of $i. field in $result - */ - public function fieldName($result, int $i): string - { - return $this->_extension->fieldName($result, $i); - } - - /** - * returns concatenated string of human readable field flags - * - * @param object $result result set identifier - * @param int $i field - * - * @return string field flags - */ - public function fieldFlags($result, $i): string - { - return $this->_extension->fieldFlags($result, $i); - } - - /** - * returns properly escaped string for use in MySQL queries - * - * @param string $str string to be escaped - * @param mixed $link optional database link to use - * - * @return string a MySQL escaped string - */ - public function escapeString(string $str, $link = DatabaseInterface::CONNECT_USER) - { - if ($this->_extension === null || ! isset($this->_links[$link])) { - return $str; - } - - return $this->_extension->escapeString($this->_links[$link], $str); - } - - /** - * Checks if this database server is running on Amazon RDS. - * - * @return boolean - */ - public function isAmazonRds(): bool - { - if (Util::cacheExists('is_amazon_rds')) { - return Util::cacheGet('is_amazon_rds'); - } - $sql = 'SELECT @@basedir'; - $result = $this->fetchValue($sql); - $rds = (substr($result, 0, 10) == '/rdsdbbin/'); - Util::cacheSet('is_amazon_rds', $rds); - - return $rds; - } - - /** - * Gets SQL for killing a process. - * - * @param int $process Process ID - * - * @return string - */ - public function getKillQuery(int $process): string - { - if ($this->isAmazonRds()) { - return 'CALL mysql.rds_kill(' . $process . ');'; - } - - return 'KILL ' . $process . ';'; - } - - /** - * Get the phpmyadmin database manager - * - * @return SystemDatabase - */ - public function getSystemDatabase(): SystemDatabase - { - return new SystemDatabase($this); - } - - /** - * Get a table with database name and table name - * - * @param string $db_name DB name - * @param string $table_name Table name - * - * @return Table - */ - public function getTable(string $db_name, string $table_name): Table - { - return new Table($table_name, $db_name, $this); - } - - /** - * returns collation of given db - * - * @param string $db name of db - * - * @return string collation of $db - */ - public function getDbCollation(string $db): string - { - if ($this->isSystemSchema($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 = 'SELECT DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA' - . ' WHERE SCHEMA_NAME = \'' . $this->escapeString($db) - . '\' LIMIT 1'; - return $this->fetchValue($sql); - } - - $this->selectDb($db); - $return = $this->fetchValue('SELECT @@collation_database'); - if ($db !== $GLOBALS['db']) { - $this->selectDb($GLOBALS['db']); - } - return $return; - } - - /** - * returns default server collation from show variables - * - * @return string - */ - public function getServerCollation(): string - { - return $this->fetchValue('SELECT @@collation_server'); - } - - /** - * Server version as number - * - * @return integer - */ - public function getVersion(): int - { - return $this->_version_int; - } - - /** - * Server version - * - * @return string - */ - public function getVersionString(): string - { - return $this->_version_str; - } - - /** - * Server version comment - * - * @return string - */ - public function getVersionComment(): string - { - return $this->_version_comment; - } - - /** - * Whether connection is MariaDB - * - * @return boolean - */ - public function isMariaDB(): bool - { - return $this->_is_mariadb; - } - - /** - * Whether connection is Percona - * - * @return boolean - */ - public function isPercona(): bool - { - return $this->_is_percona; - } - - /** - * Load correct database driver - * - * @param DbiExtension|null $extension Force the use of an alternative extension - * - * @return self - */ - public static function load(?DbiExtension $extension = null): self - { - global $dbi; - - if ($extension !== null) { - $dbi = new self($extension); - return $dbi; - } - - if (! self::checkDbExtension('mysqli')) { - $docUrl = Util::getDocuLink('faq', 'faqmysql'); - $docLink = sprintf( - __('See %sour documentation%s for more information.'), - '[a@' . $docUrl . '@documentation]', - '[/a]' - ); - Core::warnMissingExtension( - 'mysqli', - true, - $docLink - ); - } - - $dbi = new self(new DbiMysqli()); - return $dbi; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Dbi/DbiExtension.php b/srcs/phpmyadmin/libraries/classes/Dbi/DbiExtension.php deleted file mode 100644 index 8cfa9fc..0000000 --- a/srcs/phpmyadmin/libraries/classes/Dbi/DbiExtension.php +++ /dev/null @@ -1,248 +0,0 @@ - 'num', - MYSQLI_PART_KEY_FLAG => 'part_key', - MYSQLI_SET_FLAG => 'set', - MYSQLI_TIMESTAMP_FLAG => 'timestamp', - MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment', - MYSQLI_ENUM_FLAG => 'enum', - MYSQLI_ZEROFILL_FLAG => 'zerofill', - MYSQLI_UNSIGNED_FLAG => 'unsigned', - MYSQLI_BLOB_FLAG => 'blob', - MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key', - MYSQLI_UNIQUE_KEY_FLAG => 'unique_key', - MYSQLI_PRI_KEY_FLAG => 'primary_key', - MYSQLI_NOT_NULL_FLAG => 'not_null', - ]; - - /** - * connects to the database server - * - * @param string $user mysql user name - * @param string $password mysql user password - * @param array $server host/port/socket/persistent - * - * @return mysqli|bool false on error or a mysqli object on success - */ - public function connect($user, $password, array $server) - { - if ($server) { - $server['host'] = empty($server['host']) - ? 'localhost' - : $server['host']; - } - - $mysqli = mysqli_init(); - - $client_flags = 0; - - /* Optionally compress connection */ - if ($server['compress'] && defined('MYSQLI_CLIENT_COMPRESS')) { - $client_flags |= MYSQLI_CLIENT_COMPRESS; - } - - /* Optionally enable SSL */ - if ($server['ssl']) { - $client_flags |= MYSQLI_CLIENT_SSL; - if (! empty($server['ssl_key']) || - ! empty($server['ssl_cert']) || - ! empty($server['ssl_ca']) || - ! empty($server['ssl_ca_path']) || - ! empty($server['ssl_ciphers']) - ) { - if (! isset($server['ssl_key']) || is_null($server['ssl_key'])) { - $server['ssl_key'] = ''; - } - if (! isset($server['ssl_cert']) || is_null($server['ssl_cert'])) { - $server['ssl_cert'] = ''; - } - if (! isset($server['ssl_ca']) || is_null($server['ssl_ca'])) { - $server['ssl_ca'] = ''; - } - if (! isset($server['ssl_ca_path']) || is_null($server['ssl_ca_path'])) { - $server['ssl_ca_path'] = ''; - } - if (! isset($server['ssl_ciphers']) || is_null($server['ssl_ciphers'])) { - $server['ssl_ciphers'] = ''; - } - $mysqli->ssl_set( - $server['ssl_key'], - $server['ssl_cert'], - $server['ssl_ca'], - $server['ssl_ca_path'], - $server['ssl_ciphers'] - ); - } - /* - * disables SSL certificate validation on mysqlnd for MySQL 5.6 or later - * @link https://bugs.php.net/bug.php?id=68344 - * @link https://github.com/phpmyadmin/phpmyadmin/pull/11838 - */ - if (! $server['ssl_verify']) { - $mysqli->options( - MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, - $server['ssl_verify'] - ); - $client_flags |= MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT; - } - } - - if ($GLOBALS['cfg']['PersistentConnections']) { - $host = 'p:' . $server['host']; - } else { - $host = $server['host']; - } - - $return_value = $mysqli->real_connect( - $host, - $user, - $password, - '', - $server['port'], - (string) $server['socket'], - $client_flags - ); - - if ($return_value === false || $return_value === null) { - /* - * Switch to SSL if server asked us to do so, unfortunately - * there are more ways MySQL server can tell this: - * - * - MySQL 8.0 and newer should return error 3159 - * - #2001 - SSL Connection is required. Please specify SSL options and retry. - * - #9002 - SSL connection is required. Please specify SSL options and retry. - */ - $error_number = $mysqli->connect_errno; - $error_message = $mysqli->connect_error; - if (! $server['ssl'] && ($error_number == 3159 || - (($error_number == 2001 || $error_number == 9002) && stripos($error_message, 'SSL Connection is required') !== false)) - ) { - trigger_error( - __('SSL connection enforced by server, automatically enabling it.'), - E_USER_WARNING - ); - $server['ssl'] = true; - return self::connect($user, $password, $server); - } - return false; - } - - if (defined('PMA_ENABLE_LDI')) { - $mysqli->options(MYSQLI_OPT_LOCAL_INFILE, true); - } else { - $mysqli->options(MYSQLI_OPT_LOCAL_INFILE, false); - } - - return $mysqli; - } - - /** - * selects given database - * - * @param string $databaseName database name to select - * @param mysqli $mysqli the mysqli object - * - * @return boolean - */ - public function selectDb($databaseName, $mysqli) - { - return $mysqli->select_db($databaseName); - } - - /** - * runs a query and returns the result - * - * @param string $query query to execute - * @param mysqli $mysqli mysqli object - * @param int $options query options - * - * @return mysqli_result|bool - */ - public function realQuery($query, $mysqli, $options) - { - if ($options == ($options | DatabaseInterface::QUERY_STORE)) { - $method = MYSQLI_STORE_RESULT; - } elseif ($options == ($options | DatabaseInterface::QUERY_UNBUFFERED)) { - $method = MYSQLI_USE_RESULT; - } else { - $method = 0; - } - - return $mysqli->query($query, $method); - } - - /** - * Run the multi query and output the results - * - * @param mysqli $mysqli mysqli object - * @param string $query multi query statement to execute - * - * @return bool - */ - public function realMultiQuery($mysqli, $query) - { - return $mysqli->multi_query($query); - } - - /** - * returns array of rows with associative and numeric keys from $result - * - * @param mysqli_result $result result set identifier - * - * @return array|null - */ - public function fetchArray($result) - { - if (! $result instanceof mysqli_result) { - return null; - } - return $result->fetch_array(MYSQLI_BOTH); - } - - /** - * returns array of rows with associative keys from $result - * - * @param mysqli_result $result result set identifier - * - * @return array|null - */ - public function fetchAssoc($result) - { - if (! $result instanceof mysqli_result) { - return null; - } - return $result->fetch_array(MYSQLI_ASSOC); - } - - /** - * returns array of rows with numeric keys from $result - * - * @param mysqli_result $result result set identifier - * - * @return array|null - */ - public function fetchRow($result) - { - if (! $result instanceof mysqli_result) { - return null; - } - return $result->fetch_array(MYSQLI_NUM); - } - - /** - * Adjusts the result pointer to an arbitrary row in the result - * - * @param mysqli_result $result database result - * @param integer $offset offset to seek - * - * @return bool true on success, false on failure - */ - public function dataSeek($result, $offset) - { - return $result->data_seek($offset); - } - - /** - * Frees memory associated with the result - * - * @param mysqli_result $result database result - * - * @return void - */ - public function freeResult($result) - { - if ($result instanceof mysqli_result) { - $result->close(); - } - } - - /** - * Check if there are any more query results from a multi query - * - * @param mysqli $mysqli the mysqli object - * - * @return bool true or false - */ - public function moreResults($mysqli) - { - return $mysqli->more_results(); - } - - /** - * Prepare next result from multi_query - * - * @param mysqli $mysqli the mysqli object - * - * @return bool true or false - */ - public function nextResult($mysqli) - { - return $mysqli->next_result(); - } - - /** - * Store the result returned from multi query - * - * @param mysqli $mysqli the mysqli object - * - * @return mysqli_result|bool false when empty results / result set when not empty - */ - public function storeResult($mysqli) - { - return $mysqli->store_result(); - } - - /** - * Returns a string representing the type of connection used - * - * @param mysqli $mysqli mysql link - * - * @return string type of connection used - */ - public function getHostInfo($mysqli) - { - return $mysqli->host_info; - } - - /** - * Returns the version of the MySQL protocol used - * - * @param mysqli $mysqli mysql link - * - * @return string version of the MySQL protocol used - */ - public function getProtoInfo($mysqli) - { - return $mysqli->protocol_version; - } - - /** - * returns a string that represents the client library version - * - * @param mysqli $mysqli mysql link - * - * @return string MySQL client library version - */ - public function getClientInfo($mysqli) - { - return $mysqli->get_client_info(); - } - - /** - * returns last error message or false if no errors occurred - * - * @param mysqli $mysqli mysql link - * - * @return string|bool error or false - */ - public function getError($mysqli) - { - $GLOBALS['errno'] = 0; - - if (null !== $mysqli && false !== $mysqli) { - $error_number = $mysqli->errno; - $error_message = $mysqli->error; - } 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 getError() - $GLOBALS['errno'] = $error_number; - - return $GLOBALS['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 - */ - public function numRows($result) - { - // see the note for tryQuery(); - if (is_bool($result)) { - return 0; - } - - return $result->num_rows; - } - - /** - * returns the number of rows affected by last query - * - * @param mysqli $mysqli the mysqli object - * - * @return int - */ - public function affectedRows($mysqli) - { - return $mysqli->affected_rows; - } - - /** - * returns meta info for fields in $result - * - * @param mysqli_result $result result set identifier - * - * @return array|bool meta info for fields in $result - */ - public function getFieldsMeta($result) - { - if (! $result instanceof mysqli_result) { - return false; - } - // Build an associative array for a type look up - $typeAr = []; - $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'; - // 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 - // see https://github.com/phpmyadmin/phpmyadmin/issues/8569 - //$typeAr[MYSQLI_TYPE_CHAR] = 'string'; - $typeAr[MYSQLI_TYPE_GEOMETRY] = 'geometry'; - $typeAr[MYSQLI_TYPE_BIT] = 'bit'; - $typeAr[MYSQLI_TYPE_JSON] = 'json'; - - $fields = $result->fetch_fields(); - - 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 = $this->fieldFlags($result, $k); - - // Enhance the field objects for mysql-extension compatibility - //$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 - */ - public function numFields($result) - { - return $result->field_count; - } - - /** - * returns the length of the given field $i in $result - * - * @param mysqli_result $result result set identifier - * @param int $i field - * - * @return int|bool length of field - */ - public function fieldLen($result, $i) - { - if ($i >= $this->numFields($result)) { - return false; - } - /** @var stdClass $fieldDefinition */ - $fieldDefinition = $result->fetch_field_direct($i); - if ($fieldDefinition !== false) { - return $fieldDefinition->length; - } - return false; - } - - /** - * returns name of $i. field in $result - * - * @param mysqli_result $result result set identifier - * @param int $i field - * - * @return string|bool name of $i. field in $result - */ - public function fieldName($result, $i) - { - if ($i >= $this->numFields($result)) { - return false; - } - /** @var stdClass $fieldDefinition */ - $fieldDefinition = $result->fetch_field_direct($i); - if ($fieldDefinition !== false) { - return $fieldDefinition->name; - } - return false; - } - - /** - * returns concatenated string of human readable field flags - * - * @param mysqli_result $result result set identifier - * @param int $i field - * - * @return string|false field flags - */ - public function fieldFlags($result, $i) - { - if ($i >= $this->numFields($result)) { - return false; - } - /** @var stdClass $fieldDefinition */ - $fieldDefinition = $result->fetch_field_direct($i); - if ($fieldDefinition !== false) { - $type = $fieldDefinition->type; - $charsetNumber = $fieldDefinition->charsetnr; - $fieldDefinitionFlags = $fieldDefinition->flags; - $flags = []; - foreach (self::$pma_mysqli_flag_names as $flag => $name) { - if ($fieldDefinitionFlags & $flag) { - $flags[] = $name; - } - } - // See https://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 == $charsetNumber - ) { - $flags[] = 'binary'; - } - return implode(' ', $flags); - } else { - return ''; - } - } - - /** - * returns properly escaped string for use in MySQL queries - * - * @param mysqli $mysqli database link - * @param string $string string to be escaped - * - * @return string a MySQL escaped string - */ - public function escapeString($mysqli, $string) - { - return $mysqli->real_escape_string($string); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Di/Migration.php b/srcs/phpmyadmin/libraries/classes/Di/Migration.php deleted file mode 100644 index 2990610..0000000 --- a/srcs/phpmyadmin/libraries/classes/Di/Migration.php +++ /dev/null @@ -1,71 +0,0 @@ -containerBuilder = $containerBuilder; - } - - /** - * Get the instance of the service - * - * @param string $key Key of data to store - * @param mixed $value Data to store - * - * @return void - */ - public function setGlobal(string $key, $value) - { - $GLOBALS[$key] = $value; - $this->containerBuilder->setParameter($key, $value); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Display/ChangePassword.php b/srcs/phpmyadmin/libraries/classes/Display/ChangePassword.php deleted file mode 100644 index a786b6c..0000000 --- a/srcs/phpmyadmin/libraries/classes/Display/ChangePassword.php +++ /dev/null @@ -1,182 +0,0 @@ -'; - - $html .= Url::getHiddenInputs(); - - if (strpos($GLOBALS['PMA_PHP_SELF'], 'server_privileges') !== false) { - $html .= '' - . ''; - } - $html .= '
' - . '' . __('Change password') . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . ''; - - $serverType = Util::getServerType(); - $serverVersion = $GLOBALS['dbi']->getVersion(); - $orig_auth_plugin = $serverPrivileges->getCurrentAuthenticationPlugin( - 'change', - $username, - $hostname - ); - - if (($serverType == 'MySQL' - && $serverVersion >= 50507) - || ($serverType == 'MariaDB' - && $serverVersion >= 50200) - ) { - // Provide this option only for 5.7.6+ - // OR for privileged users in 5.5.7+ - if (($serverType == 'MySQL' - && $serverVersion >= 50706) - || ($GLOBALS['dbi']->isSuperuser() && $mode == 'edit_other') - ) { - $auth_plugin_dropdown = $serverPrivileges->getHtmlForAuthPluginsDropdown( - $orig_auth_plugin, - 'change_pw', - 'new' - ); - - $html .= '' - . '' - . '' - . '
' - . '' - . '' - . '
' - . '' - . '' - . '' - . __('Enter:') . '     ' - . '' - . 'Strength: ' - . ' ' - . 'Good' - . '
' . __('Re-type:') . ' ' - . '' - . '
' . __('Password Hashing:') . ''; - $html .= $auth_plugin_dropdown; - $html .= '
'; - - $html .= '' - . Message::notice( - __( - 'This method requires using an \'SSL connection\' ' - . 'or an \'unencrypted connection that encrypts the ' - . 'password using RSA\'; while connecting to the server.' - ) - . Util::showMySQLDocu( - 'sha256-authentication-plugin' - ) - ) - ->getDisplay() - . '
'; - } else { - $html .= '' - . ''; - } - } else { - $auth_plugin_dropdown = $serverPrivileges->getHtmlForAuthPluginsDropdown( - $orig_auth_plugin, - 'change_pw', - 'old' - ); - - $html .= '' - . '' . __('Password Hashing:') . ''; - $html .= $auth_plugin_dropdown . '' - . '' - . ''; - } - - $html .= '' - . '' - . ''; - return $html; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Display/CreateTable.php b/srcs/phpmyadmin/libraries/classes/Display/CreateTable.php deleted file mode 100644 index d984e55..0000000 --- a/srcs/phpmyadmin/libraries/classes/Display/CreateTable.php +++ /dev/null @@ -1,56 +0,0 @@ -= 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 - */ -declare(strict_types=1); - -namespace PhpMyAdmin\Display; - -use PhpMyAdmin\CheckUserPrivileges; -use PhpMyAdmin\Template; - -/** - * PhpMyAdmin\Display\CreateTable class - * - * @package PhpMyAdmin - */ -class CreateTable -{ - /** - * Returns the html for create table. - * - * @param string $db database name - * - * @return string - */ - public static function getHtml($db) - { - $checkUserPrivileges = new CheckUserPrivileges($GLOBALS['dbi']); - $checkUserPrivileges->getPrivileges(); - - $template = new Template(); - return $template->render('database/create_table', ['db' => $db]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Display/Error.php b/srcs/phpmyadmin/libraries/classes/Display/Error.php deleted file mode 100644 index a601532..0000000 --- a/srcs/phpmyadmin/libraries/classes/Display/Error.php +++ /dev/null @@ -1,56 +0,0 @@ -render( - 'error/generic', - [ - 'lang' => $lang, - 'dir' => $dir, - 'error_header' => $errorHeader, - 'error_message' => Sanitize::sanitizeMessage($errorMessage), - ] - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Display/Export.php b/srcs/phpmyadmin/libraries/classes/Display/Export.php deleted file mode 100644 index db02a5e..0000000 --- a/srcs/phpmyadmin/libraries/classes/Display/Export.php +++ /dev/null @@ -1,825 +0,0 @@ -relation = new Relation($GLOBALS['dbi']); - $this->template = new Template(); - } - - /** - * Outputs appropriate checked statement for checkbox. - * - * @param string $str option name - * - * @return boolean - */ - private function checkboxCheck($str) - { - return isset($GLOBALS['cfg']['Export'][$str]) - && $GLOBALS['cfg']['Export'][$str]; - } - - /** - * Prints Html For Export Selection Options - * - * @param string $tmpSelect Tmp selected method of export - * - * @return string - */ - public function getHtmlForSelectOptions($tmpSelect = '') - { - // Check if the selected databases are defined in $_POST - // (from clicking Back button on export.php) - if (isset($_POST['db_select'])) { - $_POST['db_select'] = urldecode($_POST['db_select']); - $_POST['db_select'] = explode(",", $_POST['db_select']); - } - - $databases = []; - foreach ($GLOBALS['dblist']->databases as $currentDb) { - if ($GLOBALS['dbi']->isSystemSchema($currentDb, true)) { - continue; - } - $isSelected = false; - if (isset($_POST['db_select'])) { - if (in_array($currentDb, $_POST['db_select'])) { - $isSelected = true; - } - } elseif (! empty($tmpSelect)) { - if (mb_strpos( - ' ' . $tmpSelect, - '|' . $currentDb . '|' - )) { - $isSelected = true; - } - } else { - $isSelected = true; - } - $databases[] = [ - 'name' => $currentDb, - 'is_selected' => $isSelected, - ]; - } - - return $this->template->render('display/export/select_options', [ - 'databases' => $databases, - ]); - } - - /** - * Prints Html For Export Hidden Input - * - * @param string $exportType Selected Export Type - * @param string $db Selected DB - * @param string $table Selected Table - * @param string $singleTable Single Table - * @param string $sqlQuery SQL Query - * - * @return string - */ - public function getHtmlForHiddenInputs( - $exportType, - $db, - $table, - $singleTable, - $sqlQuery - ) { - global $cfg; - - // If the export method was not set, the default is quick - if (isset($_POST['export_method'])) { - $cfg['Export']['method'] = $_POST['export_method']; - } elseif (! isset($cfg['Export']['method'])) { - $cfg['Export']['method'] = 'quick'; - } - - if (empty($sqlQuery) && isset($_POST['sql_query'])) { - $sqlQuery = $_POST['sql_query']; - } - - return $this->template->render('display/export/hidden_inputs', [ - 'db' => $db, - 'table' => $table, - 'export_type' => $exportType, - 'export_method' => $cfg['Export']['method'], - 'single_table' => $singleTable, - 'sql_query' => $sqlQuery, - 'template_id' => isset($_POST['template_id']) ? $_POST['template_id'] : '', - ]); - } - - /** - * Returns HTML for the options in template dropdown - * - * @param string $exportType export type - server, database, or table - * - * @return string HTML for the options in teplate dropdown - */ - private function getOptionsForTemplates($exportType) - { - // Get the relation settings - $cfgRelation = $this->relation->getRelationsParam(); - - $query = "SELECT `id`, `template_name` FROM " - . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['export_templates']) - . " WHERE `username` = " - . "'" . $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['user']) - . "' AND `export_type` = '" . $GLOBALS['dbi']->escapeString($exportType) . "'" - . " ORDER BY `template_name`;"; - - $result = $this->relation->queryAsControlUser($query); - - $templates = []; - if ($result !== false) { - while ($row = $GLOBALS['dbi']->fetchAssoc($result, DatabaseInterface::CONNECT_CONTROL)) { - $templates[] = [ - 'name' => $row['template_name'], - 'id' => $row['id'], - ]; - } - } - - return $this->template->render('display/export/template_options', [ - 'templates' => $templates, - 'selected_template' => ! empty($_POST['template_id']) ? $_POST['template_id'] : null, - ]); - } - - /** - * Prints Html For Export Options Method - * - * @return string - */ - private function getHtmlForOptionsMethod() - { - global $cfg; - if (isset($_POST['quick_or_custom'])) { - $exportMethod = $_POST['quick_or_custom']; - } else { - $exportMethod = $cfg['Export']['method']; - } - - return $this->template->render('display/export/method', [ - 'export_method' => $exportMethod, - ]); - } - - /** - * Prints Html For Export Options Selection - * - * @param string $exportType Selected Export Type - * @param string $multiValues Export Options - * - * @return string - */ - private function getHtmlForOptionsSelection($exportType, $multiValues) - { - return $this->template->render('display/export/selection', [ - 'export_type' => $exportType, - 'multi_values' => $multiValues, - ]); - } - - /** - * Prints Html For Export Options Format dropdown - * - * @param ExportPlugin[] $exportList Export List - * - * @return string - */ - private function getHtmlForOptionsFormatDropdown($exportList) - { - $dropdown = Plugins::getChoice('Export', 'what', $exportList, 'format'); - return $this->template->render('display/export/format_dropdown', [ - 'dropdown' => $dropdown, - ]); - } - - /** - * Prints Html For Export Options Format-specific options - * - * @param ExportPlugin[] $exportList Export List - * - * @return string - */ - private function getHtmlForOptionsFormat($exportList) - { - global $cfg; - $options = Plugins::getOptions('Export', $exportList); - - return $this->template->render('display/export/options_format', [ - 'options' => $options, - 'can_convert_kanji' => Encoding::canConvertKanji(), - 'exec_time_limit' => $cfg['ExecTimeLimit'], - ]); - } - - /** - * Prints Html For Export Options Rows - * - * @param string $db Selected DB - * @param string $table Selected Table - * @param string $unlimNumRows Num of Rows - * - * @return string - */ - private function getHtmlForOptionsRows($db, $table, $unlimNumRows) - { - $tableObject = new Table($table, $db); - $numberOfRows = $tableObject->countRecords(); - - return $this->template->render('display/export/options_rows', [ - 'allrows' => isset($_POST['allrows']) ? $_POST['allrows'] : null, - 'limit_to' => isset($_POST['limit_to']) ? $_POST['limit_to'] : null, - 'limit_from' => isset($_POST['limit_from']) ? $_POST['limit_from'] : null, - 'unlim_num_rows' => $unlimNumRows, - 'number_of_rows' => $numberOfRows, - ]); - } - - /** - * Prints Html For Export Options Quick Export - * - * @return string - */ - private function getHtmlForOptionsQuickExport() - { - global $cfg; - $saveDir = Util::userDir($cfg['SaveDir']); - $exportIsChecked = $this->checkboxCheck( - 'quick_export_onserver' - ); - $exportOverwriteIsChecked = $this->checkboxCheck( - 'quick_export_onserver_overwrite' - ); - - return $this->template->render('display/export/options_quick_export', [ - 'save_dir' => $saveDir, - 'export_is_checked' => $exportIsChecked, - 'export_overwrite_is_checked' => $exportOverwriteIsChecked, - ]); - } - - /** - * Prints Html For Export Options Save Dir - * - * @return string - */ - private function getHtmlForOptionsOutputSaveDir() - { - global $cfg; - $saveDir = Util::userDir($cfg['SaveDir']); - $exportIsChecked = $this->checkboxCheck( - 'onserver' - ); - $exportOverwriteIsChecked = $this->checkboxCheck( - 'onserver_overwrite' - ); - - return $this->template->render('display/export/options_output_save_dir', [ - 'save_dir' => $saveDir, - 'export_is_checked' => $exportIsChecked, - 'export_overwrite_is_checked' => $exportOverwriteIsChecked, - ]); - } - - - /** - * Prints Html For Export Options - * - * @param string $exportType Selected Export Type - * - * @return string - */ - private function getHtmlForOptionsOutputFormat($exportType) - { - $trans = new Message(); - $trans->addText(__('@SERVER@ will become the server name')); - if ($exportType == 'database' || $exportType == 'table') { - $trans->addText(__(', @DATABASE@ will become the database name')); - if ($exportType == 'table') { - $trans->addText(__(', @TABLE@ will become the table name')); - } - } - - $msg = new Message( - __( - 'This value is interpreted using %1$sstrftime%2$s, ' - . 'so you can use time formatting strings. ' - . 'Additionally the following transformations will happen: %3$s. ' - . 'Other text will be kept as is. See the %4$sFAQ%5$s for details.' - ) - ); - $msg->addParamHtml( - '' - ); - $msg->addParamHtml(''); - $msg->addParam($trans); - $docUrl = Util::getDocuLink('faq', 'faq6-27'); - $msg->addParamHtml( - '' - ); - $msg->addParamHtml(''); - - if (isset($_POST['filename_template'])) { - $filenameTemplate = $_POST['filename_template']; - } else { - if ($exportType == 'database') { - $filenameTemplate = $GLOBALS['PMA_Config']->getUserValue( - 'pma_db_filename_template', - $GLOBALS['cfg']['Export']['file_template_database'] - ); - } elseif ($exportType == 'table') { - $filenameTemplate = $GLOBALS['PMA_Config']->getUserValue( - 'pma_table_filename_template', - $GLOBALS['cfg']['Export']['file_template_table'] - ); - } else { - $filenameTemplate = $GLOBALS['PMA_Config']->getUserValue( - 'pma_server_filename_template', - $GLOBALS['cfg']['Export']['file_template_server'] - ); - } - } - - return $this->template->render('display/export/options_output_format', [ - 'message' => $msg->getMessage(), - 'filename_template' => $filenameTemplate, - 'is_checked' => $this->checkboxCheck('remember_file_template'), - ]); - } - - /** - * Prints Html For Export Options Charset - * - * @return string - */ - private function getHtmlForOptionsOutputCharset() - { - global $cfg; - - return $this->template->render('display/export/options_output_charset', [ - 'encodings' => Encoding::listEncodings(), - 'export_charset' => $cfg['Export']['charset'], - ]); - } - - /** - * Prints Html For Export Options Compression - * - * @return string - */ - private function getHtmlForOptionsOutputCompression() - { - global $cfg; - if (isset($_POST['compression'])) { - $selectedCompression = $_POST['compression']; - } elseif (isset($cfg['Export']['compression'])) { - $selectedCompression = $cfg['Export']['compression']; - } else { - $selectedCompression = 'none'; - } - - // Since separate files export works with ZIP only - if (isset($cfg['Export']['as_separate_files']) - && $cfg['Export']['as_separate_files'] - ) { - $selectedCompression = 'zip'; - } - - // zip and gzip encode features - $isZip = ($cfg['ZipDump'] && function_exists('gzcompress')); - $isGzip = ($cfg['GZipDump'] && function_exists('gzencode')); - - return $this->template->render('display/export/options_output_compression', [ - 'is_zip' => $isZip, - 'is_gzip' => $isGzip, - 'selected_compression' => $selectedCompression, - ]); - } - - /** - * Prints Html For Export Options Radio - * - * @return string - */ - private function getHtmlForOptionsOutputRadio() - { - return $this->template->render('display/export/options_output_radio', [ - 'has_repopulate' => isset($_POST['repopulate']), - 'export_asfile' => $GLOBALS['cfg']['Export']['asfile'], - ]); - } - - /** - * Prints Html For Export Options Checkbox - Separate files - * - * @param string $exportType Selected Export Type - * - * @return string - */ - private function getHtmlForOptionsOutputSeparateFiles($exportType) - { - $isChecked = $this->checkboxCheck('as_separate_files'); - - return $this->template->render('display/export/options_output_separate_files', [ - 'is_checked' => $isChecked, - 'export_type' => $exportType, - ]); - } - - /** - * Prints Html For Export Options - * - * @param string $exportType Selected Export Type - * - * @return string - */ - private function getHtmlForOptionsOutput($exportType) - { - global $cfg; - - $hasAliases = isset($_SESSION['tmpval']['aliases']) - && ! Core::emptyRecursive($_SESSION['tmpval']['aliases']); - unset($_SESSION['tmpval']['aliases']); - - $isCheckedLockTables = $this->checkboxCheck('lock_tables'); - $isCheckedAsfile = $this->checkboxCheck('asfile'); - - $optionsOutputSaveDir = ''; - if (isset($cfg['SaveDir']) && ! empty($cfg['SaveDir'])) { - $optionsOutputSaveDir = $this->getHtmlForOptionsOutputSaveDir(); - } - $optionsOutputFormat = $this->getHtmlForOptionsOutputFormat($exportType); - $optionsOutputCharset = ''; - if (Encoding::isSupported()) { - $optionsOutputCharset = $this->getHtmlForOptionsOutputCharset(); - } - $optionsOutputCompression = $this->getHtmlForOptionsOutputCompression(); - $optionsOutputSeparateFiles = ''; - if ($exportType == 'server' || $exportType == 'database') { - $optionsOutputSeparateFiles = $this->getHtmlForOptionsOutputSeparateFiles( - $exportType - ); - } - $optionsOutputRadio = $this->getHtmlForOptionsOutputRadio(); - - return $this->template->render('display/export/options_output', [ - 'has_aliases' => $hasAliases, - 'export_type' => $exportType, - 'is_checked_lock_tables' => $isCheckedLockTables, - 'is_checked_asfile' => $isCheckedAsfile, - 'repopulate' => isset($_POST['repopulate']), - 'lock_tables' => isset($_POST['lock_tables']), - 'save_dir' => isset($cfg['SaveDir']) ? $cfg['SaveDir'] : null, - 'is_encoding_supported' => Encoding::isSupported(), - 'options_output_save_dir' => $optionsOutputSaveDir, - 'options_output_format' => $optionsOutputFormat, - 'options_output_charset' => $optionsOutputCharset, - 'options_output_compression' => $optionsOutputCompression, - 'options_output_separate_files' => $optionsOutputSeparateFiles, - 'options_output_radio' => $optionsOutputRadio, - ]); - } - - /** - * Prints Html For Export Options - * - * @param string $exportType Selected Export Type - * @param string $db Selected DB - * @param string $table Selected Table - * @param string $multiValues Export selection - * @param string $numTables number of tables - * @param ExportPlugin[] $exportList Export List - * @param string $unlimNumRows Number of Rows - * - * @return string - */ - public function getHtmlForOptions( - $exportType, - $db, - $table, - $multiValues, - $numTables, - $exportList, - $unlimNumRows - ) { - global $cfg; - $html = $this->getHtmlForOptionsMethod(); - $html .= $this->getHtmlForOptionsFormatDropdown($exportList); - $html .= $this->getHtmlForOptionsSelection($exportType, $multiValues); - - $tableObject = new Table($table, $db); - if (strlen($table) > 0 && empty($numTables) && ! $tableObject->isMerge()) { - $html .= $this->getHtmlForOptionsRows($db, $table, $unlimNumRows); - } - - if (isset($cfg['SaveDir']) && ! empty($cfg['SaveDir'])) { - $html .= $this->getHtmlForOptionsQuickExport(); - } - - $html .= $this->getHtmlForAliasModalDialog(); - $html .= $this->getHtmlForOptionsOutput($exportType); - $html .= $this->getHtmlForOptionsFormat($exportList); - return $html; - } - - /** - * Generate Html For currently defined aliases - * - * @return string - * @throws Throwable - * @throws Twig_Error_Loader - * @throws Twig_Error_Runtime - * @throws Twig_Error_Syntax - */ - private function getHtmlForCurrentAlias() - { - $result = ''; - - $template = $this->template->load('export/alias_item'); - if (isset($_SESSION['tmpval']['aliases'])) { - foreach ($_SESSION['tmpval']['aliases'] as $db => $dbData) { - if (isset($dbData['alias'])) { - $result .= $template->render([ - 'type' => _pgettext('Alias', 'Database'), - 'name' => $db, - 'field' => 'aliases[' . $db . '][alias]', - 'value' => $dbData['alias'], - ]); - } - if (! isset($dbData['tables'])) { - continue; - } - foreach ($dbData['tables'] as $table => $tableData) { - if (isset($tableData['alias'])) { - $result .= $template->render([ - 'type' => _pgettext('Alias', 'Table'), - 'name' => $db . '.' . $table, - 'field' => 'aliases[' . $db . '][tables][' . $table . '][alias]', - 'value' => $tableData['alias'], - ]); - } - if (! isset($tableData['columns'])) { - continue; - } - foreach ($tableData['columns'] as $column => $columnName) { - $result .= $template->render([ - 'type' => _pgettext('Alias', 'Column'), - 'name' => $db . '.' . $table . '.' . $column, - 'field' => 'aliases[' . $db . '][tables][' . $table . '][colums][' . $column . ']', - 'value' => $columnName, - ]); - } - } - } - } - - // Empty row for javascript manipulations - $result .= '' . $template->render([ - 'type' => '', - 'name' => '', - 'field' => 'aliases_new', - 'value' => '', - ]) . ''; - - return $result . '
' - . __('Defined aliases') - . '
'; - } - - /** - * Generate Html For Alias Modal Dialog - * - * @return string - */ - public function getHtmlForAliasModalDialog() - { - $title = __('Rename exported databases/tables/columns'); - - $html = '
'; - $html .= $this->getHtmlForCurrentAlias(); - $html .= $this->template->render('export/alias_add'); - - $html .= '
'; - return $html; - } - - /** - * Gets HTML to display export dialogs - * - * @param string $exportType export type: server|database|table - * @param string $db selected DB - * @param string $table selected table - * @param string $sqlQuery SQL query - * @param int $numTables number of tables - * @param int $unlimNumRows unlimited number of rows - * @param string $multiValues selector options - * - * @return string - */ - public function getDisplay( - $exportType, - $db, - $table, - $sqlQuery, - $numTables, - $unlimNumRows, - $multiValues - ) { - $cfgRelation = $this->relation->getRelationsParam(); - - if (isset($_POST['single_table'])) { - $GLOBALS['single_table'] = $_POST['single_table']; - } - - // Export a single table - if (isset($_GET['single_table'])) { - $GLOBALS['single_table'] = $_GET['single_table']; - } - - /* Scan for plugins */ - /** @var ExportPlugin[] $exportList */ - $exportList = Plugins::getPlugins( - "export", - 'libraries/classes/Plugins/Export/', - [ - 'export_type' => $exportType, - 'single_table' => isset($GLOBALS['single_table']), - ] - ); - - /* Fail if we didn't find any plugin */ - if (empty($exportList)) { - Message::error( - __('Could not load export plugins, please check your installation!') - )->display(); - exit; - } - - $html = $this->template->render('display/export/option_header', [ - 'export_type' => $exportType, - 'db' => $db, - 'table' => $table, - ]); - - if ($cfgRelation['exporttemplateswork']) { - $html .= $this->template->render('display/export/template_loading', [ - 'options' => $this->getOptionsForTemplates($exportType), - ]); - } - - $html .= '
'; - - //output Hidden Inputs - $singleTableStr = isset($GLOBALS['single_table']) ? $GLOBALS['single_table'] - : ''; - $html .= $this->getHtmlForHiddenInputs( - $exportType, - $db, - $table, - $singleTableStr, - $sqlQuery - ); - - //output Export Options - $html .= $this->getHtmlForOptions( - $exportType, - $db, - $table, - $multiValues, - $numTables, - $exportList, - $unlimNumRows - ); - - $html .= '
'; - return $html; - } - - /** - * Handles export template actions - * - * @param array $cfgRelation Relation configuration - * - * @return void - */ - public function handleTemplateActions(array $cfgRelation) - { - if (isset($_POST['templateId'])) { - $id = $GLOBALS['dbi']->escapeString($_POST['templateId']); - } else { - $id = ''; - } - - $templateTable = Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['export_templates']); - $user = $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['user']); - - switch ($_POST['templateAction']) { - case 'create': - $query = "INSERT INTO " . $templateTable . "(" - . " `username`, `export_type`," - . " `template_name`, `template_data`" - . ") VALUES (" - . "'" . $user . "', " - . "'" . $GLOBALS['dbi']->escapeString($_POST['exportType']) - . "', '" . $GLOBALS['dbi']->escapeString($_POST['templateName']) - . "', '" . $GLOBALS['dbi']->escapeString($_POST['templateData']) - . "');"; - break; - case 'load': - $query = "SELECT `template_data` FROM " . $templateTable - . " WHERE `id` = " . $id . " AND `username` = '" . $user . "'"; - break; - case 'update': - $query = "UPDATE " . $templateTable . " SET `template_data` = " - . "'" . $GLOBALS['dbi']->escapeString($_POST['templateData']) . "'" - . " WHERE `id` = " . $id . " AND `username` = '" . $user . "'"; - break; - case 'delete': - $query = "DELETE FROM " . $templateTable - . " WHERE `id` = " . $id . " AND `username` = '" . $user . "'"; - break; - default: - $query = ''; - break; - } - - $result = $this->relation->queryAsControlUser($query, false); - - $response = Response::getInstance(); - if (! $result) { - $error = $GLOBALS['dbi']->getError(DatabaseInterface::CONNECT_CONTROL); - $response->setRequestStatus(false); - $response->addJSON('message', $error); - exit; - } - - $response->setRequestStatus(true); - if ('create' == $_POST['templateAction']) { - $response->addJSON( - 'data', - $this->getOptionsForTemplates($_POST['exportType']) - ); - } elseif ('load' == $_POST['templateAction']) { - $data = null; - while ($row = $GLOBALS['dbi']->fetchAssoc( - $result, - DatabaseInterface::CONNECT_CONTROL - )) { - $data = $row['template_data']; - } - $response->addJSON('data', $data); - } - $GLOBALS['dbi']->freeResult($result); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Display/GitRevision.php b/srcs/phpmyadmin/libraries/classes/Display/GitRevision.php deleted file mode 100644 index 0a20f0e..0000000 --- a/srcs/phpmyadmin/libraries/classes/Display/GitRevision.php +++ /dev/null @@ -1,144 +0,0 @@ -response = $response; - $this->config = $config; - $this->template = $template; - } - - /** - * Returns details about the current Git commit revision - * - * @return string HTML - */ - public function display(): string - { - // load revision data from repo - $this->config->checkGitRevision(); - - if (! $this->config->get('PMA_VERSION_GIT')) { - $this->response->setRequestStatus(false); - return ''; - } - - // if using a remote commit fast-forwarded, link to GitHub - $commitHash = substr( - $this->config->get('PMA_VERSION_GIT_COMMITHASH'), - 0, - 7 - ); - $commitHash = '' . htmlspecialchars($commitHash) . ''; - if ($this->config->get('PMA_VERSION_GIT_ISREMOTECOMMIT')) { - $commitHash = '' . $commitHash . ''; - } - - $branch = $this->config->get('PMA_VERSION_GIT_BRANCH'); - $isRemoteBranch = $this->config->get('PMA_VERSION_GIT_ISREMOTEBRANCH'); - if ($isRemoteBranch) { - $branch = '' . htmlspecialchars($branch) . ''; - } - if ($branch !== false) { - $branch = sprintf( - __('%1$s from %2$s branch'), - $commitHash, - $isRemoteBranch ? $branch : htmlspecialchars($branch) - ); - } else { - $branch = $commitHash . ' (' . __('no branch') . ')'; - } - - $committer = $this->config->get('PMA_VERSION_GIT_COMMITTER'); - $author = $this->config->get('PMA_VERSION_GIT_AUTHOR'); - - $name = __('Git revision:') . ' ' - . $branch . ',
' - . sprintf( - __('committed on %1$s by %2$s'), - Util::localisedDate(strtotime($committer['date'])), - '' - . htmlspecialchars($committer['name']) . '' - ) - . ($author != $committer - ? ',
' - . sprintf( - __('authored on %1$s by %2$s'), - Util::localisedDate(strtotime($author['date'])), - '' - . htmlspecialchars($author['name']) . '' - ) - : ''); - - return $this->template->render('list/item', [ - 'content' => $name, - 'id' => 'li_pma_version_git', - 'class' => null, - 'url' => [ - 'href' => null, - 'target' => null, - 'id' => null, - 'class' => null, - ], - 'mysql_help_page' => null, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Display/Import.php b/srcs/phpmyadmin/libraries/classes/Display/Import.php deleted file mode 100644 index c9e543a..0000000 --- a/srcs/phpmyadmin/libraries/classes/Display/Import.php +++ /dev/null @@ -1,127 +0,0 @@ -display(); - exit; - } - - if (Core::isValid($_REQUEST['offset'], 'numeric')) { - $offset = intval($_REQUEST['offset']); - } - if (isset($_REQUEST['timeout_passed'])) { - $timeoutPassed = $_REQUEST['timeout_passed']; - } - - $localImportFile = ''; - if (isset($_REQUEST['local_import_file'])) { - $localImportFile = $_REQUEST['local_import_file']; - } - - // zip, gzip and bzip2 encode features - $compressions = []; - if ($cfg['GZipDump'] && function_exists('gzopen')) { - $compressions[] = 'gzip'; - } - if ($cfg['BZipDump'] && function_exists('bzopen')) { - $compressions[] = 'bzip2'; - } - if ($cfg['ZipDump'] && function_exists('zip_open')) { - $compressions[] = 'zip'; - } - - $allCharsets = Charsets::getCharsets($GLOBALS['dbi'], $cfg['Server']['DisableIS']); - $charsets = []; - /** @var Charset $charset */ - foreach ($allCharsets as $charset) { - $charsets[] = [ - 'name' => $charset->getName(), - 'description' => $charset->getDescription(), - ]; - } - - return $template->render('display/import/import', [ - 'upload_id' => $uploadId, - 'handler' => $_SESSION[$SESSION_KEY]["handler"], - 'id_key' => $_SESSION[$SESSION_KEY]['handler']::getIdKey(), - 'pma_theme_image' => $GLOBALS['pmaThemeImage'], - 'import_type' => $importType, - 'db' => $db, - 'table' => $table, - 'max_upload_size' => $maxUploadSize, - 'import_list' => $importList, - 'local_import_file' => $localImportFile, - 'is_upload' => $GLOBALS['is_upload'], - 'upload_dir' => isset($cfg['UploadDir']) ? $cfg['UploadDir'] : null, - 'timeout_passed_global' => isset($GLOBALS['timeout_passed']) ? $GLOBALS['timeout_passed'] : null, - 'compressions' => $compressions, - 'is_encoding_supported' => Encoding::isSupported(), - 'encodings' => Encoding::listEncodings(), - 'import_charset' => isset($cfg['Import']['charset']) ? $cfg['Import']['charset'] : null, - 'timeout_passed' => isset($timeoutPassed) ? $timeoutPassed : null, - 'offset' => isset($offset) ? $offset : null, - 'can_convert_kanji' => Encoding::canConvertKanji(), - 'charsets' => $charsets, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Display/ImportAjax.php b/srcs/phpmyadmin/libraries/classes/Display/ImportAjax.php deleted file mode 100644 index 97c87b9..0000000 --- a/srcs/phpmyadmin/libraries/classes/Display/ImportAjax.php +++ /dev/null @@ -1,140 +0,0 @@ - null, - - /** string Database name */ - 'db' => 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, - - /** boolean */ - 'is_browse_distinct' => null, - - /** array table definitions */ - 'showtable' => null, - - /** string */ - 'printview' => null, - - /** string URL query */ - 'url_query' => null, - - /** array column names to highlight */ - 'highlight_columns' => null, - - /** array holding various display information */ - 'display_params' => null, - - /** array mime types information of fields */ - 'mime_map' => null, - - /** boolean */ - 'editable' => null, - - /** random unique ID to distinguish result set */ - 'unique_id' => null, - - /** where clauses for each row, each table in the row */ - 'whereClauseMap' => [], - ]; - - /** - * This variable contains the column transformation information - * for some of the system databases. - * One element of this array represent all relevant columns in all tables in - * one specific database - */ - public $transformation_info; - - /** - * @var Relation - */ - private $relation; - - /** - * @var Transformations - */ - private $transformations; - - /** - * @var Template - */ - public $template; - - /** - * Constructor for PhpMyAdmin\Display\Results class - * - * @param string $db the database name - * @param string $table the table name - * @param int $server the server id - * @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, $server, $goto, $sql_query) - { - $this->relation = new Relation($GLOBALS['dbi']); - $this->transformations = new Transformations(); - $this->template = new Template(); - - $this->_setDefaultTransformations(); - - $this->__set('db', $db); - $this->__set('table', $table); - $this->__set('server', $server); - $this->__set('goto', $goto); - $this->__set('sql_query', $sql_query); - $this->__set('unique_id', mt_rand()); - } - - /** - * Get any property of this class - * - * @param string $property name of the property - * - * @return mixed|void if property exist, value of the relevant property - */ - public function __get($property) - { - return $this->_property_array[$property] ?? null; - } - - /** - * Set values for any property of this class - * - * @param string $property name of the property - * @param mixed $value value to set - * - * @return void - */ - public function __set($property, $value) - { - if (array_key_exists($property, $this->_property_array)) { - $this->_property_array[$property] = $value; - } - } - - /** - * Sets default transformations for some columns - * - * @return void - */ - private function _setDefaultTransformations() - { - $json_highlighting_data = [ - 'libraries/classes/Plugins/Transformations/Output/Text_Plain_Json.php', - Text_Plain_Json::class, - 'Text_Plain', - ]; - $sql_highlighting_data = [ - 'libraries/classes/Plugins/Transformations/Output/Text_Plain_Sql.php', - Text_Plain_Sql::class, - 'Text_Plain', - ]; - $blob_sql_highlighting_data = [ - 'libraries/classes/Plugins/Transformations/Output/Text_Octetstream_Sql.php', - Text_Octetstream_Sql::class, - 'Text_Octetstream', - ]; - $link_data = [ - 'libraries/classes/Plugins/Transformations/Text_Plain_Link.php', - Text_Plain_Link::class, - 'Text_Plain', - ]; - $this->transformation_info = [ - 'information_schema' => [ - 'events' => [ - 'event_definition' => $sql_highlighting_data, - ], - 'processlist' => [ - 'info' => $sql_highlighting_data, - ], - 'routines' => [ - 'routine_definition' => $sql_highlighting_data, - ], - 'triggers' => [ - 'action_statement' => $sql_highlighting_data, - ], - 'views' => [ - 'view_definition' => $sql_highlighting_data, - ], - ], - 'mysql' => [ - 'event' => [ - 'body' => $blob_sql_highlighting_data, - 'body_utf8' => $blob_sql_highlighting_data, - ], - 'general_log' => [ - 'argument' => $sql_highlighting_data, - ], - 'help_category' => [ - 'url' => $link_data, - ], - 'help_topic' => [ - 'example' => $sql_highlighting_data, - 'url' => $link_data, - ], - 'proc' => [ - 'param_list' => $blob_sql_highlighting_data, - 'returns' => $blob_sql_highlighting_data, - 'body' => $blob_sql_highlighting_data, - 'body_utf8' => $blob_sql_highlighting_data, - ], - 'slow_log' => [ - 'sql_text' => $sql_highlighting_data, - ], - ], - ]; - - $cfgRelation = $this->relation->getRelationsParam(); - if ($cfgRelation['db']) { - $this->transformation_info[$cfgRelation['db']] = []; - $relDb = &$this->transformation_info[$cfgRelation['db']]; - if (! empty($cfgRelation['history'])) { - $relDb[$cfgRelation['history']] = [ - 'sqlquery' => $sql_highlighting_data, - ]; - } - if (! empty($cfgRelation['bookmark'])) { - $relDb[$cfgRelation['bookmark']] = [ - 'query' => $sql_highlighting_data, - ]; - } - if (! empty($cfgRelation['tracking'])) { - $relDb[$cfgRelation['tracking']] = [ - 'schema_sql' => $sql_highlighting_data, - 'data_sql' => $sql_highlighting_data, - ]; - } - if (! empty($cfgRelation['favorite'])) { - $relDb[$cfgRelation['favorite']] = [ - 'tables' => $json_highlighting_data, - ]; - } - if (! empty($cfgRelation['recent'])) { - $relDb[$cfgRelation['recent']] = [ - 'tables' => $json_highlighting_data, - ]; - } - if (! empty($cfgRelation['savedsearches'])) { - $relDb[$cfgRelation['savedsearches']] = [ - 'search_data' => $json_highlighting_data, - ]; - } - if (! empty($cfgRelation['designer_settings'])) { - $relDb[$cfgRelation['designer_settings']] = [ - 'settings_data' => $json_highlighting_data, - ]; - } - if (! empty($cfgRelation['table_uiprefs'])) { - $relDb[$cfgRelation['table_uiprefs']] = [ - 'prefs' => $json_highlighting_data, - ]; - } - if (! empty($cfgRelation['userconfig'])) { - $relDb[$cfgRelation['userconfig']] = [ - 'config_data' => $json_highlighting_data, - ]; - } - if (! empty($cfgRelation['export_templates'])) { - $relDb[$cfgRelation['export_templates']] = [ - 'template_data' => $json_highlighting_data, - ]; - } - } - } - - /** - * Set properties which were not initialized at the constructor - * - * @param integer $unlim_num_rows the total number of rows returned by - * the SQL query without any appended - * "LIMIT" clause programmatically - * @param stdClass $fields_meta meta information about fields - * @param boolean $is_count statement is SELECT COUNT - * @param integer $is_export statement contains INTO OUTFILE - * @param boolean $is_func statement contains a function like SUM() - * @param integer $is_analyse statement contains PROCEDURE ANALYSE - * @param integer $num_rows total no. of rows returned by SQL query - * @param integer $fields_cnt total no.of fields returned by SQL query - * @param double $querytime time taken for execute the SQL query - * @param string $pmaThemeImage path for theme images directory - * @param string $text_dir text direction - * @param boolean $is_maint statement contains a maintenance command - * @param boolean $is_explain statement contains EXPLAIN - * @param boolean $is_show statement contains SHOW - * @param array $showtable table definitions - * @param string $printview print view was requested - * @param string $url_query URL query - * @param boolean $editable whether the results set is editable - * @param boolean $is_browse_dist whether browsing distinct values - * - * @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, - $is_browse_dist - ) { - - $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); - $this->__set('is_browse_distinct', $is_browse_dist); - } - - /** - * Defines the parts to display for a print view - * - * @param array $displayParts the parts to display - * - * @return array the modified display parts - * - * @access private - * - */ - private function _setDisplayPartsForPrintView(array $displayParts) - { - // set all elements to false! - $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link - $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link - $displayParts['sort_lnk'] = (string) '0'; - $displayParts['nav_bar'] = (string) '0'; - $displayParts['bkm_form'] = (string) '0'; - $displayParts['text_btn'] = (string) '0'; - $displayParts['pview_lnk'] = (string) '0'; - - return $displayParts; - } - - /** - * Defines the parts to display for a SHOW statement - * - * @param array $displayParts the parts to display - * - * @return array the modified display parts - * - * @access private - * - */ - private function _setDisplayPartsForShow(array $displayParts) - { - preg_match( - '@^SHOW[[:space:]]+(VARIABLES|(FULL[[:space:]]+)?' - . 'PROCESSLIST|STATUS|TABLE|GRANTS|CREATE|LOGS|DATABASES|FIELDS' - . ')@i', - $this->__get('sql_query'), - $which - ); - - $bIsProcessList = isset($which[1]); - if ($bIsProcessList) { - $str = ' ' . strtoupper($which[1]); - $bIsProcessList = $bIsProcessList - && strpos($str, 'PROCESSLIST') > 0; - } - - if ($bIsProcessList) { - // no edit link - $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; - // "kill process" type edit link - $displayParts['del_lnk'] = self::KILL_PROCESS; - } else { - // Default case -> no links - // no edit link - $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; - // no delete link - $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; - } - // Other settings - $displayParts['sort_lnk'] = (string) '0'; - $displayParts['nav_bar'] = (string) '0'; - $displayParts['bkm_form'] = (string) '1'; - $displayParts['text_btn'] = (string) '1'; - $displayParts['pview_lnk'] = (string) '1'; - - return $displayParts; - } - - /** - * Defines the parts to display for statements not related to data - * - * @param array $displayParts the parts to display - * - * @return array the modified display parts - * - * @access private - * - */ - private function _setDisplayPartsForNonData(array $displayParts) - { - // Statement is a "SELECT COUNT", a - // "CHECK/ANALYZE/REPAIR/OPTIMIZE/CHECKSUM", an "EXPLAIN" one or - // contains a "PROC ANALYSE" part - $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link - $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link - $displayParts['sort_lnk'] = (string) '0'; - $displayParts['nav_bar'] = (string) '0'; - $displayParts['bkm_form'] = (string) '1'; - - if ($this->__get('is_maint')) { - $displayParts['text_btn'] = (string) '1'; - } else { - $displayParts['text_btn'] = (string) '0'; - } - $displayParts['pview_lnk'] = (string) '1'; - - return $displayParts; - } - - /** - * Defines the parts to display for other statements (probably SELECT) - * - * @param array $displayParts the parts to display - * - * @return array the modified display parts - * - * @access private - * - */ - private function _setDisplayPartsForSelect(array $displayParts) - { - // Other statements (ie "SELECT" ones) -> updates - // $displayParts['edit_lnk'], $displayParts['del_lnk'] and - // $displayParts['text_btn'] (keeps other default values) - - $fields_meta = $this->__get('fields_meta'); - $prev_table = ''; - $displayParts['text_btn'] = (string) '1'; - $number_of_columns = $this->__get('fields_cnt'); - - for ($i = 0; $i < $number_of_columns; $i++) { - $is_link = ($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) - || ($displayParts['sort_lnk'] != '0'); - - // Displays edit/delete/sort/insert links? - if ($is_link - && $prev_table != '' - && $fields_meta[$i]->table != '' - && $fields_meta[$i]->table != $prev_table - ) { - // don't display links - $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; - $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; - /** - * @todo May be problematic with same field names - * in two joined table. - */ - // $displayParts['sort_lnk'] = (string) '0'; - if ($displayParts['text_btn'] == '1') { - break; - } - } // end if - - // Always display print view link - $displayParts['pview_lnk'] = (string) '1'; - if ($fields_meta[$i]->table != '') { - $prev_table = $fields_meta[$i]->table; - } - } // end for - - if ($prev_table == '') { // no table for any of the columns - // don't display links - $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; - $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; - } - - return $displayParts; - } - - /** - * Defines the parts to display for the results of a SQL query - * and the total number of rows - * - * @param array $displayParts the parts to display (see a few - * lines above for explanations) - * - * @return array the first element is an array with explicit indexes - * for all the display elements - * the second element is 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, - * else computed inside this function) - * - * - * @access private - * - * @see getTable() - */ - private function _setDisplayPartsAndTotal(array $displayParts) - { - $the_total = 0; - - // 1. 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'); - $num_rows = $this->__get('num_rows'); - $printview = $this->__get('printview'); - - // 2. Updates the display parts - if ($printview == '1') { - $displayParts = $this->_setDisplayPartsForPrintView($displayParts); - } elseif ($this->__get('is_count') || $this->__get('is_analyse') - || $this->__get('is_maint') || $this->__get('is_explain') - ) { - $displayParts = $this->_setDisplayPartsForNonData($displayParts); - } elseif ($this->__get('is_show')) { - $displayParts = $this->_setDisplayPartsForShow($displayParts); - } else { - $displayParts = $this->_setDisplayPartsForSelect($displayParts); - } // end if..elseif...else - - // 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 (($displayParts['nav_bar'] == '1') - || ($displayParts['sort_lnk'] == '1') - && (strlen($db) > 0 && strlen($table) > 0) - ) { - $the_total = $GLOBALS['dbi']->getTable($db, $table)->countRecords(); - } - - // if for COUNT query, number of rows returned more than 1 - // (may be being used GROUP BY) - if ($this->__get('is_count') && isset($num_rows) && $num_rows > 1) { - $displayParts['nav_bar'] = (string) '1'; - $displayParts['sort_lnk'] = (string) '1'; - } - // 4. If navigation bar or sorting fields names URLs should be - // displayed but there is only one row, change these settings to - // false - if ($displayParts['nav_bar'] == '1' || $displayParts['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. - $_table = new Table($table, $db); - if (isset($unlim_num_rows) - && ($unlim_num_rows < 2) - && ! $_table->isView() - ) { - $displayParts['sort_lnk'] = (string) '0'; - } - } // end if (3) - - return [ - $displayParts, - $the_total, - ]; - } - - /** - * Return true if we are executing a query in the form of - * "SELECT * FROM ..." - * - * @param array $analyzed_sql_results analyzed sql results - * - * @return boolean - * - * @access private - * - * @see _getTableHeaders(), _getColumnParams() - */ - private function _isSelect(array $analyzed_sql_results) - { - return ! ($this->__get('is_count') - || $this->__get('is_export') - || $this->__get('is_func') - || $this->__get('is_analyse')) - && ! empty($analyzed_sql_results['select_from']) - && ! empty($analyzed_sql_results['statement']->from) - && (count($analyzed_sql_results['statement']->from) === 1) - && ! empty($analyzed_sql_results['statement']->from[0]->table); - } - - /** - * 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 boolean $back whether 'begin' or 'previous' - * @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, - $back, - $onsubmit = '', - $input_for_real_end = '', - $onclick = '' - ) { - $caption_output = ''; - if ($back) { - if (Util::showIcons('TableNavigationLinksMode')) { - $caption_output .= $caption; - } - if (Util::showText('TableNavigationLinksMode')) { - $caption_output .= ' ' . $title; - } - } else { - if (Util::showText('TableNavigationLinksMode')) { - $caption_output .= $title; - } - if (Util::showIcons('TableNavigationLinksMode')) { - $caption_output .= ' ' . $caption; - } - } - - return $this->template->render('display/results/table_navigation_button', [ - 'db' => $this->__get('db'), - 'table' => $this->__get('table'), - 'sql_query' => $html_sql_query, - 'pos' => $pos, - 'is_browse_distinct' => $this->__get('is_browse_distinct'), - 'goto' => $this->__get('goto'), - 'input_for_real_end' => $input_for_real_end, - 'caption_output' => $caption_output, - 'title' => $title, - 'onsubmit' => $onsubmit, - 'onclick' => $onclick, - ]); - } - - /** - * Possibly return a page selector for table navigation - * - * @return array ($output, $nbTotalPage) - * - * @access private - */ - private function _getHtmlPageSelector(): array - { - $pageNow = @floor( - $_SESSION['tmpval']['pos'] - / $_SESSION['tmpval']['max_rows'] - ) + 1; - - $nbTotalPage = @ceil( - $this->__get('unlim_num_rows') - / $_SESSION['tmpval']['max_rows'] - ); - - $output = ''; - if ($nbTotalPage > 1) { - $_url_params = [ - 'db' => $this->__get('db'), - 'table' => $this->__get('table'), - 'sql_query' => $this->__get('sql_query'), - 'goto' => $this->__get('goto'), - 'is_browse_distinct' => $this->__get('is_browse_distinct'), - ]; - - $output = $this->template->render('display/results/page_selector', [ - 'url_params' => $_url_params, - 'page_selector' => Util::pageselector( - 'pos', - $_SESSION['tmpval']['max_rows'], - $pageNow, - $nbTotalPage, - 200, - 5, - 5, - 20, - 10 - ), - ]); - } - return [ - $output, - $nbTotalPage, - ]; - } - - /** - * Get a navigation bar to browse among the results of a SQL query - * - * @param integer $posNext the offset for the "next" page - * @param integer $posPrevious the offset for the "previous" page - * @param boolean $isInnodb whether its InnoDB or not - * @param string $sortByKeyHtml the sort by key dialog - * - * @return string html content - * - * @access private - * - * @see getTable() - */ - private function _getTableNavigation( - $posNext, - $posPrevious, - $isInnodb, - $sortByKeyHtml - ): string { - $isShowingAll = $_SESSION['tmpval']['max_rows'] === self::ALL_ROWS; - - // Move to the beginning or to the previous page - $moveBackwardButtons = ''; - if ($_SESSION['tmpval']['pos'] && ! $isShowingAll) { - $moveBackwardButtons = $this->_getMoveBackwardButtonsForTableNavigation( - htmlspecialchars($this->__get('sql_query')), - $posPrevious - ); - } - - $pageSelector = ''; - $numberTotalPage = 1; - if (! $isShowingAll) { - list( - $pageSelector, - $numberTotalPage - ) = $this->_getHtmlPageSelector(); - } - - // Move to the next page or to the last one - $moveForwardButtons = ''; - if ($this->__get('unlim_num_rows') === false // view with unknown number of rows - || (! $isShowingAll - && $_SESSION['tmpval']['pos'] + $_SESSION['tmpval']['max_rows'] < $this->__get('unlim_num_rows') - && $this->__get('num_rows') >= $_SESSION['tmpval']['max_rows']) - ) { - $moveForwardButtons = $this->_getMoveForwardButtonsForTableNavigation( - htmlspecialchars($this->__get('sql_query')), - $posNext, - $isInnodb - ); - } - - $hiddenFields = [ - 'db' => $this->__get('db'), - 'table' => $this->__get('table'), - 'server' => $this->__get('server'), - 'sql_query' => $this->__get('sql_query'), - 'is_browse_distinct' => $this->__get('is_browse_distinct'), - 'goto' => $this->__get('goto'), - ]; - - return $this->template->render('display/results/table_navigation', [ - 'move_backward_buttons' => $moveBackwardButtons, - 'page_selector' => $pageSelector, - 'move_forward_buttons' => $moveForwardButtons, - 'number_total_page' => $numberTotalPage, - 'has_show_all' => $GLOBALS['cfg']['ShowAll'] || ($this->__get('unlim_num_rows') <= 500), - 'hidden_fields' => $hiddenFields, - 'session_max_rows' => $isShowingAll ? $GLOBALS['cfg']['MaxRows'] : 'all', - 'unique_id' => $this->__get('unique_id'), - 'is_showing_all' => $isShowingAll, - 'unlim_num_rows' => $this->__get('unlim_num_rows'), - 'max_rows' => $_SESSION['tmpval']['max_rows'], - 'pos' => $_SESSION['tmpval']['pos'], - 'sort_by_key' => $sortByKeyHtml, - ]); - } - - /** - * 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, - true - ) - . $this->_getTableNavigationButton( - '<', - _pgettext('Previous page', 'Previous'), - $pos_prev, - $html_sql_query, - true - ); - } - - /** - * Prepare move forward buttons - next and last - * - * @param string $html_sql_query the sql encoded by htmlspecialchars() - * @param integer $pos_next the offset for the "next" page - * @param boolean $is_innodb whether it's InnoDB or not - * - * @return string 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, - false - ); - - // 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 = ''; - } - - $maxRows = $_SESSION['tmpval']['max_rows']; - $onsubmit = 'onsubmit="return ' - . ($_SESSION['tmpval']['pos'] - + $maxRows - < $this->__get('unlim_num_rows') - && $this->__get('num_rows') >= $maxRows - ? 'true' - : 'false') . '"'; - - // display the End button - $buttons_html .= $this->_getTableNavigationButton( - '>>', - _pgettext('Last page', 'End'), - @((ceil( - $this->__get('unlim_num_rows') - / $_SESSION['tmpval']['max_rows'] - ) - 1) * $maxRows), - $html_sql_query, - false, - $onsubmit, - $input_for_real_end, - $onclick - ); - - return $buttons_html; - } - - /** - * Get the headers of the results table, for all of the columns - * - * @param array $displayParts which elements to display - * @param array $analyzed_sql_results analyzed sql results - * @param array $sort_expression sort expression - * @param array $sort_expression_nodirection sort expression - * without direction - * @param array $sort_direction sort direction - * @param boolean $is_limited_display with limited operations - * or not - * @param string $unsorted_sql_query query without the sort part - * - * @return string html content - * - * @access private - * - * @see getTableHeaders() - */ - private function _getTableHeadersForColumns( - array $displayParts, - array $analyzed_sql_results, - array $sort_expression, - array $sort_expression_nodirection, - array $sort_direction, - $is_limited_display, - $unsorted_sql_query - ) { - $html = ''; - - // 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['tmpval']['query'][$sql_md5]['max_rows']; - - // Following variable are needed for use in isset/empty or - // use with array indexes/safe use in the for loop - $highlight_columns = $this->__get('highlight_columns'); - $fields_meta = $this->__get('fields_meta'); - - // Prepare Display column comments if enabled - // ($GLOBALS['cfg']['ShowBrowseComments']). - $comments_map = $this->_getTableCommentsArray($analyzed_sql_results); - - list($col_order, $col_visib) = $this->_getColumnParams( - $analyzed_sql_results - ); - - // optimize: avoid calling a method on each iteration - $number_of_columns = $this->__get('fields_cnt'); - - for ($j = 0; $j < $number_of_columns; $j++) { - // PHP 7.4 fix for accessing array offset on bool - $col_visib_current = is_array($col_visib) && isset($col_visib[$j]) ? $col_visib[$j] : null; - - // assign $i with the 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. - $name = $fields_meta[$i]->name; - $condition_field = isset($highlight_columns[$name]) - || isset($highlight_columns[Util::backquote($name)]) - ? true - : false; - - // Prepare comment-HTML-wrappers for each row, if defined/enabled. - $comments = $this->_getCommentForRow($comments_map, $fields_meta[$i]); - $display_params = $this->__get('display_params'); - - if (($displayParts['sort_lnk'] == '1') && ! $is_limited_display) { - list($order_link, $sorted_header_html) - = $this->_getOrderLinkAndSortedHeaderHtml( - $fields_meta[$i], - $sort_expression, - $sort_expression_nodirection, - $i, - $unsorted_sql_query, - $session_max_rows, - $comments, - $sort_direction, - $col_visib, - $col_visib_current - ); - - $html .= $sorted_header_html; - - $display_params['desc'][] = ' ' . "\n" . $order_link . $comments . ' ' . "\n"; - } else { - // Results can't be sorted - $html - .= $this->_getDraggableClassForNonSortableColumns( - $col_visib, - $col_visib_current, - $condition_field, - $fields_meta[$i], - $comments - ); - - $display_params['desc'][] = ' ' - . htmlspecialchars((string) $fields_meta[$i]->name) - . $comments . ' '; - } // end else - - $this->__set('display_params', $display_params); - } // end for - return $html; - } - - /** - * Get the headers of the results table - * - * @param array $displayParts which elements to display - * @param array $analyzedSqlResults analyzed sql results - * @param string $unsortedSqlQuery the unsorted sql query - * @param array $sortExpression sort expression - * @param array|string $sortExpressionNoDirection sort expression without direction - * @param array $sortDirection sort direction - * @param boolean $isLimitedDisplay with limited operations or not - * - * @return string html content - * - * @access private - * - * @see getTable() - */ - private function _getTableHeaders( - array &$displayParts, - array $analyzedSqlResults, - $unsortedSqlQuery, - array $sortExpression = [], - $sortExpressionNoDirection = '', - array $sortDirection = [], - $isLimitedDisplay = false - ): string { - // Needed for use in isset/empty or - // use with array indexes/safe use in foreach - $printView = $this->__get('printview'); - $displayParams = $this->__get('display_params'); - - // Output data needed for column reordering and show/hide column - $dataForResettingColumnOrder = $this->_getDataForResettingColumnOrder($analyzedSqlResults); - - $displayParams['emptypre'] = 0; - $displayParams['emptyafter'] = 0; - $displayParams['textbtn'] = ''; - $fullOrPartialTextLink = ''; - - $this->__set('display_params', $displayParams); - - // Display options (if we are not in print view) - $optionsBlock = ''; - if (! (isset($printView) && ($printView == '1')) && ! $isLimitedDisplay) { - $optionsBlock = $this->_getOptionsBlock(); - - // prepare full/partial text button or link - $fullOrPartialTextLink = $this->_getFullOrPartialTextButtonOrLink(); - } - - // 1. Set $colspan and generate html with full/partial - // text button or link - list($colspan, $buttonHtml) = $this->_getFieldVisibilityParams( - $displayParts, - $fullOrPartialTextLink - ); - - // 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) - - // See if we have to highlight any header fields of a WHERE query. - // Uses SQL-Parser results. - $this->_setHighlightedColumnGlobalField($analyzedSqlResults); - - // Get the headers for all of the columns - $tableHeadersForColumns = $this->_getTableHeadersForColumns( - $displayParts, - $analyzedSqlResults, - $sortExpression, - $sortExpressionNoDirection, - $sortDirection, - $isLimitedDisplay, - $unsortedSqlQuery - ); - - // Display column at rightside - checkboxes or empty column - $columnAtRightSide = ''; - if (! $printView) { - $columnAtRightSide = $this->_getColumnAtRightSide( - $displayParts, - $fullOrPartialTextLink, - $colspan - ); - } - - return $this->template->render('display/results/table_headers', [ - 'db' => $this->__get('db'), - 'table' => $this->__get('table'), - 'unique_id' => $this->__get('unique_id'), - 'save_cells_at_once' => $GLOBALS['cfg']['SaveCellsAtOnce'], - 'data_for_resetting_column_order' => $dataForResettingColumnOrder, - 'options_block' => $optionsBlock, - 'delete_link' => $displayParts['del_lnk'], - 'delete_row' => self::DELETE_ROW, - 'kill_process' => self::KILL_PROCESS, - 'button' => $buttonHtml, - 'table_headers_for_columns' => $tableHeadersForColumns, - 'column_at_right_side' => $columnAtRightSide, - ]); - } - - /** - * Prepare unsorted sql query and sort by key drop down - * - * @param array $analyzed_sql_results analyzed sql results - * @param array|null $sort_expression sort expression - * - * @return array two element array - $unsorted_sql_query, $drop_down_html - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getUnsortedSqlAndSortByKeyDropDown( - array $analyzed_sql_results, - ?array $sort_expression - ) { - $drop_down_html = ''; - - $unsorted_sql_query = Query::replaceClause( - $analyzed_sql_results['statement'], - $analyzed_sql_results['parser']->list, - 'ORDER BY', - '' - ); - - // Data is sorted by indexes only if it there is only one table. - if ($this->_isSelect($analyzed_sql_results)) { - // grab indexes data: - $indexes = Index::getFromTable( - $this->__get('table'), - $this->__get('db') - ); - - // do we have any index? - if (! empty($indexes)) { - $drop_down_html = $this->_getSortByKeyDropDown( - $indexes, - $sort_expression, - $unsorted_sql_query - ); - } - } - - return [ - $unsorted_sql_query, - $drop_down_html, - ]; - } - - /** - * Prepare sort by key dropdown - html code segment - * - * @param Index[] $indexes the indexes of the table for sort criteria - * @param array|null $sortExpression the sort expression - * @param string $unsortedSqlQuery the unsorted sql query - * - * @return string html content - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getSortByKeyDropDown( - $indexes, - ?array $sortExpression, - $unsortedSqlQuery - ): string { - $hiddenFields = [ - 'db' => $this->__get('db'), - 'table' => $this->__get('table'), - 'server' => $this->__get('server'), - 'sort_by_key' => '1', - ]; - - $isIndexUsed = false; - $localOrder = is_array($sortExpression) ? implode(', ', $sortExpression) : ''; - - $options = []; - foreach ($indexes as $index) { - $ascSort = '`' - . implode('` ASC, `', array_keys($index->getColumns())) - . '` ASC'; - - $descSort = '`' - . implode('` DESC, `', array_keys($index->getColumns())) - . '` DESC'; - - $isIndexUsed = $isIndexUsed - || $localOrder === $ascSort - || $localOrder === $descSort; - - $unsortedSqlQueryFirstPart = $unsortedSqlQuery; - $unsortedSqlQuerySecondPart = ''; - if (preg_match( - '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|' - . 'FOR UPDATE|LOCK IN SHARE MODE))@is', - $unsortedSqlQuery, - $myReg - )) { - $unsortedSqlQueryFirstPart = $myReg[1]; - $unsortedSqlQuerySecondPart = $myReg[2]; - } - - $options[] = [ - 'value' => $unsortedSqlQueryFirstPart . ' ORDER BY ' - . $ascSort . $unsortedSqlQuerySecondPart, - 'content' => $index->getName() . ' (ASC)', - 'is_selected' => $localOrder === $ascSort, - ]; - $options[] = [ - 'value' => $unsortedSqlQueryFirstPart . ' ORDER BY ' - . $descSort . $unsortedSqlQuerySecondPart, - 'content' => $index->getName() . ' (DESC)', - 'is_selected' => $localOrder === $descSort, - ]; - } - $options[] = [ - 'value' => $unsortedSqlQuery, - 'content' => __('None'), - 'is_selected' => ! $isIndexUsed, - ]; - - return $this->template->render('display/results/sort_by_key', [ - 'hidden_fields' => $hiddenFields, - 'options' => $options, - ]); - } - - /** - * Set column span, row span and prepare html with full/partial - * text button or link - * - * @param array $displayParts which elements to display - * @param string $full_or_partial_text_link full/partial link or text button - * - * @return array 2 element array - $colspan, $button_html - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getFieldVisibilityParams( - array &$displayParts, - $full_or_partial_text_link - ) { - - $button_html = ''; - $display_params = $this->__get('display_params'); - - // 1. Displays the full/partial text button (part 1)... - $button_html .= '' . "\n"; - - $emptyPreCondition = $displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE - && $displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE; - - $colspan = $emptyPreCondition ? ' colspan="4"' - : ''; - - $leftOrBoth = $GLOBALS['cfg']['RowActionLinks'] === self::POSITION_LEFT - || $GLOBALS['cfg']['RowActionLinks'] === self::POSITION_BOTH; - - // ... before the result table - if (($displayParts['edit_lnk'] == self::NO_EDIT_OR_DELETE) - && ($displayParts['del_lnk'] == self::NO_EDIT_OR_DELETE) - && ($displayParts['text_btn'] == '1') - ) { - $display_params['emptypre'] = $emptyPreCondition ? 4 : 0; - } elseif ($leftOrBoth && ($displayParts['text_btn'] == '1') - ) { - // ... at the left column of the result table header if possible - // and required - - $display_params['emptypre'] = $emptyPreCondition ? 4 : 0; - - $button_html .= '' . $full_or_partial_text_link . ''; - } elseif ($leftOrBoth - && (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) - ) { - // ... elseif no button, displays empty(ies) col(s) if required - - $display_params['emptypre'] = $emptyPreCondition ? 4 : 0; - - $button_html .= ''; - } elseif ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) { - // ... elseif display an empty column if the actions links are - // disabled to match the rest of the table - $button_html .= ''; - } - - $this->__set('display_params', $display_params); - - return [ - $colspan, - $button_html, - ]; - } - - /** - * Get table comments as array - * - * @param array $analyzed_sql_results analyzed sql results - * - * @return array table comments - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getTableCommentsArray(array $analyzed_sql_results) - { - if (! $GLOBALS['cfg']['ShowBrowseComments'] - || empty($analyzed_sql_results['statement']->from) - ) { - return []; - } - - $ret = []; - foreach ($analyzed_sql_results['statement']->from as $field) { - if (empty($field->table)) { - continue; - } - $ret[$field->table] = $this->relation->getComments( - empty($field->database) ? $this->__get('db') : $field->database, - $field->table - ); - } - - return $ret; - } - - /** - * Set global array for store highlighted header fields - * - * @param array $analyzed_sql_results analyzed sql results - * - * @return void - * - * @access private - * - * @see _getTableHeaders() - */ - private function _setHighlightedColumnGlobalField(array $analyzed_sql_results) - { - $highlight_columns = []; - - if (! empty($analyzed_sql_results['statement']->where)) { - foreach ($analyzed_sql_results['statement']->where as $expr) { - foreach ($expr->identifiers as $identifier) { - $highlight_columns[$identifier] = 'true'; - } - } - } - - $this->__set('highlight_columns', $highlight_columns); - } - - /** - * Prepare data for column restoring and show/hide - * - * @param array $analyzedSqlResults analyzed sql results - * - * @return string html content - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getDataForResettingColumnOrder(array $analyzedSqlResults): string - { - if (! $this->_isSelect($analyzedSqlResults)) { - return ''; - } - - list($columnOrder, $columnVisibility) = $this->_getColumnParams( - $analyzedSqlResults - ); - - $tableCreateTime = ''; - $table = new Table($this->__get('table'), $this->__get('db')); - if (! $table->isView()) { - $tableCreateTime = $GLOBALS['dbi']->getTable( - $this->__get('db'), - $this->__get('table') - )->getStatusInfo('Create_time'); - } - - return $this->template->render('display/results/data_for_resetting_column_order', [ - 'column_order' => $columnOrder, - 'column_visibility' => $columnVisibility, - 'is_view' => $table->isView(), - 'table_create_time' => $tableCreateTime, - ]); - } - - /** - * Prepare option fields block - * - * @return string html content - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getOptionsBlock() - { - if (isset($_SESSION['tmpval']['possible_as_geometry']) && $_SESSION['tmpval']['possible_as_geometry'] == false) { - if ($_SESSION['tmpval']['geoOption'] == self::GEOMETRY_DISP_GEOM) { - $_SESSION['tmpval']['geoOption'] = self::GEOMETRY_DISP_WKT; - } - } - return $this->template->render('display/results/options_block', [ - 'unique_id' => $this->__get('unique_id'), - 'geo_option' => $_SESSION['tmpval']['geoOption'], - 'hide_transformation' => $_SESSION['tmpval']['hide_transformation'], - 'display_blob' => $_SESSION['tmpval']['display_blob'], - 'display_binary' => $_SESSION['tmpval']['display_binary'], - 'relational_display' => $_SESSION['tmpval']['relational_display'], - 'displaywork' => $GLOBALS['cfgRelation']['displaywork'], - 'relwork' => $GLOBALS['cfgRelation']['relwork'], - 'possible_as_geometry' => $_SESSION['tmpval']['possible_as_geometry'], - 'pftext' => $_SESSION['tmpval']['pftext'], - 'db' => $this->__get('db'), - 'table' => $this->__get('table'), - 'sql_query' => $this->__get('sql_query'), - 'goto' => $this->__get('goto'), - 'default_sliders_state' => $GLOBALS['cfg']['InitialSlidersState'], - ]); - } - - /** - * Get full/partial text button or link - * - * @return string html content - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getFullOrPartialTextButtonOrLink() - { - - $url_params_full_text = [ - 'db' => $this->__get('db'), - 'table' => $this->__get('table'), - 'sql_query' => $this->__get('sql_query'), - 'goto' => $this->__get('goto'), - 'full_text_button' => 1, - ]; - - if ($_SESSION['tmpval']['pftext'] == 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['pftext'] = self::DISPLAY_PARTIAL_TEXT; - } else { - $tmp_image_file = $this->__get('pma_theme_image') . 's_fulltext.png'; - $tmp_txt = __('Full texts'); - $url_params_full_text['pftext'] = self::DISPLAY_FULL_TEXT; - } - - $tmp_image = ''
-                     . $tmp_txt . ''; - $tmp_url = 'sql.php' . Url::getCommon($url_params_full_text); - - return Util::linkOrButton($tmp_url, $tmp_image); - } - - /** - * Get comment for row - * - * @param array $commentsMap comments array - * @param array $fieldsMeta set of field properties - * - * @return string html content - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getCommentForRow(array $commentsMap, $fieldsMeta) - { - return $this->template->render('display/results/comment_for_row', [ - 'comments_map' => $commentsMap, - 'fields_meta' => $fieldsMeta, - 'limit_chars' => $GLOBALS['cfg']['LimitChars'], - ]); - } - - /** - * Prepare parameters and html for sorted table header fields - * - * @param stdClass $fields_meta set of field properties - * @param array $sort_expression sort expression - * @param array $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 $comments comment for row - * @param array $sort_direction sort direction - * @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 - * - * @return array 2 element array - $order_link, $sorted_header_html - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getOrderLinkAndSortedHeaderHtml( - $fields_meta, - array $sort_expression, - array $sort_expression_nodirection, - $column_index, - $unsorted_sql_query, - $session_max_rows, - $comments, - array $sort_direction, - $col_visib, - $col_visib_j - ) { - - $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) > 0 - && $fields_meta->orgname == $fields_meta->name - ? Util::backquote( - $fields_meta->table - ) . '.' - : ''; - - $name_to_use_in_sort = $fields_meta->name; - - // Generates the orderby clause part of the query which is part - // of URL - list($single_sort_order, $multi_sort_order, $order_img) - = $this->_getSingleAndMultiSortUrls( - $sort_expression, - $sort_expression_nodirection, - $sort_tbl, - $name_to_use_in_sort, - $sort_direction, - $fields_meta - ); - - if (preg_match( - '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|FOR UPDATE|' - . 'LOCK IN SHARE MODE))@is', - $unsorted_sql_query, - $regs3 - )) { - $single_sorted_sql_query = $regs3[1] . $single_sort_order . $regs3[2]; - $multi_sorted_sql_query = $regs3[1] . $multi_sort_order . $regs3[2]; - } else { - $single_sorted_sql_query = $unsorted_sql_query . $single_sort_order; - $multi_sorted_sql_query = $unsorted_sql_query . $multi_sort_order; - } - - $_single_url_params = [ - 'db' => $this->__get('db'), - 'table' => $this->__get('table'), - 'sql_query' => $single_sorted_sql_query, - 'sql_signature' => Core::signSqlQuery($single_sorted_sql_query), - 'session_max_rows' => $session_max_rows, - 'is_browse_distinct' => $this->__get('is_browse_distinct'), - ]; - - $_multi_url_params = [ - 'db' => $this->__get('db'), - 'table' => $this->__get('table'), - 'sql_query' => $multi_sorted_sql_query, - 'sql_signature' => Core::signSqlQuery($multi_sorted_sql_query), - 'session_max_rows' => $session_max_rows, - 'is_browse_distinct' => $this->__get('is_browse_distinct'), - ]; - $single_order_url = 'sql.php' . Url::getCommon($_single_url_params); - $multi_order_url = 'sql.php' . Url::getCommon($_multi_url_params); - - // Displays the sorting URL - // enable sort order swapping for image - $order_link = $this->_getSortOrderLink( - $order_img, - $fields_meta, - $single_order_url, - $multi_order_url - ); - - $sorted_header_html .= $this->_getDraggableClassForSortableColumns( - $col_visib, - $col_visib_j, - $fields_meta, - $order_link, - $comments - ); - - return [ - $order_link, - $sorted_header_html, - ]; - } - - /** - * Prepare parameters and html for sorted table header fields - * - * @param array $sort_expression sort expression - * @param array $sort_expression_nodirection sort expression without direction - * @param string $sort_tbl The name of the table to which - * the current column belongs to - * @param string $name_to_use_in_sort The current column under - * consideration - * @param array $sort_direction sort direction - * @param stdClass $fields_meta set of field properties - * - * @return array 3 element array - $single_sort_order, $sort_order, $order_img - * - * @access private - * - * @see _getOrderLinkAndSortedHeaderHtml() - */ - private function _getSingleAndMultiSortUrls( - array $sort_expression, - array $sort_expression_nodirection, - $sort_tbl, - $name_to_use_in_sort, - array $sort_direction, - $fields_meta - ) { - $sort_order = ""; - // Check if the current column is in the order by clause - $is_in_sort = $this->_isInSorted( - $sort_expression, - $sort_expression_nodirection, - $sort_tbl, - $name_to_use_in_sort - ); - $current_name = $name_to_use_in_sort; - if ($sort_expression_nodirection[0] == '' || ! $is_in_sort) { - $special_index = $sort_expression_nodirection[0] == '' - ? 0 - : count($sort_expression_nodirection); - $sort_expression_nodirection[$special_index] - = Util::backquote( - $current_name - ); - $sort_direction[$special_index] = preg_match( - '@time|date@i', - $fields_meta->type - ) ? self::DESCENDING_SORT_DIR : self::ASCENDING_SORT_DIR; - } - - $sort_expression_nodirection = array_filter($sort_expression_nodirection); - $single_sort_order = null; - foreach ($sort_expression_nodirection as $index => $expression) { - // check if this is the first clause, - // if it is then we have to add "order by" - $is_first_clause = ($index == 0); - $name_to_use_in_sort = $expression; - $sort_tbl_new = $sort_tbl; - // Test to detect if the column name is a standard name - // Standard name has the table name prefixed to the column name - if (mb_strpos($name_to_use_in_sort, '.') !== false) { - $matches = explode('.', $name_to_use_in_sort); - // Matches[0] has the table name - // Matches[1] has the column name - $name_to_use_in_sort = $matches[1]; - $sort_tbl_new = $matches[0]; - } - - // $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); - $name_to_use_in_sort = trim($name_to_use_in_sort, '`'); - - // If this the first column name in the order by clause add - // order by clause to the column name - $query_head = $is_first_clause ? "\nORDER BY " : ""; - // Again a check to see if the given column is a aggregate column - if (mb_strpos($name_to_use_in_sort, '(') !== false) { - $sort_order .= $query_head . $name_to_use_in_sort . ' ' ; - } else { - if (strlen($sort_tbl_new) > 0) { - $sort_tbl_new .= "."; - } - $sort_order .= $query_head . $sort_tbl_new - . Util::backquote( - $name_to_use_in_sort - ) . ' ' ; - } - - // For a special case where the code generates two dots between - // column name and table name. - $sort_order = preg_replace("/\.\./", ".", $sort_order); - // Incase this is the current column save $single_sort_order - if ($current_name == $name_to_use_in_sort) { - if (mb_strpos($current_name, '(') !== false) { - $single_sort_order = "\n" . 'ORDER BY ' . Util::backquote($current_name) . ' '; - } else { - $single_sort_order = "\n" . 'ORDER BY ' . $sort_tbl - . Util::backquote( - $current_name - ) . ' '; - } - if ($is_in_sort) { - list($single_sort_order, $order_img) - = $this->_getSortingUrlParams( - $sort_direction, - $single_sort_order, - $index - ); - } else { - $single_sort_order .= strtoupper($sort_direction[$index]); - } - } - if ($current_name == $name_to_use_in_sort && $is_in_sort) { - // We need to generate the arrow button and related html - list($sort_order, $order_img) = $this->_getSortingUrlParams( - $sort_direction, - $sort_order, - $index - ); - $order_img .= " " . ($index + 1) . ""; - } else { - $sort_order .= strtoupper($sort_direction[$index]); - } - // Separate columns by a comma - $sort_order .= ", "; - } - // remove the comma from the last column name in the newly - // constructed clause - $sort_order = mb_substr( - $sort_order, - 0, - mb_strlen($sort_order) - 2 - ); - if (empty($order_img)) { - $order_img = ''; - } - return [ - $single_sort_order, - $sort_order, - $order_img, - ]; - } - - /** - * Check whether the column is sorted - * - * @param array $sort_expression sort expression - * @param array $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 the column sorted or not - * - * @access private - * - * @see _getTableHeaders() - */ - private function _isInSorted( - array $sort_expression, - array $sort_expression_nodirection, - $sort_tbl, - $name_to_use_in_sort - ) { - - $index_in_expression = 0; - - foreach ($sort_expression_nodirection as $index => $clause) { - if (mb_strpos($clause, '.') !== false) { - $fragments = explode('.', $clause); - $clause2 = $fragments[0] . "." . str_replace('`', '', $fragments[1]); - } else { - $clause2 = $sort_tbl . str_replace('`', '', $clause); - } - if ($clause2 === $sort_tbl . $name_to_use_in_sort) { - $index_in_expression = $index; - break; - } - } - if (empty($sort_expression[$index_in_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) - $noSortTable = empty($sort_tbl) || mb_strpos( - $sort_expression_nodirection[$index_in_expression], - $sort_tbl - ) === false; - $noOpenParenthesis = mb_strpos( - $sort_expression_nodirection[$index_in_expression], - '(' - ) === false; - if (! empty($sort_tbl) && $noSortTable && $noOpenParenthesis) { - $new_sort_expression_nodirection = $sort_tbl - . $sort_expression_nodirection[$index_in_expression]; - } else { - $new_sort_expression_nodirection - = $sort_expression_nodirection[$index_in_expression]; - } - - //Back quotes are removed in next comparison, so remove them from value - //to compare. - $name_to_use_in_sort = str_replace('`', '', $name_to_use_in_sort); - - $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[$index_in_expression]) - ) { - $is_in_sort = true; - } - } - - return $is_in_sort; - } - - /** - * Get sort url parameters - sort order and order image - * - * @param array $sort_direction the sort direction - * @param string $sort_order the sorting order - * @param integer $index the index of sort direction array. - * - * @return array 2 element array - $sort_order, $order_img - * - * @access private - * - * @see _getSingleAndMultiSortUrls() - */ - private function _getSortingUrlParams(array $sort_direction, $sort_order, $index) - { - if (strtoupper(trim($sort_direction[$index])) == self::DESCENDING_SORT_DIR) { - $sort_order .= ' ASC'; - $order_img = ' ' . Util::getImage( - 's_desc', - __('Descending'), - [ - 'class' => "soimg", - 'title' => '', - ] - ); - $order_img .= ' ' . Util::getImage( - 's_asc', - __('Ascending'), - [ - 'class' => "soimg hide", - 'title' => '', - ] - ); - } else { - $sort_order .= ' DESC'; - $order_img = ' ' . Util::getImage( - 's_asc', - __('Ascending'), - [ - 'class' => "soimg", - 'title' => '', - ] - ); - $order_img .= ' ' . Util::getImage( - 's_desc', - __('Descending'), - [ - 'class' => "soimg hide", - 'title' => '', - ] - ); - } - return [ - $sort_order, - $order_img, - ]; - } - - /** - * Get sort order link - * - * @param string $order_img the sort order image - * @param stdClass $fields_meta set of field properties - * @param string $order_url the url for sort - * @param string $multi_order_url the url for sort - * - * @return string the sort order link - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getSortOrderLink( - $order_img, - $fields_meta, - $order_url, - $multi_order_url - ) { - $order_link_params = [ - 'class' => 'sortlink', - ]; - - $order_link_content = htmlspecialchars($fields_meta->name); - $inner_link_content = $order_link_content . $order_img - . ''; - - return Util::linkOrButton( - $order_url, - $inner_link_content, - $order_link_params - ); - } - - /** - * Check if the column contains numeric data. If yes, then set the - * column header's alignment right - * - * @param stdClass $fields_meta set of field properties - * @param array $th_class array containing classes - * - * @return void - * - * @see _getDraggableClassForSortableColumns() - */ - private function _getClassForNumericColumnType($fields_meta, array &$th_class) - { - if (preg_match( - '@int|decimal|float|double|real|bit|boolean|serial@i', - (string) $fields_meta->type - )) { - $th_class[] = 'right'; - } - } - - /** - * 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 stdClass $fields_meta set of field properties - * @param string $order_link the order link - * @param string $comments the comment for the column - * - * @return string html content - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getDraggableClassForSortableColumns( - $col_visib, - $col_visib_j, - $fields_meta, - $order_link, - $comments - ) { - - $draggable_html = '_getClassForNumericColumnType($fields_meta, $th_class); - if ($col_visib && ! $col_visib_j) { - $th_class[] = 'hide'; - } - - $th_class[] = 'column_heading'; - if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) { - $th_class[] = 'pointer'; - } - - if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) { - $th_class[] = 'marker'; - } - - $draggable_html .= ' class="' . implode(' ', $th_class) . '"'; - - $draggable_html .= ' data-column="' . htmlspecialchars($fields_meta->name) - . '">' . $order_link . $comments . ''; - - return $draggable_html; - } - - /** - * 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 stdClass $fields_meta set of field properties - * @param string $comments the comment for the column - * - * @return string html content - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getDraggableClassForNonSortableColumns( - $col_visib, - $col_visib_j, - $condition_field, - $fields_meta, - $comments - ) { - - $draggable_html = '_getClassForNumericColumnType($fields_meta, $th_class); - if ($col_visib && ! $col_visib_j) { - $th_class[] = 'hide'; - } - - if ($condition_field) { - $th_class[] = 'condition'; - } - - $draggable_html .= ' class="' . implode(' ', $th_class) . '"'; - - $draggable_html .= ' data-column="' - . htmlspecialchars((string) $fields_meta->name) . '">'; - - $draggable_html .= htmlspecialchars((string) $fields_meta->name); - - $draggable_html .= "\n" . $comments . ''; - - return $draggable_html; - } - - /** - * Prepare column to show at right side - check boxes or empty column - * - * @param array $displayParts which elements to display - * @param string $full_or_partial_text_link full/partial link or text button - * @param string $colspan column span of table header - * - * @return string html content - * - * @access private - * - * @see _getTableHeaders() - */ - private function _getColumnAtRightSide( - array &$displayParts, - $full_or_partial_text_link, - $colspan - ) { - - $right_column_html = ''; - $display_params = $this->__get('display_params'); - - // 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) - && (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) - && ($displayParts['text_btn'] == '1') - ) { - $display_params['emptyafter'] - = ($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) ? 4 : 1; - - $right_column_html .= "\n" - . '' - . $full_or_partial_text_link - . ''; - } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) - || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH) - && (($displayParts['edit_lnk'] == self::NO_EDIT_OR_DELETE) - && ($displayParts['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) - - $display_params['emptyafter'] - = ($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) ? 4 : 1; - - $right_column_html .= "\n" . ''; - } - - $this->__set('display_params', $display_params); - - return $right_column_html; - } - - /** - * Prepares the display for a value - * - * @param string $class class of table cell - * @param bool $conditionField whether to add CSS class condition - * @param string $value value to display - * - * @return string the td - * - * @access private - * - * @see _getDataCellForGeometryColumns(), - * _getDataCellForNonNumericColumns() - */ - private function _buildValueDisplay($class, $conditionField, $value) - { - return $this->template->render('display/results/value_display', [ - 'class' => $class, - 'condition_field' => $conditionField, - 'value' => $value, - ]); - } - - /** - * Prepares the display for a null value - * - * @param string $class class of table cell - * @param bool $conditionField whether to add CSS class condition - * @param stdClass $meta the meta-information about this field - * @param string $align cell alignment - * - * @return string the td - * - * @access private - * - * @see _getDataCellForNumericColumns(), - * _getDataCellForGeometryColumns(), - * _getDataCellForNonNumericColumns() - */ - private function _buildNullDisplay($class, $conditionField, $meta, $align = '') - { - $classes = $this->_addClass($class, $conditionField, $meta, ''); - - return $this->template->render('display/results/null_display', [ - 'align' => $align, - 'meta' => $meta, - 'classes' => $classes, - ]); - } - - /** - * Prepares the display for an empty value - * - * @param string $class class of table cell - * @param bool $conditionField whether to add CSS class condition - * @param stdClass $meta the meta-information about this field - * @param string $align cell alignment - * - * @return string the td - * - * @access private - * - * @see _getDataCellForNumericColumns(), - * _getDataCellForGeometryColumns(), - * _getDataCellForNonNumericColumns() - */ - private function _buildEmptyDisplay($class, $conditionField, $meta, $align = '') - { - $classes = $this->_addClass($class, $conditionField, $meta, 'nowrap'); - - return $this->template->render('display/results/empty_display', [ - 'align' => $align, - 'classes' => $classes, - ]); - } - - /** - * Adds the relevant classes. - * - * @param string $class class of table cell - * @param bool $condition_field whether to add CSS class - * condition - * @param stdClass $meta the meta-information about the - * field - * @param string $nowrap avoid wrapping - * @param bool $is_field_truncated is field truncated (display ...) - * @param TransformationsPlugin|string $transformation_plugin transformation plugin. - * Can also be the default function: - * Core::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 = '' - ) { - $classes = [ - $class, - $nowrap, - ]; - - if (isset($meta->mimetype)) { - $classes[] = preg_replace('/\//', '_', $meta->mimetype); - } - - if ($condition_field) { - $classes[] = 'condition'; - } - - if ($is_field_truncated) { - $classes[] = 'truncated'; - } - - $mime_map = $this->__get('mime_map'); - $orgFullColName = $this->__get('db') . '.' . $meta->orgtable - . '.' . $meta->orgname; - if ($transformation_plugin != $default_function - || ! empty($mime_map[$orgFullColName]['input_transformation']) - ) { - $classes[] = 'transformed'; - } - - // Define classes to be added to this data field based on the type of data - $matches = [ - 'enum' => 'enum', - 'set' => 'set', - 'binary' => 'hex', - ]; - - foreach ($matches as $key => $value) { - if (mb_strpos($meta->flags, $key) !== false) { - $classes[] = $value; - } - } - - if (mb_strpos($meta->type, 'bit') !== false) { - $classes[] = 'bit'; - } - - return implode(' ', $classes); - } - - /** - * 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 $displayParts which elements to display - * @param array $map the list of relations - * @param array $analyzed_sql_results analyzed sql results - * @param boolean $is_limited_display with limited operations or not - * - * @return string html content - * - * @global array $row current row data - * - * @access private - * - * @see getTable() - */ - private function _getTableBody( - &$dt_result, - array &$displayParts, - array $map, - array $analyzed_sql_results, - $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_results); - - $display_params = $this->__get('display_params'); - - if (! is_array($map)) { - $map = []; - } - - $row_no = 0; - $display_params['edit'] = []; - $display_params['copy'] = []; - $display_params['delete'] = []; - $display_params['data'] = []; - $display_params['row_delete'] = []; - $this->__set('display_params', $display_params); - - // 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; - default: // 'disabled' - $grid_edit_class = ''; - break; - } - } - - // prepare to get the column order, if available - list($col_order, $col_visib) = $this->_getColumnParams( - $analyzed_sql_results - ); - - // 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. - - $whereClauseMap = $this->__get('whereClauseMap'); - while ($row = $GLOBALS['dbi']->fetchRow($dt_result)) { - // add repeating headers - if (($row_no != 0) && ($_SESSION['tmpval']['repeat_cells'] != 0) - && ! ($row_no % $_SESSION['tmpval']['repeat_cells']) - ) { - $table_body_html .= $this->_getRepeatingHeaders( - $display_params - ); - } - - $tr_class = []; - if ($GLOBALS['cfg']['BrowsePointerEnable'] != true) { - $tr_class[] = 'nopointer'; - } - if ($GLOBALS['cfg']['BrowseMarkerEnable'] != true) { - $tr_class[] = 'nomarker'; - } - - // pointer code part - $classes = (empty($tr_class) ? ' ' : 'class="' . implode(' ', $tr_class) . '"'); - $table_body_html .= ''; - - // 1. Prepares the row - - // In print view these variable needs to be initialized - $del_url = $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 (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) - ) { - // 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) - = Util::getUniqueCondition( - $dt_result, // handle - $this->__get('fields_cnt'), // fields_cnt - $this->__get('fields_meta'), // fields_meta - $row, // row - false, // force_unique - $this->__get('table'), // restrict_to_table - $analyzed_sql_results // analyzed_sql_results - ); - $whereClauseMap[$row_no][$this->__get('table')] = $where_clause; - $this->__set('whereClauseMap', $whereClauseMap); - - $where_clause_html = htmlspecialchars($where_clause); - - // 1.2.1 Modify link(s) - update row case - if ($displayParts['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) - list($del_url, $del_str, $js_conf) - = $this->_getDeleteAndKillLinks( - $where_clause, - $clause_is_unique, - $url_sql_query, - $displayParts['del_lnk'], - $row - ); - - // 1.3 Displays the links at left if required - if (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) - || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH) - ) { - $table_body_html .= $this->_getPlacedLinks( - self::POSITION_LEFT, - $del_url, - $displayParts, - $row_no, - $where_clause, - $where_clause_html, - $condition_array, - $edit_url, - $copy_url, - $edit_anchor_class, - $edit_str, - $copy_str, - $del_str, - $js_conf - ); - } elseif ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) { - $table_body_html .= $this->_getPlacedLinks( - self::POSITION_NONE, - $del_url, - $displayParts, - $row_no, - $where_clause, - $where_clause_html, - $condition_array, - $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 - if ($this->__get('mime_map') === null) { - $this->_setMimeMap(); - } - $table_body_html .= $this->_getRowValues( - $dt_result, - $row, - $row_no, - $col_order, - $map, - $grid_edit_class, - $col_visib, - $url_sql_query, - $analyzed_sql_results - ); - - // 3. Displays the modify/delete links on the right if required - if (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) - ) { - if (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT) - || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH) - ) { - $table_body_html .= $this->_getPlacedLinks( - self::POSITION_RIGHT, - $del_url, - $displayParts, - $row_no, - $where_clause, - $where_clause_html, - $condition_array, - $edit_url, - $copy_url, - $edit_anchor_class, - $edit_str, - $copy_str, - $del_str, - $js_conf - ); - } - } // end if (3) - - $table_body_html .= ''; - $table_body_html .= "\n"; - $row_no++; - } // end while - - return $table_body_html; - } - - /** - * Sets the MIME details of the columns in the results set - * - * @return void - */ - private function _setMimeMap() - { - $fields_meta = $this->__get('fields_meta'); - $mimeMap = []; - $added = []; - - for ($currentColumn = 0; $currentColumn < $this->__get('fields_cnt'); ++$currentColumn) { - $meta = $fields_meta[$currentColumn]; - $orgFullTableName = $this->__get('db') . '.' . $meta->orgtable; - - if ($GLOBALS['cfgRelation']['commwork'] - && $GLOBALS['cfgRelation']['mimework'] - && $GLOBALS['cfg']['BrowseMIME'] - && ! $_SESSION['tmpval']['hide_transformation'] - && empty($added[$orgFullTableName]) - ) { - $mimeMap = array_merge( - $mimeMap, - $this->transformations->getMime($this->__get('db'), $meta->orgtable, false, true) - ); - $added[$orgFullTableName] = true; - } - } - - // special browser transformation for some SHOW statements - if ($this->__get('is_show') - && ! $_SESSION['tmpval']['hide_transformation'] - ) { - 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])) { - $str = ' ' . strtoupper($which[1]); - $isShowProcessList = strpos($str, 'PROCESSLIST') > 0; - if ($isShowProcessList) { - $mimeMap['..Info'] = [ - 'mimetype' => 'Text_Plain', - 'transformation' => 'output/Text_Plain_Sql.php', - ]; - } - - $isShowCreateTable = preg_match( - '@CREATE[[:space:]]+TABLE@i', - $this->__get('sql_query') - ); - if ($isShowCreateTable) { - $mimeMap['..Create Table'] = [ - 'mimetype' => 'Text_Plain', - 'transformation' => 'output/Text_Plain_Sql.php', - ]; - } - } - } - - $this->__set('mime_map', $mimeMap); - } - - /** - * 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|boolean $col_order the column order false when - * a property not found 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|array|string $col_visib column is visible(false); - * column isn't visible(string - * array) - * @param string $url_sql_query the analyzed sql query - * @param array $analyzed_sql_results analyzed sql results - * - * @return string html content - * - * @access private - * - * @see _getTableBody() - */ - private function _getRowValues( - &$dt_result, - array $row, - $row_no, - $col_order, - array $map, - $grid_edit_class, - $col_visib, - $url_sql_query, - array $analyzed_sql_results - ) { - $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); - - $whereClauseMap = $this->__get('whereClauseMap'); - - $columnCount = $this->__get('fields_cnt'); - for ($currentColumn = 0; $currentColumn < $columnCount; ++$currentColumn) { - // assign $i with appropriate column order - $i = $col_order ? $col_order[$currentColumn] : $currentColumn; - - $meta = $fields_meta[$i]; - $orgFullColName - = $this->__get('db') . '.' . $meta->orgtable . '.' . $meta->orgname; - - $not_null_class = $meta->not_null ? 'not_null' : ''; - $relation_class = isset($map[$meta->name]) ? 'relation' : ''; - $hide_class = $col_visib && ! $col_visib[$currentColumn] - ? 'hide' - : ''; - $grid_edit = $meta->orgtable != '' ? $grid_edit_class : ''; - - // 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, - $not_null_class, - $relation_class, - $hide_class, - $field_type_class - ); - - // 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[Util::backquote($meta->name)])) - ? true - : false; - - // Wrap MIME-transformations. [MIME] - $default_function = [ - Core::class, - 'mimeDefaultFunction', - ]; // default_function - $transformation_plugin = $default_function; - $transform_options = []; - - if ($GLOBALS['cfgRelation']['mimework'] - && $GLOBALS['cfg']['BrowseMIME'] - ) { - if (isset($mime_map[$orgFullColName]['mimetype']) - && ! empty($mime_map[$orgFullColName]['transformation']) - ) { - $file = $mime_map[$orgFullColName]['transformation']; - $include_file = 'libraries/classes/Plugins/Transformations/' . $file; - - if (@file_exists($include_file)) { - $class_name = $this->transformations->getClassName($include_file); - if (class_exists($class_name)) { - // todo add $plugin_manager - $plugin_manager = null; - $transformation_plugin = new $class_name( - $plugin_manager - ); - - $transform_options = $this->transformations->getOptions( - isset( - $mime_map[$orgFullColName]['transformation_options'] - ) - ? $mime_map[$orgFullColName]['transformation_options'] - : '' - ); - - $meta->mimetype = str_replace( - '_', - '/', - $mime_map[$orgFullColName]['mimetype'] - ); - } - } // end if file_exists - } // end if transformation is set - } // end if mime/transformation works. - - // Check whether the field needs to display with syntax highlighting - - $dbLower = mb_strtolower($this->__get('db')); - $tblLower = mb_strtolower($meta->orgtable); - $nameLower = mb_strtolower($meta->orgname); - if (! empty($this->transformation_info[$dbLower][$tblLower][$nameLower]) - && (trim($row[$i]) != '') - && ! $_SESSION['tmpval']['hide_transformation'] - ) { - include_once $this->transformation_info[$dbLower][$tblLower][$nameLower][0]; - $transformation_plugin = new $this->transformation_info[$dbLower][$tblLower][$nameLower][1](null); - - $transform_options = $this->transformations->getOptions( - isset($mime_map[$orgFullColName]['transformation_options']) - ? $mime_map[$orgFullColName]['transformation_options'] - : '' - ); - - $meta->mimetype = str_replace( - '_', - '/', - $this->transformation_info[$dbLower][mb_strtolower($meta->orgtable)][mb_strtolower($meta->orgname)][2] - ); - } - - // Check for the predefined fields need to show as link in schemas - $specialSchemaLinks = SpecialSchemaLinks::get(); - - if (! empty($specialSchemaLinks[$dbLower][$tblLower][$nameLower])) { - $linking_url = $this->_getSpecialLinkUrl( - $specialSchemaLinks, - $row[$i], - $row_info, - mb_strtolower($meta->orgname) - ); - $transformation_plugin = new Text_Plain_Link(); - - $transform_options = [ - 0 => $linking_url, - 2 => true, - ]; - - $meta->mimetype = str_replace( - '_', - '/', - 'Text/Plain' - ); - } - - /* - * The result set can have columns from more than one table, - * this is why we have to check for the unique conditions - * related to this table; however getUniqueCondition() is - * costly and does not need to be called if we already know - * the conditions for the current table. - */ - if (! isset($whereClauseMap[$row_no][$meta->orgtable])) { - $unique_conditions = Util::getUniqueCondition( - $dt_result, // handle - $this->__get('fields_cnt'), // fields_cnt - $this->__get('fields_meta'), // fields_meta - $row, // row - false, // force_unique - $meta->orgtable, // restrict_to_table - $analyzed_sql_results // analyzed_sql_results - ); - $whereClauseMap[$row_no][$meta->orgtable] = $unique_conditions[0]; - } - - $_url_params = [ - 'db' => $this->__get('db'), - 'table' => $meta->orgtable, - 'where_clause' => $whereClauseMap[$row_no][$meta->orgtable], - 'transform_key' => $meta->orgname, - ]; - - if (! empty($sql_query)) { - $_url_params['sql_query'] = $url_sql_query; - } - - $transform_options['wrapper_link'] = Url::getCommon($_url_params); - - $display_params = $this->__get('display_params'); - - // in some situations (issue 11406), numeric returns 1 - // even for a string type - // for decimal numeric is returning 1 - // have to improve logic - if (($meta->numeric == 1 && $meta->type != 'string') || $meta->type == 'real') { - // n u m e r i c - - $display_params['data'][$row_no][$i] - = $this->_getDataCellForNumericColumns( - $row[$i] === null ? null : (string) $row[$i], - $class, - $condition_field, - $meta, - $map, - $is_field_truncated, - $analyzed_sql_results, - $transformation_plugin, - $default_function, - $transform_options - ); - } 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); - - $display_params['data'][$row_no][$i] - = $this->_getDataCellForGeometryColumns( - $row[$i], - $class, - $meta, - $map, - $_url_params, - $condition_field, - $transformation_plugin, - $default_function, - $transform_options, - $analyzed_sql_results - ); - } else { - // n o t n u m e r i c - - $display_params['data'][$row_no][$i] - = $this->_getDataCellForNonNumericColumns( - $row[$i], - $class, - $meta, - $map, - $_url_params, - $condition_field, - $transformation_plugin, - $default_function, - $transform_options, - $is_field_truncated, - $analyzed_sql_results, - $dt_result, - $i - ); - } - - // output stored cell - $row_values_html .= $display_params['data'][$row_no][$i]; - - if (isset($display_params['rowdata'][$i][$row_no])) { - $display_params['rowdata'][$i][$row_no] - .= $display_params['data'][$row_no][$i]; - } else { - $display_params['rowdata'][$i][$row_no] - = $display_params['data'][$row_no][$i]; - } - - $this->__set('display_params', $display_params); - } // end for - - return $row_values_html; - } - - /** - * Get link for display special schema links - * - * @param array $specialSchemaLinks 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( - array $specialSchemaLinks, - $column_value, - array $row_info, - $field_name - ) { - $linking_url_params = []; - $link_relations = $specialSchemaLinks[mb_strtolower($this->__get('db'))][mb_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 that needs to be passed 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; - } - - $divider = strpos($link_relations['default_page'], '?') ? '&' : '?'; - if (empty($link_relations['link_dependancy_params'])) { - return $link_relations['default_page'] - . Url::getCommonRaw($linking_url_params, $divider); - } - - 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]; - continue; - } - - $linking_url_params[$new_param['param_info']] - = $row_info[mb_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'])) { - continue; - } - } - - return $link_relations['default_page'] - . Url::getCommonRaw($linking_url_params, $divider); - } - - /** - * Prepare row information for display special links - * - * @param array $row current row data - * @param array|boolean $col_order the column order - * - * @return array associative array with column nama -> value - */ - private function _getRowInfoForSpecialLinks(array $row, $col_order) - { - - $row_info = []; - $fields_meta = $this->__get('fields_meta'); - - for ($n = 0; $n < $this->__get('fields_cnt'); ++$n) { - $m = $col_order ? $col_order[$n] : $n; - $row_info[mb_strtolower($fields_meta[$m]->orgname)] - = $row[$m]; - } - - return $row_info; - } - - /** - * Get url sql query without conditions to shorten URLs - * - * @param array $analyzed_sql_results analyzed sql results - * - * @return string analyzed sql query - * - * @access private - * - * @see _getTableBody() - */ - private function _getUrlSqlQuery(array $analyzed_sql_results) - { - if (($analyzed_sql_results['querytype'] != 'SELECT') - || (mb_strlen($this->__get('sql_query')) < 200) - ) { - return $this->__get('sql_query'); - } - - $query = 'SELECT ' . Query::getClause( - $analyzed_sql_results['statement'], - $analyzed_sql_results['parser']->list, - 'SELECT' - ); - - $from_clause = Query::getClause( - $analyzed_sql_results['statement'], - $analyzed_sql_results['parser']->list, - 'FROM' - ); - - if (! empty($from_clause)) { - $query .= ' FROM ' . $from_clause; - } - - return $query; - } - - /** - * Get column order and column visibility - * - * @param array $analyzed_sql_results analyzed sql results - * - * @return array 2 element array - $col_order, $col_visib - * - * @access private - * - * @see _getTableBody() - */ - private function _getColumnParams(array $analyzed_sql_results) - { - if ($this->_isSelect($analyzed_sql_results)) { - $pmatable = new Table($this->__get('table'), $this->__get('db')); - $col_order = $pmatable->getUiProp(Table::PROP_COLUMN_ORDER); - /* Validate the value */ - if ($col_order !== false) { - $fields_cnt = $this->__get('fields_cnt'); - foreach ($col_order as $value) { - if ($value >= $fields_cnt) { - $pmatable->removeUiProp(Table::PROP_COLUMN_ORDER); - $fields_cnt = false; - } - } - } - $col_visib = $pmatable->getUiProp(Table::PROP_COLUMN_VISIB); - } else { - $col_order = false; - $col_visib = false; - } - - return [ - $col_order, - $col_visib, - ]; - } - - /** - * Get HTML for repeating headers - * - * @param array $display_params holds various display info - * - * @return string html content - * - * @access private - * - * @see _getTableBody() - */ - private function _getRepeatingHeaders( - array $display_params - ) { - $header_html = '' . "\n"; - - if ($display_params['emptypre'] > 0) { - $header_html .= ' ' - . "\n" . '  ' . "\n"; - } elseif ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) { - $header_html .= ' ' . "\n"; - } - - foreach ($display_params['desc'] as $val) { - $header_html .= $val; - } - - if ($display_params['emptyafter'] > 0) { - $header_html - .= ' ' - . "\n" . '  ' . "\n"; - } - $header_html .= '' . "\n"; - - return $header_html; - } - - /** - * 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 = [ - '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' - . Url::getCommon( - $_url_params + ['default_action' => 'update'] - ); - - $copy_url = 'tbl_change.php' - . Url::getCommon( - $_url_params + ['default_action' => 'insert'] - ); - - $edit_str = $this->_getActionLinkContent( - 'b_edit', - __('Edit') - ); - $copy_str = $this->_getActionLinkContent( - 'b_insrow', - __('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 [ - $edit_url, - $copy_url, - $edit_str, - $copy_str, - $edit_anchor_class, - ]; - } - - /** - * 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 3 element array - * $del_url, $del_str, $js_conf - * - * @access private - * - * @see _getTableBody() - */ - private function _getDeleteAndKillLinks( - $where_clause, - $clause_is_unique, - $url_sql_query, - $del_lnk, - array $row - ) { - - $goto = $this->__get('goto'); - - if ($del_lnk == self::DELETE_ROW) { // delete row case - $_url_params = [ - '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' . Url::getCommonRaw($_url_params); - - $del_query = 'DELETE FROM ' - . Util::backquote($this->__get('table')) - . ' WHERE ' . $where_clause . - ($clause_is_unique ? '' : ' LIMIT 1'); - - $_url_params = [ - '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' . Url::getCommon($_url_params); - - $js_conf = 'DELETE FROM ' . Sanitize::jsFormat($this->__get('table')) - . ' WHERE ' . Sanitize::jsFormat($where_clause, false) - . ($clause_is_unique ? '' : ' LIMIT 1'); - - $del_str = $this->_getActionLinkContent('b_drop', __('Delete')); - } elseif ($del_lnk == self::KILL_PROCESS) { // kill process case - $_url_params = [ - 'db' => $this->__get('db'), - 'table' => $this->__get('table'), - 'sql_query' => $url_sql_query, - 'goto' => 'index.php', - ]; - - $lnk_goto = 'sql.php' . Url::getCommonRaw($_url_params); - - $kill = $GLOBALS['dbi']->getKillQuery((int) $row[0]); - - $_url_params = [ - 'db' => 'mysql', - 'sql_query' => $kill, - 'goto' => $lnk_goto, - ]; - - $del_url = 'sql.php' . Url::getCommon($_url_params); - $js_conf = $kill; - $del_str = Util::getIcon( - 'b_drop', - __('Kill') - ); - } else { - $del_url = $del_str = $js_conf = null; - } - - return [ - $del_url, - $del_str, - $js_conf, - ]; - } - - /** - * Get content inside the table row action links (Edit/Copy/Delete) - * - * @param string $icon The name of the file to get - * @param string $display_text The text displaying after the image icon - * - * @return string - * - * @access private - * - * @see _getModifiedLinks(), _getDeleteAndKillLinks() - */ - private function _getActionLinkContent($icon, $display_text) - { - - $linkContent = ''; - - if (isset($GLOBALS['cfg']['RowActionType']) - && $GLOBALS['cfg']['RowActionType'] == self::ACTION_LINK_CONTENT_ICONS - ) { - $linkContent .= '' - . Util::getImage( - $icon, - $display_text - ) - . ''; - } elseif (isset($GLOBALS['cfg']['RowActionType']) - && $GLOBALS['cfg']['RowActionType'] == self::ACTION_LINK_CONTENT_TEXT - ) { - $linkContent .= '' . $display_text . ''; - } else { - $linkContent .= Util::getIcon( - $icon, - $display_text - ); - } - - return $linkContent; - } - - /** - * Prepare placed links - * - * @param string $dir the direction of links should place - * @param string $del_url the url for delete row - * @param array $displayParts 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 $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|null $js_conf text for the JS confirmation - * - * @return string html content - * - * @access private - * - * @see _getTableBody() - */ - private function _getPlacedLinks( - $dir, - $del_url, - array $displayParts, - $row_no, - $where_clause, - $where_clause_html, - array $condition_array, - $edit_url, - $copy_url, - $edit_anchor_class, - $edit_str, - $copy_str, - $del_str, - ?string $js_conf - ) { - - if (! isset($js_conf)) { - $js_conf = ''; - } - - return $this->_getCheckboxAndLinks( - $dir, - $del_url, - $displayParts, - $row_no, - $where_clause, - $where_clause_html, - $condition_array, - $edit_url, - $copy_url, - $edit_anchor_class, - $edit_str, - $copy_str, - $del_str, - $js_conf - ); - } - - /** - * 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 - * - * @return string the combined classes - * - * @access private - * - * @see _getTableBody() - */ - private function _getClassesForColumn( - $grid_edit_class, - $not_null_class, - $relation_class, - $hide_class, - $field_type_class - ) { - return 'data ' . $grid_edit_class . ' ' . $not_null_class . ' ' - . $relation_class . ' ' . $hide_class . ' ' . $field_type_class; - } - - /** - * Get class for datetime related fields - * - * @param string $type the type of the column field - * - * @return string 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'; - } elseif ($type == self::DATE_FIELD) { - $field_type_class = 'datefield'; - } elseif ($type == self::TIME_FIELD) { - $field_type_class = 'timefield'; - } elseif ($type == self::STRING_FIELD) { - $field_type_class = 'text'; - } else { - $field_type_class = ''; - } - return $field_type_class; - } - - /** - * Prepare data cell for numeric type fields - * - * @param string|null $column the column's value - * @param string $class the html class for column - * @param boolean $condition_field the column should highlighted - * or not - * @param stdClass $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_results the analyzed query - * @param TransformationsPlugin $transformation_plugin the name of transformation plugin - * @param string $default_function the default transformation - * function - * @param array $transform_options the transformation parameters - * - * @return string the prepared cell, html content - * - * @access private - * - * @see _getTableBody() - */ - private function _getDataCellForNumericColumns( - ?string $column, - $class, - $condition_field, - $meta, - array $map, - $is_field_truncated, - array $analyzed_sql_results, - $transformation_plugin, - $default_function, - array $transform_options - ) { - - if (! isset($column) || $column === null) { - $cell = $this->_buildNullDisplay( - 'right ' . $class, - $condition_field, - $meta, - '' - ); - } elseif ($column != '') { - $nowrap = ' nowrap'; - $where_comparison = ' = ' . $column; - - $cell = $this->_getRowData( - 'right ' . $class, - $condition_field, - $analyzed_sql_results, - $meta, - $map, - $column, - $column, - $transformation_plugin, - $default_function, - $nowrap, - $where_comparison, - $transform_options, - $is_field_truncated, - '' - ); - } else { - $cell = $this->_buildEmptyDisplay( - 'right ' . $class, - $condition_field, - $meta, - '' - ); - } - - return $cell; - } - - /** - * Get data cell for geometry type fields - * - * @param string|null $column the relevant column in data row - * @param string $class the html class for column - * @param stdClass $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 TransformationsPlugin $transformation_plugin the name of transformation - * function - * @param string $default_function the default transformation - * function - * @param string $transform_options the transformation parameters - * @param array $analyzed_sql_results the analyzed query - * - * @return string the prepared data cell, html content - * - * @access private - * - * @see _getTableBody() - */ - private function _getDataCellForGeometryColumns( - ?string $column, - $class, - $meta, - array $map, - array $_url_params, - $condition_field, - $transformation_plugin, - $default_function, - $transform_options, - array $analyzed_sql_results - ) { - if (! isset($column) || $column === null) { - $cell = $this->_buildNullDisplay($class, $condition_field, $meta); - return $cell; - } - - if ($column == '') { - $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta); - return $cell; - } - - // Display as [GEOMETRY - (size)] - if ($_SESSION['tmpval']['geoOption'] == self::GEOMETRY_DISP_GEOM) { - $geometry_text = $this->_handleNonPrintableContents( - strtoupper(self::GEOMETRY_FIELD), - $column, - $transformation_plugin, - $transform_options, - $default_function, - $meta, - $_url_params - ); - - $cell = $this->_buildValueDisplay( - $class, - $condition_field, - $geometry_text - ); - return $cell; - } - - if ($_SESSION['tmpval']['geoOption'] == self::GEOMETRY_DISP_WKT) { - // Prepare in Well Known Text(WKT) format. - $where_comparison = ' = ' . $column; - - // Convert to WKT format - $wktval = Util::asWKT($column); - list( - $is_field_truncated, - $displayedColumn, - // skip 3rd param - ) = $this->_getPartialText($wktval); - - $cell = $this->_getRowData( - $class, - $condition_field, - $analyzed_sql_results, - $meta, - $map, - $wktval, - $displayedColumn, - $transformation_plugin, - $default_function, - '', - $where_comparison, - $transform_options, - $is_field_truncated, - '' - ); - return $cell; - } - - // Prepare in Well Known Binary (WKB) format. - - if ($_SESSION['tmpval']['display_binary']) { - $where_comparison = ' = ' . $column; - - $wkbval = substr(bin2hex($column), 8); - list( - $is_field_truncated, - $displayedColumn, - // skip 3rd param - ) = $this->_getPartialText($wkbval); - - $cell = $this->_getRowData( - $class, - $condition_field, - $analyzed_sql_results, - $meta, - $map, - $wkbval, - $displayedColumn, - $transformation_plugin, - $default_function, - '', - $where_comparison, - $transform_options, - $is_field_truncated, - '' - ); - return $cell; - } - - $wkbval = $this->_handleNonPrintableContents( - self::BINARY_FIELD, - $column, - $transformation_plugin, - $transform_options, - $default_function, - $meta, - $_url_params - ); - - $cell = $this->_buildValueDisplay( - $class, - $condition_field, - $wkbval - ); - - return $cell; - } - - /** - * Get data cell for non numeric type fields - * - * @param string|null $column the relevant column in data row - * @param string $class the html class for column - * @param stdClass $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 TransformationsPlugin $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 is data truncated due to - * LimitChars - * @param array $analyzed_sql_results 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 the prepared data cell, html content - * - * @access private - * - * @see _getTableBody() - */ - private function _getDataCellForNonNumericColumns( - ?string $column, - $class, - $meta, - array $map, - array $_url_params, - $condition_field, - $transformation_plugin, - $default_function, - $transform_options, - $is_field_truncated, - array $analyzed_sql_results, - &$dt_result, - $col_index - ) { - $original_length = 0; - - $is_analyse = $this->__get('is_analyse'); - $field_flags = $GLOBALS['dbi']->fieldFlags($dt_result, $col_index); - - $bIsText = gettype($transformation_plugin) === 'object' - && strpos($transformation_plugin->getMIMEType(), 'Text') - === false; - - // disable inline grid editing - // if binary fields are protected - // or transformation plugin is of non text type - // such as image - if ((false !== stripos($field_flags, self::BINARY_FIELD) - && ($GLOBALS['cfg']['ProtectBinary'] === 'all' - || ($GLOBALS['cfg']['ProtectBinary'] === 'noblob' - && false === stripos($meta->type, self::BLOB_FIELD)) - || ($GLOBALS['cfg']['ProtectBinary'] === 'blob' - && false !== stripos($meta->type, self::BLOB_FIELD)))) - || $bIsText - ) { - $class = str_replace('grid_edit', '', $class); - } - - if (! isset($column) || $column === null) { - $cell = $this->_buildNullDisplay($class, $condition_field, $meta); - return $cell; - } - - if ($column == '') { - $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta); - return $cell; - } - - // Cut all fields to $GLOBALS['cfg']['LimitChars'] - // (unless it's a link-type transformation or binary) - $displayedColumn = $column; - if (! (gettype($transformation_plugin) === "object" - && strpos($transformation_plugin->getName(), 'Link') !== false) - && false === stripos($field_flags, self::BINARY_FIELD) - ) { - list( - $is_field_truncated, - $column, - $original_length - ) = $this->_getPartialText($column); - } - - $formatted = false; - if (isset($meta->_type) && $meta->_type === MYSQLI_TYPE_BIT) { - $displayedColumn = Util::printableBitValue( - (int) $displayedColumn, - (int) $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 (false !== stripos($field_flags, self::BINARY_FIELD) - && ! (isset($is_analyse) && $is_analyse) - ) { - // we show the BINARY or BLOB message and field's size - // (or maybe use a transformation) - $binary_or_blob = self::BLOB_FIELD; - if ($meta->type === self::STRING_FIELD) { - $binary_or_blob = self::BINARY_FIELD; - } - $displayedColumn = $this->_handleNonPrintableContents( - $binary_or_blob, - $displayedColumn, - $transformation_plugin, - $transform_options, - $default_function, - $meta, - $_url_params, - $is_field_truncated - ); - $class = $this->_addClass( - $class, - $condition_field, - $meta, - '', - $is_field_truncated, - $transformation_plugin, - $default_function - ); - $result = strip_tags($column); - // disable inline grid editing - // if binary or blob data is not shown - if (false !== stripos($result, $binary_or_blob)) { - $class = str_replace('grid_edit', '', $class); - } - $formatted = true; - } - - if ($formatted) { - $cell = $this->_buildValueDisplay( - $class, - $condition_field, - $displayedColumn - ); - return $cell; - } - - // transform functions may enable no-wrapping: - $function_nowrap = 'applyTransformationNoWrap'; - - $bool_nowrap = ($default_function != $transformation_plugin) - && function_exists((string) $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 = ' = \'' - . $GLOBALS['dbi']->escapeString($column) - . '\''; - - $cell = $this->_getRowData( - $class, - $condition_field, - $analyzed_sql_results, - $meta, - $map, - $column, - $displayedColumn, - $transformation_plugin, - $default_function, - $nowrap, - $where_comparison, - $transform_options, - $is_field_truncated, - $original_length - ); - - return $cell; - } - - /** - * Checks the posted options for viewing query results - * 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')); - $query = []; - if (isset($_SESSION['tmpval']['query'][$sql_md5])) { - $query = $_SESSION['tmpval']['query'][$sql_md5]; - } - - $query['sql'] = $this->__get('sql_query'); - - if (empty($query['repeat_cells'])) { - $query['repeat_cells'] = $GLOBALS['cfg']['RepeatCells']; - } - - // as this is a form value, the type is always string so we cannot - // use Core::isValid($_POST['session_max_rows'], 'integer') - if (Core::isValid($_POST['session_max_rows'], 'numeric')) { - $query['max_rows'] = (int) $_POST['session_max_rows']; - unset($_POST['session_max_rows']); - } elseif ($_POST['session_max_rows'] == self::ALL_ROWS) { - $query['max_rows'] = self::ALL_ROWS; - unset($_POST['session_max_rows']); - } elseif (empty($query['max_rows'])) { - $query['max_rows'] = intval($GLOBALS['cfg']['MaxRows']); - } - - if (Core::isValid($_REQUEST['pos'], 'numeric')) { - $query['pos'] = $_REQUEST['pos']; - unset($_REQUEST['pos']); - } elseif (empty($query['pos'])) { - $query['pos'] = 0; - } - - if (Core::isValid( - $_REQUEST['pftext'], - [ - self::DISPLAY_PARTIAL_TEXT, - self::DISPLAY_FULL_TEXT, - ] - ) - ) { - $query['pftext'] = $_REQUEST['pftext']; - unset($_REQUEST['pftext']); - } elseif (empty($query['pftext'])) { - $query['pftext'] = self::DISPLAY_PARTIAL_TEXT; - } - - if (Core::isValid( - $_REQUEST['relational_display'], - [ - self::RELATIONAL_KEY, - self::RELATIONAL_DISPLAY_COLUMN, - ] - ) - ) { - $query['relational_display'] = $_REQUEST['relational_display']; - unset($_REQUEST['relational_display']); - } elseif (empty($query['relational_display'])) { - // The current session value has priority over a - // change via Settings; this change will be apparent - // starting from the next session - $query['relational_display'] = $GLOBALS['cfg']['RelationalDisplay']; - } - - if (Core::isValid( - $_REQUEST['geoOption'], - [ - self::GEOMETRY_DISP_WKT, - self::GEOMETRY_DISP_WKB, - self::GEOMETRY_DISP_GEOM, - ] - ) - ) { - $query['geoOption'] = $_REQUEST['geoOption']; - unset($_REQUEST['geoOption']); - } elseif (empty($query['geoOption'])) { - $query['geoOption'] = self::GEOMETRY_DISP_GEOM; - } - - if (isset($_REQUEST['display_binary'])) { - $query['display_binary'] = true; - unset($_REQUEST['display_binary']); - } elseif (isset($_REQUEST['display_options_form'])) { - // we know that the checkbox was unchecked - unset($query['display_binary']); - } elseif (! isset($_REQUEST['full_text_button'])) { - // selected by default because some operations like OPTIMIZE TABLE - // and all queries involving functions return "binary" contents, - // according to low-level field flags - $query['display_binary'] = true; - } - - if (isset($_REQUEST['display_blob'])) { - $query['display_blob'] = true; - unset($_REQUEST['display_blob']); - } elseif (isset($_REQUEST['display_options_form'])) { - // we know that the checkbox was unchecked - unset($query['display_blob']); - } - - if (isset($_REQUEST['hide_transformation'])) { - $query['hide_transformation'] = true; - unset($_REQUEST['hide_transformation']); - } elseif (isset($_REQUEST['display_options_form'])) { - // we know that the checkbox was unchecked - unset($query['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 - unset($_SESSION['tmpval']['query'][$sql_md5]); - $_SESSION['tmpval']['query'][$sql_md5] = $query; - - // do not exceed a maximum number of queries to remember - if (count($_SESSION['tmpval']['query']) > 10) { - array_shift($_SESSION['tmpval']['query']); - //echo 'deleting one element ...'; - } - - // populate query configuration - $_SESSION['tmpval']['pftext'] - = $query['pftext']; - $_SESSION['tmpval']['relational_display'] - = $query['relational_display']; - $_SESSION['tmpval']['geoOption'] - = $query['geoOption']; - $_SESSION['tmpval']['display_binary'] = isset( - $query['display_binary'] - ); - $_SESSION['tmpval']['display_blob'] = isset( - $query['display_blob'] - ); - $_SESSION['tmpval']['hide_transformation'] = isset( - $query['hide_transformation'] - ); - $_SESSION['tmpval']['pos'] - = $query['pos']; - $_SESSION['tmpval']['max_rows'] - = $query['max_rows']; - $_SESSION['tmpval']['repeat_cells'] - = $query['repeat_cells']; - } - - /** - * Prepare a table of results returned by a SQL query. - * - * @param integer $dt_result the link id associated to the query - * which results have to be displayed - * @param array $displayParts the parts to display - * @param array $analyzed_sql_results analyzed sql results - * @param boolean $is_limited_display With limited operations or not - * - * @return string Generated HTML content for resulted table - * - * @access public - * - * @see sql.php file - */ - public function getTable( - &$dt_result, - array &$displayParts, - array $analyzed_sql_results, - $is_limited_display = false - ) { - /** - * The statement this table is built for. - * @var SelectStatement - */ - if (isset($analyzed_sql_results['statement'])) { - $statement = $analyzed_sql_results['statement']; - } else { - $statement = null; - } - - // 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'); - - /** - * @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); - - $sql = new Sql(); - if ($is_innodb && $sql->isJustBrowsing($analyzed_sql_results, true)) { - $pre_count = '~'; - $after_count = Util::showHint( - Sanitize::sanitizeMessage( - __('May be approximate. See [doc@faq3-11]FAQ 3.11[/doc].') - ) - ); - } else { - $pre_count = ''; - $after_count = ''; - } - - // 1. ----- Prepares the work ----- - - // 1.1 Gets the information about which functionalities should be - // displayed - - list( - $displayParts, - $total - ) = $this->_setDisplayPartsAndTotal($displayParts); - - // 1.2 Defines offsets for the next and previous pages - if ($displayParts['nav_bar'] == '1') { - list($pos_next, $pos_prev) = $this->_getOffsets(); - } // end if - - // 1.3 Extract sorting expressions. - // we need $sort_expression and $sort_expression_nodirection - // even if there are many table references - $sort_expression = []; - $sort_expression_nodirection = []; - $sort_direction = []; - - if ($statement !== null && ! empty($statement->order)) { - foreach ($statement->order as $o) { - $sort_expression[] = $o->expr->expr . ' ' . $o->type; - $sort_expression_nodirection[] = $o->expr->expr; - $sort_direction[] = $o->type; - } - } else { - $sort_expression[] = ''; - $sort_expression_nodirection[] = ''; - $sort_direction[] = ''; - } - - $number_of_columns = count($sort_expression_nodirection); - - // 1.4 Prepares display of first and last value of the sorted column - $sorted_column_message = ''; - for ($i = 0; $i < $number_of_columns; $i++) { - $sorted_column_message .= $this->_getSortedColumnMessage( - $dt_result, - $sort_expression_nodirection[$i] - ); - } - - // 2. ----- Prepare to display the top of the page ----- - - // 2.1 Prepares a messages with position information - $sqlQueryMessage = ''; - if (($displayParts['nav_bar'] == '1') && isset($pos_next)) { - $message = $this->_setMessageInformation( - $sorted_column_message, - $analyzed_sql_results, - $total, - $pos_next, - $pre_count, - $after_count - ); - - $sqlQueryMessage = Util::getMessage( - $message, - $this->__get('sql_query'), - 'success' - ); - } elseif ((! isset($printview) || ($printview != '1')) && ! $is_limited_display) { - $sqlQueryMessage = 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')) === 0) { - if ($analyzed_sql_results['querytype'] == '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', ''); - } - } - - // can the result be sorted? - if ($displayParts['sort_lnk'] == '1' && $analyzed_sql_results['statement'] !== null) { - // At this point, $sort_expression is an array - list($unsorted_sql_query, $sort_by_key_html) - = $this->_getUnsortedSqlAndSortByKeyDropDown( - $analyzed_sql_results, - $sort_expression - ); - } else { - $sort_by_key_html = $unsorted_sql_query = ''; - } - - $navigation = ''; - if ($displayParts['nav_bar'] == '1' && $statement !== null && empty($statement->limit)) { - $navigation = $this->_getTableNavigation( - $pos_next, - $pos_prev, - $is_innodb, - $sort_by_key_html - ); - } - - // 2b ----- Get field references from Database ----- - // (see the 'relation' configuration variable) - - // initialize map - $map = []; - - if (strlen($this->__get('table')) > 0) { - // This method set the values for $map array - $this->_setParamForLinkForeignKeyRelatedTables($map); - - // Coming from 'Distinct values' action of structure page - // We manipulate relations mechanism to show a link to related rows. - if ($this->__get('is_browse_distinct')) { - $map[$fields_meta[1]->name] = [ - $this->__get('table'), - $fields_meta[1]->name, - '', - $this->__get('db'), - ]; - } - } // end if - // end 2b - - // 3. ----- Prepare the results table ----- - $headers = $this->_getTableHeaders( - $displayParts, - $analyzed_sql_results, - $unsorted_sql_query, - $sort_expression, - $sort_expression_nodirection, - $sort_direction, - $is_limited_display - ); - - $body = $this->_getTableBody( - $dt_result, - $displayParts, - $map, - $analyzed_sql_results, - $is_limited_display - ); - - $this->__set('display_params', null); - - // 4. ----- Prepares the link for multi-fields edit and delete - $multiRowOperationLinks = ''; - if ($displayParts['del_lnk'] == self::DELETE_ROW - && $displayParts['del_lnk'] != self::KILL_PROCESS - ) { - $multiRowOperationLinks = $this->_getMultiRowOperationLinks( - $dt_result, - $analyzed_sql_results, - $displayParts['del_lnk'] - ); - } - - // 5. ----- Prepare "Query results operations" - $operations = ''; - if ((! isset($printview) || ($printview != '1')) && ! $is_limited_display) { - $operations = $this->_getResultsOperations( - $displayParts, - $analyzed_sql_results - ); - } - - return $this->template->render('display/results/table', [ - 'sql_query_message' => $sqlQueryMessage, - 'navigation' => $navigation, - 'headers' => $headers, - 'body' => $body, - 'multi_row_operation_links' => $multiRowOperationLinks, - 'operations' => $operations, - ]); - } - - /** - * 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['tmpval']['max_rows'] == self::ALL_ROWS) { - $pos_next = 0; - $pos_prev = 0; - } else { - $pos_next = $_SESSION['tmpval']['pos'] - + $_SESSION['tmpval']['max_rows']; - - $pos_prev = $_SESSION['tmpval']['pos'] - - $_SESSION['tmpval']['max_rows']; - - if ($pos_prev < 0) { - $pos_prev = 0; - } - } - - return [ - $pos_next, - $pos_prev, - ]; - } - - /** - * 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|null 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)) { - return null; - } - - if (mb_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 = Util::unQuote($sort_table); - $sort_column = 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) { - return null; - } - - // fetch first row of the result set - $row = $GLOBALS['dbi']->fetchRow($dt_result); - - // initializing default arguments - $default_function = [ - Core::class, - 'mimeDefaultFunction', - ]; - $transformation_plugin = $default_function; - $transform_options = []; - - // check for non printable sorted row data - $meta = $fields_meta[$sorted_column_index]; - - if (false !== stripos($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 - ); - } else { - $column_for_first_row = $row[$sorted_column_index]; - } - - $column_for_first_row = mb_strtoupper( - mb_substr( - (string) $column_for_first_row, - 0, - (int) $GLOBALS['cfg']['LimitChars'] - ) . '...' - ); - - // fetch last row of the result set - $GLOBALS['dbi']->dataSeek($dt_result, $this->__get('num_rows') - 1); - $row = $GLOBALS['dbi']->fetchRow($dt_result); - - // check for non printable sorted row data - $meta = $fields_meta[$sorted_column_index]; - if (false !== stripos($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 - ); - } else { - $column_for_last_row = $row[$sorted_column_index]; - } - - $column_for_last_row = mb_strtoupper( - mb_substr( - (string) $column_for_last_row, - 0, - (int) $GLOBALS['cfg']['LimitChars'] - ) . '...' - ); - - // reset to first row for the loop in _getTableBody() - $GLOBALS['dbi']->dataSeek($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) . ']'; - } - - /** - * Set the content that needs to be shown in message - * - * @param string $sorted_column_message the message for sorted column - * @param array $analyzed_sql_results the 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 Message an object of Message - * - * @access private - * - * @see getTable() - */ - private function _setMessageInformation( - $sorted_column_message, - array $analyzed_sql_results, - $total, - $pos_next, - $pre_count, - $after_count - ) { - - $unlim_num_rows = $this->__get('unlim_num_rows'); // To use in isset() - - if (! empty($analyzed_sql_results['statement']->limit)) { - $first_shown_rec = $analyzed_sql_results['statement']->limit->offset; - $row_count = $analyzed_sql_results['statement']->limit->rowCount; - - if ($row_count < $total) { - $last_shown_rec = $first_shown_rec + $row_count - 1; - } else { - $last_shown_rec = $first_shown_rec + $total - 1; - } - } elseif (($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS) - || ($pos_next > $total) - ) { - $first_shown_rec = $_SESSION['tmpval']['pos']; - $last_shown_rec = $total - 1; - } else { - $first_shown_rec = $_SESSION['tmpval']['pos']; - $last_shown_rec = $pos_next - 1; - } - - $table = new Table($this->__get('table'), $this->__get('db')); - if ($table->isView() - && ($total == $GLOBALS['cfg']['MaxExactCountViews']) - ) { - $message = 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 = Util::showHint($message); - } else { - $message_view_warning = false; - } - - $message = Message::success(__('Showing rows %1s - %2s')); - $message->addParam($first_shown_rec); - - if ($message_view_warning !== false) { - $message->addParamHtml('... ' . $message_view_warning); - } else { - $message->addParam($last_shown_rec); - } - - $message->addText('('); - - if ($message_view_warning === false) { - if (isset($unlim_num_rows) && ($unlim_num_rows != $total)) { - $message_total = Message::notice( - $pre_count . __('%1$d total, %2$d in query') - ); - $message_total->addParam($total); - $message_total->addParam($unlim_num_rows); - } else { - $message_total = Message::notice($pre_count . __('%d total')); - $message_total->addParam($total); - } - - if (! empty($after_count)) { - $message_total->addHtml($after_count); - } - $message->addMessage($message_total, ''); - - $message->addText(', ', ''); - } - - $message_qt = Message::notice(__('Query took %01.4f seconds.') . ')'); - $message_qt->addParam($this->__get('querytime')); - - $message->addMessage($message_qt, ''); - if ($sorted_column_message !== null) { - $message->addHtml($sorted_column_message, ''); - } - - return $message; - } - - /** - * 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(array &$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 = $this->relation->getForeigners( - $this->__get('db'), - $this->__get('table'), - '', - self::POSITION_BOTH - ); - - if (! empty($exist_rel)) { - foreach ($exist_rel as $master_field => $rel) { - if ($master_field != 'foreign_keys_data') { - $display_field = $this->relation->getDisplayField( - $rel['foreign_db'], - $rel['foreign_table'] - ); - $map[$master_field] = [ - $rel['foreign_table'], - $rel['foreign_field'], - $display_field, - $rel['foreign_db'], - ]; - } else { - foreach ($rel as $key => $one_key) { - foreach ($one_key['index_list'] as $index => $one_field) { - $display_field = $this->relation->getDisplayField( - isset($one_key['ref_db_name']) - ? $one_key['ref_db_name'] - : $GLOBALS['db'], - $one_key['ref_table_name'] - ); - - $map[$one_field] = [ - $one_key['ref_table_name'], - $one_key['ref_index_list'][$index], - $display_field, - isset($one_key['ref_db_name']) - ? $one_key['ref_db_name'] - : $GLOBALS['db'], - ]; - } - } - } - } - } - } - - /** - * 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_results analyzed sql results - * @param string $del_link the display element - 'del_link' - * - * @return string html content - * - * @access private - * - * @see getTable() - */ - private function _getMultiRowOperationLinks( - &$dt_result, - array $analyzed_sql_results, - $del_link - ) { - $links_html = '\n"; - - $links_html .= '' - . "\n"; - - if (! empty($url_query)) { - $links_html .= '' . "\n"; - } - - // fetch last row of the result set - $GLOBALS['dbi']->dataSeek($dt_result, $this->__get('num_rows') - 1); - $row = $GLOBALS['dbi']->fetchRow($dt_result); - - // @see DbiMysqi::fetchRow & DatabaseInterface::fetchRow - if (! is_array($row)) { - $row = []; - } - - // $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) - = Util::getUniqueCondition( - $dt_result, // handle - $this->__get('fields_cnt'), // fields_cnt - $this->__get('fields_meta'), // fields_meta - $row, // row - false, // force_unique - false, // restrict_to_table - $analyzed_sql_results // analyzed_sql_results - ); - unset($where_clause, $condition_array); - - // reset to first row for the loop in _getTableBody() - $GLOBALS['dbi']->dataSeek($dt_result, 0); - - $links_html .= '' . "\n"; - - $links_html .= '' . "\n"; - - return $links_html; - } - - /** - * Generates HTML to display the Create view in span tag - * - * @param array $analyzed_sql_results analyzed sql results - * @param string $url_query String with URL Parameters - * - * @return string - * - * @access private - * - * @see _getResultsOperations() - */ - private function _getLinkForCreateView(array $analyzed_sql_results, $url_query) - { - $results_operations_html = ''; - if (empty($analyzed_sql_results['procedure'])) { - $results_operations_html .= '' - . Util::linkOrButton( - 'view_create.php' . $url_query, - Util::getIcon( - 'b_view_add', - __('Create view'), - true - ), - ['class' => 'create_view ajax'] - ) - . '' . "\n"; - } - return $results_operations_html; - } - - /** - * Calls the _getResultsOperations with $only_view as true - * - * @param array $analyzed_sql_results analyzed sql results - * - * @return string - * - * @access public - * - */ - public function getCreateViewQueryResultOp(array $analyzed_sql_results) - { - $results_operations_html = ''; - //calling to _getResultOperations with a fake $displayParts - //and setting only_view parameter to be true to generate just view - $results_operations_html .= $this->_getResultsOperations( - [], - $analyzed_sql_results, - true - ); - return $results_operations_html; - } - - /** - * Get copy to clipboard links for results operations - * - * @return string - * - * @access private - */ - private function _getCopytoclipboardLinks() - { - return Util::linkOrButton( - '#', - Util::getIcon( - 'b_insrow', - __('Copy to clipboard'), - true - ), - ['id' => 'copyToClipBoard'] - ); - } - - /** - * Get printview links for results operations - * - * @return string - * - * @access private - */ - private function _getPrintviewLinks() - { - return Util::linkOrButton( - '#', - Util::getIcon( - 'b_print', - __('Print'), - true - ), - ['id' => 'printView'], - 'print_view' - ); - } - - /** - * Get operations that are available on results. - * - * @param array $displayParts the parts to display - * @param array $analyzed_sql_results analyzed sql results - * @param boolean $only_view Whether to show only view - * - * @return string html content - * - * @access private - * - * @see getTable() - */ - private function _getResultsOperations( - array $displayParts, - array $analyzed_sql_results, - $only_view = false - ) { - global $printview; - - $results_operations_html = ''; - $fields_meta = $this->__get('fields_meta'); // To safe use in foreach - $header_shown = false; - $header = '
'; - } - return $results_operations_html; - } - - // Displays "printable view" link if required - if ($displayParts['pview_lnk'] == '1') { - $results_operations_html .= $this->_getPrintviewLinks(); - $results_operations_html .= $this->_getCopytoclipboardLinks(); - } // 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 \PhpMyAdmin\Export->getDisplay() - // 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 (($analyzed_sql_results['querytype'] == self::QUERY_TYPE_SELECT) - && ! isset($printview) - && empty($analyzed_sql_results['procedure']) - ) { - if (count($analyzed_sql_results['select_tables']) === 1) { - $_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'] = $GLOBALS['dbi']->fetchValue("SHOW TABLES"); - /* No result (probably no database selected) */ - if ($_url_params['table'] === false) { - unset($_url_params['table']); - } - } - - $results_operations_html .= Util::linkOrButton( - 'tbl_export.php' . Url::getCommon($_url_params), - Util::getIcon( - 'b_tblexport', - __('Export'), - true - ) - ) - . "\n"; - - // prepare chart - $results_operations_html .= Util::linkOrButton( - 'tbl_chart.php' . Url::getCommon($_url_params), - Util::getIcon( - 'b_chart', - __('Display chart'), - true - ) - ) - . "\n"; - - // prepare GIS chart - $geometry_found = false; - // If at least 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 - .= Util::linkOrButton( - 'tbl_gis_visualization.php' - . Url::getCommon($_url_params), - Util::getIcon( - 'b_globe', - __('Visualize GIS data'), - true - ) - ) - . "\n"; - } - } - - // CREATE VIEW - /** - * - * @todo detect privileges to create a view - * (but see 2006-01-19 note in PhpMyAdmin\Display\CreateTable, - * 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; - } - - $results_operations_html .= $this->_getLinkForCreateView( - $analyzed_sql_results, - $url_query - ); - - if ($header_shown) { - $results_operations_html .= '
'; - } - - return $results_operations_html; - } - - /** - * Verifies what to do with non-printable contents (binary or BLOB) - * in Browse mode. - * - * @param string $category BLOB|BINARY|GEOMETRY - * @param string|null $content the binary content - * @param mixed $transformation_plugin transformation plugin. - * Can also be the - * default function: - * Core::mimeDefaultFunction - * @param string $transform_options transformation parameters - * @param string $default_function default transformation function - * @param stdClass $meta the meta-information about the field - * @param array $url_params parameters that should go to the - * download link - * @param boolean $is_truncated the result is truncated or not - * - * @return mixed string or float - * - * @access private - * - * @see _getDataCellForGeometryColumns(), - * _getDataCellForNonNumericColumns(), - * _getSortedColumnMessage() - */ - private function _handleNonPrintableContents( - $category, - ?string $content, - $transformation_plugin, - $transform_options, - $default_function, - $meta, - array $url_params = [], - &$is_truncated = null - ) { - $is_truncated = false; - $result = '[' . $category; - - if (isset($content)) { - $size = strlen($content); - $display_size = Util::formatByteDown($size, 3, 1); - $result .= ' - ' . $display_size[0] . ' ' . $display_size[1]; - } else { - $result .= ' - NULL'; - $size = 0; - } - - $result .= ']'; - - // if we want to use a text transformation on a BLOB column - if (gettype($transformation_plugin) === "object") { - $posMimeOctetstream = strpos( - $transformation_plugin->getMIMESubtype(), - 'Octetstream' - ); - $posMimeText = strpos($transformation_plugin->getMIMEtype(), 'Text'); - if ($posMimeOctetstream - || $posMimeText !== false - ) { - // Applying Transformations on hex string of binary data - // seems more appropriate - $result = pack("H*", bin2hex($content)); - } - } - - if ($size <= 0) { - return $result; - } - - if ($default_function != $transformation_plugin) { - $result = $transformation_plugin->applyTransformation( - $result, - $transform_options, - $meta - ); - return $result; - } - - $result = $default_function($result, [], $meta); - if (($_SESSION['tmpval']['display_binary'] - && $meta->type === self::STRING_FIELD) - || ($_SESSION['tmpval']['display_blob'] - && false !== stripos($meta->type, self::BLOB_FIELD)) - ) { - // in this case, restart from the original $content - if (mb_check_encoding($content, 'utf-8') - && ! preg_match('/[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\x9F]/u', $content) - ) { - // show as text if it's valid utf-8 - $result = htmlspecialchars($content); - } else { - $result = '0x' . bin2hex($content); - } - list( - $is_truncated, - $result, - // skip 3rd param - ) = $this->_getPartialText($result); - } - - /* Create link to download */ - - // in PHP < 5.5, empty() only checks variables - $tmpdb = $this->__get('db'); - if (count($url_params) > 0 - && (! empty($tmpdb) && ! empty($meta->orgtable)) - ) { - $result = '
' - . $result . ''; - } - - return $result; - } - - /** - * Retrieves the associated foreign key info for a data cell - * - * @param array $map the list of relations - * @param stdClass $meta the meta-information about the field - * @param string $where_comparison data for the where clause - * - * @return string formatted data - * - * @access private - * - */ - private function _getFromForeign(array $map, $meta, $where_comparison) - { - $dispsql = 'SELECT ' - . Util::backquote($map[$meta->name][2]) - . ' FROM ' - . Util::backquote($map[$meta->name][3]) - . '.' - . Util::backquote($map[$meta->name][0]) - . ' WHERE ' - . Util::backquote($map[$meta->name][1]) - . $where_comparison; - - $dispresult = $GLOBALS['dbi']->tryQuery( - $dispsql, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - - if ($dispresult && $GLOBALS['dbi']->numRows($dispresult) > 0) { - list($dispval) = $GLOBALS['dbi']->fetchRow($dispresult, 0); - } else { - $dispval = __('Link not found!'); - } - - $GLOBALS['dbi']->freeResult($dispresult); - - return $dispval; - } - - /** - * 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 array $analyzed_sql_results the analyzed query - * @param stdClass $meta the meta-information about the - * field - * @param array $map the list of relations - * @param string $data data - * @param string $displayedData data that will be displayed (maybe be chunked) - * @param TransformationsPlugin $transformation_plugin transformation plugin. - * Can also be the default function: - * Core::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 options for transformation - * @param bool $is_field_truncated whether the field is truncated - * @param string $original_length of a truncated column, or '' - * - * @return string formatted data - * - * @access private - * - * @see _getDataCellForNumericColumns(), _getDataCellForGeometryColumns(), - * _getDataCellForNonNumericColumns(), - * - */ - private function _getRowData( - $class, - $condition_field, - array $analyzed_sql_results, - $meta, - array $map, - $data, - $displayedData, - $transformation_plugin, - $default_function, - $nowrap, - $where_comparison, - array $transform_options, - $is_field_truncated, - $original_length = '' - ) { - $relational_display = $_SESSION['tmpval']['relational_display']; - $printview = $this->__get('printview'); - $decimals = isset($meta->decimals) ? $meta->decimals : '-1'; - $result = '_addClass( - $class, - $condition_field, - $meta, - $nowrap, - $is_field_truncated, - $transformation_plugin, - $default_function - ) - . '">'; - - if (! empty($analyzed_sql_results['statement']->expr)) { - foreach ($analyzed_sql_results['statement']->expr as $expr) { - if (empty($expr->alias) || empty($expr->column)) { - continue; - } - if (strcasecmp($meta->name, $expr->alias) == 0) { - $meta->name = $expr->column; - } - } - } - - if (isset($map[$meta->name])) { - // Field to display from the foreign table? - if (isset($map[$meta->name][2]) - && strlen((string) $map[$meta->name][2]) > 0 - ) { - $dispval = $this->_getFromForeign( - $map, - $meta, - $where_comparison - ); - } else { - $dispval = ''; - } // end if... else... - - if (isset($printview) && ($printview == '1')) { - $result .= ($transformation_plugin != $default_function - ? $transformation_plugin->applyTransformation( - $data, - $transform_options, - $meta - ) - : $default_function($data) - ) - . ' [->' . $dispval . ']'; - } else { - if ($relational_display == self::RELATIONAL_KEY) { - // user chose "relational key" in the display options, so - // the title contains the display field - $title = ! empty($dispval) - ? htmlspecialchars($dispval) - : ''; - } else { - $title = htmlspecialchars($data); - } - - $sqlQuery = 'SELECT * FROM ' - . Util::backquote($map[$meta->name][3]) . '.' - . Util::backquote($map[$meta->name][0]) - . ' WHERE ' - . Util::backquote($map[$meta->name][1]) - . $where_comparison; - - $_url_params = [ - 'db' => $map[$meta->name][3], - 'table' => $map[$meta->name][0], - 'pos' => '0', - 'sql_signature' => Core::signSqlQuery($sqlQuery), - 'sql_query' => $sqlQuery, - ]; - - if ($transformation_plugin != $default_function) { - // always apply a transformation on the real data, - // not on the display field - $displayedData = $transformation_plugin->applyTransformation( - $data, - $transform_options, - $meta - ); - } else { - if ($relational_display == self::RELATIONAL_DISPLAY_COLUMN - && ! empty($map[$meta->name][2]) - ) { - // user chose "relational display field" in the - // display options, so show display field in the cell - $displayedData = $default_function($dispval); - } else { - // otherwise display data in the cell - $displayedData = $default_function($displayedData); - } - } - - $tag_params = ['title' => $title]; - if (strpos($class, 'grid_edit') !== false) { - $tag_params['class'] = 'ajax'; - } - $result .= Util::linkOrButton( - 'sql.php' . Url::getCommon($_url_params), - $displayedData, - $tag_params - ); - } - } else { - $result .= ($transformation_plugin != $default_function - ? $transformation_plugin->applyTransformation( - $data, - $transform_options, - $meta - ) - : $default_function($data) - ); - } - - $result .= '' . "\n"; - - return $result; - } - - /** - * Prepares a checkbox for multi-row submits - * - * @param string $del_url delete url - * @param array $displayParts 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 $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, - array $displayParts, - $row_no, - $where_clause_html, - array $condition_array, - $id_suffix, - $class - ) { - $ret = ''; - - if (! empty($del_url) && $displayParts['del_lnk'] != self::KILL_PROCESS) { - $ret .= '' - . '' - . ' '; - } - - return $ret; - } - - /** - * 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 .= '' - . '' - . Util::linkOrButton($edit_url, $edit_str); - /* - * 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; - } - - /** - * 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 .= '' - . Util::linkOrButton($copy_url, $copy_str); - - /* - * 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; - } - - /** - * 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)) { - return $ret; - } - - $ret .= '' - . Util::linkOrButton( - $del_url, - $del_str, - ['class' => 'delete_row requireConfirm' . $ajax] - ) - . '
' . $js_conf . '
' - . ''; - - return $ret; - } - - /** - * 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 $displayParts 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 $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, - array $displayParts, - $row_no, - $where_clause, - $where_clause_html, - array $condition_array, - $edit_url, - $copy_url, - $class, - $edit_str, - $copy_str, - $del_str, - $js_conf - ) { - $ret = ''; - - if ($position == self::POSITION_LEFT) { - $ret .= $this->_getCheckboxForMultiRowSubmissions( - $del_url, - $displayParts, - $row_no, - $where_clause_html, - $condition_array, - '_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, - $displayParts, - $row_no, - $where_clause_html, - $condition_array, - '_right', - '' - ); - } else { // $position == self::POSITION_NONE - $ret .= $this->_getCheckboxForMultiRowSubmissions( - $del_url, - $displayParts, - $row_no, - $where_clause_html, - $condition_array, - '_left', - '' - ); - } - - return $ret; - } - - /** - * Truncates given string based on LimitChars configuration - * and Session pftext variable - * (string is truncated only if necessary) - * - * @param string $str string to be truncated - * - * @return mixed - * - * @access private - * - * @see _handleNonPrintableContents(), _getDataCellForGeometryColumns(), - * _getDataCellForNonNumericColumns - */ - private function _getPartialText($str) - { - $original_length = mb_strlen($str); - if ($original_length > $GLOBALS['cfg']['LimitChars'] - && $_SESSION['tmpval']['pftext'] === self::DISPLAY_PARTIAL_TEXT - ) { - $str = mb_substr( - $str, - 0, - (int) $GLOBALS['cfg']['LimitChars'] - ) . '...'; - $truncated = true; - } else { - $truncated = false; - } - - return [ - $truncated, - $str, - $original_length, - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Encoding.php b/srcs/phpmyadmin/libraries/classes/Encoding.php deleted file mode 100644 index 32715f3..0000000 --- a/srcs/phpmyadmin/libraries/classes/Encoding.php +++ /dev/null @@ -1,358 +0,0 @@ - [ - 'iconv', - self::ENGINE_ICONV, - 'iconv', - ], - 'recode' => [ - 'recode_string', - self::ENGINE_RECODE, - 'recode', - ], - 'mb' => [ - 'mb_convert_encoding', - self::ENGINE_MB, - 'mbstring', - ], - 'none' => [ - 'isset', - self::ENGINE_NONE, - '', - ], - ]; - - /** - * Order of automatic detection of engines - * - * @var array - */ - private static $_engineorder = [ - 'iconv', - 'mb', - 'recode', - ]; - - /** - * Kanji encodings list - * - * @var string - */ - private static $_kanji_encodings = 'ASCII,SJIS,EUC-JP,JIS'; - - /** - * Initializes encoding engine detecting available backends. - * - * @return void - */ - public static function initEngine(): void - { - $engine = 'auto'; - if (isset($GLOBALS['cfg']['RecodingEngine'])) { - $engine = $GLOBALS['cfg']['RecodingEngine']; - } - - /* Use user configuration */ - if (isset(self::$_enginemap[$engine])) { - if (function_exists(self::$_enginemap[$engine][0])) { - self::$_engine = self::$_enginemap[$engine][1]; - return; - } else { - Core::warnMissingExtension(self::$_enginemap[$engine][2]); - } - } - - /* Autodetection */ - foreach (self::$_engineorder as $engine) { - if (function_exists(self::$_enginemap[$engine][0])) { - self::$_engine = self::$_enginemap[$engine][1]; - return; - } - } - - /* Fallback to none conversion */ - self::$_engine = self::ENGINE_NONE; - } - - /** - * Setter for engine. Use with caution, mostly useful for testing. - * - * @param int $engine Engine encoding - * - * @return void - */ - public static function setEngine(int $engine): void - { - self::$_engine = $engine; - } - - /** - * Checks whether there is any charset conversion supported - * - * @return bool - */ - public static function isSupported(): bool - { - if (self::$_engine === null) { - self::initEngine(); - } - return self::$_engine != self::ENGINE_NONE; - } - - /** - * Converts encoding of text according to parameters with detected - * conversion function. - * - * @param string $src_charset source charset - * @param string $dest_charset target charset - * @param string $what what to convert - * - * @return string converted text - * - * @access public - */ - public static function convertString( - string $src_charset, - string $dest_charset, - string $what - ): string { - if ($src_charset == $dest_charset) { - return $what; - } - if (self::$_engine === null) { - self::initEngine(); - } - switch (self::$_engine) { - case self::ENGINE_RECODE: - return recode_string( - $src_charset . '..' . $dest_charset, - $what - ); - case self::ENGINE_ICONV: - return iconv( - $src_charset, - $dest_charset . - (isset($GLOBALS['cfg']['IconvExtraParams']) ? $GLOBALS['cfg']['IconvExtraParams'] : ''), - $what - ); - case self::ENGINE_MB: - return mb_convert_encoding( - $what, - $dest_charset, - $src_charset - ); - default: - return $what; - } - } - - /** - * Detects whether Kanji encoding is available - * - * @return bool - */ - public static function canConvertKanji(): bool - { - return $GLOBALS['lang'] == 'ja'; - } - - /** - * Setter for Kanji encodings. Use with caution, mostly useful for testing. - * - * @return string - */ - public static function getKanjiEncodings(): string - { - return self::$_kanji_encodings; - } - - /** - * Setter for Kanji encodings. Use with caution, mostly useful for testing. - * - * @param string $value Kanji encodings list - * - * @return void - */ - public static function setKanjiEncodings(string $value): void - { - self::$_kanji_encodings = $value; - } - - /** - * Reverses SJIS & EUC-JP position in the encoding codes list - * - * @return void - */ - public static function kanjiChangeOrder(): void - { - $parts = explode(',', self::$_kanji_encodings); - if ($parts[1] == 'EUC-JP') { - self::$_kanji_encodings = 'ASCII,SJIS,EUC-JP,JIS'; - } else { - self::$_kanji_encodings = 'ASCII,EUC-JP,SJIS,JIS'; - } - } - - /** - * Kanji string encoding convert - * - * @param string $str the string to convert - * @param string $enc the destination encoding code - * @param string $kana set 'kana' convert to JIS-X208-kana - * - * @return string the converted string - */ - public static function kanjiStrConv(string $str, string $enc, string $kana): string - { - if ($enc == '' && $kana == '') { - return $str; - } - - $string_encoding = mb_detect_encoding($str, self::$_kanji_encodings); - if ($string_encoding === false) { - $string_encoding = 'utf-8'; - } - - if ($kana == 'kana') { - $dist = mb_convert_kana($str, 'KV', $string_encoding); - $str = $dist; - } - if ($string_encoding != $enc && $enc != '') { - $dist = mb_convert_encoding($str, $enc, $string_encoding); - } else { - $dist = $str; - } - return $dist; - } - - - /** - * Kanji file encoding convert - * - * @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 - */ - public static function kanjiFileConv(string $file, string $enc, string $kana): string - { - if ($enc == '' && $kana == '') { - return $file; - } - $tmpfname = tempnam($GLOBALS['PMA_Config']->getUploadTempDir(), $enc); - $fpd = fopen($tmpfname, 'wb'); - $fps = fopen($file, 'r'); - self::kanjiChangeOrder(); - while (! feof($fps)) { - $line = fgets($fps, 4096); - $dist = self::kanjiStrConv($line, $enc, $kana); - fwrite($fpd, $dist); - } // end while - self::kanjiChangeOrder(); - fclose($fps); - fclose($fpd); - unlink($file); - - return $tmpfname; - } - - /** - * Defines radio form fields to switch between encoding modes - * - * @return string HTML code for the radio controls - */ - public static function kanjiEncodingForm(): string - { - $template = new Template(); - return $template->render('encoding/kanji_encoding_form'); - } - - /** - * Lists available encodings. - * - * @return array - */ - public static function listEncodings(): array - { - if (self::$_engine === null) { - self::initEngine(); - } - /* Most engines do not support listing */ - if (self::$_engine != self::ENGINE_MB) { - return $GLOBALS['cfg']['AvailableCharsets']; - } - - return array_intersect( - array_map('strtolower', mb_list_encodings()), - $GLOBALS['cfg']['AvailableCharsets'] - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Engines/Bdb.php b/srcs/phpmyadmin/libraries/classes/Engines/Bdb.php deleted file mode 100644 index 70919e3..0000000 --- a/srcs/phpmyadmin/libraries/classes/Engines/Bdb.php +++ /dev/null @@ -1,76 +0,0 @@ - [ - 'title' => __('Version information'), - ], - 'bdb_cache_size' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, - ], - 'bdb_home' => [], - 'bdb_log_buffer_size' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, - ], - 'bdb_logdir' => [], - 'bdb_max_lock' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, - ], - 'bdb_shared_data' => [], - 'bdb_tmpdir' => [], - 'bdb_data_direct' => [], - 'bdb_lock_detect' => [], - 'bdb_log_direct' => [], - 'bdb_no_recover' => [], - 'bdb_no_sync' => [], - 'skip_sync_bdb_logs' => [], - 'sync_bdb_logs' => [], - ]; - } - - /** - * Returns the pattern to be used in the query for SQL variables - * related to this storage engine - * - * @return string LIKE pattern - */ - public function getVariablesLikePattern() - { - return '%bdb%'; - } - - /** - * returns string with filename for the MySQL helppage - * about this storage engine - * - * @return string mysql helppage filename - */ - public function getMysqlHelpPage() - { - return 'bdb'; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Engines/Berkeleydb.php b/srcs/phpmyadmin/libraries/classes/Engines/Berkeleydb.php deleted file mode 100644 index 0c69d5f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Engines/Berkeleydb.php +++ /dev/null @@ -1,19 +0,0 @@ - [ - 'title' => __('Data home directory'), - 'desc' => __( - 'The common part of the directory path for all InnoDB data ' - . 'files.' - ), - ], - 'innodb_data_file_path' => [ - 'title' => __('Data files'), - ], - 'innodb_autoextend_increment' => [ - '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' => [ - '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' => [ - 'title' => 'innodb_additional_mem_pool_size', - 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, - ], - 'innodb_buffer_pool_awe_mem_mb' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, - ], - 'innodb_checksums' => [], - 'innodb_commit_concurrency' => [], - 'innodb_concurrency_tickets' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, - ], - 'innodb_doublewrite' => [], - 'innodb_fast_shutdown' => [], - 'innodb_file_io_threads' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, - ], - 'innodb_file_per_table' => [], - 'innodb_flush_log_at_trx_commit' => [], - 'innodb_flush_method' => [], - 'innodb_force_recovery' => [], - 'innodb_lock_wait_timeout' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, - ], - 'innodb_locks_unsafe_for_binlog' => [], - 'innodb_log_arch_dir' => [], - 'innodb_log_archive' => [], - 'innodb_log_buffer_size' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, - ], - 'innodb_log_file_size' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, - ], - 'innodb_log_files_in_group' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, - ], - 'innodb_log_group_home_dir' => [], - 'innodb_max_dirty_pages_pct' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, - ], - 'innodb_max_purge_lag' => [], - 'innodb_mirrored_log_groups' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, - ], - 'innodb_open_files' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, - ], - 'innodb_support_xa' => [], - 'innodb_sync_spin_loops' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, - ], - 'innodb_table_locks' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_BOOLEAN, - ], - 'innodb_thread_concurrency' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC, - ], - 'innodb_thread_sleep_delay' => [ - '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 - */ - public function getVariablesLikePattern() - { - return 'innodb\\_%'; - } - - /** - * Get information pages - * - * @return array detail pages - */ - public function getInfoPages() - { - if ($this->support < PMA_ENGINE_SUPPORT_YES) { - return []; - } - $pages = []; - $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 - */ - public 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 = $GLOBALS['dbi']->fetchResult($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" - . ' : ' - . Util::formatNumber( - $status['Innodb_buffer_pool_pages_total'], - 0 - ) - . ' ' . __('pages') - . ' / ' - . implode( - ' ', - Util::formatByteDown( - $status['Innodb_buffer_pool_pages_total'] - * $status['Innodb_page_size'] - ) - ) . "\n" - . '
' . __('Free pages') . '' - . Util::formatNumber( - $status['Innodb_buffer_pool_pages_free'], - 0 - ) - . '
' . __('Dirty pages') . '' - . Util::formatNumber( - $status['Innodb_buffer_pool_pages_dirty'], - 0 - ) - . '
' . __('Pages containing data') . '' - . Util::formatNumber( - $status['Innodb_buffer_pool_pages_data'], - 0 - ) . "\n" - . '
' . __('Pages to be flushed') . '' - . Util::formatNumber( - $status['Innodb_buffer_pool_pages_flushed'], - 0 - ) . "\n" - . '
' . __('Busy pages') . '' - . Util::formatNumber( - $status['Innodb_buffer_pool_pages_misc'], - 0 - ) . "\n" - . '
' . __('Latched pages') . '' - . 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') . '' - . Util::formatNumber( - $status['Innodb_buffer_pool_read_requests'], - 0 - ) . "\n" - . '
' . __('Write requests') . '' - . Util::formatNumber( - $status['Innodb_buffer_pool_write_requests'], - 0 - ) . "\n" - . '
' . __('Read misses') . '' - . Util::formatNumber( - $status['Innodb_buffer_pool_reads'], - 0 - ) . "\n" - . '
' . __('Write waits') . '' - . Util::formatNumber( - $status['Innodb_buffer_pool_wait_free'], - 0 - ) . "\n" - . '
' . __('Read misses in %') . '' - . ($status['Innodb_buffer_pool_read_requests'] == 0 - ? '---' - : htmlspecialchars( - 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( - 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 ENGINE INNODB STATUS inside pre tags - */ - public function getPageStatus() - { - return '
' . "\n"
-            . htmlspecialchars((string) $GLOBALS['dbi']->fetchValue(
-                'SHOW ENGINE INNODB STATUS;',
-                0,
-                'Status'
-            )) . "\n" . '
' . "\n"; - } - - /** - * returns string with filename for the MySQL helppage - * about this storage engine - * - * @return string mysql helppage filename - */ - public function getMysqlHelpPage() - { - return 'innodb-storage-engine'; - } - - /** - * Gets the InnoDB plugin version number - * - * @return string the version number, or empty if not running as a plugin - */ - public function getInnodbPluginVersion() - { - return $GLOBALS['dbi']->fetchValue('SELECT @@innodb_version;'); - } - - /** - * Gets the InnoDB file format - * - * (do not confuse this with phpMyAdmin's storage engine plugins!) - * - * @return string the InnoDB file format - */ - public function getInnodbFileFormat() - { - return $GLOBALS['dbi']->fetchValue( - "SHOW GLOBAL VARIABLES LIKE 'innodb_file_format';", - 0, - 1 - ); - } - - /** - * Verifies if this server supports the innodb_file_per_table feature - * - * (do not confuse this with phpMyAdmin's storage engine plugins!) - * - * @return boolean whether this feature is supported or not - */ - public function supportsFilePerTable() - { - return ( - $GLOBALS['dbi']->fetchValue( - "SHOW GLOBAL VARIABLES LIKE 'innodb_file_per_table';", - 0, - 1 - ) == 'ON' - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Engines/Memory.php b/srcs/phpmyadmin/libraries/classes/Engines/Memory.php deleted file mode 100644 index d01a63e..0000000 --- a/srcs/phpmyadmin/libraries/classes/Engines/Memory.php +++ /dev/null @@ -1,34 +0,0 @@ - [ - 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, - ], - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Engines/Merge.php b/srcs/phpmyadmin/libraries/classes/Engines/Merge.php deleted file mode 100644 index c4bee94..0000000 --- a/srcs/phpmyadmin/libraries/classes/Engines/Merge.php +++ /dev/null @@ -1,21 +0,0 @@ - [ - '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' => [ - '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' => [ - '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' => [ - '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' => [ - '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' => [ - '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' => [], - 'delay_key_write' => [], - 'bulk_insert_buffer_size' => [ - 'type' => PMA_ENGINE_DETAILS_TYPE_SIZE, - ], - 'skip_external_locking' => [], - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Engines/Ndbcluster.php b/srcs/phpmyadmin/libraries/classes/Engines/Ndbcluster.php deleted file mode 100644 index bd331bf..0000000 --- a/srcs/phpmyadmin/libraries/classes/Engines/Ndbcluster.php +++ /dev/null @@ -1,54 +0,0 @@ - [], - ]; - } - - /** - * Returns the pattern to be used in the query for SQL variables - * related to NDBCLUSTER storage engine - * - * @return string SQL query LIKE pattern - */ - public function getVariablesLikePattern() - { - return 'ndb\\_%'; - } - - /** - * Returns string with filename for the MySQL help page - * about this storage engine - * - * @return string mysql helppage filename - */ - public function getMysqlHelpPage() - { - return 'ndbcluster'; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Engines/Pbxt.php b/srcs/phpmyadmin/libraries/classes/Engines/Pbxt.php deleted file mode 100644 index 9aa101a..0000000 --- a/srcs/phpmyadmin/libraries/classes/Engines/Pbxt.php +++ /dev/null @@ -1,195 +0,0 @@ - [ - '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' => [ - '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' => [ - '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' => [ - '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' => [ - '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' => [ - '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' => [ - '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' => [ - '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' => [ - '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' => [ - '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' => [ - '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' => [ - '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 array the formatted value and its unit - */ - public function resolveTypeSize($formatted_size) - { - if (preg_match('/^[0-9]+[a-zA-Z]+$/', $formatted_size)) { - $value = Util::extractValueFromFormattedSize( - $formatted_size - ); - } else { - $value = $formatted_size; - } - - return Util::formatByteDown($value); - } - - //-------------------- - /** - * Get information about pages - * - * @return array Information about pages - */ - public function getInfoPages() - { - $pages = []; - $pages['Documentation'] = __('Documentation'); - - return $pages; - } - - //-------------------- - /** - * Get content of documentation page - * - * @return string - */ - public function getPageDocumentation() - { - $output = '

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

' . "\n"; - - return $output; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Engines/PerformanceSchema.php b/srcs/phpmyadmin/libraries/classes/Engines/PerformanceSchema.php deleted file mode 100644 index 01669b4..0000000 --- a/srcs/phpmyadmin/libraries/classes/Engines/PerformanceSchema.php +++ /dev/null @@ -1,31 +0,0 @@ - 'Internal error', - E_ERROR => '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_USER_DEPRECATED => 'Deprecation Notice', - E_RECOVERABLE_ERROR => 'Catchable Fatal Error', - ]; - - /** - * Error levels - * - * @var array - */ - public static $errorlevel = [ - 0 => 'error', - 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_USER_DEPRECATED => 'notice', - E_RECOVERABLE_ERROR => 'error', - ]; - - /** - * The file in which the error occurred - * - * @var string - */ - protected $file = ''; - - /** - * The line in which the error occurred - * - * @var integer - */ - protected $line = 0; - - /** - * Holds the backtrace for this error - * - * @var array - */ - protected $backtrace = []; - - /** - * Hide location of errors - */ - protected $hide_location = false; - - /** - * Constructor - * - * @param integer $errno error number - * @param string $errstr error message - * @param string $errfile file - * @param integer $errline line - */ - public function __construct(int $errno, string $errstr, string $errfile, int $errline) - { - parent::__construct(); - $this->setNumber($errno); - $this->setMessage($errstr, false); - $this->setFile($errfile); - $this->setLine($errline); - - // This function can be disabled in php.ini - if (function_exists('debug_backtrace')) { - $backtrace = @debug_backtrace(); - // remove last three calls: - // debug_backtrace(), handleError() and addError() - $backtrace = array_slice($backtrace, 3); - } else { - $backtrace = []; - } - - $this->setBacktrace($backtrace); - } - - /** - * Process backtrace to avoid path disclossures, objects and so on - * - * @param array $backtrace backtrace - * - * @return array - */ - public static function processBacktrace(array $backtrace): array - { - $result = []; - - $members = [ - 'line', - 'function', - 'class', - 'type', - ]; - - foreach ($backtrace as $idx => $step) { - /* Create new backtrace entry */ - $result[$idx] = []; - - /* Make path relative */ - if (isset($step['file'])) { - $result[$idx]['file'] = self::relPath($step['file']); - } - - /* Store members we want */ - foreach ($members as $name) { - if (isset($step[$name])) { - $result[$idx][$name] = $step[$name]; - } - } - - /* Store simplified args */ - if (isset($step['args'])) { - foreach ($step['args'] as $key => $arg) { - $result[$idx]['args'][$key] = self::getArg($arg, $step['function']); - } - } - } - - return $result; - } - - /** - * Toggles location hiding - * - * @param boolean $hide Whether to hide - * - * @return void - */ - public function setHideLocation(bool $hide): void - { - $this->hide_location = $hide; - } - - /** - * sets PhpMyAdmin\Error::$_backtrace - * - * We don't store full arguments to avoid wakeup or memory problems. - * - * @param array $backtrace backtrace - * - * @return void - */ - public function setBacktrace(array $backtrace): void - { - $this->backtrace = self::processBacktrace($backtrace); - } - - /** - * sets PhpMyAdmin\Error::$_line - * - * @param integer $line the line - * - * @return void - */ - public function setLine(int $line): void - { - $this->line = $line; - } - - /** - * sets PhpMyAdmin\Error::$_file - * - * @param string $file the file - * - * @return void - */ - public function setFile(string $file): void - { - $this->file = self::relPath($file); - } - - - /** - * returns unique PhpMyAdmin\Error::$hash, if not exists it will be created - * - * @return string PhpMyAdmin\Error::$hash - */ - public function getHash(): string - { - 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 PhpMyAdmin\Error::$_backtrace for first $count frames - * pass $count = -1 to get full backtrace. - * The same can be done by not passing $count at all. - * - * @param integer $count Number of stack frames. - * - * @return array PhpMyAdmin\Error::$_backtrace - */ - public function getBacktrace(int $count = -1): array - { - if ($count != -1) { - return array_slice($this->backtrace, 0, $count); - } - return $this->backtrace; - } - - /** - * returns PhpMyAdmin\Error::$file - * - * @return string PhpMyAdmin\Error::$file - */ - public function getFile(): string - { - return $this->file; - } - - /** - * returns PhpMyAdmin\Error::$line - * - * @return integer PhpMyAdmin\Error::$line - */ - public function getLine(): int - { - return $this->line; - } - - /** - * returns type of error - * - * @return string type of error - */ - public function getType(): string - { - return self::$errortype[$this->getNumber()]; - } - - /** - * returns level of error - * - * @return string level of error - */ - public function getLevel(): string - { - return self::$errorlevel[$this->getNumber()]; - } - - /** - * returns title prepared for HTML Title-Tag - * - * @return string HTML escaped and truncated title - */ - public function getHtmlTitle(): string - { - return htmlspecialchars( - mb_substr($this->getTitle(), 0, 100) - ); - } - - /** - * returns title for error - * - * @return string - */ - public function getTitle(): string - { - return $this->getType() . ': ' . $this->getMessage(); - } - - /** - * Get HTML backtrace - * - * @return string - */ - public function getBacktraceDisplay(): string - { - return self::formatBacktrace( - $this->getBacktrace(), - "
\n", - "
\n" - ); - } - - /** - * return formatted backtrace field - * - * @param array $backtrace Backtrace data - * @param string $separator Arguments separator to use - * @param string $lines Lines separator to use - * - * @return string formatted backtrace - */ - public static function formatBacktrace( - array $backtrace, - string $separator, - string $lines - ): string { - $retval = ''; - - foreach ($backtrace as $step) { - if (isset($step['file']) && isset($step['line'])) { - $retval .= self::relPath($step['file']) - . '#' . $step['line'] . ': '; - } - if (isset($step['class'])) { - $retval .= $step['class'] . $step['type']; - } - $retval .= self::getFunctionCall($step, $separator); - $retval .= $lines; - } - - return $retval; - } - - /** - * Formats function call in a backtrace - * - * @param array $step backtrace step - * @param string $separator Arguments separator to use - * - * @return string - */ - public static function getFunctionCall(array $step, string $separator): string - { - $retval = $step['function'] . '('; - if (isset($step['args'])) { - if (count($step['args']) > 1) { - $retval .= $separator; - foreach ($step['args'] as $arg) { - $retval .= "\t"; - $retval .= $arg; - $retval .= ',' . $separator; - } - } elseif (count($step['args']) > 0) { - foreach ($step['args'] as $arg) { - $retval .= $arg; - } - } - } - $retval .= ')'; - 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 argument to process - * @param string $function function name - * - * @return string - */ - public static function getArg($arg, string $function): string - { - $retval = ''; - $include_functions = [ - 'include', - 'include_once', - 'require', - 'require_once', - ]; - $connect_functions = [ - 'mysql_connect', - 'mysql_pconnect', - 'mysqli_connect', - 'mysqli_real_connect', - 'connect', - '_realConnect', - ]; - - if (in_array($function, $include_functions)) { - $retval .= self::relPath($arg); - } elseif (in_array($function, $connect_functions) - && gettype($arg) === 'string' - ) { - $retval .= gettype($arg) . ' ********'; - } elseif (is_scalar($arg)) { - $retval .= gettype($arg) . ' ' - . htmlspecialchars(var_export($arg, true)); - } elseif (is_object($arg)) { - $retval .= ''; - } else { - $retval .= gettype($arg); - } - - return $retval; - } - - /** - * Gets the error as string of HTML - * - * @return string - */ - public function getDisplay(): string - { - $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(): bool - { - return $this->hide_location || - ($this->getNumber() & (E_USER_WARNING | E_USER_ERROR | E_USER_NOTICE)); - } - - /** - * return short relative path to phpMyAdmin basedir - * - * prevent path disclosure in error message, - * and make users feel safe to submit error reports - * - * @param string $path path to be shorten - * - * @return string shortened path - */ - public static function relPath(string $path): string - { - $dest = @realpath($path); - - /* Probably affected by open_basedir */ - if ($dest === false) { - return basename($path); - } - - $Ahere = explode( - DIRECTORY_SEPARATOR, - realpath(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..') - ); - $Adest = explode(DIRECTORY_SEPARATOR, $dest); - - $result = '.'; - // && count ($Adest)>0 && count($Ahere)>0 ) - while (implode(DIRECTORY_SEPARATOR, $Adest) != implode(DIRECTORY_SEPARATOR, $Ahere)) { - if (count($Ahere) > count($Adest)) { - array_pop($Ahere); - $result .= DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..'; - } else { - array_pop($Adest); - } - } - $path = $result . str_replace(implode(DIRECTORY_SEPARATOR, $Adest), '', $dest); - return str_replace( - DIRECTORY_SEPARATOR . PATH_SEPARATOR, - DIRECTORY_SEPARATOR, - $path - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/ErrorHandler.php b/srcs/phpmyadmin/libraries/classes/ErrorHandler.php deleted file mode 100644 index f5cf124..0000000 --- a/srcs/phpmyadmin/libraries/classes/ErrorHandler.php +++ /dev/null @@ -1,604 +0,0 @@ -error_reporting = error_reporting(); - } - } - - /** - * Destructor - * - * stores errors in session - * - */ - public function __destruct() - { - if (isset($_SESSION)) { - if (! isset($_SESSION['errors'])) { - $_SESSION['errors'] = []; - } - - // 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. - */ - if (count($_SESSION['errors']) >= 10) { - $error = new Error( - 0, - __('Too many error messages, some are not displayed.'), - __FILE__, - __LINE__ - ); - $_SESSION['errors'][$error->getHash()] = $error; - break; - } elseif (($error instanceof Error) - && ! $error->isDisplayed() - ) { - $_SESSION['errors'][$key] = $error; - } - } - } - } - - /** - * Toggles location hiding - * - * @param boolean $hide Whether to hide - * - * @return void - */ - public function setHideLocation(bool $hide): void - { - $this->hide_location = $hide; - } - - /** - * returns array with all errors - * - * @param bool $check Whether to check for session errors - * - * @return Error[] - */ - public function getErrors(bool $check = true): array - { - if ($check) { - $this->checkSavedErrors(); - } - return $this->errors; - } - - /** - * returns the errors occurred in the current run only. - * Does not include the errors saved in the SESSION - * - * @return Error[] - */ - public function getCurrentErrors(): array - { - return $this->errors; - } - - /** - * Pops recent errors from the storage - * - * @param int $count Old error count - * - * @return Error[] - */ - public function sliceErrors(int $count): array - { - $errors = $this->getErrors(false); - $this->errors = array_splice($errors, 0, $count); - return array_splice($errors, $count); - } - - /** - * Error handler - called when errors are triggered/occurred - * - * This calls the addError() function, escaping the error string - * Ignores the errors wherever Error Control Operator (@) is used. - * - * @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( - int $errno, - string $errstr, - string $errfile, - int $errline - ): void { - if (function_exists('error_reporting')) { - /** - * Check if Error Control Operator (@) was used, but still show - * user errors even in this case. - */ - if (error_reporting() == 0 && - $this->error_reporting != 0 && - ($errno & (E_USER_WARNING | E_USER_ERROR | E_USER_NOTICE)) == 0 - ) { - return; - } - } else { - if (($errno & (E_USER_WARNING | E_USER_ERROR | E_USER_NOTICE)) == 0) { - return; - } - } - - $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( - string $errstr, - int $errno, - string $errfile, - int $errline, - bool $escape = true - ): void { - if ($escape) { - $errstr = htmlspecialchars($errstr); - } - // create error object - $error = new Error( - $errno, - $errstr, - $errfile, - $errline - ); - $error->setHideLocation($this->hide_location); - - // do not repeat errors - $this->errors[$error->getHash()] = $error; - - switch ($error->getNumber()) { - case E_STRICT: - case E_DEPRECATED: - case E_NOTICE: - case E_WARNING: - case E_CORE_WARNING: - case E_COMPILE_WARNING: - case E_RECOVERABLE_ERROR: - /* Avoid rendering BB code in PHP errors */ - $error->setBBCode(false); - break; - case E_USER_NOTICE: - case E_USER_WARNING: - case E_USER_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, display it and exit - $this->dispFatalError($error); - exit; - } - } - - /** - * trigger a custom error - * - * @param string $errorInfo error message - * @param integer $errorNumber error number - * - * @return void - */ - public function triggerError(string $errorInfo, ?int $errorNumber = null): void - { - // we could also extract file and line from backtrace - // and call handleError() directly - trigger_error($errorInfo, $errorNumber); - } - - /** - * display fatal error and exit - * - * @param Error $error the error - * - * @return void - */ - protected function dispFatalError(Error $error): void - { - if (! headers_sent()) { - $this->dispPageStart($error); - } - $error->display(); - $this->dispPageEnd(); - exit; - } - - /** - * Displays user errors not displayed - * - * @return void - */ - public function dispUserErrors(): void - { - echo $this->getDispUserErrors(); - } - - /** - * Renders user errors not displayed - * - * @return string - */ - public function getDispUserErrors(): string - { - $retval = ''; - foreach ($this->getErrors() as $error) { - if ($error->isUserError() && ! $error->isDisplayed()) { - $retval .= $error->getDisplay(); - } - } - return $retval; - } - - /** - * display HTML header - * - * @param Error $error the error - * - * @return void - */ - protected function dispPageStart(?Error $error = null): void - { - Response::getInstance()->disable(); - echo ''; - if ($error) { - echo $error->getTitle(); - } else { - echo 'phpMyAdmin error reporting page'; - } - echo ''; - } - - /** - * display HTML footer - * - * @return void - */ - protected function dispPageEnd(): void - { - echo ''; - } - - /** - * renders errors not displayed - * - * @return string - */ - public function getDispErrors(): string - { - $retval = ''; - // display errors if SendErrorReports is set to 'ask'. - if ($GLOBALS['cfg']['SendErrorReports'] != 'never') { - foreach ($this->getErrors() as $error) { - if (! $error->isDisplayed()) { - $retval .= $error->getDisplay(); - } - } - } else { - $retval .= $this->getDispUserErrors(); - } - // if preference is not 'never' and - // there are 'actual' errors to be reported - if ($GLOBALS['cfg']['SendErrorReports'] != 'never' - && $this->countErrors() != $this->countUserErrors() - ) { - // add report button. - $retval .= '
'php', - 'send_error_report' => '1', - 'server' => $GLOBALS['server'], - ]); - $retval .= '' - . '' - . ''; - - if ($GLOBALS['cfg']['SendErrorReports'] == 'ask') { - // add ignore buttons - $retval .= ''; - } - $retval .= ''; - $retval .= '
'; - } - return $retval; - } - - /** - * displays errors not displayed - * - * @return void - */ - public function dispErrors(): void - { - echo $this->getDispErrors(); - } - - /** - * look in session for saved errors - * - * @return void - */ - protected function checkSavedErrors(): void - { - if (isset($_SESSION['errors'])) { - // restore saved errors - foreach ($_SESSION['errors'] as $hash => $error) { - if ($error instanceof Error && ! isset($this->errors[$hash])) { - $this->errors[$hash] = $error; - } - } - - // delete stored errors - $_SESSION['errors'] = []; - unset($_SESSION['errors']); - } - } - - /** - * return count of errors - * - * @param bool $check Whether to check for session errors - * - * @return integer number of errors occurred - */ - public function countErrors(bool $check = true): int - { - return count($this->getErrors($check)); - } - - /** - * return count of user errors - * - * @return integer number of user errors occurred - */ - public function countUserErrors(): int - { - $count = 0; - if ($this->countErrors()) { - foreach ($this->getErrors() as $error) { - if ($error->isUserError()) { - $count++; - } - } - } - - return $count; - } - - /** - * whether use errors occurred or not - * - * @return boolean - */ - public function hasUserErrors(): bool - { - return (bool) $this->countUserErrors(); - } - - /** - * whether errors occurred or not - * - * @return boolean - */ - public function hasErrors(): bool - { - return (bool) $this->countErrors(); - } - - /** - * number of errors to be displayed - * - * @return integer number of errors to be displayed - */ - public function countDisplayErrors(): int - { - if ($GLOBALS['cfg']['SendErrorReports'] != 'never') { - return $this->countErrors(); - } - - return $this->countUserErrors(); - } - - /** - * whether there are errors to display or not - * - * @return boolean - */ - public function hasDisplayErrors(): bool - { - return (bool) $this->countDisplayErrors(); - } - - /** - * Deletes previously stored errors in SESSION. - * Saves current errors in session as previous errors. - * Required to save current errors in case 'ask' - * - * @return void - */ - public function savePreviousErrors(): void - { - unset($_SESSION['prev_errors']); - $_SESSION['prev_errors'] = $GLOBALS['error_handler']->getCurrentErrors(); - } - - /** - * Function to check if there are any errors to be prompted. - * Needed because user warnings raised are - * also collected by global error handler. - * This distinguishes between the actual errors - * and user errors raised to warn user. - * - * @return boolean true if there are errors to be "prompted", false otherwise - */ - public function hasErrorsForPrompt(): bool - { - return ( - $GLOBALS['cfg']['SendErrorReports'] != 'never' - && $this->countErrors() != $this->countUserErrors() - ); - } - - /** - * Function to report all the collected php errors. - * Must be called at the end of each script - * by the $GLOBALS['error_handler'] only. - * - * @return void - */ - public function reportErrors(): void - { - // if there're no actual errors, - if (! $this->hasErrors() - || $this->countErrors() == $this->countUserErrors() - ) { - // then simply return. - return; - } - // Delete all the prev_errors in session & store new prev_errors in session - $this->savePreviousErrors(); - $response = Response::getInstance(); - $jsCode = ''; - if ($GLOBALS['cfg']['SendErrorReports'] == 'always') { - if ($response->isAjax()) { - // set flag for automatic report submission. - $response->addJSON('sendErrorAlways', '1'); - } else { - // send the error reports asynchronously & without asking user - $jsCode .= '$("#pma_report_errors_form").submit();' - . 'Functions.ajaxShowMessage( - Messages.phpErrorsBeingSubmitted, false - );'; - // js code to appropriate focusing, - $jsCode .= '$("html, body").animate({ - scrollTop:$(document).height() - }, "slow");'; - } - } elseif ($GLOBALS['cfg']['SendErrorReports'] == 'ask') { - //ask user whether to submit errors or not. - if (! $response->isAjax()) { - // js code to show appropriate msgs, event binding & focusing. - $jsCode = 'Functions.ajaxShowMessage(Messages.phpErrorsFound);' - . '$("#pma_ignore_errors_popup").on("click", function() { - Functions.ignorePhpErrors() - });' - . '$("#pma_ignore_all_errors_popup").on("click", - function() { - Functions.ignorePhpErrors(false) - });' - . '$("#pma_ignore_errors_bottom").on("click", function(e) { - e.preventDefault(); - Functions.ignorePhpErrors() - });' - . '$("#pma_ignore_all_errors_bottom").on("click", - function(e) { - e.preventDefault(); - Functions.ignorePhpErrors(false) - });' - . '$("html, body").animate({ - scrollTop:$(document).height() - }, "slow");'; - } - } - // The errors are already sent from the response. - // Just focus on errors division upon load event. - $response->getFooter()->getScripts()->addCode($jsCode); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/ErrorReport.php b/srcs/phpmyadmin/libraries/classes/ErrorReport.php deleted file mode 100644 index b7044f2..0000000 --- a/srcs/phpmyadmin/libraries/classes/ErrorReport.php +++ /dev/null @@ -1,294 +0,0 @@ -httpRequest = $httpRequest; - $this->relation = $relation; - $this->template = $template; - } - - /** - * Set the URL where to submit reports to - * - * @param string $submissionUrl Submission URL - * @return void - */ - public function setSubmissionUrl(string $submissionUrl): void - { - $this->submissionUrl = $submissionUrl; - } - - /** - * Returns the pretty printed error report data collected from the - * current configuration or from the request parameters sent by the - * error reporting js code. - * - * @return string the report - */ - private function getPrettyData(): string - { - $report = $this->getData(); - - return json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); - } - - /** - * Returns the error report data collected from the current configuration or - * from the request parameters sent by the error reporting js code. - * - * @param string $exceptionType whether exception is 'js' or 'php' - * - * @return array error report if success, Empty Array otherwise - */ - public function getData(string $exceptionType = 'js'): array - { - /** @var Config $PMA_Config */ - global $PMA_Config; - - $relParams = $this->relation->getRelationsParam(); - // common params for both, php & js exceptions - $report = [ - "pma_version" => PMA_VERSION, - "browser_name" => PMA_USR_BROWSER_AGENT, - "browser_version" => PMA_USR_BROWSER_VER, - "user_os" => PMA_USR_OS, - "server_software" => $_SERVER['SERVER_SOFTWARE'], - "user_agent_string" => $_SERVER['HTTP_USER_AGENT'], - "locale" => $PMA_Config->getCookie('pma_lang'), - "configuration_storage" => - $relParams['db'] === null ? "disabled" : "enabled", - "php_version" => PHP_VERSION, - ]; - - if ($exceptionType == 'js') { - if (empty($_POST['exception'])) { - return []; - } - $exception = $_POST['exception']; - $exception["stack"] = $this->translateStacktrace($exception["stack"]); - - if (isset($exception["url"])) { - list($uri, $scriptName) = $this->sanitizeUrl($exception["url"]); - $exception["uri"] = $uri; - $report["script_name"] = $scriptName; - unset($exception["url"]); - } elseif (isset($_POST["url"])) { - list($uri, $scriptName) = $this->sanitizeUrl($_POST["url"]); - $exception["uri"] = $uri; - $report["script_name"] = $scriptName; - unset($_POST["url"]); - } else { - $report["script_name"] = null; - } - - $report["exception_type"] = 'js'; - $report["exception"] = $exception; - if (isset($_POST['microhistory'])) { - $report["microhistory"] = $_POST['microhistory']; - } - - if (! empty($_POST['description'])) { - $report['steps'] = $_POST['description']; - } - } elseif ($exceptionType == 'php') { - $errors = []; - // create php error report - $i = 0; - if (! isset($_SESSION['prev_errors']) - || $_SESSION['prev_errors'] == '' - ) { - return []; - } - foreach ($_SESSION['prev_errors'] as $errorObj) { - /** @var Error $errorObj */ - if ($errorObj->getLine() - && $errorObj->getType() - && $errorObj->getNumber() != E_USER_WARNING - ) { - $errors[$i++] = [ - "lineNum" => $errorObj->getLine(), - "file" => $errorObj->getFile(), - "type" => $errorObj->getType(), - "msg" => $errorObj->getOnlyMessage(), - "stackTrace" => $errorObj->getBacktrace(5), - "stackhash" => $errorObj->getHash(), - ]; - } - } - - // if there were no 'actual' errors to be submitted. - if ($i == 0) { - return []; // then return empty array - } - $report["exception_type"] = 'php'; - $report["errors"] = $errors; - } else { - return []; - } - - return $report; - } - - /** - * Sanitize a url to remove the identifiable host name and extract the - * current script name from the url fragment - * - * It returns two things in an array. The first is the uri without the - * hostname and identifying query params. The second is the name of the - * php script in the url - * - * @param string $url the url to sanitize - * - * @return array the uri and script name - */ - private function sanitizeUrl(string $url): array - { - $components = parse_url($url); - if (isset($components["fragment"]) - && preg_match("", $components["fragment"], $matches) - ) { - $uri = str_replace($matches[0], "", $components["fragment"]); - $url = "https://example.com/" . $uri; - $components = parse_url($url); - } - - // get script name - preg_match("<([a-zA-Z\-_\d\.]*\.php|js\/[a-zA-Z\-_\d\/\.]*\.js)$>", $components["path"], $matches); - if (count($matches) < 2) { - $scriptName = 'index.php'; - } else { - $scriptName = $matches[1]; - } - - // remove deployment specific details to make uri more generic - if (isset($components["query"])) { - parse_str($components["query"], $queryArray); - unset($queryArray["db"]); - unset($queryArray["table"]); - unset($queryArray["token"]); - unset($queryArray["server"]); - $query = http_build_query($queryArray); - } else { - $query = ''; - } - - $uri = $scriptName . "?" . $query; - return [ - $uri, - $scriptName, - ]; - } - - /** - * Sends report data to the error reporting server - * - * @param array $report the report info to be sent - * - * @return string|null|bool the reply of the server - */ - public function send(array $report) - { - return $this->httpRequest->create( - $this->submissionUrl, - "POST", - false, - json_encode($report), - "Content-Type: application/json" - ); - } - - /** - * Translates the cumulative line numbers in the stack trace as well as sanitize - * urls and trim long lines in the context - * - * @param array $stack the stack trace - * - * @return array the modified stack trace - */ - private function translateStacktrace(array $stack): array - { - foreach ($stack as &$level) { - foreach ($level["context"] as &$line) { - if (mb_strlen($line) > 80) { - $line = mb_substr($line, 0, 75) . "//..."; - } - } - list($uri, $scriptName) = $this->sanitizeUrl($level["url"]); - $level["uri"] = $uri; - $level["scriptname"] = $scriptName; - unset($level["url"]); - } - unset($level); - return $stack; - } - - /** - * Generates the error report form to collect user description and preview the - * report before being sent - * - * @return string the form - */ - public function getForm(): string - { - $datas = [ - 'report_data' => $this->getPrettyData(), - 'hidden_inputs' => Url::getHiddenInputs(), - 'hidden_fields' => null, - ]; - - $reportData = $this->getData(); - if (! empty($reportData)) { - $datas['hidden_fields'] = Url::getHiddenFields($reportData, '', true); - } - - return $this->template->render('error/report_form', $datas); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Export.php b/srcs/phpmyadmin/libraries/classes/Export.php deleted file mode 100644 index 34a16b4..0000000 --- a/srcs/phpmyadmin/libraries/classes/Export.php +++ /dev/null @@ -1,1225 +0,0 @@ -dbi = $dbi; - } - - /** - * Sets a session variable upon a possible fatal error during export - * - * @return void - */ - public function shutdown(): void - { - $error = error_get_last(); - if ($error != null && mb_strpos($error['message'], "execution time")) { - //set session variable to check if there was error while exporting - $_SESSION['pma_export_error'] = $error['message']; - } - } - - /** - * Detect ob_gzhandler - * - * @return bool - */ - public function isGzHandlerEnabled(): bool - { - 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 - */ - public function gzencodeNeeded(): bool - { - /* - * We should gzencode only if the function exists - * but we don't want to compress twice, therefore - * gzencode only if transparent compression is not enabled - * and gz compression was not asked via $cfg['OBGzip'] - * but transparent compression does not apply when saving to server - */ - $chromeAndGreaterThan43 = PMA_USR_BROWSER_AGENT == 'CHROME' - && PMA_USR_BROWSER_VER >= 43; // see bug #4942 - - return function_exists('gzencode') - && ((! ini_get('zlib.output_compression') - && ! $this->isGzHandlerEnabled()) - || $GLOBALS['save_on_server'] - || $chromeAndGreaterThan43); - } - - /** - * Output handler for all exports, if needed buffering, it stores data into - * $dump_buffer, otherwise it prints them out. - * - * @param string $line the insert statement - * - * @return bool Whether output succeeded - */ - public function outputHandler(?string $line): bool - { - global $time_start, $dump_buffer, $dump_buffer_len, $save_filename; - - // Kanji encoding convert feature - if ($GLOBALS['output_kanji_conversion']) { - $line = Encoding::kanjiStrConv( - $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 = Encoding::convertString( - 'utf-8', - $GLOBALS['charset'], - $dump_buffer - ); - } - if ($GLOBALS['compression'] == 'gzip' - && $this->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); - // Here, use strlen rather than mb_strlen to get the length - // in bytes to compare against the number of bytes written. - if ($write_result != strlen($dump_buffer)) { - $GLOBALS['message'] = 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 - } - } elseif ($GLOBALS['asfile']) { - if ($GLOBALS['output_charset_conversion']) { - $line = Encoding::convertString( - 'utf-8', - $GLOBALS['charset'], - $line - ); - } - if ($GLOBALS['save_on_server'] && mb_strlen($line) > 0) { - if ($GLOBALS['file_handle'] !== null) { - $write_result = @fwrite($GLOBALS['file_handle'], $line); - } else { - $write_result = false; - } - // Here, use strlen rather than mb_strlen to get the length - // in bytes to compare against the number of bytes written. - if (! $write_result - || $write_result != strlen($line) - ) { - $GLOBALS['message'] = 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; - } - - /** - * Returns HTML containing the footer for a displayed export - * - * @param string $back_button the link for going Back - * @param string $refreshButton the link for refreshing page - * - * @return string the HTML output - */ - public function getHtmlForDisplayedExportFooter( - string $back_button, - string $refreshButton - ): string { - /** - * Close the html tags and add the footers for on-screen export - */ - return '' - . ' ' - . '
' - // bottom back button - . $back_button - . $refreshButton - . '' - . '' . "\n"; - } - - /** - * Computes the memory limit for export - * - * @return int the memory limit - */ - public function getMemoryLimit(): int - { - $memory_limit = trim(ini_get('memory_limit')); - $memory_limit_num = (int) substr($memory_limit, 0, -1); - $lowerLastChar = strtolower(substr($memory_limit, -1)); - // 2 MB as default - if (empty($memory_limit) || '-1' == $memory_limit) { - $memory_limit = 2 * 1024 * 1024; - } elseif ($lowerLastChar == 'm') { - $memory_limit = $memory_limit_num * 1024 * 1024; - } elseif ($lowerLastChar == 'k') { - $memory_limit = $memory_limit_num * 1024; - } elseif ($lowerLastChar == 'g') { - $memory_limit = $memory_limit_num * 1024 * 1024 * 1024; - } else { - $memory_limit = (int) $memory_limit; - } - - // Some of memory is needed for other things and as threshold. - // During export I had allocated (see memory_get_usage function) - // approx 1.2MB so this comes from that. - if ($memory_limit > 1500000) { - $memory_limit -= 1500000; - } - - // Some memory is needed for compression, assume 1/3 - $memory_limit /= 8; - return $memory_limit; - } - - /** - * Return the filename and MIME type for export file - * - * @param string $export_type type of export - * @param string $remember_template whether to remember template - * @param ExportPlugin $export_plugin the export plugin - * @param string $compression compression asked - * @param string $filename_template the filename template - * - * @return string[] the filename template and mime type - */ - public function getFilenameAndMimetype( - string $export_type, - string $remember_template, - ExportPlugin $export_plugin, - string $compression, - string $filename_template - ): array { - if ($export_type == 'server') { - if (! empty($remember_template)) { - $GLOBALS['PMA_Config']->setUserValue( - 'pma_server_filename_template', - 'Export/file_template_server', - $filename_template - ); - } - } elseif ($export_type == 'database') { - if (! empty($remember_template)) { - $GLOBALS['PMA_Config']->setUserValue( - 'pma_db_filename_template', - 'Export/file_template_database', - $filename_template - ); - } - } else { - if (! empty($remember_template)) { - $GLOBALS['PMA_Config']->setUserValue( - 'pma_table_filename_template', - 'Export/file_template_table', - $filename_template - ); - } - } - $filename = 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 = Sanitize::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 = mb_strlen($filename) - mb_strlen( - $export_plugin->getProperties()->getExtension() - ) - 1; - $user_extension = mb_substr( - $filename, - $extension_start_pos, - mb_strlen($filename) - ); - $required_extension = "." . $export_plugin->getProperties()->getExtension(); - if (mb_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 == 'gzip') { - $filename .= '.gz'; - $mime_type = 'application/x-gzip'; - } elseif ($compression == 'zip') { - $filename .= '.zip'; - $mime_type = 'application/zip'; - } - return [ - $filename, - $mime_type, - ]; - } - - /** - * Open the export file - * - * @param string $filename the export filename - * @param boolean $quick_export whether it's a quick export or not - * - * @return array the full save filename, possible message and the file handle - */ - public function openFile(string $filename, bool $quick_export): array - { - $file_handle = null; - $message = ''; - $doNotSaveItOver = true; - - if (isset($_POST['quick_export_onserver_overwrite'])) { - $doNotSaveItOver = $_POST['quick_export_onserver_overwrite'] != 'saveitover'; - } - - $save_filename = Util::userDir($GLOBALS['cfg']['SaveDir']) - . preg_replace('@[/\\\\]@', '_', $filename); - - if (@file_exists($save_filename) - && ((! $quick_export && empty($_POST['onserver_overwrite'])) - || ($quick_export - && $doNotSaveItOver)) - ) { - $message = Message::error( - __( - 'File %s already exists on server, ' - . 'change filename or check overwrite option.' - ) - ); - $message->addParam($save_filename); - } elseif (@is_file($save_filename) && ! @is_writable($save_filename)) { - $message = Message::error( - __( - 'The web server does not have permission ' - . 'to save the file %s.' - ) - ); - $message->addParam($save_filename); - } elseif (! $file_handle = @fopen($save_filename, 'w')) { - $message = Message::error( - __( - 'The web server does not have permission ' - . 'to save the file %s.' - ) - ); - $message->addParam($save_filename); - } - return [ - $save_filename, - $message, - $file_handle, - ]; - } - - /** - * Close the export file - * - * @param resource $file_handle the export file handle - * @param string $dump_buffer the current dump buffer - * @param string $save_filename the export filename - * - * @return Message a message object (or empty string) - */ - public function closeFile( - $file_handle, - string $dump_buffer, - string $save_filename - ): Message { - $write_result = @fwrite($file_handle, $dump_buffer); - fclose($file_handle); - // Here, use strlen rather than mb_strlen to get the length - // in bytes to compare against the number of bytes written. - if (strlen($dump_buffer) > 0 - && (! $write_result || $write_result != strlen($dump_buffer)) - ) { - $message = new Message( - __('Insufficient space to save the file %s.'), - Message::ERROR, - [$save_filename] - ); - } else { - $message = new Message( - __('Dump has been saved to file %s.'), - Message::SUCCESS, - [$save_filename] - ); - } - return $message; - } - - /** - * Compress the export buffer - * - * @param array|string $dump_buffer the current dump buffer - * @param string $compression the compression mode - * @param string $filename the filename - * - * @return array|string|bool - */ - public function compress($dump_buffer, string $compression, string $filename) - { - if ($compression == 'zip' && function_exists('gzcompress')) { - $zipExtension = new ZipExtension(); - $filename = substr($filename, 0, -4); // remove extension (.zip) - $dump_buffer = $zipExtension->createFile($dump_buffer, $filename); - } elseif ($compression == 'gzip' && $this->gzencodeNeeded()) { - // without the optional parameter level because it bugs - $dump_buffer = gzencode($dump_buffer); - } - return $dump_buffer; - } - - /** - * Saves the dump_buffer for a particular table in an array - * Used in separate files export - * - * @param string $object_name the name of current object to be stored - * @param boolean $append optional boolean to append to an existing index or not - * - * @return void - */ - public function saveObjectInBuffer(string $object_name, bool $append = false): void - { - global $dump_buffer_objects, $dump_buffer, $dump_buffer_len; - - if (! empty($dump_buffer)) { - if ($append && isset($dump_buffer_objects[$object_name])) { - $dump_buffer_objects[$object_name] .= $dump_buffer; - } else { - $dump_buffer_objects[$object_name] = $dump_buffer; - } - } - - // Re - initialize - $dump_buffer = ''; - $dump_buffer_len = 0; - } - - /** - * Returns HTML containing the header for a displayed export - * - * @param string $export_type the export type - * @param string $db the database name - * @param string $table the table name - * - * @return string[] the generated HTML and back button - */ - public function getHtmlForDisplayedExportHeader( - string $export_type, - string $db, - string $table - ): array { - $html = '
'; - - /** - * Displays a back button with all the $_POST data in the URL - * (store in a variable to also display after the textarea) - */ - $back_button = '

[ ' . __('Back') . ' ]

'; - $html .= '
'; - $html .= $back_button; - $refreshButton = '
'; - $refreshButton .= '[ ' . __('Refresh') . ' ]'; - foreach ($_POST as $name => $value) { - if (is_array($value)) { - foreach ($value as $val) { - $refreshButton .= ''; - } - } else { - $refreshButton .= ''; - } - } - $refreshButton .= '
'; - $html .= $refreshButton - . '
' - . '
' - . ''; - - return $html_output; - } - - /** - * Get HTML for enum type - * - * @param array $column description of column in given table - * @param string $backup_field hidden input field - * @param string $column_name_appendix the name attribute - * @param array $extracted_columnspec associative array containing type, - * spec_in_brackets and possibly - * enum_set_values (another array) - * @param string $onChangeClause onchange clause for fields - * @param integer $tabindex tab index - * @param integer $tabindex_for_value offset for the values tabindex - * @param integer $idindex id index - * @param mixed $data data to edit - * @param boolean $readOnly is column read only or not - * - * @return string an html snippet - */ - private function getPmaTypeEnum( - array $column, - $backup_field, - $column_name_appendix, - array $extracted_columnspec, - $onChangeClause, - $tabindex, - $tabindex_for_value, - $idindex, - $data, - $readOnly - ) { - $html_output = ''; - if (! isset($column['values'])) { - $column['values'] = $this->getColumnEnumValues( - $column, - $extracted_columnspec - ); - } - $column_enum_values = $column['values']; - $html_output .= ''; - $html_output .= "\n" . ' ' . $backup_field . "\n"; - if (mb_strlen($column['Type']) > 20) { - $html_output .= $this->getDropDownDependingOnLength( - $column, - $column_name_appendix, - $onChangeClause, - $tabindex, - $tabindex_for_value, - $idindex, - $data, - $column_enum_values, - $readOnly - ); - } else { - $html_output .= $this->getRadioButtonDependingOnLength( - $column_name_appendix, - $onChangeClause, - $tabindex, - $column, - $tabindex_for_value, - $idindex, - $data, - $column_enum_values, - $readOnly - ); - } - 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 - */ - private function getColumnEnumValues(array $column, array $extracted_columnspec) - { - $column['values'] = []; - foreach ($extracted_columnspec['enum_set_values'] as $val) { - $column['values'][] = [ - '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 attribute - * @param string $onChangeClause onchange clause for fields - * @param integer $tabindex tab index - * @param integer $tabindex_for_value offset for the values tabindex - * @param integer $idindex id index - * @param string $data data to edit - * @param array $column_enum_values $column['values'] - * @param boolean $readOnly is column read only or not - * - * @return string an html snippet - */ - private function getDropDownDependingOnLength( - array $column, - $column_name_appendix, - $onChangeClause, - $tabindex, - $tabindex_for_value, - $idindex, - $data, - array $column_enum_values, - $readOnly - ) { - $html_output = ''; - - //Add hidden input, as disabled '; - } - return $html_output; - } - - /** - * Get HTML radio button for less than 20 string length - * - * @param string $column_name_appendix the name attribute - * @param string $onChangeClause onchange clause for fields - * @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 string $data data to edit - * @param array $column_enum_values $column['values'] - * @param boolean $readOnly is column read only or not - * - * @return string an html snippet - */ - private function getRadioButtonDependingOnLength( - $column_name_appendix, - $onChangeClause, - $tabindex, - array $column, - $tabindex_for_value, - $idindex, - $data, - array $column_enum_values, - $readOnly - ) { - $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 attribute - * @param string $onChangeClause onchange clause for fields - * @param integer $tabindex tab index - * @param integer $tabindex_for_value offset for the values tabindex - * @param integer $idindex id index - * @param string $data description of the column field - * @param boolean $readOnly is column read only or not - * - * @return string an html snippet - */ - private function getPmaTypeSet( - array $column, - array $extracted_columnspec, - $backup_field, - $column_name_appendix, - $onChangeClause, - $tabindex, - $tabindex_for_value, - $idindex, - $data, - $readOnly - ) { - list($column_set_values, $select_size) = $this->getColumnSetValueAndSelectSize( - $column, - $extracted_columnspec - ); - $vset = array_flip(explode(',', $data)); - $html_output = $backup_field . "\n"; - $html_output .= ''; - $html_output .= ''; - - //Add hidden input, as disabled '; - } - 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'] - */ - private function getColumnSetValueAndSelectSize( - array $column, - array $extracted_columnspec - ) { - if (! isset($column['values'])) { - $column['values'] = []; - foreach ($extracted_columnspec['enum_set_values'] as $val) { - $column['values'][] = [ - 'plain' => $val, - 'html' => htmlspecialchars($val), - ]; - } - $column['select_size'] = min(4, count($column['values'])); - } - return [ - $column['values'], - $column['select_size'], - ]; - } - - /** - * Get HTML for binary and blob column - * - * @param array $column description of column in given table - * @param string|null $data data to edit - * @param string $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 attribute - * @param string $onChangeClause onchange clause for fields - * @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 - * @param boolean $readOnly is column read only or not - * - * @return string an html snippet - */ - private function getBinaryAndBlobColumn( - array $column, - ?string $data, - $special_chars, - $biggest_max_file_size, - $backup_field, - $column_name_appendix, - $onChangeClause, - $tabindex, - $tabindex_for_value, - $idindex, - $text_dir, - $special_chars_encoded, - $vkey, - $is_upload, - $readOnly - ) { - $html_output = ''; - // Add field type : Protected or Hexadecimal - $fields_type_html = ''; - // Default value : hex - $fields_type_val = 'hex'; - if (($GLOBALS['cfg']['ProtectBinary'] === 'blob' && $column['is_blob']) - || ($GLOBALS['cfg']['ProtectBinary'] === 'all') - || ($GLOBALS['cfg']['ProtectBinary'] === 'noblob' && ! $column['is_blob']) - ) { - $html_output .= __('Binary - do not edit'); - if (isset($data)) { - $data_size = Util::formatByteDown( - mb_strlen(stripslashes($data)), - 3, - 1 - ); - $html_output .= ' (' . $data_size[0] . ' ' . $data_size[1] . ')'; - unset($data_size); - } - $fields_type_val = 'protected'; - $html_output .= ''; - } elseif ($column['is_blob'] - || ($column['len'] > $GLOBALS['cfg']['LimitChars']) - ) { - $html_output .= "\n" . $this->getTextarea( - $column, - $backup_field, - $column_name_appendix, - $onChangeClause, - $tabindex, - $tabindex_for_value, - $idindex, - $text_dir, - $special_chars_encoded, - 'HEX', - $readOnly - ); - } 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" . $this->getHtmlInput( - $column, - $column_name_appendix, - $special_chars, - $fieldsize, - $onChangeClause, - $tabindex, - $tabindex_for_value, - $idindex, - 'HEX', - $readOnly - ); - } - $html_output .= sprintf($fields_type_html, $fields_type_val); - - if ($is_upload && $column['is_blob'] && ! $readOnly) { - // We don't want to prevent users from using - // browser's default drag-drop feature on some page(s), - // so we add noDragDrop class to the input - $html_output .= '
' - . ' '; - list($html_out,) = $this->getMaxUploadSize( - $column, - $biggest_max_file_size - ); - $html_output .= $html_out; - } - - if (! empty($GLOBALS['cfg']['UploadDir']) && ! $readOnly) { - $html_output .= $this->getSelectOptionForUpload($vkey, $column); - } - - return $html_output; - } - - /** - * Get HTML input type - * - * @param array $column description of column in given table - * @param string $column_name_appendix the name attribute - * @param string $special_chars special characters - * @param integer $fieldsize html field size - * @param string $onChangeClause onchange clause for fields - * @param integer $tabindex tab index - * @param integer $tabindex_for_value offset for the values tabindex - * @param integer $idindex id index - * @param string $data_type the html5 data-* attribute type - * @param boolean $readOnly is column read only or not - * - * @return string an html snippet - */ - private function getHtmlInput( - array $column, - $column_name_appendix, - $special_chars, - $fieldsize, - $onChangeClause, - $tabindex, - $tabindex_for_value, - $idindex, - $data_type, - $readOnly - ) { - $input_type = 'text'; - // do not use the 'date' or 'time' types here; they have no effect on some - // browsers and create side effects (see bug #4218) - - $the_class = 'textfield'; - // verify True_Type which does not contain the parentheses and length - if (! $readOnly) { - if ($column['True_Type'] === 'date') { - $the_class .= ' datefield'; - } elseif ($column['True_Type'] === 'time') { - $the_class .= ' timefield'; - } elseif ($column['True_Type'] === 'datetime' - || $column['True_Type'] === 'timestamp' - ) { - $the_class .= ' datetimefield'; - } - } - $input_min_max = false; - if (in_array($column['True_Type'], $this->dbi->types->getIntegerTypes())) { - $extracted_columnspec = Util::extractColumnSpec( - $column['Type'] - ); - $is_unsigned = $extracted_columnspec['unsigned']; - $min_max_values = $this->dbi->types->getIntegerRange( - $column['True_Type'], - ! $is_unsigned - ); - $input_min_max = 'min="' . $min_max_values[0] . '" ' - . 'max="' . $min_max_values[1] . '"'; - $data_type = 'INT'; - } - 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|null an html snippet - */ - private function getSelectOptionForUpload($vkey, array $column) - { - $files = $this->fileListing->getFileSelectOptions( - 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"; - } - - return null; - } - - /** - * 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 - */ - private function getMaxUploadSize(array $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 = [ - '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 - = 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 [ - $html_output, - $biggest_max_file_size, - ]; - } - - /** - * Get HTML for the Value column of other datatypes - * (here, "column" is used in the sense of HTML column in HTML table) - * - * @param array $column description of column in given table - * @param string $default_char_editing default char editing mode which is stored - * in the config.inc.php script - * @param string $backup_field hidden input field - * @param string $column_name_appendix the name attribute - * @param string $onChangeClause onchange clause for fields - * @param integer $tabindex tab index - * @param string $special_chars special characters - * @param integer $tabindex_for_value offset for the values tabindex - * @param integer $idindex id index - * @param string $text_dir text direction - * @param string $special_chars_encoded replaced char if the string starts - * with a \r\n pair (0x0d0a) add an extra \n - * @param string $data data to edit - * @param array $extracted_columnspec associative array containing type, - * spec_in_brackets and possibly - * enum_set_values (another array) - * @param boolean $readOnly is column read only or not - * - * @return string an html snippet - */ - private function getValueColumnForOtherDatatypes( - array $column, - $default_char_editing, - $backup_field, - $column_name_appendix, - $onChangeClause, - $tabindex, - $special_chars, - $tabindex_for_value, - $idindex, - $text_dir, - $special_chars_encoded, - $data, - array $extracted_columnspec, - $readOnly - ) { - // HTML5 data-* attribute data-type - $data_type = $this->dbi->types->getTypeClass($column['True_Type']); - $fieldsize = $this->getColumnSize($column, $extracted_columnspec); - $html_output = $backup_field . "\n"; - if ($column['is_char'] - && ($GLOBALS['cfg']['CharEditing'] == 'textarea' - || mb_strpos($data, "\n") !== false) - ) { - $html_output .= "\n"; - $GLOBALS['cfg']['CharEditing'] = $default_char_editing; - $html_output .= $this->getTextarea( - $column, - $backup_field, - $column_name_appendix, - $onChangeClause, - $tabindex, - $tabindex_for_value, - $idindex, - $text_dir, - $special_chars_encoded, - $data_type, - $readOnly - ); - } else { - $html_output .= $this->getHtmlInput( - $column, - $column_name_appendix, - $special_chars, - $fieldsize, - $onChangeClause, - $tabindex, - $tabindex_for_value, - $idindex, - $data_type, - $readOnly - ); - - if (preg_match('/(VIRTUAL|PERSISTENT|GENERATED)/', $column['Extra']) && $column['Extra'] !== 'DEFAULT_GENERATED') { - $html_output .= ''; - } - 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 .= ''; - } - } - 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 - */ - private function getColumnSize(array $column, array $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 - */ - private function getHtmlForGisDataTypes() - { - $edit_str = Util::getIcon('b_edit', __('Edit/Insert')); - return '' - . Util::linkOrButton( - '#', - $edit_str, - [], - '_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 - */ - public function getContinueInsertionForm( - $table, - $db, - array $where_clause_array, - $err_url - ) { - return $this->template->render('table/insert/continue_insertion_form', [ - 'db' => $db, - 'table' => $table, - 'where_clause_array' => $where_clause_array, - 'err_url' => $err_url, - 'goto' => $GLOBALS['goto'], - 'sql_query' => isset($_POST['sql_query']) ? $_POST['sql_query'] : null, - 'has_where_clause' => isset($_POST['where_clause']), - 'insert_rows_default' => $GLOBALS['cfg']['InsertRows'], - ]); - } - - /** - * Get action panel - * - * @param array|null $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 - */ - public function getActionsPanel( - $where_clause, - $after_insert, - $tabindex, - $tabindex_for_value, - $found_unique_key - ) { - $html_output = '
' - . '' - . '' - . '' - . '' - . '' - . ''; - $html_output .= '' - . $this->getSubmitAndResetButtonForActionsPanel($tabindex, $tabindex_for_value) - . '' - . '
' - . $this->getSubmitTypeDropDown($where_clause, $tabindex, $tabindex_for_value) - . "\n"; - - $html_output .= '' - . '   ' - . __('and then') . '   ' - . '' - . $this->getAfterInsertDropDown( - $where_clause, - $after_insert, - $found_unique_key - ) - . '
' - . '
'; - return $html_output; - } - - /** - * Get a HTML drop down for submit types - * - * @param array|null $where_clause where clause - * @param integer $tabindex tab index - * @param integer $tabindex_for_value offset for the values tabindex - * - * @return string an html snippet - */ - private function getSubmitTypeDropDown( - $where_clause, - $tabindex, - $tabindex_for_value - ) { - $html_output = ''; - return $html_output; - } - - /** - * Get HTML drop down for after insert - * - * @param array|null $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 - */ - private function 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 - */ - private function getSubmitAndResetButtonForActionsPanel($tabindex, $tabindex_for_value) - { - return '' - . 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 - */ - private function getHeadAndFootOfInsertRowTable(array $url_params) - { - $html_output = '
' - . '' - . '' - . '' - . ''; - - if ($GLOBALS['cfg']['ShowFieldTypesInDataEditView']) { - $html_output .= $this->showTypeOrFunction('type', $url_params, true); - } - if ($GLOBALS['cfg']['ShowFunctionFields']) { - $html_output .= $this->showTypeOrFunction('function', $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 - * @param bool $as_is use the data as is, used in repopulating - * - * @return array $real_null_value, $data, $special_chars, $backup_field, - * $special_chars_encoded - */ - private function getSpecialCharsAndBackupFieldForExistingRow( - array $current_row, - array $column, - array $extracted_columnspec, - $real_null_value, - array $gis_data_types, - $column_name_appendix, - $as_is - ) { - $special_chars_encoded = ''; - $data = null; - // (we are editing) - if (! isset($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 = $as_is - ? $current_row[$column['Field']] - : Util::printableBitValue( - (int) $current_row[$column['Field']], - (int) $extracted_columnspec['spec_in_brackets'] - ); - } elseif ((substr($column['True_Type'], 0, 9) == 'timestamp' - || $column['True_Type'] == 'datetime' - || $column['True_Type'] == 'time') - && (mb_strpos($current_row[$column['Field']], ".") !== false) - ) { - $current_row[$column['Field']] = $as_is - ? $current_row[$column['Field']] - : Util::addMicroseconds( - $current_row[$column['Field']] - ); - $special_chars = htmlspecialchars($current_row[$column['Field']]); - } elseif (in_array($column['True_Type'], $gis_data_types)) { - // Convert gis data to Well Know Text format - $current_row[$column['Field']] = $as_is - ? $current_row[$column['Field']] - : 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'] !== 'all') - ) { - $current_row[$column['Field']] = $as_is - ? $current_row[$column['Field']] - : bin2hex( - $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 - = 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($_POST['default_action']) - && $_POST['default_action'] === 'insert' - ) { - if ($column['Key'] === 'PRI' - && mb_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 [ - $real_null_value, - $special_chars_encoded, - $special_chars, - $data, - $backup_field, - ]; - } - - /** - * display default values - * - * @param array $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 - */ - private function getSpecialCharsAndBackupFieldForInsertingMode( - array $column, - $real_null_value - ) { - if (! isset($column['Default'])) { - $column['Default'] = ''; - $real_null_value = true; - $data = ''; - } else { - $data = $column['Default']; - } - - $trueType = $column['True_Type']; - - if ($trueType == 'bit') { - $special_chars = Util::convertBitDefaultValue( - $column['Default'] - ); - } elseif (substr($trueType, 0, 9) == 'timestamp' - || $trueType == 'datetime' - || $trueType == 'time' - ) { - $special_chars = Util::addMicroseconds($column['Default']); - } elseif ($trueType == 'binary' || $trueType == 'varbinary') { - $special_chars = bin2hex($column['Default']); - } elseif ('text' === substr($trueType, -4)) { - $textDefault = substr($column['Default'], 1, -1); - $special_chars = stripcslashes($textDefault !== false ? $textDefault : $column['Default']); - } else { - $special_chars = htmlspecialchars($column['Default']); - } - $backup_field = ''; - $special_chars_encoded = Util::duplicateFirstNewline( - $special_chars - ); - return [ - $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 - */ - public function getParamsForUpdateOrInsert() - { - if (isset($_POST['where_clause'])) { - // we were editing something => use the WHERE clause - $loop_array = is_array($_POST['where_clause']) - ? $_POST['where_clause'] - : [$_POST['where_clause']]; - $using_key = true; - $is_insert = isset($_POST['submit_type']) - && ($_POST['submit_type'] == 'insert' - || $_POST['submit_type'] == 'showinsert' - || $_POST['submit_type'] == 'insertignore'); - } else { - // new row => use indexes - $loop_array = []; - if (! empty($_POST['fields'])) { - foreach ($_POST['fields']['multi_edit'] as $key => $dummy) { - $loop_array[] = $key; - } - } - $using_key = false; - $is_insert = true; - } - $is_insertignore = isset($_POST['submit_type']) - && $_POST['submit_type'] == 'insertignore'; - return [ - $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 - */ - public function isInsertRow() - { - if (isset($_POST['insert_rows']) - && is_numeric($_POST['insert_rows']) - && $_POST['insert_rows'] != $GLOBALS['cfg']['InsertRows'] - ) { - $GLOBALS['cfg']['InsertRows'] = $_POST['insert_rows']; - $response = Response::getInstance(); - $header = $response->getHeader(); - $scripts = $header->getScripts(); - $scripts->addFile('vendor/jquery/additional-methods.js'); - $scripts->addFile('table/change.js'); - if (! defined('TESTSUITE')) { - include ROOT_PATH . 'tbl_change.php'; - exit; - } - } - } - - /** - * set $_SESSION for edit_next - * - * @param string $one_where_clause one where clause from where clauses array - * - * @return void - */ - public function setSessionForEditNext($one_where_clause) - { - $local_query = 'SELECT * FROM ' . Util::backquote($GLOBALS['db']) - . '.' . Util::backquote($GLOBALS['table']) . ' WHERE ' - . str_replace('` =', '` >', $one_where_clause) . ' LIMIT 1;'; - - $res = $this->dbi->query($local_query); - $row = $this->dbi->fetchRow($res); - $meta = $this->dbi->getFieldsMeta($res); - // must find a unique condition based on unique key, - // not a combination of all fields - list($unique_condition, $clause_is_unique) - = Util::getUniqueCondition( - $res, // handle - count($meta), // fields_cnt - $meta, // fields_meta - $row, // row - true, // force_unique - false, // restrict_to_table - null // analyzed_sql_results - ); - 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 - */ - public function getGotoInclude($goto_include) - { - $valid_options = [ - 'new_insert', - 'same_insert', - 'edit_next', - ]; - if (isset($_POST['after_insert']) - && in_array($_POST['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']) > 0) { - $GLOBALS['table'] = ''; - } - } - if (! $goto_include) { - if (strlen($GLOBALS['table']) === 0) { - $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 - */ - public function getErrorUrl(array $url_params) - { - if (isset($_POST['err_url'])) { - return $_POST['err_url']; - } - - return 'tbl_change.php' . Url::getCommon($url_params); - } - - /** - * Builds the sql query - * - * @param boolean $is_insertignore $_POST['submit_type'] == 'insertignore' - * @param array $query_fields column names array - * @param array $value_sets array of query values - * - * @return array of query - */ - public function buildSqlQuery($is_insertignore, array $query_fields, array $value_sets) - { - if ($is_insertignore) { - $insert_command = 'INSERT IGNORE '; - } else { - $insert_command = 'INSERT '; - } - $query = [ - $insert_command . 'INTO ' - . Util::backquote($GLOBALS['table']) - . ' (' . implode(', ', $query_fields) . ') VALUES (' - . implode('), (', $value_sets) . ')', - ]; - return $query; - } - - /** - * Executes the sql query and get the result, then move back to the calling page - * - * @param array $url_params url parameters array - * @param array $query built query from buildSqlQuery() - * - * @return array $url_params, $total_affected_rows, $last_messages - * $warning_messages, $error_messages, $return_to_sql_query - */ - public function executeSqlQuery(array $url_params, array $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 = []; - $warning_messages = []; - $error_messages = []; - - foreach ($query as $single_query) { - if ($_POST['submit_type'] == 'showinsert') { - $last_messages[] = Message::notice(__('Showing SQL query')); - continue; - } - if ($GLOBALS['cfg']['IgnoreMultiSubmitErrors']) { - $result = $this->dbi->tryQuery($single_query); - } else { - $result = $this->dbi->query($single_query); - } - if (! $result) { - $error_messages[] = $this->dbi->getError(); - } else { - // The next line contains a real assignment, it's not a typo - if ($tmp = @$this->dbi->affectedRows()) { - $total_affected_rows += $tmp; - } - unset($tmp); - - $insert_id = $this->dbi->insertId(); - if ($insert_id != 0) { - // insert_id is id of FIRST record inserted in one insert, so if we - // inserted multiple rows, we had to increment this - - if ($total_affected_rows > 0) { - $insert_id += $total_affected_rows - 1; - } - $last_message = Message::notice(__('Inserted row id: %1$d')); - $last_message->addParam($insert_id); - $last_messages[] = $last_message; - } - $this->dbi->freeResult($result); - } - $warning_messages = $this->getWarningMessages(); - } - return [ - $url_params, - $total_affected_rows, - $last_messages, - $warning_messages, - $error_messages, - $return_to_sql_query, - ]; - } - - /** - * get the warning messages array - * - * @return array - */ - private function getWarningMessages() - { - $warning_essages = []; - foreach ($this->dbi->getWarnings() as $warning) { - $warning_essages[] = 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 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 display value from the foreign table - */ - public function getDisplayValueForForeignTableColumn( - $where_comparison, - array $map, - $relation_field - ) { - $foreigner = $this->relation->searchColumnInForeigners($map, $relation_field); - $display_field = $this->relation->getDisplayField( - $foreigner['foreign_db'], - $foreigner['foreign_table'] - ); - // Field to display from the foreign table? - if (is_string($display_field) && strlen($display_field) > 0) { - $dispsql = 'SELECT ' . Util::backquote($display_field) - . ' FROM ' . Util::backquote($foreigner['foreign_db']) - . '.' . Util::backquote($foreigner['foreign_table']) - . ' WHERE ' . Util::backquote($foreigner['foreign_field']) - . $where_comparison; - $dispresult = $this->dbi->tryQuery( - $dispsql, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - if ($dispresult && $this->dbi->numRows($dispresult) > 0) { - list($dispval) = $this->dbi->fetchRow($dispresult); - } else { - $dispval = ''; - } - if ($dispresult) { - $this->dbi->freeResult($dispresult); - } - return $dispval; - } - return ''; - } - - /** - * Display option in the cell according to user choices - * - * @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 HTML tag - */ - public function getLinkForRelationalDisplayField( - array $map, - $relation_field, - $where_comparison, - $dispval, - $relation_field_value - ) { - $foreigner = $this->relation->searchColumnInForeigners($map, $relation_field); - if ('K' == $_SESSION['tmpval']['relational_display']) { - // user chose "relational key" in the display options, so - // the title contains the display field - $title = ! empty($dispval) - ? ' title="' . htmlspecialchars($dispval) . '"' - : ''; - } else { - $title = ' title="' . htmlspecialchars($relation_field_value) . '"'; - } - $_url_params = [ - 'db' => $foreigner['foreign_db'], - 'table' => $foreigner['foreign_table'], - 'pos' => '0', - 'sql_query' => 'SELECT * FROM ' - . Util::backquote($foreigner['foreign_db']) - . '.' . Util::backquote($foreigner['foreign_table']) - . ' WHERE ' . Util::backquote($foreigner['foreign_field']) - . $where_comparison, - ]; - $output = ''; - - if ('D' == $_SESSION['tmpval']['relational_display']) { - // user chose "relational display field" in the - // display options, so show display field in the cell - $output .= ! empty($dispval) ? htmlspecialchars($dispval) : ''; - } else { - // otherwise display data in the cell - $output .= htmlspecialchars($relation_field_value); - } - $output .= ''; - return $output; - } - - /** - * Transform edited values - * - * @param string $db db name - * @param string $table table name - * @param array $transformation mimetypes for all columns of a table - * [field_name][field_key] - * @param array $edited_values transform columns list and new values - * @param string $file file containing the transformation plugin - * @param string $column_name column name - * @param array $extra_data extra data array - * @param string $type the type of transformation - * - * @return array - */ - public function transformEditedValues( - $db, - $table, - array $transformation, - array &$edited_values, - $file, - $column_name, - array $extra_data, - $type - ) { - $include_file = 'libraries/classes/Plugins/Transformations/' . $file; - if (is_file($include_file)) { - $_url_params = [ - 'db' => $db, - 'table' => $table, - 'where_clause' => $_POST['where_clause'], - 'transform_key' => $column_name, - ]; - $transform_options = $this->transformations->getOptions( - isset($transformation[$type . '_options']) - ? $transformation[$type . '_options'] - : '' - ); - $transform_options['wrapper_link'] = Url::getCommon($_url_params); - $class_name = $this->transformations->getClassName($include_file); - if (class_exists($class_name)) { - /** @var TransformationsPlugin $transformation_plugin */ - $transformation_plugin = new $class_name(); - - foreach ($edited_values as $cell_index => $curr_cell_edited_values) { - if (isset($curr_cell_edited_values[$column_name])) { - $edited_values[$cell_index][$column_name] - = $extra_data['transformations'][$cell_index] - = $transformation_plugin->applyTransformation( - $curr_cell_edited_values[$column_name], - $transform_options - ); - } - } // end of loop for each transformation cell - } - } - return $extra_data; - } - - /** - * Get current value in multi edit mode - * - * @param array $multi_edit_funcs multiple edit functions array - * @param array $multi_edit_salt multiple edit array with encryption salt - * @param array $gis_from_text_functions array that contains gis from text functions - * @param string $current_value current value in the column - * @param array $gis_from_wkb_functions initially $val is $multi_edit_columns[$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 string - */ - public function getCurrentValueAsAnArrayForMultipleEdit( - $multi_edit_funcs, - $multi_edit_salt, - $gis_from_text_functions, - $current_value, - $gis_from_wkb_functions, - $func_optional_param, - $func_no_param, - $key - ) { - if (empty($multi_edit_funcs[$key])) { - return $current_value; - } elseif ('UUID' === $multi_edit_funcs[$key]) { - /* This way user will know what UUID new row has */ - $uuid = $this->dbi->fetchValue('SELECT UUID()'); - return "'" . $uuid . "'"; - } elseif ((in_array($multi_edit_funcs[$key], $gis_from_text_functions) - && substr($current_value, 0, 3) == "'''") - || in_array($multi_edit_funcs[$key], $gis_from_wkb_functions) - ) { - // Remove enclosing apostrophes - $current_value = mb_substr($current_value, 1, -1); - // Remove escaping apostrophes - $current_value = str_replace("''", "'", $current_value); - return $multi_edit_funcs[$key] . '(' . $current_value . ')'; - } elseif (! in_array($multi_edit_funcs[$key], $func_no_param) - || ($current_value != "''" - && in_array($multi_edit_funcs[$key], $func_optional_param)) - ) { - if ((isset($multi_edit_salt[$key]) - && ($multi_edit_funcs[$key] == "AES_ENCRYPT" - || $multi_edit_funcs[$key] == "AES_DECRYPT")) - || (! empty($multi_edit_salt[$key]) - && ($multi_edit_funcs[$key] == "DES_ENCRYPT" - || $multi_edit_funcs[$key] == "DES_DECRYPT" - || $multi_edit_funcs[$key] == "ENCRYPT")) - ) { - return $multi_edit_funcs[$key] . '(' . $current_value . ",'" - . $this->dbi->escapeString($multi_edit_salt[$key]) . "')"; - } - - return $multi_edit_funcs[$key] . '(' . $current_value . ')'; - } - - return $multi_edit_funcs[$key] . '()'; - } - - /** - * Get query values array and query fields array for insert and update in multi edit - * - * @param array $multi_edit_columns_name multiple edit columns name array - * @param array $multi_edit_columns_null multiple edit columns null array - * @param string $current_value current value in the column in loop - * @param array $multi_edit_columns_prev multiple edit previous columns array - * @param array $multi_edit_funcs multiple edit functions array - * @param boolean $is_insert boolean value whether insert or not - * @param array $query_values SET part of the sql query - * @param array $query_fields array of query fields - * @param string $current_value_as_an_array current value in the column - * as an array - * @param array $value_sets array of valu sets - * @param string $key an md5 of the column name - * @param array $multi_edit_columns_null_prev array of multiple edit columns - * null previous - * - * @return array ($query_values, $query_fields) - */ - public function 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) > 0) { - $query_values[] = $current_value_as_an_array; - // first inserted row so prepare the list of fields - if (empty($value_sets)) { - $query_fields[] = 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[] - = Util::backquote($multi_edit_columns_name[$key]) - . ' = ' . $current_value_as_an_array; - } elseif (! (empty($multi_edit_funcs[$key]) - && isset($multi_edit_columns_prev[$key]) - && (("'" . $this->dbi->escapeString($multi_edit_columns_prev[$key]) . "'" === $current_value) - || ('0x' . $multi_edit_columns_prev[$key] === $current_value))) - && ! 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[] - = Util::backquote($multi_edit_columns_name[$key]) - . ' = ' . $current_value_as_an_array; - } - } - return [ - $query_values, - $query_fields, - ]; - } - - /** - * Get the current column value in the form for different data types - * - * @param string|false $possibly_uploaded_val uploaded file content - * @param string $key an md5 of the column name - * @param array|null $multi_edit_columns_type array of multi edit column types - * @param string $current_value current column value in the form - * @param array|null $multi_edit_auto_increment multi edit auto increment - * @param integer $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 string $where_clause where clause - * @param string $table table name - * @param array $multi_edit_funcs multiple edit functions array - * - * @return string current column value in the form - */ - public function getCurrentValueForDifferentTypes( - $possibly_uploaded_val, - $key, - ?array $multi_edit_columns_type, - $current_value, - ?array $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, - $multi_edit_funcs - ) { - // 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) && ! empty($where_clause) - ) { - $protected_row = $this->dbi->fetchSingleRow( - 'SELECT * FROM ' . Util::backquote($table) - . ' WHERE ' . $where_clause . ';' - ); - } - - if (false !== $possibly_uploaded_val) { - $current_value = $possibly_uploaded_val; - } elseif (! empty($multi_edit_funcs[$key])) { - $current_value = "'" . $this->dbi->escapeString($current_value) - . "'"; - } 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' && strlen($current_value) === 0) { - // 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($_POST['fields']['multi_edit'][$rownumber][$key])) { - $current_value = implode( - ',', - $_POST['fields']['multi_edit'][$rownumber][$key] - ); - $current_value = "'" - . $this->dbi->escapeString($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 - // columns 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 === 'hex') { - if (substr($current_value, 0, 2) != '0x') { - $current_value = '0x' . $current_value; - } - } elseif ($type == 'bit') { - $current_value = preg_replace('/[^01]/', '0', $current_value); - $current_value = "b'" . $this->dbi->escapeString($current_value) - . "'"; - } elseif (! ($type == 'datetime' || $type == 'timestamp') - || ($current_value != 'CURRENT_TIMESTAMP' - && $current_value != 'current_timestamp()') - ) { - $current_value = "'" . $this->dbi->escapeString($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 - */ - public function verifyWhetherValueCanBeTruncatedAndAppendExtraData( - $db, - $table, - $column_name, - array &$extra_data - ) { - $extra_data['isNeedToRecheck'] = false; - - $sql_for_real_value = 'SELECT ' . Util::backquote($table) . '.' - . Util::backquote($column_name) - . ' FROM ' . Util::backquote($db) . '.' - . Util::backquote($table) - . ' WHERE ' . $_POST['where_clause'][0]; - - $result = $this->dbi->tryQuery($sql_for_real_value); - $fields_meta = $this->dbi->getFieldsMeta($result); - $meta = $fields_meta[0]; - if ($row = $this->dbi->fetchRow($result)) { - $new_value = $row[0]; - if ((substr($meta->type, 0, 9) == 'timestamp') - || ($meta->type == 'datetime') - || ($meta->type == 'time') - ) { - $new_value = Util::addMicroseconds($new_value); - } elseif (mb_strpos($meta->flags, 'binary') !== false) { - $new_value = '0x' . bin2hex($new_value); - } - $extra_data['isNeedToRecheck'] = true; - $extra_data['truncatableFieldValue'] = $new_value; - } - $this->dbi->freeResult($result); - } - - /** - * Function to get the columns of a table - * - * @param string $db current db - * @param string $table current table - * - * @return array - */ - public function getTableColumns($db, $table) - { - $this->dbi->selectDb($db); - return array_values($this->dbi->getColumns($db, $table, null, true)); - } - - /** - * Function to determine Insert/Edit rows - * - * @param string $where_clause where clause - * @param string $db current database - * @param string $table current table - * - * @return mixed - */ - public function determineInsertOrEdit($where_clause, $db, $table) - { - if (isset($_POST['where_clause'])) { - $where_clause = $_POST['where_clause']; - } - if (isset($_SESSION['edit_next'])) { - $where_clause = $_SESSION['edit_next']; - unset($_SESSION['edit_next']); - $after_insert = 'edit_next'; - } - if (isset($_POST['ShowFunctionFields'])) { - $GLOBALS['cfg']['ShowFunctionFields'] = $_POST['ShowFunctionFields']; - } - if (isset($_POST['ShowFieldTypesInDataEditView'])) { - $GLOBALS['cfg']['ShowFieldTypesInDataEditView'] - = $_POST['ShowFieldTypesInDataEditView']; - } - if (isset($_POST['after_insert'])) { - $after_insert = $_POST['after_insert']; - } - - if (isset($where_clause)) { - // we are editing - $insert_mode = false; - $where_clause_array = $this->getWhereClauseArray($where_clause); - list($where_clauses, $result, $rows, $found_unique_key) - = $this->analyzeWhereClauses( - $where_clause_array, - $table, - $db - ); - } else { - // we are inserting - $insert_mode = true; - $where_clause = null; - list($result, $rows) = $this->loadFirstRow($table, $db); - $where_clauses = null; - $where_clause_array = []; - $found_unique_key = false; - } - - // Copying a row - fetched data will be inserted as a new row, - // therefore the where clause is needless. - if (isset($_POST['default_action']) - && $_POST['default_action'] === 'insert' - ) { - $where_clause = $where_clauses = null; - } - - return [ - $insert_mode, - $where_clause, - $where_clause_array, - $where_clauses, - $result, - $rows, - $found_unique_key, - isset($after_insert) ? $after_insert : null, - ]; - } - - /** - * Function to get comments for the table columns - * - * @param string $db current database - * @param string $table current table - * - * @return array comments for columns - */ - public function getCommentsMap($db, $table) - { - $comments_map = []; - - if ($GLOBALS['cfg']['ShowPropertyComments']) { - $comments_map = $this->relation->getComments($db, $table); - } - - return $comments_map; - } - - /** - * Function to get URL parameters - * - * @param string $db current database - * @param string $table current table - * - * @return array url parameters - */ - public function getUrlParameters($db, $table) - { - /** - * @todo check if we could replace by "db_|tbl_" - please clarify!? - */ - $url_params = [ - 'db' => $db, - 'sql_query' => $_POST['sql_query'], - ]; - - if (0 === strpos($GLOBALS['goto'], "tbl_")) { - $url_params['table'] = $table; - } - - return $url_params; - } - - /** - * Function to get html for the gis editor div - * - * @return string - */ - public function getHtmlForGisEditor() - { - return '
' - . '' - . '
'; - } - - /** - * Function to get html for the ignore option in insert mode - * - * @param int $row_id row id - * @param bool $checked ignore option is checked or not - * - * @return string - */ - public function getHtmlForIgnoreOption($row_id, $checked = true) - { - return '' - . '
' . "\n"; - } - - /** - * Function to get html for the function option - * - * @param array $column column - * @param string $column_name_appendix column name appendix - * - * @return String - */ - private function getHtmlForFunctionOption(array $column, $column_name_appendix) - { - return '' - . ''; - } - - /** - * Function to get html for the column type - * - * @param array $column column - * - * @return string - */ - private function getHtmlForInsertEditColumnType(array $column) - { - return ''; - } - - /** - * Function to get html for the insert edit form header - * - * @param bool $has_blob_field whether has blob field - * @param bool $is_upload whether is upload - * - * @return string - */ - public function getHtmlForInsertEditFormHeader($has_blob_field, $is_upload) - { - $html_output = 'analyzeTableColumnsArray( - $column, - $comments_map, - $timestamp_seen - ); - } - $as_is = false; - if (! empty($repopulate) && ! empty($current_row)) { - $current_row[$column['Field']] = $repopulate[$column['Field_md5']]; - $as_is = true; - } - - $extracted_columnspec - = Util::extractColumnSpec($column['Type']); - - if (-1 === $column['len']) { - $column['len'] = $this->dbi->fieldLen( - $current_result, - $column_number - ); - // length is unknown for geometry fields, - // make enough space to edit very simple WKTs - if (-1 === $column['len']) { - $column['len'] = 30; - } - } - //Call validation when the form submitted... - $onChangeClause = $chg_evt_handler - . "=\"return verificationsAfterFieldChange('" - . Sanitize::escapeJsString($column['Field_md5']) . "', '" - . Sanitize::escapeJsString($jsvkey) . "','" . $column['pma_type'] . "')\""; - - // Use an MD5 as an array index to avoid having special characters - // in the name attribute (see bug #1746964 ) - $column_name_appendix = $vkey . '[' . $column['Field_md5'] . ']'; - - if ($column['Type'] === 'datetime' - && ! isset($column['Default']) - && $column['Default'] !== null - && $insert_mode - ) { - $column['Default'] = date('Y-m-d H:i:s', time()); - } - - $html_output = $this->getHtmlForFunctionOption( - $column, - $column_name_appendix - ); - - if ($GLOBALS['cfg']['ShowFieldTypesInDataEditView']) { - $html_output .= $this->getHtmlForInsertEditColumnType($column); - } //End if - - // Get a list of GIS data types. - $gis_data_types = Util::getGISDatatypes(); - - // Prepares the field value - $real_null_value = false; - $special_chars_encoded = ''; - if (! empty($current_row)) { - // (we are editing) - list( - $real_null_value, $special_chars_encoded, $special_chars, - $data, $backup_field - ) - = $this->getSpecialCharsAndBackupFieldForExistingRow( - $current_row, - $column, - $extracted_columnspec, - $real_null_value, - $gis_data_types, - $column_name_appendix, - $as_is - ); - } else { - // (we are inserting) - // display default values - $tmp = $column; - if (isset($repopulate[$column['Field_md5']])) { - $tmp['Default'] = $repopulate[$column['Field_md5']]; - } - list($real_null_value, $data, $special_chars, $backup_field, - $special_chars_encoded - ) - = $this->getSpecialCharsAndBackupFieldForInsertingMode( - $tmp, - $real_null_value - ); - unset($tmp); - } - - $idindex = ($o_rows * $columns_cnt) + $column_number + 1; - $tabindex = $idindex; - - // Get a list of data types that are not yet supported. - $no_support_types = Util::unsupportedDatatypes(); - - // The function column - // ------------------- - $foreignData = $this->relation->getForeignData( - $foreigners, - $column['Field'], - false, - '', - '' - ); - if ($GLOBALS['cfg']['ShowFunctionFields']) { - $html_output .= $this->getFunctionColumn( - $column, - $is_upload, - $column_name_appendix, - $onChangeClause, - $no_support_types, - $tabindex_for_function, - $tabindex, - $idindex, - $insert_mode, - $readOnly, - $foreignData - ); - } - - // The null column - // --------------- - $html_output .= $this->getNullColumn( - $column, - $column_name_appendix, - $real_null_value, - $tabindex, - $tabindex_for_null, - $idindex, - $vkey, - $foreigners, - $foreignData, - $readOnly - ); - - // The value column (depends on type) - // ---------------- - // See bug #1667887 for the reason why we don't use the maxlength - // HTML attribute - - //add data attributes "no of decimals" and "data type" - $no_decimals = 0; - $type = current(explode("(", $column['pma_type'])); - if (preg_match('/\(([^()]+)\)/', $column['pma_type'], $match)) { - $match[0] = trim($match[0], '()'); - $no_decimals = $match[0]; - } - $html_output .= ''; - - //store the default value for CharEditing - $default_char_editing = $GLOBALS['cfg']['CharEditing']; - $mime_map = $this->transformations->getMime($db, $table); - $where_clause = ''; - if (isset($where_clause_array[$row_id])) { - $where_clause = $where_clause_array[$row_id]; - } - for ($column_number = 0; $column_number < $columns_cnt; $column_number++) { - $table_column = $table_columns[$column_number]; - $column_mime = []; - if (isset($mime_map[$table_column['Field']])) { - $column_mime = $mime_map[$table_column['Field']]; - } - - $virtual = [ - 'VIRTUAL', - 'PERSISTENT', - 'VIRTUAL GENERATED', - 'STORED GENERATED', - ]; - if (! in_array($table_column['Extra'], $virtual)) { - $html_output .= $this->getHtmlForInsertEditFormColumn( - $table_columns, - $column_number, - $comments_map, - $timestamp_seen, - $current_result, - $chg_evt_handler, - $jsvkey, - $vkey, - $insert_mode, - $current_row, - $o_rows, - $tabindex, - $columns_cnt, - $is_upload, - $tabindex_for_function, - $foreigners, - $tabindex_for_null, - $tabindex_for_value, - $table, - $db, - $row_id, - $titles, - $biggest_max_file_size, - $default_char_editing, - $text_dir, - $repopulate, - $column_mime, - $where_clause - ); - } - } // end for - $o_rows++; - $html_output .= ' ' - . '
' . __('Column') . '' . __('Null') . '' . __('Value') . '
' - . '' - . '
' - . $column['Field_title'] - . '' - . '' - . '' . $column['pma_type'] . '' - . '' . "\n"; - // Will be used by js/table/change.js to set the default value - // for the "Continue insertion" feature - $html_output .= '' - . $special_chars . ''; - - // Check input transformation of column - $transformed_html = ''; - if (! empty($column_mime['input_transformation'])) { - $file = $column_mime['input_transformation']; - $include_file = 'libraries/classes/Plugins/Transformations/' . $file; - if (is_file($include_file)) { - $class_name = $this->transformations->getClassName($include_file); - if (class_exists($class_name)) { - $transformation_plugin = new $class_name(); - $transformation_options = $this->transformations->getOptions( - $column_mime['input_transformation_options'] - ); - $_url_params = [ - 'db' => $db, - 'table' => $table, - 'transform_key' => $column['Field'], - 'where_clause' => $where_clause, - ]; - $transformation_options['wrapper_link'] - = Url::getCommon($_url_params); - $current_value = ''; - if (isset($current_row[$column['Field']])) { - $current_value = $current_row[$column['Field']]; - } - if (method_exists($transformation_plugin, 'getInputHtml')) { - $transformed_html = $transformation_plugin->getInputHtml( - $column, - $row_id, - $column_name_appendix, - $transformation_options, - $current_value, - $text_dir, - $tabindex, - $tabindex_for_value, - $idindex - ); - } - if (method_exists($transformation_plugin, 'getScripts')) { - $GLOBALS['plugin_scripts'] = array_merge( - $GLOBALS['plugin_scripts'], - $transformation_plugin->getScripts() - ); - } - } - } - } - if (! empty($transformed_html)) { - $html_output .= $transformed_html; - } else { - $html_output .= $this->getValueColumn( - $column, - $backup_field, - $column_name_appendix, - $onChangeClause, - $tabindex, - $tabindex_for_value, - $idindex, - $data, - $special_chars, - $foreignData, - [ - $table, - $db, - ], - $row_id, - $titles, - $text_dir, - $special_chars_encoded, - $vkey, - $is_upload, - $biggest_max_file_size, - $default_char_editing, - $no_support_types, - $gis_data_types, - $extracted_columnspec, - $readOnly - ); - } - return $html_output; - } - - /** - * Function to get html for each insert/edit row - * - * @param array $url_params url parameters - * @param array $table_columns table columns - * @param array $comments_map comments map - * @param bool $timestamp_seen whether timestamp seen - * @param array $current_result current result - * @param string $chg_evt_handler javascript change event handler - * @param string $jsvkey javascript validation key - * @param string $vkey validation key - * @param bool $insert_mode whether insert mode - * @param array $current_row current row - * @param int $o_rows row offset - * @param int $tabindex tab index - * @param int $columns_cnt columns count - * @param bool $is_upload whether upload - * @param int $tabindex_for_function tab index offset for function - * @param array $foreigners foreigners - * @param int $tabindex_for_null tab index offset for null - * @param int $tabindex_for_value tab index offset for value - * @param string $table table - * @param string $db database - * @param int $row_id row id - * @param array $titles titles - * @param int $biggest_max_file_size biggest max file size - * @param string $text_dir text direction - * @param array $repopulate the data to be repopulated - * @param array $where_clause_array the array of where clauses - * - * @return string - */ - public function getHtmlForInsertEditRow( - array $url_params, - array $table_columns, - array $comments_map, - $timestamp_seen, - $current_result, - $chg_evt_handler, - $jsvkey, - $vkey, - $insert_mode, - array $current_row, - &$o_rows, - &$tabindex, - $columns_cnt, - $is_upload, - $tabindex_for_function, - array $foreigners, - $tabindex_for_null, - $tabindex_for_value, - $table, - $db, - $row_id, - array $titles, - $biggest_max_file_size, - $text_dir, - array $repopulate, - array $where_clause_array - ) { - $html_output = $this->getHeadAndFootOfInsertRowTable($url_params) - . '

' - . '
'; - - return $html_output; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/InternalRelations.php b/srcs/phpmyadmin/libraries/classes/InternalRelations.php deleted file mode 100644 index 771ccc9..0000000 --- a/srcs/phpmyadmin/libraries/classes/InternalRelations.php +++ /dev/null @@ -1,505 +0,0 @@ - [ - 'DEFAULT_COLLATE_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - ], - 'COLLATIONS' => [ - 'CHARACTER_SET_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'CHARACTER_SETS', - 'foreign_field' => 'CHARACTER_SET_NAME', - ], - ], - 'COLLATION_CHARACTER_SET_APPLICABILITY' => [ - 'CHARACTER_SET_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'CHARACTER_SETS', - 'foreign_field' => 'CHARACTER_SET_NAME', - ], - 'COLLATION_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - ], - 'COLUMNS' => [ - 'TABLE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'CHARACTER_SET_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'CHARACTER_SETS', - 'foreign_field' => 'CHARACTER_SET_NAME', - ], - 'COLLATION_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - ], - 'COLUMN_PRIVILEGES' => [ - 'TABLE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'EVENTS' => [ - 'EVENT_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'CHARACTER_SET_CLIENT' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'CHARACTER_SETS', - 'foreign_field' => 'CHARACTER_SET_NAME', - ], - 'COLLATION_CONNECTION' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - 'DATABASE_COLLATION' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - ], - 'FILES' => [ - 'TABLESPACE_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'TABLESPACES', - 'foreign_field' => 'TABLESPACE_NAME', - ], - 'TABLE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'COLLATION_CONNECTION' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - 'ENGINE' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'ENGINES', - 'foreign_field' => 'ENGINE', - ], - ], - 'KEY_COLUMN_USAGE' => [ - 'CONSTRAINT_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'TABLE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'REFERENCED_TABLE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'PARAMETERS' => [ - 'SPECIFIC_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'CHARACTER_SET_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'CHARACTER_SETS', - 'foreign_field' => 'CHARACTER_SET_NAME', - ], - 'COLLATION_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - ], - 'PARTITIONS' => [ - 'TABLE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'TABLESPACE_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'TABLESPACES', - 'foreign_field' => 'TABLESPACE_NAME', - ], - ], - 'PROCESSLIST' => [ - 'DB' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'REFERENTIAL_CONSTRAINTS' => [ - 'CONSTRAINT_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'UNIQUE_CONSTRAINT_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'ROUTINES' => [ - 'ROUTINE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'CHARACTER_SET_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'CHARACTER_SETS', - 'foreign_field' => 'CHARACTER_SET_NAME', - ], - 'COLLATION_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - 'CHARACTER_SET_CLIENT' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'CHARACTER_SETS', - 'foreign_field' => 'CHARACTER_SET_NAME', - ], - 'COLLATION_CONNECTION' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - 'DATABASE_COLLATION' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - ], - 'SCHEMATA' => [ - 'DEFAULT_CHARACTER_SET_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'CHARACTER_SETS', - 'foreign_field' => 'CHARACTER_SET_NAME', - ], - 'DEFAULT_COLLATION_NAME' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - ], - 'SCHEMA_PRIVILEGES' => [ - 'TABLE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'STATISTICS' => [ - 'TABLE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'INDEX_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'TABLES' => [ - 'TABLE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'TABLE_COLLATION' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - 'ENGINE' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'ENGINES', - 'foreign_field' => 'ENGINE', - ], - ], - 'TABLESAPCES' => [ - 'ENGINE' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'ENGINES', - 'foreign_field' => 'ENGINE', - ], - ], - 'TABLE_CONSTRAINTS' => [ - 'CONSTRAINT_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'TABLE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'TABLE_PRIVILEGES' => [ - 'TABLE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'TRIGGERS' => [ - 'TRIGGER_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'EVENT_OBJECT_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'CHARACTER_SET_CLIENT' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'CHARACTER_SETS', - 'foreign_field' => 'CHARACTER_SET_NAME', - ], - 'COLLATION_CONNECTION' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - 'DATABASE_COLLATION' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - ], - 'VIEWS' => [ - 'TABLE_SCHEMA' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'CHARACTER_SET_CLIENT' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'CHARACTER_SETS', - 'foreign_field' => 'CHARACTER_SET_NAME', - ], - 'COLLATION_CONNECTION' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - ], - ]; - - /** - * @var array - */ - private static $mysql = [ - 'columns_priv' => [ - 'Db' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'db' => [ - 'Db' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'event' => [ - 'db' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'character_set_client' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'CHARACTER_SETS', - 'foreign_field' => 'CHARACTER_SET_NAME', - ], - 'collation_connection' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - 'db_collation' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - ], - 'help_category' => [ - 'parent_category_id' => [ - 'foreign_db' => 'mysql', - 'foreign_table' => 'help_category', - 'foreign_field' => 'help_category_id', - ], - ], - 'help_relation' => [ - 'help_topic_id' => [ - 'foreign_db' => 'mysql', - 'foreign_table' => 'help_topic', - 'foreign_field' => 'help_topic_id', - ], - 'help_keyword_id' => [ - 'foreign_db' => 'mysql', - 'foreign_table' => 'help_keyword', - 'foreign_field' => 'help_keyword_id', - ], - ], - 'help_topic' => [ - 'help_category_id' => [ - 'foreign_db' => 'mysql', - 'foreign_table' => 'help_category', - 'foreign_field' => 'help_category_id', - ], - ], - 'innodb_index_stats' => [ - 'database_name' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'innodb_table_stats' => [ - 'database_name' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'proc' => [ - 'db' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - 'character_set_client' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'CHARACTER_SETS', - 'foreign_field' => 'CHARACTER_SET_NAME', - ], - 'collation_connection' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - 'db_collation' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'COLLATIONS', - 'foreign_field' => 'COLLATION_NAME', - ], - ], - 'proc_priv' => [ - 'Db' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'servers' => [ - 'Db' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'slow_log' => [ - 'db' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'tables_priv' => [ - 'Db' => [ - 'foreign_db' => 'information_schema', - 'foreign_table' => 'SCHEMATA', - 'foreign_field' => 'SCHEMA_NAME', - ], - ], - 'time_zone_name' => [ - 'Time_zone_id' => [ - 'foreign_db' => 'mysql', - 'foreign_table' => 'time_zone', - 'foreign_field' => 'Time_zone_id', - ], - ], - 'time_zone_transition' => [ - 'Time_zone_id' => [ - 'foreign_db' => 'mysql', - 'foreign_table' => 'time_zone', - 'foreign_field' => 'Time_zone_id', - ], - 'Transition_time' => [ - 'foreign_db' => 'mysql', - 'foreign_table' => 'time_zone_leap_second', - 'foreign_field' => 'Transition_time', - ], - ], - 'time_zone_transition_type' => [ - 'Time_zone_id' => [ - 'foreign_db' => 'mysql', - 'foreign_table' => 'time_zone', - 'foreign_field' => 'Time_zone_id', - ], - ], - ]; - - /** - * @return array - */ - public static function getInformationSchema(): array - { - return self::$informationSchema; - } - - /** - * @return array - */ - public static function getMySql(): array - { - return self::$mysql; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/IpAllowDeny.php b/srcs/phpmyadmin/libraries/classes/IpAllowDeny.php deleted file mode 100644 index d1a7c79..0000000 --- a/srcs/phpmyadmin/libraries/classes/IpAllowDeny.php +++ /dev/null @@ -1,336 +0,0 @@ - -1 - || mb_strpos($ipToTest, ':') > -1 - ) { - // assume IPv6 - $result = $this->ipv6MaskTest($testRange, $ipToTest); - } else { - $result = $this->ipv4MaskTest($testRange, $ipToTest); - } - - return $result; - } - - /** - * 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 - */ - public function 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 += pow(2, 30 - $i); - } // end if - } // end for - - return ($maskl & $rangel) == ($maskl & $ipl); - } - - // 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 - - return $result; - } - - /** - * IPv6 matcher - * CIDR section taken from https://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 - */ - public function ipv6MaskTest($test_range, $ip_to_test) - { - $result = true; - - // convert to lowercase for easier comparison - $test_range = mb_strtolower($test_range); - $ip_to_test = mb_strtolower($ip_to_test); - - $is_cidr = mb_strpos($test_range, '/') > -1; - $is_range = mb_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 = hash_equals($ip_hex, $range_hex); - return $result; - } - - if ($is_range) { - // what range do we operate on? - $range_match = []; - $match = preg_match( - '/\[([0-9a-f]+)\-([0-9a-f]+)\]/', - $test_range, - $range_match - ); - if ($match) { - $range_start = $range_match[1]; - $range_end = $range_match[2]; - - // get the first and last allowed IPs - $first_ip = str_replace($range_match[0], $range_start, $test_range); - $first_hex = bin2hex(inet_pton($first_ip)); - $last_ip = str_replace($range_match[0], $range_end, $test_range); - $last_hex = bin2hex(inet_pton($last_ip)); - - // check if the IP to test is within the range - $result = ($ip_hex >= $first_hex && $ip_hex <= $last_hex); - } - return $result; - } - - if ($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); - - $flexbits = 128 - (int) $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 = mb_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; - } - - // check if the IP to test is within the range - $result = ($ip_hex >= $first_hex && $ip_hex <= $last_hex); - } - - return $result; - } - - /** - * Runs through IP Allow rules the use of it below for more information - * - * @return bool Whether rule has matched - * - * @access public - * - * @see Core::getIp() - */ - public function allow() - { - return $this->allowDeny("allow"); - } - - /** - * Runs through IP Deny rules the use of it below for more information - * - * @return bool Whether rule has matched - * - * @access public - * - * @see Core::getIp() - */ - public function deny() - { - return $this->allowDeny("deny"); - } - - /** - * 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 Whether rule has matched - * - * @access public - * - * @see Core::getIp() - */ - private function allowDeny($type) - { - global $cfg; - - // Grabs true IP of the user and returns if it can't be found - $remote_ip = Core::getIp(); - if (empty($remote_ip)) { - return false; - } - - // copy username - $username = $cfg['Server']['user']; - - // copy rule database - if (isset($cfg['Server']['AllowDeny']['rules'])) { - $rules = $cfg['Server']['AllowDeny']['rules']; - if (! is_array($rules)) { - $rules = []; - } - } else { - $rules = []; - } - - // lookup table for some name shortcuts - $shortcuts = [ - 'all' => '0.0.0.0/0', - 'localhost' => '127.0.0.1/8', - ]; - - // Provide some useful shortcuts if server gives us address: - if (Core::getenv('SERVER_ADDR')) { - $shortcuts['localnetA'] = Core::getenv('SERVER_ADDR') . '/8'; - $shortcuts['localnetB'] = Core::getenv('SERVER_ADDR') . '/16'; - $shortcuts['localnetC'] = Core::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 - && (! hash_equals($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 ($this->ipMaskTest($rule_data[2], $remote_ip)) { - return true; - } - } // end while - - return false; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Language.php b/srcs/phpmyadmin/libraries/classes/Language.php deleted file mode 100644 index d88fdf9..0000000 --- a/srcs/phpmyadmin/libraries/classes/Language.php +++ /dev/null @@ -1,204 +0,0 @@ -code = $code; - $this->name = $name; - $this->native = $native; - if (strpos($regex, '[-_]') === false) { - $regex = str_replace('|', '([-_][[:alpha:]]{2,3})?|', $regex); - } - $this->regex = $regex; - $this->mysql = $mysql; - } - - /** - * Returns native name for language - * - * @return string - */ - public function getNativeName() - { - return $this->native; - } - - /** - * Returns English name for language - * - * @return string - */ - public function getEnglishName() - { - return $this->name; - } - - /** - * Returns verbose name for language - * - * @return string - */ - public function getName() - { - if (! empty($this->native)) { - return $this->native . ' - ' . $this->name; - } - - return $this->name; - } - - /** - * Returns language code - * - * @return string - */ - public function getCode() - { - return $this->code; - } - - /** - * Returns MySQL locale code, can be empty - * - * @return string - */ - public function getMySQLLocale() - { - return $this->mysql; - } - - /** - * Compare function used for sorting - * - * @param Language $other Other object to compare - * - * @return int same as strcmp - */ - public function cmp($other) - { - return strcmp($this->name, $other->name); - } - - /** - * Checks whether language is currently active. - * - * @return bool - */ - public function isActive() - { - return $GLOBALS['lang'] == $this->code; - } - - /** - * Checks whether language matches HTTP header Accept-Language. - * - * @param string $header Header content - * - * @return bool - */ - public function matchesAcceptLanguage($header) - { - $pattern = '/^(' - . addcslashes($this->regex, '/') - . ')(;q=[0-9]\\.[0-9])?$/i'; - return preg_match($pattern, $header); - } - - /** - * Checks whether language matches HTTP header User-Agent - * - * @param string $header Header content - * - * @return bool - */ - public function matchesUserAgent($header) - { - $pattern = '/(\(|\[|;[[:space:]])(' - . addcslashes($this->regex, '/') - . ')(;|\]|\))/i'; - return preg_match($pattern, $header); - } - - /** - * Checks whether language is RTL - * - * @return bool - */ - public function isRTL() - { - return in_array($this->code, ['ar', 'fa', 'he', 'ur']); - } - - /** - * Activates given translation - * - * @return void - */ - public function activate() - { - $GLOBALS['lang'] = $this->code; - - // Set locale - _setlocale(0, $this->code); - _bindtextdomain('phpmyadmin', LOCALE_PATH); - _textdomain('phpmyadmin'); - // Set PHP locale as well - if (function_exists('setlocale')) { - setlocale(0, $this->code); - } - - /* Text direction for language */ - if ($this->isRTL()) { - $GLOBALS['text_dir'] = 'rtl'; - } else { - $GLOBALS['text_dir'] = 'ltr'; - } - - /* TCPDF */ - $GLOBALS['l'] = []; - - /* TCPDF settings */ - $GLOBALS['l']['a_meta_charset'] = 'UTF-8'; - $GLOBALS['l']['a_meta_dir'] = $GLOBALS['text_dir']; - $GLOBALS['l']['a_meta_language'] = $this->code; - - /* TCPDF translations */ - $GLOBALS['l']['w_page'] = __('Page number:'); - - /* Show possible warnings from langauge selection */ - LanguageManager::getInstance()->showWarnings(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/LanguageManager.php b/srcs/phpmyadmin/libraries/classes/LanguageManager.php deleted file mode 100644 index 84b12b7..0000000 --- a/srcs/phpmyadmin/libraries/classes/LanguageManager.php +++ /dev/null @@ -1,975 +0,0 @@ - [ - 'af', - 'Afrikaans', - '', - 'af|afrikaans', - '', - ], - 'am' => [ - 'am', - 'Amharic', - 'አማርኛ', - 'am|amharic', - '', - ], - 'ar' => [ - 'ar', - 'Arabic', - 'العربية', - 'ar|arabic', - 'ar_AE', - ], - 'az' => [ - 'az', - 'Azerbaijani', - 'Azərbaycanca', - 'az|azerbaijani', - '', - ], - 'bn' => [ - 'bn', - 'Bangla', - 'বাংলা', - 'bn|bangla', - '', - ], - 'be' => [ - 'be', - 'Belarusian', - 'Беларуская', - 'be|belarusian', - 'be_BY', - ], - 'be@latin' => [ - 'be@latin', - 'Belarusian (latin)', - 'Biełaruskaja', - 'be[-_]lat|be@latin|belarusian latin', - '', - ], - 'bg' => [ - 'bg', - 'Bulgarian', - 'Български', - 'bg|bulgarian', - 'bg_BG', - ], - 'bs' => [ - 'bs', - 'Bosnian', - 'Bosanski', - 'bs|bosnian', - '', - ], - 'br' => [ - 'br', - 'Breton', - 'Brezhoneg', - 'br|breton', - '', - ], - 'brx' => [ - 'brx', - 'Bodo', - 'बड़ो', - 'brx|bodo', - '', - ], - 'ca' => [ - 'ca', - 'Catalan', - 'Català', - 'ca|catalan', - 'ca_ES', - ], - 'ckb' => [ - 'ckb', - 'Sorani', - 'سۆرانی', - 'ckb|sorani', - '', - ], - 'cs' => [ - 'cs', - 'Czech', - 'Čeština', - 'cs|czech', - 'cs_CZ', - ], - 'cy' => [ - 'cy', - 'Welsh', - 'Cymraeg', - 'cy|welsh', - '', - ], - 'da' => [ - 'da', - 'Danish', - 'Dansk', - 'da|danish', - 'da_DK', - ], - 'de' => [ - 'de', - 'German', - 'Deutsch', - 'de|german', - 'de_DE', - ], - 'el' => [ - 'el', - 'Greek', - 'Ελληνικά', - 'el|greek', - '', - ], - 'en' => [ - 'en', - 'English', - '', - 'en|english', - 'en_US', - ], - 'en_gb' => [ - 'en_GB', - 'English (United Kingdom)', - '', - 'en[_-]gb|english (United Kingdom)', - 'en_GB', - ], - 'eo' => [ - 'eo', - 'Esperanto', - 'Esperanto', - 'eo|esperanto', - '', - ], - 'es' => [ - 'es', - 'Spanish', - 'Español', - 'es|spanish', - 'es_ES', - ], - 'et' => [ - 'et', - 'Estonian', - 'Eesti', - 'et|estonian', - 'et_EE', - ], - 'eu' => [ - 'eu', - 'Basque', - 'Euskara', - 'eu|basque', - 'eu_ES', - ], - 'fa' => [ - 'fa', - 'Persian', - 'فارسی', - 'fa|persian', - '', - ], - 'fi' => [ - 'fi', - 'Finnish', - 'Suomi', - 'fi|finnish', - 'fi_FI', - ], - 'fil' => [ - 'fil', - 'Filipino', - 'Pilipino', - 'fil|filipino', - '', - ], - 'fr' => [ - 'fr', - 'French', - 'Français', - 'fr|french', - 'fr_FR', - ], - 'fy' => [ - 'fy', - 'Frisian', - 'Frysk', - 'fy|frisian', - '', - ], - 'gl' => [ - 'gl', - 'Galician', - 'Galego', - 'gl|galician', - 'gl_ES', - ], - 'gu' => [ - 'gu', - 'Gujarati', - 'ગુજરાતી', - 'gu|gujarati', - 'gu_IN', - ], - 'he' => [ - 'he', - 'Hebrew', - 'עברית', - 'he|hebrew', - 'he_IL', - ], - 'hi' => [ - 'hi', - 'Hindi', - 'हिन्दी', - 'hi|hindi', - 'hi_IN', - ], - 'hr' => [ - 'hr', - 'Croatian', - 'Hrvatski', - 'hr|croatian', - 'hr_HR', - ], - 'hu' => [ - 'hu', - 'Hungarian', - 'Magyar', - 'hu|hungarian', - 'hu_HU', - ], - 'hy' => [ - 'hy', - 'Armenian', - 'Հայերէն', - 'hy|armenian', - '', - ], - 'ia' => [ - 'ia', - 'Interlingua', - '', - 'ia|interlingua', - '', - ], - 'id' => [ - 'id', - 'Indonesian', - 'Bahasa Indonesia', - 'id|indonesian', - 'id_ID', - ], - 'ig' => [ - 'ig', - 'Igbo', - 'Asụsụ Igbo', - 'ig|igbo', - '', - ], - 'it' => [ - 'it', - 'Italian', - 'Italiano', - 'it|italian', - 'it_IT', - ], - 'ja' => [ - 'ja', - 'Japanese', - '日本語', - 'ja|japanese', - 'ja_JP', - ], - 'ko' => [ - 'ko', - 'Korean', - '한국어', - 'ko|korean', - 'ko_KR', - ], - 'ka' => [ - 'ka', - 'Georgian', - 'ქართული', - 'ka|georgian', - '', - ], - 'kab' => [ - 'kab', - 'Kabylian', - 'Taqbaylit', - 'kab|kabylian', - '', - ], - 'kk' => [ - 'kk', - 'Kazakh', - 'Қазақ', - 'kk|kazakh', - '', - ], - 'km' => [ - 'km', - 'Khmer', - 'ខ្មែរ', - 'km|khmer', - '', - ], - 'kn' => [ - 'kn', - 'Kannada', - 'ಕನ್ನಡ', - 'kn|kannada', - '', - ], - 'ksh' => [ - 'ksh', - 'Colognian', - 'Kölsch', - 'ksh|colognian', - '', - ], - 'ku' => [ - 'ku', - 'Kurdish', - 'کوردی', - 'ku|kurdish', - '', - ], - 'ky' => [ - 'ky', - 'Kyrgyz', - 'Кыргызча', - 'ky|kyrgyz', - '', - ], - 'li' => [ - 'li', - 'Limburgish', - 'Lèmbörgs', - 'li|limburgish', - '', - ], - 'lt' => [ - 'lt', - 'Lithuanian', - 'Lietuvių', - 'lt|lithuanian', - 'lt_LT', - ], - 'lv' => [ - 'lv', - 'Latvian', - 'Latviešu', - 'lv|latvian', - 'lv_LV', - ], - 'mk' => [ - 'mk', - 'Macedonian', - 'Macedonian', - 'mk|macedonian', - 'mk_MK', - ], - 'ml' => [ - 'ml', - 'Malayalam', - 'Malayalam', - 'ml|malayalam', - '', - ], - 'mn' => [ - 'mn', - 'Mongolian', - 'Монгол', - 'mn|mongolian', - 'mn_MN', - ], - 'ms' => [ - 'ms', - 'Malay', - 'Bahasa Melayu', - 'ms|malay', - 'ms_MY', - ], - 'my' => [ - 'my', - 'Burmese', - 'မြန်မာ', - 'my|burmese', - '', - ], - 'ne' => [ - 'ne', - 'Nepali', - 'नेपाली', - 'ne|nepali', - '', - ], - 'nb' => [ - 'nb', - 'Norwegian', - 'Norsk', - 'nb|norwegian', - 'nb_NO', - ], - 'nn' => [ - 'nn', - 'Norwegian Nynorsk', - 'Nynorsk', - 'nn|nynorsk', - 'nn_NO', - ], - 'nl' => [ - 'nl', - 'Dutch', - 'Nederlands', - 'nl|dutch', - 'nl_NL', - ], - 'pa' => [ - 'pa', - 'Punjabi', - 'ਪੰਜਾਬੀ', - 'pa|punjabi', - '', - ], - 'pl' => [ - 'pl', - 'Polish', - 'Polski', - 'pl|polish', - 'pl_PL', - ], - 'pt' => [ - 'pt', - 'Portuguese', - 'Português', - 'pt|portuguese', - 'pt_PT', - ], - 'pt_br' => [ - 'pt_BR', - 'Portuguese (Brazil)', - 'Português (Brasil)', - 'pt[-_]br|portuguese (brazil)', - 'pt_BR', - ], - 'ro' => [ - 'ro', - 'Romanian', - 'Română', - 'ro|romanian', - 'ro_RO', - ], - 'ru' => [ - 'ru', - 'Russian', - 'Русский', - 'ru|russian', - 'ru_RU', - ], - 'si' => [ - 'si', - 'Sinhala', - 'සිංහල', - 'si|sinhala', - '', - ], - 'sk' => [ - 'sk', - 'Slovak', - 'Slovenčina', - 'sk|slovak', - 'sk_SK', - ], - 'sl' => [ - 'sl', - 'Slovenian', - 'Slovenščina', - 'sl|slovenian', - 'sl_SI', - ], - 'sq' => [ - 'sq', - 'Albanian', - 'Shqip', - 'sq|albanian', - 'sq_AL', - ], - 'sr@latin' => [ - 'sr@latin', - 'Serbian (latin)', - 'Srpski', - 'sr[-_]lat|sr@latin|serbian latin', - 'sr_YU', - ], - 'sr' => [ - 'sr', - 'Serbian', - 'Српски', - 'sr|serbian', - 'sr_YU', - ], - 'sv' => [ - 'sv', - 'Swedish', - 'Svenska', - 'sv|swedish', - 'sv_SE', - ], - 'ta' => [ - 'ta', - 'Tamil', - 'தமிழ்', - 'ta|tamil', - 'ta_IN', - ], - 'te' => [ - 'te', - 'Telugu', - 'తెలుగు', - 'te|telugu', - 'te_IN', - ], - 'th' => [ - 'th', - 'Thai', - 'ภาษาไทย', - 'th|thai', - 'th_TH', - ], - 'tk' => [ - 'tk', - 'Turkmen', - 'Türkmençe', - 'tk|turkmen', - '', - ], - 'tr' => [ - 'tr', - 'Turkish', - 'Türkçe', - 'tr|turkish', - 'tr_TR', - ], - 'tt' => [ - 'tt', - 'Tatarish', - 'Tatarça', - 'tt|tatarish', - '', - ], - 'ug' => [ - 'ug', - 'Uyghur', - 'ئۇيغۇرچە', - 'ug|uyghur', - '', - ], - 'uk' => [ - 'uk', - 'Ukrainian', - 'Українська', - 'uk|ukrainian', - 'uk_UA', - ], - 'ur' => [ - 'ur', - 'Urdu', - 'اُردوُ', - 'ur|urdu', - 'ur_PK', - ], - 'uz@latin' => [ - 'uz@latin', - 'Uzbek (latin)', - 'O‘zbekcha', - 'uz[-_]lat|uz@latin|uzbek-latin', - '', - ], - 'uz' => [ - 'uz', - 'Uzbek (cyrillic)', - 'Ўзбекча', - 'uz[-_]cyr|uz@cyrillic|uzbek-cyrillic', - '', - ], - 'vi' => [ - 'vi', - 'Vietnamese', - 'Tiếng Việt', - 'vi|vietnamese', - 'vi_VN', - ], - 'vls' => [ - 'vls', - 'Flemish', - 'West-Vlams', - 'vls|flemish', - '', - ], - 'zh_tw' => [ - 'zh_TW', - 'Chinese traditional', - '中文', - 'zh[-_](tw|hk)|chinese traditional', - 'zh_TW', - ], - // only TW and HK use traditional Chinese while others (CN, SG, MY) - // use simplified Chinese - 'zh_cn' => [ - 'zh_CN', - 'Chinese simplified', - '中文', - 'zh(?![-_](tw|hk))([-_][[:alpha:]]{2,3})?|chinese simplified', - 'zh_CN', - ], - ]; - - private $_available_locales; - private $_available_languages; - private $_lang_failed_cfg; - private $_lang_failed_cookie; - private $_lang_failed_request; - - /** - * @var LanguageManager - */ - private static $instance; - - /** - * Returns LanguageManager singleton - * - * @return LanguageManager - */ - public static function getInstance() - { - if (self::$instance === null) { - self::$instance = new LanguageManager(); - } - return self::$instance; - } - - /** - * Returns list of available locales - * - * @return array - */ - public function listLocaleDir() - { - $result = ['en']; - - /* Check for existing directory */ - if (! is_dir(LOCALE_PATH)) { - return $result; - } - - /* Open the directory */ - $handle = @opendir(LOCALE_PATH); - /* This can happen if the kit is English-only */ - if ($handle === false) { - return $result; - } - - /* Process all files */ - while (false !== ($file = readdir($handle))) { - $path = LOCALE_PATH - . '/' . $file - . '/LC_MESSAGES/phpmyadmin.mo'; - if ($file != "." - && $file != ".." - && @file_exists($path) - ) { - $result[] = $file; - } - } - /* Close the handle */ - closedir($handle); - - return $result; - } - - /** - * Returns (cached) list of all available locales - * - * @return array of strings - */ - public function availableLocales() - { - if (! $this->_available_locales) { - if (! isset($GLOBALS['PMA_Config']) || empty($GLOBALS['PMA_Config']->get('FilterLanguages'))) { - $this->_available_locales = $this->listLocaleDir(); - } else { - $this->_available_locales = preg_grep( - '@' . $GLOBALS['PMA_Config']->get('FilterLanguages') . '@', - $this->listLocaleDir() - ); - } - } - return $this->_available_locales; - } - - /** - * Checks whether there are some languages available - * - * @return boolean - */ - public function hasChoice() - { - return count($this->availableLanguages()) > 1; - } - - /** - * Returns (cached) list of all available languages - * - * @return Language[] array of Language objects - */ - public function availableLanguages() - { - if (! $this->_available_languages) { - $this->_available_languages = []; - - foreach ($this->availableLocales() as $lang) { - $lang = strtolower($lang); - if (isset(static::$_language_data[$lang])) { - $data = static::$_language_data[$lang]; - $this->_available_languages[$lang] = new Language( - $data[0], - $data[1], - $data[2], - $data[3], - $data[4] - ); - } else { - $this->_available_languages[$lang] = new Language( - $lang, - ucfirst($lang), - ucfirst($lang), - $lang, - '' - ); - } - } - } - return $this->_available_languages; - } - - /** - * Returns (cached) list of all available languages sorted - * by name - * - * @return Language[] array of Language objects - */ - public function sortedLanguages() - { - $this->availableLanguages(); - uasort($this->_available_languages, function ($a, $b) { - return $a->cmp($b); - }); - return $this->_available_languages; - } - - /** - * Return Language object for given code - * - * @param string $code Language code - * - * @return Language|false Language object or false on failure - */ - public function getLanguage($code) - { - $code = strtolower($code); - $langs = $this->availableLanguages(); - if (isset($langs[$code])) { - return $langs[$code]; - } - return false; - } - - /** - * Return currently active Language object - * - * @return Language Language object - */ - public function getCurrentLanguage() - { - return $this->_available_languages[strtolower($GLOBALS['lang'])]; - } - - /** - * Activates language based on configuration, user preferences or - * browser - * - * @return Language - */ - public function selectLanguage() - { - // check forced language - if (! empty($GLOBALS['PMA_Config']->get('Lang'))) { - $lang = $this->getLanguage($GLOBALS['PMA_Config']->get('Lang')); - if ($lang !== false) { - return $lang; - } - $this->_lang_failed_cfg = true; - } - - // Don't use REQUEST in following code as it might be confused by cookies - // with same name. Check user requested language (POST) - if (! empty($_POST['lang'])) { - $lang = $this->getLanguage($_POST['lang']); - if ($lang !== false) { - return $lang; - } - $this->_lang_failed_request = true; - } - - // check user requested language (GET) - if (! empty($_GET['lang'])) { - $lang = $this->getLanguage($_GET['lang']); - if ($lang !== false) { - return $lang; - } - $this->_lang_failed_request = true; - } - - // check previous set language - if (! empty($GLOBALS['PMA_Config']->getCookie('pma_lang'))) { - $lang = $this->getLanguage($GLOBALS['PMA_Config']->getCookie('pma_lang')); - if ($lang !== false) { - return $lang; - } - $this->_lang_failed_cookie = true; - } - - $langs = $this->availableLanguages(); - - // try to find out user's language by checking its HTTP_ACCEPT_LANGUAGE variable; - $accepted_languages = Core::getenv('HTTP_ACCEPT_LANGUAGE'); - if ($accepted_languages) { - foreach (explode(',', $accepted_languages) as $header) { - foreach ($langs as $language) { - if ($language->matchesAcceptLanguage($header)) { - return $language; - } - } - } - } - - // try to find out user's language by checking its HTTP_USER_AGENT variable - $user_agent = Core::getenv('HTTP_USER_AGENT'); - if (! empty($user_agent)) { - foreach ($langs as $language) { - if ($language->matchesUserAgent($user_agent)) { - return $language; - } - } - } - - // Didn't catch any valid lang : we use the default settings - if (isset($langs[$GLOBALS['PMA_Config']->get('DefaultLang')])) { - return $langs[$GLOBALS['PMA_Config']->get('DefaultLang')]; - } - - // Fallback to English - return $langs['en']; - } - - /** - * Displays warnings about invalid languages. This needs to be postponed - * to show messages at time when language is initialized. - * - * @return void - */ - public function showWarnings() - { - // now, that we have loaded the language strings we can send the errors - if ($this->_lang_failed_cfg - || $this->_lang_failed_cookie - || $this->_lang_failed_request - ) { - trigger_error( - __('Ignoring unsupported language code.'), - E_USER_ERROR - ); - } - } - - - /** - * Returns HTML code for the language selector - * - * @param Template $template Template instance - * @param boolean $use_fieldset whether to use fieldset for selection - * @param boolean $show_doc whether to show documentation links - * - * @return string - * - * @access public - */ - public function getSelectorDisplay(Template $template, $use_fieldset = false, $show_doc = true) - { - $_form_params = [ - 'db' => $GLOBALS['db'], - 'table' => $GLOBALS['table'], - ]; - - // 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 .= Util::showDocu('faq', 'faq7-2'); - } - - $available_languages = $this->sortedLanguages(); - - return $template->render('select_lang', [ - 'language_title' => $language_title, - 'use_fieldset' => $use_fieldset, - 'available_languages' => $available_languages, - '_form_params' => $_form_params, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Linter.php b/srcs/phpmyadmin/libraries/classes/Linter.php deleted file mode 100644 index ff31bfa..0000000 --- a/srcs/phpmyadmin/libraries/classes/Linter.php +++ /dev/null @@ -1,186 +0,0 @@ -length() : strlen($str); - - $lines = [0]; - for ($i = 0; $i < $len; ++$i) { - if ($str[$i] === "\n") { - $lines[] = $i + 1; - } - } - return $lines; - } - - /** - * Computes the number of the line and column given an absolute position. - * - * @param array $lines The starting position of each line. - * @param int $pos The absolute position - * - * @return array - */ - public static function findLineNumberAndColumn(array $lines, $pos) - { - $line = 0; - foreach ($lines as $lineNo => $lineStart) { - if ($lineStart > $pos) { - break; - } - $line = $lineNo; - } - return [ - $line, - $pos - $lines[$line], - ]; - } - - /** - * Runs the linting process. - * - * @param string $query The query to be checked. - * - * @return array - */ - public static function lint($query) - { - // Disabling lint for huge queries to save some resources. - if (mb_strlen($query) > 10000) { - return [ - [ - 'message' => __( - 'Linting is disabled for this query because it exceeds the ' - . 'maximum length.' - ), - 'fromLine' => 0, - 'fromColumn' => 0, - 'toLine' => 0, - 'toColumn' => 0, - 'severity' => 'warning', - ], - ]; - } - - /** - * Lexer used for tokenizing the query. - * - * @var Lexer - */ - $lexer = new Lexer($query); - - /** - * Parsed used for analysing the query. - * - * @var Parser - */ - $parser = new Parser($lexer->list); - - /** - * Array containing all errors. - * - * @var array - */ - $errors = ParserError::get([$lexer, $parser]); - - /** - * The response containing of all errors. - * - * @var array - */ - $response = []; - - /** - * The starting position for each line. - * - * CodeMirror requires relative position to line, but the parser stores - * only the absolute position of the character in string. - * - * @var array - */ - $lines = static::getLines($query); - - // Building the response. - foreach ($errors as $idx => $error) { - // Starting position of the string that caused the error. - list($fromLine, $fromColumn) = static::findLineNumberAndColumn( - $lines, - $error[3] - ); - - // Ending position of the string that caused the error. - list($toLine, $toColumn) = static::findLineNumberAndColumn( - $lines, - $error[3] + mb_strlen((string) $error[2]) - ); - - // Building the response. - $response[] = [ - 'message' => sprintf( - __('%1$s (near %2$s)'), - htmlspecialchars((string) $error[0]), - htmlspecialchars((string) $error[2]) - ), - 'fromLine' => $fromLine, - 'fromColumn' => $fromColumn, - 'toLine' => $toLine, - 'toColumn' => $toColumn, - 'severity' => 'error', - ]; - } - - // Sending back the answer. - return $response; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/ListAbstract.php b/srcs/phpmyadmin/libraries/classes/ListAbstract.php deleted file mode 100644 index e5b9a7a..0000000 --- a/srcs/phpmyadmin/libraries/classes/ListAbstract.php +++ /dev/null @@ -1,107 +0,0 @@ -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 - * - * @param mixed[] ...$params params - * @return bool true if all items exists, otherwise false - */ - public function exists(...$params) - { - $this_elements = $this->getArrayCopy(); - foreach ($params as $result) { - if (! in_array($result, $this_elements)) { - return false; - } - } - return true; - } - - /** - * returns HTML '; - return $html; - } - - /** - * Gets HTML for replace_prefix_tbl or copy_tbl_change_prefix - * - * @param string $action action type - * @param array $urlParams URL params - * - * @return string - */ - public function getHtmlForReplacePrefixTable($action, array $urlParams) - { - $html = '
'; - $html .= Url::getHiddenInputs($urlParams); - $html .= '
'; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= '
' . __('From') . ''; - $html .= ''; - $html .= '
' . __('To') . ''; - $html .= ''; - $html .= '
'; - $html .= '
'; - $html .= ''; - $html .= '
'; - - return $html; - } - - /** - * Gets HTML for add_prefix_tbl - * - * @param string $action action type - * @param array $urlParams URL params - * - * @return string - */ - public function getHtmlForAddPrefixTable($action, array $urlParams) - { - $html = '
'; - $html .= Url::getHiddenInputs($urlParams); - $html .= '
'; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= '
' . __('Add prefix') . ''; - $html .= ''; - $html .= '
'; - $html .= '
'; - $html .= ''; - $html .= '
'; - - return $html; - } - - /** - * Gets HTML for other mult_submits actions - * - * @param string $what mult_submit type - * @param string $action action type - * @param array $urlParams URL params - * @param string $fullQuery full sql query string - * - * @return string - */ - public function getHtmlForOtherActions($what, $action, array $urlParams, $fullQuery) - { - $html = '
'; - $html .= Url::getHiddenInputs($urlParams); - $html .= '
'; - $html .= ''; - if ($what == 'drop_db') { - $html .= __('You are about to DESTROY a complete database!') . ' '; - } - $html .= __('Do you really want to execute the following query?'); - $html .= ''; - $html .= '' . $fullQuery . ''; - $html .= '
'; - $html .= '
'; - // Display option to disable foreign key checks while dropping tables - if ($what === 'drop_tbl' || $what === 'empty_tbl' || $what === 'row_delete') { - $html .= '
'; - $html .= Util::getFKCheckbox(); - $html .= '
'; - } - $html .= ''; - $html .= ''; - $html .= '
'; - $html .= '
'; - - return $html; - } - - /** - * Get query string from Selected - * - * @param string $what mult_submit type - * @param string $table table name - * @param array $selected the selected columns - * @param array $views table views - * - * @return array - */ - public function getQueryFromSelected($what, $table, array $selected, array $views) - { - $reload = false; - $fullQueryViews = null; - $fullQuery = ''; - - if ($what == 'drop_tbl') { - $fullQueryViews = ''; - } - - $selectedCount = count($selected); - $i = 0; - foreach ($selected as $selectedValue) { - switch ($what) { - case 'row_delete': - $fullQuery .= 'DELETE FROM ' - . Util::backquote(htmlspecialchars($table)) - // Do not append a "LIMIT 1" clause here - // (it's not binlog friendly). - // We don't need the clause because the calling panel permits - // this feature only when there is a unique index. - . ' WHERE ' . htmlspecialchars($selectedValue) - . ';
'; - break; - case 'drop_db': - $fullQuery .= 'DROP DATABASE ' - . Util::backquote(htmlspecialchars($selectedValue)) - . ';
'; - $reload = true; - break; - - case 'drop_tbl': - $current = $selectedValue; - if (! empty($views) && in_array($current, $views)) { - $fullQueryViews .= (empty($fullQueryViews) ? 'DROP VIEW ' : ', ') - . Util::backquote(htmlspecialchars($current)); - } else { - $fullQuery .= (empty($fullQuery) ? 'DROP TABLE ' : ', ') - . Util::backquote(htmlspecialchars($current)); - } - break; - - case 'empty_tbl': - $fullQuery .= 'TRUNCATE '; - $fullQuery .= Util::backquote(htmlspecialchars($selectedValue)) - . ';
'; - break; - - case 'primary_fld': - if ($fullQuery == '') { - $fullQuery .= 'ALTER TABLE ' - . Util::backquote(htmlspecialchars($table)) - . '
  DROP PRIMARY KEY,' - . '
   ADD PRIMARY KEY(' - . '
     ' - . Util::backquote(htmlspecialchars($selectedValue)) - . ','; - } else { - $fullQuery .= '
     ' - . Util::backquote(htmlspecialchars($selectedValue)) - . ','; - } - if ($i == $selectedCount - 1) { - $fullQuery = preg_replace('@,$@', ');
', $fullQuery); - } - break; - - case 'drop_fld': - if ($fullQuery == '') { - $fullQuery .= 'ALTER TABLE ' - . Util::backquote(htmlspecialchars($table)); - } - $fullQuery .= '
  DROP ' - . Util::backquote(htmlspecialchars($selectedValue)) - . ','; - if ($i == $selectedCount - 1) { - $fullQuery = preg_replace('@,$@', ';
', $fullQuery); - } - break; - } // end switch - $i++; - } - - if ($what == 'drop_tbl') { - if (! empty($fullQuery)) { - $fullQuery .= ';
' . "\n"; - } - if (! empty($fullQueryViews)) { - $fullQuery .= $fullQueryViews . ';
' . "\n"; - } - unset($fullQueryViews); - } - - $fullQueryViews = isset($fullQueryViews) ? $fullQueryViews : null; - - return [ - $fullQuery, - $reload, - $fullQueryViews, - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Navigation.php b/srcs/phpmyadmin/libraries/classes/Navigation/Navigation.php deleted file mode 100644 index 49d40df..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Navigation.php +++ /dev/null @@ -1,280 +0,0 @@ -template = $template; - $this->relation = $relation; - $this->dbi = $dbi; - $this->tree = new NavigationTree($this->template, $this->dbi); - } - - /** - * Renders the navigation tree, or part of it - * - * @return string The navigation tree - */ - public function getDisplay(): string - { - global $cfg; - - $logo = [ - 'is_displayed' => $cfg['NavigationDisplayLogo'], - 'has_link' => false, - 'link' => '#', - 'attributes' => ' target="_blank" rel="noopener noreferrer"', - 'source' => '', - ]; - - $response = Response::getInstance(); - if (! $response->isAjax()) { - $logo['source'] = $this->getLogoSource(); - $logo['has_link'] = (string) $cfg['NavigationLogoLink'] !== ''; - $logo['link'] = trim((string) $cfg['NavigationLogoLink']); - if (! Sanitize::checkLink($logo['link'], true)) { - $logo['link'] = 'index.php'; - } - if ($cfg['NavigationLogoLinkWindow'] === 'main') { - if (empty(parse_url($logo['link'], PHP_URL_HOST))) { - $hasStartChar = strpos($logo['link'], '?'); - $logo['link'] .= Url::getCommon( - [], - is_bool($hasStartChar) ? '?' : Url::getArgSeparator() - ); - } - $logo['attributes'] = ''; - } - - if ($cfg['NavigationDisplayServers'] && count($cfg['Servers']) > 1) { - $serverSelect = Select::render(true, true); - } - - if (! defined('PMA_DISABLE_NAVI_SETTINGS')) { - $navigationSettings = PageSettings::getNaviSettings(); - } - } - if (! $response->isAjax() - || ! empty($_POST['full']) - || ! empty($_POST['reload']) - ) { - if ($cfg['ShowDatabasesNavigationAsTree']) { - // provide database tree in navigation - $navRender = $this->tree->renderState(); - } else { - // provide legacy pre-4.0 navigation - $navRender = $this->tree->renderDbSelect(); - } - } else { - $navRender = $this->tree->renderPath(); - } - - return $this->template->render('navigation/main', [ - 'is_ajax' => $response->isAjax(), - 'logo' => $logo, - 'is_synced' => $cfg['NavigationLinkWithMainPanel'], - 'is_highlighted' => $cfg['NavigationTreePointerEnable'], - 'is_autoexpanded' => $cfg['NavigationTreeAutoexpandSingleDb'], - 'server' => $GLOBALS['server'], - 'auth_type' => $cfg['Server']['auth_type'], - 'is_servers_displayed' => $cfg['NavigationDisplayServers'], - 'servers' => $cfg['Servers'], - 'server_select' => $serverSelect ?? '', - 'navigation_tree' => $navRender, - 'is_navigation_settings_enabled' => ! defined('PMA_DISABLE_NAVI_SETTINGS'), - 'navigation_settings' => $navigationSettings ?? '', - 'is_drag_drop_import_enabled' => $cfg['enable_drag_drop_import'] === true, - ]); - } - - /** - * Add an item of navigation tree to the hidden items list in PMA database. - * - * @param string $itemName name of the navigation tree item - * @param string $itemType type of the navigation tree item - * @param string $dbName database name - * @param string $tableName table name if applicable - * - * @return void - */ - public function hideNavigationItem( - $itemName, - $itemType, - $dbName, - $tableName = null - ) { - $navTable = Util::backquote($GLOBALS['cfgRelation']['db']) - . "." . Util::backquote($GLOBALS['cfgRelation']['navigationhiding']); - $sqlQuery = "INSERT INTO " . $navTable - . "(`username`, `item_name`, `item_type`, `db_name`, `table_name`)" - . " VALUES (" - . "'" . $this->dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "'," - . "'" . $this->dbi->escapeString($itemName) . "'," - . "'" . $this->dbi->escapeString($itemType) . "'," - . "'" . $this->dbi->escapeString($dbName) . "'," - . "'" . (! empty($tableName) ? $this->dbi->escapeString($tableName) : "" ) - . "')"; - $this->relation->queryAsControlUser($sqlQuery, false); - } - - /** - * Remove a hidden item of navigation tree from the - * list of hidden items in PMA database. - * - * @param string $itemName name of the navigation tree item - * @param string $itemType type of the navigation tree item - * @param string $dbName database name - * @param string $tableName table name if applicable - * - * @return void - */ - public function unhideNavigationItem( - $itemName, - $itemType, - $dbName, - $tableName = null - ) { - $navTable = Util::backquote($GLOBALS['cfgRelation']['db']) - . "." . Util::backquote($GLOBALS['cfgRelation']['navigationhiding']); - $sqlQuery = "DELETE FROM " . $navTable - . " WHERE" - . " `username`='" - . $this->dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "'" - . " AND `item_name`='" . $this->dbi->escapeString($itemName) . "'" - . " AND `item_type`='" . $this->dbi->escapeString($itemType) . "'" - . " AND `db_name`='" . $this->dbi->escapeString($dbName) . "'" - . (! empty($tableName) - ? " AND `table_name`='" . $this->dbi->escapeString($tableName) . "'" - : "" - ); - $this->relation->queryAsControlUser($sqlQuery, false); - } - - /** - * Returns HTML for the dialog to show hidden navigation items. - * - * @param string $database database name - * @param string $itemType type of the items to include - * @param string $table table name - * - * @return string HTML for the dialog to show hidden navigation items - */ - public function getItemUnhideDialog($database, $itemType = null, $table = null) - { - $hidden = $this->getHiddenItems($database, $table); - - $typeMap = [ - 'group' => __('Groups:'), - 'event' => __('Events:'), - 'function' => __('Functions:'), - 'procedure' => __('Procedures:'), - 'table' => __('Tables:'), - 'view' => __('Views:'), - ]; - - return $this->template->render('navigation/item_unhide_dialog', [ - 'database' => $database, - 'table' => $table, - 'hidden' => $hidden, - 'types' => $typeMap, - 'item_type' => $itemType, - ]); - } - - /** - * @param string $database Database name - * @param string|null $table Table name - * @return array - */ - private function getHiddenItems(string $database, ?string $table): array - { - $navTable = Util::backquote($GLOBALS['cfgRelation']['db']) - . "." . Util::backquote($GLOBALS['cfgRelation']['navigationhiding']); - $sqlQuery = "SELECT `item_name`, `item_type` FROM " . $navTable - . " WHERE `username`='" - . $this->dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "'" - . " AND `db_name`='" . $this->dbi->escapeString($database) . "'" - . " AND `table_name`='" - . (! empty($table) ? $this->dbi->escapeString($table) : '') . "'"; - $result = $this->relation->queryAsControlUser($sqlQuery, false); - - $hidden = []; - if ($result) { - while ($row = $this->dbi->fetchArray($result)) { - $type = $row['item_type']; - if (! isset($hidden[$type])) { - $hidden[$type] = []; - } - $hidden[$type][] = $row['item_name']; - } - } - $this->dbi->freeResult($result); - return $hidden; - } - - /** - * @return string Logo source - */ - private function getLogoSource(): string - { - global $pmaThemeImage; - - if (isset($pmaThemeImage) && @file_exists($pmaThemeImage . 'logo_left.png')) { - return $pmaThemeImage . 'logo_left.png'; - } elseif (isset($pmaThemeImage) && @file_exists($pmaThemeImage . 'pma_logo2.png')) { - return $pmaThemeImage . 'pma_logo2.png'; - } - return ''; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/NavigationTree.php b/srcs/phpmyadmin/libraries/classes/Navigation/NavigationTree.php deleted file mode 100644 index 289ed6e..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/NavigationTree.php +++ /dev/null @@ -1,1581 +0,0 @@ -template = $template; - $this->dbi = $dbi; - - $checkUserPrivileges = new CheckUserPrivileges($this->dbi); - $checkUserPrivileges->getPrivileges(); - - // Save the position at which we are in the database list - if (isset($_POST['pos'])) { - $this->pos = (int) $_POST['pos']; - } elseif (isset($_GET['pos'])) { - $this->pos = (int) $_GET['pos']; - } - if (! isset($this->pos)) { - $this->pos = $this->getNavigationDbPos(); - } - // Get the active node - if (isset($_REQUEST['aPath'])) { - $this->aPath[0] = $this->parsePath($_REQUEST['aPath']); - $this->pos2Name[0] = $_REQUEST['pos2_name']; - $this->pos2Value[0] = $_REQUEST['pos2_value']; - if (isset($_REQUEST['pos3_name'])) { - $this->pos3Name[0] = $_REQUEST['pos3_name']; - $this->pos3Value[0] = $_REQUEST['pos3_value']; - } - } else { - if (isset($_POST['n0_aPath'])) { - $count = 0; - while (isset($_POST['n' . $count . '_aPath'])) { - $this->aPath[$count] = $this->parsePath( - $_POST['n' . $count . '_aPath'] - ); - $index = 'n' . $count . '_pos2_'; - $this->pos2Name[$count] = $_POST[$index . 'name']; - $this->pos2Value[$count] = $_POST[$index . 'value']; - $index = 'n' . $count . '_pos3_'; - if (isset($_POST[$index])) { - $this->pos3Name[$count] = $_POST[$index . 'name']; - $this->pos3Value[$count] = $_POST[$index . 'value']; - } - $count++; - } - } - } - if (isset($_REQUEST['vPath'])) { - $this->vPath[0] = $this->parsePath($_REQUEST['vPath']); - } else { - if (isset($_POST['n0_vPath'])) { - $count = 0; - while (isset($_POST['n' . $count . '_vPath'])) { - $this->vPath[$count] = $this->parsePath( - $_POST['n' . $count . '_vPath'] - ); - $count++; - } - } - } - if (isset($_REQUEST['searchClause'])) { - $this->searchClause = $_REQUEST['searchClause']; - } - if (isset($_REQUEST['searchClause2'])) { - $this->searchClause2 = $_REQUEST['searchClause2']; - } - // Initialise the tree by creating a root node - $node = NodeFactory::getInstance('NodeDatabaseContainer', 'root'); - $this->tree = $node; - if ($GLOBALS['cfg']['NavigationTreeEnableGrouping'] - && $GLOBALS['cfg']['ShowDatabasesNavigationAsTree'] - ) { - $this->tree->separator = $GLOBALS['cfg']['NavigationTreeDbSeparator']; - $this->tree->separatorDepth = 10000; - } - } - - /** - * Returns the database position for the page selector - * - * @return int - */ - private function getNavigationDbPos() - { - $retval = 0; - - if (strlen($GLOBALS['db']) == 0) { - return $retval; - } - - /* - * @todo describe a scenario where this code is executed - */ - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $dbSeparator = $this->dbi->escapeString( - $GLOBALS['cfg']['NavigationTreeDbSeparator'] - ); - $query = "SELECT (COUNT(DB_first_level) DIV %d) * %d "; - $query .= "from ( "; - $query .= " SELECT distinct SUBSTRING_INDEX(SCHEMA_NAME, "; - $query .= " '%s', 1) "; - $query .= " DB_first_level "; - $query .= " FROM INFORMATION_SCHEMA.SCHEMATA "; - $query .= " WHERE `SCHEMA_NAME` < '%s' "; - $query .= ") t "; - - $retval = $this->dbi->fetchValue( - sprintf( - $query, - (int) $GLOBALS['cfg']['FirstLevelNavigationItems'], - (int) $GLOBALS['cfg']['FirstLevelNavigationItems'], - $dbSeparator, - $this->dbi->escapeString($GLOBALS['db']) - ) - ); - - return $retval; - } - - $prefixMap = []; - if ($GLOBALS['dbs_to_test'] === false) { - $handle = $this->dbi->tryQuery("SHOW DATABASES"); - if ($handle !== false) { - while ($arr = $this->dbi->fetchArray($handle)) { - if (strcasecmp($arr[0], $GLOBALS['db']) >= 0) { - break; - } - - $prefix = strstr( - $arr[0], - $GLOBALS['cfg']['NavigationTreeDbSeparator'], - true - ); - if ($prefix === false) { - $prefix = $arr[0]; - } - $prefixMap[$prefix] = 1; - } - } - } else { - $databases = []; - foreach ($GLOBALS['dbs_to_test'] as $db) { - $query = "SHOW DATABASES LIKE '" . $db . "'"; - $handle = $this->dbi->tryQuery($query); - if ($handle === false) { - continue; - } - while ($arr = $this->dbi->fetchArray($handle)) { - $databases[] = $arr[0]; - } - } - sort($databases); - foreach ($databases as $database) { - if (strcasecmp($database, $GLOBALS['db']) >= 0) { - break; - } - - $prefix = strstr( - $database, - $GLOBALS['cfg']['NavigationTreeDbSeparator'], - true - ); - if ($prefix === false) { - $prefix = $database; - } - $prefixMap[$prefix] = 1; - } - } - - $navItems = (int) $GLOBALS['cfg']['FirstLevelNavigationItems']; - $retval = (int) floor(count($prefixMap) / $navItems) * $navItems; - - return $retval; - } - - /** - * Converts an encoded path to a node in string format to an array - * - * @param string $string The path to parse - * - * @return array - */ - private function parsePath($string) - { - $path = explode('.', $string); - foreach ($path as $key => $value) { - $path[$key] = base64_decode($value); - } - - return $path; - } - - /** - * Generates the tree structure so that it can be rendered later - * - * @return Node|false The active node or false in case of failure - */ - private function buildPath() - { - $retval = $this->tree; - - // Add all databases unconditionally - $data = $this->tree->getData( - 'databases', - $this->pos, - $this->searchClause - ); - $hiddenCounts = $this->tree->getNavigationHidingData(); - foreach ($data as $db) { - $node = NodeFactory::getInstance('NodeDatabase', $db); - if (isset($hiddenCounts[$db])) { - $node->setHiddenCount($hiddenCounts[$db]); - } - $this->tree->addChild($node); - } - - // Whether build other parts of the tree depends - // on whether we have any paths in $this->_aPath - foreach ($this->aPath as $key => $path) { - $retval = $this->buildPathPart( - $path, - $this->pos2Name[$key], - $this->pos2Value[$key], - isset($this->pos3Name[$key]) ? $this->pos3Name[$key] : '', - isset($this->pos3Value[$key]) ? $this->pos3Value[$key] : '' - ); - } - - return $retval; - } - - /** - * Builds a branch of the tree - * - * @param array $path A paths pointing to the branch - * of the tree that needs to be built - * @param string $type2 The type of item being paginated on - * the second level of the tree - * @param int $pos2 The position for the pagination of - * the branch at the second level of the tree - * @param string $type3 The type of item being paginated on - * the third level of the tree - * @param int $pos3 The position for the pagination of - * the branch at the third level of the tree - * - * @return Node|bool The active node or false in case of failure, true if the path contains <= 1 items - */ - private function buildPathPart(array $path, $type2, $pos2, $type3, $pos3) - { - if (empty($pos2)) { - $pos2 = 0; - } - if (empty($pos3)) { - $pos3 = 0; - } - - $retval = true; - if (count($path) <= 1) { - return $retval; - } - - array_shift($path); // remove 'root' - /** @var NodeDatabase $db */ - $db = $this->tree->getChild($path[0]); - $retval = $db; - - if ($db === false) { - return false; - } - - $containers = $this->addDbContainers($db, $type2, $pos2); - - array_shift($path); // remove db - - if ((count($path) <= 0 || ! array_key_exists($path[0], $containers)) - && count($containers) != 1 - ) { - return $retval; - } - - if (count($containers) === 1) { - $container = array_shift($containers); - } else { - $container = $db->getChild($path[0], true); - if ($container === false) { - return false; - } - } - $retval = $container; - - if (count($container->children) <= 1) { - $dbData = $db->getData( - $container->realName, - $pos2, - $this->searchClause2 - ); - foreach ($dbData as $item) { - switch ($container->realName) { - case 'events': - $node = NodeFactory::getInstance( - 'NodeEvent', - $item - ); - break; - case 'functions': - $node = NodeFactory::getInstance( - 'NodeFunction', - $item - ); - break; - case 'procedures': - $node = NodeFactory::getInstance( - 'NodeProcedure', - $item - ); - break; - case 'tables': - $node = NodeFactory::getInstance( - 'NodeTable', - $item - ); - break; - case 'views': - $node = NodeFactory::getInstance( - 'NodeView', - $item - ); - break; - default: - break; - } - if (isset($node)) { - if ($type2 == $container->realName) { - $node->pos2 = $pos2; - } - $container->addChild($node); - } - } - } - if (count($path) > 1 && $path[0] != 'tables') { - $retval = false; - - return $retval; - } - - array_shift($path); // remove container - if (count($path) <= 0) { - return $retval; - } - - /** @var NodeTable $table */ - $table = $container->getChild($path[0], true); - if ($table === false) { - if (! $db->getPresence('tables', $path[0])) { - return false; - } - - $node = NodeFactory::getInstance( - 'NodeTable', - $path[0] - ); - if ($type2 == $container->realName) { - $node->pos2 = $pos2; - } - $container->addChild($node); - $table = $container->getChild($path[0], true); - } - $retval = $table; - $containers = $this->addTableContainers( - $table, - $pos2, - $type3, - $pos3 - ); - array_shift($path); // remove table - if (count($path) <= 0 - || ! array_key_exists($path[0], $containers) - ) { - return $retval; - } - - $container = $table->getChild($path[0], true); - $retval = $container; - $tableData = $table->getData( - $container->realName, - $pos3 - ); - foreach ($tableData as $item) { - switch ($container->realName) { - case 'indexes': - $node = NodeFactory::getInstance( - 'NodeIndex', - $item - ); - break; - case 'columns': - $node = NodeFactory::getInstance( - 'NodeColumn', - $item - ); - break; - case 'triggers': - $node = NodeFactory::getInstance( - 'NodeTrigger', - $item - ); - break; - default: - break; - } - if (isset($node)) { - $node->pos2 = $container->parent->pos2; - if ($type3 == $container->realName) { - $node->pos3 = $pos3; - } - $container->addChild($node); - } - } - - return $retval; - } - - /** - * Adds containers to a node that is a table - * - * References to existing children are returned - * if this function is called twice on the same node - * - * @param NodeTable $table The table node, new containers will be - * attached to this node - * @param int $pos2 The position for the pagination of - * the branch at the second level of the tree - * @param string $type3 The type of item being paginated on - * the third level of the tree - * @param int $pos3 The position for the pagination of - * the branch at the third level of the tree - * - * @return array An array of new nodes - */ - private function addTableContainers($table, $pos2, $type3, $pos3) - { - $retval = []; - if ($table->hasChildren(true) == 0) { - if ($table->getPresence('columns')) { - $retval['columns'] = NodeFactory::getInstance( - 'NodeColumnContainer' - ); - } - if ($table->getPresence('indexes')) { - $retval['indexes'] = NodeFactory::getInstance( - 'NodeIndexContainer' - ); - } - if ($table->getPresence('triggers')) { - $retval['triggers'] = NodeFactory::getInstance( - 'NodeTriggerContainer' - ); - } - // Add all new Nodes to the tree - foreach ($retval as $node) { - $node->pos2 = $pos2; - if ($type3 == $node->realName) { - $node->pos3 = $pos3; - } - $table->addChild($node); - } - } else { - foreach ($table->children as $node) { - if ($type3 == $node->realName) { - $node->pos3 = $pos3; - } - $retval[$node->realName] = $node; - } - } - - return $retval; - } - - /** - * Adds containers to a node that is a database - * - * References to existing children are returned - * if this function is called twice on the same node - * - * @param NodeDatabase $db The database node, new containers will be - * attached to this node - * @param string $type The type of item being paginated on - * the second level of the tree - * @param int $pos2 The position for the pagination of - * the branch at the second level of the tree - * - * @return array An array of new nodes - */ - private function addDbContainers($db, $type, $pos2) - { - // Get items to hide - $hidden = $db->getHiddenItems('group'); - if (! $GLOBALS['cfg']['NavigationTreeShowTables'] - && ! in_array('tables', $hidden) - ) { - $hidden[] = 'tables'; - } - if (! $GLOBALS['cfg']['NavigationTreeShowViews'] - && ! in_array('views', $hidden) - ) { - $hidden[] = 'views'; - } - if (! $GLOBALS['cfg']['NavigationTreeShowFunctions'] - && ! in_array('functions', $hidden) - ) { - $hidden[] = 'functions'; - } - if (! $GLOBALS['cfg']['NavigationTreeShowProcedures'] - && ! in_array('procedures', $hidden) - ) { - $hidden[] = 'procedures'; - } - if (! $GLOBALS['cfg']['NavigationTreeShowEvents'] - && ! in_array('events', $hidden) - ) { - $hidden[] = 'events'; - } - - $retval = []; - if ($db->hasChildren(true) == 0) { - if (! in_array('tables', $hidden) && $db->getPresence('tables')) { - $retval['tables'] = NodeFactory::getInstance( - 'NodeTableContainer' - ); - } - if (! in_array('views', $hidden) && $db->getPresence('views')) { - $retval['views'] = NodeFactory::getInstance( - 'NodeViewContainer' - ); - } - if (! in_array('functions', $hidden) && $db->getPresence('functions')) { - $retval['functions'] = NodeFactory::getInstance( - 'NodeFunctionContainer' - ); - } - if (! in_array('procedures', $hidden) && $db->getPresence('procedures')) { - $retval['procedures'] = NodeFactory::getInstance( - 'NodeProcedureContainer' - ); - } - if (! in_array('events', $hidden) && $db->getPresence('events')) { - $retval['events'] = NodeFactory::getInstance( - 'NodeEventContainer' - ); - } - // Add all new Nodes to the tree - foreach ($retval as $node) { - if ($type == $node->realName) { - $node->pos2 = $pos2; - } - $db->addChild($node); - } - } else { - foreach ($db->children as $node) { - if ($type == $node->realName) { - $node->pos2 = $pos2; - } - $retval[$node->realName] = $node; - } - } - - return $retval; - } - - /** - * Recursively groups tree nodes given a separator - * - * @param mixed $node The node to group or null - * to group the whole tree. If - * passed as an argument, $node - * must be of type CONTAINER - * - * @return void - */ - public function groupTree($node = null) - { - if (! isset($node)) { - $node = $this->tree; - } - $this->groupNode($node); - foreach ($node->children as $child) { - $this->groupTree($child); - } - } - - /** - * Recursively groups tree nodes given a separator - * - * @param Node $node The node to group - * - * @return void - */ - public function groupNode($node) - { - if ($node->type != Node::CONTAINER - || ! $GLOBALS['cfg']['NavigationTreeEnableExpansion'] - ) { - return; - } - - $separators = []; - if (is_array($node->separator)) { - $separators = $node->separator; - } else { - if (strlen($node->separator)) { - $separators[] = $node->separator; - } - } - $prefixes = []; - if ($node->separatorDepth > 0) { - foreach ($node->children as $child) { - $prefixPos = false; - foreach ($separators as $separator) { - $sepPos = mb_strpos((string) $child->name, $separator); - if ($sepPos != false - && $sepPos != mb_strlen($child->name) - && $sepPos != 0 - && ($prefixPos === false || $sepPos < $prefixPos) - ) { - $prefixPos = $sepPos; - } - } - if ($prefixPos !== false) { - $prefix = mb_substr($child->name, 0, $prefixPos); - if (! isset($prefixes[$prefix])) { - $prefixes[$prefix] = 1; - } else { - $prefixes[$prefix]++; - } - } - //Bug #4375: Check if prefix is the name of a DB, to create a group. - foreach ($node->children as $otherChild) { - if (array_key_exists($otherChild->name, $prefixes)) { - $prefixes[$otherChild->name]++; - } - } - } - //Check if prefix is the name of a DB, to create a group. - foreach ($node->children as $child) { - if (array_key_exists($child->name, $prefixes)) { - $prefixes[$child->name]++; - } - } - } - // It is not a group if it has only one item - foreach ($prefixes as $key => $value) { - if ($value == 1) { - unset($prefixes[$key]); - } - } - // rfe #1634 Don't group if there's only one group and no other items - if (count($prefixes) === 1) { - $keys = array_keys($prefixes); - $key = $keys[0]; - if ($prefixes[$key] == count($node->children) - 1) { - unset($prefixes[$key]); - } - } - if (count($prefixes)) { - /** @var Node[] $groups */ - $groups = []; - foreach ($prefixes as $key => $value) { - // warn about large groups - if ($value > 500 && ! $this->largeGroupWarning) { - trigger_error( - __( - 'There are large item groups in navigation panel which ' - . 'may affect the performance. Consider disabling item ' - . 'grouping in the navigation panel.' - ), - E_USER_WARNING - ); - $this->largeGroupWarning = true; - } - - $groups[$key] = new Node( - htmlspecialchars((string) $key), - Node::CONTAINER, - true - ); - $groups[$key]->separator = $node->separator; - $groups[$key]->separatorDepth = $node->separatorDepth - 1; - $groups[$key]->icon = Util::getImage( - 'b_group', - __('Groups') - ); - $groups[$key]->pos2 = $node->pos2; - $groups[$key]->pos3 = $node->pos3; - if ($node instanceof NodeTableContainer - || $node instanceof NodeViewContainer - ) { - $tblGroup = '&tbl_group=' . urlencode($key); - $groups[$key]->links = [ - 'text' => $node->links['text'] . $tblGroup, - 'icon' => $node->links['icon'] . $tblGroup, - ]; - } - $node->addChild($groups[$key]); - foreach ($separators as $separator) { - $separatorLength = strlen($separator); - // FIXME: this could be more efficient - foreach ($node->children as $child) { - $keySeparatorLength = mb_strlen((string) $key) + $separatorLength; - $nameSubstring = mb_substr( - (string) $child->name, - 0, - $keySeparatorLength - ); - if (($nameSubstring != $key . $separator - && $child->name != $key) - || $child->type != Node::OBJECT - ) { - continue; - } - $class = get_class($child); - $className = substr($class, strrpos($class, '\\') + 1); - unset($class); - $newChild = NodeFactory::getInstance( - $className, - mb_substr( - $child->name, - $keySeparatorLength - ) - ); - - if ($newChild instanceof NodeDatabase - && $child->getHiddenCount() > 0 - ) { - $newChild->setHiddenCount($child->getHiddenCount()); - } - - $newChild->realName = $child->realName; - $newChild->icon = $child->icon; - $newChild->links = $child->links; - $newChild->pos2 = $child->pos2; - $newChild->pos3 = $child->pos3; - $groups[$key]->addChild($newChild); - foreach ($child->children as $elm) { - $newChild->addChild($elm); - } - $node->removeChild($child->name); - } - } - } - foreach ($prefixes as $key => $value) { - $this->groupNode($groups[$key]); - $groups[$key]->classes = "navGroup"; - } - } - } - - /** - * Renders a state of the tree, used in light mode when - * either JavaScript and/or Ajax are disabled - * - * @return string HTML code for the navigation tree - */ - public function renderState() - { - $this->buildPath(); - - $quickWarp = $this->quickWarp(); - $fastFilter = $this->fastFilterHtml($this->tree); - $controls = ''; - if ($GLOBALS['cfg']['NavigationTreeEnableExpansion']) { - $controls = $this->controls(); - } - $pageSelector = $this->getPageSelector($this->tree); - - $this->groupTree(); - $children = $this->tree->children; - usort($children, [ - NavigationTree::class, - 'sortNode', - ]); - $this->setVisibility(); - - $nodes = ''; - for ($i = 0, $nbChildren = count($children); $i < $nbChildren; $i++) { - if ($i == 0) { - $nodes .= $this->renderNode($children[0], true, 'first'); - } else { - if ($i + 1 != $nbChildren) { - $nodes .= $this->renderNode($children[$i], true); - } else { - $nodes .= $this->renderNode($children[$i], true, 'last'); - } - } - } - - return $this->template->render('navigation/tree/state', [ - 'quick_warp' => $quickWarp, - 'fast_filter' => $fastFilter, - 'controls' => $controls, - 'page_selector' => $pageSelector, - 'nodes' => $nodes, - ]); - } - - /** - * Renders a part of the tree, used for Ajax requests in light mode - * - * @return string|false HTML code for the navigation tree - */ - public function renderPath() - { - $node = $this->buildPath(); - if ($node !== false) { - $this->groupTree(); - - $listContent = $this->fastFilterHtml($node); - $listContent .= $this->getPageSelector($node); - $children = $node->children; - usort($children, [ - NavigationTree::class, - 'sortNode', - ]); - - for ($i = 0, $nbChildren = count($children); $i < $nbChildren; $i++) { - if ($i + 1 != $nbChildren) { - $listContent .= $this->renderNode($children[$i], true); - } else { - $listContent .= $this->renderNode($children[$i], true, 'last'); - } - } - - if (! $GLOBALS['cfg']['ShowDatabasesNavigationAsTree']) { - $parents = $node->parents(true); - $parentName = $parents[0]->realName; - } - } - - if (! empty($this->searchClause) || ! empty($this->searchClause2)) { - $results = 0; - if (! empty($this->searchClause2)) { - if (is_object($node->realParent())) { - $results = $node->realParent() - ->getPresence( - $node->realName, - $this->searchClause2 - ); - } - } else { - $results = $this->tree->getPresence( - 'databases', - $this->searchClause - ); - } - $results = sprintf( - _ngettext( - '%s result found', - '%s results found', - $results - ), - $results - ); - Response::getInstance() - ->addJSON( - 'results', - $results - ); - } - - if ($node !== false) { - return $this->template->render('navigation/tree/path', [ - 'has_search_results' => ! empty($this->searchClause) || ! empty($this->searchClause2), - 'list_content' => $listContent ?? '', - 'is_tree' => $GLOBALS['cfg']['ShowDatabasesNavigationAsTree'], - 'parent_name' => $parentName ?? '', - ]); - } - return false; - } - - /** - * Renders the parameters that are required on the client - * side to know which page(s) we will be requesting data from - * - * @param Node $node The node to create the pagination parameters for - * - * @return string - */ - private function getPaginationParamsHtml($node) - { - $retval = ''; - $paths = $node->getPaths(); - if (isset($paths['aPath_clean'][2])) { - $retval .= ""; - $retval .= $paths['aPath_clean'][2]; - $retval .= ""; - $retval .= ""; - $retval .= htmlspecialchars((string) $node->pos2); - $retval .= ""; - } - if (isset($paths['aPath_clean'][4])) { - $retval .= ""; - $retval .= $paths['aPath_clean'][4]; - $retval .= ""; - $retval .= ""; - $retval .= htmlspecialchars((string) $node->pos3); - $retval .= ""; - } - - return $retval; - } - - /** - * Finds whether given tree matches this tree. - * - * @param array $tree Tree to check - * @param array $paths Paths to check - * - * @return boolean - */ - private function findTreeMatch(array $tree, array $paths) - { - $match = false; - foreach ($tree as $path) { - $match = true; - foreach ($paths as $key => $part) { - if (! isset($path[$key]) || $part != $path[$key]) { - $match = false; - break; - } - } - if ($match) { - break; - } - } - - return $match; - } - - /** - * Renders a single node or a branch of the tree - * - * @param Node $node The node to render - * @param bool $recursive Bool: Whether to render a single node or a branch - * @param string $class An additional class for the list item - * - * @return string HTML code for the tree node or branch - */ - private function renderNode($node, $recursive, $class = '') - { - $retval = ''; - $paths = $node->getPaths(); - if ($node->hasSiblings() - || $node->realParent() === false - ) { - $response = Response::getInstance(); - if ($node->type == Node::CONTAINER - && count($node->children) === 0 - && ! $response->isAjax() - ) { - return ''; - } - $retval .= '
  • '; - $sterile = [ - 'events', - 'triggers', - 'functions', - 'procedures', - 'views', - 'columns', - 'indexes', - ]; - $parentName = ''; - $parents = $node->parents(false, true); - if (count($parents)) { - $parentName = $parents[0]->realName; - } - // if node name itself is in sterile, then allow - if ($node->isGroup - || (! in_array($parentName, $sterile) && ! $node->isNew) - || in_array($node->realName, $sterile) - ) { - $retval .= "
    "; - $iClass = ''; - if ($class == 'first') { - $iClass = " class='first'"; - } - $retval .= ""; - if (strpos($class, 'last') === false) { - $retval .= ""; - } - - $match = $this->findTreeMatch( - $this->vPath, - $paths['vPath_clean'] - ); - - $retval .= 'pos; - $retval .= ""; - $retval .= $this->getPaginationParamsHtml($node); - if ($GLOBALS['cfg']['ShowDatabasesNavigationAsTree'] - || $parentName != 'root' - ) { - $retval .= $node->getIcon($match); - } - - $retval .= ""; - $retval .= "
    "; - } else { - $retval .= "
    "; - $iClass = ''; - if ($class == 'first') { - $iClass = " class='first'"; - } - $retval .= ""; - $retval .= $this->getPaginationParamsHtml($node); - $retval .= "
    "; - } - - $linkClass = ''; - $haveAjax = [ - 'functions', - 'procedures', - 'events', - 'triggers', - 'indexes', - ]; - $parent = $node->parents(false, true); - $isNewView = $parent[0]->realName == 'views' && $node->isNew === true; - if ($parent[0]->type == Node::CONTAINER - && (in_array($parent[0]->realName, $haveAjax) || $isNewView) - ) { - $linkClass = ' ajax'; - } - - if ($node->type == Node::CONTAINER) { - $retval .= ""; - } - - $divClass = ''; - - if (isset($node->links['icon']) && ! empty($node->links['icon'])) { - $iconLinks = $node->links['icon']; - $icons = $node->icon; - if (! is_array($iconLinks)) { - $iconLinks = [$iconLinks]; - $icons = [$icons]; - } - - if (count($icons) > 1) { - $divClass = 'double'; - } - } - - $retval .= "
    "; - - if (isset($node->links['icon']) && ! empty($node->links['icon'])) { - $args = []; - foreach ($node->parents(true) as $parent) { - $args[] = urlencode($parent->realName); - } - - foreach ($icons as $key => $icon) { - $link = vsprintf($iconLinks[$key], $args); - if ($linkClass != '') { - $retval .= ""; - $retval .= "{$icon}"; - } else { - $retval .= "{$icon}"; - } - } - } else { - $retval .= "{$node->icon}"; - } - $retval .= "
    "; - - if (isset($node->links['text'])) { - $args = []; - foreach ($node->parents(true) as $parent) { - $args[] = urlencode($parent->realName); - } - $link = vsprintf($node->links['text'], $args); - $title = isset($node->links['title']) ? $node->links['title'] : ''; - if ($node->type == Node::CONTAINER) { - $retval .= " "; - $retval .= htmlspecialchars($node->name); - $retval .= ""; - } else { - $retval .= "displayName ?? $node->realName); - $retval .= ""; - } - } else { - $retval .= " {$node->name}"; - } - $retval .= $node->getHtmlForControlButtons(); - if ($node->type == Node::CONTAINER) { - $retval .= "
    "; - } - $retval .= '
    '; - $wrap = true; - } else { - $node->visible = true; - $wrap = false; - $retval .= $this->getPaginationParamsHtml($node); - } - - if ($recursive) { - $hide = ''; - if (! $node->visible) { - $hide = " style='display: none;'"; - } - $children = $node->children; - usort( - $children, - [ - NavigationTree::class, - 'sortNode', - ] - ); - $buffer = ''; - $extraClass = ''; - for ($i = 0, $nbChildren = count($children); $i < $nbChildren; $i++) { - if ($i + 1 == $nbChildren) { - $extraClass = ' last'; - } - $buffer .= $this->renderNode( - $children[$i], - true, - $children[$i]->classes . $extraClass - ); - } - if (! empty($buffer)) { - if ($wrap) { - $retval .= "
      "; - } - $retval .= $this->fastFilterHtml($node); - $retval .= $this->getPageSelector($node); - $retval .= $buffer; - if ($wrap) { - $retval .= "
  • "; - } - } - } - if ($node->hasSiblings()) { - $retval .= ""; - } - - return $retval; - } - - /** - * Renders a database select box like the pre-4.0 navigation panel - * - * @return string HTML code - */ - public function renderDbSelect() - { - $this->buildPath(); - - $quickWarp = $this->quickWarp(); - - $this->tree->isGroup = false; - - // Provide for pagination in database select - $listNavigator = Util::getListNavigator( - $this->tree->getPresence('databases', ''), - $this->pos, - ['server' => $GLOBALS['server']], - 'navigation.php', - 'frame_navigation', - $GLOBALS['cfg']['FirstLevelNavigationItems'], - 'pos', - ['dbselector'] - ); - - $children = $this->tree->children; - $selected = $GLOBALS['db']; - $options = ''; - foreach ($children as $node) { - if ($node->isNew) { - continue; - } - $paths = $node->getPaths(); - if (isset($node->links['text'])) { - $title = isset($node->links['title']) ? '' : $node->links['title']; - $options .= ''; - } - } - - $children = $this->tree->children; - usort($children, [ - NavigationTree::class, - 'sortNode', - ]); - $this->setVisibility(); - - $nodes = ''; - for ($i = 0, $nbChildren = count($children); $i < $nbChildren; $i++) { - if ($i == 0) { - $nodes .= $this->renderNode($children[0], true, 'first'); - } else { - if ($i + 1 != $nbChildren) { - $nodes .= $this->renderNode($children[$i], true); - } else { - $nodes .= $this->renderNode($children[$i], true, 'last'); - } - } - } - - return $this->template->render('navigation/tree/database_select', [ - 'quick_warp' => $quickWarp, - 'list_navigator' => $listNavigator, - 'server' => $GLOBALS['server'], - 'options' => $options, - 'nodes' => $nodes, - ]); - } - - /** - * Makes some nodes visible based on the which node is active - * - * @return void - */ - 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 = ''; - $filterDbMin - = (int) $GLOBALS['cfg']['NavigationTreeDisplayDbFilterMinimum']; - $filterItemMin - = (int) $GLOBALS['cfg']['NavigationTreeDisplayItemFilterMinimum']; - if ($node === $this->tree - && $this->tree->getPresence() >= $filterDbMin - ) { - $urlParams = [ - 'pos' => 0, - ]; - $retval .= '
  • '; - $retval .= '
    '; - $retval .= Url::getHiddenInputs($urlParams); - $retval .= 'X'; - $retval .= "
    "; - $retval .= "
  • "; - - return $retval; - } - - if (($node->type == Node::CONTAINER - && ($node->realName == 'tables' - || $node->realName == 'views' - || $node->realName == 'functions' - || $node->realName == 'procedures' - || $node->realName == 'events')) - && method_exists($node->realParent(), 'getPresence') - && $node->realParent()->getPresence($node->realName) >= $filterItemMin - ) { - $paths = $node->getPaths(); - $urlParams = [ - 'pos' => $this->pos, - 'aPath' => $paths['aPath'], - 'vPath' => $paths['vPath'], - 'pos2_name' => $node->realName, - 'pos2_value' => 0, - ]; - $retval .= "
  • "; - $retval .= "
    "; - $retval .= Url::getHiddenFields($urlParams); - $retval .= ""; - $retval .= "X"; - $retval .= "
    "; - $retval .= "
  • "; - } - - return $retval; - } - - /** - * Creates the code for displaying the controls - * at the top of the navigation tree - * - * @return string HTML code for the controls - */ - private function controls() - { - // always iconic - $showIcon = true; - $showText = false; - - $retval = ''; - $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 .= Util::getListNavigator( - $this->tree->getPresence('databases', $this->searchClause), - $this->pos, - ['server' => $GLOBALS['server']], - 'navigation.php', - 'frame_navigation', - $GLOBALS['cfg']['FirstLevelNavigationItems'], - 'pos', - ['dbselector'] - ); - } else { - if ($node->type == Node::CONTAINER && ! $node->isGroup) { - $paths = $node->getPaths(); - - $level = isset($paths['aPath_clean'][4]) ? 3 : 2; - $urlParams = [ - 'aPath' => $paths['aPath'], - 'vPath' => $paths['vPath'], - 'pos' => $this->pos, - 'server' => $GLOBALS['server'], - 'pos2_name' => $paths['aPath_clean'][2], - ]; - if ($level == 3) { - $pos = $node->pos3; - $urlParams['pos2_value'] = $node->pos2; - $urlParams['pos3_name'] = $paths['aPath_clean'][4]; - } else { - $pos = $node->pos2; - } - $num = $node->realParent() - ->getPresence( - $node->realName, - $this->searchClause2 - ); - $retval .= Util::getListNavigator( - $num, - $pos, - $urlParams, - '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() - */ - public static function sortNode($a, $b) - { - if ($a->isNew) { - return -1; - } - - if ($b->isNew) { - return 1; - } - - if ($GLOBALS['cfg']['NaturalOrder']) { - return strnatcasecmp($a->name, $b->name); - } - - return strcasecmp($a->name, $b->name); - } - - /** - * Display quick warp links, contain Recents and Favorites - * - * @return string HTML code - */ - private function quickWarp() - { - $retval = '
    '; - if ($GLOBALS['cfg']['NumRecentTables'] > 0) { - $retval .= RecentFavoriteTable::getInstance('recent') - ->getHtml(); - } - if ($GLOBALS['cfg']['NumFavoriteTables'] > 0) { - $retval .= RecentFavoriteTable::getInstance('favorite') - ->getHtml(); - } - $retval .= '
    '; - $retval .= '
    '; - - return $retval; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/NodeFactory.php b/srcs/phpmyadmin/libraries/classes/Navigation/NodeFactory.php deleted file mode 100644 index 3e751b2..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/NodeFactory.php +++ /dev/null @@ -1,93 +0,0 @@ -name = $name; - $this->realName = $name; - } - if ($type === Node::CONTAINER) { - $this->type = Node::CONTAINER; - } - $this->isGroup = (bool) $isGroup; - $this->relation = new Relation($GLOBALS['dbi']); - } - - /** - * Adds a child node to this node - * - * @param Node $child A child node - * - * @return void - */ - public function addChild($child) - { - $this->children[] = $child; - $child->parent = $this; - } - - /** - * Returns a child node given it's name - * - * @param string $name The name of requested child - * @param bool $realName Whether to use the "realName" - * 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, $realName = false) - { - if ($realName) { - foreach ($this->children as $child) { - if ($child->realName == $name) { - return $child; - } - } - } else { - foreach ($this->children as $child) { - if ($child->name == $name) { - return $child; - } - } - } - - return false; - } - - /** - * Removes a child node from this node - * - * @param string $name The name of child to be removed - * - * @return void - */ - public function removeChild($name) - { - foreach ($this->children as $key => $child) { - if ($child->name == $name) { - unset($this->children[$key]); - break; - } - } - } - - /** - * Retrieves 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 = []; - if ($self - && ($this->type != Node::CONTAINER || $containers) - && (! $this->isGroup || $groups) - ) { - $parents[] = $this; - } - $parent = $this->parent; - while ($parent !== null) { - if (($parent->type != Node::CONTAINER || $containers) - && (! $parent->isGroup || $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|false - */ - public function realParent() - { - $retval = $this->parents(); - if (count($retval) <= 0) { - return false; - } - - return $retval[0]; - } - - /** - * This function checks if the node has children nodes associated with it - * - * @param bool $countEmptyContainers Whether to count empty child - * containers as valid children - * - * @return bool Whether the node has child nodes - */ - public function hasChildren($countEmptyContainers = true) - { - $retval = false; - if ($countEmptyContainers) { - 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 if 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) { - return true; - } - - 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 = []; - $aPathClean = []; - foreach ($this->parents(true, true, false) as $parent) { - $aPath[] = base64_encode($parent->realName); - $aPathClean[] = $parent->realName; - } - $aPath = implode('.', array_reverse($aPath)); - $aPathClean = array_reverse($aPathClean); - - $vPath = []; - $vPathClean = []; - foreach ($this->parents(true, true, true) as $parent) { - $vPath[] = base64_encode((string) $parent->name); - $vPathClean[] = $parent->name; - } - $vPath = implode('.', array_reverse($vPath)); - $vPathClean = array_reverse($vPathClean); - - return [ - 'aPath' => $aPath, - 'aPath_clean' => $aPathClean, - 'vPath' => $vPath, - 'vPath_clean' => $vPathClean, - ]; - } - - /** - * Returns the names of children of type $type present inside this container - * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase and PhpMyAdmin\Navigation\Nodes\NodeTable 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']['FirstLevelNavigationItems']; - if (! $GLOBALS['cfg']['NavigationTreeEnableGrouping'] - || ! $GLOBALS['cfg']['ShowDatabasesNavigationAsTree'] - ) { - if (isset($GLOBALS['cfg']['Server']['DisableIS']) - && ! $GLOBALS['cfg']['Server']['DisableIS'] - ) { - $query = "SELECT `SCHEMA_NAME` "; - $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA` "; - $query .= $this->getWhereClause('SCHEMA_NAME', $searchClause); - $query .= "ORDER BY `SCHEMA_NAME` "; - $query .= "LIMIT $pos, $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); - - return $retval; - } - - if ($GLOBALS['dbs_to_test'] === false) { - $retval = []; - $query = "SHOW DATABASES "; - $query .= $this->getWhereClause('Database', $searchClause); - $handle = $GLOBALS['dbi']->tryQuery($query); - if ($handle === false) { - return $retval; - } - - $count = 0; - if (! $GLOBALS['dbi']->dataSeek($handle, $pos)) { - return $retval; - } - - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - if ($count < $maxItems) { - $retval[] = $arr[0]; - $count++; - } else { - break; - } - } - - return $retval; - } - - $retval = []; - $count = 0; - foreach ($this->getDatabasesToSearch($searchClause) as $db) { - $query = "SHOW DATABASES LIKE '" . $db . "'"; - $handle = $GLOBALS['dbi']->tryQuery($query); - if ($handle === false) { - continue; - } - - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - if ($this->isHideDb($arr[0])) { - continue; - } - if (in_array($arr[0], $retval)) { - continue; - } - - if ($pos <= 0 && $count < $maxItems) { - $retval[] = $arr[0]; - $count++; - } - $pos--; - } - } - sort($retval); - - return $retval; - } - - $dbSeparator = $GLOBALS['cfg']['NavigationTreeDbSeparator']; - if (isset($GLOBALS['cfg']['Server']['DisableIS']) - && ! $GLOBALS['cfg']['Server']['DisableIS'] - ) { - $query = "SELECT `SCHEMA_NAME` "; - $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA`, "; - $query .= "("; - $query .= "SELECT DB_first_level "; - $query .= "FROM ( "; - $query .= "SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, "; - $query .= "'" . $GLOBALS['dbi']->escapeString($dbSeparator) . "', 1) "; - $query .= "DB_first_level "; - $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; - $query .= $this->getWhereClause('SCHEMA_NAME', $searchClause); - $query .= ") t "; - $query .= "ORDER BY DB_first_level ASC "; - $query .= "LIMIT $pos, $maxItems"; - $query .= ") t2 "; - $query .= $this->getWhereClause('SCHEMA_NAME', $searchClause); - $query .= "AND 1 = LOCATE(CONCAT(DB_first_level, "; - $query .= "'" . $GLOBALS['dbi']->escapeString($dbSeparator) . "'), "; - $query .= "CONCAT(SCHEMA_NAME, "; - $query .= "'" . $GLOBALS['dbi']->escapeString($dbSeparator) . "')) "; - $query .= "ORDER BY SCHEMA_NAME ASC"; - $retval = $GLOBALS['dbi']->fetchResult($query); - - return $retval; - } - - if ($GLOBALS['dbs_to_test'] === false) { - $query = "SHOW DATABASES "; - $query .= $this->getWhereClause('Database', $searchClause); - $handle = $GLOBALS['dbi']->tryQuery($query); - $prefixes = []; - if ($handle !== false) { - $prefixMap = []; - $total = $pos + $maxItems; - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - $prefix = strstr($arr[0], $dbSeparator, true); - if ($prefix === false) { - $prefix = $arr[0]; - } - $prefixMap[$prefix] = 1; - if (count($prefixMap) == $total) { - break; - } - } - $prefixes = array_slice(array_keys($prefixMap), (int) $pos); - } - - $query = "SHOW DATABASES "; - $query .= $this->getWhereClause('Database', $searchClause); - $query .= "AND ("; - $subClauses = []; - foreach ($prefixes as $prefix) { - $subClauses[] = " LOCATE('" - . $GLOBALS['dbi']->escapeString((string) $prefix) . $dbSeparator - . "', " - . "CONCAT(`Database`, '" . $dbSeparator . "')) = 1 "; - } - $query .= implode("OR", $subClauses) . ")"; - $retval = $GLOBALS['dbi']->fetchResult($query); - - return $retval; - } - - $retval = []; - $prefixMap = []; - $total = $pos + $maxItems; - foreach ($this->getDatabasesToSearch($searchClause) as $db) { - $query = "SHOW DATABASES LIKE '" . $db . "'"; - $handle = $GLOBALS['dbi']->tryQuery($query); - if ($handle === false) { - continue; - } - - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - if ($this->isHideDb($arr[0])) { - continue; - } - $prefix = strstr($arr[0], $dbSeparator, true); - if ($prefix === false) { - $prefix = $arr[0]; - } - $prefixMap[$prefix] = 1; - if (count($prefixMap) == $total) { - break 2; - } - } - } - $prefixes = array_slice(array_keys($prefixMap), $pos); - - foreach ($this->getDatabasesToSearch($searchClause) as $db) { - $query = "SHOW DATABASES LIKE '" . $db . "'"; - $handle = $GLOBALS['dbi']->tryQuery($query); - if ($handle === false) { - continue; - } - - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - if ($this->isHideDb($arr[0])) { - continue; - } - if (in_array($arr[0], $retval)) { - continue; - } - - foreach ($prefixes as $prefix) { - $startsWith = strpos( - $arr[0] . $dbSeparator, - $prefix . $dbSeparator - ) === 0; - if ($startsWith) { - $retval[] = $arr[0]; - break; - } - } - } - } - sort($retval); - - return $retval; - } - - /** - * Returns the number of children of type $type present inside this container - * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase and PhpMyAdmin\Navigation\Nodes\NodeTable 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']['NavigationTreeEnableGrouping'] - || ! $GLOBALS['cfg']['ShowDatabasesNavigationAsTree'] - ) { - if (isset($GLOBALS['cfg']['Server']['DisableIS']) - && ! $GLOBALS['cfg']['Server']['DisableIS'] - ) { - $query = "SELECT COUNT(*) "; - $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; - $query .= $this->getWhereClause('SCHEMA_NAME', $searchClause); - $retval = (int) $GLOBALS['dbi']->fetchValue($query); - - return $retval; - } - - if ($GLOBALS['dbs_to_test'] === false) { - $query = "SHOW DATABASES "; - $query .= $this->getWhereClause('Database', $searchClause); - $retval = $GLOBALS['dbi']->numRows( - $GLOBALS['dbi']->tryQuery($query) - ); - - return $retval; - } - - $retval = 0; - foreach ($this->getDatabasesToSearch($searchClause) as $db) { - $query = "SHOW DATABASES LIKE '" . $db . "'"; - $retval += $GLOBALS['dbi']->numRows( - $GLOBALS['dbi']->tryQuery($query) - ); - } - - return $retval; - } - - $dbSeparator = $GLOBALS['cfg']['NavigationTreeDbSeparator']; - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $query = "SELECT COUNT(*) "; - $query .= "FROM ( "; - $query .= "SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, "; - $query .= "'$dbSeparator', 1) "; - $query .= "DB_first_level "; - $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; - $query .= $this->getWhereClause('SCHEMA_NAME', $searchClause); - $query .= ") t "; - $retval = (int) $GLOBALS['dbi']->fetchValue($query); - - return $retval; - } - - if ($GLOBALS['dbs_to_test'] !== false) { - $prefixMap = []; - foreach ($this->getDatabasesToSearch($searchClause) as $db) { - $query = "SHOW DATABASES LIKE '" . $db . "'"; - $handle = $GLOBALS['dbi']->tryQuery($query); - if ($handle === false) { - continue; - } - - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - if ($this->isHideDb($arr[0])) { - continue; - } - $prefix = strstr($arr[0], $dbSeparator, true); - if ($prefix === false) { - $prefix = $arr[0]; - } - $prefixMap[$prefix] = 1; - } - } - $retval = count($prefixMap); - - return $retval; - } - - $prefixMap = []; - $query = "SHOW DATABASES "; - $query .= $this->getWhereClause('Database', $searchClause); - $handle = $GLOBALS['dbi']->tryQuery($query); - if ($handle !== false) { - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - $prefix = strstr($arr[0], $dbSeparator, true); - if ($prefix === false) { - $prefix = $arr[0]; - } - $prefixMap[$prefix] = 1; - } - } - $retval = count($prefixMap); - - return $retval; - } - - /** - * Detemines whether a given database should be hidden according to 'hide_db' - * - * @param string $db database name - * - * @return boolean whether to hide - */ - private function isHideDb($db) - { - return ! empty($GLOBALS['cfg']['Server']['hide_db']) - && preg_match('/' . $GLOBALS['cfg']['Server']['hide_db'] . '/', $db); - } - - /** - * Get the list of databases for 'SHOW DATABASES LIKE' queries. - * If a search clause is set it gets the highest priority while only_db gets - * the next priority. In case both are empty list of databases determined by - * GRANTs are used - * - * @param string $searchClause search clause - * - * @return array array of databases - */ - private function getDatabasesToSearch($searchClause) - { - $databases = []; - if (! empty($searchClause)) { - $databases = [ - "%" . $GLOBALS['dbi']->escapeString($searchClause) . "%", - ]; - } elseif (! empty($GLOBALS['cfg']['Server']['only_db'])) { - $databases = $GLOBALS['cfg']['Server']['only_db']; - } elseif (! empty($GLOBALS['dbs_to_test'])) { - $databases = $GLOBALS['dbs_to_test']; - } - sort($databases); - - return $databases; - } - - /** - * Returns the WHERE clause depending on the $searchClause parameter - * and the hide_db directive - * - * @param string $columnName Column name of the column having database names - * @param string $searchClause A string used to filter the results of the query - * - * @return string - */ - private function getWhereClause($columnName, $searchClause = '') - { - $whereClause = "WHERE TRUE "; - if (! empty($searchClause)) { - $whereClause .= "AND " . Util::backquote($columnName) - . " LIKE '%"; - $whereClause .= $GLOBALS['dbi']->escapeString($searchClause); - $whereClause .= "%' "; - } - - if (! empty($GLOBALS['cfg']['Server']['hide_db'])) { - $whereClause .= "AND " . Util::backquote($columnName) - . " NOT REGEXP '" - . $GLOBALS['dbi']->escapeString($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'] = [ - $GLOBALS['cfg']['Server']['only_db'], - ]; - } - $whereClause .= "AND ("; - $subClauses = []; - foreach ($GLOBALS['cfg']['Server']['only_db'] as $eachOnlyDb) { - $subClauses[] = " " . Util::backquote($columnName) - . " LIKE '" - . $GLOBALS['dbi']->escapeString($eachOnlyDb) . "' "; - } - $whereClause .= implode("OR", $subClauses) . ") "; - } - - return $whereClause; - } - - /** - * Returns HTML for control buttons displayed infront of a node - * - * @return String HTML for control buttons - */ - public function getHtmlForControlButtons() - { - return ''; - } - - /** - * Returns CSS classes for a node - * - * @param boolean $match Whether the node matched loaded tree - * - * @return String with html classes. - */ - public function getCssClasses($match) - { - if (! $GLOBALS['cfg']['NavigationTreeEnableExpansion'] - ) { - return ''; - } - - $result = ['expander']; - - if ($this->isGroup || $match) { - $result[] = 'loaded'; - } - if ($this->type == Node::CONTAINER) { - $result[] = 'container'; - } - - return implode(' ', $result); - } - - /** - * Returns icon for the node - * - * @param boolean $match Whether the node matched loaded tree - * - * @return String with image name - */ - public function getIcon($match) - { - if (! $GLOBALS['cfg']['NavigationTreeEnableExpansion'] - ) { - return ''; - } elseif ($match) { - $this->visible = true; - - return Util::getImage('b_minus'); - } - - return Util::getImage('b_plus', __('Expand/Collapse')); - } - - /** - * Gets the count of hidden elements for each database - * - * @return array|null array containing the count of hidden elements for each database - */ - public function getNavigationHidingData() - { - $cfgRelation = $this->relation->getRelationsParam(); - if ($cfgRelation['navwork']) { - $navTable = Util::backquote($cfgRelation['db']) - . "." . Util::backquote( - $cfgRelation['navigationhiding'] - ); - $sqlQuery = "SELECT `db_name`, COUNT(*) AS `count` FROM " . $navTable - . " WHERE `username`='" - . $GLOBALS['dbi']->escapeString( - $GLOBALS['cfg']['Server']['user'] - ) . "'" - . " GROUP BY `db_name`"; - $counts = $GLOBALS['dbi']->fetchResult( - $sqlQuery, - 'db_name', - 'count', - DatabaseInterface::CONNECT_CONTROL - ); - - return $counts; - } - - return null; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumn.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumn.php deleted file mode 100644 index 9c9e605..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumn.php +++ /dev/null @@ -1,116 +0,0 @@ -displayName = $this->getDisplayName($item); - - parent::__construct($item['name'], $type, $isGroup); - $this->icon = Util::getImage($this->getColumnIcon($item['key']), __('Column')); - $this->links = [ - 'text' => 'tbl_structure.php?server=' . $GLOBALS['server'] - . '&db=%3$s&table=%2$s&field=%1$s' - . '&change_column=1', - 'icon' => 'tbl_structure.php?server=' . $GLOBALS['server'] - . '&db=%3$s&table=%2$s&field=%1$s' - . '&change_column=1', - 'title' => __('Structure'), - ]; - } - - /** - * Get customized Icon for columns in navigation tree - * - * @param string $key The key type - (primary, foreign etc.) - * - * @return string Icon name for required key. - */ - private function getColumnIcon($key) - { - switch ($key) { - case 'PRI': - $retval = 'b_primary'; - break; - case 'UNI': - $retval = 'bd_primary'; - break; - default: - $retval = 'pause'; - break; - } - return $retval; - } - - /** - * Get displayable name for navigation tree (key_type, data_type, default) - * - * @param array $item Item is array containing required info - * - * @return string Display name for navigation tree - */ - private function getDisplayName($item) - { - $retval = $item['name']; - $flag = 0; - foreach ($item as $key => $value) { - if (! empty($value) && $key != 'name') { - $flag == 0 ? $retval .= ' (' : $retval .= ', '; - $flag = 1; - $retval .= $this->getTruncateValue($key, $value); - } - } - $retval .= ')'; - return $retval; - } - - /** - * Get truncated value for display in node column view - * - * @param string $key key to identify default,datatype etc - * @param string $value value corresponding to key - * - * @return string truncated value - */ - public function getTruncateValue($key, $value) - { - $retval = ''; - - switch ($key) { - case 'default': - strlen($value) > 6 ? - $retval .= substr($value, 0, 6) . '...' : - $retval = $value; - break; - default: - $retval = $value; - break; - } - - return $retval; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumnContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumnContainer.php deleted file mode 100644 index 22cba58..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumnContainer.php +++ /dev/null @@ -1,55 +0,0 @@ -icon = Util::getImage('pause', __('Columns')); - $this->links = [ - 'text' => 'tbl_structure.php?server=' . $GLOBALS['server'] - . '&db=%2$s&table=%1$s', - 'icon' => 'tbl_structure.php?server=' . $GLOBALS['server'] - . '&db=%2$s&table=%1$s', - ]; - $this->realName = 'columns'; - - $newLabel = _pgettext('Create new column', 'New'); - $new = NodeFactory::getInstance( - 'Node', - $newLabel - ); - $new->isNew = true; - $new->icon = Util::getImage('b_column_add', $newLabel); - $new->links = [ - 'text' => 'tbl_addfield.php?server=' . $GLOBALS['server'] - . '&db=%3$s&table=%2$s' - . '&field_where=last&after_field=', - 'icon' => 'tbl_addfield.php?server=' . $GLOBALS['server'] - . '&db=%3$s&table=%2$s' - . '&field_where=last&after_field=', - ]; - $new->classes = 'new_column italics'; - $this->addChild($new); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabase.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabase.php deleted file mode 100644 index 33c93fb..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabase.php +++ /dev/null @@ -1,717 +0,0 @@ -icon = Util::getImage( - 's_db', - __('Database operations') - ); - - $scriptName = Util::getScriptNameForOption( - $GLOBALS['cfg']['DefaultTabDatabase'], - 'database' - ); - $this->links = [ - 'text' => $scriptName - . '?server=' . $GLOBALS['server'] - . '&db=%1$s', - 'icon' => 'db_operations.php?server=' . $GLOBALS['server'] - . '&db=%1$s&', - 'title' => __('Structure'), - ]; - $this->classes = 'database'; - } - - /** - * Returns the number of children of type $type present inside this container - * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase - * and PhpMyAdmin\Navigation\Nodes\NodeTable 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 - * @param boolean $singleItem Whether to get presence of a single known - * item or false in none - * - * @return int - */ - public function getPresence($type = '', $searchClause = '', $singleItem = false) - { - $retval = 0; - switch ($type) { - case 'tables': - $retval = $this->getTableCount($searchClause, $singleItem); - break; - case 'views': - $retval = $this->getViewCount($searchClause, $singleItem); - break; - case 'procedures': - $retval = $this->getProcedureCount($searchClause, $singleItem); - break; - case 'functions': - $retval = $this->getFunctionCount($searchClause, $singleItem); - break; - case 'events': - $retval = $this->getEventCount($searchClause, $singleItem); - break; - default: - break; - } - - return $retval; - } - - /** - * Returns the number of tables or views present inside this database - * - * @param string $which tables|views - * @param string $searchClause A string used to filter the results of - * the query - * @param boolean $singleItem Whether to get presence of a single known - * item or false in none - * - * @return int - */ - private function getTableOrViewCount($which, $searchClause, $singleItem) - { - $db = $this->realName; - if ($which == 'tables') { - $condition = 'IN'; - } else { - $condition = 'NOT IN'; - } - - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $GLOBALS['dbi']->escapeString($db); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; - $query .= "WHERE `TABLE_SCHEMA`='$db' "; - $query .= "AND `TABLE_TYPE`" . $condition . "('BASE TABLE', 'SYSTEM VERSIONED') "; - if (! empty($searchClause)) { - $query .= "AND " . $this->getWhereClauseForSearch( - $searchClause, - $singleItem, - 'TABLE_NAME' - ); - } - $retval = (int) $GLOBALS['dbi']->fetchValue($query); - } else { - $query = "SHOW FULL TABLES FROM "; - $query .= Util::backquote($db); - $query .= " WHERE `Table_type`" . $condition . "('BASE TABLE', 'SYSTEM VERSIONED') "; - if (! empty($searchClause)) { - $query .= "AND " . $this->getWhereClauseForSearch( - $searchClause, - $singleItem, - 'Tables_in_' . $db - ); - } - $retval = $GLOBALS['dbi']->numRows( - $GLOBALS['dbi']->tryQuery($query) - ); - } - - return $retval; - } - - /** - * Returns the number of tables present inside this database - * - * @param string $searchClause A string used to filter the results of - * the query - * @param boolean $singleItem Whether to get presence of a single known - * item or false in none - * - * @return int - */ - private function getTableCount($searchClause, $singleItem) - { - return $this->getTableOrViewCount( - 'tables', - $searchClause, - $singleItem - ); - } - - /** - * Returns the number of views present inside this database - * - * @param string $searchClause A string used to filter the results of - * the query - * @param boolean $singleItem Whether to get presence of a single known - * item or false in none - * - * @return int - */ - private function getViewCount($searchClause, $singleItem) - { - return $this->getTableOrViewCount( - 'views', - $searchClause, - $singleItem - ); - } - - /** - * Returns the number of procedures present inside this database - * - * @param string $searchClause A string used to filter the results of - * the query - * @param boolean $singleItem Whether to get presence of a single known - * item or false in none - * - * @return int - */ - private function getProcedureCount($searchClause, $singleItem) - { - $db = $this->realName; - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $GLOBALS['dbi']->escapeString($db); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; - $query .= "WHERE `ROUTINE_SCHEMA` " - . Util::getCollateForIS() . "='$db'"; - $query .= "AND `ROUTINE_TYPE`='PROCEDURE' "; - if (! empty($searchClause)) { - $query .= "AND " . $this->getWhereClauseForSearch( - $searchClause, - $singleItem, - 'ROUTINE_NAME' - ); - } - $retval = (int) $GLOBALS['dbi']->fetchValue($query); - } else { - $db = $GLOBALS['dbi']->escapeString($db); - $query = "SHOW PROCEDURE STATUS WHERE `Db`='$db' "; - if (! empty($searchClause)) { - $query .= "AND " . $this->getWhereClauseForSearch( - $searchClause, - $singleItem, - 'Name' - ); - } - $retval = $GLOBALS['dbi']->numRows( - $GLOBALS['dbi']->tryQuery($query) - ); - } - - return $retval; - } - - /** - * Returns the number of functions present inside this database - * - * @param string $searchClause A string used to filter the results of - * the query - * @param boolean $singleItem Whether to get presence of a single known - * item or false in none - * - * @return int - */ - private function getFunctionCount($searchClause, $singleItem) - { - $db = $this->realName; - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $GLOBALS['dbi']->escapeString($db); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; - $query .= "WHERE `ROUTINE_SCHEMA` " - . Util::getCollateForIS() . "='$db' "; - $query .= "AND `ROUTINE_TYPE`='FUNCTION' "; - if (! empty($searchClause)) { - $query .= "AND " . $this->getWhereClauseForSearch( - $searchClause, - $singleItem, - 'ROUTINE_NAME' - ); - } - $retval = (int) $GLOBALS['dbi']->fetchValue($query); - } else { - $db = $GLOBALS['dbi']->escapeString($db); - $query = "SHOW FUNCTION STATUS WHERE `Db`='$db' "; - if (! empty($searchClause)) { - $query .= "AND " . $this->getWhereClauseForSearch( - $searchClause, - $singleItem, - 'Name' - ); - } - $retval = $GLOBALS['dbi']->numRows( - $GLOBALS['dbi']->tryQuery($query) - ); - } - - return $retval; - } - - /** - * Returns the number of events present inside this database - * - * @param string $searchClause A string used to filter the results of - * the query - * @param boolean $singleItem Whether to get presence of a single known - * item or false in none - * - * @return int - */ - private function getEventCount($searchClause, $singleItem) - { - $db = $this->realName; - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $GLOBALS['dbi']->escapeString($db); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`EVENTS` "; - $query .= "WHERE `EVENT_SCHEMA` " - . Util::getCollateForIS() . "='$db' "; - if (! empty($searchClause)) { - $query .= "AND " . $this->getWhereClauseForSearch( - $searchClause, - $singleItem, - 'EVENT_NAME' - ); - } - $retval = (int) $GLOBALS['dbi']->fetchValue($query); - } else { - $db = Util::backquote($db); - $query = "SHOW EVENTS FROM $db "; - if (! empty($searchClause)) { - $query .= "WHERE " . $this->getWhereClauseForSearch( - $searchClause, - $singleItem, - 'Name' - ); - } - $retval = $GLOBALS['dbi']->numRows( - $GLOBALS['dbi']->tryQuery($query) - ); - } - - return $retval; - } - - /** - * Returns the WHERE clause for searching inside a database - * - * @param string $searchClause A string used to filter the results of the query - * @param boolean $singleItem Whether to get presence of a single known item - * @param string $columnName Name of the column in the result set to match - * - * @return string WHERE clause for searching - */ - private function getWhereClauseForSearch( - $searchClause, - $singleItem, - $columnName - ) { - $query = ''; - if ($singleItem) { - $query .= Util::backquote($columnName) . " = "; - $query .= "'" . $GLOBALS['dbi']->escapeString($searchClause) . "'"; - } else { - $query .= Util::backquote($columnName) . " LIKE "; - $query .= "'%" . $GLOBALS['dbi']->escapeString($searchClause) - . "%'"; - } - - return $query; - } - - /** - * Returns the names of children of type $type present inside this container - * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase - * and PhpMyAdmin\Navigation\Nodes\NodeTable 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 = '') - { - $retval = []; - switch ($type) { - case 'tables': - $retval = $this->getTables($pos, $searchClause); - break; - case 'views': - $retval = $this->getViews($pos, $searchClause); - break; - case 'procedures': - $retval = $this->getProcedures($pos, $searchClause); - break; - case 'functions': - $retval = $this->getFunctions($pos, $searchClause); - break; - case 'events': - $retval = $this->getEvents($pos, $searchClause); - break; - default: - break; - } - - // Remove hidden items so that they are not displayed in navigation tree - $cfgRelation = $this->relation->getRelationsParam(); - if ($cfgRelation['navwork']) { - $hiddenItems = $this->getHiddenItems(substr($type, 0, -1)); - foreach ($retval as $key => $item) { - if (in_array($item, $hiddenItems)) { - unset($retval[$key]); - } - } - } - - return $retval; - } - - /** - * Return list of hidden items of given type - * - * @param string $type The type of items we are looking for - * ('table', 'function', 'group', etc.) - * - * @return array Array containing hidden items of given type - */ - public function getHiddenItems($type) - { - $db = $this->realName; - $cfgRelation = $this->relation->getRelationsParam(); - if (! $cfgRelation['navwork']) { - return []; - } - $navTable = Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['navigationhiding']); - $sqlQuery = "SELECT `item_name` FROM " . $navTable - . " WHERE `username`='" . $cfgRelation['user'] . "'" - . " AND `item_type`='" . $type - . "' AND `db_name`='" . $GLOBALS['dbi']->escapeString($db) - . "'"; - $result = $this->relation->queryAsControlUser($sqlQuery, false); - $hiddenItems = []; - if ($result) { - while ($row = $GLOBALS['dbi']->fetchArray($result)) { - $hiddenItems[] = $row[0]; - } - } - $GLOBALS['dbi']->freeResult($result); - - return $hiddenItems; - } - - /** - * Returns the list of tables or views inside this database - * - * @param string $which tables|views - * @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 - */ - private function getTablesOrViews($which, $pos, $searchClause) - { - if ($which == 'tables') { - $condition = 'IN'; - } else { - $condition = 'NOT IN'; - } - $maxItems = $GLOBALS['cfg']['MaxNavigationItems']; - $retval = []; - $db = $this->realName; - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $escdDb = $GLOBALS['dbi']->escapeString($db); - $query = "SELECT `TABLE_NAME` AS `name` "; - $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; - $query .= "WHERE `TABLE_SCHEMA`='$escdDb' "; - $query .= "AND `TABLE_TYPE`" . $condition . "('BASE TABLE', 'SYSTEM VERSIONED') "; - if (! empty($searchClause)) { - $query .= "AND `TABLE_NAME` LIKE '%"; - $query .= $GLOBALS['dbi']->escapeString($searchClause); - $query .= "%'"; - } - $query .= "ORDER BY `TABLE_NAME` ASC "; - $query .= "LIMIT " . intval($pos) . ", $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); - } else { - $query = " SHOW FULL TABLES FROM "; - $query .= Util::backquote($db); - $query .= " WHERE `Table_type`" . $condition . "('BASE TABLE', 'SYSTEM VERSIONED') "; - if (! empty($searchClause)) { - $query .= "AND " . Util::backquote( - "Tables_in_" . $db - ); - $query .= " LIKE '%" . $GLOBALS['dbi']->escapeString( - $searchClause - ); - $query .= "%'"; - } - $handle = $GLOBALS['dbi']->tryQuery($query); - if ($handle !== false) { - $count = 0; - if ($GLOBALS['dbi']->dataSeek($handle, $pos)) { - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - if ($count < $maxItems) { - $retval[] = $arr[0]; - $count++; - } else { - break; - } - } - } - } - } - - return $retval; - } - - /** - * Returns the list of tables inside this database - * - * @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 - */ - private function getTables($pos, $searchClause) - { - return $this->getTablesOrViews('tables', $pos, $searchClause); - } - - /** - * Returns the list of views inside this database - * - * @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 - */ - private function getViews($pos, $searchClause) - { - return $this->getTablesOrViews('views', $pos, $searchClause); - } - - /** - * Returns the list of procedures or functions inside this database - * - * @param string $routineType PROCEDURE|FUNCTION - * @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 - */ - private function getRoutines($routineType, $pos, $searchClause) - { - $maxItems = $GLOBALS['cfg']['MaxNavigationItems']; - $retval = []; - $db = $this->realName; - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $escdDb = $GLOBALS['dbi']->escapeString($db); - $query = "SELECT `ROUTINE_NAME` AS `name` "; - $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; - $query .= "WHERE `ROUTINE_SCHEMA` " - . Util::getCollateForIS() . "='$escdDb'"; - $query .= "AND `ROUTINE_TYPE`='" . $routineType . "' "; - if (! empty($searchClause)) { - $query .= "AND `ROUTINE_NAME` LIKE '%"; - $query .= $GLOBALS['dbi']->escapeString($searchClause); - $query .= "%'"; - } - $query .= "ORDER BY `ROUTINE_NAME` ASC "; - $query .= "LIMIT " . intval($pos) . ", $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); - } else { - $escdDb = $GLOBALS['dbi']->escapeString($db); - $query = "SHOW " . $routineType . " STATUS WHERE `Db`='$escdDb' "; - if (! empty($searchClause)) { - $query .= "AND `Name` LIKE '%"; - $query .= $GLOBALS['dbi']->escapeString($searchClause); - $query .= "%'"; - } - $handle = $GLOBALS['dbi']->tryQuery($query); - if ($handle !== false) { - $count = 0; - if ($GLOBALS['dbi']->dataSeek($handle, $pos)) { - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - if ($count < $maxItems) { - $retval[] = $arr['Name']; - $count++; - } else { - break; - } - } - } - } - } - - return $retval; - } - - /** - * Returns the list of procedures inside this database - * - * @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 - */ - private function getProcedures($pos, $searchClause) - { - return $this->getRoutines('PROCEDURE', $pos, $searchClause); - } - - /** - * Returns the list of functions inside this database - * - * @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 - */ - private function getFunctions($pos, $searchClause) - { - return $this->getRoutines('FUNCTION', $pos, $searchClause); - } - - /** - * Returns the list of events inside this database - * - * @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 - */ - private function getEvents($pos, $searchClause) - { - $maxItems = $GLOBALS['cfg']['MaxNavigationItems']; - $retval = []; - $db = $this->realName; - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $escdDb = $GLOBALS['dbi']->escapeString($db); - $query = "SELECT `EVENT_NAME` AS `name` "; - $query .= "FROM `INFORMATION_SCHEMA`.`EVENTS` "; - $query .= "WHERE `EVENT_SCHEMA` " - . Util::getCollateForIS() . "='$escdDb' "; - if (! empty($searchClause)) { - $query .= "AND `EVENT_NAME` LIKE '%"; - $query .= $GLOBALS['dbi']->escapeString($searchClause); - $query .= "%'"; - } - $query .= "ORDER BY `EVENT_NAME` ASC "; - $query .= "LIMIT " . intval($pos) . ", $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); - } else { - $escdDb = Util::backquote($db); - $query = "SHOW EVENTS FROM $escdDb "; - if (! empty($searchClause)) { - $query .= "WHERE `Name` LIKE '%"; - $query .= $GLOBALS['dbi']->escapeString($searchClause); - $query .= "%'"; - } - $handle = $GLOBALS['dbi']->tryQuery($query); - if ($handle !== false) { - $count = 0; - if ($GLOBALS['dbi']->dataSeek($handle, $pos)) { - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - if ($count < $maxItems) { - $retval[] = $arr['Name']; - $count++; - } else { - break; - } - } - } - } - } - - return $retval; - } - - /** - * Returns HTML for control buttons displayed infront of a node - * - * @return String HTML for control buttons - */ - public function getHtmlForControlButtons() - { - $ret = ''; - $cfgRelation = $this->relation->getRelationsParam(); - if ($cfgRelation['navwork']) { - if ($this->hiddenCount > 0) { - $params = [ - 'showUnhideDialog' => true, - 'dbName' => $this->realName, - ]; - $ret = '' - . '' - . Util::getImage( - 'show', - __('Show hidden items') - ) - . ''; - } - } - - return $ret; - } - - /** - * Sets the number of hidden items in this database - * - * @param int $count hidden item count - * - * @return void - */ - public function setHiddenCount($count) - { - $this->hiddenCount = $count; - } - - /** - * Returns the number of hidden items in this database - * - * @return int hidden item count - */ - public function getHiddenCount() - { - return $this->hiddenCount; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChild.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChild.php deleted file mode 100644 index 0005915..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChild.php +++ /dev/null @@ -1,62 +0,0 @@ -relation->getRelationsParam(); - if ($cfgRelation['navwork']) { - $db = $this->realParent()->realName; - $item = $this->realName; - - $params = [ - 'hideNavItem' => true, - 'itemType' => $this->getItemType(), - 'itemName' => $item, - 'dbName' => $db, - ]; - - $ret = '' - . '' - . Util::getImage('hide', __('Hide')) - . ''; - } - - return $ret; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChildContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChildContainer.php deleted file mode 100644 index 7c182c6..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChildContainer.php +++ /dev/null @@ -1,43 +0,0 @@ -separator = $GLOBALS['cfg']['NavigationTreeTableSeparator']; - $this->separatorDepth = (int) $GLOBALS['cfg']['NavigationTreeTableLevel']; - } - } - - /** - * Returns the type of the item represented by the node. - * - * @return string type of the item - */ - protected function getItemType() - { - return 'group'; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php deleted file mode 100644 index 9b5746f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php +++ /dev/null @@ -1,52 +0,0 @@ -getPrivileges(); - - parent::__construct($name, Node::CONTAINER); - - if ($GLOBALS['is_create_db_priv'] - && $GLOBALS['cfg']['ShowCreateDb'] !== false - ) { - $new = NodeFactory::getInstance( - 'Node', - _pgettext('Create new database', 'New') - ); - $new->isNew = true; - $new->icon = Util::getImage('b_newdb', ''); - $new->links = [ - 'text' => 'server_databases.php?server=' . $GLOBALS['server'], - 'icon' => 'server_databases.php?server=' . $GLOBALS['server'], - ]; - $new->classes = 'new_database italics'; - $this->addChild($new); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEvent.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEvent.php deleted file mode 100644 index 91aa5ce..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEvent.php +++ /dev/null @@ -1,51 +0,0 @@ -icon = Util::getImage('b_events'); - $this->links = [ - 'text' => 'db_events.php?server=' . $GLOBALS['server'] - . '&db=%2$s&item_name=%1$s&edit_item=1', - 'icon' => 'db_events.php?server=' . $GLOBALS['server'] - . '&db=%2$s&item_name=%1$s&export_item=1', - ]; - $this->classes = 'event'; - } - - /** - * Returns the type of the item represented by the node. - * - * @return string type of the item - */ - protected function getItemType() - { - return 'event'; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEventContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEventContainer.php deleted file mode 100644 index 86c2937..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEventContainer.php +++ /dev/null @@ -1,52 +0,0 @@ -icon = Util::getImage('b_events', ''); - $this->links = [ - 'text' => 'db_events.php?server=' . $GLOBALS['server'] - . '&db=%1$s', - 'icon' => 'db_events.php?server=' . $GLOBALS['server'] - . '&db=%1$s', - ]; - $this->realName = 'events'; - - $new = NodeFactory::getInstance( - 'Node', - _pgettext('Create new event', 'New') - ); - $new->isNew = true; - $new->icon = Util::getImage('b_event_add', ''); - $new->links = [ - 'text' => 'db_events.php?server=' . $GLOBALS['server'] - . '&db=%2$s&add_item=1', - 'icon' => 'db_events.php?server=' . $GLOBALS['server'] - . '&db=%2$s&add_item=1', - ]; - $new->classes = 'new_event italics'; - $this->addChild($new); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunction.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunction.php deleted file mode 100644 index ffd2afe..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunction.php +++ /dev/null @@ -1,53 +0,0 @@ -icon = Util::getImage('b_routines', __('Function')); - $this->links = [ - 'text' => 'db_routines.php?server=' . $GLOBALS['server'] - . '&db=%2$s&item_name=%1$s&item_type=FUNCTION' - . '&edit_item=1', - 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] - . '&db=%2$s&item_name=%1$s&item_type=FUNCTION' - . '&execute_dialog=1', - ]; - $this->classes = 'function'; - } - - /** - * Returns the type of the item represented by the node. - * - * @return string type of the item - */ - protected function getItemType() - { - return 'function'; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunctionContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunctionContainer.php deleted file mode 100644 index 52715a3..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunctionContainer.php +++ /dev/null @@ -1,53 +0,0 @@ -icon = Util::getImage('b_routines', __('Functions')); - $this->links = [ - 'text' => 'db_routines.php?server=' . $GLOBALS['server'] - . '&db=%1$s&type=FUNCTION', - 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] - . '&db=%1$s&type=FUNCTION', - ]; - $this->realName = 'functions'; - - $newLabel = _pgettext('Create new function', 'New'); - $new = NodeFactory::getInstance( - 'Node', - $newLabel - ); - $new->isNew = true; - $new->icon = Util::getImage('b_routine_add', $newLabel); - $new->links = [ - 'text' => 'db_routines.php?server=' . $GLOBALS['server'] - . '&db=%2$s&add_item=1&item_type=FUNCTION', - 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] - . '&db=%2$s&add_item=1&item_type=FUNCTION', - ]; - $new->classes = 'new_function italics'; - $this->addChild($new); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndex.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndex.php deleted file mode 100644 index c464114..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndex.php +++ /dev/null @@ -1,41 +0,0 @@ -icon = Util::getImage('b_index', __('Index')); - $this->links = [ - 'text' => 'tbl_indexes.php?server=' . $GLOBALS['server'] - . '&db=%3$s&table=%2$s&index=%1$s', - 'icon' => 'tbl_indexes.php?server=' . $GLOBALS['server'] - . '&db=%3$s&table=%2$s&index=%1$s', - ]; - $this->classes = 'index'; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndexContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndexContainer.php deleted file mode 100644 index 9be90d3..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndexContainer.php +++ /dev/null @@ -1,55 +0,0 @@ -icon = Util::getImage('b_index', __('Indexes')); - $this->links = [ - 'text' => 'tbl_structure.php?server=' . $GLOBALS['server'] - . '&db=%2$s&table=%1$s', - 'icon' => 'tbl_structure.php?server=' . $GLOBALS['server'] - . '&db=%2$s&table=%1$s', - ]; - $this->realName = 'indexes'; - - $newLabel = _pgettext('Create new index', 'New'); - $new = NodeFactory::getInstance( - 'Node', - $newLabel - ); - $new->isNew = true; - $new->icon = Util::getImage('b_index_add', $newLabel); - $new->links = [ - 'text' => 'tbl_indexes.php?server=' . $GLOBALS['server'] - . '&create_index=1&added_fields=2' - . '&db=%3$s&table=%2$s', - 'icon' => 'tbl_indexes.php?server=' . $GLOBALS['server'] - . '&create_index=1&added_fields=2' - . '&db=%3$s&table=%2$s', - ]; - $new->classes = 'new_index italics'; - $this->addChild($new); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedure.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedure.php deleted file mode 100644 index fbced93..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedure.php +++ /dev/null @@ -1,53 +0,0 @@ -icon = Util::getImage('b_routines', __('Procedure')); - $this->links = [ - 'text' => 'db_routines.php?server=' . $GLOBALS['server'] - . '&db=%2$s&item_name=%1$s&item_type=PROCEDURE' - . '&edit_item=1', - 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] - . '&db=%2$s&item_name=%1$s&item_type=PROCEDURE' - . '&execute_dialog=1', - ]; - $this->classes = 'procedure'; - } - - /** - * Returns the type of the item represented by the node. - * - * @return string type of the item - */ - protected function getItemType() - { - return 'procedure'; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedureContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedureContainer.php deleted file mode 100644 index 1978ede..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedureContainer.php +++ /dev/null @@ -1,53 +0,0 @@ -icon = Util::getImage('b_routines', __('Procedures')); - $this->links = [ - 'text' => 'db_routines.php?server=' . $GLOBALS['server'] - . '&db=%1$s&type=PROCEDURE', - 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] - . '&db=%1$s&type=PROCEDURE', - ]; - $this->realName = 'procedures'; - - $newLabel = _pgettext('Create new procedure', 'New'); - $new = NodeFactory::getInstance( - 'Node', - $newLabel - ); - $new->isNew = true; - $new->icon = Util::getImage('b_routine_add', $newLabel); - $new->links = [ - 'text' => 'db_routines.php?server=' . $GLOBALS['server'] - . '&db=%2$s&add_item=1', - 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] - . '&db=%2$s&add_item=1', - ]; - $new->classes = 'new_procedure italics'; - $this->addChild($new); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTable.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTable.php deleted file mode 100644 index 89965eb..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTable.php +++ /dev/null @@ -1,310 +0,0 @@ -icon = []; - $this->addIcon( - Util::getScriptNameForOption( - $GLOBALS['cfg']['NavigationTreeDefaultTabTable'], - 'table' - ) - ); - $this->addIcon( - Util::getScriptNameForOption( - $GLOBALS['cfg']['NavigationTreeDefaultTabTable2'], - 'table' - ) - ); - $title = Util::getTitleForTarget( - $GLOBALS['cfg']['DefaultTabTable'] - ); - $this->title = $title; - - $scriptName = Util::getScriptNameForOption( - $GLOBALS['cfg']['DefaultTabTable'], - 'table' - ); - $this->links = [ - 'text' => $scriptName - . '?server=' . $GLOBALS['server'] - . '&db=%2$s&table=%1$s' - . '&pos=0', - 'icon' => [ - Util::getScriptNameForOption( - $GLOBALS['cfg']['NavigationTreeDefaultTabTable'], - 'table' - ) - . '?server=' . $GLOBALS['server'] - . '&db=%2$s&table=%1$s', - Util::getScriptNameForOption( - $GLOBALS['cfg']['NavigationTreeDefaultTabTable2'], - 'table' - ) - . '?server=' . $GLOBALS['server'] - . '&db=%2$s&table=%1$s', - ], - 'title' => $this->title, - ]; - $this->classes = 'table'; - } - - /** - * Returns the number of children of type $type present inside this container - * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase - * and PhpMyAdmin\Navigation\Nodes\NodeTable 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()->realName; - $table = $this->realName; - switch ($type) { - case 'columns': - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $GLOBALS['dbi']->escapeString($db); - $table = $GLOBALS['dbi']->escapeString($table); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`COLUMNS` "; - $query .= "WHERE `TABLE_NAME`='$table' "; - $query .= "AND `TABLE_SCHEMA`='$db'"; - $retval = (int) $GLOBALS['dbi']->fetchValue($query); - } else { - $db = Util::backquote($db); - $table = Util::backquote($table); - $query = "SHOW COLUMNS FROM $table FROM $db"; - $retval = (int) $GLOBALS['dbi']->numRows( - $GLOBALS['dbi']->tryQuery($query) - ); - } - break; - case 'indexes': - $db = Util::backquote($db); - $table = Util::backquote($table); - $query = "SHOW INDEXES FROM $table FROM $db"; - $retval = (int) $GLOBALS['dbi']->numRows( - $GLOBALS['dbi']->tryQuery($query) - ); - break; - case 'triggers': - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $GLOBALS['dbi']->escapeString($db); - $table = $GLOBALS['dbi']->escapeString($table); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`TRIGGERS` "; - $query .= "WHERE `EVENT_OBJECT_SCHEMA` " - . Util::getCollateForIS() . "='$db' "; - $query .= "AND `EVENT_OBJECT_TABLE` " - . Util::getCollateForIS() . "='$table'"; - $retval = (int) $GLOBALS['dbi']->fetchValue($query); - } else { - $db = Util::backquote($db); - $table = $GLOBALS['dbi']->escapeString($table); - $query = "SHOW TRIGGERS FROM $db WHERE `Table` = '$table'"; - $retval = (int) $GLOBALS['dbi']->numRows( - $GLOBALS['dbi']->tryQuery($query) - ); - } - break; - default: - break; - } - - return $retval; - } - - /** - * Returns the names of children of type $type present inside this container - * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase - * and PhpMyAdmin\Navigation\Nodes\NodeTable 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 = []; - $db = $this->realParent()->realName; - $table = $this->realName; - switch ($type) { - case 'columns': - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $GLOBALS['dbi']->escapeString($db); - $table = $GLOBALS['dbi']->escapeString($table); - $query = "SELECT `COLUMN_NAME` AS `name` "; - $query .= ",`COLUMN_KEY` AS `key` "; - $query .= ",`DATA_TYPE` AS `type` "; - $query .= ",`COLUMN_DEFAULT` AS `default` "; - $query .= ",IF (`IS_NULLABLE` = 'NO', '', 'nullable') AS `nullable` "; - $query .= "FROM `INFORMATION_SCHEMA`.`COLUMNS` "; - $query .= "WHERE `TABLE_NAME`='$table' "; - $query .= "AND `TABLE_SCHEMA`='$db' "; - $query .= "ORDER BY `COLUMN_NAME` ASC "; - $query .= "LIMIT " . intval($pos) . ", $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); - break; - } - - $db = Util::backquote($db); - $table = Util::backquote($table); - $query = "SHOW COLUMNS FROM $table FROM $db"; - $handle = $GLOBALS['dbi']->tryQuery($query); - if ($handle === false) { - break; - } - - $count = 0; - if ($GLOBALS['dbi']->dataSeek($handle, $pos)) { - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - if ($count < $maxItems) { - $retval[] = $arr['Field']; - $count++; - } else { - break; - } - } - } - break; - case 'indexes': - $db = Util::backquote($db); - $table = Util::backquote($table); - $query = "SHOW INDEXES FROM $table FROM $db"; - $handle = $GLOBALS['dbi']->tryQuery($query); - if ($handle === false) { - break; - } - - $count = 0; - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - if (in_array($arr['Key_name'], $retval)) { - continue; - } - if ($pos <= 0 && $count < $maxItems) { - $retval[] = $arr['Key_name']; - $count++; - } - $pos--; - } - break; - case 'triggers': - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $GLOBALS['dbi']->escapeString($db); - $table = $GLOBALS['dbi']->escapeString($table); - $query = "SELECT `TRIGGER_NAME` AS `name` "; - $query .= "FROM `INFORMATION_SCHEMA`.`TRIGGERS` "; - $query .= "WHERE `EVENT_OBJECT_SCHEMA` " - . Util::getCollateForIS() . "='$db' "; - $query .= "AND `EVENT_OBJECT_TABLE` " - . Util::getCollateForIS() . "='$table' "; - $query .= "ORDER BY `TRIGGER_NAME` ASC "; - $query .= "LIMIT " . intval($pos) . ", $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); - break; - } - - $db = Util::backquote($db); - $table = $GLOBALS['dbi']->escapeString($table); - $query = "SHOW TRIGGERS FROM $db WHERE `Table` = '$table'"; - $handle = $GLOBALS['dbi']->tryQuery($query); - if ($handle === false) { - break; - } - - $count = 0; - if ($GLOBALS['dbi']->dataSeek($handle, $pos)) { - while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { - if ($count < $maxItems) { - $retval[] = $arr['Trigger']; - $count++; - } else { - break; - } - } - } - break; - default: - break; - } - - return $retval; - } - - /** - * Returns the type of the item represented by the node. - * - * @return string type of the item - */ - protected function getItemType() - { - return 'table'; - } - - /** - * Add an icon to navigation tree - * - * @param string $page Page name to redirect - * - * @return void - */ - private function addIcon($page) - { - if (empty($page)) { - return; - } - - switch ($page) { - case 'tbl_structure.php': - $this->icon[] = Util::getImage('b_props', __('Structure')); - break; - case 'tbl_select.php': - $this->icon[] = Util::getImage('b_search', __('Search')); - break; - case 'tbl_change.php': - $this->icon[] = Util::getImage('b_insrow', __('Insert')); - break; - case 'tbl_sql.php': - $this->icon[] = Util::getImage('b_sql', __('SQL')); - break; - case 'sql.php': - $this->icon[] = Util::getImage('b_browse', __('Browse')); - break; - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTableContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTableContainer.php deleted file mode 100644 index ec93203..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTableContainer.php +++ /dev/null @@ -1,54 +0,0 @@ -icon = Util::getImage('b_browse', __('Tables')); - $this->links = [ - 'text' => 'db_structure.php?server=' . $GLOBALS['server'] - . '&db=%1$s&tbl_type=table', - 'icon' => 'db_structure.php?server=' . $GLOBALS['server'] - . '&db=%1$s&tbl_type=table', - ]; - $this->realName = 'tables'; - $this->classes = 'tableContainer subContainer'; - - $newLabel = _pgettext('Create new table', 'New'); - $new = NodeFactory::getInstance( - 'Node', - $newLabel - ); - $new->isNew = true; - $new->icon = Util::getImage('b_table_add', $newLabel); - $new->links = [ - 'text' => 'tbl_create.php?server=' . $GLOBALS['server'] - . '&db=%2$s', - 'icon' => 'tbl_create.php?server=' . $GLOBALS['server'] - . '&db=%2$s', - ]; - $new->classes = 'new_table italics'; - $this->addChild($new); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTrigger.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTrigger.php deleted file mode 100644 index 8ec4612..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTrigger.php +++ /dev/null @@ -1,41 +0,0 @@ -icon = Util::getImage('b_triggers'); - $this->links = [ - 'text' => 'db_triggers.php?server=' . $GLOBALS['server'] - . '&db=%3$s&item_name=%1$s&edit_item=1', - 'icon' => 'db_triggers.php?server=' . $GLOBALS['server'] - . '&db=%3$s&item_name=%1$s&export_item=1', - ]; - $this->classes = 'trigger'; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTriggerContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTriggerContainer.php deleted file mode 100644 index a5aa3b7..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTriggerContainer.php +++ /dev/null @@ -1,52 +0,0 @@ -icon = Util::getImage('b_triggers'); - $this->links = [ - 'text' => 'db_triggers.php?server=' . $GLOBALS['server'] - . '&db=%2$s&table=%1$s', - 'icon' => 'db_triggers.php?server=' . $GLOBALS['server'] - . '&db=%2$s&table=%1$s', - ]; - $this->realName = 'triggers'; - - $new = NodeFactory::getInstance( - 'Node', - _pgettext('Create new trigger', 'New') - ); - $new->isNew = true; - $new->icon = Util::getImage('b_trigger_add', ''); - $new->links = [ - 'text' => 'db_triggers.php?server=' . $GLOBALS['server'] - . '&db=%3$s&add_item=1', - 'icon' => 'db_triggers.php?server=' . $GLOBALS['server'] - . '&db=%3$s&add_item=1', - ]; - $new->classes = 'new_trigger italics'; - $this->addChild($new); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeView.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeView.php deleted file mode 100644 index 1ded149..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeView.php +++ /dev/null @@ -1,51 +0,0 @@ -icon = Util::getImage('b_props', __('View')); - $this->links = [ - 'text' => 'sql.php?server=' . $GLOBALS['server'] - . '&db=%2$s&table=%1$s&pos=0', - 'icon' => 'tbl_structure.php?server=' . $GLOBALS['server'] - . '&db=%2$s&table=%1$s', - ]; - $this->classes = 'view'; - } - - /** - * Returns the type of the item represented by the node. - * - * @return string type of the item - */ - protected function getItemType() - { - return 'view'; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeViewContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeViewContainer.php deleted file mode 100644 index f202904..0000000 --- a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeViewContainer.php +++ /dev/null @@ -1,54 +0,0 @@ -icon = Util::getImage('b_views', __('Views')); - $this->links = [ - 'text' => 'db_structure.php?server=' . $GLOBALS['server'] - . '&db=%1$s&tbl_type=view', - 'icon' => 'db_structure.php?server=' . $GLOBALS['server'] - . '&db=%1$s&tbl_type=view', - ]; - $this->classes = 'viewContainer subContainer'; - $this->realName = 'views'; - - $newLabel = _pgettext('Create new view', 'New'); - $new = NodeFactory::getInstance( - 'Node', - $newLabel - ); - $new->isNew = true; - $new->icon = Util::getImage('b_view_add', $newLabel); - $new->links = [ - 'text' => 'view_create.php?server=' . $GLOBALS['server'] - . '&db=%2$s', - 'icon' => 'view_create.php?server=' . $GLOBALS['server'] - . '&db=%2$s', - ]; - $new->classes = 'new_view italics'; - $this->addChild($new); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Normalization.php b/srcs/phpmyadmin/libraries/classes/Normalization.php deleted file mode 100644 index 6c3d73b..0000000 --- a/srcs/phpmyadmin/libraries/classes/Normalization.php +++ /dev/null @@ -1,1105 +0,0 @@ -dbi = $dbi; - $this->relation = $relation; - $this->transformations = $transformations; - $this->template = $template; - } - - /** - * build the html for columns of $colTypeCategory category - * in form of given $listType in a table - * - * @param string $db current database - * @param string $table current table - * @param string $colTypeCategory supported all|Numeric|String|Spatial - * |Date and time using the _pgettext() format - * @param string $listType type of list to build, supported dropdown|checkbox - * - * @return string HTML for list of columns in form of given list types - */ - public function getHtmlForColumnsList( - $db, - $table, - $colTypeCategory = 'all', - $listType = 'dropdown' - ) { - $columnTypeList = []; - if ($colTypeCategory != 'all') { - $types = $this->dbi->types->getColumns(); - $columnTypeList = $types[$colTypeCategory]; - } - $this->dbi->selectDb($db); - $columns = $this->dbi->getColumns( - $db, - $table, - null, - true - ); - $type = ""; - $selectColHtml = ""; - foreach ($columns as $column => $def) { - if (isset($def['Type'])) { - $extractedColumnSpec = Util::extractColumnSpec($def['Type']); - $type = $extractedColumnSpec['type']; - } - if (empty($columnTypeList) - || in_array(mb_strtoupper($type), $columnTypeList) - ) { - if ($listType == 'checkbox') { - $selectColHtml .= '' - . htmlspecialchars($column) . ' [ ' - . htmlspecialchars($def['Type']) . ' ]
    '; - } else { - $selectColHtml .= ''; - } - } - } - return $selectColHtml; - } - - /** - * get the html of the form to add the new column to given table - * - * @param integer $numFields number of columns to add - * @param string $db current database - * @param string $table current table - * @param array $columnMeta array containing default values for the fields - * - * @return string HTML - */ - public function getHtmlForCreateNewColumn( - $numFields, - $db, - $table, - array $columnMeta = [] - ) { - $cfgRelation = $this->relation->getRelationsParam(); - $contentCells = []; - $availableMime = []; - $mimeMap = []; - if ($cfgRelation['mimework'] && $GLOBALS['cfg']['BrowseMIME']) { - $mimeMap = $this->transformations->getMime($db, $table); - $availableMimeTypes = $this->transformations->getAvailableMimeTypes(); - if ($availableMimeTypes !== null) { - $availableMime = $availableMimeTypes; - } - } - $commentsMap = $this->relation->getComments($db, $table); - for ($columnNumber = 0; $columnNumber < $numFields; $columnNumber++) { - $contentCells[$columnNumber] = [ - 'column_number' => $columnNumber, - 'column_meta' => $columnMeta, - 'type_upper' => '', - 'length_values_input_size' => 8, - 'length' => '', - 'extracted_columnspec' => [], - 'submit_attribute' => null, - 'comments_map' => $commentsMap, - 'fields_meta' => null, - 'is_backup' => true, - 'move_columns' => [], - 'cfg_relation' => $cfgRelation, - 'available_mime' => $availableMime, - 'mime_map' => $mimeMap, - ]; - } - - $charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); - $collations = Charsets::getCollations($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); - $charsetsList = []; - /** @var Charset $charset */ - foreach ($charsets as $charset) { - $collationsList = []; - /** @var Collation $collation */ - foreach ($collations[$charset->getName()] as $collation) { - $collationsList[] = [ - 'name' => $collation->getName(), - 'description' => $collation->getDescription(), - ]; - } - $charsetsList[] = [ - 'name' => $charset->getName(), - 'description' => $charset->getDescription(), - 'collations' => $collationsList, - ]; - } - - return $this->template->render('columns_definitions/table_fields_definitions', [ - 'is_backup' => true, - 'fields_meta' => null, - 'mimework' => $cfgRelation['mimework'], - 'content_cells' => $contentCells, - 'change_column' => $_POST['change_column'], - 'is_virtual_columns_supported' => Util::isVirtualColumnsSupported(), - 'browse_mime' => $GLOBALS['cfg']['BrowseMIME'], - 'server_type' => Util::getServerType(), - 'max_rows' => intval($GLOBALS['cfg']['MaxRows']), - 'char_editing' => $GLOBALS['cfg']['CharEditing'], - 'attribute_types' => $this->dbi->types->getAttributes(), - 'privs_available' => $GLOBALS['col_priv'] && $GLOBALS['is_reload_priv'], - 'max_length' => $this->dbi->getVersion() >= 50503 ? 1024 : 255, - 'charsets' => $charsetsList, - ]); - } - - /** - * build the html for step 1.1 of normalization - * - * @param string $db current database - * @param string $table current table - * @param string $normalizedTo up to which step normalization will go, - * possible values 1nf|2nf|3nf - * - * @return string HTML for step 1.1 - */ - public function getHtmlFor1NFStep1($db, $table, $normalizedTo) - { - $step = 1; - $stepTxt = __('Make all columns atomic'); - $html = "

    " - . __('First step of normalization (1NF)') . "

    "; - $html .= "
    " . - "
    " . - "" . __('Step 1.') . $step . " " . $stepTxt . "" . - "

    " . __( - 'Do you have any column which can be split into more than' - . ' one column? ' - . 'For example: address can be split into street, city, country and zip.' - ) - . "
    ( " - . __( - 'Show me the central list of columns that are not already in this table' - ) . " )

    " - . "

    " . __( - 'Select a column which can be split into more ' - . 'than one (on select of \'no such column\', it\'ll move to next step).' - ) - . "

    " - . "
    " - . "" - . "" . __('split into ') - . "" - . "
    " - . "
    " - . "
    " - . "
    " - . "
    "; - return $html; - } - - /** - * build the html contents of various html elements in step 1.2 - * - * @param string $db current database - * @param string $table current table - * - * @return string[] HTML contents for step 1.2 - */ - public function getHtmlContentsFor1NFStep2($db, $table) - { - $step = 2; - $stepTxt = __('Have a primary key'); - $primary = Index::getPrimary($table, $db); - $hasPrimaryKey = "0"; - $legendText = __('Step 1.') . $step . " " . $stepTxt; - $extra = ''; - if ($primary) { - $headText = __("Primary key already exists."); - $subText = __("Taking you to next step…"); - $hasPrimaryKey = "1"; - } else { - $headText = __( - "There is no primary key; please add one.
    " - . "Hint: A primary key is a column " - . "(or combination of columns) that uniquely identify all rows." - ); - $subText = '' - . Util::getIcon( - 'b_index_add', - __( - 'Add a primary key on existing column(s)' - ) - ) - . ''; - $extra = __( - "If it's not possible to make existing " - . "column combinations as primary key" - ) . "
    " - . '' - . __('+ Add a new primary key column') . ''; - } - return [ - 'legendText' => $legendText, - 'headText' => $headText, - 'subText' => $subText, - 'hasPrimaryKey' => $hasPrimaryKey, - 'extra' => $extra, - ]; - } - - /** - * build the html contents of various html elements in step 1.4 - * - * @param string $db current database - * @param string $table current table - * - * @return string[] HTML contents for step 1.4 - */ - public function getHtmlContentsFor1NFStep4($db, $table) - { - $step = 4; - $stepTxt = __('Remove redundant columns'); - $legendText = __('Step 1.') . $step . " " . $stepTxt; - $headText = __( - "Do you have a group of columns which on combining gives an existing" - . " column? For example, if you have first_name, last_name and" - . " full_name then combining first_name and last_name gives full_name" - . " which is redundant." - ); - $subText = __( - "Check the columns which are redundant and click on remove. " - . "If no redundant column, click on 'No redundant column'" - ); - $extra = $this->getHtmlForColumnsList($db, $table, 'all', "checkbox") . "
    " - . '' - . ''; - return [ - 'legendText' => $legendText, - 'headText' => $headText, - 'subText' => $subText, - 'extra' => $extra, - ]; - } - - /** - * build the html contents of various html elements in step 1.3 - * - * @param string $db current database - * @param string $table current table - * - * @return string[] HTML contents for step 1.3 - */ - public function getHtmlContentsFor1NFStep3($db, $table) - { - $step = 3; - $stepTxt = __('Move repeating groups'); - $legendText = __('Step 1.') . $step . " " . $stepTxt; - $headText = __( - "Do you have a group of two or more columns that are closely " - . "related and are all repeating the same attribute? For example, " - . "a table that holds data on books might have columns such as book_id, " - . "author1, author2, author3 and so on which form a " - . "repeating group. In this case a new table (book_id, author) should " - . "be created." - ); - $subText = __( - "Check the columns which form a repeating group. " - . "If no such group, click on 'No repeating group'" - ); - $extra = $this->getHtmlForColumnsList($db, $table, 'all', "checkbox") . "
    " - . '' - . ''; - $primary = Index::getPrimary($table, $db); - $primarycols = $primary->getColumns(); - $pk = []; - foreach ($primarycols as $col) { - $pk[] = $col->getName(); - } - return [ - 'legendText' => $legendText, - 'headText' => $headText, - 'subText' => $subText, - 'extra' => $extra, - 'primary_key' => json_encode($pk), - ]; - } - - /** - * build html contents for 2NF step 2.1 - * - * @param string $db current database - * @param string $table current table - * - * @return string[] HTML contents for 2NF step 2.1 - */ - public function getHtmlFor2NFstep1($db, $table) - { - $legendText = __('Step 2.') . "1 " . __('Find partial dependencies'); - $primary = Index::getPrimary($table, $db); - $primarycols = $primary->getColumns(); - $pk = []; - $subText = ''; - $selectPkForm = ""; - $extra = ""; - foreach ($primarycols as $col) { - $pk[] = $col->getName(); - $selectPkForm .= '' - . htmlspecialchars($col->getName()); - } - $key = implode(', ', $pk); - if (count($primarycols) > 1) { - $this->dbi->selectDb($db); - $columns = (array) $this->dbi->getColumnNames( - $db, - $table - ); - if (count($pk) == count($columns)) { - $headText = sprintf( - __( - 'No partial dependencies possible as ' - . 'no non-primary column exists since primary key ( %1$s ) ' - . 'is composed of all the columns in the table.' - ), - htmlspecialchars($key) - ) . '
    '; - $extra = '

    ' . __('Table is already in second normal form.') - . '

    '; - } else { - $headText = sprintf( - __( - 'The primary key ( %1$s ) consists of more than one column ' - . 'so we need to find the partial dependencies.' - ), - htmlspecialchars($key) - ) . '
    ' . __( - 'Please answer the following question(s) ' - . 'carefully to obtain a correct normalization.' - ) - . '
    ' . __( - '+ Show me the possible partial dependencies ' - . 'based on data in the table' - ) . ''; - $subText = __( - 'For each column below, ' - . 'please select the minimal set of columns among given set ' - . 'whose values combined together are sufficient' - . ' to determine the value of the column.' - ); - $cnt = 0; - foreach ($columns as $column) { - if (! in_array($column, $pk)) { - $cnt++; - $extra .= "" . sprintf( - __('\'%1$s\' depends on:'), - htmlspecialchars($column) - ) . "
    "; - $extra .= '
    ' - . $selectPkForm . '


    '; - } - } - } - } else { - $headText = sprintf( - __( - 'No partial dependencies possible as the primary key' - . ' ( %1$s ) has just one column.' - ), - htmlspecialchars($key) - ) . '
    '; - $extra = '

    ' . __('Table is already in second normal form.') . '

    '; - } - return [ - 'legendText' => $legendText, - 'headText' => $headText, - 'subText' => $subText, - 'extra' => $extra, - 'primary_key' => $key, - ]; - } - - /** - * build the html for showing the tables to have in order to put current table in 2NF - * - * @param array $partialDependencies array containing all the dependencies - * @param string $table current table - * - * @return string HTML - */ - public function getHtmlForNewTables2NF(array $partialDependencies, $table) - { - $html = '

    ' . sprintf( - __( - 'In order to put the ' - . 'original table \'%1$s\' into Second normal form we need ' - . 'to create the following tables:' - ), - htmlspecialchars($table) - ) . '

    '; - $tableName = $table; - $i = 1; - foreach ($partialDependencies as $key => $dependents) { - $html .= '

    ' - . '( ' . htmlspecialchars($key) . '' - . (count($dependents) > 0 ? ', ' : '') - . htmlspecialchars(implode(', ', $dependents)) . ' )'; - $i++; - $tableName = 'table' . $i; - } - return $html; - } - - /** - * create/alter the tables needed for 2NF - * - * @param array $partialDependencies array containing all the partial dependencies - * @param object $tablesName name of new tables - * @param string $table current table - * @param string $db current database - * - * @return array - */ - public function createNewTablesFor2NF(array $partialDependencies, $tablesName, $table, $db) - { - $dropCols = false; - $nonPKCols = []; - $queries = []; - $error = false; - $headText = '

    ' . sprintf( - __('The second step of normalization is complete for table \'%1$s\'.'), - htmlspecialchars($table) - ) . '

    '; - if (count((array) $partialDependencies) === 1) { - return [ - 'legendText' => __('End of step'), - 'headText' => $headText, - 'queryError' => $error, - ]; - } - $message = ''; - $this->dbi->selectDb($db); - foreach ($partialDependencies as $key => $dependents) { - if ($tablesName->$key != $table) { - $backquotedKey = implode(', ', Util::backquote(explode(', ', $key))); - $queries[] = 'CREATE TABLE ' . Util::backquote($tablesName->$key) - . ' SELECT DISTINCT ' . $backquotedKey - . (count($dependents) > 0 ? ', ' : '') - . implode(',', Util::backquote($dependents)) - . ' FROM ' . Util::backquote($table) . ';'; - $queries[] = 'ALTER TABLE ' . Util::backquote($tablesName->$key) - . ' ADD PRIMARY KEY(' . $backquotedKey . ');'; - $nonPKCols = array_merge($nonPKCols, $dependents); - } else { - $dropCols = true; - } - } - - if ($dropCols) { - $query = 'ALTER TABLE ' . Util::backquote($table); - foreach ($nonPKCols as $col) { - $query .= ' DROP ' . Util::backquote($col) . ','; - } - $query = trim($query, ', '); - $query .= ';'; - $queries[] = $query; - } else { - $queries[] = 'DROP TABLE ' . Util::backquote($table); - } - foreach ($queries as $query) { - if (! $this->dbi->tryQuery($query)) { - $message = Message::error(__('Error in processing!')); - $message->addMessage( - Message::rawError( - $this->dbi->getError() - ), - '

    ' - ); - $error = true; - break; - } - } - return [ - 'legendText' => __('End of step'), - 'headText' => $headText, - 'queryError' => $error, - 'extra' => $message, - ]; - } - - /** - * build the html for showing the new tables to have in order - * to put given tables in 3NF - * - * @param object $dependencies containing all the dependencies - * @param array $tables tables formed after 2NF and need to convert to 3NF - * @param string $db current database - * - * @return array containing html and the list of new tables - */ - public function getHtmlForNewTables3NF($dependencies, array $tables, $db) - { - $html = ""; - $i = 1; - $newTables = []; - foreach ($tables as $table => $arrDependson) { - if (count(array_unique($arrDependson)) === 1) { - continue; - } - $primary = Index::getPrimary($table, $db); - $primarycols = $primary->getColumns(); - $pk = []; - foreach ($primarycols as $col) { - $pk[] = $col->getName(); - } - $html .= '

    ' . sprintf( - __( - 'In order to put the ' - . 'original table \'%1$s\' into Third normal form we need ' - . 'to create the following tables:' - ), - htmlspecialchars($table) - ) . '

    '; - $tableName = $table; - $columnList = []; - foreach ($arrDependson as $key) { - $dependents = $dependencies->$key; - if ($key == $table) { - $key = implode(', ', $pk); - } - $tmpTableCols = array_merge(explode(', ', $key), $dependents); - sort($tmpTableCols); - if (! in_array($tmpTableCols, $columnList)) { - $columnList[] = $tmpTableCols; - $html .= '

    ' - . '( ' . htmlspecialchars($key) . '' - . (count($dependents) > 0 ? ', ' : '') - . htmlspecialchars(implode(', ', $dependents)) . ' )'; - $newTables[$table][$tableName] = [ - "pk" => $key, - "nonpk" => implode(', ', $dependents), - ]; - $i++; - $tableName = 'table' . $i; - } - } - } - return [ - 'html' => $html, - 'newTables' => $newTables, - 'success' => true, - ]; - } - - /** - * create new tables or alter existing to get 3NF - * - * @param array $newTables list of new tables to be created - * @param string $db current database - * - * @return array - */ - public function createNewTablesFor3NF(array $newTables, $db) - { - $queries = []; - $dropCols = false; - $error = false; - $headText = '

    ' . - __('The third step of normalization is complete.') - . '

    '; - if (count((array) $newTables) === 0) { - return [ - 'legendText' => __('End of step'), - 'headText' => $headText, - 'queryError' => $error, - ]; - } - $message = ''; - $this->dbi->selectDb($db); - foreach ($newTables as $originalTable => $tablesList) { - foreach ($tablesList as $table => $cols) { - if ($table != $originalTable) { - $quotedPk = implode( - ', ', - Util::backquote(explode(', ', $cols->pk)) - ); - $quotedNonpk = implode( - ', ', - Util::backquote(explode(', ', $cols->nonpk)) - ); - $queries[] = 'CREATE TABLE ' . Util::backquote($table) - . ' SELECT DISTINCT ' . $quotedPk - . ', ' . $quotedNonpk - . ' FROM ' . Util::backquote($originalTable) . ';'; - $queries[] = 'ALTER TABLE ' . Util::backquote($table) - . ' ADD PRIMARY KEY(' . $quotedPk . ');'; - } else { - $dropCols = $cols; - } - } - if ($dropCols) { - $columns = (array) $this->dbi->getColumnNames( - $db, - $originalTable - ); - $colPresent = array_merge( - explode(', ', $dropCols->pk), - explode(', ', $dropCols->nonpk) - ); - $query = 'ALTER TABLE ' . Util::backquote($originalTable); - foreach ($columns as $col) { - if (! in_array($col, $colPresent)) { - $query .= ' DROP ' . Util::backquote($col) . ','; - } - } - $query = trim($query, ', '); - $query .= ';'; - $queries[] = $query; - } else { - $queries[] = 'DROP TABLE ' . Util::backquote($originalTable); - } - $dropCols = false; - } - foreach ($queries as $query) { - if (! $this->dbi->tryQuery($query)) { - $message = Message::error(__('Error in processing!')); - $message->addMessage( - Message::rawError( - $this->dbi->getError() - ), - '

    ' - ); - $error = true; - break; - } - } - return [ - 'legendText' => __('End of step'), - 'headText' => $headText, - 'queryError' => $error, - 'extra' => $message, - ]; - } - - /** - * move the repeating group of columns to a new table - * - * @param string $repeatingColumns comma separated list of repeating group columns - * @param string $primaryColumns comma separated list of column in primary key - * of $table - * @param string $newTable name of the new table to be created - * @param string $newColumn name of the new column in the new table - * @param string $table current table - * @param string $db current database - * - * @return array - */ - public function moveRepeatingGroup( - $repeatingColumns, - $primaryColumns, - $newTable, - $newColumn, - $table, - $db - ) { - $repeatingColumnsArr = (array) Util::backquote( - explode(', ', $repeatingColumns) - ); - $primaryColumns = implode( - ',', - Util::backquote(explode(',', $primaryColumns)) - ); - $query1 = 'CREATE TABLE ' . Util::backquote($newTable); - $query2 = 'ALTER TABLE ' . Util::backquote($table); - $message = Message::success( - sprintf( - __('Selected repeating group has been moved to the table \'%s\''), - htmlspecialchars($table) - ) - ); - $first = true; - $error = false; - foreach ($repeatingColumnsArr as $repeatingColumn) { - if (! $first) { - $query1 .= ' UNION '; - } - $first = false; - $query1 .= ' SELECT ' . $primaryColumns . ',' . $repeatingColumn - . ' as ' . Util::backquote($newColumn) - . ' FROM ' . Util::backquote($table); - $query2 .= ' DROP ' . $repeatingColumn . ','; - } - $query2 = trim($query2, ','); - $queries = [ - $query1, - $query2, - ]; - $this->dbi->selectDb($db); - foreach ($queries as $query) { - if (! $this->dbi->tryQuery($query)) { - $message = Message::error(__('Error in processing!')); - $message->addMessage( - Message::rawError( - $this->dbi->getError() - ), - '

    ' - ); - $error = true; - break; - } - } - return [ - 'queryError' => $error, - 'message' => $message, - ]; - } - - /** - * build html for 3NF step 1 to find the transitive dependencies - * - * @param string $db current database - * @param array $tables tables formed after 2NF and need to process for 3NF - * - * @return string[] - */ - public function getHtmlFor3NFstep1($db, array $tables) - { - $legendText = __('Step 3.') . "1 " . __('Find transitive dependencies'); - $extra = ""; - $headText = __( - 'Please answer the following question(s) ' - . 'carefully to obtain a correct normalization.' - ); - $subText = __( - 'For each column below, ' - . 'please select the minimal set of columns among given set ' - . 'whose values combined together are sufficient' - . ' to determine the value of the column.
    ' - . 'Note: A column may have no transitive dependency, ' - . 'in that case you don\'t have to select any.' - ); - $cnt = 0; - foreach ($tables as $table) { - $primary = Index::getPrimary($table, $db); - $primarycols = $primary->getColumns(); - $selectTdForm = ""; - $pk = []; - foreach ($primarycols as $col) { - $pk[] = $col->getName(); - } - $this->dbi->selectDb($db); - $columns = (array) $this->dbi->getColumnNames( - $db, - $table - ); - if (count($columns) - count($pk) <= 1) { - continue; - } - foreach ($columns as $column) { - if (! in_array($column, $pk)) { - $selectTdForm .= '' - . '' . htmlspecialchars($column) . ''; - } - } - foreach ($columns as $column) { - if (! in_array($column, $pk)) { - $cnt++; - $extra .= "" . sprintf( - __('\'%1$s\' depends on:'), - htmlspecialchars($column) - ) - . "
    "; - $extra .= '
    ' - . $selectTdForm - . '


    '; - } - } - } - if ($extra == "") { - $headText = __( - "No Transitive dependencies possible as the table " - . "doesn't have any non primary key columns" - ); - $subText = ""; - $extra = "

    " . __("Table is already in Third normal form!") . "

    "; - } - return [ - 'legendText' => $legendText, - 'headText' => $headText, - 'subText' => $subText, - 'extra' => $extra, - ]; - } - - /** - * get html for options to normalize table - * - * @return string HTML - */ - public function getHtmlForNormalizeTable() - { - $htmlOutput = '
    ' - . Url::getHiddenInputs($GLOBALS['db'], $GLOBALS['table']) - . ''; - $htmlOutput .= '
    '; - $htmlOutput .= '' - . __('Improve table structure (Normalization):') . ''; - $htmlOutput .= '

    ' . __('Select up to what step you want to normalize') - . '

    '; - $choices = [ - '1nf' => __('First step of normalization (1NF)'), - '2nf' => __('Second step of normalization (1NF+2NF)'), - '3nf' => __('Third step of normalization (1NF+2NF+3NF)'), - ]; - - $htmlOutput .= Util::getRadioFields( - 'normalizeTo', - $choices, - '1nf', - true - ); - $htmlOutput .= '
    ' - . "" . __( - 'Hint: Please follow the procedure carefully in order ' - . 'to obtain correct normalization' - ) . "" - . '' - . '
    ' - . '
    ' - . ''; - - return $htmlOutput; - } - - /** - * find all the possible partial dependencies based on data in the table. - * - * @param string $table current table - * @param string $db current database - * - * @return string HTML containing the list of all the possible partial dependencies - */ - public function findPartialDependencies($table, $db) - { - $dependencyList = []; - $this->dbi->selectDb($db); - $columns = (array) $this->dbi->getColumnNames( - $db, - $table - ); - $columns = (array) Util::backquote($columns); - $totalRowsRes = $this->dbi->fetchResult( - 'SELECT COUNT(*) FROM (SELECT * FROM ' - . Util::backquote($table) . ' LIMIT 500) as dt;' - ); - $totalRows = $totalRowsRes[0]; - $primary = Index::getPrimary($table, $db); - $primarycols = $primary->getColumns(); - $pk = []; - foreach ($primarycols as $col) { - $pk[] = Util::backquote($col->getName()); - } - $partialKeys = $this->getAllCombinationPartialKeys($pk); - $distinctValCount = $this->findDistinctValuesCount( - array_unique( - array_merge($columns, $partialKeys) - ), - $table - ); - foreach ($columns as $column) { - if (! in_array($column, $pk)) { - foreach ($partialKeys as $partialKey) { - if ($partialKey - && $this->checkPartialDependency( - $partialKey, - $column, - $table, - $distinctValCount[$partialKey], - $distinctValCount[$column], - $totalRows - ) - ) { - $dependencyList[$partialKey][] = $column; - } - } - } - } - - $html = __( - 'This list is based on a subset of the table\'s data ' - . 'and is not necessarily accurate. ' - ) - . '
    '; - foreach ($dependencyList as $dependon => $colList) { - $html .= '' - . '' - . '' - . htmlspecialchars(str_replace('`', '', $dependon)) . ' -> ' - . '' - . htmlspecialchars(str_replace('`', '', implode(', ', $colList))) - . '' - . ''; - } - if (empty($dependencyList)) { - $html .= '

    ' - . __('No partial dependencies found!') . '

    '; - } - $html .= '
    '; - return $html; - } - - /** - * check whether a particular column is dependent on given subset of primary key - * - * @param string $partialKey the partial key, subset of primary key, - * each column in key supposed to be backquoted - * @param string $column backquoted column on whose dependency being checked - * @param string $table current table - * @param integer $pkCnt distinct value count for given partial key - * @param integer $colCnt distinct value count for given column - * @param integer $totalRows total distinct rows count of the table - * - * @return boolean TRUE if $column is dependent on $partialKey, False otherwise - */ - private function checkPartialDependency( - $partialKey, - $column, - $table, - $pkCnt, - $colCnt, - $totalRows - ) { - $query = 'SELECT ' - . 'COUNT(DISTINCT ' . $partialKey . ',' . $column . ') as pkColCnt ' - . 'FROM (SELECT * FROM ' . Util::backquote($table) - . ' LIMIT 500) as dt;'; - $res = $this->dbi->fetchResult($query, null, null); - $pkColCnt = $res[0]; - if ($pkCnt && $pkCnt == $colCnt && $colCnt == $pkColCnt) { - return true; - } - if ($totalRows && $totalRows == $pkCnt) { - return true; - } - return false; - } - - /** - * function to get distinct values count of all the column in the array $columns - * - * @param array $columns array of backquoted columns whose distinct values - * need to be counted. - * @param string $table table to which these columns belong - * - * @return array associative array containing the count - */ - private function findDistinctValuesCount(array $columns, $table) - { - $result = []; - $query = 'SELECT '; - foreach ($columns as $column) { - if ($column) { //each column is already backquoted - $query .= 'COUNT(DISTINCT ' . $column . ') as \'' - . $column . '_cnt\', '; - } - } - $query = trim($query, ', '); - $query .= ' FROM (SELECT * FROM ' . Util::backquote($table) - . ' LIMIT 500) as dt;'; - $res = $this->dbi->fetchResult($query, null, null); - foreach ($columns as $column) { - if ($column) { - $result[$column] = $res[0][$column . '_cnt'] ?? null; - } - } - return $result; - } - - /** - * find all the possible partial keys - * - * @param array $primaryKey array containing all the column present in primary key - * - * @return array containing all the possible partial keys(subset of primary key) - */ - private function getAllCombinationPartialKeys(array $primaryKey) - { - $results = ['']; - foreach ($primaryKey as $element) { - foreach ($results as $combination) { - $results[] = trim($element . ',' . $combination, ','); - } - } - array_pop($results); //remove key which consist of all primary key columns - return $results; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/OpenDocument.php b/srcs/phpmyadmin/libraries/classes/OpenDocument.php deleted file mode 100644 index 40ebe15..0000000 --- a/srcs/phpmyadmin/libraries/classes/OpenDocument.php +++ /dev/null @@ -1,179 +0,0 @@ -' - . '' - . '' - . 'phpMyAdmin ' . PMA_VERSION . '' - . 'phpMyAdmin ' . PMA_VERSION - . '' - . '' . strftime('%Y-%m-%dT%H:%M:%S') - . '' - . '' - . '', - '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '', - '' - . '' - . '' - . '' - . '' - . '' - . '', - ]; - - $name = [ - 'mimetype', - 'content.xml', - 'meta.xml', - 'styles.xml', - 'META-INF/manifest.xml', - ]; - - $zipExtension = new ZipExtension(); - return $zipExtension->createFile($data, $name); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Operations.php b/srcs/phpmyadmin/libraries/classes/Operations.php deleted file mode 100644 index 7cedd17..0000000 --- a/srcs/phpmyadmin/libraries/classes/Operations.php +++ /dev/null @@ -1,2263 +0,0 @@ -dbi = $dbi; - $this->relation = $relation; - } - - /** - * Get HTML output for database comment - * - * @param string $db database name - * - * @return string - */ - public function getHtmlForDatabaseComment($db) - { - $html_output = '
    ' - . '
    ' - . Url::getHiddenInputs($db) - . '
    ' - . ''; - if (Util::showIcons('ActionLinksMode')) { - $html_output .= Util::getImage('b_comment') . ' '; - } - $html_output .= __('Database comment'); - $html_output .= ''; - $html_output .= '' - . '
    '; - $html_output .= '
    ' - . '' - . '
    ' - . '
    ' - . '
    '; - - return $html_output; - } - - /** - * Get HTML output for rename database - * - * @param string $db database name - * @param string $db_collation dataset collation - * - * @return string - */ - public function getHtmlForRenameDatabase($db, $db_collation) - { - $html_output = '
    ' - . '
    '; - if ($db_collation !== null) { - $html_output .= '' . "\n"; - } - $html_output .= '' - . '' - . Url::getHiddenInputs($db) - . '
    ' - . ''; - - if (Util::showIcons('ActionLinksMode')) { - $html_output .= Util::getImage('b_edit') . ' '; - } - $html_output .= __('Rename database to') - . ''; - - $html_output .= ''; - $html_output .= '
    '; - - if ($GLOBALS['db_priv'] && $GLOBALS['table_priv'] - && $GLOBALS['col_priv'] && $GLOBALS['proc_priv'] - && $GLOBALS['is_reload_priv'] - ) { - $html_output .= ''; - } else { - $html_output .= ''; - } - - $html_output .= '
    '; - - $html_output .= '' - . '
    ' - . '
    ' - . '' - . '
    ' - . '
    ' - . '
    '; - - return $html_output; - } - - /** - * Get HTML for database drop link - * - * @param string $db database name - * - * @return string - */ - public function getHtmlForDropDatabaseLink($db) - { - $this_sql_query = 'DROP DATABASE ' . Util::backquote($db); - $this_url_params = [ - '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(Util::backquote($db)) - ), - 'db' => null, - ]; - - $html_output = '
    ' - . '
    '; - $html_output .= ''; - if (Util::showIcons('ActionLinksMode')) { - $html_output .= Util::getImage('b_deltbl') . ' '; - } - $html_output .= __('Remove database') - . ''; - $html_output .= '
      '; - $html_output .= $this->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 - * @param string $db_collation dataset collation - * - * @return string - */ - public function getHtmlForCopyDatabase($db, $db_collation) - { - $drop_clause = 'DROP TABLE / DROP VIEW'; - $choices = [ - 'structure' => __('Structure only'), - 'data' => __('Structure and data'), - 'dataonly' => __('Data only'), - ]; - - $pma_switch_to_new = isset($_SESSION['pma_switch_to_new']) && $_SESSION['pma_switch_to_new']; - - $html_output = '
    '; - $html_output .= '
    '; - - if ($db_collation !== null) { - $html_output .= '' . "\n"; - } - $html_output .= '' . "\n" - . Url::getHiddenInputs($db); - $html_output .= '
    ' - . ''; - - if (Util::showIcons('ActionLinksMode')) { - $html_output .= Util::getImage('b_edit') . ' '; - } - $html_output .= __('Copy database to') - . '' - . '
    ' - . 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 .= '
    '; - - if ($GLOBALS['db_priv'] && $GLOBALS['table_priv'] - && $GLOBALS['col_priv'] && $GLOBALS['proc_priv'] - && $GLOBALS['is_reload_priv'] - ) { - $html_output .= ''; - } else { - $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 $db_collation dataset collation - * - * @return string - */ - public function getHtmlForChangeDatabaseCharset($db, $db_collation) - { - $html_output = '
    ' - . '
    '; - if (Util::showIcons('ActionLinksMode')) { - $html_output .= Util::getImage('s_asci') . ' '; - } - $html_output .= '' . "\n" - . '' . "\n"; - $html_output .= '' . "\n"; - $html_output .= '
    ' - . '' - . '' - . '
    ' - . '' - . '' - . '' - . '
    ' - . '' . "\n" - . '
    ' . "\n" - . '
    ' . "\n"; - - 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 - */ - public function runProcedureAndFunctionDefinitions($db) - { - $procedure_names = $this->dbi->getProceduresOrFunctions($db, 'PROCEDURE'); - if ($procedure_names) { - foreach ($procedure_names as $procedure_name) { - $this->dbi->selectDb($db); - $tmp_query = $this->dbi->getDefinition( - $db, - 'PROCEDURE', - $procedure_name - ); - if ($tmp_query !== null) { - // collect for later display - $GLOBALS['sql_query'] .= "\n" . $tmp_query; - $this->dbi->selectDb($_POST['newname']); - $this->dbi->query($tmp_query); - } - } - } - - $function_names = $this->dbi->getProceduresOrFunctions($db, 'FUNCTION'); - if ($function_names) { - foreach ($function_names as $function_name) { - $this->dbi->selectDb($db); - $tmp_query = $this->dbi->getDefinition( - $db, - 'FUNCTION', - $function_name - ); - if ($tmp_query !== null) { - // collect for later display - $GLOBALS['sql_query'] .= "\n" . $tmp_query; - $this->dbi->selectDb($_POST['newname']); - $this->dbi->query($tmp_query); - } - } - } - } - - /** - * Create database before copy - * - * @return void - */ - public function createDbBeforeCopy() - { - $local_query = 'CREATE DATABASE IF NOT EXISTS ' - . Util::backquote($_POST['newname']); - if (isset($_POST['db_collation'])) { - $local_query .= ' DEFAULT' - . Util::getCharsetQueryPart($_POST['db_collation']); - } - $local_query .= ';'; - $GLOBALS['sql_query'] .= $local_query; - - // save the original db name because Tracker.php which - // may be called under $this->dbi->query() changes $GLOBALS['db'] - // for some statements, one of which being CREATE DATABASE - $original_db = $GLOBALS['db']; - $this->dbi->query($local_query); - $GLOBALS['db'] = $original_db; - - // Set the SQL mode to NO_AUTO_VALUE_ON_ZERO to prevent MySQL from creating - // export statements it cannot import - $sql_set_mode = "SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO'"; - $this->dbi->query($sql_set_mode); - - // rebuild the database list because Table::moveCopy - // checks in this list if the target db exists - $GLOBALS['dblist']->databases->build(); - } - - /** - * 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 ExportSql $export_sql_plugin export plugin instance - * @param string $db database name - * - * @return array - */ - public function getViewsAndCreateSqlViewStandIn( - array $tables_full, - $export_sql_plugin, - $db - ) { - $views = []; - 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 ($this->dbi->getTable($db, (string) $each_table)->isView()) { - // If view exists, and 'add drop view' is selected: Drop it! - if ($_POST['what'] != 'nocopy' - && isset($_POST['drop_if_exists']) - && $_POST['drop_if_exists'] == 'true' - ) { - $drop_query = 'DROP VIEW IF EXISTS ' - . Util::backquote($_POST['newname']) . '.' - . Util::backquote($each_table); - $this->dbi->query($drop_query); - - $GLOBALS['sql_query'] .= "\n" . $drop_query . ';'; - } - - $views[] = $each_table; - // Create stand-in definition to resolve view dependencies - $sql_view_standin = $export_sql_plugin->getTableDefStandIn( - $db, - $each_table, - "\n" - ); - $this->dbi->selectDb($_POST['newname']); - $this->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 boolean $move whether database name is empty or not - * @param string $db database name - * - * @return array SQL queries for the constraints - */ - public function copyTables(array $tables_full, $move, $db) - { - $sqlContraints = []; - foreach ($tables_full as $each_table => $tmp) { - // skip the views; we have created stand-in definitions - if ($this->dbi->getTable($db, (string) $each_table)->isView()) { - continue; - } - - // value of $what for this table only - $this_what = $_POST['what']; - - // do not copy the data from a Merge table - // note: on the calling FORM, 'data' means 'structure and data' - if ($this->dbi->getTable($db, (string) $each_table)->isMerge()) { - 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 = $this->dbi->getTriggers($db, (string) $each_table, ''); - - if (! Table::moveCopy( - $db, - $each_table, - $_POST['newname'], - $each_table, - (isset($this_what) ? $this_what : 'data'), - $move, - 'db_copy' - )) { - $GLOBALS['_error'] = true; - break; - } - // apply the triggers to the destination db+table - if ($triggers) { - $this->dbi->selectDb($_POST['newname']); - foreach ($triggers as $trigger) { - $this->dbi->query($trigger['create']); - $GLOBALS['sql_query'] .= "\n" . $trigger['create'] . ';'; - } - } - - // this does not apply to a rename operation - if (isset($_POST['add_constraints']) - && ! empty($GLOBALS['sql_constraints_query']) - ) { - $sqlContraints[] = $GLOBALS['sql_constraints_query']; - unset($GLOBALS['sql_constraints_query']); - } - } - } - return $sqlContraints; - } - - /** - * 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 - */ - public function runEventDefinitionsForDb($db) - { - $event_names = $this->dbi->fetchResult( - 'SELECT EVENT_NAME FROM information_schema.EVENTS WHERE EVENT_SCHEMA= \'' - . $this->dbi->escapeString($db) . '\';' - ); - if ($event_names) { - foreach ($event_names as $event_name) { - $this->dbi->selectDb($db); - $tmp_query = $this->dbi->getDefinition($db, 'EVENT', $event_name); - // collect for later display - $GLOBALS['sql_query'] .= "\n" . $tmp_query; - $this->dbi->selectDb($_POST['newname']); - $this->dbi->query($tmp_query); - } - } - } - - /** - * Handle the views, return the boolean value whether table rename/copy or not - * - * @param array $views views as an array - * @param boolean $move whether database name is empty or not - * @param string $db database name - * - * @return void - */ - public function handleTheViews(array $views, $move, $db) - { - // temporarily force to add DROP IF EXIST to CREATE VIEW query, - // to remove stand-in VIEW that was created earlier - // ( $_POST['drop_if_exists'] is used in moveCopy() ) - if (isset($_POST['drop_if_exists'])) { - $temp_drop_if_exists = $_POST['drop_if_exists']; - } - - $_POST['drop_if_exists'] = 'true'; - foreach ($views as $view) { - $copying_succeeded = Table::moveCopy( - $db, - $view, - $_POST['newname'], - $view, - 'structure', - $move, - 'db_copy' - ); - if (! $copying_succeeded) { - $GLOBALS['_error'] = true; - break; - } - } - unset($_POST['drop_if_exists']); - - if (isset($temp_drop_if_exists)) { - // restore previous value - $_POST['drop_if_exists'] = $temp_drop_if_exists; - } - } - - /** - * Adjust the privileges after Renaming the db - * - * @param string $oldDb Database name before renaming - * @param string $newname New Database name requested - * - * @return void - */ - public function adjustPrivilegesMoveDb($oldDb, $newname) - { - if ($GLOBALS['db_priv'] && $GLOBALS['table_priv'] - && $GLOBALS['col_priv'] && $GLOBALS['proc_priv'] - && $GLOBALS['is_reload_priv'] - ) { - $this->dbi->selectDb('mysql'); - $newname = str_replace("_", "\_", $newname); - $oldDb = str_replace("_", "\_", $oldDb); - - // For Db specific privileges - $query_db_specific = 'UPDATE ' . Util::backquote('db') - . 'SET Db = \'' . $this->dbi->escapeString($newname) - . '\' where Db = \'' . $this->dbi->escapeString($oldDb) . '\';'; - $this->dbi->query($query_db_specific); - - // For table specific privileges - $query_table_specific = 'UPDATE ' . Util::backquote('tables_priv') - . 'SET Db = \'' . $this->dbi->escapeString($newname) - . '\' where Db = \'' . $this->dbi->escapeString($oldDb) . '\';'; - $this->dbi->query($query_table_specific); - - // For column specific privileges - $query_col_specific = 'UPDATE ' . Util::backquote('columns_priv') - . 'SET Db = \'' . $this->dbi->escapeString($newname) - . '\' where Db = \'' . $this->dbi->escapeString($oldDb) . '\';'; - $this->dbi->query($query_col_specific); - - // For procedures specific privileges - $query_proc_specific = 'UPDATE ' . Util::backquote('procs_priv') - . 'SET Db = \'' . $this->dbi->escapeString($newname) - . '\' where Db = \'' . $this->dbi->escapeString($oldDb) . '\';'; - $this->dbi->query($query_proc_specific); - - // Finally FLUSH the new privileges - $flush_query = "FLUSH PRIVILEGES;"; - $this->dbi->query($flush_query); - } - } - - /** - * Adjust the privileges after Copying the db - * - * @param string $oldDb Database name before copying - * @param string $newname New Database name requested - * - * @return void - */ - public function adjustPrivilegesCopyDb($oldDb, $newname) - { - if ($GLOBALS['db_priv'] && $GLOBALS['table_priv'] - && $GLOBALS['col_priv'] && $GLOBALS['proc_priv'] - && $GLOBALS['is_reload_priv'] - ) { - $this->dbi->selectDb('mysql'); - $newname = str_replace("_", "\_", $newname); - $oldDb = str_replace("_", "\_", $oldDb); - - $query_db_specific_old = 'SELECT * FROM ' - . Util::backquote('db') . ' WHERE ' - . 'Db = "' . $oldDb . '";'; - - $old_privs_db = $this->dbi->fetchResult($query_db_specific_old, 0); - - foreach ($old_privs_db as $old_priv) { - $newDb_db_privs_query = 'INSERT INTO ' . Util::backquote('db') - . ' VALUES("' . $old_priv[0] . '", "' . $newname . '"'; - for ($i = 2; $i < count($old_priv); $i++) { - $newDb_db_privs_query .= ', "' . $old_priv[$i] . '"'; - } - $newDb_db_privs_query .= ')'; - - $this->dbi->query($newDb_db_privs_query); - } - - // For Table Specific privileges - $query_table_specific_old = 'SELECT * FROM ' - . Util::backquote('tables_priv') . ' WHERE ' - . 'Db = "' . $oldDb . '";'; - - $old_privs_table = $this->dbi->fetchResult( - $query_table_specific_old, - 0 - ); - - foreach ($old_privs_table as $old_priv) { - $newDb_table_privs_query = 'INSERT INTO ' . Util::backquote( - 'tables_priv' - ) . ' VALUES("' . $old_priv[0] . '", "' . $newname . '", "' - . $old_priv[2] . '", "' . $old_priv[3] . '", "' . $old_priv[4] - . '", "' . $old_priv[5] . '", "' . $old_priv[6] . '", "' - . $old_priv[7] . '");'; - - $this->dbi->query($newDb_table_privs_query); - } - - // For Column Specific privileges - $query_col_specific_old = 'SELECT * FROM ' - . Util::backquote('columns_priv') . ' WHERE ' - . 'Db = "' . $oldDb . '";'; - - $old_privs_col = $this->dbi->fetchResult( - $query_col_specific_old, - 0 - ); - - foreach ($old_privs_col as $old_priv) { - $newDb_col_privs_query = 'INSERT INTO ' . Util::backquote( - 'columns_priv' - ) . ' VALUES("' . $old_priv[0] . '", "' . $newname . '", "' - . $old_priv[2] . '", "' . $old_priv[3] . '", "' . $old_priv[4] - . '", "' . $old_priv[5] . '", "' . $old_priv[6] . '");'; - - $this->dbi->query($newDb_col_privs_query); - } - - // For Procedure Specific privileges - $query_proc_specific_old = 'SELECT * FROM ' - . Util::backquote('procs_priv') . ' WHERE ' - . 'Db = "' . $oldDb . '";'; - - $old_privs_proc = $this->dbi->fetchResult( - $query_proc_specific_old, - 0 - ); - - foreach ($old_privs_proc as $old_priv) { - $newDb_proc_privs_query = 'INSERT INTO ' . Util::backquote( - 'procs_priv' - ) . ' VALUES("' . $old_priv[0] . '", "' . $newname . '", "' - . $old_priv[2] . '", "' . $old_priv[3] . '", "' . $old_priv[4] - . '", "' . $old_priv[5] . '", "' . $old_priv[6] . '", "' - . $old_priv[7] . '");'; - - $this->dbi->query($newDb_proc_privs_query); - } - - // Finally FLUSH the new privileges - $flush_query = "FLUSH PRIVILEGES;"; - $this->dbi->query($flush_query); - } - } - - /** - * Create all accumulated constraints - * - * @param array $sqlConstratints array of sql constraints for the database - * - * @return void - */ - public function createAllAccumulatedConstraints(array $sqlConstratints) - { - $this->dbi->selectDb($_POST['newname']); - foreach ($sqlConstratints as $one_query) { - $this->dbi->query($one_query); - // and prepare to display them - $GLOBALS['sql_query'] .= "\n" . $one_query; - } - } - - /** - * 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 - */ - public function duplicateBookmarks($_error, $db) - { - if (! $_error && $db != $_POST['newname']) { - $get_fields = [ - 'user', - 'label', - 'query', - ]; - $where_fields = ['dbase' => $db]; - $new_fields = ['dbase' => $_POST['newname']]; - 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 - */ - public function getHtmlForOrderTheTable(array $columns) - { - $html_output = '
    '; - $html_output .= '
    '; - $html_output .= Url::getHiddenInputs( - $GLOBALS['db'], - $GLOBALS['table'] - ); - $html_output .= '
    ' - . '' . __('Alter table order by') . '' - . ' ' . __('(singly)') . ' ' - . '
    ' - . '' - . '' - . '' - . '' - . '
    ' - . '
    ' - . '' - . '' - . '
    ' - . '
    ' - . '
    '; - - return $html_output; - } - - /** - * Get the HTML snippet for move table - * - * @return string - */ - public function getHtmlForMoveTable() - { - $html_output = '
    '; - $html_output .= '
    ' - . Url::getHiddenInputs($GLOBALS['db'], $GLOBALS['table']); - - $html_output .= '' - . '' - . '
    '; - - $html_output .= '' . __('Move table to (database.table)') - . ''; - - if (count($GLOBALS['dblist']->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 .= '' - . '
    '; - - if ($GLOBALS['table_priv'] && $GLOBALS['col_priv'] - && $GLOBALS['is_reload_priv'] - ) { - $html_output .= ''; - } else { - $html_output .= ''; - } - $html_output .= '
    '; - - $html_output .= '
    ' - . '' - . '
    ' - . '
    ' - . '
    '; - - return $html_output; - } - - /** - * Get the HTML div for Table option - * - * @param Table $pma_table Table object - * @param string $comment Comment - * @param string $tbl_collation table collation - * @param string $tbl_storage_engine table storage engine - * @param string $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 string $checksum the checksum - * - * @return string - */ - public function getTableOptionDiv( - $pma_table, - $comment, - $tbl_collation, - $tbl_storage_engine, - $pack_keys, - $auto_increment, - $delay_key_write, - $transactional, - $page_checksum, - $checksum - ) { - $html_output = '
    '; - $html_output .= '
    getTableOptionFieldset( - $pma_table, - $comment, - $tbl_collation, - $tbl_storage_engine, - $pack_keys, - $delay_key_write, - $auto_increment, - $transactional, - $page_checksum, - $checksum - ); - - $html_output .= '
    ' - . '' - . '' - . '
    ' - . '
    ' - . '
    '; - - return $html_output; - } - - /** - * Get HTML for the rename table part of table options - * - * @return string - */ - private function getHtmlForRenameTable() - { - $html_output = '' . __('Rename table to') . '' - . '' - . '' - . '' - . ''; - - if ($GLOBALS['table_priv'] && $GLOBALS['col_priv'] - && $GLOBALS['is_reload_priv'] - ) { - $html_output .= ''; - } else { - $html_output .= ''; - } - $html_output .= ''; - - $html_output .= ''; - return $html_output; - } - - /** - * Get HTML for the table comments part of table options - * - * @param string $current_value of the table comments - * - * @return string - */ - private function getHtmlForTableComments($current_value) - { - $commentLength = $this->dbi->getVersion() >= 50503 ? 2048 : 60; - return '' . __('Table comments') . '' - . '' - . '' - . '' - . ''; - } - - /** - * Get HTML for the PACK KEYS part of table options - * - * @param string $current_value of the pack keys option - * - * @return string - */ - private function getHtmlForPackKeys($current_value) - { - $html_output = '' - . '' - . '' . "\n"; - $html_output .= '' . "\n"; - - $charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); - $collations = Charsets::getCollations($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); - /** @var Charset $charset */ - foreach ($charsets as $charset) { - $html_output .= '' . "\n"; - /** @var Collation $collation */ - foreach ($collations[$charset->getName()] as $collation) { - $html_output .= '' . "\n"; - } - $html_output .= '' . "\n"; - } - $html_output .= '' . "\n"; - $html_output .= '' - . ''; - - // Change all Column collations - $html_output .= '' - . '' - . '' - . ''; - - if ($pma_table->isEngine(['MYISAM', 'ARIA', 'ISAM'])) { - $html_output .= $this->getHtmlForPackKeys($pack_keys); - } // end if (MYISAM|ISAM) - - if ($pma_table->isEngine(['MYISAM', 'ARIA'])) { - $html_output .= $this->getHtmlForTableRow( - 'new_checksum', - 'CHECKSUM', - $checksum - ); - - $html_output .= $this->getHtmlForTableRow( - 'new_delay_key_write', - 'DELAY_KEY_WRITE', - $delay_key_write - ); - } // end if (MYISAM) - - if ($pma_table->isEngine('ARIA')) { - $html_output .= $this->getHtmlForTableRow( - 'new_transactional', - 'TRANSACTIONAL', - $transactional - ); - - $html_output .= $this->getHtmlForTableRow( - 'new_page_checksum', - 'PAGE_CHECKSUM', - $page_checksum - ); - } // end if (ARIA) - - if (strlen($auto_increment) > 0 - && $pma_table->isEngine(['MYISAM', 'ARIA', 'INNODB', 'PBXT', 'ROCKSDB']) - ) { - $html_output .= '' - . '' - . '' - . ' '; - } // end if (MYISAM|INNODB) - - $possible_row_formats = $this->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 - = mb_strtoupper($GLOBALS['showtable']['Row_format']); - $html_output .= '' - . '' - . ''; - $html_output .= Util::getDropdown( - 'new_row_format', - $possible_row_formats[$tbl_storage_engine], - $current_row_format, - 'new_row_format' - ); - $html_output .= ''; - } - $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 - */ - private function getHtmlForTableRow($attribute, $label, $val) - { - return '' - . '' - . '' - . '' - . '' - . '' - . '' - . ''; - } - - /** - * Get array of possible row formats - * - * @return array - */ - private function 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 = [ - 'ARCHIVE' => [ - 'COMPRESSED' => 'COMPRESSED', - ], - 'ARIA' => [ - 'FIXED' => 'FIXED', - 'DYNAMIC' => 'DYNAMIC', - 'PAGE' => 'PAGE', - ], - 'MARIA' => [ - 'FIXED' => 'FIXED', - 'DYNAMIC' => 'DYNAMIC', - 'PAGE' => 'PAGE', - ], - 'MYISAM' => [ - 'FIXED' => 'FIXED', - 'DYNAMIC' => 'DYNAMIC', - ], - 'PBXT' => [ - 'FIXED' => 'FIXED', - 'DYNAMIC' => 'DYNAMIC', - ], - 'INNODB' => [ - 'COMPACT' => 'COMPACT', - 'REDUNDANT' => 'REDUNDANT', - ], - ]; - - /** @var Innodb $innodbEnginePlugin */ - $innodbEnginePlugin = StorageEngine::getEngine('Innodb'); - $innodbPluginVersion = $innodbEnginePlugin->getInnodbPluginVersion(); - if (! empty($innodbPluginVersion)) { - $innodb_file_format = $innodbEnginePlugin->getInnodbFileFormat(); - } else { - $innodb_file_format = ''; - } - /** - * Newer MySQL/MariaDB always return empty a.k.a '' on $innodb_file_format otherwise - * old versions of MySQL/MariaDB must be returning something or not empty. - * This patch is to support newer MySQL/MariaDB while also for backward compatibilities. - */ - if (( ('Barracuda' == $innodb_file_format) || ($innodb_file_format == '') ) - && $innodbEnginePlugin->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 - */ - public function getHtmlForCopytable() - { - $html_output = '
    '; - $html_output .= '
    ' - . Url::getHiddenInputs($GLOBALS['db'], $GLOBALS['table']) - . ''; - - $html_output .= '
    '; - $html_output .= '' - . __('Copy table to (database.table)') . ''; - - if (count($GLOBALS['dblist']->databases) > $GLOBALS['cfg']['MaxDbList']) { - $html_output .= ''; - } else { - $html_output .= ''; - } - $html_output .= ' . '; - $html_output .= '
    '; - - $choices = [ - 'structure' => __('Structure only'), - 'data' => __('Structure and data'), - 'dataonly' => __('Data only'), - ]; - - $html_output .= Util::getRadioFields( - 'what', - $choices, - 'data', - true - ); - $html_output .= '
    '; - - $html_output .= '' - . '
    ' - . '' - . '
    '; - - // display "Add constraints" choice only if there are - // foreign keys - if ($this->relation->getForeigners($GLOBALS['db'], $GLOBALS['table'], '', 'foreign')) { - $html_output .= ''; - $html_output .= '
    '; - } // endif - - $html_output .= '
    '; - - if ($GLOBALS['table_priv'] && $GLOBALS['col_priv'] - && $GLOBALS['is_reload_priv'] - ) { - $html_output .= ''; - } else { - $html_output .= ''; - } - $html_output .= '
    '; - - $pma_switch_to_new = isset($_SESSION['pma_switch_to_new']) && $_SESSION['pma_switch_to_new']; - - $html_output .= ''; - $html_output .= '' - . '
    '; - - $html_output .= '
    ' - . '' - . '
    ' - . '
    ' - . '
    '; - - return $html_output; - } - - /** - * Get HTML snippet for table maintenance - * - * @param Table $pma_table Table object - * @param array $url_params array of URL parameters - * - * @return string - */ - public function getHtmlForTableMaintenance($pma_table, array $url_params) - { - $html_output = '
    '; - $html_output .= '
    ' - . '' . __('Table maintenance') . ''; - $html_output .= '
      '; - - // Note: BERKELEY (BDB) is no longer supported, starting with MySQL 5.1 - $html_output .= $this->getListofMaintainActionLink($pma_table, $url_params); - - $html_output .= '
    ' - . '
    ' - . '
    '; - - return $html_output; - } - - /** - * Get HTML 'li' having a link of maintain action - * - * @param Table $pma_table Table object - * @param array $url_params Array of URL parameters - * - * @return string - */ - private function getListofMaintainActionLink($pma_table, array $url_params) - { - $html_output = ''; - - // analyze table - if ($pma_table->isEngine(['MYISAM', 'ARIA', 'INNODB', 'BERKELEYDB', 'TOKUDB'])) { - $params = [ - 'sql_query' => 'ANALYZE TABLE ' - . Util::backquote($GLOBALS['table']), - 'table_maintenance' => 'Go', - ]; - $html_output .= $this->getMaintainActionlink( - __('Analyze table'), - $params, - $url_params, - 'ANALYZE_TABLE' - ); - } - - // check table - if ($pma_table->isEngine(['MYISAM', 'ARIA', 'INNODB', 'TOKUDB'])) { - $params = [ - 'sql_query' => 'CHECK TABLE ' - . Util::backquote($GLOBALS['table']), - 'table_maintenance' => 'Go', - ]; - $html_output .= $this->getMaintainActionlink( - __('Check table'), - $params, - $url_params, - 'CHECK_TABLE' - ); - } - - // checksum table - $params = [ - 'sql_query' => 'CHECKSUM TABLE ' - . Util::backquote($GLOBALS['table']), - 'table_maintenance' => 'Go', - ]; - $html_output .= $this->getMaintainActionlink( - __('Checksum table'), - $params, - $url_params, - 'CHECKSUM_TABLE' - ); - - // defragment table - if ($pma_table->isEngine(['INNODB'])) { - $params = [ - 'sql_query' => 'ALTER TABLE ' - . Util::backquote($GLOBALS['table']) - . ' ENGINE = InnoDB;', - ]; - $html_output .= $this->getMaintainActionlink( - __('Defragment table'), - $params, - $url_params, - 'InnoDB_File_Defragmenting' - ); - } - - // flush table - $params = [ - 'sql_query' => 'FLUSH TABLE ' - . Util::backquote($GLOBALS['table']), - 'message_to_show' => sprintf( - __('Table %s has been flushed.'), - htmlspecialchars($GLOBALS['table']) - ), - 'reload' => 1, - ]; - $html_output .= $this->getMaintainActionlink( - __('Flush the table (FLUSH)'), - $params, - $url_params, - 'FLUSH' - ); - - // optimize table - if ($pma_table->isEngine(['MYISAM', 'ARIA', 'INNODB', 'BERKELEYDB', 'TOKUDB'])) { - $params = [ - 'sql_query' => 'OPTIMIZE TABLE ' - . Util::backquote($GLOBALS['table']), - 'table_maintenance' => 'Go', - ]; - $html_output .= $this->getMaintainActionlink( - __('Optimize table'), - $params, - $url_params, - 'OPTIMIZE_TABLE' - ); - } - - // repair table - if ($pma_table->isEngine(['MYISAM', 'ARIA'])) { - $params = [ - 'sql_query' => 'REPAIR TABLE ' - . Util::backquote($GLOBALS['table']), - 'table_maintenance' => 'Go', - ]; - $html_output .= $this->getMaintainActionlink( - __('Repair table'), - $params, - $url_params, - 'REPAIR_TABLE' - ); - } - - return $html_output; - } - - /** - * Get maintain action HTML link - * - * @param string $action_message action message - * @param array $params url parameters array - * @param array $url_params additional url parameters - * @param string $link contains name of page/anchor that is being linked - * - * @return string - */ - private function getMaintainActionlink($action_message, array $params, array $url_params, $link) - { - return '
  • ' - . Util::linkOrButton( - 'sql.php' . Url::getCommon(array_merge($url_params, $params)), - $action_message, - ['class' => 'maintain_action ajax'] - ) - . Util::showMySQLDocu($link) - . '
  • '; - } - - /** - * Get HTML for Delete data or table (truncate table, drop table) - * - * @param array $truncate_table_url_params url parameter array for truncate table - * @param array $dropTableUrlParams url parameter array for drop table - * - * @return string - */ - public function getHtmlForDeleteDataOrTable( - array $truncate_table_url_params, - array $dropTableUrlParams - ) { - $html_output = '
    ' - . '
    ' - . '' . __('Delete data or table') . ''; - - $html_output .= '
      '; - - if (! empty($truncate_table_url_params)) { - $html_output .= $this->getDeleteDataOrTablelink( - $truncate_table_url_params, - 'TRUNCATE_TABLE', - __('Empty the table (TRUNCATE)'), - 'truncate_tbl_anchor' - ); - } - if (! empty($dropTableUrlParams)) { - $html_output .= $this->getDeleteDataOrTablelink( - $dropTableUrlParams, - '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 $htmlId id of the link - * - * @return string html output - */ - public function getDeleteDataOrTablelink(array $url_params, $syntax, $link, $htmlId) - { - return '
  • ' . Util::linkOrButton( - 'sql.php' . Url::getCommon($url_params), - $link, - [ - 'id' => $htmlId, - 'class' => 'ajax', - ] - ) - . Util::showMySQLDocu($syntax) - . '
  • '; - } - - /** - * Get HTML snippet for partition maintenance - * - * @param array $partition_names array of partition names for a specific db/table - * @param array $url_params url parameters - * - * @return string - */ - public function getHtmlForPartitionMaintenance(array $partition_names, array $url_params) - { - $choices = [ - 'ANALYZE' => __('Analyze'), - 'CHECK' => __('Check'), - 'OPTIMIZE' => __('Optimize'), - 'REBUILD' => __('Rebuild'), - 'REPAIR' => __('Repair'), - 'TRUNCATE' => __('Truncate'), - ]; - - $partition_method = Partition::getPartitionMethod( - $GLOBALS['db'], - $GLOBALS['table'] - ); - // add COALESCE or DROP option to choices array depeding on Partition method - if ($partition_method == 'RANGE' - || $partition_method == 'RANGE COLUMNS' - || $partition_method == 'LIST' - || $partition_method == 'LIST COLUMNS' - ) { - $choices['DROP'] = __('Drop'); - } else { - $choices['COALESCE'] = __('Coalesce'); - } - - $html_output = '
    ' - . '
    ' - . Url::getHiddenInputs($GLOBALS['db'], $GLOBALS['table']) - . '
    ' - . '' - . __('Partition maintenance') - . Util::showMySQLDocu('partitioning_maintenance') - . ''; - - $html_select = '' . "\n"; - $html_output .= sprintf(__('Partition %s'), $html_select); - - $html_output .= '
    '; - $html_output .= Util::getRadioFields( - 'partition_operation', - $choices, - 'ANALYZE', - false, - true, - 'floatleft' - ); - $this_url_params = array_merge( - $url_params, - [ - 'sql_query' => 'ALTER TABLE ' - . Util::backquote($GLOBALS['table']) - . ' REMOVE PARTITIONING;', - ] - ); - $html_output .= '

    '; - - $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 - */ - public function getHtmlForReferentialIntegrityCheck(array $foreign, array $url_params) - { - $html_output = '
    ' - . '
    ' - . '' . __('Check referential integrity:') . ''; - - $html_output .= '
      '; - - foreach ($foreign as $master => $arr) { - $join_query = 'SELECT ' - . Util::backquote($GLOBALS['table']) . '.*' - . ' FROM ' . Util::backquote($GLOBALS['table']) - . ' LEFT JOIN ' - . Util::backquote($arr['foreign_db']) - . '.' - . Util::backquote($arr['foreign_table']); - if ($arr['foreign_table'] == $GLOBALS['table']) { - $foreign_table = $GLOBALS['table'] . '1'; - $join_query .= ' AS ' . Util::backquote($foreign_table); - } else { - $foreign_table = $arr['foreign_table']; - } - $join_query .= ' ON ' - . Util::backquote($GLOBALS['table']) . '.' - . Util::backquote($master) - . ' = ' - . Util::backquote($arr['foreign_db']) - . '.' - . Util::backquote($foreign_table) . '.' - . Util::backquote($arr['foreign_field']) - . ' WHERE ' - . Util::backquote($arr['foreign_db']) - . '.' - . Util::backquote($foreign_table) . '.' - . Util::backquote($arr['foreign_field']) - . ' IS NULL AND ' - . Util::backquote($GLOBALS['table']) . '.' - . Util::backquote($master) - . ' IS NOT NULL'; - $this_url_params = array_merge( - $url_params, - [ - 'sql_query' => $join_query, - 'sql_signature' => Core::signSqlQuery($join_query), - ] - ); - - $html_output .= '
    • ' - . '' - . $master . ' -> ' . $arr['foreign_db'] . '.' - . $arr['foreign_table'] . '.' . $arr['foreign_field'] - . '
    • ' . "\n"; - } // foreach $foreign - $html_output .= '
    '; - - return $html_output; - } - - /** - * Reorder table based on request params - * - * @return array SQL query and result - */ - public function getQueryAndResultForReorderingTable() - { - $sql_query = 'ALTER TABLE ' - . Util::backquote($GLOBALS['table']) - . ' ORDER BY ' - . Util::backquote(urldecode($_POST['order_field'])); - if (isset($_POST['order_order']) - && $_POST['order_order'] === 'desc' - ) { - $sql_query .= ' DESC'; - } else { - $sql_query .= ' ASC'; - } - $sql_query .= ';'; - $result = $this->dbi->query($sql_query); - - return [ - $sql_query, - $result, - ]; - } - - /** - * Get table alters array - * - * @param Table $pma_table The Table object - * @param string $pack_keys pack keys - * @param string $checksum value of checksum - * @param string $page_checksum value of page checksum - * @param string $delay_key_write delay key write - * @param string $row_format row format - * @param string $newTblStorageEngine table storage engine - * @param string $transactional value of transactional - * @param string $tbl_collation collation of the table - * - * @return array - */ - public function getTableAltersArray( - $pma_table, - $pack_keys, - $checksum, - $page_checksum, - $delay_key_write, - $row_format, - $newTblStorageEngine, - $transactional, - $tbl_collation - ) { - global $auto_increment; - - $table_alters = []; - - if (isset($_POST['comment']) - && urldecode($_POST['prev_comment']) !== $_POST['comment'] - ) { - $table_alters[] = 'COMMENT = \'' - . $this->dbi->escapeString($_POST['comment']) . '\''; - } - - if (! empty($newTblStorageEngine) - && mb_strtolower($newTblStorageEngine) !== mb_strtolower($GLOBALS['tbl_storage_engine']) - ) { - $table_alters[] = 'ENGINE = ' . $newTblStorageEngine; - } - if (! empty($_POST['tbl_collation']) - && $_POST['tbl_collation'] !== $tbl_collation - ) { - $table_alters[] = 'DEFAULT ' - . Util::getCharsetQueryPart($_POST['tbl_collation']); - } - - if ($pma_table->isEngine(['MYISAM', 'ARIA', 'ISAM']) - && isset($_POST['new_pack_keys']) - && $_POST['new_pack_keys'] != (string) $pack_keys - ) { - $table_alters[] = 'pack_keys = ' . $_POST['new_pack_keys']; - } - - $_POST['new_checksum'] = empty($_POST['new_checksum']) ? '0' : '1'; - if ($pma_table->isEngine(['MYISAM', 'ARIA']) - && $_POST['new_checksum'] !== $checksum - ) { - $table_alters[] = 'checksum = ' . $_POST['new_checksum']; - } - - $_POST['new_transactional'] - = empty($_POST['new_transactional']) ? '0' : '1'; - if ($pma_table->isEngine('ARIA') - && $_POST['new_transactional'] !== $transactional - ) { - $table_alters[] = 'TRANSACTIONAL = ' . $_POST['new_transactional']; - } - - $_POST['new_page_checksum'] - = empty($_POST['new_page_checksum']) ? '0' : '1'; - if ($pma_table->isEngine('ARIA') - && $_POST['new_page_checksum'] !== $page_checksum - ) { - $table_alters[] = 'PAGE_CHECKSUM = ' . $_POST['new_page_checksum']; - } - - $_POST['new_delay_key_write'] - = empty($_POST['new_delay_key_write']) ? '0' : '1'; - if ($pma_table->isEngine(['MYISAM', 'ARIA']) - && $_POST['new_delay_key_write'] !== $delay_key_write - ) { - $table_alters[] = 'delay_key_write = ' . $_POST['new_delay_key_write']; - } - - if ($pma_table->isEngine(['MYISAM', 'ARIA', 'INNODB', 'PBXT', 'ROCKSDB']) - && ! empty($_POST['new_auto_increment']) - && (! isset($auto_increment) - || $_POST['new_auto_increment'] !== $auto_increment) - ) { - $table_alters[] = 'auto_increment = ' - . $this->dbi->escapeString($_POST['new_auto_increment']); - } - - if (! empty($_POST['new_row_format'])) { - $newRowFormat = $_POST['new_row_format']; - $newRowFormatLower = mb_strtolower($newRowFormat); - if ($pma_table->isEngine(['MYISAM', 'ARIA', 'INNODB', 'PBXT']) - && (strlen($row_format) === 0 - || $newRowFormatLower !== mb_strtolower($row_format)) - ) { - $table_alters[] = 'ROW_FORMAT = ' - . $this->dbi->escapeString($newRowFormat); - } - } - - return $table_alters; - } - - /** - * Get warning messages array - * - * @return array - */ - public function getWarningMessagesArray() - { - $warning_messages = []; - foreach ($this->dbi->getWarnings() as $warning) { - // In MariaDB 5.1.44, when altering a table from Maria to MyISAM - // and if TRANSACTIONAL was set, the system reports an error; - // I discussed with a Maria developer and he agrees that this - // should not be reported with a Level of Error, so here - // I just ignore it. But there are other 1478 messages - // that it's better to show. - if (! (isset($_POST['new_tbl_storage_engine']) - && $_POST['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 - */ - public function getQueryAndResultForPartition() - { - $sql_query = 'ALTER TABLE ' - . Util::backquote($GLOBALS['table']) . ' ' - . $_POST['partition_operation'] - . ' PARTITION '; - - if ($_POST['partition_operation'] == 'COALESCE') { - $sql_query .= count($_POST['partition_name']); - } else { - $sql_query .= implode(', ', $_POST['partition_name']) . ';'; - } - - $result = $this->dbi->query($sql_query); - - return [ - $sql_query, - $result, - ]; - } - - /** - * Adjust the privileges after renaming/moving a table - * - * @param string $oldDb Database name before table renaming/moving table - * @param string $oldTable Table name before table renaming/moving table - * @param string $newDb Database name after table renaming/ moving table - * @param string $newTable Table name after table renaming/moving table - * - * @return void - */ - public function adjustPrivilegesRenameOrMoveTable($oldDb, $oldTable, $newDb, $newTable) - { - if ($GLOBALS['table_priv'] && $GLOBALS['col_priv'] - && $GLOBALS['is_reload_priv'] - ) { - $this->dbi->selectDb('mysql'); - - // For table specific privileges - $query_table_specific = 'UPDATE ' . Util::backquote('tables_priv') - . 'SET Db = \'' . $this->dbi->escapeString($newDb) . '\', Table_name = \'' . $this->dbi->escapeString($newTable) - . '\' where Db = \'' . $this->dbi->escapeString($oldDb) . '\' AND Table_name = \'' . $this->dbi->escapeString($oldTable) - . '\';'; - $this->dbi->query($query_table_specific); - - // For column specific privileges - $query_col_specific = 'UPDATE ' . Util::backquote('columns_priv') - . 'SET Db = \'' . $this->dbi->escapeString($newDb) . '\', Table_name = \'' . $this->dbi->escapeString($newTable) - . '\' where Db = \'' . $this->dbi->escapeString($oldDb) . '\' AND Table_name = \'' . $this->dbi->escapeString($oldTable) - . '\';'; - $this->dbi->query($query_col_specific); - - // Finally FLUSH the new privileges - $flush_query = "FLUSH PRIVILEGES;"; - $this->dbi->query($flush_query); - } - } - - /** - * Adjust the privileges after copying a table - * - * @param string $oldDb Database name before table copying - * @param string $oldTable Table name before table copying - * @param string $newDb Database name after table copying - * @param string $newTable Table name after table copying - * - * @return void - */ - public function adjustPrivilegesCopyTable($oldDb, $oldTable, $newDb, $newTable) - { - if ($GLOBALS['table_priv'] && $GLOBALS['col_priv'] - && $GLOBALS['is_reload_priv'] - ) { - $this->dbi->selectDb('mysql'); - - // For Table Specific privileges - $query_table_specific_old = 'SELECT * FROM ' - . Util::backquote('tables_priv') . ' where ' - . 'Db = "' . $oldDb . '" AND Table_name = "' . $oldTable . '";'; - - $old_privs_table = $this->dbi->fetchResult( - $query_table_specific_old, - 0 - ); - - foreach ($old_privs_table as $old_priv) { - $newDb_table_privs_query = 'INSERT INTO ' - . Util::backquote('tables_priv') . ' VALUES("' - . $old_priv[0] . '", "' . $newDb . '", "' . $old_priv[2] . '", "' - . $newTable . '", "' . $old_priv[4] . '", "' . $old_priv[5] - . '", "' . $old_priv[6] . '", "' . $old_priv[7] . '");'; - - $this->dbi->query($newDb_table_privs_query); - } - - // For Column Specific privileges - $query_col_specific_old = 'SELECT * FROM ' - . Util::backquote('columns_priv') . ' WHERE ' - . 'Db = "' . $oldDb . '" AND Table_name = "' . $oldTable . '";'; - - $old_privs_col = $this->dbi->fetchResult( - $query_col_specific_old, - 0 - ); - - foreach ($old_privs_col as $old_priv) { - $newDb_col_privs_query = 'INSERT INTO ' - . Util::backquote('columns_priv') . ' VALUES("' - . $old_priv[0] . '", "' . $newDb . '", "' . $old_priv[2] . '", "' - . $newTable . '", "' . $old_priv[4] . '", "' . $old_priv[5] - . '", "' . $old_priv[6] . '");'; - - $this->dbi->query($newDb_col_privs_query); - } - - // Finally FLUSH the new privileges - $flush_query = "FLUSH PRIVILEGES;"; - $this->dbi->query($flush_query); - } - } - - /** - * Change all collations and character sets of all columns in table - * - * @param string $db Database name - * @param string $table Table name - * @param string $tbl_collation Collation Name - * - * @return void - */ - public function changeAllColumnsCollation($db, $table, $tbl_collation) - { - $this->dbi->selectDb($db); - - $change_all_collations_query = 'ALTER TABLE ' - . Util::backquote($table) - . ' CONVERT TO'; - - list($charset) = explode('_', $tbl_collation); - - $change_all_collations_query .= ' CHARACTER SET ' . $charset - . ($charset == $tbl_collation ? '' : ' COLLATE ' . $tbl_collation); - - $this->dbi->query($change_all_collations_query); - } - - /** - * Move or copy a table - * - * @param string $db current database name - * @param string $table current table name - * - * @return void - */ - public function moveOrCopyTable($db, $table) - { - /** - * Selects the database to work with - */ - $this->dbi->selectDb($db); - - /** - * $_POST['target_db'] could be empty in case we came from an input field - * (when there are many databases, no drop-down) - */ - if (empty($_POST['target_db'])) { - $_POST['target_db'] = $db; - } - - /** - * A target table name has been sent to this script -> do the work - */ - if (Core::isValid($_POST['new_name'])) { - if ($db == $_POST['target_db'] && $table == $_POST['new_name']) { - if (isset($_POST['submit_move'])) { - $message = Message::error(__('Can\'t move table to same one!')); - } else { - $message = Message::error(__('Can\'t copy table to same one!')); - } - } else { - Table::moveCopy( - $db, - $table, - $_POST['target_db'], - $_POST['new_name'], - $_POST['what'], - isset($_POST['submit_move']), - 'one_table' - ); - - if (isset($_POST['adjust_privileges']) - && ! empty($_POST['adjust_privileges']) - ) { - if (isset($_POST['submit_move'])) { - $this->adjustPrivilegesRenameOrMoveTable( - $db, - $table, - $_POST['target_db'], - $_POST['new_name'] - ); - } else { - $this->adjustPrivilegesCopyTable( - $db, - $table, - $_POST['target_db'], - $_POST['new_name'] - ); - } - - if (isset($_POST['submit_move'])) { - $message = Message::success( - __( - 'Table %s has been moved to %s. Privileges have been ' - . 'adjusted.' - ) - ); - } else { - $message = Message::success( - __( - 'Table %s has been copied to %s. Privileges have been ' - . 'adjusted.' - ) - ); - } - } else { - if (isset($_POST['submit_move'])) { - $message = Message::success( - __('Table %s has been moved to %s.') - ); - } else { - $message = Message::success( - __('Table %s has been copied to %s.') - ); - } - } - - $old = Util::backquote($db) . '.' - . Util::backquote($table); - $message->addParam($old); - - $new_name = $_POST['new_name']; - if ($this->dbi->getLowerCaseNames() === '1') { - $new_name = strtolower($new_name); - } - - $GLOBALS['table'] = $new_name; - - $new = Util::backquote($_POST['target_db']) . '.' - . Util::backquote($new_name); - $message->addParam($new); - } - } else { - /** - * No new name for the table! - */ - $message = Message::error(__('The table name is empty!')); - } - - $response = Response::getInstance(); - if ($response->isAjax()) { - $response->addJSON('message', $message); - if ($message->isSuccess()) { - $response->addJSON('db', $GLOBALS['db']); - } else { - $response->setRequestStatus(false); - } - exit; - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/OutputBuffering.php b/srcs/phpmyadmin/libraries/classes/OutputBuffering.php deleted file mode 100644 index 7714976..0000000 --- a/srcs/phpmyadmin/libraries/classes/OutputBuffering.php +++ /dev/null @@ -1,144 +0,0 @@ -_mode = $this->_getMode(); - $this->_on = false; - } - - /** - * This function could be used eventually to support more modes. - * - * @return integer the output buffer mode - */ - private function _getMode() - { - $mode = 0; - if ($GLOBALS['cfg']['OBGzip'] && function_exists('ob_start')) { - if (ini_get('output_handler') == 'ob_gzhandler') { - // If a user sets the output_handler in php.ini to ob_gzhandler, then - // any right frame file in phpMyAdmin will not be handled properly by - // the browser. My fix was to check the ini file within the - // PMA_outBufferModeGet() function. - $mode = 0; - } elseif (function_exists('ob_get_level') && ob_get_level() > 0) { - // happens when php.ini's output_buffering is not Off - ob_end_clean(); - $mode = 1; - } else { - $mode = 1; - } - } - // Zero (0) is no mode or in other words output buffering is OFF. - // Follow 2^0, 2^1, 2^2, 2^3 type values for the modes. - // Useful if we ever decide to combine modes. Then a bitmask field of - // the sum of all modes will be the natural choice. - return $mode; - } - - /** - * Returns the singleton OutputBuffering object - * - * @return OutputBuffering object - */ - public static function getInstance() - { - if (empty(self::$_instance)) { - self::$_instance = new OutputBuffering(); - } - return self::$_instance; - } - - /** - * This function will need to run at the top of all pages if output - * output buffering is turned on. It also needs to be passed $mode from - * the PMA_outBufferModeGet() function or it will be useless. - * - * @return void - */ - public function start() - { - if (! $this->_on) { - if ($this->_mode && function_exists('ob_gzhandler')) { - ob_start('ob_gzhandler'); - } - ob_start(); - if (! defined('TESTSUITE')) { - header('X-ob_mode: ' . $this->_mode); - } - register_shutdown_function( - [ - OutputBuffering::class, - 'stop', - ] - ); - $this->_on = true; - } - } - - /** - * This function will need to run at the bottom of all pages if output - * buffering is turned on. It also needs to be passed $mode from the - * PMA_outBufferModeGet() function or it will be useless. - * - * @return void - */ - public static function stop() - { - $buffer = OutputBuffering::getInstance(); - if ($buffer->_on) { - $buffer->_on = false; - $buffer->_content = ob_get_contents(); - if (ob_get_length() > 0) { - ob_end_clean(); - } - } - } - - /** - * Gets buffer content - * - * @return string buffer content - */ - public function getContents() - { - return $this->_content; - } - - /** - * Flushes output buffer - * - * @return void - */ - public function flush() - { - if (ob_get_status() && $this->_mode) { - ob_flush(); - } else { - flush(); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/ParseAnalyze.php b/srcs/phpmyadmin/libraries/classes/ParseAnalyze.php deleted file mode 100644 index 8fa8ff2..0000000 --- a/srcs/phpmyadmin/libraries/classes/ParseAnalyze.php +++ /dev/null @@ -1,84 +0,0 @@ - 1) { - - /** - * @todo if there are more than one table name in the Select: - * - do not extract the first table name - * - do not show a table name in the page header - * - do not display the sub-pages links) - */ - $table = ''; - } else { - $table = $analyzed_sql_results['select_tables'][0][0]; - if (! empty($analyzed_sql_results['select_tables'][0][1])) { - $db = $analyzed_sql_results['select_tables'][0][1]; - } - } - // There is no point checking if a reload is required if we already decided - // to reload. Also, no reload is required for AJAX requests. - $response = Response::getInstance(); - if (empty($reload) && ! $response->isAjax()) { - // NOTE: Database names are case-insensitive. - $reload = strcasecmp($db, $prev_db) != 0; - } - - // Updating the array. - $analyzed_sql_results['reload'] = $reload; - } - - return [ - $analyzed_sql_results, - $db, - $table, - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Partition.php b/srcs/phpmyadmin/libraries/classes/Partition.php deleted file mode 100644 index 6727fad..0000000 --- a/srcs/phpmyadmin/libraries/classes/Partition.php +++ /dev/null @@ -1,270 +0,0 @@ -name = $row['PARTITION_NAME']; - $this->ordinal = $row['PARTITION_ORDINAL_POSITION']; - $this->method = $row['PARTITION_METHOD']; - $this->expression = $row['PARTITION_EXPRESSION']; - $this->description = $row['PARTITION_DESCRIPTION']; - // no sub partitions, load all data to this object - if (empty($row['SUBPARTITION_NAME'])) { - $this->loadCommonData($row); - } - } - - /** - * Returns the partiotion description - * - * @return string partition description - */ - public function getDescription() - { - return $this->description; - } - - /** - * Add a sub partition - * - * @param SubPartition $partition Sub partition - * - * @return void - */ - public function addSubPartition(SubPartition $partition) - { - $this->subPartitions[] = $partition; - } - - /** - * Whether there are sub partitions - * - * @return boolean - */ - public function hasSubPartitions() - { - return ! empty($this->subPartitions); - } - - /** - * Returns the number of data rows - * - * @return integer number of rows - */ - public function getRows() - { - if (empty($this->subPartitions)) { - return $this->rows; - } - - $rows = 0; - foreach ($this->subPartitions as $subPartition) { - $rows += $subPartition->rows; - } - return $rows; - } - - /** - * Returns the total data length - * - * @return integer data length - */ - public function getDataLength() - { - if (empty($this->subPartitions)) { - return $this->dataLength; - } - - $dataLength = 0; - foreach ($this->subPartitions as $subPartition) { - $dataLength += $subPartition->dataLength; - } - return $dataLength; - } - - /** - * Returns the tatal index length - * - * @return integer index length - */ - public function getIndexLength() - { - if (empty($this->subPartitions)) { - return $this->indexLength; - } - - $indexLength = 0; - foreach ($this->subPartitions as $subPartition) { - $indexLength += $subPartition->indexLength; - } - return $indexLength; - } - - /** - * Returns the list of sub partitions - * - * @return SubPartition[] - */ - public function getSubPartitions() - { - return $this->subPartitions; - } - - /** - * Returns array of partitions for a specific db/table - * - * @param string $db database name - * @param string $table table name - * - * @access public - * @return Partition[] - */ - public static function getPartitions($db, $table) - { - if (Partition::havePartitioning()) { - $result = $GLOBALS['dbi']->fetchResult( - "SELECT * FROM `information_schema`.`PARTITIONS`" - . " WHERE `TABLE_SCHEMA` = '" . $GLOBALS['dbi']->escapeString($db) - . "' AND `TABLE_NAME` = '" . $GLOBALS['dbi']->escapeString($table) . "'" - ); - if ($result) { - $partitionMap = []; - foreach ($result as $row) { - if (isset($partitionMap[$row['PARTITION_NAME']])) { - $partition = $partitionMap[$row['PARTITION_NAME']]; - } else { - $partition = new Partition($row); - $partitionMap[$row['PARTITION_NAME']] = $partition; - } - - if (! empty($row['SUBPARTITION_NAME'])) { - $parentPartition = $partition; - $partition = new SubPartition($row); - $parentPartition->addSubPartition($partition); - } - } - return array_values($partitionMap); - } - return []; - } - - return []; - } - - /** - * returns array of partition names for a specific db/table - * - * @param string $db database name - * @param string $table table name - * - * @access public - * @return array of partition names - */ - public static function getPartitionNames($db, $table) - { - if (Partition::havePartitioning()) { - return $GLOBALS['dbi']->fetchResult( - "SELECT DISTINCT `PARTITION_NAME` FROM `information_schema`.`PARTITIONS`" - . " WHERE `TABLE_SCHEMA` = '" . $GLOBALS['dbi']->escapeString($db) - . "' AND `TABLE_NAME` = '" . $GLOBALS['dbi']->escapeString($table) . "'" - ); - } - - return []; - } - - /** - * returns the partition method used by the table. - * - * @param string $db database name - * @param string $table table name - * - * @return string|null partition method - */ - public static function getPartitionMethod($db, $table) - { - if (Partition::havePartitioning()) { - $partition_method = $GLOBALS['dbi']->fetchResult( - "SELECT `PARTITION_METHOD` FROM `information_schema`.`PARTITIONS`" - . " WHERE `TABLE_SCHEMA` = '" . $GLOBALS['dbi']->escapeString($db) . "'" - . " AND `TABLE_NAME` = '" . $GLOBALS['dbi']->escapeString($table) . "'" - . " LIMIT 1" - ); - if (! empty($partition_method)) { - return $partition_method[0]; - } - } - return null; - } - - /** - * checks if MySQL server supports partitioning - * - * @static - * @staticvar boolean $have_partitioning - * @staticvar boolean $already_checked - * @access public - * @return boolean - */ - public static function havePartitioning() - { - static $have_partitioning = false; - static $already_checked = false; - - if (! $already_checked) { - if ($GLOBALS['dbi']->getVersion() < 50600) { - if ($GLOBALS['dbi']->fetchValue( - "SELECT @@have_partitioning;" - )) { - $have_partitioning = true; - } - } elseif ($GLOBALS['dbi']->getVersion() >= 80000) { - $have_partitioning = true; - } else { - // see https://dev.mysql.com/doc/refman/5.6/en/partitioning.html - $plugins = $GLOBALS['dbi']->fetchResult("SHOW PLUGINS"); - foreach ($plugins as $value) { - if ($value['Name'] == 'partition') { - $have_partitioning = true; - break; - } - } - } - $already_checked = true; - } - return $have_partitioning; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Pdf.php b/srcs/phpmyadmin/libraries/classes/Pdf.php deleted file mode 100644 index 3dacdb5..0000000 --- a/srcs/phpmyadmin/libraries/classes/Pdf.php +++ /dev/null @@ -1,178 +0,0 @@ -SetAuthor('phpMyAdmin ' . PMA_VERSION); - $this->AddFont('DejaVuSans', '', 'dejavusans.php'); - $this->AddFont('DejaVuSans', 'B', 'dejavusansb.php'); - $this->SetFont(Pdf::PMA_PDF_FONT, '', 14); - $this->setFooterFont([Pdf::PMA_PDF_FONT, '', 14]); - } - - /** - * This function must be named "Footer" to work with the TCPDF library - * - * @return void - */ - // @codingStandardsIgnoreLine - public function Footer() - { - // Check if footer for this page already exists - if (! isset($this->footerset[$this->page])) { - $this->SetY(-15); - $this->SetFont(Pdf::PMA_PDF_FONT, '', 14); - $this->Cell( - 0, - 6, - __('Page number:') . ' ' - . $this->getAliasNumPage() . '/' . $this->getAliasNbPages(), - 'T', - 0, - 'C' - ); - $this->Cell(0, 6, Util::localisedDate(), 0, 1, 'R'); - $this->SetY(20); - - // set footerset - $this->footerset[$this->page] = 1; - } - } - - /** - * Function to set alias which will be expanded on page rendering. - * - * @param string $name name of the alias - * @param string $value value of the alias - * - * @return void - */ - public function setAlias($name, $value) - { - $name = TCPDF_FONTS::UTF8ToUTF16BE( - $name, - false, - true, - $this->CurrentFont - ); - $this->Alias[$name] = TCPDF_FONTS::UTF8ToUTF16BE( - $value, - false, - true, - $this->CurrentFont - ); - } - - /** - * Improved with alias expanding. - * - * @return void - */ - public function _putpages() - { - if (count($this->Alias) > 0) { - $nbPages = count($this->pages); - for ($n = 1; $n <= $nbPages; $n++) { - $this->pages[$n] = strtr($this->pages[$n], $this->Alias); - } - } - parent::_putpages(); - } - - /** - * Displays an error message - * - * @param string $error_message the error message - * - * @return void - */ - // @codingStandardsIgnoreLine - public function Error($error_message = '') - { - Message::error( - __('Error while creating PDF:') . ' ' . $error_message - )->display(); - exit; - } - - /** - * Sends file as a download to user. - * - * @param string $filename file name - * - * @return void - */ - public function download($filename) - { - $pdfData = $this->getPDFData(); - Response::getInstance()->disable(); - Core::downloadHeader( - $filename, - 'application/pdf', - strlen($pdfData) - ); - echo $pdfData; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins.php b/srcs/phpmyadmin/libraries/classes/Plugins.php deleted file mode 100644 index cd6f6c0..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins.php +++ /dev/null @@ -1,633 +0,0 @@ -getProperties()) { - $plugin_list[] = $plugin; - } - } - } - } - - usort($plugin_list, function ($cmp_name_1, $cmp_name_2) { - return strcasecmp( - $cmp_name_1->getProperties()->getText(), - $cmp_name_2->getProperties()->getText() - ); - }); - return $plugin_list; - } - - /** - * Returns locale string for $name or $name if no locale is found - * - * @param string $name for local string - * - * @return string locale string for $name - */ - public static function getString($name) - { - return isset($GLOBALS[$name]) ? $GLOBALS[$name] : $name; - } - - /** - * Returns html input tag option 'checked' if plugin $opt - * should be set by config or request - * - * @param string $section name of config section in - * $GLOBALS['cfg'][$section] for plugin - * @param string $opt name of option - * - * @return string html input tag option 'checked' - */ - public static function checkboxCheck($section, $opt) - { - // If the form is being repopulated using $_GET data, that is priority - if (isset($_GET[$opt]) - || ! isset($_GET['repopulate']) - && ((! empty($GLOBALS['timeout_passed']) && isset($_REQUEST[$opt])) - || ! empty($GLOBALS['cfg'][$section][$opt])) - ) { - return ' checked="checked"'; - } - return ''; - } - - /** - * Returns default value for option $opt - * - * @param string $section name of config section in - * $GLOBALS['cfg'][$section] for plugin - * @param string $opt name of option - * - * @return string default value for option $opt - */ - public static function getDefault($section, $opt) - { - if (isset($_GET[$opt])) { - // If the form is being repopulated using $_GET data, that is priority - return htmlspecialchars($_GET[$opt]); - } - - if (isset($GLOBALS['timeout_passed']) - && $GLOBALS['timeout_passed'] - && isset($_REQUEST[$opt]) - ) { - return htmlspecialchars($_REQUEST[$opt]); - } - - if (! isset($GLOBALS['cfg'][$section][$opt])) { - return ''; - } - - $matches = []; - /* Possibly replace localised texts */ - if (! preg_match_all( - '/(str[A-Z][A-Za-z0-9]*)/', - (string) $GLOBALS['cfg'][$section][$opt], - $matches - )) { - return htmlspecialchars((string) $GLOBALS['cfg'][$section][$opt]); - } - - $val = $GLOBALS['cfg'][$section][$opt]; - foreach ($matches[0] as $match) { - if (isset($GLOBALS[$match])) { - $val = str_replace($match, $GLOBALS[$match], $val); - } - } - return htmlspecialchars($val); - } - - /** - * Returns html select form element for plugin choice - * and hidden fields denoting whether each plugin must be exported as a file - * - * @param string $section name of config section in - * $GLOBALS['cfg'][$section] for plugin - * @param string $name name of select element - * @param array $list array with plugin instances - * @param string $cfgname name of config value, if none same as $name - * - * @return string html select tag - */ - public static function getChoice($section, $name, array $list, $cfgname = null) - { - if (! isset($cfgname)) { - $cfgname = $name; - } - $ret = '' . "\n"; - } - $ret .= '' . "\n" . $hidden; - - 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 OptionsPropertyItem $propertyGroup options property main group instance - * @param boolean $is_subgroup if this group is a subgroup - * - * @return string table row with option - */ - public static function getOneOption( - $section, - $plugin_name, - &$propertyGroup, - $is_subgroup = false - ) { - $ret = "\n"; - - $properties = null; - if (! $is_subgroup) { - // for subgroup headers - if (mb_strpos(get_class($propertyGroup), "PropertyItem")) { - $properties = [$propertyGroup]; - } else { - // for main groups - $ret .= '
    '; - - $text = null; - if (method_exists($propertyGroup, 'getText')) { - $text = $propertyGroup->getText(); - } - - if ($text != null) { - $ret .= '

    ' . self::getString($text) . '

    '; - } - $ret .= '
      '; - } - } - - if (! isset($properties)) { - $not_subgroup_header = true; - if (method_exists($propertyGroup, 'getProperties')) { - $properties = $propertyGroup->getProperties(); - } - } - - if (isset($properties)) { - /** @var OptionsPropertySubgroup $propertyItem */ - foreach ($properties as $propertyItem) { - $property_class = get_class($propertyItem); - // if the property is a subgroup, we deal with it recursively - if (mb_strpos($property_class, "Subgroup")) { - // for subgroups - // each subgroup can have a header, which may also be a form element - /** @var OptionsPropertyItem $subgroup_header */ - $subgroup_header = $propertyItem->getSubgroupHeader(); - if ($subgroup_header !== null) { - $ret .= self::getOneOption( - $section, - $plugin_name, - $subgroup_header - ); - } - - $ret .= '
    • getName() . '">'; - } else { - $ret .= '>'; - } - - $ret .= self::getOneOption( - $section, - $plugin_name, - $propertyItem, - true - ); - continue; - } - - // single property item - $ret .= self::getHtmlForProperty( - $section, - $plugin_name, - $propertyItem - ); - } - } - - 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 .= Util::showMySQLDocu( - $doc[1], - false, - null, - null, - $doc[2] - ); - } elseif (count($doc) === 1) { - $ret .= Util::showDocu('faq', $doc[0]); - } else { - $ret .= Util::showMySQLDocu( - $doc[1] - ); - } - } - } - - // Close the list element after $doc link is displayed - if (isset($property_class)) { - if ($property_class == 'PhpMyAdmin\Properties\Options\Items\BoolPropertyItem' - || $property_class == 'PhpMyAdmin\Properties\Options\Items\MessageOnlyPropertyItem' - || $property_class == 'PhpMyAdmin\Properties\Options\Items\SelectPropertyItem' - || $property_class == 'PhpMyAdmin\Properties\Options\Items\TextPropertyItem' - ) { - $ret .= ''; - } - } - $ret .= "\n"; - return $ret; - } - - /** - * Get HTML for properties items - * - * @param string $section name of config section in - * $GLOBALS['cfg'][$section] for plugin - * @param string $plugin_name unique plugin name - * @param OptionsPropertyItem $propertyItem Property item - * - * @return string - */ - public static function getHtmlForProperty( - $section, - $plugin_name, - $propertyItem - ) { - $ret = null; - $property_class = get_class($propertyItem); - switch ($property_class) { - case BoolPropertyItem::class: - $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::class: - echo DocPropertyItem::class; - break; - case HiddenPropertyItem::class: - $ret .= '
  • '; - break; - case MessageOnlyPropertyItem::class: - $ret .= '
  • ' . "\n"; - $ret .= '

    ' . self::getString($propertyItem->getText()) . '

    '; - break; - case RadioPropertyItem::class: - /** - * @var RadioPropertyItem $pitem - */ - $pitem = $propertyItem; - - $default = self::getDefault( - $section, - $plugin_name . '_' . $pitem->getName() - ); - - foreach ($pitem->getValues() as $key => $val) { - $ret .= '
  • getName() . '_' . $key . '">' - . self::getString($val) . '
  • '; - } - break; - case SelectPropertyItem::class: - /** - * @var SelectPropertyItem $pitem - */ - $pitem = $propertyItem; - $ret .= '
  • ' . "\n"; - $ret .= ''; - $ret .= ''; - break; - case TextPropertyItem::class: - /** - * @var TextPropertyItem $pitem - */ - $pitem = $propertyItem; - $ret .= '
  • ' . "\n"; - $ret .= ''; - $ret .= 'getSize() != null - ? ' size="' . $pitem->getSize() . '"' - : '') - . ($pitem->getLen() != null - ? ' maxlength="' . $pitem->getLen() . '"' - : '') - . '>'; - break; - case NumberPropertyItem::class: - $ret .= '
  • ' . "\n"; - $ret .= ''; - $ret .= ''; - break; - default: - break; - } - 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 - */ - public static function getOptions($section, array $list) - { - $ret = ''; - // Options for plugins that support them - foreach ($list as $plugin) { - $properties = $plugin->getProperties(); - $text = null; - $options = null; - if ($properties != null) { - $text = $properties->getText(); - $options = $properties->getOptions(); - } - - $elem = explode('\\', get_class($plugin)); - $plugin_name = array_pop($elem); - unset($elem); - $plugin_name = mb_strtolower( - mb_substr( - $plugin_name, - mb_strlen($section) - ) - ); - - $ret .= '
    '; - $ret .= '

    ' . self::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::class, get_class($propertyItem))) { - $no_options = false; - break; - } - } - - $ret .= self::getOneOption( - $section, - $plugin_name, - $propertyMainGroup - ); - } - } - - if ($no_options) { - $ret .= '

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

    '; - } - $ret .= '
    '; - } - return $ret; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationConfig.php b/srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationConfig.php deleted file mode 100644 index 7ebd1ae..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationConfig.php +++ /dev/null @@ -1,172 +0,0 @@ -isAjax()) { - $response->setRequestStatus(false); - // reload_flag removes the token parameter from the URL and reloads - $response->addJSON('reload_flag', '1'); - if (defined('TESTSUITE')) { - return true; - } else { - exit; - } - } - - return true; - } - - /** - * Gets authentication credentials - * - * @return boolean always true - */ - public function readCredentials() - { - if ($GLOBALS['token_provided'] && $GLOBALS['token_mismatch']) { - return false; - } - - $this->user = $GLOBALS['cfg']['Server']['user']; - $this->password = $GLOBALS['cfg']['Server']['password']; - - return true; - } - - /** - * User is not allowed to login to MySQL -> authentication failed - * - * @param string $failure String describing why authentication has failed - * - * @return void - */ - public function showFailure($failure) - { - parent::showFailure($failure); - $conn_error = $GLOBALS['dbi']->getError(); - if (! $conn_error) { - $conn_error = __('Cannot connect: invalid settings.'); - } - - /* HTML header */ - $response = Response::getInstance(); - $response->getFooter() - ->setMinimal(); - $header = $response->getHeader(); - $header->setBodyId('loginform'); - $header->setTitle(__('Access denied!')); - $header->disableMenuAndConsole(); - 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 - 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 Util::mysqlDie( - $conn_error, - '', - true, - '', - false - ); - } - $GLOBALS['error_handler']->dispUserErrors(); - echo '
    ' , "\n"; - echo '' - , __('Retry to connect') - , '' , "\n"; - echo '
    ' , "\n"; - echo Select::render(true, true); - echo '
    ' , "\n"; - if (! defined('TESTSUITE')) { - exit; - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationCookie.php b/srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationCookie.php deleted file mode 100644 index 7a794d0..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationCookie.php +++ /dev/null @@ -1,964 +0,0 @@ -_use_openssl = ! class_exists(Random::class); - } - - /** - * Forces (not)using of openSSL - * - * @param boolean $use The flag - * - * @return void - */ - public function setUseOpenSSL($use) - { - $this->_use_openssl = $use; - } - - /** - * Displays authentication form - * - * this function MUST exit/quit the application - * - * @global string $conn_error the last connection error - * - * @return boolean|void - */ - public function showLoginForm() - { - global $conn_error; - - $response = Response::getInstance(); - - // When sending login modal after session has expired, send the new token explicitly with the response to update the token in all the forms having a hidden token. - $session_expired = isset($_REQUEST['check_timeout']) || isset($_REQUEST['session_timedout']); - if (! $session_expired && $response->loginPage()) { - if (defined('TESTSUITE')) { - return true; - } else { - exit; - } - } - - // When sending login modal after session has expired, send the new token explicitly with the response to update the token in all the forms having a hidden token. - if ($session_expired) { - $response->setRequestStatus(false); - $response->addJSON( - 'new_token', - $_SESSION[' PMA_token '] - ); - } - - // logged_in response parameter is used to check if the login, using the modal was successful after session expiration - if (isset($_REQUEST['session_timedout'])) { - $response->addJSON( - 'logged_in', - 0 - ); - } - - // No recall if blowfish secret is not configured as it would produce - // garbage - if ($GLOBALS['cfg']['LoginCookieRecall'] - && ! empty($GLOBALS['cfg']['blowfish_secret']) - ) { - $default_user = $this->user; - $default_server = $GLOBALS['pma_auth_server']; - $autocomplete = ''; - } else { - $default_user = ''; - $default_server = ''; - // skip the IE autocomplete feature. - $autocomplete = ' autocomplete="off"'; - } - - // wrap the login form in a div which overlays the whole page. - if ($session_expired) { - echo $this->template->render('login/header', [ - 'theme' => $GLOBALS['PMA_Theme'], - 'add_class' => ' modal_form', - 'session_expired' => 1, - ]); - } else { - echo $this->template->render('login/header', [ - 'theme' => $GLOBALS['PMA_Theme'], - 'add_class' => '', - 'session_expired' => 0, - ]); - } - - if ($GLOBALS['cfg']['DBG']['demo']) { - echo '
    '; - echo '' , __('phpMyAdmin Demo Server') , ''; - printf( - __( - 'You are using the demo server. You can do anything here, but ' - . 'please do not change root, debian-sys-maint and pma users. ' - . 'More information is available at %s.' - ), - 'demo.phpmyadmin.net' - ); - echo '
    '; - } - - // Show error message - if (! empty($conn_error)) { - Message::rawError((string) $conn_error)->display(); - } elseif (isset($_GET['session_expired']) - && intval($_GET['session_expired']) == 1 - ) { - Message::rawError( - __('Your session has expired. Please log in again.') - )->display(); - } - - // Displays the languages form - $language_manager = LanguageManager::getInstance(); - if (empty($GLOBALS['cfg']['Lang']) && $language_manager->hasChoice()) { - echo "
    "; - // use fieldset, don't show doc link - echo $language_manager->getSelectorDisplay(new Template(), true, false); - echo '
    '; - } - echo ' -
    - -
    -
    - '; - echo ''; - - // Add a hidden element session_timedout which is used to check if the user requested login after session expiration - if ($session_expired) { - echo ''; - } - echo __('Log in'); - echo Util::showDocu('index'); - echo ''; - if ($GLOBALS['cfg']['AllowArbitraryServer']) { - echo ' -
    - - -
    '; - } - echo '
    - - -
    -
    - - -
    '; - if (count($GLOBALS['cfg']['Servers']) > 1) { - echo '
    - -
    '; - } else { - echo ' '; - } // end if (server choice) - - echo '
    '; - - // binds input field with invisible reCaptcha if enabled - if (empty($GLOBALS['cfg']['CaptchaLoginPrivateKey']) - && empty($GLOBALS['cfg']['CaptchaLoginPublicKey']) - ) { - echo ''; - } else { - echo ''; - echo ''; - } - $_form_params = []; - if (! empty($GLOBALS['target'])) { - $_form_params['target'] = $GLOBALS['target']; - } - if (strlen($GLOBALS['db'])) { - $_form_params['db'] = $GLOBALS['db']; - } - if (strlen($GLOBALS['table'])) { - $_form_params['table'] = $GLOBALS['table']; - } - // do not generate a "server" hidden field as we want the "server" - // drop-down to have priority - echo Url::getHiddenInputs($_form_params, '', 0, 'server'); - echo '
    -
    '; - - if ($GLOBALS['error_handler']->hasDisplayErrors()) { - echo '
    '; - $GLOBALS['error_handler']->dispErrors(); - echo '
    '; - } - - // close the wrapping div tag, if the request is after session timeout - if ($session_expired) { - echo $this->template->render('login/footer', ['session_expired' => 1]); - } else { - echo $this->template->render('login/footer', ['session_expired' => 0]); - } - - echo Config::renderFooter(); - - if (! defined('TESTSUITE')) { - exit; - } else { - return true; - } - } - - /** - * Gets authentication credentials - * - * this function DOES NOT check authentication - it just checks/provides - * authentication credentials required to connect to the MySQL server - * usually with $GLOBALS['dbi']->connect() - * - * it returns false if something is missing - which usually leads to - * showLoginForm() which displays login form - * - * it returns true if all seems ok which usually leads to auth_set_user() - * - * it directly switches to showFailure() if user inactivity timeout is reached - * - * @return boolean whether we get authentication settings or not - */ - public function readCredentials() - { - global $conn_error; - - // Initialization - /** - * @global $GLOBALS['pma_auth_server'] the user provided server to - * connect to - */ - $GLOBALS['pma_auth_server'] = ''; - - $this->user = $this->password = ''; - $GLOBALS['from_cookie'] = false; - - if (isset($_POST['pma_username']) && strlen($_POST['pma_username']) > 0) { - // Verify Captcha if it is required. - if (! empty($GLOBALS['cfg']['CaptchaLoginPrivateKey']) - && ! empty($GLOBALS['cfg']['CaptchaLoginPublicKey']) - ) { - if (! empty($_POST["g-recaptcha-response"])) { - if (function_exists('curl_init')) { - $reCaptcha = new ReCaptcha\ReCaptcha( - $GLOBALS['cfg']['CaptchaLoginPrivateKey'], - new ReCaptcha\RequestMethod\CurlPost() - ); - } elseif (ini_get('allow_url_fopen')) { - $reCaptcha = new ReCaptcha\ReCaptcha( - $GLOBALS['cfg']['CaptchaLoginPrivateKey'], - new ReCaptcha\RequestMethod\Post() - ); - } else { - $reCaptcha = new ReCaptcha\ReCaptcha( - $GLOBALS['cfg']['CaptchaLoginPrivateKey'], - new ReCaptcha\RequestMethod\SocketPost() - ); - } - - // verify captcha status. - $resp = $reCaptcha->verify( - $_POST["g-recaptcha-response"], - Core::getIp() - ); - - // Check if the captcha entered is valid, if not stop the login. - if ($resp == null || ! $resp->isSuccess()) { - $codes = $resp->getErrorCodes(); - - if (in_array('invalid-json', $codes)) { - $conn_error = __('Failed to connect to the reCAPTCHA service!'); - } else { - $conn_error = __('Entered captcha is wrong, try again!'); - } - return false; - } - } else { - $conn_error = __('Missing reCAPTCHA verification, maybe it has been blocked by adblock?'); - return false; - } - } - - // The user just logged in - $this->user = Core::sanitizeMySQLUser($_POST['pma_username']); - $this->password = isset($_POST['pma_password']) ? $_POST['pma_password'] : ''; - if ($GLOBALS['cfg']['AllowArbitraryServer'] - && isset($_REQUEST['pma_servername']) - ) { - if ($GLOBALS['cfg']['ArbitraryServerRegexp']) { - $parts = explode(' ', $_REQUEST['pma_servername']); - if (count($parts) === 2) { - $tmp_host = $parts[0]; - } else { - $tmp_host = $_REQUEST['pma_servername']; - } - - $match = preg_match( - $GLOBALS['cfg']['ArbitraryServerRegexp'], - $tmp_host - ); - if (! $match) { - $conn_error = __( - 'You are not allowed to log in to this MySQL server!' - ); - return false; - } - } - $GLOBALS['pma_auth_server'] = Core::sanitizeMySQLHost($_REQUEST['pma_servername']); - } - /* Secure current session on login to avoid session fixation */ - Session::secure(); - return true; - } - - // At the end, try to set the $this->user - // and $this->password variables from cookies - - // check cookies - $serverCookie = $GLOBALS['PMA_Config']->getCookie('pmaUser-' . $GLOBALS['server']); - if (empty($serverCookie)) { - return false; - } - - $value = $this->cookieDecrypt( - $serverCookie, - $this->_getEncryptionSecret() - ); - - if ($value === false) { - return false; - } - - $this->user = $value; - // user was never logged in since session start - if (empty($_SESSION['browser_access_time'])) { - return false; - } - - // User inactive too long - $last_access_time = time() - $GLOBALS['cfg']['LoginCookieValidity']; - foreach ($_SESSION['browser_access_time'] as $key => $value) { - if ($value < $last_access_time) { - unset($_SESSION['browser_access_time'][$key]); - } - } - // All sessions expired - if (empty($_SESSION['browser_access_time'])) { - Util::cacheUnset('is_create_db_priv'); - Util::cacheUnset('is_reload_priv'); - Util::cacheUnset('db_to_create'); - Util::cacheUnset('dbs_where_create_table_allowed'); - Util::cacheUnset('dbs_to_test'); - Util::cacheUnset('db_priv'); - Util::cacheUnset('col_priv'); - Util::cacheUnset('table_priv'); - Util::cacheUnset('proc_priv'); - - $this->showFailure('no-activity'); - if (! defined('TESTSUITE')) { - exit; - } else { - return false; - } - } - - // check password cookie - $serverCookie = $GLOBALS['PMA_Config']->getCookie('pmaAuth-' . $GLOBALS['server']); - - if (empty($serverCookie)) { - return false; - } - $value = $this->cookieDecrypt( - $serverCookie, - $this->_getSessionEncryptionSecret() - ); - if ($value === false) { - return false; - } - - $auth_data = json_decode($value, true); - - if (! is_array($auth_data) || ! isset($auth_data['password'])) { - return false; - } - $this->password = $auth_data['password']; - if ($GLOBALS['cfg']['AllowArbitraryServer'] && ! empty($auth_data['server'])) { - $GLOBALS['pma_auth_server'] = $auth_data['server']; - } - - $GLOBALS['from_cookie'] = true; - - return true; - } - - /** - * Set the user and password after last checkings if required - * - * @return boolean always true - */ - public function storeCredentials() - { - global $cfg; - - 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); - } - - return parent::storeCredentials(); - } - - /** - * Stores user credentials after successful login. - * - * @return void|bool - */ - public function rememberCredentials() - { - // Name and password cookies need to be refreshed each time - // Duration = one month for username - - $this->storeUsernameCookie($this->user); - - // Duration = as configured - // Do not store password cookie on password change as we will - // set the cookie again after password has been changed - if (! isset($_POST['change_pw'])) { - $this->storePasswordCookie($this->password); - } - // URL where to go: - $redirect_url = './index.php'; - - // any parameters to pass? - $url_params = []; - if (strlen($GLOBALS['db']) > 0) { - $url_params['db'] = $GLOBALS['db']; - } - if (strlen($GLOBALS['table']) > 0) { - $url_params['table'] = $GLOBALS['table']; - } - // any target to pass? - if (! empty($GLOBALS['target']) - && $GLOBALS['target'] != 'index.php' - ) { - $url_params['target'] = $GLOBALS['target']; - } - - // user logged in successfully after session expiration - if (isset($_REQUEST['session_timedout'])) { - $response = Response::getInstance(); - $response->addJSON( - 'logged_in', - 1 - ); - $response->addJSON( - 'success', - 1 - ); - $response->addJSON( - 'new_token', - $_SESSION[' PMA_token '] - ); - - if (! defined('TESTSUITE')) { - exit; - } else { - return false; - } - } - // Set server cookies if required (once per session) and, in this case, - // force reload to ensure the client accepts cookies - if (! $GLOBALS['from_cookie']) { - - /** - * Clear user cache. - */ - Util::clearUserCache(); - - Response::getInstance() - ->disable(); - - Core::sendHeaderLocation( - $redirect_url . Url::getCommonRaw($url_params), - true - ); - if (! defined('TESTSUITE')) { - exit; - } else { - return false; - } - } // end if - - return true; - } - - /** - * Stores username in a cookie. - * - * @param string $username User name - * - * @return void - */ - public function storeUsernameCookie($username) - { - // Name and password cookies need to be refreshed each time - // Duration = one month for username - $GLOBALS['PMA_Config']->setCookie( - 'pmaUser-' . $GLOBALS['server'], - $this->cookieEncrypt( - $username, - $this->_getEncryptionSecret() - ) - ); - } - - /** - * Stores password in a cookie. - * - * @param string $password Password - * - * @return void - */ - public function storePasswordCookie($password) - { - $payload = ['password' => $password]; - if ($GLOBALS['cfg']['AllowArbitraryServer'] && ! empty($GLOBALS['pma_auth_server'])) { - $payload['server'] = $GLOBALS['pma_auth_server']; - } - // Duration = as configured - $GLOBALS['PMA_Config']->setCookie( - 'pmaAuth-' . $GLOBALS['server'], - $this->cookieEncrypt( - json_encode($payload), - $this->_getSessionEncryptionSecret() - ), - null, - (int) $GLOBALS['cfg']['LoginCookieStore'] - ); - } - - /** - * User is not allowed to login to MySQL -> authentication failed - * - * prepares error message and switches to showLoginForm() which display the error - * and the login form - * - * this function MUST exit/quit the application, - * currently done by call to showLoginForm() - * - * @param string $failure String describing why authentication has failed - * - * @return void - */ - public function showFailure($failure) - { - global $conn_error; - - parent::showFailure($failure); - - // Deletes password cookie and displays the login form - $GLOBALS['PMA_Config']->removeCookie('pmaAuth-' . $GLOBALS['server']); - - $conn_error = $this->getErrorMessage($failure); - - $response = Response::getInstance(); - - // needed for PHP-CGI (not need for FastCGI or mod-php) - $response->header('Cache-Control: no-store, no-cache, must-revalidate'); - $response->header('Pragma: no-cache'); - - $this->showLoginForm(); - } - - /** - * Returns blowfish secret or generates one if needed. - * - * @return string - */ - private function _getEncryptionSecret() - { - if (empty($GLOBALS['cfg']['blowfish_secret'])) { - return $this->_getSessionEncryptionSecret(); - } - - return $GLOBALS['cfg']['blowfish_secret']; - } - - /** - * Returns blowfish secret or generates one if needed. - * - * @return string - */ - private function _getSessionEncryptionSecret() - { - if (empty($_SESSION['encryption_key'])) { - if ($this->_use_openssl) { - $_SESSION['encryption_key'] = openssl_random_pseudo_bytes(32); - } else { - $_SESSION['encryption_key'] = Crypt\Random::string(32); - } - } - return $_SESSION['encryption_key']; - } - - /** - * Concatenates secret in order to make it 16 bytes log - * - * This doesn't add any security, just ensures the secret - * is long enough by copying it. - * - * @param string $secret Original secret - * - * @return string - */ - public function enlargeSecret($secret) - { - while (strlen($secret) < 16) { - $secret .= $secret; - } - return substr($secret, 0, 16); - } - - /** - * Derives MAC secret from encryption secret. - * - * @param string $secret the secret - * - * @return string the MAC secret - */ - public function getMACSecret($secret) - { - // Grab first part, up to 16 chars - // The MAC and AES secrets can overlap if original secret is short - $length = strlen($secret); - if ($length > 16) { - return substr($secret, 0, 16); - } - return $this->enlargeSecret( - $length == 1 ? $secret : substr($secret, 0, -1) - ); - } - - /** - * Derives AES secret from encryption secret. - * - * @param string $secret the secret - * - * @return string the AES secret - */ - public function getAESSecret($secret) - { - // Grab second part, up to 16 chars - // The MAC and AES secrets can overlap if original secret is short - $length = strlen($secret); - if ($length > 16) { - return substr($secret, -16); - } - return $this->enlargeSecret( - $length == 1 ? $secret : substr($secret, 1) - ); - } - - /** - * Cleans any SSL errors - * - * This can happen from corrupted cookies, by invalid encryption - * parameters used in older phpMyAdmin versions or by wrong openSSL - * configuration. - * - * In neither case the error is useful to user, but we need to clear - * the error buffer as otherwise the errors would pop up later, for - * example during MySQL SSL setup. - * - * @return void - */ - public function cleanSSLErrors() - { - if (function_exists('openssl_error_string')) { - do { - $hasSslErrors = openssl_error_string(); - } while ($hasSslErrors !== false); - } - } - - /** - * Encryption using openssl's AES or phpseclib's AES - * (phpseclib uses mcrypt when it is available) - * - * @param string $data original data - * @param string $secret the secret - * - * @return string the encrypted result - */ - public function cookieEncrypt($data, $secret) - { - $mac_secret = $this->getMACSecret($secret); - $aes_secret = $this->getAESSecret($secret); - $iv = $this->createIV(); - if ($this->_use_openssl) { - $result = openssl_encrypt( - $data, - 'AES-128-CBC', - $aes_secret, - 0, - $iv - ); - } else { - $cipher = new Crypt\AES(Crypt\Base::MODE_CBC); - $cipher->setIV($iv); - $cipher->setKey($aes_secret); - $result = base64_encode($cipher->encrypt($data)); - } - $this->cleanSSLErrors(); - $iv = base64_encode($iv); - return json_encode( - [ - 'iv' => $iv, - 'mac' => hash_hmac('sha1', $iv . $result, $mac_secret), - 'payload' => $result, - ] - ); - } - - /** - * Decryption using openssl's AES or phpseclib's AES - * (phpseclib uses mcrypt when it is available) - * - * @param string $encdata encrypted data - * @param string $secret the secret - * - * @return string|false original data, false on error - */ - public function cookieDecrypt($encdata, $secret) - { - $data = json_decode($encdata, true); - - if (! is_array($data) || ! isset($data['mac']) || ! isset($data['iv']) || ! isset($data['payload']) - || ! is_string($data['mac']) || ! is_string($data['iv']) || ! is_string($data['payload']) - ) { - return false; - } - - $mac_secret = $this->getMACSecret($secret); - $aes_secret = $this->getAESSecret($secret); - $newmac = hash_hmac('sha1', $data['iv'] . $data['payload'], $mac_secret); - - if (! hash_equals($data['mac'], $newmac)) { - return false; - } - - if ($this->_use_openssl) { - $result = openssl_decrypt( - $data['payload'], - 'AES-128-CBC', - $aes_secret, - 0, - base64_decode($data['iv']) - ); - } else { - $cipher = new Crypt\AES(Crypt\Base::MODE_CBC); - $cipher->setIV(base64_decode($data['iv'])); - $cipher->setKey($aes_secret); - $result = $cipher->decrypt(base64_decode($data['payload'])); - } - $this->cleanSSLErrors(); - return $result; - } - - /** - * Returns size of IV for encryption. - * - * @return int - */ - public function getIVSize() - { - if ($this->_use_openssl) { - return openssl_cipher_iv_length('AES-128-CBC'); - } - return (new Crypt\AES(Crypt\Base::MODE_CBC))->block_size; - } - - /** - * Initialization - * Store the initialization vector because it will be needed for - * further decryption. I don't think necessary to have one iv - * per server so I don't put the server number in the cookie name. - * - * @return string - */ - public function createIV() - { - /* Testsuite shortcut only to allow predictable IV */ - if ($this->_cookie_iv !== null) { - return $this->_cookie_iv; - } - if ($this->_use_openssl) { - return openssl_random_pseudo_bytes( - $this->getIVSize() - ); - } - - return Crypt\Random::string( - $this->getIVSize() - ); - } - - /** - * Sets encryption IV to use - * - * This is for testing only! - * - * @param string $vector The IV - * - * @return void - */ - public function setIV($vector) - { - $this->_cookie_iv = $vector; - } - - /** - * Callback when user changes password. - * - * @param string $password New password to set - * - * @return void - */ - public function handlePasswordChange($password) - { - $this->storePasswordCookie($password); - } - - /** - * Perform logout - * - * @return void - */ - public function logOut() - { - /** @var Config $PMA_Config */ - global $PMA_Config; - - // -> delete password cookie(s) - if ($GLOBALS['cfg']['LoginCookieDeleteAll']) { - foreach ($GLOBALS['cfg']['Servers'] as $key => $val) { - $PMA_Config->removeCookie('pmaAuth-' . $key); - if ($PMA_Config->issetCookie('pmaAuth-' . $key)) { - $PMA_Config->removeCookie('pmaAuth-' . $key); - } - } - } else { - $cookieName = 'pmaAuth-' . $GLOBALS['server']; - $PMA_Config->removeCookie($cookieName); - if ($PMA_Config->issetCookie($cookieName)) { - $PMA_Config->removeCookie($cookieName); - } - } - parent::logOut(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationHttp.php b/srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationHttp.php deleted file mode 100644 index 6d735e8..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationHttp.php +++ /dev/null @@ -1,214 +0,0 @@ -isAjax()) { - $response->setRequestStatus(false); - // reload_flag removes the token parameter from the URL and reloads - $response->addJSON('reload_flag', '1'); - if (defined('TESTSUITE')) { - return true; - } else { - exit; - } - } - - return $this->authForm(); - } - - /** - * Displays authentication form - * - * @return boolean - */ - public function authForm() - { - if (empty($GLOBALS['cfg']['Server']['auth_http_realm'])) { - if (empty($GLOBALS['cfg']['Server']['verbose'])) { - $server_message = $GLOBALS['cfg']['Server']['host']; - } else { - $server_message = $GLOBALS['cfg']['Server']['verbose']; - } - $realm_message = 'phpMyAdmin ' . $server_message; - } else { - $realm_message = $GLOBALS['cfg']['Server']['auth_http_realm']; - } - - $response = Response::getInstance(); - - // remove non US-ASCII to respect RFC2616 - $realm_message = preg_replace('/[^\x20-\x7e]/i', '', $realm_message); - $response->header('WWW-Authenticate: Basic realm="' . $realm_message . '"'); - $response->setHttpResponseCode(401); - - /* HTML header */ - $footer = $response->getFooter(); - $footer->setMinimal(); - $header = $response->getHeader(); - $header->setTitle(__('Access denied!')); - $header->disableMenuAndConsole(); - $header->setBodyId('loginform'); - - $response->addHTML('

    '); - $response->addHTML(sprintf(__('Welcome to %s'), ' phpMyAdmin')); - $response->addHTML('

    '); - $response->addHTML('

    '); - $response->addHTML( - Message::error( - __('Wrong username/password. Access denied.') - ) - ); - $response->addHTML('

    '); - - $response->addHTML(Config::renderFooter()); - - if (! defined('TESTSUITE')) { - exit; - } else { - return false; - } - } - - /** - * Gets authentication credentials - * - * @return boolean whether we get authentication settings or not - */ - public function readCredentials() - { - // Grabs the $PHP_AUTH_USER variable - if (isset($GLOBALS['PHP_AUTH_USER'])) { - $this->user = $GLOBALS['PHP_AUTH_USER']; - } - if (empty($this->user)) { - if (Core::getenv('PHP_AUTH_USER')) { - $this->user = Core::getenv('PHP_AUTH_USER'); - } elseif (Core::getenv('REMOTE_USER')) { - // CGI, might be encoded, see below - $this->user = Core::getenv('REMOTE_USER'); - } elseif (Core::getenv('REDIRECT_REMOTE_USER')) { - // CGI, might be encoded, see below - $this->user = Core::getenv('REDIRECT_REMOTE_USER'); - } elseif (Core::getenv('AUTH_USER')) { - // WebSite Professional - $this->user = Core::getenv('AUTH_USER'); - } elseif (Core::getenv('HTTP_AUTHORIZATION')) { - // IIS, might be encoded, see below - $this->user = Core::getenv('HTTP_AUTHORIZATION'); - } elseif (Core::getenv('Authorization')) { - // FastCGI, might be encoded, see below - $this->user = Core::getenv('Authorization'); - } - } - // Grabs the $PHP_AUTH_PW variable - if (isset($GLOBALS['PHP_AUTH_PW'])) { - $this->password = $GLOBALS['PHP_AUTH_PW']; - } - if (empty($this->password)) { - if (Core::getenv('PHP_AUTH_PW')) { - $this->password = Core::getenv('PHP_AUTH_PW'); - } elseif (Core::getenv('REMOTE_PASSWORD')) { - // Apache/CGI - $this->password = Core::getenv('REMOTE_PASSWORD'); - } elseif (Core::getenv('AUTH_PASSWORD')) { - // WebSite Professional - $this->password = Core::getenv('AUTH_PASSWORD'); - } - } - // Sanitize empty password login - if ($this->password === null) { - $this->password = ''; - } - - // Avoid showing the password in phpinfo()'s output - unset($GLOBALS['PHP_AUTH_PW']); - unset($_SERVER['PHP_AUTH_PW']); - - // 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($this->user, 0, 6), 'Basic ') == 0) { - $usr_pass = base64_decode(substr($this->user, 6)); - if (! empty($usr_pass)) { - $colon = strpos($usr_pass, ':'); - if ($colon) { - $this->user = substr($usr_pass, 0, $colon); - $this->password = substr($usr_pass, $colon + 1); - } - unset($colon); - } - unset($usr_pass); - } - - // sanitize username - $this->user = Core::sanitizeMySQLUser($this->user); - - // User logged out -> ensure the new username is not the same - $old_usr = isset($_REQUEST['old_usr']) ? $_REQUEST['old_usr'] : ''; - if (! empty($old_usr) - && (isset($this->user) && hash_equals($old_usr, $this->user)) - ) { - $this->user = ''; - } - - // Returns whether we get authentication settings or not - return ! empty($this->user); - } - - /** - * User is not allowed to login to MySQL -> authentication failed - * - * @param string $failure String describing why authentication has failed - * - * @return void - */ - public function showFailure($failure) - { - parent::showFailure($failure); - $error = $GLOBALS['dbi']->getError(); - if ($error && $GLOBALS['errno'] != 1045) { - Core::fatalError($error); - } else { - $this->authForm(); - } - } - - /** - * Returns URL for login form. - * - * @return string - */ - public function getLoginFormURL() - { - return './index.php?old_usr=' . $this->user; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationSignon.php b/srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationSignon.php deleted file mode 100644 index 36b1d66..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Auth/AuthenticationSignon.php +++ /dev/null @@ -1,282 +0,0 @@ -=')) { - session_set_cookie_params($sessionCookieParams); - } - - session_set_cookie_params( - $sessionCookieParams['lifetime'], - $sessionCookieParams['path'], - $sessionCookieParams['domain'], - $sessionCookieParams['secure'], - $sessionCookieParams['httponly'] - ); - } - - /** - * Gets authentication credentials - * - * @return boolean whether we get authentication settings or not - */ - public function readCredentials() - { - /* Check if we're using same signon server */ - $signon_url = $GLOBALS['cfg']['Server']['SignonURL']; - if (isset($_SESSION['LAST_SIGNON_URL']) - && $_SESSION['LAST_SIGNON_URL'] != $signon_url - ) { - return false; - } - - /* Script name */ - $script_name = $GLOBALS['cfg']['Server']['SignonScript']; - - /* Session name */ - $session_name = $GLOBALS['cfg']['Server']['SignonSession']; - - /* Login URL */ - $signon_url = $GLOBALS['cfg']['Server']['SignonURL']; - - /* Current host */ - $single_signon_host = $GLOBALS['cfg']['Server']['host']; - - /* Current port */ - $single_signon_port = $GLOBALS['cfg']['Server']['port']; - - /* No configuration updates */ - $single_signon_cfgupdate = []; - - /* Handle script based auth */ - if (! empty($script_name)) { - if (! @file_exists($script_name)) { - Core::fatalError( - __('Can not find signon authentication script:') - . ' ' . $script_name - ); - } - include $script_name; - - list ($this->user, $this->password) - = get_login_credentials($GLOBALS['cfg']['Server']['user']); - } elseif (isset($_COOKIE[$session_name])) { /* Does session exist? */ - /* End current session */ - $old_session = session_name(); - $old_id = session_id(); - $oldCookieParams = session_get_cookie_params(); - if (! defined('TESTSUITE')) { - session_write_close(); - } - /* Load single signon session */ - if (! defined('TESTSUITE')) { - $this->setCookieParams(); - session_name($session_name); - session_id($_COOKIE[$session_name]); - session_start(); - } - - /* Clear error message */ - unset($_SESSION['PMA_single_signon_error_message']); - - /* Grab credentials if they exist */ - if (isset($_SESSION['PMA_single_signon_user'])) { - $this->user = $_SESSION['PMA_single_signon_user']; - } - if (isset($_SESSION['PMA_single_signon_password'])) { - $this->password = $_SESSION['PMA_single_signon_password']; - } - if (isset($_SESSION['PMA_single_signon_host'])) { - $single_signon_host = $_SESSION['PMA_single_signon_host']; - } - - if (isset($_SESSION['PMA_single_signon_port'])) { - $single_signon_port = $_SESSION['PMA_single_signon_port']; - } - - if (isset($_SESSION['PMA_single_signon_cfgupdate'])) { - $single_signon_cfgupdate = $_SESSION['PMA_single_signon_cfgupdate']; - } - - /* Also get token as it is needed to access subpages */ - if (isset($_SESSION['PMA_single_signon_token'])) { - /* No need to care about token on logout */ - $pma_token = $_SESSION['PMA_single_signon_token']; - } - - /* End single signon session */ - if (! defined('TESTSUITE')) { - session_write_close(); - } - - /* Restart phpMyAdmin session */ - if (! defined('TESTSUITE')) { - $this->setCookieParams($oldCookieParams); - session_name($old_session); - if (! empty($old_id)) { - session_id($old_id); - } - session_start(); - } - - /* Set the single signon host */ - $GLOBALS['cfg']['Server']['host'] = $single_signon_host; - - /* Set the single signon port */ - $GLOBALS['cfg']['Server']['port'] = $single_signon_port; - - /* Configuration update */ - $GLOBALS['cfg']['Server'] = array_merge( - $GLOBALS['cfg']['Server'], - $single_signon_cfgupdate - ); - - /* Restore our token */ - if (! empty($pma_token)) { - $_SESSION[' PMA_token '] = $pma_token; - $_SESSION[' HMAC_secret '] = Util::generateRandom(16); - } - - /** - * Clear user cache. - */ - Util::clearUserCache(); - } - - // Returns whether we get authentication settings or not - if (empty($this->user)) { - unset($_SESSION['LAST_SIGNON_URL']); - - return false; - } - - $_SESSION['LAST_SIGNON_URL'] = $GLOBALS['cfg']['Server']['SignonURL']; - - return true; - } - - /** - * User is not allowed to login to MySQL -> authentication failed - * - * @param string $failure String describing why authentication has failed - * - * @return void - */ - public function showFailure($failure) - { - parent::showFailure($failure); - - /* Session name */ - $session_name = $GLOBALS['cfg']['Server']['SignonSession']; - - /* Does session exist? */ - if (isset($_COOKIE[$session_name])) { - if (! defined('TESTSUITE')) { - /* End current session */ - session_write_close(); - - /* Load single signon session */ - $this->setCookieParams(); - session_name($session_name); - session_id($_COOKIE[$session_name]); - session_start(); - } - - /* Set error message */ - $_SESSION['PMA_single_signon_error_message'] = $this->getErrorMessage($failure); - } - $this->showLoginForm(); - } - - /** - * Returns URL for login form. - * - * @return string - */ - public function getLoginFormURL() - { - return $GLOBALS['cfg']['Server']['SignonURL']; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/AuthenticationPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/AuthenticationPlugin.php deleted file mode 100644 index a275f49..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/AuthenticationPlugin.php +++ /dev/null @@ -1,371 +0,0 @@ -ipAllowDeny = new IpAllowDeny(); - $this->template = new Template(); - } - - /** - * Displays authentication form - * - * @return boolean - */ - abstract public function showLoginForm(); - - /** - * Gets authentication credentials - * - * @return boolean - */ - abstract public function readCredentials(); - - /** - * Set the user and password after last checkings if required - * - * @return boolean - */ - public function storeCredentials() - { - global $cfg; - - $this->setSessionAccessTime(); - - $cfg['Server']['user'] = $this->user; - $cfg['Server']['password'] = $this->password; - - return true; - } - - /** - * Stores user credentials after successful login. - * - * @return void - */ - public function rememberCredentials() - { - } - - /** - * User is not allowed to login to MySQL -> authentication failed - * - * @param string $failure String describing why authentication has failed - * - * @return void - */ - public function showFailure($failure) - { - Logging::logUser($this->user, $failure); - } - - /** - * Perform logout - * - * @return void - */ - public function logOut() - { - /** @var Config $PMA_Config */ - global $PMA_Config; - - /* Obtain redirect URL (before doing logout) */ - if (! empty($GLOBALS['cfg']['Server']['LogoutURL'])) { - $redirect_url = $GLOBALS['cfg']['Server']['LogoutURL']; - } else { - $redirect_url = $this->getLoginFormURL(); - } - - /* Clear credentials */ - $this->user = ''; - $this->password = ''; - - /* - * Get a logged-in server count in case of LoginCookieDeleteAll is disabled. - */ - $server = 0; - if ($GLOBALS['cfg']['LoginCookieDeleteAll'] === false - && $GLOBALS['cfg']['Server']['auth_type'] == 'cookie' - ) { - foreach ($GLOBALS['cfg']['Servers'] as $key => $val) { - if ($PMA_Config->issetCookie('pmaAuth-' . $key)) { - $server = $key; - } - } - } - - if ($server === 0) { - /* delete user's choices that were stored in session */ - if (! defined('TESTSUITE')) { - session_unset(); - session_destroy(); - } - - /* Redirect to login form (or configured URL) */ - Core::sendHeaderLocation($redirect_url); - } else { - /* Redirect to other autenticated server */ - $_SESSION['partial_logout'] = true; - Core::sendHeaderLocation( - './index.php' . Url::getCommonRaw(['server' => $server]) - ); - } - } - - /** - * Returns URL for login form. - * - * @return string - */ - public function getLoginFormURL() - { - return './index.php'; - } - - /** - * Returns error message for failed authentication. - * - * @param string $failure String describing why authentication has failed - * - * @return string - */ - public function getErrorMessage($failure) - { - if ($failure == 'empty-denied') { - return __( - 'Login without a password is forbidden by configuration' - . ' (see AllowNoPassword)' - ); - } elseif ($failure == 'root-denied' || $failure == 'allow-denied') { - return __('Access denied!'); - } elseif ($failure == 'no-activity') { - return sprintf( - __('No activity within %s seconds; please log in again.'), - intval($GLOBALS['cfg']['LoginCookieValidity']) - ); - } - - $dbi_error = $GLOBALS['dbi']->getError(); - if (! empty($dbi_error)) { - return htmlspecialchars($dbi_error); - } elseif (isset($GLOBALS['errno'])) { - return '#' . $GLOBALS['errno'] . ' ' - . __('Cannot log in to the MySQL server'); - } - - return __('Cannot log in to the MySQL server'); - } - - /** - * Callback when user changes password. - * - * @param string $password New password to set - * - * @return void - */ - public function handlePasswordChange($password) - { - } - - /** - * Store session access time in session. - * - * Tries to workaround PHP 5 session garbage collection which - * looks at the session file's last modified time - * - * @return void - */ - public function setSessionAccessTime() - { - if (isset($_REQUEST['guid'])) { - $guid = (string) $_REQUEST['guid']; - } else { - $guid = 'default'; - } - if (isset($_REQUEST['access_time'])) { - // Ensure access_time is in range <0, LoginCookieValidity + 1> - // to avoid excessive extension of validity. - // - // Negative values can cause session expiry extension - // Too big values can cause overflow and lead to same - $time = time() - min(max(0, intval($_REQUEST['access_time'])), $GLOBALS['cfg']['LoginCookieValidity'] + 1); - } else { - $time = time(); - } - $_SESSION['browser_access_time'][$guid] = $time; - } - - /** - * High level authentication interface - * - * Gets the credentials or shows login form if necessary - * - * @return void - */ - public function authenticate() - { - $success = $this->readCredentials(); - - /* Show login form (this exits) */ - if (! $success) { - /* Force generating of new session */ - Session::secure(); - $this->showLoginForm(); - } - - /* Store credentials (eg. in cookies) */ - $this->storeCredentials(); - /* Check allow/deny rules */ - $this->checkRules(); - } - - /** - * Check configuration defined restrictions for authentication - * - * @return void - */ - public function checkRules() - { - global $cfg; - - // Check IP-based Allow/Deny rules as soon as possible to reject the - // user based on mod_access in Apache - if (isset($cfg['Server']['AllowDeny']) - && isset($cfg['Server']['AllowDeny']['order']) - ) { - $allowDeny_forbidden = false; // default - if ($cfg['Server']['AllowDeny']['order'] == 'allow,deny') { - $allowDeny_forbidden = true; - if ($this->ipAllowDeny->allow()) { - $allowDeny_forbidden = false; - } - if ($this->ipAllowDeny->deny()) { - $allowDeny_forbidden = true; - } - } elseif ($cfg['Server']['AllowDeny']['order'] == 'deny,allow') { - if ($this->ipAllowDeny->deny()) { - $allowDeny_forbidden = true; - } - if ($this->ipAllowDeny->allow()) { - $allowDeny_forbidden = false; - } - } elseif ($cfg['Server']['AllowDeny']['order'] == 'explicit') { - if ($this->ipAllowDeny->allow() && ! $this->ipAllowDeny->deny()) { - $allowDeny_forbidden = false; - } else { - $allowDeny_forbidden = true; - } - } // end if ... elseif ... elseif - - // Ejects the user if banished - if ($allowDeny_forbidden) { - $this->showFailure('allow-denied'); - } - } // end if - - // is root allowed? - if (! $cfg['Server']['AllowRoot'] && $cfg['Server']['user'] == 'root') { - $this->showFailure('root-denied'); - } - - // is a login without password allowed? - if (! $cfg['Server']['AllowNoPassword'] - && $cfg['Server']['password'] === '' - ) { - $this->showFailure('empty-denied'); - } - } - - /** - * Checks whether two factor authentication is active - * for given user and performs it. - * - * @return boolean|void - */ - public function checkTwoFactor() - { - $twofactor = new TwoFactor($this->user); - - /* Do we need to show the form? */ - if ($twofactor->check()) { - return; - } - - $response = Response::getInstance(); - if ($response->loginPage()) { - if (defined('TESTSUITE')) { - return; - } else { - exit; - } - } - echo $this->template->render('login/header', ['theme' => $GLOBALS['PMA_Theme']]); - Message::rawNotice( - __('You have enabled two factor authentication, please confirm your login.') - )->display(); - echo $this->template->render('login/twofactor', [ - 'form' => $twofactor->render(), - 'show_submit' => $twofactor->showSubmit, - ]); - echo $this->template->render('login/footer'); - echo Config::renderFooter(); - if (! defined('TESTSUITE')) { - exit; - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCodegen.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCodegen.php deleted file mode 100644 index 8a29538..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCodegen.php +++ /dev/null @@ -1,447 +0,0 @@ -initSpecificVariables(); - $this->setProperties(); - } - - /** - * Initialize the local variables that are used for export CodeGen - * - * @return void - */ - protected function initSpecificVariables() - { - $this->_setCgFormats( - [ - "NHibernate C# DO", - "NHibernate XML", - ] - ); - - $this->_setCgHandlers( - [ - "_handleNHibernateCSBody", - "_handleNHibernateXMLBody", - ] - ); - } - - /** - * Sets the export CodeGen properties - * - * @return void - */ - protected function setProperties() - { - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('CodeGen'); - $exportPluginProperties->setExtension('cs'); - $exportPluginProperties->setMimeType('text/cs'); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - // create primary items and add them to the group - $leaf = new HiddenPropertyItem("structure_or_data"); - $generalOptions->addProperty($leaf); - $leaf = new SelectPropertyItem( - "format", - __('Format:') - ); - $leaf->setValues($this->_getCgFormats()); - $generalOptions->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($generalOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - return true; - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter() - { - return true; - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - return true; - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs the content of a table in NHibernate format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - $CG_FORMATS = $this->_getCgFormats(); - $CG_HANDLERS = $this->_getCgHandlers(); - - $format = $GLOBALS['codegen_format']; - if (isset($CG_FORMATS[$format])) { - $method = $CG_HANDLERS[$format]; - - return $this->export->outputHandler( - $this->$method($db, $table, $crlf, $aliases) - ); - } - - return $this->export->outputHandler(sprintf("%s is not supported.", $format)); - } - - /** - * Used to make identifiers (from table or database names) - * - * @param string $str name to be converted - * @param bool $ucfirst whether to make the first character uppercase - * - * @return string identifier - */ - public static function cgMakeIdentifier($str, $ucfirst = true) - { - // remove unsafe characters - $str = preg_replace('/[^\p{L}\p{Nl}_]/u', '', $str); - // make sure first character is a letter or _ - if (! preg_match('/^\pL/u', $str)) { - $str = '_' . $str; - } - if ($ucfirst) { - $str = ucfirst($str); - } - - return $str; - } - - /** - * C# Handler - * - * @param string $db database name - * @param string $table table name - * @param string $crlf line separator - * @param array $aliases Aliases of db/table/columns - * - * @return string containing C# code lines, separated by "\n" - */ - private function _handleNHibernateCSBody($db, $table, $crlf, array $aliases = []) - { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - $lines = []; - - $result = $GLOBALS['dbi']->query( - sprintf( - 'DESC %s.%s', - Util::backquote($db), - Util::backquote($table) - ) - ); - if ($result) { - /** @var TableProperty[] $tableProperties */ - $tableProperties = []; - while ($row = $GLOBALS['dbi']->fetchRow($result)) { - $col_as = $this->getAlias($aliases, $row[0], 'col', $db, $table); - if (! empty($col_as)) { - $row[0] = $col_as; - } - $tableProperties[] = new TableProperty($row); - } - $GLOBALS['dbi']->freeResult($result); - $lines[] = 'using System;'; - $lines[] = 'using System.Collections;'; - $lines[] = 'using System.Collections.Generic;'; - $lines[] = 'using System.Text;'; - $lines[] = 'namespace ' . ExportCodegen::cgMakeIdentifier($db_alias); - $lines[] = '{'; - $lines[] = ' #region ' - . ExportCodegen::cgMakeIdentifier($table_alias); - $lines[] = ' public class ' - . ExportCodegen::cgMakeIdentifier($table_alias); - $lines[] = ' {'; - $lines[] = ' #region Member Variables'; - foreach ($tableProperties as $tableProperty) { - $lines[] = $tableProperty->formatCs( - ' protected #dotNetPrimitiveType# _#name#;' - ); - } - $lines[] = ' #endregion'; - $lines[] = ' #region Constructors'; - $lines[] = ' public ' - . ExportCodegen::cgMakeIdentifier($table_alias) . '() { }'; - $temp = []; - foreach ($tableProperties as $tableProperty) { - if (! $tableProperty->isPK()) { - $temp[] = $tableProperty->formatCs( - '#dotNetPrimitiveType# #name#' - ); - } - } - $lines[] = ' public ' - . ExportCodegen::cgMakeIdentifier($table_alias) - . '(' - . implode(', ', $temp) - . ')'; - $lines[] = ' {'; - foreach ($tableProperties as $tableProperty) { - if (! $tableProperty->isPK()) { - $lines[] = $tableProperty->formatCs( - ' this._#name#=#name#;' - ); - } - } - $lines[] = ' }'; - $lines[] = ' #endregion'; - $lines[] = ' #region Public Properties'; - foreach ($tableProperties as $tableProperty) { - $lines[] = $tableProperty->formatCs( - ' public virtual #dotNetPrimitiveType# #ucfirstName#' - . "\n" - . ' {' . "\n" - . ' get {return _#name#;}' . "\n" - . ' set {_#name#=value;}' . "\n" - . ' }' - ); - } - $lines[] = ' #endregion'; - $lines[] = ' }'; - $lines[] = ' #endregion'; - $lines[] = '}'; - } - - return implode($crlf, $lines); - } - - /** - * XML Handler - * - * @param string $db database name - * @param string $table table name - * @param string $crlf line separator - * @param array $aliases Aliases of db/table/columns - * - * @return string containing XML code lines, separated by "\n" - */ - private function _handleNHibernateXMLBody( - $db, - $table, - $crlf, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - $lines = []; - $lines[] = ''; - $lines[] = ''; - $lines[] = ' '; - $result = $GLOBALS['dbi']->query( - sprintf( - "DESC %s.%s", - Util::backquote($db), - Util::backquote($table) - ) - ); - if ($result) { - while ($row = $GLOBALS['dbi']->fetchRow($result)) { - $col_as = $this->getAlias($aliases, $row[0], 'col', $db, $table); - if (! empty($col_as)) { - $row[0] = $col_as; - } - $tableProperty = new TableProperty($row); - if ($tableProperty->isPK()) { - $lines[] = $tableProperty->formatXml( - ' ' . "\n" - . ' ' . "\n" - . ' ' . "\n" - . ' ' - ); - } else { - $lines[] = $tableProperty->formatXml( - ' ' . "\n" - . ' ' . "\n" - . ' ' - ); - } - } - $GLOBALS['dbi']->freeResult($result); - } - $lines[] = ' '; - $lines[] = ''; - - return implode($crlf, $lines); - } - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Getter for CodeGen formats - * - * @return array - */ - private function _getCgFormats() - { - return $this->_cgFormats; - } - - /** - * Setter for CodeGen formats - * - * @param array $CG_FORMATS contains CodeGen Formats - * - * @return void - */ - private function _setCgFormats(array $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(array $CG_HANDLERS) - { - $this->_cgHandlers = $CG_HANDLERS; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCsv.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCsv.php deleted file mode 100644 index 8e5a319..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCsv.php +++ /dev/null @@ -1,347 +0,0 @@ -setProperties(); - } - - /** - * Sets the export CSV properties - * - * @return void - */ - protected function setProperties() - { - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('CSV'); - $exportPluginProperties->setExtension('csv'); - $exportPluginProperties->setMimeType('text/comma-separated-values'); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - // create leaf items and add them to the group - $leaf = new TextPropertyItem( - "separator", - __('Columns separated with:') - ); - $generalOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - "enclosed", - __('Columns enclosed with:') - ); - $generalOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - "escaped", - __('Columns escaped with:') - ); - $generalOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - "terminated", - __('Lines terminated with:') - ); - $generalOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - 'null', - __('Replace NULL with:') - ); - $generalOptions->addProperty($leaf); - $leaf = new BoolPropertyItem( - 'removeCRLF', - __('Remove carriage return/line feed characters within columns') - ); - $generalOptions->addProperty($leaf); - $leaf = new BoolPropertyItem( - 'columns', - __('Put columns names in the first row') - ); - $generalOptions->addProperty($leaf); - $leaf = new HiddenPropertyItem( - 'structure_or_data' - ); - $generalOptions->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($generalOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped; - //Enable columns names by default for CSV - if ($what == 'csv') { - $GLOBALS['csv_columns'] = 'yes'; - } - // Here we just prepare some values for export - if ($what == 'excel') { - $csv_terminated = "\015\012"; - switch ($GLOBALS['excel_edition']) { - case 'win': - // as tested on Windows with Excel 2002 and Excel 2007 - $csv_separator = ';'; - break; - case 'mac_excel2003': - $csv_separator = ';'; - break; - case 'mac_excel2008': - $csv_separator = ','; - break; - } - $csv_enclosed = '"'; - $csv_escaped = '"'; - if (isset($GLOBALS['excel_columns'])) { - $GLOBALS['csv_columns'] = 'yes'; - } - } else { - if (empty($csv_terminated) - || mb_strtolower($csv_terminated) == 'auto' - ) { - $csv_terminated = $GLOBALS['crlf']; - } else { - $csv_terminated = str_replace( - [ - '\\r', - '\\n', - '\\t', - ], - [ - "\015", - "\012", - "\011", - ], - $csv_terminated - ); - } // end if - $csv_separator = str_replace('\\t', "\011", $csv_separator); - } - - return true; - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter() - { - return true; - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Alias of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - return true; - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs the content of a table in CSV format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped; - - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - // Gets the data from the database - $result = $GLOBALS['dbi']->query( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - $fields_cnt = $GLOBALS['dbi']->numFields($result); - - // If required, get fields name at the first line - if (isset($GLOBALS['csv_columns'])) { - $schema_insert = ''; - for ($i = 0; $i < $fields_cnt; $i++) { - $col_as = $GLOBALS['dbi']->fieldName($result, $i); - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $col_as = stripslashes($col_as); - if ($csv_enclosed == '') { - $schema_insert .= $col_as; - } else { - $schema_insert .= $csv_enclosed - . str_replace( - $csv_enclosed, - $csv_escaped . $csv_enclosed, - $col_as - ) - . $csv_enclosed; - } - $schema_insert .= $csv_separator; - } // end for - $schema_insert = trim(mb_substr($schema_insert, 0, -1)); - if (! $this->export->outputHandler($schema_insert . $csv_terminated)) { - return false; - } - } // end if - - // Format the data - while ($row = $GLOBALS['dbi']->fetchRow($result)) { - $schema_insert = ''; - for ($j = 0; $j < $fields_cnt; $j++) { - if (! isset($row[$j]) || $row[$j] === null) { - $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( - [ - "\r", - "\n", - ], - "", - $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 (! $this->export->outputHandler($schema_insert . $csv_terminated)) { - return false; - } - } // end while - $GLOBALS['dbi']->freeResult($result); - - return true; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportExcel.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportExcel.php deleted file mode 100644 index e778d20..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportExcel.php +++ /dev/null @@ -1,90 +0,0 @@ -setText('CSV for MS Excel'); - $exportPluginProperties->setExtension('csv'); - $exportPluginProperties->setMimeType('text/comma-separated-values'); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - // create primary items and add them to the group - $leaf = new TextPropertyItem( - 'null', - __('Replace NULL with:') - ); - $generalOptions->addProperty($leaf); - $leaf = new BoolPropertyItem( - 'removeCRLF', - __('Remove carriage return/line feed characters within columns') - ); - $generalOptions->addProperty($leaf); - $leaf = new BoolPropertyItem( - 'columns', - __('Put columns names in the first row') - ); - $generalOptions->addProperty($leaf); - $leaf = new SelectPropertyItem( - 'edition', - __('Excel edition:') - ); - $leaf->setValues( - [ - 'win' => 'Windows', - 'mac_excel2003' => 'Excel 2003 / Macintosh', - 'mac_excel2008' => 'Excel 2008 / Macintosh', - ] - ); - $generalOptions->addProperty($leaf); - $leaf = new HiddenPropertyItem( - 'structure_or_data' - ); - $generalOptions->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($generalOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportHtmlword.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportHtmlword.php deleted file mode 100644 index cbf4fce..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportHtmlword.php +++ /dev/null @@ -1,670 +0,0 @@ -setProperties(); - } - - /** - * Sets the export HTML-Word properties - * - * @return void - */ - protected function setProperties() - { - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('Microsoft Word 2000'); - $exportPluginProperties->setExtension('doc'); - $exportPluginProperties->setMimeType('application/vnd.ms-word'); - $exportPluginProperties->setForceFile(true); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // what to dump (structure/data/both) - $dumpWhat = new OptionsPropertyMainGroup( - "dump_what", - __('Dump table') - ); - // create primary items and add them to the group - $leaf = new RadioPropertyItem("structure_or_data"); - $leaf->setValues( - [ - 'structure' => __('structure'), - 'data' => __('data'), - 'structure_and_data' => __('structure and data'), - ] - ); - $dumpWhat->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($dumpWhat); - - // data options main group - $dataOptions = new OptionsPropertyMainGroup( - "dump_what", - __('Data dump options') - ); - $dataOptions->setForce('structure'); - // create primary items and add them to the group - $leaf = new TextPropertyItem( - "null", - __('Replace NULL with:') - ); - $dataOptions->addProperty($leaf); - $leaf = new BoolPropertyItem( - "columns", - __('Put columns names in the first row') - ); - $dataOptions->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($dataOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - global $charset; - - return $this->export->outputHandler( - ' - - - - - - - ' - ); - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter() - { - return $this->export->outputHandler(''); - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - if (empty($db_alias)) { - $db_alias = $db; - } - - return $this->export->outputHandler( - '

    ' . __('Database') . ' ' . htmlspecialchars($db_alias) . '

    ' - ); - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs the content of a table in HTML-Word format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - global $what; - - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - if (! $this->export->outputHandler( - '

    ' - . __('Dumping data for table') . ' ' . htmlspecialchars($table_alias) - . '

    ' - ) - ) { - return false; - } - if (! $this->export->outputHandler( - '' - ) - ) { - return false; - } - - // Gets the data from the database - $result = $GLOBALS['dbi']->query( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - $fields_cnt = $GLOBALS['dbi']->numFields($result); - - // If required, get fields name at the first line - if (isset($GLOBALS['htmlword_columns'])) { - $schema_insert = ''; - for ($i = 0; $i < $fields_cnt; $i++) { - $col_as = $GLOBALS['dbi']->fieldName($result, $i); - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $col_as = stripslashes($col_as); - $schema_insert .= ''; - } // end for - $schema_insert .= ''; - if (! $this->export->outputHandler($schema_insert)) { - return false; - } - } // end if - - // Format the data - while ($row = $GLOBALS['dbi']->fetchRow($result)) { - $schema_insert = ''; - for ($j = 0; $j < $fields_cnt; $j++) { - if (! isset($row[$j]) || $row[$j] === null) { - $value = $GLOBALS[$what . '_null']; - } elseif ($row[$j] == '0' || $row[$j] != '') { - $value = $row[$j]; - } else { - $value = ''; - } - $schema_insert .= ''; - } // end for - $schema_insert .= ''; - if (! $this->export->outputHandler($schema_insert)) { - return false; - } - } // end while - $GLOBALS['dbi']->freeResult($result); - - return $this->export->outputHandler('
    '); - } - - /** - * Returns a stand-in CREATE definition to resolve view dependencies - * - * @param string $db the database name - * @param string $view the view name - * @param string $crlf the end of line sequence - * @param array $aliases Aliases of db/table/columns - * - * @return string resulting definition - */ - public function getTableDefStandIn($db, $view, $crlf, $aliases = []) - { - $schema_insert = '' - . '' - . '' - . '' - . '' - . '' - . ''; - - /** - * Get the unique keys in the view - */ - $unique_keys = []; - $keys = $GLOBALS['dbi']->getTableIndexes($db, $view); - foreach ($keys as $key) { - if ($key['Non_unique'] == 0) { - $unique_keys[] = $key['Column_name']; - } - } - - $columns = $GLOBALS['dbi']->getColumns($db, $view); - foreach ($columns as $column) { - $col_as = $column['Field']; - if (! empty($aliases[$db]['tables'][$view]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$view]['columns'][$col_as]; - } - $schema_insert .= $this->formatOneColumnDefinition( - $column, - $unique_keys, - $col_as - ); - $schema_insert .= ''; - } - - $schema_insert .= '
    '; - - return $schema_insert; - } - - /** - * Returns $table's CREATE definition - * - * @param string $db the database name - * @param string $table the table name - * @param bool $do_relation whether to include relation comments - * @param bool $do_comments whether to include the pmadb-style column - * comments as comments in the structure; - * this is deprecated but the parameter is - * left here because export.php calls - * PMA_exportStructure() also for other - * export types which use this parameter - * @param bool $do_mime whether to include mime comments - * at the end - * @param bool $view whether we're handling a view - * @param array $aliases Aliases of db/table/columns - * - * @return string resulting schema - */ - public function getTableDef( - $db, - $table, - $do_relation, - $do_comments, - $do_mime, - $view = false, - array $aliases = [] - ) { - // set $cfgRelation here, because there is a chance that it's modified - // since the class initialization - global $cfgRelation; - - $schema_insert = ''; - - /** - * Gets fields properties - */ - $GLOBALS['dbi']->selectDb($db); - - // Check if we can use Relations - list($res_rel, $have_rel) = $this->relation->getRelationsAndStatus( - $do_relation && ! empty($cfgRelation['relation']), - $db, - $table - ); - - /** - * Displays the table structure - */ - $schema_insert .= ''; - - $schema_insert .= ''; - $schema_insert .= ''; - $schema_insert .= ''; - $schema_insert .= ''; - $schema_insert .= ''; - if ($do_relation && $have_rel) { - $schema_insert .= ''; - } - if ($do_comments) { - $schema_insert .= ''; - $comments = $this->relation->getComments($db, $table); - } - if ($do_mime && $cfgRelation['mimework']) { - $schema_insert .= ''; - $mime_map = $this->transformations->getMime($db, $table, true); - } - $schema_insert .= ''; - - $columns = $GLOBALS['dbi']->getColumns($db, $table); - /** - * Get the unique keys in the table - */ - $unique_keys = []; - $keys = $GLOBALS['dbi']->getTableIndexes($db, $table); - foreach ($keys as $key) { - if ($key['Non_unique'] == 0) { - $unique_keys[] = $key['Column_name']; - } - } - foreach ($columns as $column) { - $col_as = $column['Field']; - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $schema_insert .= $this->formatOneColumnDefinition( - $column, - $unique_keys, - $col_as - ); - $field_name = $column['Field']; - if ($do_relation && $have_rel) { - $schema_insert .= ''; - } - if ($do_comments && $cfgRelation['commwork']) { - $schema_insert .= ''; - } - if ($do_mime && $cfgRelation['mimework']) { - $schema_insert .= ''; - } - - $schema_insert .= ''; - } // end foreach - - $schema_insert .= '
    ' - . htmlspecialchars( - $this->getRelationString( - $res_rel, - $field_name, - $db, - $aliases - ) - ) - . '' - . (isset($comments[$field_name]) - ? htmlspecialchars($comments[$field_name]) - : '') . '' - . (isset($mime_map[$field_name]) ? - htmlspecialchars( - str_replace('_', '/', $mime_map[$field_name]['mimetype']) - ) - : '') . '
    '; - - return $schema_insert; - } - - /** - * Outputs triggers - * - * @param string $db database name - * @param string $table table name - * - * @return string Formatted triggers list - */ - protected function getTriggers($db, $table) - { - $dump = ''; - $dump .= ''; - $dump .= ''; - $dump .= ''; - $dump .= ''; - $dump .= ''; - $dump .= ''; - - $triggers = $GLOBALS['dbi']->getTriggers($db, $table); - - foreach ($triggers as $trigger) { - $dump .= ''; - $dump .= '' - . '' - . '' - . '' - . ''; - } - - $dump .= '
    '; - - return $dump; - } - - /** - * Outputs table's structure - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $export_mode 'create_table', 'triggers', 'create_view', - * 'stand_in' - * @param string $export_type 'server', 'database', 'table' - * @param bool $do_relation whether to include relation comments - * @param bool $do_comments whether to include the pmadb-style column - * comments as comments in the structure; - * this is deprecated but the parameter is - * left here because export.php calls - * PMA_exportStructure() also for other - * export types which use this parameter - * @param bool $do_mime whether to include mime comments - * @param bool $dates whether to include creation/update/check dates - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportStructure( - $db, - $table, - $crlf, - $error_url, - $export_mode, - $export_type, - $do_relation = false, - $do_comments = false, - $do_mime = false, - $dates = false, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - $dump = ''; - - switch ($export_mode) { - case 'create_table': - $dump .= '

    ' - . __('Table structure for table') . ' ' - . htmlspecialchars($table_alias) - . '

    '; - $dump .= $this->getTableDef( - $db, - $table, - $do_relation, - $do_comments, - $do_mime, - false, - $aliases - ); - break; - case 'triggers': - $dump = ''; - $triggers = $GLOBALS['dbi']->getTriggers($db, $table); - if ($triggers) { - $dump .= '

    ' - . __('Triggers') . ' ' . htmlspecialchars($table_alias) - . '

    '; - $dump .= $this->getTriggers($db, $table); - } - break; - case 'create_view': - $dump .= '

    ' - . __('Structure for view') . ' ' . htmlspecialchars($table_alias) - . '

    '; - $dump .= $this->getTableDef( - $db, - $table, - $do_relation, - $do_comments, - $do_mime, - true, - $aliases - ); - break; - case 'stand_in': - $dump .= '

    ' - . __('Stand-in structure for view') . ' ' - . htmlspecialchars($table_alias) - . '

    '; - // export a stand-in definition to resolve view dependencies - $dump .= $this->getTableDefStandIn($db, $table, $crlf, $aliases); - } // end switch - - return $this->export->outputHandler($dump); - } - - /** - * Formats the definition for one column - * - * @param array $column info about this column - * @param array $unique_keys unique keys of the table - * @param string $col_alias Column Alias - * - * @return string Formatted column definition - */ - protected function formatOneColumnDefinition( - array $column, - array $unique_keys, - $col_alias = '' - ) { - if (empty($col_alias)) { - $col_alias = $column['Field']; - } - $definition = ''; - - $extracted_columnspec = 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 .= ''; - } - if ($column['Key'] == 'PRI') { - $fmt_pre = '' . $fmt_pre; - $fmt_post .= ''; - } - $definition .= '' . $fmt_pre - . htmlspecialchars($col_alias) . $fmt_post . ''; - $definition .= '' . htmlspecialchars($type) . ''; - $definition .= '' - . (($column['Null'] == '' || $column['Null'] == 'NO') - ? __('No') - : __('Yes')) - . ''; - $definition .= '' - . htmlspecialchars(isset($column['Default']) ? $column['Default'] : '') - . ''; - - return $definition; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportJson.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportJson.php deleted file mode 100644 index 4ebfbbe..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportJson.php +++ /dev/null @@ -1,295 +0,0 @@ -setProperties(); - } - - /** - * Encodes the data into JSON - * - * @param mixed $data Data to encode - * - * @return string - */ - public function encode($data) - { - $options = 0; - if (isset($GLOBALS['json_pretty_print']) - && $GLOBALS['json_pretty_print'] - ) { - $options |= JSON_PRETTY_PRINT; - } - if (isset($GLOBALS['json_unicode']) - && $GLOBALS['json_unicode'] - ) { - $options |= JSON_UNESCAPED_UNICODE; - } - return json_encode($data, $options); - } - - /** - * Sets the export JSON properties - * - * @return void - */ - protected function setProperties() - { - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('JSON'); - $exportPluginProperties->setExtension('json'); - $exportPluginProperties->setMimeType('text/plain'); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - // create primary items and add them to the group - $leaf = new HiddenPropertyItem("structure_or_data"); - $generalOptions->addProperty($leaf); - - $leaf = new BoolPropertyItem( - 'pretty_print', - __('Output pretty-printed JSON (Use human-readable formatting)') - ); - $generalOptions->addProperty($leaf); - - $leaf = new BoolPropertyItem( - 'unicode', - __('Output unicode characters unescaped') - ); - $generalOptions->addProperty($leaf); - - // add the main group to the root group - $exportSpecificOptions->addProperty($generalOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - global $crlf; - - $meta = [ - 'type' => 'header', - 'version' => PMA_VERSION, - 'comment' => 'Export to JSON plugin for PHPMyAdmin', - ]; - - return $this->export->outputHandler( - '[' . $crlf . $this->encode($meta) . ',' . $crlf - ); - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter() - { - global $crlf; - - return $this->export->outputHandler(']' . $crlf); - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - global $crlf; - - if (empty($db_alias)) { - $db_alias = $db; - } - - $meta = [ - 'type' => 'database', - 'name' => $db_alias, - ]; - - return $this->export->outputHandler( - $this->encode($meta) . ',' . $crlf - ); - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs the content of a table in JSON format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - if (! $this->first) { - if (! $this->export->outputHandler(',')) { - return false; - } - } else { - $this->first = false; - } - - $buffer = $this->encode( - [ - 'type' => 'table', - 'name' => $table_alias, - 'database' => $db_alias, - 'data' => "@@DATA@@", - ] - ); - list($header, $footer) = explode('"@@DATA@@"', $buffer); - - if (! $this->export->outputHandler($header . $crlf . '[' . $crlf)) { - return false; - } - - $result = $GLOBALS['dbi']->query( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - $columns_cnt = $GLOBALS['dbi']->numFields($result); - $fieldsMeta = $GLOBALS['dbi']->getFieldsMeta($result); - - $columns = []; - for ($i = 0; $i < $columns_cnt; $i++) { - $col_as = $GLOBALS['dbi']->fieldName($result, $i); - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $columns[$i] = stripslashes($col_as); - } - - $record_cnt = 0; - while ($record = $GLOBALS['dbi']->fetchRow($result)) { - $record_cnt++; - - // Output table name as comment if this is the first record of the table - if ($record_cnt > 1) { - if (! $this->export->outputHandler(',' . $crlf)) { - return false; - } - } - - $data = []; - - for ($i = 0; $i < $columns_cnt; $i++) { - if ($fieldsMeta[$i]->type === 'geometry') { - // export GIS types as hex - $record[$i] = '0x' . bin2hex($record[$i]); - } - $data[$columns[$i]] = $record[$i]; - } - - $encodedData = $this->encode($data); - if (! $encodedData) { - return false; - } - if (! $this->export->outputHandler($encodedData)) { - return false; - } - } - - if (! $this->export->outputHandler($crlf . ']' . $crlf . $footer . $crlf)) { - return false; - } - - $GLOBALS['dbi']->freeResult($result); - - return true; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportLatex.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportLatex.php deleted file mode 100644 index e215300..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportLatex.php +++ /dev/null @@ -1,709 +0,0 @@ -initSpecificVariables(); - $this->setProperties(); - } - - /** - * Initialize the local variables that are used for export Latex - * - * @return void - */ - protected function initSpecificVariables() - { - /* Messages used in default captions */ - $GLOBALS['strLatexContent'] = __('Content of table @TABLE@'); - $GLOBALS['strLatexContinued'] = __('(continued)'); - $GLOBALS['strLatexStructure'] = __('Structure of table @TABLE@'); - } - - /** - * Sets the export Latex properties - * - * @return void - */ - protected function setProperties() - { - global $plugin_param; - $hide_structure = false; - if ($plugin_param['export_type'] == 'table' - && ! $plugin_param['single_table'] - ) { - $hide_structure = true; - } - - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('LaTeX'); - $exportPluginProperties->setExtension('tex'); - $exportPluginProperties->setMimeType('application/x-tex'); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - // create primary items and add them to the group - $leaf = new BoolPropertyItem( - "caption", - __('Include table caption') - ); - $generalOptions->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($generalOptions); - - // what to dump (structure/data/both) main group - $dumpWhat = new OptionsPropertyMainGroup( - "dump_what", - __('Dump table') - ); - // create primary items and add them to the group - $leaf = new RadioPropertyItem("structure_or_data"); - $leaf->setValues( - [ - 'structure' => __('structure'), - 'data' => __('data'), - 'structure_and_data' => __('structure and data'), - ] - ); - $dumpWhat->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($dumpWhat); - - // structure options main group - if (! $hide_structure) { - $structureOptions = new OptionsPropertyMainGroup( - "structure", - __('Object creation options') - ); - $structureOptions->setForce('data'); - // create primary items and add them to the group - $leaf = new TextPropertyItem( - "structure_caption", - __('Table caption:') - ); - $leaf->setDoc('faq6-27'); - $structureOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - "structure_continued_caption", - __('Table caption (continued):') - ); - $leaf->setDoc('faq6-27'); - $structureOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - "structure_label", - __('Label key:') - ); - $leaf->setDoc('faq6-27'); - $structureOptions->addProperty($leaf); - if (! empty($GLOBALS['cfgRelation']['relation'])) { - $leaf = new BoolPropertyItem( - "relation", - __('Display foreign key relationships') - ); - $structureOptions->addProperty($leaf); - } - $leaf = new BoolPropertyItem( - "comments", - __('Display comments') - ); - $structureOptions->addProperty($leaf); - if (! empty($GLOBALS['cfgRelation']['mimework'])) { - $leaf = new BoolPropertyItem( - "mime", - __('Display media (MIME) types') - ); - $structureOptions->addProperty($leaf); - } - // add the main group to the root group - $exportSpecificOptions->addProperty($structureOptions); - } - - // data options main group - $dataOptions = new OptionsPropertyMainGroup( - "data", - __('Data dump options') - ); - $dataOptions->setForce('structure'); - // create primary items and add them to the group - $leaf = new BoolPropertyItem( - "columns", - __('Put columns names in the first row:') - ); - $dataOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - "data_caption", - __('Table caption:') - ); - $leaf->setDoc('faq6-27'); - $dataOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - "data_continued_caption", - __('Table caption (continued):') - ); - $leaf->setDoc('faq6-27'); - $dataOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - "data_label", - __('Label key:') - ); - $leaf->setDoc('faq6-27'); - $dataOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - 'null', - __('Replace NULL with:') - ); - $dataOptions->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($dataOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - global $crlf; - global $cfg; - - $head = '% phpMyAdmin LaTeX Dump' . $crlf - . '% version ' . PMA_VERSION . $crlf - . '% https://www.phpmyadmin.net/' . $crlf - . '%' . $crlf - . '% ' . __('Host:') . ' ' . $cfg['Server']['host']; - if (! empty($cfg['Server']['port'])) { - $head .= ':' . $cfg['Server']['port']; - } - $head .= $crlf - . '% ' . __('Generation Time:') . ' ' - . Util::localisedDate() . $crlf - . '% ' . __('Server version:') . ' ' . $GLOBALS['dbi']->getVersionString() . $crlf - . '% ' . __('PHP Version:') . ' ' . PHP_VERSION . $crlf; - - return $this->export->outputHandler($head); - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter() - { - return true; - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - if (empty($db_alias)) { - $db_alias = $db; - } - global $crlf; - $head = '% ' . $crlf - . '% ' . __('Database:') . ' \'' . $db_alias . '\'' . $crlf - . '% ' . $crlf; - - return $this->export->outputHandler($head); - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs the content of a table in JSON format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - $result = $GLOBALS['dbi']->tryQuery( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - - $columns_cnt = $GLOBALS['dbi']->numFields($result); - $columns = []; - $columns_alias = []; - for ($i = 0; $i < $columns_cnt; $i++) { - $columns[$i] = $col_as = $GLOBALS['dbi']->fieldName($result, $i); - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $columns_alias[$i] = $col_as; - } - - $buffer = $crlf . '%' . $crlf . '% ' . __('Data:') . ' ' . $table_alias - . $crlf . '%' . $crlf . ' \\begin{longtable}{|'; - - for ($index = 0; $index < $columns_cnt; $index++) { - $buffer .= 'l|'; - } - $buffer .= '} ' . $crlf; - - $buffer .= ' \\hline \\endhead \\hline \\endfoot \\hline ' . $crlf; - if (isset($GLOBALS['latex_caption'])) { - $buffer .= ' \\caption{' - . Util::expandUserString( - $GLOBALS['latex_data_caption'], - [ - 'texEscape', - static::class, - ], - [ - 'table' => $table_alias, - 'database' => $db_alias, - ] - ) - . '} \\label{' - . Util::expandUserString( - $GLOBALS['latex_data_label'], - null, - [ - 'table' => $table_alias, - 'database' => $db_alias, - ] - ) - . '} \\\\'; - } - if (! $this->export->outputHandler($buffer)) { - return false; - } - - // show column names - if (isset($GLOBALS['latex_columns'])) { - $buffer = '\\hline '; - for ($i = 0; $i < $columns_cnt; $i++) { - $buffer .= '\\multicolumn{1}{|c|}{\\textbf{' - . self::texEscape(stripslashes($columns_alias[$i])) . '}} & '; - } - - $buffer = mb_substr($buffer, 0, -2) . '\\\\ \\hline \hline '; - if (! $this->export->outputHandler($buffer . ' \\endfirsthead ' . $crlf)) { - return false; - } - if (isset($GLOBALS['latex_caption'])) { - if (! $this->export->outputHandler( - '\\caption{' - . Util::expandUserString( - $GLOBALS['latex_data_continued_caption'], - [ - 'texEscape', - static::class, - ], - [ - 'table' => $table_alias, - 'database' => $db_alias, - ] - ) - . '} \\\\ ' - ) - ) { - return false; - } - } - if (! $this->export->outputHandler($buffer . '\\endhead \\endfoot' . $crlf)) { - return false; - } - } else { - if (! $this->export->outputHandler('\\\\ \hline')) { - return false; - } - } - - // print the whole table - while ($record = $GLOBALS['dbi']->fetchAssoc($result)) { - $buffer = ''; - // print each row - for ($i = 0; $i < $columns_cnt; $i++) { - if ($record[$columns[$i]] !== null - && 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 (! $this->export->outputHandler($buffer)) { - return false; - } - } - - $buffer = ' \\end{longtable}' . $crlf; - if (! $this->export->outputHandler($buffer)) { - return false; - } - - $GLOBALS['dbi']->freeResult($result); - - return true; - } // end getTableLaTeX - - /** - * Outputs table's structure - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $export_mode 'create_table', 'triggers', 'create_view', - * 'stand_in' - * @param string $export_type 'server', 'database', 'table' - * @param bool $do_relation whether to include relation comments - * @param bool $do_comments whether to include the pmadb-style column - * comments as comments in the structure; - * this is deprecated but the parameter is - * left here because export.php calls - * exportStructure() also for other - * export types which use this parameter - * @param bool $do_mime whether to include mime comments - * @param bool $dates whether to include creation/update/check dates - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportStructure( - $db, - $table, - $crlf, - $error_url, - $export_mode, - $export_type, - $do_relation = false, - $do_comments = false, - $do_mime = false, - $dates = false, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - global $cfgRelation; - - /* We do not export triggers */ - if ($export_mode == 'triggers') { - return true; - } - - /** - * Get the unique keys in the table - */ - $unique_keys = []; - $keys = $GLOBALS['dbi']->getTableIndexes($db, $table); - foreach ($keys as $key) { - if ($key['Non_unique'] == 0) { - $unique_keys[] = $key['Column_name']; - } - } - - /** - * Gets fields properties - */ - $GLOBALS['dbi']->selectDb($db); - - // Check if we can use Relations - list($res_rel, $have_rel) = $this->relation->getRelationsAndStatus( - $do_relation && ! empty($cfgRelation['relation']), - $db, - $table - ); - /** - * Displays the table structure - */ - $buffer = $crlf . '%' . $crlf . '% ' . __('Structure:') . ' ' - . $table_alias . $crlf . '%' . $crlf . ' \\begin{longtable}{'; - if (! $this->export->outputHandler($buffer)) { - return false; - } - - $alignment = '|l|c|c|c|'; - if ($do_relation && $have_rel) { - $alignment .= 'l|'; - } - if ($do_comments) { - $alignment .= 'l|'; - } - if ($do_mime && $cfgRelation['mimework']) { - $alignment .= 'l|'; - } - $buffer = $alignment . '} ' . $crlf; - - $header = ' \\hline '; - $header .= '\\multicolumn{1}{|c|}{\\textbf{' . __('Column') - . '}} & \\multicolumn{1}{|c|}{\\textbf{' . __('Type') - . '}} & \\multicolumn{1}{|c|}{\\textbf{' . __('Null') - . '}} & \\multicolumn{1}{|c|}{\\textbf{' . __('Default') . '}}'; - if ($do_relation && $have_rel) { - $header .= ' & \\multicolumn{1}{|c|}{\\textbf{' . __('Links to') . '}}'; - } - if ($do_comments) { - $header .= ' & \\multicolumn{1}{|c|}{\\textbf{' . __('Comments') . '}}'; - $comments = $this->relation->getComments($db, $table); - } - if ($do_mime && $cfgRelation['mimework']) { - $header .= ' & \\multicolumn{1}{|c|}{\\textbf{MIME}}'; - $mime_map = $this->transformations->getMime($db, $table, true); - } - - // Table caption for first page and label - if (isset($GLOBALS['latex_caption'])) { - $buffer .= ' \\caption{' - . Util::expandUserString( - $GLOBALS['latex_structure_caption'], - [ - 'texEscape', - static::class, - ], - [ - 'table' => $table_alias, - 'database' => $db_alias, - ] - ) - . '} \\label{' - . Util::expandUserString( - $GLOBALS['latex_structure_label'], - null, - [ - 'table' => $table_alias, - 'database' => $db_alias, - ] - ) - . '} \\\\' . $crlf; - } - $buffer .= $header . ' \\\\ \\hline \\hline' . $crlf - . '\\endfirsthead' . $crlf; - // Table caption on next pages - if (isset($GLOBALS['latex_caption'])) { - $buffer .= ' \\caption{' - . Util::expandUserString( - $GLOBALS['latex_structure_continued_caption'], - [ - 'texEscape', - static::class, - ], - [ - 'table' => $table_alias, - 'database' => $db_alias, - ] - ) - . '} \\\\ ' . $crlf; - } - $buffer .= $header . ' \\\\ \\hline \\hline \\endhead \\endfoot ' . $crlf; - - if (! $this->export->outputHandler($buffer)) { - return false; - } - - $fields = $GLOBALS['dbi']->getColumns($db, $table); - foreach ($fields as $row) { - $extracted_columnspec = Util::extractColumnSpec($row['Type']); - $type = $extracted_columnspec['print_type']; - if (empty($type)) { - $type = ' '; - } - - if (! isset($row['Default'])) { - if ($row['Null'] != 'NO') { - $row['Default'] = 'NULL'; - } - } - - $field_name = $col_as = $row['Field']; - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - - $local_buffer = $col_as . "\000" . $type . "\000" - . (($row['Null'] == '' || $row['Null'] == 'NO') - ? __('No') : __('Yes')) - . "\000" . (isset($row['Default']) ? $row['Default'] : ''); - - if ($do_relation && $have_rel) { - $local_buffer .= "\000"; - $local_buffer .= $this->getRelationString( - $res_rel, - $field_name, - $db, - $aliases - ); - } - if ($do_comments && $cfgRelation['commwork']) { - $local_buffer .= "\000"; - if (isset($comments[$field_name])) { - $local_buffer .= $comments[$field_name]; - } - } - if ($do_mime && $cfgRelation['mimework']) { - $local_buffer .= "\000"; - if (isset($mime_map[$field_name])) { - $local_buffer .= str_replace( - '_', - '/', - $mime_map[$field_name]['mimetype'] - ); - } - } - $local_buffer = self::texEscape($local_buffer); - if ($row['Key'] == 'PRI') { - $pos = mb_strpos($local_buffer, "\000"); - $local_buffer = '\\textit{' - . - mb_substr($local_buffer, 0, $pos) - . '}' . - mb_substr($local_buffer, $pos); - } - if (in_array($field_name, $unique_keys)) { - $pos = mb_strpos($local_buffer, "\000"); - $local_buffer = '\\textbf{' - . - mb_substr($local_buffer, 0, $pos) - . '}' . - mb_substr($local_buffer, $pos); - } - $buffer = str_replace("\000", ' & ', $local_buffer); - $buffer .= ' \\\\ \\hline ' . $crlf; - - if (! $this->export->outputHandler($buffer)) { - return false; - } - } // end while - - $buffer = ' \\end{longtable}' . $crlf; - - return $this->export->outputHandler($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 = [ - '$', - '%', - '{', - '}', - '&', - '#', - '_', - '^', - ]; - $cnt_escape = count($escape); - for ($k = 0; $k < $cnt_escape; $k++) { - $string = str_replace($escape[$k], '\\' . $escape[$k], $string); - } - - return $string; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportMediawiki.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportMediawiki.php deleted file mode 100644 index 9d971cb..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportMediawiki.php +++ /dev/null @@ -1,386 +0,0 @@ -setProperties(); - } - - /** - * Sets the export MediaWiki properties - * - * @return void - */ - protected function setProperties() - { - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('MediaWiki Table'); - $exportPluginProperties->setExtension('mediawiki'); - $exportPluginProperties->setMimeType('text/plain'); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup( - "general_opts", - __('Dump table') - ); - - // what to dump (structure/data/both) - $subgroup = new OptionsPropertySubgroup( - "dump_table", - __("Dump table") - ); - $leaf = new RadioPropertyItem('structure_or_data'); - $leaf->setValues( - [ - 'structure' => __('structure'), - 'data' => __('data'), - 'structure_and_data' => __('structure and data'), - ] - ); - $subgroup->setSubgroupHeader($leaf); - $generalOptions->addProperty($subgroup); - - // export table name - $leaf = new BoolPropertyItem( - "caption", - __('Export table names') - ); - $generalOptions->addProperty($leaf); - - // export table headers - $leaf = new BoolPropertyItem( - "headers", - __('Export table headers') - ); - $generalOptions->addProperty($leaf); - //add the main group to the root group - $exportSpecificOptions->addProperty($generalOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - return true; - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter() - { - return true; - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Alias of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - return true; - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs table's structure - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $export_mode 'create_table','triggers','create_view', - * 'stand_in' - * @param string $export_type 'server', 'database', 'table' - * @param bool $do_relation whether to include relation comments - * @param bool $do_comments whether to include the pmadb-style column - * comments as comments in the structure; this is - * deprecated but the parameter is left here - * because export.php calls exportStructure() - * also for other export types which use this - * parameter - * @param bool $do_mime whether to include mime comments - * @param bool $dates whether to include creation/update/check dates - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportStructure( - $db, - $table, - $crlf, - $error_url, - $export_mode, - $export_type, - $do_relation = false, - $do_comments = false, - $do_mime = false, - $dates = false, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - $output = ''; - switch ($export_mode) { - case 'create_table': - $columns = $GLOBALS['dbi']->getColumns($db, $table); - $columns = array_values($columns); - $row_cnt = count($columns); - - // Print structure comment - $output = $this->_exportComment( - "Table structure for " - . Util::backquote($table_alias) - ); - - // Begin the table construction - $output .= "{| class=\"wikitable\" style=\"text-align:center;\"" - . $this->_exportCRLF(); - - // Add the table name - if (isset($GLOBALS['mediawiki_caption'])) { - $output .= "|+'''" . $table_alias . "'''" . $this->_exportCRLF(); - } - - // Add the table headers - if (isset($GLOBALS['mediawiki_headers'])) { - $output .= "|- style=\"background:#ffdead;\"" . $this->_exportCRLF(); - $output .= "! style=\"background:#ffffff\" | " - . $this->_exportCRLF(); - for ($i = 0; $i < $row_cnt; ++$i) { - $col_as = $columns[$i]['Field']; - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as]) - ) { - $col_as - = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $output .= " | " . $col_as . $this->_exportCRLF(); - } - } - - // Add the table structure - $output .= "|-" . $this->_exportCRLF(); - $output .= "! Type" . $this->_exportCRLF(); - for ($i = 0; $i < $row_cnt; ++$i) { - $output .= " | " . $columns[$i]['Type'] . $this->_exportCRLF(); - } - - $output .= "|-" . $this->_exportCRLF(); - $output .= "! Null" . $this->_exportCRLF(); - for ($i = 0; $i < $row_cnt; ++$i) { - $output .= " | " . $columns[$i]['Null'] . $this->_exportCRLF(); - } - - $output .= "|-" . $this->_exportCRLF(); - $output .= "! Default" . $this->_exportCRLF(); - for ($i = 0; $i < $row_cnt; ++$i) { - $output .= " | " . $columns[$i]['Default'] . $this->_exportCRLF(); - } - - $output .= "|-" . $this->_exportCRLF(); - $output .= "! Extra" . $this->_exportCRLF(); - for ($i = 0; $i < $row_cnt; ++$i) { - $output .= " | " . $columns[$i]['Extra'] . $this->_exportCRLF(); - } - - $output .= "|}" . str_repeat($this->_exportCRLF(), 2); - break; - } // end switch - - return $this->export->outputHandler($output); - } - - /** - * Outputs the content of a table in MediaWiki format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - // Print data comment - $output = $this->_exportComment( - "Table data for " . Util::backquote($table_alias) - ); - - // Begin the table construction - // Use the "wikitable" class for style - // Use the "sortable" class for allowing tables to be sorted by column - $output .= "{| class=\"wikitable sortable\" style=\"text-align:center;\"" - . $this->_exportCRLF(); - - // Add the table name - if (isset($GLOBALS['mediawiki_caption'])) { - $output .= "|+'''" . $table_alias . "'''" . $this->_exportCRLF(); - } - - // Add the table headers - if (isset($GLOBALS['mediawiki_headers'])) { - // Get column names - $column_names = $GLOBALS['dbi']->getColumnNames($db, $table); - - // Add column names as table headers - if ($column_names !== null) { - // Use '|-' for separating rows - $output .= "|-" . $this->_exportCRLF(); - - // Use '!' for separating table headers - foreach ($column_names as $column) { - if (! empty($aliases[$db]['tables'][$table]['columns'][$column]) - ) { - $column - = $aliases[$db]['tables'][$table]['columns'][$column]; - } - $output .= " ! " . $column . "" . $this->_exportCRLF(); - } - } - } - - // Get the table data from the database - $result = $GLOBALS['dbi']->query( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - $fields_cnt = $GLOBALS['dbi']->numFields($result); - - while ($row = $GLOBALS['dbi']->fetchRow($result)) { - $output .= "|-" . $this->_exportCRLF(); - - // Use '|' for separating table columns - for ($i = 0; $i < $fields_cnt; ++$i) { - $output .= " | " . $row[$i] . "" . $this->_exportCRLF(); - } - } - - // End table construction - $output .= "|}" . str_repeat($this->_exportCRLF(), 2); - - return $this->export->outputHandler($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 https://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/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOds.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOds.php deleted file mode 100644 index bc062da..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOds.php +++ /dev/null @@ -1,345 +0,0 @@ -setProperties(); - } - - /** - * Sets the export ODS properties - * - * @return void - */ - protected function setProperties() - { - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('OpenDocument Spreadsheet'); - $exportPluginProperties->setExtension('ods'); - $exportPluginProperties->setMimeType( - 'application/vnd.oasis.opendocument.spreadsheet' - ); - $exportPluginProperties->setForceFile(true); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - // create primary items and add them to the group - $leaf = new TextPropertyItem( - "null", - __('Replace NULL with:') - ); - $generalOptions->addProperty($leaf); - $leaf = new BoolPropertyItem( - "columns", - __('Put columns names in the first row') - ); - $generalOptions->addProperty($leaf); - $leaf = new HiddenPropertyItem("structure_or_data"); - $generalOptions->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($generalOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - $GLOBALS['ods_buffer'] .= '' - . '' - . '' - . '' - . '' - . '/' - . '' - . '/' - . '' - . '' - . '' - . '' - . ':' - . '' - . ':' - . '' - . ' ' - . '' - . '' - . '' - . '' - . '/' - . '' - . '/' - . '' - . ' ' - . '' - . ':' - . '' - . ' ' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . ''; - - return true; - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter() - { - $GLOBALS['ods_buffer'] .= '' - . '' - . ''; - - return $this->export->outputHandler( - OpenDocument::create( - 'application/vnd.oasis.opendocument.spreadsheet', - $GLOBALS['ods_buffer'] - ) - ); - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - return true; - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs the content of a table in NHibernate format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - global $what; - - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - // Gets the data from the database - $result = $GLOBALS['dbi']->query( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - $fields_cnt = $GLOBALS['dbi']->numFields($result); - $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result); - $field_flags = []; - for ($j = 0; $j < $fields_cnt; $j++) { - $field_flags[$j] = $GLOBALS['dbi']->fieldFlags($result, $j); - } - - $GLOBALS['ods_buffer'] - .= ''; - - // If required, get fields name at the first line - if (isset($GLOBALS[$what . '_columns'])) { - $GLOBALS['ods_buffer'] .= ''; - for ($i = 0; $i < $fields_cnt; $i++) { - $col_as = $GLOBALS['dbi']->fieldName($result, $i); - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $GLOBALS['ods_buffer'] - .= '' - . '' - . htmlspecialchars( - stripslashes($col_as) - ) - . '' - . ''; - } // end for - $GLOBALS['ods_buffer'] .= ''; - } // end if - - // Format the data - while ($row = $GLOBALS['dbi']->fetchRow($result)) { - $GLOBALS['ods_buffer'] .= ''; - for ($j = 0; $j < $fields_cnt; $j++) { - if ($fields_meta[$j]->type === 'geometry') { - // export GIS types as hex - $row[$j] = '0x' . bin2hex($row[$j]); - } - if (! isset($row[$j]) || $row[$j] === null) { - $GLOBALS['ods_buffer'] - .= '' - . '' - . htmlspecialchars($GLOBALS[$what . '_null']) - . '' - . ''; - } elseif (false !== stripos($field_flags[$j], 'BINARY') - && $fields_meta[$j]->blob - ) { - // ignore BLOB - $GLOBALS['ods_buffer'] - .= '' - . '' - . ''; - } elseif ($fields_meta[$j]->type == "date") { - $GLOBALS['ods_buffer'] - .= '' - . '' - . htmlspecialchars($row[$j]) - . '' - . ''; - } elseif ($fields_meta[$j]->type == "time") { - $GLOBALS['ods_buffer'] - .= '' - . '' - . htmlspecialchars($row[$j]) - . '' - . ''; - } elseif ($fields_meta[$j]->type == "datetime") { - $GLOBALS['ods_buffer'] - .= '' - . '' - . htmlspecialchars($row[$j]) - . '' - . ''; - } elseif (($fields_meta[$j]->numeric - && $fields_meta[$j]->type != 'timestamp' - && ! $fields_meta[$j]->blob) - || $fields_meta[$j]->type == 'real' - ) { - $GLOBALS['ods_buffer'] - .= '' - . '' - . htmlspecialchars($row[$j]) - . '' - . ''; - } else { - $GLOBALS['ods_buffer'] - .= '' - . '' - . htmlspecialchars($row[$j]) - . '' - . ''; - } - } // end for - $GLOBALS['ods_buffer'] .= ''; - } // end while - $GLOBALS['dbi']->freeResult($result); - - $GLOBALS['ods_buffer'] .= ''; - - return true; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOdt.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOdt.php deleted file mode 100644 index 8173afb..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOdt.php +++ /dev/null @@ -1,813 +0,0 @@ -setProperties(); - } - - /** - * Sets the export ODT properties - * - * @return void - */ - protected function setProperties() - { - global $plugin_param; - $hide_structure = false; - if ($plugin_param['export_type'] == 'table' - && ! $plugin_param['single_table'] - ) { - $hide_structure = true; - } - - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('OpenDocument Text'); - $exportPluginProperties->setExtension('odt'); - $exportPluginProperties->setMimeType( - 'application/vnd.oasis.opendocument.text' - ); - $exportPluginProperties->setForceFile(true); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // what to dump (structure/data/both) main group - $dumpWhat = new OptionsPropertyMainGroup( - "general_opts", - __('Dump table') - ); - // create primary items and add them to the group - $leaf = new RadioPropertyItem("structure_or_data"); - $leaf->setValues( - [ - 'structure' => __('structure'), - 'data' => __('data'), - 'structure_and_data' => __('structure and data'), - ] - ); - $dumpWhat->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($dumpWhat); - - // structure options main group - if (! $hide_structure) { - $structureOptions = new OptionsPropertyMainGroup( - "structure", - __('Object creation options') - ); - $structureOptions->setForce('data'); - // create primary items and add them to the group - if (! empty($GLOBALS['cfgRelation']['relation'])) { - $leaf = new BoolPropertyItem( - "relation", - __('Display foreign key relationships') - ); - $structureOptions->addProperty($leaf); - } - $leaf = new BoolPropertyItem( - "comments", - __('Display comments') - ); - $structureOptions->addProperty($leaf); - if (! empty($GLOBALS['cfgRelation']['mimework'])) { - $leaf = new BoolPropertyItem( - "mime", - __('Display media (MIME) types') - ); - $structureOptions->addProperty($leaf); - } - // add the main group to the root group - $exportSpecificOptions->addProperty($structureOptions); - } - - // data options main group - $dataOptions = new OptionsPropertyMainGroup( - "data", - __('Data dump options') - ); - $dataOptions->setForce('structure'); - // create primary items and add them to the group - $leaf = new BoolPropertyItem( - "columns", - __('Put columns names in the first row') - ); - $dataOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - 'null', - __('Replace NULL with:') - ); - $dataOptions->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($dataOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - $GLOBALS['odt_buffer'] .= '' - . '' - . '' - . ''; - - return true; - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter() - { - $GLOBALS['odt_buffer'] .= '' - . '' - . ''; - if (! $this->export->outputHandler( - OpenDocument::create( - 'application/vnd.oasis.opendocument.text', - $GLOBALS['odt_buffer'] - ) - ) - ) { - return false; - } - - return true; - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - if (empty($db_alias)) { - $db_alias = $db; - } - $GLOBALS['odt_buffer'] - .= '' - . __('Database') . ' ' . htmlspecialchars($db_alias) - . ''; - - return true; - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs the content of a table in NHibernate format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - global $what; - - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - // Gets the data from the database - $result = $GLOBALS['dbi']->query( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - $fields_cnt = $GLOBALS['dbi']->numFields($result); - $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result); - $field_flags = []; - for ($j = 0; $j < $fields_cnt; $j++) { - $field_flags[$j] = $GLOBALS['dbi']->fieldFlags($result, $j); - } - - $GLOBALS['odt_buffer'] - .= '' - . __('Dumping data for table') . ' ' . htmlspecialchars($table_alias) - . '' - . '' - . ''; - - // If required, get fields name at the first line - if (isset($GLOBALS[$what . '_columns'])) { - $GLOBALS['odt_buffer'] .= ''; - for ($i = 0; $i < $fields_cnt; $i++) { - $col_as = $GLOBALS['dbi']->fieldName($result, $i); - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $GLOBALS['odt_buffer'] - .= '' - . '' - . htmlspecialchars( - stripslashes($col_as) - ) - . '' - . ''; - } // end for - $GLOBALS['odt_buffer'] .= ''; - } // end if - - // Format the data - while ($row = $GLOBALS['dbi']->fetchRow($result)) { - $GLOBALS['odt_buffer'] .= ''; - for ($j = 0; $j < $fields_cnt; $j++) { - if ($fields_meta[$j]->type === 'geometry') { - // export GIS types as hex - $row[$j] = '0x' . bin2hex($row[$j]); - } - if (! isset($row[$j]) || $row[$j] === null) { - $GLOBALS['odt_buffer'] - .= '' - . '' - . htmlspecialchars($GLOBALS[$what . '_null']) - . '' - . ''; - } elseif (false !== stripos($field_flags[$j], 'BINARY') - && $fields_meta[$j]->blob - ) { - // ignore BLOB - $GLOBALS['odt_buffer'] - .= '' - . '' - . ''; - } elseif ($fields_meta[$j]->numeric - && $fields_meta[$j]->type != 'timestamp' - && ! $fields_meta[$j]->blob - ) { - $GLOBALS['odt_buffer'] - .= '' - . '' - . htmlspecialchars($row[$j]) - . '' - . ''; - } else { - $GLOBALS['odt_buffer'] - .= '' - . '' - . htmlspecialchars($row[$j]) - . '' - . ''; - } - } // end for - $GLOBALS['odt_buffer'] .= ''; - } // end while - $GLOBALS['dbi']->freeResult($result); - - $GLOBALS['odt_buffer'] .= ''; - - return true; - } - - /** - * Returns a stand-in CREATE definition to resolve view dependencies - * - * @param string $db the database name - * @param string $view the view name - * @param string $crlf the end of line sequence - * @param array $aliases Aliases of db/table/columns - * - * @return string resulting definition - */ - public function getTableDefStandIn($db, $view, $crlf, $aliases = []) - { - $db_alias = $db; - $view_alias = $view; - $this->initAlias($aliases, $db_alias, $view_alias); - /** - * Gets fields properties - */ - $GLOBALS['dbi']->selectDb($db); - - /** - * Displays the table structure - */ - $GLOBALS['odt_buffer'] - .= ''; - $columns_cnt = 4; - $GLOBALS['odt_buffer'] - .= ''; - /* Header */ - $GLOBALS['odt_buffer'] .= '' - . '' - . '' . __('Column') . '' - . '' - . '' - . '' . __('Type') . '' - . '' - . '' - . '' . __('Null') . '' - . '' - . '' - . '' . __('Default') . '' - . '' - . ''; - - $columns = $GLOBALS['dbi']->getColumns($db, $view); - foreach ($columns as $column) { - $col_as = $column['Field'] ?? null; - if (! empty($aliases[$db]['tables'][$view]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$view]['columns'][$col_as]; - } - $GLOBALS['odt_buffer'] .= $this->formatOneColumnDefinition( - $column, - $col_as - ); - $GLOBALS['odt_buffer'] .= ''; - } // end foreach - - $GLOBALS['odt_buffer'] .= ''; - - return ''; - } - - /** - * Returns $table's CREATE definition - * - * @param string $db the database name - * @param string $table the table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param bool $do_relation whether to include relation comments - * @param bool $do_comments whether to include the pmadb-style column - * comments as comments in the structure; - * this is deprecated but the parameter is - * left here because export.php calls - * PMA_exportStructure() also for other - * @param bool $do_mime whether to include mime comments - * @param bool $show_dates whether to include creation/update/check dates - * @param bool $add_semicolon whether to add semicolon and end-of-line at - * the end - * @param bool $view whether we're handling a view - * @param array $aliases Aliases of db/table/columns - * - * @return bool true - */ - public function getTableDef( - $db, - $table, - $crlf, - $error_url, - $do_relation, - $do_comments, - $do_mime, - $show_dates = false, - $add_semicolon = true, - $view = false, - array $aliases = [] - ) { - global $cfgRelation; - - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - /** - * Gets fields properties - */ - $GLOBALS['dbi']->selectDb($db); - - // Check if we can use Relations - list($res_rel, $have_rel) = $this->relation->getRelationsAndStatus( - $do_relation && ! empty($cfgRelation['relation']), - $db, - $table - ); - /** - * 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 = $this->relation->getComments($db, $table); - } - if ($do_mime && $cfgRelation['mimework']) { - $GLOBALS['odt_buffer'] .= '' - . '' . __('Media (MIME) type') . '' - . ''; - $mime_map = $this->transformations->getMime($db, $table, true); - } - $GLOBALS['odt_buffer'] .= ''; - - $columns = $GLOBALS['dbi']->getColumns($db, $table); - foreach ($columns as $column) { - $col_as = $field_name = $column['Field']; - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $GLOBALS['odt_buffer'] .= $this->formatOneColumnDefinition( - $column, - $col_as - ); - if ($do_relation && $have_rel) { - $foreigner = $this->relation->searchColumnInForeigners($res_rel, $field_name); - if ($foreigner) { - $rtable = $foreigner['foreign_table']; - $rfield = $foreigner['foreign_field']; - if (! empty($aliases[$db]['tables'][$rtable]['columns'][$rfield]) - ) { - $rfield - = $aliases[$db]['tables'][$rtable]['columns'][$rfield]; - } - if (! empty($aliases[$db]['tables'][$rtable]['alias'])) { - $rtable = $aliases[$db]['tables'][$rtable]['alias']; - } - $relation = htmlspecialchars($rtable . ' (' . $rfield . ')'); - $GLOBALS['odt_buffer'] - .= '' - . '' - . htmlspecialchars($relation) - . '' - . ''; - } - } - 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 - * @param array $aliases Aliases of db/table/columns - * - * @return bool true - */ - protected function getTriggers($db, $table, array $aliases = []) - { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - $GLOBALS['odt_buffer'] .= '' - . '' - . '' - . '' - . '' . __('Name') . '' - . '' - . '' - . '' . __('Time') . '' - . '' - . '' - . '' . __('Event') . '' - . '' - . '' - . '' . __('Definition') . '' - . '' - . ''; - - $triggers = $GLOBALS['dbi']->getTriggers($db, $table); - - foreach ($triggers as $trigger) { - $GLOBALS['odt_buffer'] .= ''; - $GLOBALS['odt_buffer'] .= '' - . '' - . htmlspecialchars($trigger['name']) - . '' - . ''; - $GLOBALS['odt_buffer'] .= '' - . '' - . htmlspecialchars($trigger['action_timing']) - . '' - . ''; - $GLOBALS['odt_buffer'] .= '' - . '' - . htmlspecialchars($trigger['event_manipulation']) - . '' - . ''; - $GLOBALS['odt_buffer'] .= '' - . '' - . htmlspecialchars($trigger['definition']) - . '' - . ''; - $GLOBALS['odt_buffer'] .= ''; - } - - $GLOBALS['odt_buffer'] .= ''; - - return true; - } - - /** - * Outputs table's structure - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $export_mode 'create_table', 'triggers', 'create_view', - * 'stand_in' - * @param string $export_type 'server', 'database', 'table' - * @param bool $do_relation whether to include relation comments - * @param bool $do_comments whether to include the pmadb-style column - * comments as comments in the structure; - * this is deprecated but the parameter is - * left here because export.php calls - * PMA_exportStructure() also for other - * @param bool $do_mime whether to include mime comments - * @param bool $dates whether to include creation/update/check dates - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportStructure( - $db, - $table, - $crlf, - $error_url, - $export_mode, - $export_type, - $do_relation = false, - $do_comments = false, - $do_mime = false, - $dates = false, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - switch ($export_mode) { - case 'create_table': - $GLOBALS['odt_buffer'] - .= '' - . __('Table structure for table') . ' ' . - htmlspecialchars($table_alias) - . ''; - $this->getTableDef( - $db, - $table, - $crlf, - $error_url, - $do_relation, - $do_comments, - $do_mime, - $dates, - true, - false, - $aliases - ); - break; - case 'triggers': - $triggers = $GLOBALS['dbi']->getTriggers($db, $table, $aliases); - if ($triggers) { - $GLOBALS['odt_buffer'] - .= '' - . __('Triggers') . ' ' - . htmlspecialchars($table_alias) - . ''; - $this->getTriggers($db, $table); - } - break; - case 'create_view': - $GLOBALS['odt_buffer'] - .= '' - . __('Structure for view') . ' ' - . htmlspecialchars($table_alias) - . ''; - $this->getTableDef( - $db, - $table, - $crlf, - $error_url, - $do_relation, - $do_comments, - $do_mime, - $dates, - true, - true, - $aliases - ); - break; - case 'stand_in': - $GLOBALS['odt_buffer'] - .= '' - . __('Stand-in structure for view') . ' ' - . htmlspecialchars($table_alias) - . ''; - // export a stand-in definition to resolve view dependencies - $this->getTableDefStandIn($db, $table, $crlf, $aliases); - } // end switch - - return true; - } // end of the '$this->exportStructure' function - - /** - * Formats the definition for one column - * - * @param array $column info about this column - * @param string $col_as column alias - * - * @return string Formatted column definition - */ - protected function formatOneColumnDefinition($column, $col_as = '') - { - if (empty($col_as)) { - $col_as = $column['Field']; - } - $definition = ''; - $definition .= '' - . '' . htmlspecialchars($col_as) . '' - . ''; - - $extracted_columnspec - = Util::extractColumnSpec($column['Type']); - $type = htmlspecialchars($extracted_columnspec['print_type']); - if (empty($type)) { - $type = ' '; - } - - $definition .= '' - . '' . htmlspecialchars($type) . '' - . ''; - if (! isset($column['Default'])) { - if ($column['Null'] != 'NO') { - $column['Default'] = 'NULL'; - } else { - $column['Default'] = ''; - } - } - $definition .= '' - . '' - . (($column['Null'] == '' || $column['Null'] == 'NO') - ? __('No') - : __('Yes')) - . '' - . ''; - $definition .= '' - . '' . htmlspecialchars($column['Default']) . '' - . ''; - - return $definition; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPdf.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPdf.php deleted file mode 100644 index 49e74b3..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPdf.php +++ /dev/null @@ -1,395 +0,0 @@ -initSpecificVariables(); - - $this->setProperties(); - } - - /** - * Initialize the local variables that are used for export PDF - * - * @return void - */ - protected function initSpecificVariables() - { - if (! empty($_POST['pdf_report_title'])) { - $this->_setPdfReportTitle($_POST['pdf_report_title']); - } - $this->_setPdf(new Pdf('L', 'pt', 'A3')); - } - - /** - * Sets the export PDF properties - * - * @return void - */ - protected function setProperties() - { - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('PDF'); - $exportPluginProperties->setExtension('pdf'); - $exportPluginProperties->setMimeType('application/pdf'); - $exportPluginProperties->setForceFile(true); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - // create primary items and add them to the group - $leaf = new TextPropertyItem( - "report_title", - __('Report title:') - ); - $generalOptions->addProperty($leaf); - // add the group to the root group - $exportSpecificOptions->addProperty($generalOptions); - - // what to dump (structure/data/both) main group - $dumpWhat = new OptionsPropertyMainGroup( - "dump_what", - __('Dump table') - ); - $leaf = new RadioPropertyItem("structure_or_data"); - $leaf->setValues( - [ - 'structure' => __('structure'), - 'data' => __('data'), - 'structure_and_data' => __('structure and data'), - ] - ); - $dumpWhat->addProperty($leaf); - // add the group to the root group - $exportSpecificOptions->addProperty($dumpWhat); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - $pdf_report_title = $this->_getPdfReportTitle(); - $pdf = $this->_getPdf(); - $pdf->Open(); - - $attr = [ - '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(): - return $this->export->outputHandler($pdf->getPDFData()); - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - return true; - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs the content of a table in NHibernate format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - $pdf = $this->_getPdf(); - $attr = [ - 'currentDb' => $db, - 'currentTable' => $table, - 'dbAlias' => $db_alias, - 'tableAlias' => $table_alias, - 'aliases' => $aliases, - 'purpose' => __('Dumping data'), - ]; - $pdf->setAttributes($attr); - $pdf->mysqlReport($sql_query); - - return true; - } // end of the 'PMA_exportData()' function - - /** - * Outputs table structure - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $export_mode 'create_table', 'triggers', 'create_view', - * 'stand_in' - * @param string $export_type 'server', 'database', 'table' - * @param bool $do_relation whether to include relation comments - * @param bool $do_comments whether to include the pmadb-style column - * comments as comments in the structure; - * this is deprecated but the parameter is - * left here because export.php calls - * PMA_exportStructure() also for other - * export types which use this parameter - * @param bool $do_mime whether to include mime comments - * @param bool $dates whether to include creation/update/check dates - * @param array $aliases aliases for db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportStructure( - $db, - $table, - $crlf, - $error_url, - $export_mode, - $export_type, - $do_relation = false, - $do_comments = false, - $do_mime = false, - $dates = false, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $purpose = null; - $this->initAlias($aliases, $db_alias, $table_alias); - $pdf = $this->_getPdf(); - // getting purpose to show at top - switch ($export_mode) { - case 'create_table': - $purpose = __('Table structure'); - break; - case 'triggers': - $purpose = __('Triggers'); - break; - case 'create_view': - $purpose = __('View structure'); - break; - case 'stand_in': - $purpose = __('Stand in'); - } // end switch - - $attr = [ - 'currentDb' => $db, - 'currentTable' => $table, - 'dbAlias' => $db_alias, - 'tableAlias' => $table_alias, - 'aliases' => $aliases, - 'purpose' => $purpose, - ]; - $pdf->setAttributes($attr); - /** - * comment display set true as presently in pdf - * format, no option is present to take user input. - */ - $do_comments = true; - switch ($export_mode) { - case 'create_table': - $pdf->getTableDef( - $db, - $table, - $do_relation, - $do_comments, - $do_mime, - false, - $aliases - ); - break; - case 'triggers': - $pdf->getTriggers($db, $table); - break; - case 'create_view': - $pdf->getTableDef( - $db, - $table, - $do_relation, - $do_comments, - $do_mime, - false, - $aliases - ); - break; - case 'stand_in': - /* export a stand-in definition to resolve view dependencies - * Yet to develop this function - * $pdf->getTableDefStandIn($db, $table, $crlf); - */ - } // end switch - - return true; - } - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the PhpMyAdmin\Plugins\Export\Helpers\Pdf instance - * - * @return Pdf - */ - private function _getPdf() - { - return $this->_pdf; - } - - /** - * Instantiates the PhpMyAdmin\Plugins\Export\Helpers\Pdf class - * - * @param Pdf $pdf The instance - * - * @return void - */ - private function _setPdf($pdf) - { - $this->_pdf = $pdf; - } - - /** - * Gets the PDF report title - * - * @return string - */ - private function _getPdfReportTitle() - { - return $this->_pdfReportTitle; - } - - /** - * Sets the PDF report title - * - * @param string $pdfReportTitle PDF report title - * - * @return void - */ - private function _setPdfReportTitle($pdfReportTitle) - { - $this->_pdfReportTitle = $pdfReportTitle; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPhparray.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPhparray.php deleted file mode 100644 index 3fe9bd1..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPhparray.php +++ /dev/null @@ -1,259 +0,0 @@ -setProperties(); - } - - /** - * Sets the export PHP Array properties - * - * @return void - */ - protected function setProperties() - { - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('PHP array'); - $exportPluginProperties->setExtension('php'); - $exportPluginProperties->setMimeType('text/plain'); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - // create primary items and add them to the group - $leaf = new HiddenPropertyItem("structure_or_data"); - $generalOptions->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($generalOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Removes end of comment from a string - * - * @param string $string String to replace - * - * @return string - */ - public function commentString($string) - { - return strtr($string, '*/', '-'); - } - - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - $this->export->outputHandler( - 'export->outputHandler( - '/**' . $GLOBALS['crlf'] - . ' * Database ' . $this->commentString(Util::backquote($db_alias)) - . $GLOBALS['crlf'] . ' */' . $GLOBALS['crlf'] - ); - - return true; - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs the content of a table in PHP array format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - $result = $GLOBALS['dbi']->query( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - - $columns_cnt = $GLOBALS['dbi']->numFields($result); - $columns = []; - for ($i = 0; $i < $columns_cnt; $i++) { - $col_as = $GLOBALS['dbi']->fieldName($result, $i); - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $columns[$i] = stripslashes($col_as); - } - - // fix variable names (based on - // https://www.php.net/manual/en/language.variables.basics.php) - if (! preg_match( - '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', - $table_alias - ) - ) { - // fix invalid characters in variable names by replacing them with - // underscores - $tablefixed = preg_replace( - '/[^a-zA-Z0-9_\x7f-\xff]/', - '_', - $table_alias - ); - - // variable name must not start with a number or dash... - if (preg_match('/^[a-zA-Z_\x7f-\xff]/', $tablefixed) === 0) { - $tablefixed = '_' . $tablefixed; - } - } else { - $tablefixed = $table; - } - - $buffer = ''; - $record_cnt = 0; - // Output table name as comment - $buffer .= $crlf . '/* ' - . $this->commentString(Util::backquote($db_alias)) . '.' - . $this->commentString(Util::backquote($table_alias)) . ' */' . $crlf; - $buffer .= '$' . $tablefixed . ' = array('; - - while ($record = $GLOBALS['dbi']->fetchRow($result)) { - $record_cnt++; - - if ($record_cnt == 1) { - $buffer .= $crlf . ' array('; - } else { - $buffer .= ',' . $crlf . ' array('; - } - - for ($i = 0; $i < $columns_cnt; $i++) { - $buffer .= var_export($columns[$i], true) - . " => " . var_export($record[$i], true) - . (($i + 1 >= $columns_cnt) ? '' : ','); - } - - $buffer .= ')'; - } - - $buffer .= $crlf . ');' . $crlf; - if (! $this->export->outputHandler($buffer)) { - return false; - } - - $GLOBALS['dbi']->freeResult($result); - - return true; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportSql.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportSql.php deleted file mode 100644 index 9c5b1a2..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportSql.php +++ /dev/null @@ -1,2915 +0,0 @@ -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) { - $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( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - - // comments - $subgroup = new OptionsPropertySubgroup("include_comments"); - $leaf = new BoolPropertyItem( - 'include_comments', - __( - 'Display comments (includes info such as export' - . ' timestamp, PHP version, and server version)' - ) - ); - $subgroup->setSubgroupHeader($leaf); - - $leaf = new TextPropertyItem( - 'header_comment', - __('Additional custom header comment (\n splits lines):') - ); - $subgroup->addProperty($leaf); - $leaf = new BoolPropertyItem( - 'dates', - __( - 'Include a timestamp of when databases were created, last' - . ' updated, and last checked' - ) - ); - $subgroup->addProperty($leaf); - if (! empty($GLOBALS['cfgRelation']['relation'])) { - $leaf = new BoolPropertyItem( - 'relation', - __('Display foreign key relationships') - ); - $subgroup->addProperty($leaf); - } - if (! empty($GLOBALS['cfgRelation']['mimework'])) { - $leaf = new BoolPropertyItem( - 'mime', - __('Display media (MIME) types') - ); - $subgroup->addProperty($leaf); - } - $generalOptions->addProperty($subgroup); - - // enclose in a transaction - $leaf = new BoolPropertyItem( - "use_transaction", - __('Enclose export in a transaction') - ); - $leaf->setDoc( - [ - 'programs', - 'mysqldump', - 'option_mysqldump_single-transaction', - ] - ); - $generalOptions->addProperty($leaf); - - // disable foreign key checks - $leaf = new BoolPropertyItem( - "disable_fk", - __('Disable foreign key checks') - ); - $leaf->setDoc( - [ - 'manual_MySQL_Database_Administration', - 'server-system-variables', - 'sysvar_foreign_key_checks', - ] - ); - $generalOptions->addProperty($leaf); - - // export views as tables - $leaf = new BoolPropertyItem( - "views_as_tables", - __('Export views as tables') - ); - $generalOptions->addProperty($leaf); - - // export metadata - $leaf = new BoolPropertyItem( - "metadata", - __('Export metadata') - ); - $generalOptions->addProperty($leaf); - - // compatibility maximization - $compats = $GLOBALS['dbi']->getCompatibilities(); - if (count($compats) > 0) { - $values = []; - foreach ($compats as $val) { - $values[$val] = $val; - } - - $leaf = new SelectPropertyItem( - "compatibility", - __( - 'Database system or older MySQL server to maximize output' - . ' compatibility with:' - ) - ); - $leaf->setValues($values); - $leaf->setDoc( - [ - 'manual_MySQL_Database_Administration', - 'Server_SQL_mode', - ] - ); - $generalOptions->addProperty($leaf); - - unset($values); - } - - // what to dump (structure/data/both) - $subgroup = new OptionsPropertySubgroup( - "dump_table", - __("Dump table") - ); - $leaf = new RadioPropertyItem('structure_or_data'); - $leaf->setValues( - [ - '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( - "structure", - __('Object creation options') - ); - $structureOptions->setForce('data'); - - // begin SQL Statements - $subgroup = new OptionsPropertySubgroup(); - $leaf = new MessageOnlyPropertyItem( - 'add_statements', - __('Add statements:') - ); - $subgroup->setSubgroupHeader($leaf); - - // server export options - if ($plugin_param['export_type'] == 'server') { - $leaf = new BoolPropertyItem( - "drop_database", - sprintf(__('Add %s statement'), 'DROP DATABASE IF EXISTS') - ); - $subgroup->addProperty($leaf); - } - - if ($plugin_param['export_type'] == 'database') { - $create_clause = 'CREATE DATABASE / USE'; - $leaf = new BoolPropertyItem( - 'create_database', - sprintf(__('Add %s statement'), $create_clause) - ); - $subgroup->addProperty($leaf); - } - - if ($plugin_param['export_type'] == 'table') { - $drop_clause = $GLOBALS['dbi']->getTable( - $GLOBALS['db'], - $GLOBALS['table'] - )->isView() - ? 'DROP VIEW' - : 'DROP TABLE'; - } else { - $drop_clause = 'DROP TABLE / VIEW / PROCEDURE' - . ' / FUNCTION / EVENT'; - } - - $drop_clause .= ' / TRIGGER'; - - $leaf = new BoolPropertyItem( - 'drop_table', - sprintf(__('Add %s statement'), $drop_clause) - ); - $subgroup->addProperty($leaf); - - $subgroup_create_table = new OptionsPropertySubgroup(); - - // Add table structure option - $leaf = new BoolPropertyItem( - 'create_table', - sprintf(__('Add %s statement'), 'CREATE TABLE') - ); - $subgroup_create_table->setSubgroupHeader($leaf); - - $leaf = new BoolPropertyItem( - 'if_not_exists', - 'IF NOT EXISTS ' . __( - '(less efficient as indexes will be generated during table ' - . 'creation)' - ) - ); - $subgroup_create_table->addProperty($leaf); - - $leaf = new BoolPropertyItem( - 'auto_increment', - sprintf(__('%s value'), 'AUTO_INCREMENT') - ); - $subgroup_create_table->addProperty($leaf); - - $subgroup->addProperty($subgroup_create_table); - - // Add view option - $subgroup_create_view = new OptionsPropertySubgroup(); - $leaf = new BoolPropertyItem( - 'create_view', - sprintf(__('Add %s statement'), 'CREATE VIEW') - ); - $subgroup_create_view->setSubgroupHeader($leaf); - - $leaf = new BoolPropertyItem( - 'view_current_user', - __('Exclude definition of current user') - ); - $subgroup_create_view->addProperty($leaf); - - $leaf = new BoolPropertyItem( - 'or_replace_view', - sprintf(__('%s view'), 'OR REPLACE') - ); - $subgroup_create_view->addProperty($leaf); - - $subgroup->addProperty($subgroup_create_view); - - $leaf = new BoolPropertyItem( - 'procedure_function', - sprintf( - __('Add %s statement'), - 'CREATE PROCEDURE / FUNCTION / EVENT' - ) - ); - $subgroup->addProperty($leaf); - - // Add triggers option - $leaf = new BoolPropertyItem( - 'create_trigger', - sprintf(__('Add %s statement'), 'CREATE TRIGGER') - ); - $subgroup->addProperty($leaf); - - $structureOptions->addProperty($subgroup); - - $leaf = new BoolPropertyItem( - "backquotes", - __( - '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( - "data", - __('Data creation options') - ); - $dataOptions->setForce('structure'); - $leaf = new BoolPropertyItem( - "truncate", - __('Truncate table before insert') - ); - $dataOptions->addProperty($leaf); - - // begin SQL Statements - $subgroup = new OptionsPropertySubgroup(); - $leaf = new MessageOnlyPropertyItem( - __('Instead of INSERT statements, use:') - ); - $subgroup->setSubgroupHeader($leaf); - - $leaf = new BoolPropertyItem( - "delayed", - __('INSERT DELAYED statements') - ); - $leaf->setDoc( - [ - 'manual_MySQL_Database_Administration', - 'insert_delayed', - ] - ); - $subgroup->addProperty($leaf); - - $leaf = new BoolPropertyItem( - "ignore", - __('INSERT IGNORE statements') - ); - $leaf->setDoc( - [ - 'manual_MySQL_Database_Administration', - 'insert', - ] - ); - $subgroup->addProperty($leaf); - $dataOptions->addProperty($subgroup); - - // Function to use when dumping dat - $leaf = new SelectPropertyItem( - "type", - __('Function to use when dumping data:') - ); - $leaf->setValues( - [ - 'INSERT' => 'INSERT', - 'UPDATE' => 'UPDATE', - 'REPLACE' => 'REPLACE', - ] - ); - $dataOptions->addProperty($leaf); - - /* Syntax to use when inserting data */ - $subgroup = new OptionsPropertySubgroup(); - $leaf = new MessageOnlyPropertyItem( - null, - __('Syntax to use when inserting data:') - ); - $subgroup->setSubgroupHeader($leaf); - $leaf = new RadioPropertyItem( - "insert_syntax", - __('INSERT IGNORE statements') - ); - $leaf->setValues( - [ - '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,col_C) VALUES' - . ' (1,2,3), (4,5,6), (7,8,9)' - ), - 'none' => __( - 'neither of the above
          Example:' - . ' INSERT INTO tbl_name VALUES (1,2,3)' - ), - ] - ); - $subgroup->addProperty($leaf); - $dataOptions->addProperty($subgroup); - - // Max length of query - $leaf = new NumberPropertyItem( - "max_query_size", - __('Maximal length of created query') - ); - $dataOptions->addProperty($leaf); - - // Dump binary columns in hexadecimal - $leaf = new BoolPropertyItem( - "hex_for_binary", - __( - 'Dump binary columns in hexadecimal notation' - . ' (for example, "abc" becomes 0x616263)' - ) - ); - $dataOptions->addProperty($leaf); - - // Dump time in UTC - $leaf = new BoolPropertyItem( - "utc_time", - __( - '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; - } - } - - /** - * Generates SQL for routines export - * - * @param string $db Database - * @param array $aliases Aliases of db/table/columns - * @param string $type Type of exported routine - * @param string $name Verbose name of exported routine - * @param array $routines List of routines to export - * @param string $delimiter Delimiter to use in SQL - * - * @return string SQL query - */ - protected function _exportRoutineSQL( - $db, - array $aliases, - $type, - $name, - array $routines, - $delimiter - ) { - global $crlf; - - $text = $this->_exportComment() - . $this->_exportComment($name) - . $this->_exportComment(); - - $used_alias = false; - $proc_query = ''; - - foreach ($routines as $routine) { - if (! empty($GLOBALS['sql_drop_table'])) { - $proc_query .= 'DROP ' . $type . ' IF EXISTS ' - . Util::backquote($routine) - . $delimiter . $crlf; - } - $create_query = $this->replaceWithAliases( - $GLOBALS['dbi']->getDefinition($db, $type, $routine), - $aliases, - $db, - '', - $flag - ); - // One warning per database - if ($flag) { - $used_alias = true; - } - $proc_query .= $create_query . $delimiter . $crlf . $crlf; - } - if ($used_alias) { - $text .= $this->_exportComment( - __('It appears your database uses routines;') - ) - . $this->_exportComment( - __('alias export may not work reliably in all cases.') - ) - . $this->_exportComment(); - } - $text .= $proc_query; - - return $text; - } - - /** - * Exports routines (procedures and functions) - * - * @param string $db Database - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportRoutines($db, array $aliases = []) - { - global $crlf; - - $db_alias = $db; - $this->initAlias($aliases, $db_alias); - - $text = ''; - $delimiter = '$$'; - - $procedure_names = $GLOBALS['dbi'] - ->getProceduresOrFunctions($db, 'PROCEDURE'); - $function_names = $GLOBALS['dbi']->getProceduresOrFunctions($db, 'FUNCTION'); - - if ($procedure_names || $function_names) { - $text .= $crlf - . 'DELIMITER ' . $delimiter . $crlf; - - if ($procedure_names) { - $text .= $this->_exportRoutineSQL( - $db, - $aliases, - 'PROCEDURE', - __('Procedures'), - $procedure_names, - $delimiter - ); - } - - if ($function_names) { - $text .= $this->_exportRoutineSQL( - $db, - $aliases, - 'FUNCTION', - __('Functions'), - $function_names, - $delimiter - ); - } - - $text .= 'DELIMITER ;' . $crlf; - } - - if (! empty($text)) { - return $this->export->outputHandler($text); - } - - 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 https://dev.mysql.com/doc/refman/5.0/en/ansi-diff-comments.html - if (empty($text)) { - return '--' . $GLOBALS['crlf']; - } - - $lines = preg_split("/\\r\\n|\\r|\\n/", $text); - $result = []; - foreach ($lines as $line) { - $result[] = '-- ' . $line . $GLOBALS['crlf']; - } - return implode('', $result); - } - - 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']; - } - - return ''; - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter() - { - global $crlf; - - $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 - if ($this->_sent_charset) { - $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; - $this->_sent_charset = false; - } - - /* Restore timezone */ - if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) { - $GLOBALS['dbi']->query('SET time_zone = "' . $GLOBALS['old_tz'] . '"'); - } - - return $this->export->outputHandler($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; - - if (isset($GLOBALS['sql_compatibility'])) { - $tmp_compat = $GLOBALS['sql_compatibility']; - if ($tmp_compat == 'NONE') { - $tmp_compat = ''; - } - $GLOBALS['dbi']->tryQuery('SET SQL_MODE="' . $tmp_compat . '"'); - unset($tmp_compat); - } - $head = $this->_exportComment('phpMyAdmin SQL Dump') - . $this->_exportComment('version ' . PMA_VERSION) - . $this->_exportComment('https://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:') . ' ' - . Util::localisedDate() - ) - . $this->_exportComment( - __('Server version:') . ' ' . $GLOBALS['dbi']->getVersionString() - ) - . $this->_exportComment(__('PHP Version:') . ' ' . PHP_VERSION) - . $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' - ) { - $head .= 'SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";' . $crlf; - } - - if (isset($GLOBALS['sql_use_transaction'])) { - $head .= 'SET AUTOCOMMIT = 0;' . $crlf - . 'START TRANSACTION;' . $crlf; - } - - /* Change timezone if we should export timestamps in UTC */ - if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) { - $head .= 'SET time_zone = "+00:00";' . $crlf; - $GLOBALS['old_tz'] = $GLOBALS['dbi'] - ->fetchValue('SELECT @@session.time_zone'); - $GLOBALS['dbi']->query('SET time_zone = "+00:00"'); - } - - $head .= $this->_possibleCRLF(); - - if (! empty($GLOBALS['asfile'])) { - // 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']) - && isset(Charsets::$mysqlCharsetMap[$GLOBALS['charset']]) - ) { - // we got a charset from the export dialog - $set_names = Charsets::$mysqlCharsetMap[$GLOBALS['charset']]; - } else { - // by default we use the connection charset - $set_names = Charsets::$mysqlCharsetMap['utf-8']; - } - if ($set_names == 'utf8' && $GLOBALS['dbi']->getVersion() > 50503) { - $set_names = 'utf8mb4'; - } - $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; - $this->_sent_charset = true; - } - - return $this->export->outputHandler($head); - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - global $crlf; - - if (empty($db_alias)) { - $db_alias = $db; - } - if (isset($GLOBALS['sql_compatibility'])) { - $compat = $GLOBALS['sql_compatibility']; - } else { - $compat = 'NONE'; - } - if (isset($GLOBALS['sql_drop_database'])) { - if (! $this->export->outputHandler( - 'DROP DATABASE IF EXISTS ' - . Util::backquoteCompat( - $db_alias, - $compat, - isset($GLOBALS['sql_backquotes']) - ) - . ';' . $crlf - ) - ) { - return false; - } - } - if ($export_type == 'database' && ! isset($GLOBALS['sql_create_database'])) { - return true; - } - - $create_query = 'CREATE DATABASE IF NOT EXISTS ' - . Util::backquoteCompat( - $db_alias, - $compat, - isset($GLOBALS['sql_backquotes']) - ); - $collation = $GLOBALS['dbi']->getDbCollation($db); - if (mb_strpos($collation, '_')) { - $create_query .= ' DEFAULT CHARACTER SET ' - . mb_substr( - $collation, - 0, - mb_strpos($collation, '_') - ) - . ' COLLATE ' . $collation; - } else { - $create_query .= ' DEFAULT CHARACTER SET ' . $collation; - } - $create_query .= ';' . $crlf; - if (! $this->export->outputHandler($create_query)) { - return false; - } - - return $this->_exportUseStatement($db_alias, $compat); - } - - /** - * Outputs USE statement - * - * @param string $db db to use - * @param string $compat sql compatibility - * - * @return bool Whether it succeeded - */ - private function _exportUseStatement($db, $compat) - { - global $crlf; - - if (isset($GLOBALS['sql_compatibility']) - && $GLOBALS['sql_compatibility'] == 'NONE' - ) { - $result = $this->export->outputHandler( - 'USE ' - . Util::backquoteCompat( - $db, - $compat, - isset($GLOBALS['sql_backquotes']) - ) - . ';' . $crlf - ); - } else { - $result = $this->export->outputHandler('USE ' . $db . ';' . $crlf); - } - - return $result; - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Alias of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - if (empty($db_alias)) { - $db_alias = $db; - } - if (isset($GLOBALS['sql_compatibility'])) { - $compat = $GLOBALS['sql_compatibility']; - } else { - $compat = 'NONE'; - } - $head = $this->_exportComment() - . $this->_exportComment( - __('Database:') . ' ' - . Util::backquoteCompat( - $db_alias, - $compat, - isset($GLOBALS['sql_backquotes']) - ) - ) - . $this->_exportComment(); - - return $this->export->outputHandler($head); - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - global $crlf; - - $result = true; - - //add indexes to the sql dump file - if (isset($GLOBALS['sql_indexes'])) { - $result = $this->export->outputHandler($GLOBALS['sql_indexes']); - unset($GLOBALS['sql_indexes']); - } - //add auto increments to the sql dump file - if (isset($GLOBALS['sql_auto_increments'])) { - $result = $this->export->outputHandler($GLOBALS['sql_auto_increments']); - unset($GLOBALS['sql_auto_increments']); - } - //add constraints to the sql dump file - if (isset($GLOBALS['sql_constraints'])) { - $result = $this->export->outputHandler($GLOBALS['sql_constraints']); - unset($GLOBALS['sql_constraints']); - } - - return $result; - } - - /** - * Exports events - * - * @param string $db Database - * - * @return bool Whether it succeeded - */ - public function exportEvents($db) - { - global $crlf; - - $text = ''; - $delimiter = '$$'; - - $event_names = $GLOBALS['dbi']->fetchResult( - "SELECT EVENT_NAME FROM information_schema.EVENTS WHERE" - . " EVENT_SCHEMA= '" . $GLOBALS['dbi']->escapeString($db) - . "';" - ); - - 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 " - . Util::backquote($event_name) - . $delimiter . $crlf; - } - $text .= $GLOBALS['dbi']->getDefinition($db, 'EVENT', $event_name) - . $delimiter . $crlf . $crlf; - } - - $text .= "DELIMITER ;" . $crlf; - } - - if (! empty($text)) { - return $this->export->outputHandler($text); - } - - return false; - } - - /** - * Exports metadata from Configuration Storage - * - * @param string $db database being exported - * @param string|array $tables table(s) being exported - * @param array $metadataTypes types of metadata to export - * - * @return bool Whether it succeeded - */ - public function exportMetadata( - $db, - $tables, - array $metadataTypes - ) { - $cfgRelation = $this->relation->getRelationsParam(); - if (! isset($cfgRelation['db'])) { - return true; - } - - $comment = $this->_possibleCRLF() - . $this->_possibleCRLF() - . $this->_exportComment() - . $this->_exportComment(__('Metadata')) - . $this->_exportComment(); - if (! $this->export->outputHandler($comment)) { - return false; - } - - if (! $this->_exportUseStatement( - $cfgRelation['db'], - $GLOBALS['sql_compatibility'] - ) - ) { - return false; - } - - $r = true; - if (is_array($tables)) { - // export metadata for each table - foreach ($tables as $table) { - $r &= $this->_exportMetadata($db, $table, $metadataTypes); - } - // export metadata for the database - $r &= $this->_exportMetadata($db, null, $metadataTypes); - } else { - // export metadata for single table - $r &= $this->_exportMetadata($db, $tables, $metadataTypes); - } - - return $r; - } - - /** - * Exports metadata from Configuration Storage - * - * @param string $db database being exported - * @param string $table table being exported - * @param array $metadataTypes types of metadata to export - * - * @return bool Whether it succeeded - */ - private function _exportMetadata( - $db, - $table, - array $metadataTypes - ) { - $cfgRelation = $this->relation->getRelationsParam(); - - if (isset($table)) { - $types = [ - 'column_info' => 'db_name', - 'table_uiprefs' => 'db_name', - 'tracking' => 'db_name', - ]; - } else { - $types = [ - 'bookmark' => 'dbase', - 'relation' => 'master_db', - 'pdf_pages' => 'db_name', - 'savedsearches' => 'db_name', - 'central_columns' => 'db_name', - ]; - } - - $aliases = []; - - $comment = $this->_possibleCRLF() - . $this->_exportComment(); - - if (isset($table)) { - $comment .= $this->_exportComment( - sprintf( - __('Metadata for table %s'), - $table - ) - ); - } else { - $comment .= $this->_exportComment( - sprintf( - __('Metadata for database %s'), - $db - ) - ); - } - - $comment .= $this->_exportComment(); - - if (! $this->export->outputHandler($comment)) { - return false; - } - - foreach ($types as $type => $dbNameColumn) { - if (in_array($type, $metadataTypes) && isset($cfgRelation[$type])) { - // special case, designer pages and their coordinates - if ($type == 'pdf_pages') { - $sql_query = "SELECT `page_nr`, `page_descr` FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation[$type]) - . " WHERE " . Util::backquote($dbNameColumn) - . " = '" . $GLOBALS['dbi']->escapeString($db) . "'"; - - $result = $GLOBALS['dbi']->fetchResult( - $sql_query, - 'page_nr', - 'page_descr' - ); - - foreach ($result as $page => $name) { - // insert row for pdf_page - $sql_query_row = "SELECT `db_name`, `page_descr` FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote( - $cfgRelation[$type] - ) - . " WHERE " . Util::backquote( - $dbNameColumn - ) - . " = '" . $GLOBALS['dbi']->escapeString($db) . "'" - . " AND `page_nr` = '" . intval($page) . "'"; - - if (! $this->exportData( - $cfgRelation['db'], - $cfgRelation[$type], - $GLOBALS['crlf'], - '', - $sql_query_row, - $aliases - ) - ) { - return false; - } - - $lastPage = $GLOBALS['crlf'] - . "SET @LAST_PAGE = LAST_INSERT_ID();" - . $GLOBALS['crlf']; - if (! $this->export->outputHandler($lastPage)) { - return false; - } - - $sql_query_coords = "SELECT `db_name`, `table_name`, " - . "'@LAST_PAGE' AS `pdf_page_number`, `x`, `y` FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote( - $cfgRelation['table_coords'] - ) - . " WHERE `pdf_page_number` = '" . $page . "'"; - - $GLOBALS['exporting_metadata'] = true; - if (! $this->exportData( - $cfgRelation['db'], - $cfgRelation['table_coords'], - $GLOBALS['crlf'], - '', - $sql_query_coords, - $aliases - ) - ) { - $GLOBALS['exporting_metadata'] = false; - - return false; - } - $GLOBALS['exporting_metadata'] = false; - } - continue; - } - - // remove auto_incrementing id field for some tables - if ($type == 'bookmark') { - $sql_query = "SELECT `dbase`, `user`, `label`, `query` FROM "; - } elseif ($type == 'column_info') { - $sql_query = "SELECT `db_name`, `table_name`, `column_name`," - . " `comment`, `mimetype`, `transformation`," - . " `transformation_options`, `input_transformation`," - . " `input_transformation_options` FROM"; - } elseif ($type == 'savedsearches') { - $sql_query = "SELECT `username`, `db_name`, `search_name`," - . " `search_data` FROM"; - } else { - $sql_query = "SELECT * FROM "; - } - $sql_query .= Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation[$type]) - . " WHERE " . Util::backquote($dbNameColumn) - . " = '" . $GLOBALS['dbi']->escapeString($db) . "'"; - if (isset($table)) { - $sql_query .= " AND `table_name` = '" - . $GLOBALS['dbi']->escapeString($table) . "'"; - } - - if (! $this->exportData( - $cfgRelation['db'], - $cfgRelation[$type], - $GLOBALS['crlf'], - '', - $sql_query, - $aliases - ) - ) { - return false; - } - } - } - - return true; - } - - /** - * Returns a stand-in CREATE definition to resolve view dependencies - * - * @param string $db the database name - * @param string $view the view name - * @param string $crlf the end of line sequence - * @param array $aliases Aliases of db/table/columns - * - * @return string resulting definition - */ - public function getTableDefStandIn($db, $view, $crlf, $aliases = []) - { - $db_alias = $db; - $view_alias = $view; - $this->initAlias($aliases, $db_alias, $view_alias); - $create_query = ''; - if (! empty($GLOBALS['sql_drop_table'])) { - $create_query .= 'DROP VIEW IF EXISTS ' - . Util::backquote($view_alias) - . ';' . $crlf; - } - - $create_query .= 'CREATE TABLE '; - - if (isset($GLOBALS['sql_if_not_exists']) - && $GLOBALS['sql_if_not_exists'] - ) { - $create_query .= 'IF NOT EXISTS '; - } - $create_query .= Util::backquote($view_alias) . ' (' . $crlf; - $tmp = []; - $columns = $GLOBALS['dbi']->getColumnsFull($db, $view); - foreach ($columns as $column_name => $definition) { - $col_alias = $column_name; - if (! empty($aliases[$db]['tables'][$view]['columns'][$col_alias])) { - $col_alias = $aliases[$db]['tables'][$view]['columns'][$col_alias]; - } - $tmp[] = Util::backquote($col_alias) . ' ' . - $definition['Type'] . $crlf; - } - $create_query .= implode(',', $tmp) . ');' . $crlf; - - return $create_query; - } - - /** - * Returns CREATE definition that matches $view's structure - * - * @param string $db the database name - * @param string $view the view name - * @param string $crlf the end of line sequence - * @param bool $add_semicolon whether to add semicolon and end-of-line at - * the end - * @param array $aliases Aliases of db/table/columns - * - * @return string resulting schema - */ - private function _getTableDefForView( - $db, - $view, - $crlf, - $add_semicolon = true, - array $aliases = [] - ) { - $db_alias = $db; - $view_alias = $view; - $this->initAlias($aliases, $db_alias, $view_alias); - $create_query = "CREATE TABLE"; - if (isset($GLOBALS['sql_if_not_exists'])) { - $create_query .= " IF NOT EXISTS "; - } - $create_query .= Util::backquote($view_alias) . "(" . $crlf; - - $columns = $GLOBALS['dbi']->getColumns($db, $view, null, true); - - $firstCol = true; - foreach ($columns as $column) { - $col_alias = $column['Field']; - if (! empty($aliases[$db]['tables'][$view]['columns'][$col_alias])) { - $col_alias = $aliases[$db]['tables'][$view]['columns'][$col_alias]; - } - $extracted_columnspec = Util::extractColumnSpec( - $column['Type'] - ); - - if (! $firstCol) { - $create_query .= "," . $crlf; - } - $create_query .= " " . Util::backquote($col_alias); - $create_query .= " " . $column['Type']; - if ($extracted_columnspec['can_contain_collation'] - && ! empty($column['Collation']) - ) { - $create_query .= " COLLATE " . $column['Collation']; - } - if ($column['Null'] == 'NO') { - $create_query .= " NOT NULL"; - } - if (isset($column['Default'])) { - $create_query .= " DEFAULT '" - . $GLOBALS['dbi']->escapeString($column['Default']) . "'"; - } else { - if ($column['Null'] == 'YES') { - $create_query .= " DEFAULT NULL"; - } - } - if (! empty($column['Comment'])) { - $create_query .= " COMMENT '" - . $GLOBALS['dbi']->escapeString($column['Comment']) . "'"; - } - $firstCol = false; - } - $create_query .= $crlf . ")" . ($add_semicolon ? ';' : '') . $crlf; - - if (isset($GLOBALS['sql_compatibility'])) { - $compat = $GLOBALS['sql_compatibility']; - } else { - $compat = 'NONE'; - } - if ($compat == 'MSSQL') { - $create_query = $this->_makeCreateTableMSSQLCompatible( - $create_query - ); - } - - return $create_query; - } - - /** - * Returns $table's CREATE definition - * - * @param string $db the database name - * @param string $table the table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case - * of error - * @param bool $show_dates whether to include creation/ - * update/check dates - * @param bool $add_semicolon whether to add semicolon and - * end-of-line at the end - * @param bool $view whether we're handling a view - * @param bool $update_indexes_increments whether we need to update - * two global variables - * @param array $aliases Aliases of db/table/columns - * - * @return string resulting schema - */ - public function getTableDef( - $db, - $table, - $crlf, - $error_url, - $show_dates = false, - $add_semicolon = true, - $view = false, - $update_indexes_increments = true, - array $aliases = [] - ) { - global $sql_drop_table, $sql_backquotes, $sql_constraints, - $sql_constraints_query, $sql_indexes, $sql_indexes_query, - $sql_auto_increments, $sql_drop_foreign_keys; - - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - $schema_create = ''; - $auto_increment = ''; - $new_crlf = $crlf; - - if (isset($GLOBALS['sql_compatibility'])) { - $compat = $GLOBALS['sql_compatibility']; - } else { - $compat = 'NONE'; - } - - // need to use PhpMyAdmin\DatabaseInterface::QUERY_STORE - // with $GLOBALS['dbi']->numRows() in mysqli - $result = $GLOBALS['dbi']->tryQuery( - 'SHOW TABLE STATUS FROM ' . Util::backquote($db) - . ' WHERE Name = \'' . $GLOBALS['dbi']->escapeString((string) $table) . '\'', - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - if ($result != false) { - if ($GLOBALS['dbi']->numRows($result) > 0) { - $tmpres = $GLOBALS['dbi']->fetchAssoc($result); - - // 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 - 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:') . ' ' - . 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:') . ' ' - . 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:') . ' ' - . Util::localisedDate( - strtotime($tmpres['Check_time']) - ) - ); - $new_crlf = $this->_exportComment() . $crlf; - } - } - $GLOBALS['dbi']->freeResult($result); - } - - $schema_create .= $new_crlf; - - if (! empty($sql_drop_table) - && $GLOBALS['dbi']->getTable($db, $table)->isView() - ) { - $schema_create .= 'DROP VIEW IF EXISTS ' - . Util::backquote($table_alias, $sql_backquotes) . ';' - . $crlf; - } - - // no need to generate a DROP VIEW here, it was done earlier - if (! empty($sql_drop_table) - && ! $GLOBALS['dbi']->getTable($db, $table)->isView() - ) { - $schema_create .= 'DROP TABLE IF EXISTS ' - . Util::backquote($table_alias, $sql_backquotes) . ';' - . $crlf; - } - - // Complete table dump, - // Whether to quote table and column names or not - if ($sql_backquotes) { - $GLOBALS['dbi']->query('SET SQL_QUOTE_SHOW_CREATE = 1'); - } else { - $GLOBALS['dbi']->query('SET SQL_QUOTE_SHOW_CREATE = 0'); - } - - // I don't see the reason why this unbuffered query could cause problems, - // because SHOW CREATE TABLE returns only one row, and we free the - // results below. Nonetheless, we got 2 user reports about this - // (see bug 1562533) so I removed the unbuffered mode. - // $result = $GLOBALS['dbi']->query('SHOW CREATE TABLE ' . backquote($db) - // . '.' . backquote($table), null, DatabaseInterface::QUERY_UNBUFFERED); - // - // Note: SHOW CREATE TABLE, at least in MySQL 5.1.23, does not - // produce a displayable result for the default value of a BIT - // column, nor does the mysqldump command. See MySQL bug 35796 - $GLOBALS['dbi']->tryQuery('USE ' . Util::backquote($db)); - $result = $GLOBALS['dbi']->tryQuery( - 'SHOW CREATE TABLE ' . Util::backquote($db) . '.' - . Util::backquote($table) - ); - // an error can happen, for example the table is crashed - $tmp_error = $GLOBALS['dbi']->getError(); - if ($tmp_error) { - $message = sprintf(__('Error reading structure for table %s:'), "$db.$table"); - $message .= ' ' . $tmp_error; - if (! defined('TESTSUITE')) { - trigger_error($message, E_USER_ERROR); - } - return $this->_exportComment($message); - } - - // Old mode is stored so it can be restored once exporting is done. - $old_mode = Context::$MODE; - - $warning = ''; - if ($result != false && ($row = $GLOBALS['dbi']->fetchRow($result))) { - $create_query = $row[1]; - unset($row); - - // Convert end of line chars to one that we want (note that MySQL - // doesn't return query it will accept in all cases) - if (mb_strpos($create_query, "(\r\n ")) { - $create_query = str_replace("\r\n", $crlf, $create_query); - } elseif (mb_strpos($create_query, "(\n ")) { - $create_query = str_replace("\n", $crlf, $create_query); - } elseif (mb_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( - '/' . preg_quote(Util::backquote($db), '/') . '\./', - '', - $create_query - ); - - // exclude definition of current user - if (isset($GLOBALS['sql_view_current_user'])) { - $create_query = preg_replace( - '/(^|\s)DEFINER=([\S]+)/', - '', - $create_query - ); - } - - // whether to replace existing view or not - if (isset($GLOBALS['sql_or_replace_view'])) { - $create_query = preg_replace( - '/^CREATE/', - 'CREATE OR REPLACE', - $create_query - ); - } - } - - // Substitute aliases in `CREATE` query. - $create_query = $this->replaceWithAliases( - $create_query, - $aliases, - $db, - $table, - $flag - ); - - // One warning per view. - if ($flag && $view) { - $warning = $this->_exportComment() - . $this->_exportComment( - __('It appears your database uses views;') - ) - . $this->_exportComment( - __('alias export may not work reliably in all cases.') - ) - . $this->_exportComment(); - } - - // Adding IF NOT EXISTS, if required. - if (isset($GLOBALS['sql_if_not_exists'])) { - $create_query = preg_replace( - '/^CREATE TABLE/', - 'CREATE TABLE IF NOT EXISTS', - $create_query - ); - } - - // Making the query MSSQL compatible. - if ($compat == 'MSSQL') { - $create_query = $this->_makeCreateTableMSSQLCompatible( - $create_query - ); - } - - // Views have no constraints, indexes, etc. They do not require any - // analysis. - if (! $view) { - if (empty($sql_backquotes)) { - // Option "Enclose table and column names with backquotes" - // was checked. - Context::$MODE |= Context::SQL_MODE_NO_ENCLOSING_QUOTES; - } - - // Using appropriate quotes. - if (($compat === 'MSSQL') || ($sql_backquotes === '"')) { - Context::$MODE |= Context::SQL_MODE_ANSI_QUOTES; - } - } - - /** - * Parser used for analysis. - * - * @var Parser - */ - $parser = new Parser($create_query); - - /** - * `CREATE TABLE` statement. - * - * @var CreateStatement - */ - $statement = $parser->statements[0]; - - if (! empty($statement->entityOptions)) { - $engine = $statement->entityOptions->has('ENGINE'); - } else { - $engine = ''; - } - - /* Avoid operation on ARCHIVE tables as those can not be altered */ - if (! empty($statement->fields) && (empty($engine) || strtoupper($engine) != 'ARCHIVE')) { - - /** - * Fragments containining definition of each constraint. - * - * @var array - */ - $constraints = []; - - /** - * Fragments containining definition of each index. - * - * @var array - */ - $indexes = []; - - /** - * Fragments containining definition of each FULLTEXT index. - * - * @var array - */ - $indexes_fulltext = []; - - /** - * Fragments containining definition of each foreign key that will - * be dropped. - * - * @var array - */ - $dropped = []; - - /** - * Fragment containining definition of the `AUTO_INCREMENT`. - * - * @var array - */ - $auto_increment = []; - - // Scanning each field of the `CREATE` statement to fill the arrays - // above. - // If the field is used in any of the arrays above, it is removed - // from the original definition. - // Also, AUTO_INCREMENT attribute is removed. - /** @var CreateDefinition $field */ - foreach ($statement->fields as $key => $field) { - if ($field->isConstraint) { - // Creating the parts that add constraints. - $constraints[] = $field::build($field); - unset($statement->fields[$key]); - } elseif (! empty($field->key)) { - // Creating the parts that add indexes (must not be - // constraints). - if ($field->key->type === 'FULLTEXT KEY') { - $indexes_fulltext[] = $field->build($field); - unset($statement->fields[$key]); - } else { - if (empty($GLOBALS['sql_if_not_exists'])) { - $indexes[] = str_replace( - 'COMMENT=\'', - 'COMMENT \'', - $field::build($field) - ); - unset($statement->fields[$key]); - } - } - } - - // Creating the parts that drop foreign keys. - if (! empty($field->key)) { - if ($field->key->type === 'FOREIGN KEY') { - $dropped[] = 'FOREIGN KEY ' . Context::escape( - $field->name - ); - unset($statement->fields[$key]); - } - } - - // Dropping AUTO_INCREMENT. - if (! empty($field->options)) { - if ($field->options->has('AUTO_INCREMENT') - && empty($GLOBALS['sql_if_not_exists']) - ) { - $auto_increment[] = $field::build($field); - $field->options->remove('AUTO_INCREMENT'); - } - } - } - - /** - * The header of the `ALTER` statement (`ALTER TABLE tbl`). - * - * @var string - */ - $alter_header = 'ALTER TABLE ' . - Util::backquoteCompat( - $table_alias, - $compat, - $sql_backquotes - ); - - /** - * The footer of the `ALTER` statement (usually ';') - * - * @var string - */ - $alter_footer = ';' . $crlf; - - // Generating constraints-related query. - if (! empty($constraints)) { - $sql_constraints_query = $alter_header . $crlf . ' ADD ' - . implode(',' . $crlf . ' ADD ', $constraints) - . $alter_footer; - - $sql_constraints = $this->generateComment( - $crlf, - $sql_constraints, - __('Constraints for dumped tables'), - __('Constraints for table'), - $table_alias, - $compat - ) . $sql_constraints_query; - } - - // Generating indexes-related query. - $sql_indexes_query = ''; - - if (! empty($indexes)) { - $sql_indexes_query .= $alter_header . $crlf . ' ADD ' - . implode(',' . $crlf . ' ADD ', $indexes) - . $alter_footer; - } - - if (! empty($indexes_fulltext)) { - // InnoDB supports one FULLTEXT index creation at a time. - // So FULLTEXT indexes are created one-by-one after other - // indexes where created. - $sql_indexes_query .= $alter_header . - ' ADD ' . implode( - $alter_footer . $alter_header . ' ADD ', - $indexes_fulltext - ) . $alter_footer; - } - - if (! empty($indexes) || ! empty($indexes_fulltext)) { - $sql_indexes = $this->generateComment( - $crlf, - $sql_indexes, - __('Indexes for dumped tables'), - __('Indexes for table'), - $table_alias, - $compat - ) . $sql_indexes_query; - } - - // Generating drop foreign keys-related query. - if (! empty($dropped)) { - $sql_drop_foreign_keys = $alter_header . $crlf . ' DROP ' - . implode(',' . $crlf . ' DROP ', $dropped) - . $alter_footer; - } - - // Generating auto-increment-related query. - if (! empty($auto_increment) && $update_indexes_increments) { - $sql_auto_increments_query = $alter_header . $crlf . ' MODIFY ' - . implode(',' . $crlf . ' MODIFY ', $auto_increment); - if (isset($GLOBALS['sql_auto_increment']) - && ($statement->entityOptions->has('AUTO_INCREMENT') !== false) - ) { - if (! isset($GLOBALS['table_data']) - || (isset($GLOBALS['table_data']) - && in_array($table, $GLOBALS['table_data'])) - ) { - $sql_auto_increments_query .= ', AUTO_INCREMENT=' - . $statement->entityOptions->has('AUTO_INCREMENT'); - } - } - $sql_auto_increments_query .= ';' . $crlf; - - $sql_auto_increments = $this->generateComment( - $crlf, - $sql_auto_increments, - __('AUTO_INCREMENT for dumped tables'), - __('AUTO_INCREMENT for table'), - $table_alias, - $compat - ) . $sql_auto_increments_query; - } - - // Removing the `AUTO_INCREMENT` attribute from the `CREATE TABLE` - // too. - if (! empty($statement->entityOptions) - && (empty($GLOBALS['sql_if_not_exists']) - || empty($GLOBALS['sql_auto_increment'])) - ) { - $statement->entityOptions->remove('AUTO_INCREMENT'); - } - - // Rebuilding the query. - $create_query = $statement->build(); - } - - $schema_create .= $create_query; - } - - $GLOBALS['dbi']->freeResult($result); - - // Restoring old mode. - Context::$MODE = $old_mode; - - return $warning . $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 - * @param array $aliases Aliases of db/table/columns - * - * @return string resulting comments - */ - private function _getTableComments( - $db, - $table, - $crlf, - $do_relation = false, - $do_mime = false, - array $aliases = [] - ) { - global $cfgRelation, $sql_backquotes; - - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - $schema_create = ''; - - // Check if we can use Relations - list($res_rel, $have_rel) = $this->relation->getRelationsAndStatus( - $do_relation && ! empty($cfgRelation['relation']), - $db, - $table - ); - - if ($do_mime && $cfgRelation['mimework']) { - if (! ($mime_map = $this->transformations->getMime($db, $table, true))) { - unset($mime_map); - } - } - - if (isset($mime_map) && count($mime_map) > 0) { - $schema_create .= $this->_possibleCRLF() - . $this->_exportComment() - . $this->_exportComment( - __('MEDIA (MIME) TYPES FOR TABLE') . ' ' - . Util::backquote($table, $sql_backquotes) . ':' - ); - foreach ($mime_map as $mime_field => $mime) { - $schema_create .= $this->_exportComment( - ' ' - . Util::backquote($mime_field, $sql_backquotes) - ) - . $this->_exportComment( - ' ' - . Util::backquote( - $mime['mimetype'], - $sql_backquotes - ) - ); - } - $schema_create .= $this->_exportComment(); - } - - if ($have_rel) { - $schema_create .= $this->_possibleCRLF() - . $this->_exportComment() - . $this->_exportComment( - __('RELATIONSHIPS FOR TABLE') . ' ' - . Util::backquote($table_alias, $sql_backquotes) - . ':' - ); - - foreach ($res_rel as $rel_field => $rel) { - if ($rel_field != 'foreign_keys_data') { - $rel_field_alias = ! empty( - $aliases[$db]['tables'][$table]['columns'][$rel_field] - ) ? $aliases[$db]['tables'][$table]['columns'][$rel_field] - : $rel_field; - $schema_create .= $this->_exportComment( - ' ' - . Util::backquote( - $rel_field_alias, - $sql_backquotes - ) - ) - . $this->_exportComment( - ' ' - . Util::backquote( - $rel['foreign_table'], - $sql_backquotes - ) - . ' -> ' - . Util::backquote( - $rel['foreign_field'], - $sql_backquotes - ) - ); - } else { - foreach ($rel as $one_key) { - foreach ($one_key['index_list'] as $index => $field) { - $rel_field_alias = ! empty( - $aliases[$db]['tables'][$table]['columns'][$field] - ) ? $aliases[$db]['tables'][$table]['columns'][$field] - : $field; - $schema_create .= $this->_exportComment( - ' ' - . Util::backquote( - $rel_field_alias, - $sql_backquotes - ) - ) - . $this->_exportComment( - ' ' - . Util::backquote( - $one_key['ref_table_name'], - $sql_backquotes - ) - . ' -> ' - . Util::backquote( - $one_key['ref_index_list'][$index], - $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 - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportStructure( - $db, - $table, - $crlf, - $error_url, - $export_mode, - $export_type, - $relation = false, - $comments = false, - $mime = false, - $dates = false, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - if (isset($GLOBALS['sql_compatibility'])) { - $compat = $GLOBALS['sql_compatibility']; - } else { - $compat = 'NONE'; - } - - $formatted_table_name = Util::backquoteCompat( - $table_alias, - $compat, - isset($GLOBALS['sql_backquotes']) - ); - $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, - true, - false, - true, - $aliases - ); - $dump .= $this->_getTableComments( - $db, - $table, - $crlf, - $relation, - $mime, - $aliases - ); - break; - case 'triggers': - $dump = ''; - $delimiter = '$$'; - $triggers = $GLOBALS['dbi']->getTriggers($db, $table, $delimiter); - if ($triggers) { - $dump .= $this->_possibleCRLF() - . $this->_exportComment() - . $this->_exportComment( - __('Triggers') . ' ' . $formatted_table_name - ) - . $this->_exportComment(); - $used_alias = false; - $trigger_query = ''; - foreach ($triggers as $trigger) { - if (! empty($GLOBALS['sql_drop_table'])) { - $trigger_query .= $trigger['drop'] . ';' . $crlf; - } - - $trigger_query .= 'DELIMITER ' . $delimiter . $crlf; - $trigger_query .= $this->replaceWithAliases( - $trigger['create'], - $aliases, - $db, - $table, - $flag - ); - if ($flag) { - $used_alias = true; - } - $trigger_query .= 'DELIMITER ;' . $crlf; - } - // One warning per table. - if ($used_alias) { - $dump .= $this->_exportComment( - __('It appears your table uses triggers;') - ) - . $this->_exportComment( - __('alias export may not work reliably in all cases.') - ) - . $this->_exportComment(); - } - $dump .= $trigger_query; - } - break; - case 'create_view': - if (empty($GLOBALS['sql_views_as_tables'])) { - $dump .= $this->_exportComment( - __('Structure for view') - . ' ' - . $formatted_table_name - ) - . $this->_exportComment(); - // delete the stand-in table previously created (if any) - if ($export_type != 'table') { - $dump .= 'DROP TABLE IF EXISTS ' - . Util::backquote($table_alias) . ';' . $crlf; - } - $dump .= $this->getTableDef( - $db, - $table, - $crlf, - $error_url, - $dates, - true, - true, - true, - $aliases - ); - } else { - $dump .= $this->_exportComment( - sprintf( - __('Structure for view %s exported as a table'), - $formatted_table_name - ) - ) - . $this->_exportComment(); - // delete the stand-in table previously created (if any) - if ($export_type != 'table') { - $dump .= 'DROP TABLE IF EXISTS ' - . Util::backquote($table_alias) . ';' . $crlf; - } - $dump .= $this->_getTableDefForView( - $db, - $table, - $crlf, - true, - $aliases - ); - } - break; - case 'stand_in': - $dump .= $this->_exportComment( - __('Stand-in structure for view') . ' ' . $formatted_table_name - ) - . $this->_exportComment( - __('(See below for the actual view)') - ) - . $this->_exportComment(); - // export a stand-in definition to resolve view dependencies - $dump .= $this->getTableDefStandIn($db, $table, $crlf, $aliases); - } // 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 $this->export->outputHandler($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 - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - global $current_row, $sql_backquotes; - - // Do not export data for merge tables - if ($GLOBALS['dbi']->getTable($db, $table)->isMerge()) { - return true; - } - - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - if (isset($GLOBALS['sql_compatibility'])) { - $compat = $GLOBALS['sql_compatibility']; - } else { - $compat = 'NONE'; - } - - $formatted_table_name = Util::backquoteCompat( - $table_alias, - $compat, - $sql_backquotes - ); - - // Do not export data for a VIEW, unless asked to export the view as a table - // (For a VIEW, this is called only when exporting a single VIEW) - if ($GLOBALS['dbi']->getTable($db, $table)->isView() - && empty($GLOBALS['sql_views_as_tables']) - ) { - $head = $this->_possibleCRLF() - . $this->_exportComment() - . $this->_exportComment('VIEW ' . $formatted_table_name) - . $this->_exportComment(__('Data:') . ' ' . __('None')) - . $this->_exportComment() - . $this->_possibleCRLF(); - - return $this->export->outputHandler($head); - } - - $result = $GLOBALS['dbi']->tryQuery( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - // a possible error: the table has crashed - $tmp_error = $GLOBALS['dbi']->getError(); - if ($tmp_error) { - $message = sprintf(__('Error reading data for table %s:'), "$db.$table"); - $message .= ' ' . $tmp_error; - if (! defined('TESTSUITE')) { - trigger_error($message, E_USER_ERROR); - } - return $this->export->outputHandler( - $this->_exportComment($message) - ); - } - - if ($result == false) { - $GLOBALS['dbi']->freeResult($result); - - return true; - } - - $fields_cnt = $GLOBALS['dbi']->numFields($result); - - // Get field information - $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result); - $field_flags = []; - for ($j = 0; $j < $fields_cnt; $j++) { - $field_flags[$j] = $GLOBALS['dbi']->fieldFlags($result, $j); - } - - $field_set = []; - for ($j = 0; $j < $fields_cnt; $j++) { - $col_as = $fields_meta[$j]->name; - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $field_set[$j] = Util::backquoteCompat( - $col_as, - $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 .= Util::backquoteCompat( - $table_alias, - $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 ' - . Util::backquoteCompat( - $table_alias, - $compat, - $sql_backquotes - ) . ";"; - $truncatehead = $this->_possibleCRLF() - . $this->_exportComment() - . $this->_exportComment( - __('Truncate table before insert') . ' ' - . $formatted_table_name - ) - . $this->_exportComment() - . $crlf; - $this->export->outputHandler($truncatehead); - $this->export->outputHandler($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 ' - . Util::backquoteCompat( - $table_alias, - $compat, - $sql_backquotes - ) - // avoid EOL blank - . ' (' . $fields . ') VALUES'; - } else { - $schema_insert = $sql_command . $insert_delayed . ' INTO ' - . Util::backquoteCompat( - $table_alias, - $compat, - $sql_backquotes - ) - . ' VALUES'; - } - } - - //\x08\\x09, not required - $current_row = 0; - $query_size = 0; - if (($GLOBALS['sql_insert_syntax'] == 'extended' - || $GLOBALS['sql_insert_syntax'] == 'both') - && (! isset($GLOBALS['sql_type']) - || $GLOBALS['sql_type'] != 'UPDATE') - ) { - $separator = ','; - $schema_insert .= $crlf; - } else { - $separator = ';'; - } - - while ($row = $GLOBALS['dbi']->fetchRow($result)) { - if ($current_row == 0) { - $head = $this->_possibleCRLF() - . $this->_exportComment() - . $this->_exportComment( - __('Dumping data for table') . ' ' - . $formatted_table_name - ) - . $this->_exportComment() - . $crlf; - if (! $this->export->outputHandler($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 (! $this->export->outputHandler( - 'SET IDENTITY_INSERT ' - . Util::backquoteCompat( - $table_alias, - $compat, - $sql_backquotes - ) - . ' ON ;' . $crlf - ) - ) { - return false; - } - } - $current_row++; - $values = []; - for ($j = 0; $j < $fields_cnt; $j++) { - // NULL - if (! isset($row[$j]) || $row[$j] === null) { - $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 (false !== stripos($field_flags[$j], 'BINARY') - && isset($GLOBALS['sql_hex_for_binary']) - ) { - // 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'" . $GLOBALS['dbi']->escapeString( - Util::printableBitValue( - (int) $row[$j], - (int) $fields_meta[$j]->length - ) - ) - . "'"; - } elseif ($fields_meta[$j]->type === 'geometry') { - // export GIS types as hex - $values[] = '0x' . bin2hex($row[$j]); - } elseif (! empty($GLOBALS['exporting_metadata']) - && $row[$j] == '@LAST_PAGE' - ) { - $values[] = '@LAST_PAGE'; - } else { - // something else -> treat as a string - $values[] = '\'' - . $GLOBALS['dbi']->escapeString($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) - = Util::getUniqueCondition( - $result, // handle - $fields_cnt, // fields_cnt - $fields_meta, // fields_meta - $row, // row - false, // force_unique - false, // restrict_to_table - null // analyzed_sql_results - ); - $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) . ')'; - $insertLineSize = mb_strlen($insert_line); - $sql_max_size = $GLOBALS['sql_max_query_size']; - if (isset($sql_max_size) - && $sql_max_size > 0 - && $query_size + $insertLineSize > $sql_max_size - ) { - if (! $this->export->outputHandler(';' . $crlf)) { - return false; - } - $query_size = 0; - $current_row = 1; - $insert_line = $schema_insert . $insert_line; - } - } - $query_size += mb_strlen($insert_line); - // Other inserts case - } else { - $insert_line = $schema_insert - . '(' . implode(', ', $values) . ')'; - } - } - unset($values); - - if (! $this->export->outputHandler( - ($current_row == 1 ? '' : $separator . $crlf) - . $insert_line - ) - ) { - return false; - } - } // end while - - if ($current_row > 0) { - if (! $this->export->outputHandler(';' . $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 = $this->export->outputHandler( - $crlf . 'SET IDENTITY_INSERT ' - . Util::backquoteCompat( - $table_alias, - $compat, - $sql_backquotes - ) - . ' OFF;' . $crlf - ); - if (! $outputSucceeded) { - return false; - } - } - - $GLOBALS['dbi']->freeResult($result); - - return true; - } // end of the 'exportData()' function - - /** - * Make a create table statement compatible with MSSQL - * - * @param string $create_query MySQL create table statement - * - * @return string MSSQL compatible create table statement - */ - private function _makeCreateTableMSSQLCompatible($create_query) - { - // In MSSQL - // 1. No 'IF NOT EXISTS' in CREATE TABLE - // 2. DATE field doesn't exists, we will use DATETIME instead - // 3. UNSIGNED attribute doesn't exist - // 4. No length on INT, TINYINT, SMALLINT, BIGINT and no precision on - // FLOAT fields - // 5. No KEY and INDEX inside CREATE TABLE - // 6. DOUBLE field doesn't exists, we will use FLOAT instead - - $create_query = preg_replace( - "/^CREATE TABLE IF NOT EXISTS/", - 'CREATE TABLE', - $create_query - ); - // first we need to replace all lines ended with '" DATE ...,\n' - // last preg_replace preserve us from situation with date text - // inside DEFAULT field value - $create_query = preg_replace( - "/\" date DEFAULT NULL(,)?\n/", - '" datetime DEFAULT NULL$1' . "\n", - $create_query - ); - $create_query = preg_replace( - "/\" date NOT NULL(,)?\n/", - '" datetime NOT NULL$1' . "\n", - $create_query - ); - $create_query = preg_replace( - '/" date NOT NULL DEFAULT \'([^\'])/', - '" datetime NOT NULL DEFAULT \'$1', - $create_query - ); - - // next we need to replace all lines ended with ') UNSIGNED ...,' - // last preg_replace preserve us from situation with unsigned text - // inside DEFAULT field value - $create_query = preg_replace( - "/\) unsigned NOT NULL(,)?\n/", - ') NOT NULL$1' . "\n", - $create_query - ); - $create_query = preg_replace( - "/\) unsigned DEFAULT NULL(,)?\n/", - ') DEFAULT NULL$1' . "\n", - $create_query - ); - $create_query = preg_replace( - '/\) unsigned NOT NULL DEFAULT \'([^\'])/', - ') NOT NULL DEFAULT \'$1', - $create_query - ); - - // we need to replace all lines ended with - // '" INT|TINYINT([0-9]{1,}) ...,' last preg_replace preserve us - // from situation with int([0-9]{1,}) text inside DEFAULT field - // value - $create_query = preg_replace( - '/" (int|tinyint|smallint|bigint)\([0-9]+\) DEFAULT NULL(,)?\n/', - '" $1 DEFAULT NULL$2' . "\n", - $create_query - ); - $create_query = preg_replace( - '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL(,)?\n/', - '" $1 NOT NULL$2' . "\n", - $create_query - ); - $create_query = preg_replace( - '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL DEFAULT \'([^\'])/', - '" $1 NOT NULL DEFAULT \'$2', - $create_query - ); - - // we need to replace all lines ended with - // '" FLOAT|DOUBLE([0-9,]{1,}) ...,' - // last preg_replace preserve us from situation with - // float([0-9,]{1,}) text inside DEFAULT field value - $create_query = preg_replace( - '/" (float|double)(\([0-9]+,[0-9,]+\))? DEFAULT NULL(,)?\n/', - '" float DEFAULT NULL$3' . "\n", - $create_query - ); - $create_query = preg_replace( - '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL(,)?\n/', - '" float NOT NULL$3' . "\n", - $create_query - ); - return preg_replace( - '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL DEFAULT \'([^\'])/', - '" float NOT NULL DEFAULT \'$3', - $create_query - ); - - // @todo remove indexes from CREATE TABLE - } - - /** - * replaces db/table/column names with their aliases - * - * @param string $sql_query SQL query in which aliases are to be substituted - * @param array $aliases Alias information for db/table/column - * @param string $db the database name - * @param string $table the tablename - * @param string $flag the flag denoting whether any replacement was done - * - * @return string query replaced with aliases - */ - public function replaceWithAliases( - $sql_query, - array $aliases, - $db, - $table = '', - &$flag = null - ) { - $flag = false; - - /** - * The parser of this query. - * - * @var Parser $parser - */ - $parser = new Parser($sql_query); - - if (empty($parser->statements[0])) { - return $sql_query; - } - - /** - * The statement that represents the query. - * - * @var CreateStatement $statement - */ - $statement = $parser->statements[0]; - - /** - * Old database name. - * - * @var string $old_database - */ - $old_database = $db; - - // Replacing aliases in `CREATE TABLE` statement. - if ($statement->options->has('TABLE')) { - // Extracting the name of the old database and table from the - // statement to make sure the parameters are corect. - if (! empty($statement->name->database)) { - $old_database = $statement->name->database; - } - - /** - * Old table name. - * - * @var string $old_table - */ - $old_table = $statement->name->table; - - // Finding the aliased database name. - // The database might be empty so we have to add a few checks. - $new_database = null; - if (! empty($statement->name->database)) { - $new_database = $statement->name->database; - if (! empty($aliases[$old_database]['alias'])) { - $new_database = $aliases[$old_database]['alias']; - } - } - - // Finding the aliases table name. - $new_table = $old_table; - if (! empty($aliases[$old_database]['tables'][$old_table]['alias'])) { - $new_table = $aliases[$old_database]['tables'][$old_table]['alias']; - } - - // Replacing new values. - if (($statement->name->database !== $new_database) - || ($statement->name->table !== $new_table) - ) { - $statement->name->database = $new_database; - $statement->name->table = $new_table; - $statement->name->expr = null; // Force rebuild. - $flag = true; - } - - /** @var CreateDefinition $field */ - foreach ($statement->fields as $field) { - // Column name. - if (! empty($field->type)) { - if (! empty($aliases[$old_database]['tables'][$old_table]['columns'][$field->name])) { - $field->name = $aliases[$old_database]['tables'][$old_table]['columns'][$field->name]; - $flag = true; - } - } - - // Key's columns. - if (! empty($field->key)) { - foreach ($field->key->columns as $key => $column) { - if (! empty($aliases[$old_database]['tables'][$old_table]['columns'][$column['name']])) { - $field->key->columns[$key]['name'] = $aliases[$old_database]['tables'][$old_table]['columns'][$column['name']]; - $flag = true; - } - } - } - - // References. - if (! empty($field->references)) { - $ref_table = $field->references->table->table; - // Replacing table. - if (! empty($aliases[$old_database]['tables'][$ref_table]['alias'])) { - $field->references->table->table - = $aliases[$old_database]['tables'][$ref_table]['alias']; - $field->references->table->expr = null; - $flag = true; - } - // Replacing column names. - foreach ($field->references->columns as $key => $column) { - if (! empty($aliases[$old_database]['tables'][$ref_table]['columns'][$column])) { - $field->references->columns[$key] - = $aliases[$old_database]['tables'][$ref_table]['columns'][$column]; - $flag = true; - } - } - } - } - } elseif ($statement->options->has('TRIGGER')) { - // Extracting the name of the old database and table from the - // statement to make sure the parameters are corect. - if (! empty($statement->table->database)) { - $old_database = $statement->table->database; - } - - /** - * Old table name. - * - * @var string $old_table - */ - $old_table = $statement->table->table; - - if (! empty($aliases[$old_database]['tables'][$old_table]['alias'])) { - $statement->table->table - = $aliases[$old_database]['tables'][$old_table]['alias']; - $statement->table->expr = null; // Force rebuild. - $flag = true; - } - } - - if ($statement->options->has('TRIGGER') - || $statement->options->has('PROCEDURE') - || $statement->options->has('FUNCTION') - || $statement->options->has('VIEW') - ) { - // Repalcing the body. - for ($i = 0, $count = count($statement->body); $i < $count; ++$i) { - - /** - * Token parsed at this moment. - * - * @var Token $token - */ - $token = $statement->body[$i]; - - // Replacing only symbols (that are not variables) and unknown - // identifiers. - if (($token->type === Token::TYPE_SYMBOL) - && (! ($token->flags & Token::FLAG_SYMBOL_VARIABLE)) - || (($token->type === Token::TYPE_KEYWORD) - && (! ($token->flags & Token::FLAG_KEYWORD_RESERVED)) - || ($token->type === Token::TYPE_NONE)) - ) { - $alias = $this->getAlias($aliases, $token->value); - if (! empty($alias)) { - // Replacing the token. - $token->token = Context::escape($alias); - $flag = true; - } - } - } - } - - return $statement->build(); - } - - /** - * Generate comment - * - * @param string $crlf Carriage return character - * @param string|null $sql_statement SQL statement - * @param string $comment1 Comment for dumped table - * @param string $comment2 Comment for current table - * @param string $table_alias Table alias - * @param string $compat Compatibility mode - * - * @return string - */ - protected function generateComment( - $crlf, - ?string $sql_statement, - $comment1, - $comment2, - $table_alias, - $compat - ) { - if (! isset($sql_statement)) { - if (isset($GLOBALS['no_constraints_comments'])) { - $sql_statement = ''; - } else { - $sql_statement = $crlf - . $this->_exportComment() - . $this->_exportComment($comment1) - . $this->_exportComment(); - } - } - - // comments for current table - if (! isset($GLOBALS['no_constraints_comments'])) { - $sql_statement .= $crlf - . $this->_exportComment() - . $this->_exportComment( - $comment2 . ' ' . Util::backquoteCompat( - $table_alias, - $compat, - isset($GLOBALS['sql_backquotes']) - ) - ) - . $this->_exportComment(); - } - - return $sql_statement; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportTexytext.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportTexytext.php deleted file mode 100644 index a2fdec8..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportTexytext.php +++ /dev/null @@ -1,624 +0,0 @@ -setProperties(); - } - - /** - * Sets the export Texy! text properties - * - * @return void - */ - protected function setProperties() - { - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('Texy! text'); - $exportPluginProperties->setExtension('txt'); - $exportPluginProperties->setMimeType('text/plain'); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // what to dump (structure/data/both) main group - $dumpWhat = new OptionsPropertyMainGroup( - "general_opts", - __('Dump table') - ); - // create primary items and add them to the group - $leaf = new RadioPropertyItem("structure_or_data"); - $leaf->setValues( - [ - 'structure' => __('structure'), - 'data' => __('data'), - 'structure_and_data' => __('structure and data'), - ] - ); - $dumpWhat->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($dumpWhat); - - // data options main group - $dataOptions = new OptionsPropertyMainGroup( - "data", - __('Data dump options') - ); - $dataOptions->setForce('structure'); - // create primary items and add them to the group - $leaf = new BoolPropertyItem( - "columns", - __('Put columns names in the first row') - ); - $dataOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - 'null', - __('Replace NULL with:') - ); - $dataOptions->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($dataOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - return true; - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter() - { - return true; - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Alias of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - if (empty($db_alias)) { - $db_alias = $db; - } - - return $this->export->outputHandler( - '===' . __('Database') . ' ' . $db_alias . "\n\n" - ); - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs the content of a table in NHibernate format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - global $what; - - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - - if (! $this->export->outputHandler( - '== ' . __('Dumping data for table') . ' ' . $table_alias . "\n\n" - ) - ) { - return false; - } - - // Gets the data from the database - $result = $GLOBALS['dbi']->query( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - $fields_cnt = $GLOBALS['dbi']->numFields($result); - - // If required, get fields name at the first line - if (isset($GLOBALS[$what . '_columns'])) { - $text_output = "|------\n"; - for ($i = 0; $i < $fields_cnt; $i++) { - $col_as = $GLOBALS['dbi']->fieldName($result, $i); - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $text_output .= '|' - . htmlspecialchars(stripslashes($col_as)); - } // end for - $text_output .= "\n|------\n"; - if (! $this->export->outputHandler($text_output)) { - return false; - } - } // end if - - // Format the data - while ($row = $GLOBALS['dbi']->fetchRow($result)) { - $text_output = ''; - for ($j = 0; $j < $fields_cnt; $j++) { - if (! isset($row[$j]) || $row[$j] === null) { - $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 (! $this->export->outputHandler($text_output)) { - return false; - } - } // end while - $GLOBALS['dbi']->freeResult($result); - - return true; - } - - /** - * Returns a stand-in CREATE definition to resolve view dependencies - * - * @param string $db the database name - * @param string $view the view name - * @param string $crlf the end of line sequence - * @param array $aliases Aliases of db/table/columns - * - * @return string resulting definition - */ - public function getTableDefStandIn($db, $view, $crlf, $aliases = []) - { - $text_output = ''; - - /** - * Get the unique keys in the table - */ - $unique_keys = []; - $keys = $GLOBALS['dbi']->getTableIndexes($db, $view); - foreach ($keys as $key) { - if ($key['Non_unique'] == 0) { - $unique_keys[] = $key['Column_name']; - } - } - - /** - * Gets fields properties - */ - $GLOBALS['dbi']->selectDb($db); - - /** - * Displays the table structure - */ - - $text_output .= "|------\n" - . '|' . __('Column') - . '|' . __('Type') - . '|' . __('Null') - . '|' . __('Default') - . "\n|------\n"; - - $columns = $GLOBALS['dbi']->getColumns($db, $view); - foreach ($columns as $column) { - $col_as = $column['Field'] ?? null; - if (! empty($aliases[$db]['tables'][$view]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$view]['columns'][$col_as]; - } - $text_output .= $this->formatOneColumnDefinition( - $column, - $unique_keys, - $col_as - ); - $text_output .= "\n"; - } // end foreach - - return $text_output; - } - - /** - * Returns $table's CREATE definition - * - * @param string $db the database name - * @param string $table the table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param bool $do_relation whether to include relation comments - * @param bool $do_comments whether to include the pmadb-style column - * comments as comments in the structure; - * this is deprecated but the parameter is - * left here because export.php calls - * $this->exportStructure() also for other - * export types which use this parameter - * @param bool $do_mime whether to include mime comments - * @param bool $show_dates whether to include creation/update/check dates - * @param bool $add_semicolon whether to add semicolon and end-of-line - * at the end - * @param bool $view whether we're handling a view - * @param array $aliases Aliases of db/table/columns - * - * @return string resulting schema - */ - public function getTableDef( - $db, - $table, - $crlf, - $error_url, - $do_relation, - $do_comments, - $do_mime, - $show_dates = false, - $add_semicolon = true, - $view = false, - array $aliases = [] - ) { - global $cfgRelation; - - $text_output = ''; - - /** - * Get the unique keys in the table - */ - $unique_keys = []; - $keys = $GLOBALS['dbi']->getTableIndexes($db, $table); - foreach ($keys as $key) { - if ($key['Non_unique'] == 0) { - $unique_keys[] = $key['Column_name']; - } - } - - /** - * Gets fields properties - */ - $GLOBALS['dbi']->selectDb($db); - - // Check if we can use Relations - list($res_rel, $have_rel) = $this->relation->getRelationsAndStatus( - $do_relation && ! empty($cfgRelation['relation']), - $db, - $table - ); - - /** - * Displays the table structure - */ - - $text_output .= "|------\n"; - $text_output .= '|' . __('Column'); - $text_output .= '|' . __('Type'); - $text_output .= '|' . __('Null'); - $text_output .= '|' . __('Default'); - if ($do_relation && $have_rel) { - $text_output .= '|' . __('Links to'); - } - if ($do_comments) { - $text_output .= '|' . __('Comments'); - $comments = $this->relation->getComments($db, $table); - } - if ($do_mime && $cfgRelation['mimework']) { - $text_output .= '|' . __('Media (MIME) type'); - $mime_map = $this->transformations->getMime($db, $table, true); - } - $text_output .= "\n|------\n"; - - $columns = $GLOBALS['dbi']->getColumns($db, $table); - foreach ($columns as $column) { - $col_as = $column['Field']; - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $text_output .= $this->formatOneColumnDefinition( - $column, - $unique_keys, - $col_as - ); - $field_name = $column['Field']; - if ($do_relation && $have_rel) { - $text_output .= '|' . htmlspecialchars( - $this->getRelationString( - $res_rel, - $field_name, - $db, - $aliases - ) - ); - } - if ($do_comments && $cfgRelation['commwork']) { - $text_output .= '|' - . (isset($comments[$field_name]) - ? htmlspecialchars($comments[$field_name]) - : ''); - } - if ($do_mime && $cfgRelation['mimework']) { - $text_output .= '|' - . (isset($mime_map[$field_name]) - ? htmlspecialchars( - str_replace('_', '/', $mime_map[$field_name]['mimetype']) - ) - : ''); - } - - $text_output .= "\n"; - } // end foreach - - return $text_output; - } // end of the '$this->getTableDef()' function - - /** - * Outputs triggers - * - * @param string $db database name - * @param string $table table name - * - * @return string Formatted triggers list - */ - public function getTriggers($db, $table) - { - $dump = "|------\n"; - $dump .= '|' . __('Name'); - $dump .= '|' . __('Time'); - $dump .= '|' . __('Event'); - $dump .= '|' . __('Definition'); - $dump .= "\n|------\n"; - - $triggers = $GLOBALS['dbi']->getTriggers($db, $table); - - foreach ($triggers as $trigger) { - $dump .= '|' . $trigger['name']; - $dump .= '|' . $trigger['action_timing']; - $dump .= '|' . $trigger['event_manipulation']; - $dump .= '|' . - str_replace( - '|', - '|', - htmlspecialchars($trigger['definition']) - ); - $dump .= "\n"; - } - - return $dump; - } - - /** - * Outputs table's structure - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $export_mode 'create_table', 'triggers', 'create_view', - * 'stand_in' - * @param string $export_type 'server', 'database', 'table' - * @param bool $do_relation whether to include relation comments - * @param bool $do_comments whether to include the pmadb-style column - * comments as comments in the structure; - * this is deprecated but the parameter is - * left here because export.php calls - * $this->exportStructure() also for other - * export types which use this parameter - * @param bool $do_mime whether to include mime comments - * @param bool $dates whether to include creation/update/check dates - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportStructure( - $db, - $table, - $crlf, - $error_url, - $export_mode, - $export_type, - $do_relation = false, - $do_comments = false, - $do_mime = false, - $dates = false, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - $dump = ''; - - switch ($export_mode) { - case 'create_table': - $dump .= '== ' . __('Table structure for table') . ' ' - . $table_alias . "\n\n"; - $dump .= $this->getTableDef( - $db, - $table, - $crlf, - $error_url, - $do_relation, - $do_comments, - $do_mime, - $dates, - true, - false, - $aliases - ); - break; - case 'triggers': - $dump = ''; - $triggers = $GLOBALS['dbi']->getTriggers($db, $table); - if ($triggers) { - $dump .= '== ' . __('Triggers') . ' ' . $table_alias . "\n\n"; - $dump .= $this->getTriggers($db, $table); - } - break; - case 'create_view': - $dump .= '== ' . __('Structure for view') . ' ' . $table_alias . "\n\n"; - $dump .= $this->getTableDef( - $db, - $table, - $crlf, - $error_url, - $do_relation, - $do_comments, - $do_mime, - $dates, - true, - true, - $aliases - ); - break; - case 'stand_in': - $dump .= '== ' . __('Stand-in structure for view') - . ' ' . $table . "\n\n"; - // export a stand-in definition to resolve view dependencies - $dump .= $this->getTableDefStandIn($db, $table, $crlf, $aliases); - } // end switch - - return $this->export->outputHandler($dump); - } - - /** - * Formats the definition for one column - * - * @param array $column info about this column - * @param array $unique_keys unique keys for this table - * @param string $col_alias Column Alias - * - * @return string Formatted column definition - */ - public function formatOneColumnDefinition( - $column, - $unique_keys, - $col_alias = '' - ) { - if (empty($col_alias)) { - $col_alias = $column['Field']; - } - $extracted_columnspec - = Util::extractColumnSpec($column['Type']); - $type = $extracted_columnspec['print_type']; - if (empty($type)) { - $type = ' '; - } - - 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 .= '**'; - } - if ($column['Key'] == 'PRI') { - $fmt_pre = '//' . $fmt_pre; - $fmt_post .= '//'; - } - $definition = '|' - . $fmt_pre . htmlspecialchars($col_alias) . $fmt_post; - $definition .= '|' . htmlspecialchars($type); - $definition .= '|' - . (($column['Null'] == '' || $column['Null'] == 'NO') - ? __('No') : __('Yes')); - $definition .= '|' - . htmlspecialchars( - isset($column['Default']) ? $column['Default'] : '' - ); - - return $definition; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportXml.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportXml.php deleted file mode 100644 index db85add..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportXml.php +++ /dev/null @@ -1,593 +0,0 @@ -setProperties(); - } - - /** - * Initialize the local variables that are used for export XML - * - * @return void - */ - protected function initSpecificVariables() - { - global $table, $tables; - $this->_setTable($table); - if (is_array($tables)) { - $this->_setTables($tables); - } - } - - /** - * Sets the export XML properties - * - * @return void - */ - protected function setProperties() - { - // create the export plugin property item - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('XML'); - $exportPluginProperties->setExtension('xml'); - $exportPluginProperties->setMimeType('text/xml'); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - // create primary items and add them to the group - $leaf = new HiddenPropertyItem("structure_or_data"); - $generalOptions->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($generalOptions); - - // export structure main group - $structure = new OptionsPropertyMainGroup( - "structure", - __('Object creation options (all are recommended)') - ); - - // create primary items and add them to the group - $leaf = new BoolPropertyItem( - "export_events", - __('Events') - ); - $structure->addProperty($leaf); - $leaf = new BoolPropertyItem( - "export_functions", - __('Functions') - ); - $structure->addProperty($leaf); - $leaf = new BoolPropertyItem( - "export_procedures", - __('Procedures') - ); - $structure->addProperty($leaf); - $leaf = new BoolPropertyItem( - "export_tables", - __('Tables') - ); - $structure->addProperty($leaf); - $leaf = new BoolPropertyItem( - "export_triggers", - __('Triggers') - ); - $structure->addProperty($leaf); - $leaf = new BoolPropertyItem( - "export_views", - __('Views') - ); - $structure->addProperty($leaf); - $exportSpecificOptions->addProperty($structure); - - // data main group - $data = new OptionsPropertyMainGroup( - "data", - __('Data dump options') - ); - // create primary items and add them to the group - $leaf = new BoolPropertyItem( - "export_contents", - __('Export contents') - ); - $data->addProperty($leaf); - $exportSpecificOptions->addProperty($data); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Generates output for SQL defintions of routines - * - * @param string $db Database name - * @param string $type Item type to be used in XML output - * @param string $dbitype Item type used in DBI qieries - * - * @return string XML with definitions - */ - private function _exportRoutines($db, $type, $dbitype) - { - // Export routines - $routines = $GLOBALS['dbi']->getProceduresOrFunctions( - $db, - $dbitype - ); - return $this->_exportDefinitions($db, $type, $dbitype, $routines); - } - - /** - * Generates output for SQL defintions - * - * @param string $db Database name - * @param string $type Item type to be used in XML output - * @param string $dbitype Item type used in DBI qieries - * @param array $names Names of items to export - * - * @return string XML with definitions - */ - private function _exportDefinitions($db, $type, $dbitype, array $names) - { - global $crlf; - - $head = ''; - - if ($names) { - foreach ($names as $name) { - $head .= ' ' . $crlf; - - // Do some formatting - $sql = $GLOBALS['dbi']->getDefinition($db, $dbitype, $name); - $sql = htmlspecialchars(rtrim($sql)); - $sql = str_replace("\n", "\n ", $sql); - - $head .= " " . $sql . $crlf; - $head .= ' ' . $crlf; - } - } - - return $head; - } - - /** - * Outputs export header. It is the first method to be called, so all - * the required variables are initialized here. - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - $this->initSpecificVariables(); - global $crlf, $cfg, $db; - $table = $this->_getTable(); - $tables = $this->_getTables(); - - $export_struct = isset($GLOBALS['xml_export_functions']) - || isset($GLOBALS['xml_export_procedures']) - || isset($GLOBALS['xml_export_tables']) - || isset($GLOBALS['xml_export_triggers']) - || isset($GLOBALS['xml_export_views']); - $export_data = isset($GLOBALS['xml_export_contents']) ? true : false; - - if ($GLOBALS['output_charset_conversion']) { - $charset = $GLOBALS['charset']; - } else { - $charset = 'utf-8'; - } - - $head = '' . $crlf - . '' . $crlf . $crlf; - - $head .= '' . $crlf; - - if ($export_struct) { - $result = $GLOBALS['dbi']->fetchResult( - 'SELECT `DEFAULT_CHARACTER_SET_NAME`, `DEFAULT_COLLATION_NAME`' - . ' FROM `information_schema`.`SCHEMATA` WHERE `SCHEMA_NAME`' - . ' = \'' . $GLOBALS['dbi']->escapeString($db) . '\' LIMIT 1' - ); - $db_collation = $result[0]['DEFAULT_COLLATION_NAME']; - $db_charset = $result[0]['DEFAULT_CHARACTER_SET_NAME']; - - $head .= ' ' . $crlf; - $head .= ' ' . $crlf; - $head .= ' ' . $crlf; - - if ($tables === null) { - $tables = []; - } - - if (count($tables) === 0) { - $tables[] = $table; - } - - foreach ($tables as $table) { - // Export tables and views - $result = $GLOBALS['dbi']->fetchResult( - 'SHOW CREATE TABLE ' . Util::backquote($db) . '.' - . Util::backquote($table), - 0 - ); - $tbl = $result[$table][1]; - - $is_view = $GLOBALS['dbi']->getTable($db, $table) - ->isView(); - - if ($is_view) { - $type = 'view'; - } else { - $type = 'table'; - } - - if ($is_view && ! isset($GLOBALS['xml_export_views'])) { - continue; - } - - if (! $is_view && ! isset($GLOBALS['xml_export_tables'])) { - continue; - } - - $head .= ' ' - . $crlf; - - $tbl = " " . htmlspecialchars($tbl); - $tbl = str_replace("\n", "\n ", $tbl); - - $head .= $tbl . ';' . $crlf; - $head .= ' ' . $crlf; - - if (isset($GLOBALS['xml_export_triggers']) - && $GLOBALS['xml_export_triggers'] - ) { - // Export triggers - $triggers = $GLOBALS['dbi']->getTriggers($db, $table); - if ($triggers) { - foreach ($triggers as $trigger) { - $code = $trigger['create']; - $head .= ' ' . $crlf; - - // Do some formatting - $code = mb_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'] - ) { - $head .= $this->_exportRoutines($db, 'function', 'FUNCTION'); - } - - if (isset($GLOBALS['xml_export_procedures']) - && $GLOBALS['xml_export_procedures'] - ) { - $head .= $this->_exportRoutines($db, 'procedure', 'PROCEDURE'); - } - - if (isset($GLOBALS['xml_export_events']) - && $GLOBALS['xml_export_events'] - ) { - // Export events - $events = $GLOBALS['dbi']->fetchResult( - "SELECT EVENT_NAME FROM information_schema.EVENTS " - . "WHERE EVENT_SCHEMA='" . $GLOBALS['dbi']->escapeString($db) - . "'" - ); - $head .= $this->_exportDefinitions( - $db, - 'event', - 'EVENT', - $events - ); - } - - unset($result); - - $head .= ' ' . $crlf; - $head .= ' ' . $crlf; - - if ($export_data) { - $head .= $crlf; - } - } - - return $this->export->outputHandler($head); - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter() - { - $foot = ''; - - return $this->export->outputHandler($foot); - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - global $crlf; - - if (empty($db_alias)) { - $db_alias = $db; - } - if (isset($GLOBALS['xml_export_contents']) - && $GLOBALS['xml_export_contents'] - ) { - $head = ' ' . $crlf . ' ' . $crlf; - - return $this->export->outputHandler($head); - } - - 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 $this->export->outputHandler(' ' . $crlf); - } - - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs the content of a table in XML format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - // Do not export data for merge tables - if ($GLOBALS['dbi']->getTable($db, $table)->isMerge()) { - return true; - } - - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - if (isset($GLOBALS['xml_export_contents']) - && $GLOBALS['xml_export_contents'] - ) { - $result = $GLOBALS['dbi']->query( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - - $columns_cnt = $GLOBALS['dbi']->numFields($result); - $columns = []; - for ($i = 0; $i < $columns_cnt; $i++) { - $columns[$i] = stripslashes($GLOBALS['dbi']->fieldName($result, $i)); - } - unset($i); - - $buffer = ' ' . $crlf; - if (! $this->export->outputHandler($buffer)) { - return false; - } - - while ($record = $GLOBALS['dbi']->fetchRow($result)) { - $buffer = ' ' . $crlf; - for ($i = 0; $i < $columns_cnt; $i++) { - $col_as = $columns[$i]; - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as]) - ) { - $col_as - = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - // If a cell is NULL, still export it to preserve - // the XML structure - if (! isset($record[$i]) || $record[$i] === null) { - $record[$i] = 'NULL'; - } - $buffer .= ' ' - . htmlspecialchars((string) $record[$i]) - . '' . $crlf; - } - $buffer .= '
    ' . $crlf; - - if (! $this->export->outputHandler($buffer)) { - return false; - } - } - $GLOBALS['dbi']->freeResult($result); - } - - return true; - } - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the table name - * - * @return string - */ - private function _getTable() - { - return $this->_table; - } - - /** - * Sets the table name - * - * @param string $table table name - * - * @return void - */ - private function _setTable($table) - { - $this->_table = $table; - } - - /** - * Gets the table names - * - * @return array - */ - private function _getTables() - { - return $this->_tables; - } - - /** - * Sets the table names - * - * @param array $tables table names - * - * @return void - */ - private function _setTables(array $tables) - { - $this->_tables = $tables; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportYaml.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportYaml.php deleted file mode 100644 index 971f9c6..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportYaml.php +++ /dev/null @@ -1,230 +0,0 @@ -setProperties(); - } - - /** - * Sets the export YAML properties - * - * @return void - */ - protected function setProperties() - { - $exportPluginProperties = new ExportPluginProperties(); - $exportPluginProperties->setText('YAML'); - $exportPluginProperties->setExtension('yml'); - $exportPluginProperties->setMimeType('text/yaml'); - $exportPluginProperties->setForceFile(true); - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - // create primary items and add them to the group - $leaf = new HiddenPropertyItem("structure_or_data"); - $generalOptions->addProperty($leaf); - // add the main group to the root group - $exportSpecificOptions->addProperty($generalOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader() - { - $this->export->outputHandler( - '%YAML 1.1' . $GLOBALS['crlf'] . '---' . $GLOBALS['crlf'] - ); - - return true; - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter() - { - $this->export->outputHandler('...' . $GLOBALS['crlf']); - - return true; - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader($db, $db_alias = '') - { - return true; - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter($db) - { - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $export_type, $db_alias = '') - { - return true; - } - - /** - * Outputs the content of a table in JSON format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ) { - $db_alias = $db; - $table_alias = $table; - $this->initAlias($aliases, $db_alias, $table_alias); - $result = $GLOBALS['dbi']->query( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - - $columns_cnt = $GLOBALS['dbi']->numFields($result); - $columns = []; - for ($i = 0; $i < $columns_cnt; $i++) { - $col_as = $GLOBALS['dbi']->fieldName($result, $i); - if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $columns[$i] = stripslashes($col_as); - } - - $buffer = ''; - $record_cnt = 0; - while ($record = $GLOBALS['dbi']->fetchRow($result)) { - $record_cnt++; - - // Output table name as comment if this is the first record of the table - if ($record_cnt == 1) { - $buffer = '# ' . $db_alias . '.' . $table_alias . $crlf; - $buffer .= '-' . $crlf; - } else { - $buffer = '-' . $crlf; - } - - for ($i = 0; $i < $columns_cnt; $i++) { - if (! isset($record[$i])) { - continue; - } - - if ($record[$i] === null) { - $buffer .= ' ' . $columns[$i] . ': null' . $crlf; - continue; - } - - if (is_numeric($record[$i])) { - $buffer .= ' ' . $columns[$i] . ': ' . $record[$i] . $crlf; - continue; - } - - $record[$i] = str_replace( - [ - '\\', - '"', - "\n", - "\r", - ], - [ - '\\\\', - '\"', - '\n', - '\r', - ], - $record[$i] - ); - $buffer .= ' ' . $columns[$i] . ': "' . $record[$i] . '"' . $crlf; - } - - if (! $this->export->outputHandler($buffer)) { - return false; - } - } - $GLOBALS['dbi']->freeResult($result); - - return true; - } // end getTableYAML -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/Pdf.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/Pdf.php deleted file mode 100644 index 58f1b5a..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/Pdf.php +++ /dev/null @@ -1,855 +0,0 @@ -relation = new Relation($GLOBALS['dbi']); - $this->transformations = new Transformations(); - } - - /** - * Add page if needed. - * - * @param float|int $h cell height. Default value: 0 - * @param mixed $y starting y position, leave empty for current - * position - * @param boolean $addpage if true add a page, otherwise only return - * the true/false state - * - * @return boolean true in case of page break, false otherwise. - */ - public function checkPageBreak($h = 0, $y = '', $addpage = true) - { - if (TCPDF_STATIC::empty_string($y)) { - $y = $this->y; - } - $current_page = $this->page; - if ((($y + $h) > $this->PageBreakTrigger) - && (! $this->InFooter) - && $this->AcceptPageBreak() - ) { - if ($addpage) { - //Automatic page break - $x = $this->x; - $this->AddPage($this->CurOrientation); - $this->y = $this->dataY; - $oldpage = $this->page - 1; - - $this_page_orm = $this->pagedim[$this->page]['orm']; - $old_page_orm = $this->pagedim[$oldpage]['orm']; - $this_page_olm = $this->pagedim[$this->page]['olm']; - $old_page_olm = $this->pagedim[$oldpage]['olm']; - if ($this->rtl) { - if ($this_page_orm != $old_page_orm) { - $this->x = $x - ($this_page_orm - $old_page_orm); - } else { - $this->x = $x; - } - } else { - if ($this_page_olm != $old_page_olm) { - $this->x = $x + ($this_page_olm - $old_page_olm); - } else { - $this->x = $x; - } - } - } - - return true; - } - - // account for columns mode - return $current_page != $this->page; - } - - /** - * This method is used to render the page header. - * - * @return void - */ - // @codingStandardsIgnoreLine - public function Header() - { - global $maxY; - // We don't want automatic page breaks while generating header - // as this can lead to infinite recursion as auto generated page - // will want header as well causing another page break - // FIXME: Better approach might be to try to compact the content - $this->SetAutoPageBreak(false); - // Check if header for this page already exists - if (! isset($this->headerset[$this->page])) { - $this->SetY($this->tMargin - ($this->FontSizePt / $this->k) * 5); - $this->cellFontSize = $this->FontSizePt; - $this->SetFont( - PdfLib::PMA_PDF_FONT, - '', - ($this->titleFontSize - ?: $this->FontSizePt) - ); - $this->Cell(0, $this->FontSizePt, $this->titleText, 0, 1, 'C'); - $this->SetFont(PdfLib::PMA_PDF_FONT, '', $this->cellFontSize); - $this->SetY($this->tMargin - ($this->FontSizePt / $this->k) * 2.5); - $this->Cell( - 0, - $this->FontSizePt, - __('Database:') . ' ' . $this->dbAlias . ', ' - . __('Table:') . ' ' . $this->tableAlias . ', ' - . __('Purpose:') . ' ' . $this->purpose, - 0, - 1, - 'L' - ); - $l = $this->lMargin; - foreach ($this->colTitles as $col => $txt) { - $this->SetXY($l, $this->tMargin); - $this->MultiCell( - $this->tablewidths[$col], - $this->FontSizePt, - $txt - ); - $l += $this->tablewidths[$col]; - $maxY = $maxY < $this->GetY() ? $this->GetY() : $maxY; - } - $this->SetXY($this->lMargin, $this->tMargin); - $this->SetFillColor(200, 200, 200); - $l = $this->lMargin; - foreach ($this->colTitles as $col => $txt) { - $this->SetXY($l, $this->tMargin); - $this->Cell( - $this->tablewidths[$col], - $maxY - $this->tMargin, - '', - 1, - 0, - 'L', - 1 - ); - $this->SetXY($l, $this->tMargin); - $this->MultiCell( - $this->tablewidths[$col], - $this->FontSizePt, - $txt, - 0, - 'C' - ); - $l += $this->tablewidths[$col]; - } - $this->SetFillColor(255, 255, 255); - // set headerset - $this->headerset[$this->page] = 1; - } - - $this->dataY = $maxY; - $this->SetAutoPageBreak(true); - } - - /** - * Generate table - * - * @param int $lineheight Height of line - * - * @return void - */ - public function morepagestable($lineheight = 8) - { - // some things to set and 'remember' - $l = $this->lMargin; - $startheight = $h = $this->dataY; - $startpage = $currpage = $this->page; - - // calculate the whole width - $fullwidth = 0; - foreach ($this->tablewidths as $width) { - $fullwidth += $width; - } - - // Now let's start to write the table - $row = 0; - $tmpheight = []; - $maxpage = $this->page; - - while ($data = $GLOBALS['dbi']->fetchRow($this->results)) { - $this->page = $currpage; - // write the horizontal borders - $this->Line($l, $h, $fullwidth + $l, $h); - // write the content and remember the height of the highest col - foreach ($data as $col => $txt) { - $this->page = $currpage; - $this->SetXY($l, $h); - if ($this->tablewidths[$col] > 0) { - $this->MultiCell( - $this->tablewidths[$col], - $lineheight, - $txt, - 0, - $this->colAlign[$col] - ); - $l += $this->tablewidths[$col]; - } - - if (! isset($tmpheight[$row . '-' . $this->page])) { - $tmpheight[$row . '-' . $this->page] = 0; - } - if ($tmpheight[$row . '-' . $this->page] < $this->GetY()) { - $tmpheight[$row . '-' . $this->page] = $this->GetY(); - } - if ($this->page > $maxpage) { - $maxpage = $this->page; - } - unset($data[$col]); - } - - // get the height we were in the last used page - $h = $tmpheight[$row . '-' . $maxpage]; - // set the "pointer" to the left margin - $l = $this->lMargin; - // set the $currpage to the last page - $currpage = $maxpage; - unset($data[$row]); - $row++; - } - // draw the borders - // we start adding a horizontal line on the last page - $this->page = $maxpage; - $this->Line($l, $h, $fullwidth + $l, $h); - // now we start at the top of the document and walk down - for ($i = $startpage; $i <= $maxpage; $i++) { - $this->page = $i; - $l = $this->lMargin; - $t = $i == $startpage ? $startheight : $this->tMargin; - $lh = $i == $maxpage ? $h : $this->h - $this->bMargin; - $this->Line($l, $t, $l, $lh); - foreach ($this->tablewidths as $width) { - $l += $width; - $this->Line($l, $t, $l, $lh); - } - } - // set it to the last page, if not it'll cause some problems - $this->page = $maxpage; - } - - /** - * Sets a set of attributes. - * - * @param array $attr array containing the attributes - * - * @return void - */ - public function setAttributes(array $attr = []) - { - foreach ($attr as $key => $val) { - $this->$key = $val; - } - } - - /** - * Defines the top margin. - * The method can be called before creating the first page. - * - * @param float $topMargin the margin - * - * @return void - */ - public function setTopMargin($topMargin) - { - $this->tMargin = $topMargin; - } - - /** - * Prints triggers - * - * @param string $db database name - * @param string $table table name - * - * @return void - */ - public function getTriggers($db, $table) - { - $triggers = $GLOBALS['dbi']->getTriggers($db, $table); - if ([] === $triggers) { - return; //prevents printing blank trigger list for any table - } - - unset($this->tablewidths); - unset($this->colTitles); - unset($this->titleWidth); - unset($this->colFits); - unset($this->display_column); - unset($this->colAlign); - - /** - * Making table heading - * Keeping column width constant - */ - $this->colTitles[0] = __('Name'); - $this->tablewidths[0] = 90; - $this->colTitles[1] = __('Time'); - $this->tablewidths[1] = 80; - $this->colTitles[2] = __('Event'); - $this->tablewidths[2] = 40; - $this->colTitles[3] = __('Definition'); - $this->tablewidths[3] = 240; - - for ($columns_cnt = 0; $columns_cnt < 4; $columns_cnt++) { - $this->colAlign[$columns_cnt] = 'L'; - $this->display_column[$columns_cnt] = true; - } - - // Starting to fill table with required info - - $this->SetY($this->tMargin); - $this->AddPage(); - $this->SetFont(PdfLib::PMA_PDF_FONT, '', 9); - - $l = $this->lMargin; - $startheight = $h = $this->dataY; - $startpage = $currpage = $this->page; - - // calculate the whole width - $fullwidth = 0; - foreach ($this->tablewidths as $width) { - $fullwidth += $width; - } - - $row = 0; - $tmpheight = []; - $maxpage = $this->page; - $data = []; - - foreach ($triggers as $trigger) { - $data[] = $trigger['name']; - $data[] = $trigger['action_timing']; - $data[] = $trigger['event_manipulation']; - $data[] = $trigger['definition']; - $this->page = $currpage; - // write the horizontal borders - $this->Line($l, $h, $fullwidth + $l, $h); - // write the content and remember the height of the highest col - foreach ($data as $col => $txt) { - $this->page = $currpage; - $this->SetXY($l, $h); - if ($this->tablewidths[$col] > 0) { - $this->MultiCell( - $this->tablewidths[$col], - $this->FontSizePt, - $txt, - 0, - $this->colAlign[$col] - ); - $l += $this->tablewidths[$col]; - } - - if (! isset($tmpheight[$row . '-' . $this->page])) { - $tmpheight[$row . '-' . $this->page] = 0; - } - if ($tmpheight[$row . '-' . $this->page] < $this->GetY()) { - $tmpheight[$row . '-' . $this->page] = $this->GetY(); - } - if ($this->page > $maxpage) { - $maxpage = $this->page; - } - } - // get the height we were in the last used page - $h = $tmpheight[$row . '-' . $maxpage]; - // set the "pointer" to the left margin - $l = $this->lMargin; - // set the $currpage to the last page - $currpage = $maxpage; - unset($data); - $row++; - } - // draw the borders - // we start adding a horizontal line on the last page - $this->page = $maxpage; - $this->Line($l, $h, $fullwidth + $l, $h); - // now we start at the top of the document and walk down - for ($i = $startpage; $i <= $maxpage; $i++) { - $this->page = $i; - $l = $this->lMargin; - $t = $i == $startpage ? $startheight : $this->tMargin; - $lh = $i == $maxpage ? $h : $this->h - $this->bMargin; - $this->Line($l, $t, $l, $lh); - foreach ($this->tablewidths as $width) { - $l += $width; - $this->Line($l, $t, $l, $lh); - } - } - // set it to the last page, if not it'll cause some problems - $this->page = $maxpage; - } - - /** - * Print $table's CREATE definition - * - * @param string $db the database name - * @param string $table the table name - * @param bool $do_relation whether to include relation comments - * @param bool $do_comments whether to include the pmadb-style column - * comments as comments in the structure; - * this is deprecated but the parameter is - * left here because export.php calls - * PMA_exportStructure() also for other - * export types which use this parameter - * @param bool $do_mime whether to include mime comments - * @param bool $view whether we're handling a view - * @param array $aliases aliases of db/table/columns - * - * @return void - */ - public function getTableDef( - $db, - $table, - $do_relation, - $do_comments, - $do_mime, - $view = false, - array $aliases = [] - ) { - // set $cfgRelation here, because there is a chance that it's modified - // since the class initialization - global $cfgRelation; - - unset($this->tablewidths); - unset($this->colTitles); - unset($this->titleWidth); - unset($this->colFits); - unset($this->display_column); - unset($this->colAlign); - - /** - * Gets fields properties - */ - $GLOBALS['dbi']->selectDb($db); - - /** - * All these three checks do_relation, do_comment and do_mime is - * not required. As presently all are set true by default. - * But when, methods to take user input will be developed, - * it will be of use - */ - // Check if we can use Relations - if ($do_relation) { - // Find which tables are related with the current one and write it in - // an array - $res_rel = $this->relation->getForeigners($db, $table); - $have_rel = ! empty($res_rel); - } else { - $have_rel = false; - } // end if - - //column count and table heading - - $this->colTitles[0] = __('Column'); - $this->tablewidths[0] = 90; - $this->colTitles[1] = __('Type'); - $this->tablewidths[1] = 80; - $this->colTitles[2] = __('Null'); - $this->tablewidths[2] = 40; - $this->colTitles[3] = __('Default'); - $this->tablewidths[3] = 120; - - for ($columns_cnt = 0; $columns_cnt < 4; $columns_cnt++) { - $this->colAlign[$columns_cnt] = 'L'; - $this->display_column[$columns_cnt] = true; - } - - if ($do_relation && $have_rel) { - $this->colTitles[$columns_cnt] = __('Links to'); - $this->display_column[$columns_cnt] = true; - $this->colAlign[$columns_cnt] = 'L'; - $this->tablewidths[$columns_cnt] = 120; - $columns_cnt++; - } - if ($do_comments /*&& $cfgRelation['commwork']*/) { - $this->colTitles[$columns_cnt] = __('Comments'); - $this->display_column[$columns_cnt] = true; - $this->colAlign[$columns_cnt] = 'L'; - $this->tablewidths[$columns_cnt] = 120; - $columns_cnt++; - } - if ($do_mime && $cfgRelation['mimework']) { - $this->colTitles[$columns_cnt] = __('Media (MIME) type'); - $this->display_column[$columns_cnt] = true; - $this->colAlign[$columns_cnt] = 'L'; - $this->tablewidths[$columns_cnt] = 120; - $columns_cnt++; - } - - // Starting to fill table with required info - - $this->SetY($this->tMargin); - $this->AddPage(); - $this->SetFont(PdfLib::PMA_PDF_FONT, '', 9); - - // Now let's start to write the table structure - - if ($do_comments) { - $comments = $this->relation->getComments($db, $table); - } - if ($do_mime && $cfgRelation['mimework']) { - $mime_map = $this->transformations->getMime($db, $table, true); - } - - $columns = $GLOBALS['dbi']->getColumns($db, $table); - - // some things to set and 'remember' - $l = $this->lMargin; - $startheight = $h = $this->dataY; - $startpage = $currpage = $this->page; - // calculate the whole width - $fullwidth = 0; - foreach ($this->tablewidths as $width) { - $fullwidth += $width; - } - - $row = 0; - $tmpheight = []; - $maxpage = $this->page; - $data = []; - - // fun begin - foreach ($columns as $column) { - $extracted_columnspec - = Util::extractColumnSpec($column['Type']); - - $type = $extracted_columnspec['print_type']; - if (empty($type)) { - $type = ' '; - } - - if (! isset($column['Default'])) { - if ($column['Null'] != 'NO') { - $column['Default'] = 'NULL'; - } - } - $data[] = $column['Field']; - $data[] = $type; - $data[] = $column['Null'] == '' || $column['Null'] == 'NO' - ? 'No' - : 'Yes'; - $data[] = isset($column['Default']) ? $column['Default'] : ''; - - $field_name = $column['Field']; - - if ($do_relation && $have_rel) { - $data[] = isset($res_rel[$field_name]) - ? $res_rel[$field_name]['foreign_table'] - . ' (' . $res_rel[$field_name]['foreign_field'] - . ')' - : ''; - } - if ($do_comments) { - $data[] = isset($comments[$field_name]) - ? $comments[$field_name] - : ''; - } - if ($do_mime) { - $data[] = isset($mime_map[$field_name]) - ? $mime_map[$field_name]['mimetype'] - : ''; - } - - $this->page = $currpage; - // write the horizontal borders - $this->Line($l, $h, $fullwidth + $l, $h); - // write the content and remember the height of the highest col - foreach ($data as $col => $txt) { - $this->page = $currpage; - $this->SetXY($l, $h); - if ($this->tablewidths[$col] > 0) { - $this->MultiCell( - $this->tablewidths[$col], - $this->FontSizePt, - $txt, - 0, - $this->colAlign[$col] - ); - $l += $this->tablewidths[$col]; - } - - if (! isset($tmpheight[$row . '-' . $this->page])) { - $tmpheight[$row . '-' . $this->page] = 0; - } - if ($tmpheight[$row . '-' . $this->page] < $this->GetY()) { - $tmpheight[$row . '-' . $this->page] = $this->GetY(); - } - if ($this->page > $maxpage) { - $maxpage = $this->page; - } - } - - // get the height we were in the last used page - $h = $tmpheight[$row . '-' . $maxpage]; - // set the "pointer" to the left margin - $l = $this->lMargin; - // set the $currpage to the last page - $currpage = $maxpage; - unset($data); - $row++; - } - // draw the borders - // we start adding a horizontal line on the last page - $this->page = $maxpage; - $this->Line($l, $h, $fullwidth + $l, $h); - // now we start at the top of the document and walk down - for ($i = $startpage; $i <= $maxpage; $i++) { - $this->page = $i; - $l = $this->lMargin; - $t = $i == $startpage ? $startheight : $this->tMargin; - $lh = $i == $maxpage ? $h : $this->h - $this->bMargin; - $this->Line($l, $t, $l, $lh); - foreach ($this->tablewidths as $width) { - $l += $width; - $this->Line($l, $t, $l, $lh); - } - } - // set it to the last page, if not it'll cause some problems - $this->page = $maxpage; - } - - /** - * MySQL report - * - * @param string $query Query to execute - * - * @return void - */ - public function mysqlReport($query) - { - unset($this->tablewidths); - unset($this->colTitles); - unset($this->titleWidth); - unset($this->colFits); - unset($this->display_column); - unset($this->colAlign); - - /** - * Pass 1 for column widths - */ - $this->results = $GLOBALS['dbi']->query( - $query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - $this->numFields = $GLOBALS['dbi']->numFields($this->results); - $this->fields = $GLOBALS['dbi']->getFieldsMeta($this->results); - - // sColWidth = starting col width (an average size width) - $availableWidth = $this->w - $this->lMargin - $this->rMargin; - $this->sColWidth = $availableWidth / $this->numFields; - $totalTitleWidth = 0; - - // loop through results header and set initial - // col widths/ titles/ alignment - // if a col title is less than the starting col width, - // reduce that column size - $colFits = []; - $titleWidth = []; - for ($i = 0; $i < $this->numFields; $i++) { - $col_as = $this->fields[$i]->name; - $db = $this->currentDb; - $table = $this->currentTable; - if (! empty($this->aliases[$db]['tables'][$table]['columns'][$col_as])) { - $col_as = $this->aliases[$db]['tables'][$table]['columns'][$col_as]; - } - $stringWidth = $this->GetStringWidth($col_as) + 6; - // save the real title's width - $titleWidth[$i] = $stringWidth; - $totalTitleWidth += $stringWidth; - - // set any column titles less than the start width to - // the column title width - if ($stringWidth < $this->sColWidth) { - $colFits[$i] = $stringWidth; - } - $this->colTitles[$i] = $col_as; - $this->display_column[$i] = true; - - switch ($this->fields[$i]->type) { - case 'int': - $this->colAlign[$i] = 'R'; - break; - case 'blob': - case 'tinyblob': - case 'mediumblob': - case 'longblob': - /** - * @todo do not deactivate completely the display - * but show the field's name and [BLOB] - */ - if (false !== stripos($this->fields[$i]->flags, 'BINARY')) { - $this->display_column[$i] = false; - unset($this->colTitles[$i]); - } - $this->colAlign[$i] = 'L'; - break; - default: - $this->colAlign[$i] = 'L'; - } - } - - // title width verification - if ($totalTitleWidth > $availableWidth) { - $adjustingMode = true; - } else { - $adjustingMode = false; - // we have enough space for all the titles at their - // original width so use the true title's width - foreach ($titleWidth as $key => $val) { - $colFits[$key] = $val; - } - } - - // loop through the data; any column whose contents - // is greater than the column size is resized - /** - * @todo force here a LIMIT to avoid reading all rows - */ - while ($row = $GLOBALS['dbi']->fetchRow($this->results)) { - foreach ($colFits as $key => $val) { - $stringWidth = $this->GetStringWidth($row[$key]) + 6; - if ($adjustingMode && ($stringWidth > $this->sColWidth)) { - // any column whose data's width is bigger than - // the start width is now discarded - unset($colFits[$key]); - } else { - // if data's width is bigger than the current column width, - // enlarge the column (but avoid enlarging it if the - // data's width is very big) - if ($stringWidth > $val - && $stringWidth < ($this->sColWidth * 3) - ) { - $colFits[$key] = $stringWidth; - } - } - } - } - - $totAlreadyFitted = 0; - foreach ($colFits as $key => $val) { - // set fitted columns to smallest size - $this->tablewidths[$key] = $val; - // to work out how much (if any) space has been freed up - $totAlreadyFitted += $val; - } - - if ($adjustingMode) { - $surplus = (count($colFits) * $this->sColWidth) - $totAlreadyFitted; - $surplusToAdd = $surplus / ($this->numFields - count($colFits)); - } else { - $surplusToAdd = 0; - } - - for ($i = 0; $i < $this->numFields; $i++) { - if (! array_key_exists($i, $colFits)) { - $this->tablewidths[$i] = $this->sColWidth + $surplusToAdd; - } - if ($this->display_column[$i] == false) { - $this->tablewidths[$i] = 0; - } - } - - ksort($this->tablewidths); - - $GLOBALS['dbi']->freeResult($this->results); - - // Pass 2 - - $this->results = $GLOBALS['dbi']->query( - $query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_UNBUFFERED - ); - $this->SetY($this->tMargin); - $this->AddPage(); - $this->SetFont(PdfLib::PMA_PDF_FONT, '', 9); - $this->morepagestable($this->FontSizePt); - $GLOBALS['dbi']->freeResult($this->results); - } // end of mysqlReport function -} // end of Pdf class diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/TableProperty.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/TableProperty.php deleted file mode 100644 index 8991251..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/TableProperty.php +++ /dev/null @@ -1,277 +0,0 @@ -name = trim((string) $row[0]); - $this->type = trim((string) $row[1]); - $this->nullable = trim((string) $row[2]); - $this->key = trim((string) $row[3]); - $this->defaultValue = trim((string) $row[4]); - $this->ext = trim((string) $row[5]); - } - - /** - * Gets the pure type - * - * @return string type - */ - public function getPureType() - { - $pos = mb_strpos($this->type, "("); - if ($pos > 0) { - return mb_substr($this->type, 0, $pos); - } - return $this->type; - } - - /** - * Tells whether the key is null or not - * - * @return string true if the key is not null, false otherwise - */ - public function isNotNull() - { - return $this->nullable === "NO" ? "true" : "false"; - } - - /** - * Tells whether the key is unique or not - * - * @return string "true" if the key is unique, "false" otherwise - */ - public function isUnique(): string - { - return ($this->key === "PRI" || $this->key === "UNI") ? "true" : "false"; - } - - /** - * Gets the .NET primitive type - * - * @return string type - */ - public function getDotNetPrimitiveType() - { - if (mb_strpos($this->type, "int") === 0) { - return "int"; - } - if (mb_strpos($this->type, "longtext") === 0) { - return "string"; - } - if (mb_strpos($this->type, "long") === 0) { - return "long"; - } - if (mb_strpos($this->type, "char") === 0) { - return "string"; - } - if (mb_strpos($this->type, "varchar") === 0) { - return "string"; - } - if (mb_strpos($this->type, "text") === 0) { - return "string"; - } - if (mb_strpos($this->type, "tinyint") === 0) { - return "bool"; - } - if (mb_strpos($this->type, "datetime") === 0) { - return "DateTime"; - } - return "unknown"; - } - - /** - * Gets the .NET object type - * - * @return string type - */ - public function getDotNetObjectType() - { - if (mb_strpos($this->type, "int") === 0) { - return "Int32"; - } - if (mb_strpos($this->type, "longtext") === 0) { - return "String"; - } - if (mb_strpos($this->type, "long") === 0) { - return "Long"; - } - if (mb_strpos($this->type, "char") === 0) { - return "String"; - } - if (mb_strpos($this->type, "varchar") === 0) { - return "String"; - } - if (mb_strpos($this->type, "text") === 0) { - return "String"; - } - if (mb_strpos($this->type, "tinyint") === 0) { - return "Boolean"; - } - if (mb_strpos($this->type, "datetime") === 0) { - return "DateTime"; - } - return "Unknown"; - } - - /** - * Gets the index name - * - * @return string containing the name of the index - */ - public function getIndexName() - { - if (strlen($this->key) > 0) { - return "index=\"" - . htmlspecialchars($this->name, ENT_COMPAT, 'UTF-8') - . "\""; - } - return ""; - } - - /** - * Tells whether the key is primary or not - * - * @return bool true if the key is primary, false otherwise - */ - public function isPK(): bool - { - return $this->key === "PRI"; - } - - /** - * Formats a string for C# - * - * @param string $text string to be formatted - * - * @return string formatted text - */ - public function formatCs($text) - { - $text = str_replace( - '#name#', - ExportCodegen::cgMakeIdentifier($this->name, false), - $text - ); - return $this->format($text); - } - - /** - * Formats a string for XML - * - * @param string $text string to be formatted - * - * @return string formatted text - */ - public function formatXml($text) - { - $text = str_replace( - [ - '#name#', - '#indexName#', - ], - [ - htmlspecialchars($this->name, ENT_COMPAT, 'UTF-8'), - $this->getIndexName(), - ], - $text - ); - return $this->format($text); - } - - /** - * Formats a string - * - * @param string $text string to be formatted - * - * @return string formatted text - */ - public function format($text) - { - $text = str_replace( - [ - '#ucfirstName#', - '#dotNetPrimitiveType#', - '#dotNetObjectType#', - '#type#', - '#notNull#', - '#unique#', - ], - [ - ExportCodegen::cgMakeIdentifier($this->name), - $this->getDotNetPrimitiveType(), - $this->getDotNetObjectType(), - $this->getPureType(), - $this->isNotNull(), - $this->isUnique(), - ], - $text - ); - return $text; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/README b/srcs/phpmyadmin/libraries/classes/Plugins/Export/README deleted file mode 100644 index 5ada85b..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Export/README +++ /dev/null @@ -1,255 +0,0 @@ -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() - { - $exportPluginProperties = new PhpMyAdmin\Properties\Plugins\ExportPluginProperties(); - $exportPluginProperties->setText('[name]'); // the name of your plug-in - $exportPluginProperties->setExtension('[ext]'); // extension this plug-in can handle - $exportPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $exportPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup( - "general_opts" - ); - - // optional : - // create primary items and add them to the group - // type - one of the classes listed in libraries/properties/options/items/ - // name - form element name - // text - description in GUI - // size - size of text element - // len - maximal size of input - // values - possible values of the item - $leaf = new PhpMyAdmin\Properties\Options\Items\RadioPropertyItem( - "structure_or_data" - ); - $leaf->setValues( - array( - 'structure' => __('structure'), - 'data' => __('data'), - 'structure_and_data' => __('structure and data') - ) - ); - $generalOptions->addProperty($leaf); - - // add the main group to the root group - $exportSpecificOptions->addProperty($generalOptions); - - // set the options for the export plugin property item - $exportPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $exportPluginProperties; - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - public function exportHeader () - { - // implementation - return true; - } - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - public function exportFooter () - { - // implementation - return true; - } - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBHeader ($db, $db_alias = '') - { - // implementation - return true; - } - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - public function exportDBFooter ($db) - { - // implementation - return true; - } - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - public function exportDBCreate($db, $db_alias = '') - { - // implementation - return true; - } - - /** - * Outputs the content of a table in [Name] format - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportData( - $db, $table, $crlf, $error_url, $sql_query, $aliases = array() - ) { - // implementation; - return true; - } - - // optional - implement other methods defined in PhpMyAdmin\Plugins\ExportPlugin.class.php: - // - exportRoutines() - // - exportStructure() - // - getTableDefStandIn() - // - getTriggers() - - // optional - implement other private methods in order to avoid - // having huge methods or avoid duplicate code. Make use of them - // as well as of the getters and setters declared both here - // and in the PhpMyAdmin\Plugins\ExportPlugin class - - - // optional: - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - - /** - * Getter description - * - * @return type - */ - private function _getMyOptionalVariable() - { - return $this->_myOptionalVariable; - } - - /** - * Setter description - * - * @param type $my_optional_variable description - * - * @return void - */ - private function _setMyOptionalVariable($my_optional_variable) - { - $this->_myOptionalVariable = $my_optional_variable; - } - - /** - * Getter description - * - * @return type - */ - private function _getGlobalVariableName() - { - return $this->_globalVariableName; - } - - /** - * Setter description - * - * @param type $global_variable_name description - * - * @return void - */ - private function _setGlobalVariableName($global_variable_name) - { - $this->_globalVariableName = $global_variable_name; - } -} -?> diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/ExportPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/ExportPlugin.php deleted file mode 100644 index a81a826..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/ExportPlugin.php +++ /dev/null @@ -1,386 +0,0 @@ -relation = new Relation($GLOBALS['dbi']); - $this->export = new Export($GLOBALS['dbi']); - $this->transformations = new Transformations(); - } - - /** - * Outputs export header - * - * @return bool Whether it succeeded - */ - abstract public function exportHeader(); - - /** - * Outputs export footer - * - * @return bool Whether it succeeded - */ - abstract public function exportFooter(); - - /** - * Outputs database header - * - * @param string $db Database name - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - abstract public function exportDBHeader($db, $db_alias = ''); - - /** - * Outputs database footer - * - * @param string $db Database name - * - * @return bool Whether it succeeded - */ - abstract public function exportDBFooter($db); - - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $export_type 'server', 'database', 'table' - * @param string $db_alias Aliases of db - * - * @return bool Whether it succeeded - */ - abstract public function exportDBCreate($db, $export_type, $db_alias = ''); - - /** - * Outputs the content of a table - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $sql_query SQL query for obtaining data - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - abstract public function exportData( - $db, - $table, - $crlf, - $error_url, - $sql_query, - array $aliases = [] - ); - - /** - * The following methods are used in export.php or in db_operations.php, - * but they are not implemented by all export plugins - */ - - /** - * Exports routines (procedures and functions) - * - * @param string $db Database - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportRoutines($db, array $aliases = []) - { - } - - /** - * Exports events - * - * @param string $db Database - * - * @return bool Whether it succeeded - */ - public function exportEvents($db) - { - } - - /** - * Outputs table's structure - * - * @param string $db database name - * @param string $table table name - * @param string $crlf the end of line sequence - * @param string $error_url the url to go back in case of error - * @param string $export_mode 'create_table','triggers','create_view', - * 'stand_in' - * @param string $export_type 'server', 'database', 'table' - * @param bool $relation whether to include relation comments - * @param bool $comments whether to include the pmadb-style column comments - * as comments in the structure; this is deprecated - * but the parameter is left here because export.php - * calls exportStructure() also for other export - * types which use this parameter - * @param bool $mime whether to include mime comments - * @param bool $dates whether to include creation/update/check dates - * @param array $aliases Aliases of db/table/columns - * - * @return bool Whether it succeeded - */ - public function exportStructure( - $db, - $table, - $crlf, - $error_url, - $export_mode, - $export_type, - $relation = false, - $comments = false, - $mime = false, - $dates = false, - array $aliases = [] - ) { - } - - /** - * Exports metadata from Configuration Storage - * - * @param string $db database being exported - * @param string|array $tables table(s) being exported - * @param array $metadataTypes types of metadata to export - * - * @return bool Whether it succeeded - */ - public function exportMetadata( - $db, - $tables, - array $metadataTypes - ) { - } - - /** - * Returns a stand-in CREATE definition to resolve view dependencies - * - * @param string $db the database name - * @param string $view the view name - * @param string $crlf the end of line sequence - * @param array $aliases Aliases of db/table/columns - * - * @return string resulting definition - */ - public function getTableDefStandIn($db, $view, $crlf, $aliases = []) - { - } - - /** - * Outputs triggers - * - * @param string $db database name - * @param string $table table name - * - * @return string Formatted triggers list - */ - protected function getTriggers($db, $table) - { - } - - /** - * Initialize the specific variables for each export plugin - * - * @return void - */ - protected function initSpecificVariables() - { - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the export specific format plugin properties - * - * @return ExportPluginProperties - */ - public function getProperties() - { - return $this->properties; - } - - /** - * Sets the export plugins properties and is implemented by each export - * plugin - * - * @return void - */ - abstract protected function setProperties(); - - /** - * The following methods are implemented here so that they - * can be used by all export plugin without overriding it. - * Note: If you are creating a export plugin then don't include - * below methods unless you want to override them. - */ - - /** - * Initialize aliases - * - * @param array $aliases Alias information for db/table/column - * @param string $db the database - * @param string $table the table - * - * @return void - */ - public function initAlias($aliases, &$db, &$table = null) - { - if (! empty($aliases[$db]['tables'][$table]['alias'])) { - $table = $aliases[$db]['tables'][$table]['alias']; - } - if (! empty($aliases[$db]['alias'])) { - $db = $aliases[$db]['alias']; - } - } - - /** - * Search for alias of a identifier. - * - * @param array $aliases Alias information for db/table/column - * @param string $id the identifier to be searched - * @param string $type db/tbl/col or any combination of them - * representing what to be searched - * @param string $db the database in which search is to be done - * @param string $tbl the table in which search is to be done - * - * @return string alias of the identifier if found or '' - */ - public function getAlias(array $aliases, $id, $type = 'dbtblcol', $db = '', $tbl = '') - { - if (! empty($db) && isset($aliases[$db])) { - $aliases = [ - $db => $aliases[$db], - ]; - } - // search each database - foreach ($aliases as $db_key => $db) { - // check if id is database and has alias - if (false !== stripos($type, 'db') - && $db_key === $id - && ! empty($db['alias']) - ) { - return $db['alias']; - } - if (empty($db['tables'])) { - continue; - } - if (! empty($tbl) && isset($db['tables'][$tbl])) { - $db['tables'] = [ - $tbl => $db['tables'][$tbl], - ]; - } - // search each of its tables - foreach ($db['tables'] as $table_key => $table) { - // check if id is table and has alias - if (false !== stripos($type, 'tbl') - && $table_key === $id - && ! empty($table['alias']) - ) { - return $table['alias']; - } - if (empty($table['columns'])) { - continue; - } - // search each of its columns - foreach ($table['columns'] as $col_key => $col) { - // check if id is column - if (false !== stripos($type, 'col') - && $col_key === $id - && ! empty($col) - ) { - return $col; - } - } - } - } - - return ''; - } - - /** - * Gives the relation string and - * also substitutes with alias if required - * in this format: - * [Foreign Table] ([Foreign Field]) - * - * @param array $res_rel the foreigners array - * @param string $field_name the field name - * @param string $db the field name - * @param array $aliases Alias information for db/table/column - * - * @return string the Relation string - */ - public function getRelationString( - array $res_rel, - $field_name, - $db, - array $aliases = [] - ) { - $relation = ''; - $foreigner = $this->relation->searchColumnInForeigners($res_rel, $field_name); - if ($foreigner) { - $ftable = $foreigner['foreign_table']; - $ffield = $foreigner['foreign_field']; - if (! empty($aliases[$db]['tables'][$ftable]['columns'][$ffield])) { - $ffield = $aliases[$db]['tables'][$ftable]['columns'][$ffield]; - } - if (! empty($aliases[$db]['tables'][$ftable]['alias'])) { - $ftable = $aliases[$db]['tables'][$ftable]['alias']; - } - $relation = $ftable . ' (' . $ffield . ')'; - } - - return $relation; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/IOTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/IOTransformationsPlugin.php deleted file mode 100644 index 3652eba..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/IOTransformationsPlugin.php +++ /dev/null @@ -1,98 +0,0 @@ -error; - } - - /** - * Returns the success status - * - * @return bool - */ - public function isSuccess() - { - return $this->success; - } - - /** - * Resets the object properties - * - * @return void - */ - public function reset() - { - $this->success = true; - $this->error = ''; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/AbstractImportCsv.php b/srcs/phpmyadmin/libraries/classes/Plugins/Import/AbstractImportCsv.php deleted file mode 100644 index 5c5a250..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/AbstractImportCsv.php +++ /dev/null @@ -1,94 +0,0 @@ -setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $importPluginProperties - // this will be shown as "Format specific options" - $importSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - - // create common items and add them to the group - $leaf = new BoolPropertyItem( - "replace", - __( - 'Update data when duplicate keys found on import (add ON DUPLICATE ' - . 'KEY UPDATE)' - ) - ); - $generalOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - "terminated", - __('Columns separated with:') - ); - $leaf->setSize(2); - $generalOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - "enclosed", - __('Columns enclosed with:') - ); - $leaf->setSize(2); - $leaf->setLen(2); - $generalOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - "escaped", - __('Columns escaped with:') - ); - $leaf->setSize(2); - $leaf->setLen(2); - $generalOptions->addProperty($leaf); - $leaf = new TextPropertyItem( - "new_line", - __('Lines terminated with:') - ); - $leaf->setSize(2); - $generalOptions->addProperty($leaf); - - // add the main group to the root group - $importSpecificOptions->addProperty($generalOptions); - - // set the options for the import plugin property item - $importPluginProperties->setOptions($importSpecificOptions); - $this->properties = $importPluginProperties; - - return $generalOptions; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportCsv.php b/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportCsv.php deleted file mode 100644 index e5494a9..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportCsv.php +++ /dev/null @@ -1,818 +0,0 @@ -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 TextPropertyItem( - "new_tbl_name", - __( - 'Name of the new table (optional):' - ) - ); - $generalOptions->addProperty($leaf); - - if ($GLOBALS['plugin_param'] === 'server') { - $leaf = new TextPropertyItem( - "new_db_name", - __( - 'Name of the new database (optional):' - ) - ); - $generalOptions->addProperty($leaf); - } - - $leaf = new NumberPropertyItem( - "partial_import", - __( - 'Import these many number of rows (optional):' - ) - ); - $generalOptions->addProperty($leaf); - - $leaf = new BoolPropertyItem( - "col_names", - __( - '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 { - $leaf = new NumberPropertyItem( - "partial_import", - __( - 'Import these many number of rows (optional):' - ) - ); - $generalOptions->addProperty($leaf); - - $hint = new Message( - __( - 'If the data in each row of the file is not' - . ' in the same order as in the database, list the corresponding' - . ' column names here. Column names must be separated by commas' - . ' and not enclosed in quotations.' - ) - ); - $leaf = new TextPropertyItem( - "columns", - __('Column names:') . ' ' . Util::showHint($hint) - ); - $generalOptions->addProperty($leaf); - } - - $leaf = new BoolPropertyItem( - "ignore", - __('Do not abort on INSERT error') - ); - $generalOptions->addProperty($leaf); - } - - /** - * Handles the whole import logic - * - * @param array $sql_data 2-element array with sql data - * - * @return void - */ - public function doImport(array &$sql_data = []) - { - global $db, $table, $csv_terminated, $csv_enclosed, $csv_escaped, - $csv_new_line, $csv_columns, $err_url, $import_file_name; - // $csv_replace and $csv_ignore should have been here, - // but we use directly from $_POST - global $error, $timeout_passed, $finished, $message; - - $import_file_name = basename($import_file_name, ".csv"); - $import_file_name = mb_strtolower($import_file_name); - $import_file_name = preg_replace("/[^a-zA-Z0-9_]/", "_", $import_file_name); - - $replacements = [ - '\\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) === 0) { - $message = Message::error( - __('Invalid parameter for CSV import: %s') - ); - $message->addParam(__('Columns terminated with')); - $error = true; - $param_error = true; - // The default dialog of MS Excel when generating a CSV produces a - // semi-colon-separated file with no chance of specifying the - // enclosing character. Thus, users who want to import this file - // tend to remove the enclosing character on the Import dialog. - // I could not find a test case where having no enclosing characters - // confuses this script. - // But the parser won't work correctly with strings so we allow just - // one character. - } elseif (mb_strlen($csv_enclosed) > 1) { - $message = Message::error( - __('Invalid parameter for CSV import: %s') - ); - $message->addParam(__('Columns enclosed with')); - $error = true; - $param_error = true; - // I could not find a test case where having no escaping characters - // confuses this script. - // But the parser won't work correctly with strings so we allow just - // one character. - } elseif (mb_strlen($csv_escaped) > 1) { - $message = Message::error( - __('Invalid parameter for CSV import: %s') - ); - $message->addParam(__('Columns escaped with')); - $error = true; - $param_error = true; - } elseif (mb_strlen($csv_new_line) != 1 - && $csv_new_line != 'auto' - ) { - $message = Message::error( - __('Invalid parameter for CSV import: %s') - ); - $message->addParam(__('Lines terminated with')); - $error = true; - $param_error = true; - } - - // If there is an error in the parameters entered, - // indicate that immediately. - if ($param_error) { - Util::mysqlDie( - $message->getMessage(), - '', - false, - $err_url - ); - } - - $buffer = ''; - $required_fields = 0; - $sql_template = ''; - $fields = []; - if (! $this->_getAnalyze()) { - $sql_template = 'INSERT'; - if (isset($_POST['csv_ignore'])) { - $sql_template .= ' IGNORE'; - } - $sql_template .= ' INTO ' . Util::backquote($table); - - $tmp_fields = $GLOBALS['dbi']->getColumns($db, $table); - - if (empty($csv_columns)) { - $fields = $tmp_fields; - } else { - $sql_template .= ' ('; - $fields = []; - $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 = 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; - } - if (isset($field)) { - $fields[] = $field; - } - $sql_template .= Util::backquote($val); - } - $sql_template .= ') '; - } - - $required_fields = count($fields); - - $sql_template .= ' VALUES ('; - } - - // Defaults for parser - $i = 0; - $len = 0; - $lastlen = null; - $line = 1; - $lasti = -1; - $values = []; - $csv_finish = false; - $max_lines = 0; // defaults to 0 (get all the lines) - - // If we get a negative value, probably someone changed min value attribute in DOM or there is an integer overflow, whatever be the case, get all the lines - if (isset($_REQUEST['csv_partial_import']) && $_REQUEST['csv_partial_import'] > 0) { - $max_lines = $_REQUEST['csv_partial_import']; - } - $max_lines_constraint = $max_lines+1; - // if the first row has to be counted as column names, include one more row in the max lines - if (isset($_REQUEST['csv_col_names'])) { - $max_lines_constraint++; - } - - $tempRow = []; - $rows = []; - $col_names = []; - $tables = []; - - $col_count = 0; - $max_cols = 0; - $csv_terminated_len = mb_strlen($csv_terminated); - while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { - $data = $this->import->getNextChunk(); - if ($data === false) { - // subtract data we didn't handle yet and stop processing - $GLOBALS['offset'] -= strlen($buffer); - break; - } elseif ($data !== true) { - // Append new data to buffer - $buffer .= $data; - unset($data); - - // Force a trailing new line at EOF to prevent parsing problems - if ($finished && $buffer) { - $finalch = mb_substr($buffer, -1); - if ($csv_new_line == 'auto' - && $finalch != "\r" - && $finalch != "\n" - ) { - $buffer .= "\n"; - } elseif ($csv_new_line != 'auto' - && $finalch != $csv_new_line - ) { - $buffer .= $csv_new_line; - } - } - - // Do not parse string when we're not at the end - // and don't have new line inside - if (($csv_new_line == 'auto' - && mb_strpos($buffer, "\r") === false - && mb_strpos($buffer, "\n") === false) - || ($csv_new_line != 'auto' - && mb_strpos($buffer, $csv_new_line) === false) - ) { - continue; - } - } - - // Current length of our buffer - $len = mb_strlen($buffer); - // Currently parsed char - - $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { - $ch = $this->readCsvTerminatedString( - $buffer, - $ch, - $i, - $csv_terminated_len - ); - $i += $csv_terminated_len - 1; - } - while ($i < $len) { - // Deadlock protection - if ($lasti == $i && $lastlen == $len) { - $message = Message::error( - __('Invalid format of CSV input on line %d.') - ); - $message->addParam($line); - $error = true; - break; - } - $lasti = $i; - $lastlen = $len; - - // This can happen with auto EOL and \r at the end of buffer - if (! $csv_finish) { - // Grab empty field - if ($ch == $csv_terminated) { - if ($i == $len - 1) { - break; - } - $values[] = ''; - $i++; - $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { - $ch = $this->readCsvTerminatedString( - $buffer, - $ch, - $i, - $csv_terminated_len - ); - $i += $csv_terminated_len - 1; - } - continue; - } - - // Grab one field - $fallbacki = $i; - if ($ch == $csv_enclosed) { - if ($i == $len - 1) { - break; - } - $need_end = true; - $i++; - $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { - $ch = $this->readCsvTerminatedString( - $buffer, - $ch, - $i, - $csv_terminated_len - ); - $i += $csv_terminated_len - 1; - } - } else { - $need_end = false; - } - $fail = false; - $value = ''; - while (($need_end - && ($ch != $csv_enclosed - || $csv_enclosed == $csv_escaped)) - || (! $need_end - && ! ($ch == $csv_terminated - || $ch == $csv_new_line - || ($csv_new_line == 'auto' - && ($ch == "\r" || $ch == "\n")))) - ) { - if ($ch == $csv_escaped) { - if ($i == $len - 1) { - $fail = true; - break; - } - $i++; - $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 - && $ch == $csv_terminated[0] - ) { - $ch = $this->readCsvTerminatedString( - $buffer, - $ch, - $i, - $csv_terminated_len - ); - $i += $csv_terminated_len - 1; - } - if ($csv_enclosed == $csv_escaped - && ($ch == $csv_terminated - || $ch == $csv_new_line - || ($csv_new_line == 'auto' - && ($ch == "\r" || $ch == "\n"))) - ) { - break; - } - } - $value .= $ch; - if ($i == $len - 1) { - if (! $finished) { - $fail = true; - } - break; - } - $i++; - $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { - $ch = $this->readCsvTerminatedString( - $buffer, - $ch, - $i, - $csv_terminated_len - ); - $i += $csv_terminated_len - 1; - } - } - - // unquoted NULL string - if (false === $need_end && $value === 'NULL') { - $value = null; - } - - if ($fail) { - $i = $fallbacki; - $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { - $i += $csv_terminated_len - 1; - } - break; - } - // Need to strip trailing enclosing char? - if ($need_end && $ch == $csv_enclosed) { - if ($finished && $i == $len - 1) { - $ch = null; - } elseif ($i == $len - 1) { - $i = $fallbacki; - $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 - && $ch == $csv_terminated[0] - ) { - $i += $csv_terminated_len - 1; - } - break; - } else { - $i++; - $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 - && $ch == $csv_terminated[0] - ) { - $ch = $this->readCsvTerminatedString( - $buffer, - $ch, - $i, - $csv_terminated_len - ); - $i += $csv_terminated_len - 1; - } - } - } - // Are we at the end? - if ($ch == $csv_new_line - || ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n")) - || ($finished && $i == $len - 1) - ) { - $csv_finish = true; - } - // Go to next char - if ($ch == $csv_terminated) { - if ($i == $len - 1) { - $i = $fallbacki; - $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 - && $ch == $csv_terminated[0] - ) { - $i += $csv_terminated_len - 1; - } - break; - } - $i++; - $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 - && $ch == $csv_terminated[0] - ) { - $ch = $this->readCsvTerminatedString( - $buffer, - $ch, - $i, - $csv_terminated_len - ); - $i += $csv_terminated_len - 1; - } - } - // If everything went okay, store value - $values[] = $value; - } - - // End of line - if ($csv_finish - || $ch == $csv_new_line - || ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n")) - ) { - if ($csv_new_line == 'auto' && $ch == "\r") { // Handle "\r\n" - if ($i >= ($len - 2) && ! $finished) { - break; // We need more data to decide new line - } - if (mb_substr($buffer, $i + 1, 1) == "\n") { - $i++; - } - } - // We didn't parse value till the end of line, so there was - // empty one - if (! $csv_finish) { - $values[] = ''; - } - - if ($this->_getAnalyze()) { - foreach ($values as $val) { - $tempRow[] = $val; - ++$col_count; - } - - if ($col_count > $max_cols) { - $max_cols = $col_count; - } - $col_count = 0; - - $rows[] = $tempRow; - $tempRow = []; - } 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 = Message::error( - __( - 'Invalid column count in CSV input' - . ' on line %d.' - ) - ); - $message->addParam($line); - $error = true; - break; - } - } - - $first = true; - $sql = $sql_template; - foreach ($values as $key => $val) { - if (! $first) { - $sql .= ', '; - } - if ($val === null) { - $sql .= 'NULL'; - } else { - $sql .= '\'' - . $GLOBALS['dbi']->escapeString($val) - . '\''; - } - - $first = false; - } - $sql .= ')'; - if (isset($_POST['csv_replace'])) { - $sql .= " ON DUPLICATE KEY UPDATE "; - foreach ($fields as $field) { - $fieldName = Util::backquote( - $field['Field'] - ); - $sql .= $fieldName . " = VALUES(" . $fieldName - . "), "; - } - $sql = rtrim($sql, ', '); - } - - /** - * @todo maybe we could add original line to verbose - * SQL in comment - */ - $this->import->runQuery($sql, $sql, $sql_data); - } - - $line++; - $csv_finish = false; - $values = []; - $buffer = mb_substr($buffer, $i + 1); - $len = mb_strlen($buffer); - $i = 0; - $lasti = -1; - $ch = mb_substr($buffer, 0, 1); - if ($max_lines > 0 && $line == $max_lines_constraint) { - $finished = 1; - break; - } - } - } // End of parser loop - if ($max_lines > 0 && $line == $max_lines_constraint) { - $finished = 1; - break; - } - } // End of import loop - - if ($this->_getAnalyze()) { - /* Fill out all rows */ - $num_rows = count($rows); - for ($i = 0; $i < $num_rows; ++$i) { - for ($j = count($rows[$i]); $j < $max_cols; ++$j) { - $rows[$i][] = 'NULL'; - } - } - - if (isset($_REQUEST['csv_col_names'])) { - $col_names = array_splice($rows, 0, 1); - $col_names = $col_names[0]; - // MySQL column names can't end with a space character. - foreach ($col_names as $key => $col_name) { - $col_names[$key] = rtrim($col_name); - } - } - - if ((isset($col_names) && count($col_names) != $max_cols) - || ! isset($col_names) - ) { - // Fill out column names - for ($i = 0; $i < $max_cols; ++$i) { - $col_names[] = 'COL ' . ($i + 1); - } - } - - // get new table name, if user didn't provide one, set the default name - if (isset($_REQUEST['csv_new_tbl_name']) - && strlen($_REQUEST['csv_new_tbl_name']) > 0 - ) { - $tbl_name = $_REQUEST['csv_new_tbl_name']; - } elseif (mb_strlen((string) $db)) { - $result = $GLOBALS['dbi']->fetchResult('SHOW TABLES'); - - // logic to get table name from filename - // if no table then use filename as table name - if (count($result) === 0) { - $tbl_name = $import_file_name; - } else { - // check to see if {filename} as table exist - $name_array = preg_grep("/{$import_file_name}/isU", $result); - // if no use filename as table name - if (count($name_array) === 0) { - $tbl_name = $import_file_name; - } else { - // check if {filename}_ as table exist - $name_array = preg_grep("/{$import_file_name}_/isU", $result); - $tbl_name = $import_file_name . "_" . (count($name_array) + 1); - } - } - } else { - $tbl_name = $import_file_name; - } - - $tables[] = [ - $tbl_name, - $col_names, - $rows, - ]; - - /* Obtain the best-fit MySQL types for each column */ - $analyses = []; - $analyses[] = $this->import->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, - * Otherwise, check if user provided the database name in the request, - * if not, set the default name - */ - if (isset($_REQUEST['csv_new_db_name']) - && strlen($_REQUEST['csv_new_db_name']) > 0 - ) { - $newDb = $_REQUEST['csv_new_db_name']; - } else { - $result = $GLOBALS['dbi']->fetchResult('SHOW DATABASES'); - if (! is_array($result)) { - $result = []; - } - $newDb = 'CSV_DB ' . (count($result) + 1); - } - list($db_name, $options) = $this->getDbnameAndOptions($db, $newDb); - - /* Non-applicable parameters */ - $create = null; - - /* Created and execute necessary SQL statements from data */ - $this->import->buildSql($db_name, $tables, $analyses, $create, $options, $sql_data); - - unset($tables); - unset($analyses); - } - - // Commit any possible data in buffers - $this->import->runQuery('', '', $sql_data); - - if (count($values) != 0 && ! $error) { - $message = Message::error( - __('Invalid format of CSV input on line %d.') - ); - $message->addParam($line); - $error = true; - } - } - - /** - * Read the expected column_separated_with String of length - * $csv_terminated_len from the $buffer - * into variable $ch and return the read string $ch - * - * @param string $buffer The original string buffer read from - * csv file - * @param string $ch Partially read "column Separated with" - * string, also used to return after - * reading length equal $csv_terminated_len - * @param int $i Current read counter of buffer string - * @param int $csv_terminated_len The length of "column separated with" - * String - * - * @return string - */ - public function readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len) - { - for ($j = 0; $j < $csv_terminated_len - 1; $j++) { - $i++; - $ch .= mb_substr($buffer, $i, 1); - } - - return $ch; - } - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Returns true if the table should be analyzed, false otherwise - * - * @return bool - */ - private function _getAnalyze() - { - return $this->_analyze; - } - - /** - * Sets to true if the table should be analyzed, false otherwise - * - * @param bool $analyze status - * - * @return void - */ - private function _setAnalyze($analyze) - { - $this->_analyze = $analyze; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportLdi.php b/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportLdi.php deleted file mode 100644 index 91260c5..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportLdi.php +++ /dev/null @@ -1,176 +0,0 @@ -setProperties(); - } - - /** - * Sets the import plugin properties. - * Called in the constructor. - * - * @return void - */ - protected function setProperties() - { - if ($GLOBALS['cfg']['Import']['ldi_local_option'] == 'auto') { - $GLOBALS['cfg']['Import']['ldi_local_option'] = false; - - $result = $GLOBALS['dbi']->tryQuery( - 'SELECT @@local_infile;' - ); - if ($result != false && $GLOBALS['dbi']->numRows($result) > 0) { - $tmp = $GLOBALS['dbi']->fetchRow($result); - if ($tmp[0] == 'ON') { - $GLOBALS['cfg']['Import']['ldi_local_option'] = true; - } - } - $GLOBALS['dbi']->freeResult($result); - unset($result); - } - - $generalOptions = parent::setProperties(); - $this->properties->setText('CSV using LOAD DATA'); - $this->properties->setExtension('ldi'); - - $leaf = new TextPropertyItem( - "columns", - __('Column names: ') - ); - $generalOptions->addProperty($leaf); - - $leaf = new BoolPropertyItem( - "ignore", - __('Do not abort on INSERT error') - ); - $generalOptions->addProperty($leaf); - - $leaf = new BoolPropertyItem( - "local_option", - __('Use LOCAL keyword') - ); - $generalOptions->addProperty($leaf); - } - - /** - * Handles the whole import logic - * - * @param array $sql_data 2-element array with sql data - * - * @return void - */ - public function doImport(array &$sql_data = []) - { - global $finished, $import_file, $charset_conversion, $table; - global $ldi_local_option, $ldi_replace, $ldi_ignore, $ldi_terminated, - $ldi_enclosed, $ldi_escaped, $ldi_new_line, $skip_queries, $ldi_columns; - - $compression = $GLOBALS['import_handle']->getCompression(); - - if ($import_file == 'none' - || $compression != 'none' - || $charset_conversion - ) { - // We handle only some kind of data! - $GLOBALS['message'] = Message::error( - __('This plugin does not support compressed imports!') - ); - $GLOBALS['error'] = true; - - return; - } - - $sql = 'LOAD DATA'; - if (isset($ldi_local_option)) { - $sql .= ' LOCAL'; - } - $sql .= ' INFILE \'' . $GLOBALS['dbi']->escapeString($import_file) - . '\''; - if (isset($ldi_replace)) { - $sql .= ' REPLACE'; - } elseif (isset($ldi_ignore)) { - $sql .= ' IGNORE'; - } - $sql .= ' INTO TABLE ' . Util::backquote($table); - - if (strlen((string) $ldi_terminated) > 0) { - $sql .= ' FIELDS TERMINATED BY \'' . $ldi_terminated . '\''; - } - if (strlen((string) $ldi_enclosed) > 0) { - $sql .= ' ENCLOSED BY \'' - . $GLOBALS['dbi']->escapeString($ldi_enclosed) . '\''; - } - if (strlen((string) $ldi_escaped) > 0) { - $sql .= ' ESCAPED BY \'' - . $GLOBALS['dbi']->escapeString($ldi_escaped) . '\''; - } - if (strlen((string) $ldi_new_line) > 0) { - if ($ldi_new_line == 'auto') { - $ldi_new_line - = (PHP_EOL == "\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((string) $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 .= Util::backquote( - trim($tmp[$i], " \t\r\n\0\x0B`") - ); - } // end for - $sql .= ')'; - } - - $this->import->runQuery($sql, $sql, $sql_data); - $this->import->runQuery('', '', $sql_data); - $finished = true; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportMediawiki.php b/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportMediawiki.php deleted file mode 100644 index 9723daf..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportMediawiki.php +++ /dev/null @@ -1,604 +0,0 @@ -setProperties(); - } - - /** - * Sets the import plugin properties. - * Called in the constructor. - * - * @return void - */ - protected function setProperties() - { - $this->_setAnalyze(false); - if ($GLOBALS['plugin_param'] !== 'table') { - $this->_setAnalyze(true); - } - - $importPluginProperties = new ImportPluginProperties(); - $importPluginProperties->setText(__('MediaWiki Table')); - $importPluginProperties->setExtension('txt'); - $importPluginProperties->setMimeType('text/plain'); - $importPluginProperties->setOptions([]); - $importPluginProperties->setOptionsText(__('Options')); - - $this->properties = $importPluginProperties; - } - - /** - * Handles the whole import logic - * - * @param array $sql_data 2-element array with sql data - * - * @return void - */ - public function doImport(array &$sql_data = []) - { - 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 = $this->import->getNextChunk(); - - if ($data === false) { - // Subtract data we didn't handle yet and stop processing - $GLOBALS['offset'] -= mb_strlen($buffer); - break; - } elseif ($data !== true) { - // Append new data to buffer - $buffer = $data; - unset($data); - // Don't parse string if we're not at the end - // and don't have a new line inside - if (mb_strpos($buffer, $mediawiki_new_line) === false) { - continue; - } - } - - // Because of reading chunk by chunk, the first line from the buffer - // contains only a portion of an actual line from the imported file. - // Therefore, we have to append it to the last line from the previous - // chunk. If we are at the first chunk, $last_chunk_line should be empty. - $buffer = $last_chunk_line . $buffer; - - // Process the buffer line by line - $buffer_lines = explode($mediawiki_new_line, $buffer); - - $full_buffer_lines_count = count($buffer_lines); - // If the reading is not finalised, the final line of the current chunk - // will not be complete - if (! $finished) { - $last_chunk_line = $buffer_lines[--$full_buffer_lines_count]; - } - - for ($line_nr = 0; $line_nr < $full_buffer_lines_count; ++$line_nr) { - $cur_buffer_line = trim($buffer_lines[$line_nr]); - - // If the line is empty, go to the next one - if ($cur_buffer_line === '') { - continue; - } - - $first_character = $cur_buffer_line[0]; - $matches = []; - - // Check beginning of comment - if (! strcmp(mb_substr($cur_buffer_line, 0, 4), "") - ) { - // Only data comments are closed. The structure comments - // will be closed when a data comment begins (in order to - // skip structure tables) - if ($inside_data_comment) { - $inside_data_comment = false; - } - - // End comments that are not related to table structure - if (! $inside_structure_comment) { - $inside_comment = false; - } - } else { - // Check table name - $match_table_name = []; - if (preg_match( - "/^Table data for `(.*)`$/", - $cur_buffer_line, - $match_table_name - ) - ) { - $cur_table_name = $match_table_name[1]; - $inside_data_comment = true; - - $inside_structure_comment - = $this->_mngInsideStructComm( - $inside_structure_comment - ); - } elseif (preg_match( - "/^Table structure for `(.*)`$/", - $cur_buffer_line, - $match_table_name - ) - ) { - // The structure comments will be ignored - $inside_structure_comment = true; - } - } - continue; - } elseif (preg_match('/^\{\|(.*)$/', $cur_buffer_line, $matches)) { - // Check start of table - - // This will store all the column info on all rows from - // the current table read from the buffer - $cur_temp_table = []; - - // 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 = []; - - // Helps us differentiate the header columns - // from the normal columns - $in_table_header = false; - // End processing because the current line does not - // contain any column information - } elseif (mb_substr($cur_buffer_line, 0, 2) === '|-' - || mb_substr($cur_buffer_line, 0, 2) === '|+' - || mb_substr($cur_buffer_line, 0, 2) === '|}' - ) { - // Check begin row or end table - - // Add current line to the values storage - if (! empty($cur_temp_line)) { - // If the current line contains header cells - // ( marked with '!' ), - // it will be marked as table header - if ($in_table_header) { - // Set the header columns - $cur_temp_table_headers = $cur_temp_line; - } else { - // Normal line, add it to the table - $cur_temp_table[] = $cur_temp_line; - } - } - - // Empty the temporary buffer - $cur_temp_line = []; - - // No more processing required at the end of the table - if (mb_substr($cur_buffer_line, 0, 2) === '|}') { - $current_table = [ - $cur_table_name, - $cur_temp_table_headers, - $cur_temp_table, - ]; - - // Import the current table data into the database - $this->_importDataOneTable($current_table, $sql_data); - - // Reset table name - $cur_table_name = ""; - } - // What's after the row tag is now only attributes - } elseif (($first_character === '|') || ($first_character === '!')) { - // Check cell elements - - // Header cells - if ($first_character === '!') { - // Mark as table header, but treat as normal row - $cur_buffer_line = str_replace('!!', '||', $cur_buffer_line); - // Will be used to set $cur_temp_line as table header - $in_table_header = true; - } else { - $in_table_header = false; - } - - // Loop through each table cell - $cells = $this->_explodeMarkup($cur_buffer_line); - foreach ($cells as $cell) { - $cell = $this->_getCellData($cell); - - // Delete the beginning of the column, if there is one - $cell = trim($cell); - $col_start_chars = [ - "|", - "!", - ]; - foreach ($col_start_chars as $col_start_char) { - $cell = $this->_getCellContent($cell, $col_start_char); - } - - // Add the cell to the row - $cur_temp_line[] = $cell; - } // foreach $cells - } else { - // If it's none of the above, then the current line has a bad - // format - $message = 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 - * - * @param array $sql_data 2-element array with sql data - * - * @global bool $analyze whether to scan for column types - * - * @return void - */ - private function _importDataOneTable(array $table, array &$sql_data) - { - $analyze = $this->_getAnalyze(); - if ($analyze) { - // Set the table name - $this->_setTableName($table[0]); - - // Set generic names for table headers if they don't exist - $this->_setTableHeaders($table[1], $table[2][0]); - - // Create the tables array to be used in Import::buildSql() - $tables = []; - $tables[] = [ - $table[0], - $table[1], - $table[2], - ]; - - // Obtain the best-fit MySQL types for each column - $analyses = []; - $analyses[] = $this->import->analyzeTable($tables[0]); - - $this->_executeImportTables($tables, $analyses, $sql_data); - } - - // Commit any possible data in buffers - $this->import->runQuery('', '', $sql_data); - } - - /** - * Sets the table name - * - * @param string $table_name reference to the name of the table - * - * @return void - */ - private function _setTableName(&$table_name) - { - if (empty($table_name)) { - $result = $GLOBALS['dbi']->fetchResult('SHOW TABLES'); - // todo check if the name below already exists - $table_name = 'TABLE ' . (count($result) + 1); - } - } - - /** - * Set generic names for table headers, if they don't exist - * - * @param array $table_headers reference to the array containing the headers - * of a table - * @param array $table_row array containing the first content row - * - * @return void - */ - private function _setTableHeaders(array &$table_headers, array $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 Import::buildSql() - * Used in PMA_importDataAllTables() and $this->_importDataOneTable() - * - * @param array $tables structure: - * array( - * array(table_name, array() column_names, array()() - * rows) - * ) - * @param array $analyses structure: - * $analyses = array( - * array(array() column_types, array() column_sizes) - * ) - * @param array $sql_data 2-element array with sql data - * - * @global string $db name of the database to import in - * - * @return void - */ - private function _executeImportTables(array &$tables, array &$analyses, array &$sql_data) - { - global $db; - - // $db_name : The currently selected database name, if applicable - // No backquotes - // $options : An associative array of options - list($db_name, $options) = $this->getDbnameAndOptions($db, 'mediawiki_DB'); - - // Array of SQL strings - // Non-applicable parameters - $create = null; - - // Create and execute necessary SQL statements from data - $this->import->buildSql($db_name, $tables, $analyses, $create, $options, $sql_data); - } - - /** - * Replaces all instances of the '||' separator between delimiters - * in a given string - * - * @param string $replace the string to be replaced with - * @param string $subject the text to be replaced - * - * @return string with replacements - */ - private function _delimiterReplace($replace, $subject) - { - // String that will be returned - $cleaned = ""; - // Possible states of current character - $inside_tag = false; - $inside_attribute = false; - // Attributes can be declared with either " or ' - $start_attribute_character = false; - - // The full separator is "||"; - // This remembers if the previous character was '|' - $partial_separator = false; - - // Parse text char by char - for ($i = 0, $iMax = strlen($subject); $i < $iMax; $i++) { - $cur_char = $subject[$i]; - // Check for separators - if ($cur_char == '|') { - // If we're not inside a tag, then this is part of a real separator, - // so we append it to the current segment - if (! $inside_attribute) { - $cleaned .= $cur_char; - if ($partial_separator) { - $inside_tag = false; - $inside_attribute = false; - } - } elseif ($partial_separator) { - // If we are inside a tag, we replace the current char with - // the placeholder and append that to the current segment - $cleaned .= $replace; - } - - // If the previous character was also '|', then this ends a - // full separator. If not, this may be the beginning of one - $partial_separator = ! $partial_separator; - } else { - // If we're inside a tag attribute and the current character is - // not '|', but the previous one was, it means that the single '|' - // was not appended, so we append it now - if ($partial_separator && $inside_attribute) { - $cleaned .= "|"; - } - // If the char is different from "|", no separator can be formed - $partial_separator = false; - - // any other character should be appended to the current segment - $cleaned .= $cur_char; - - if ($cur_char == '<' && ! $inside_attribute) { - // start of a tag - $inside_tag = true; - } elseif ($cur_char == '>' && ! $inside_attribute) { - // end of a tag - $inside_tag = false; - } elseif (($cur_char == '"' || $cur_char == "'") && $inside_tag) { - // start or end of an attribute - if (! $inside_attribute) { - $inside_attribute = true; - // remember the attribute`s declaration character (" or ') - $start_attribute_character = $cur_char; - } else { - if ($cur_char == $start_attribute_character) { - $inside_attribute = false; - // unset attribute declaration character - $start_attribute_character = false; - } - } - } - } - } // end for each character in $subject - - return $cleaned; - } - - /** - * Separates a string into items, similarly to explode - * Uses the '||' separator (which is standard in the mediawiki format) - * and ignores any instances of it inside markup tags - * Used in parsing buffer lines containing data cells - * - * @param string $text text to be split - * - * @return array - */ - private function _explodeMarkup($text) - { - $separator = "||"; - $placeholder = "\x00"; - - // Remove placeholder instances - $text = str_replace($placeholder, '', $text); - - // Replace instances of the separator inside HTML-like - // tags with the placeholder - $cleaned = $this->_delimiterReplace($placeholder, $text); - // Explode, then put the replaced separators back in - $items = explode($separator, $cleaned); - foreach ($items as $i => $str) { - $items[$i] = str_replace($placeholder, $separator, $str); - } - - return $items; - } - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Returns true if the table should be analyzed, false otherwise - * - * @return bool - */ - private function _getAnalyze() - { - return $this->_analyze; - } - - /** - * Sets to true if the table should be analyzed, false otherwise - * - * @param bool $analyze status - * - * @return void - */ - private function _setAnalyze($analyze) - { - $this->_analyze = $analyze; - } - - /** - * Get cell - * - * @param string $cell Cell - * - * @return mixed - */ - private function _getCellData($cell) - { - // A cell could contain both parameters and data - $cell_data = explode('|', $cell, 2); - - // A '|' inside an invalid link should not - // be mistaken as delimiting cell parameters - if (mb_strpos($cell_data[0], '[[') === false) { - return $cell; - } - - if (count($cell_data) === 1) { - return $cell_data[0]; - } - - return $cell_data[1]; - } - - /** - * Manage $inside_structure_comment - * - * @param boolean $inside_structure_comment Value to test - * - * @return bool - */ - private function _mngInsideStructComm($inside_structure_comment) - { - // End ignoring structure rows - if ($inside_structure_comment) { - $inside_structure_comment = false; - } - - return $inside_structure_comment; - } - - /** - * Get cell content - * - * @param string $cell Cell - * @param string $col_start_char Start char - * - * @return string - */ - private function _getCellContent($cell, $col_start_char) - { - if (mb_strpos($cell, $col_start_char) === 0) { - $cell = trim(mb_substr($cell, 1)); - } - - return $cell; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportOds.php b/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportOds.php deleted file mode 100644 index 8e68692..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportOds.php +++ /dev/null @@ -1,427 +0,0 @@ -setProperties(); - } - - /** - * Sets the import plugin properties. - * Called in the constructor. - * - * @return void - */ - protected function setProperties() - { - $importPluginProperties = new ImportPluginProperties(); - $importPluginProperties->setText('OpenDocument Spreadsheet'); - $importPluginProperties->setExtension('ods'); - $importPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $importPluginProperties - // this will be shown as "Format specific options" - $importSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - // create primary items and add them to the group - $leaf = new BoolPropertyItem( - "col_names", - __( - 'The first line of the file contains the table column names' - . ' (if this is unchecked, the first line will become part' - . ' of the data)' - ) - ); - $generalOptions->addProperty($leaf); - $leaf = new BoolPropertyItem( - "empty_rows", - __('Do not import empty rows') - ); - $generalOptions->addProperty($leaf); - $leaf = new BoolPropertyItem( - "recognize_percentages", - __( - 'Import percentages as proper decimals (ex. 12.00% to .12)' - ) - ); - $generalOptions->addProperty($leaf); - $leaf = new BoolPropertyItem( - "recognize_currency", - __('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; - } - - /** - * Handles the whole import logic - * - * @param array $sql_data 2-element array with sql data - * - * @return void - */ - public function doImport(array &$sql_data = []) - { - global $db, $error, $timeout_passed, $finished; - - $i = 0; - $len = 0; - $buffer = ""; - - /** - * Read in the file via Import::getNextChunk so that - * it can process compressed files - */ - while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { - $data = $this->import->getNextChunk(); - if ($data === false) { - /* subtract data we didn't handle yet and stop processing */ - $GLOBALS['offset'] -= strlen($buffer); - break; - } elseif ($data !== true) { - /* 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 = []; - $GLOBALS['message'] = Message::error( - __( - 'The XML file specified was either malformed or incomplete.' - . ' Please correct the issue and try again.' - ) - ); - $GLOBALS['error'] = true; - } else { - /** @var SimpleXMLElement $root */ - $root = $xml->children('office', true)->{'body'}->{'spreadsheet'}; - if (empty($root)) { - $sheets = []; - $GLOBALS['message'] = Message::error( - __('Could not parse OpenDocument Spreadsheet!') - ); - $GLOBALS['error'] = true; - } else { - $sheets = $root->children('table', true); - } - } - - $tables = []; - - $max_cols = 0; - - $col_count = 0; - $col_names = []; - - $tempRow = []; - $tempRows = []; - $rows = []; - - /* Iterate over tables */ - /** @var SimpleXMLElement $sheet */ - foreach ($sheets as $sheet) { - $col_names_in_first_row = isset($_REQUEST['ods_col_names']); - - /* Iterate over rows */ - /** @var SimpleXMLElement $row */ - foreach ($sheet as $row) { - $type = $row->getName(); - if (strcmp('table-row', $type)) { - continue; - } - /* Iterate over columns */ - $cellCount = count($row); - $a = 0; - /** @var SimpleXMLElement $cell */ - foreach ($row as $cell) { - $a++; - $text = $cell->children('text', true); - $cell_attrs = $cell->attributes('office', true); - - if (count($text) != 0) { - $attr = $cell->attributes('table', true); - $num_repeat = (int) $attr['number-columns-repeated']; - $num_iterations = $num_repeat ?: 1; - - for ($k = 0; $k < $num_iterations; $k++) { - $value = $this->getValue($cell_attrs, $text); - if (! $col_names_in_first_row) { - $tempRow[] = $value; - } else { - // MySQL column names can't end with a space - // character. - $col_names[] = rtrim($value); - } - - ++$col_count; - } - continue; - } - - // skip empty repeats in the last row - if ($a == $cellCount) { - continue; - } - - $attr = $cell->attributes('table', true); - $num_null = (int) $attr['number-columns-repeated']; - - if ($num_null) { - if (! $col_names_in_first_row) { - for ($i = 0; $i < $num_null; ++$i) { - $tempRow[] = 'NULL'; - ++$col_count; - } - } else { - for ($i = 0; $i < $num_null; ++$i) { - $col_names[] = $this->import->getColumnAlphaName( - $col_count + 1 - ); - ++$col_count; - } - } - } else { - if (! $col_names_in_first_row) { - $tempRow[] = 'NULL'; - } else { - $col_names[] = $this->import->getColumnAlphaName( - $col_count + 1 - ); - } - - ++$col_count; - } - } //Endforeach - - /* Find the widest row */ - if ($col_count > $max_cols) { - $max_cols = $col_count; - } - - /* Don't include a row that is full of NULL values */ - if (! $col_names_in_first_row) { - if ($_REQUEST['ods_empty_rows']) { - foreach ($tempRow as $cell) { - if (strcmp('NULL', $cell)) { - $tempRows[] = $tempRow; - break; - } - } - } else { - $tempRows[] = $tempRow; - } - } - - $col_count = 0; - $col_names_in_first_row = false; - $tempRow = []; - } - - /* Skip over empty sheets */ - if (count($tempRows) == 0 || count($tempRows[0]) === 0) { - $col_names = []; - $tempRow = []; - $tempRows = []; - 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[] = $this->import->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[] = [(string) $tbl_attr['name']]; - - /* Store the current sheet in the accumulator */ - $rows[] = [ - (string) $tbl_attr['name'], - $col_names, - $tempRows, - ]; - $tempRows = []; - $col_names = []; - $max_cols = 0; - } - - unset($tempRow); - unset($tempRows); - unset($col_names); - unset($sheets); - unset($xml); - - /** - * Bring accumulated rows into the corresponding table - */ - $num_tables = count($tables); - for ($i = 0; $i < $num_tables; ++$i) { - $num_rows = count($rows); - for ($j = 0; $j < $num_rows; ++$j) { - if (strcmp($tables[$i][Import::TBL_NAME], $rows[$j][Import::TBL_NAME])) { - continue; - } - - if (! isset($tables[$i][Import::COL_NAMES])) { - $tables[$i][] = $rows[$j][Import::COL_NAMES]; - } - - $tables[$i][Import::ROWS] = $rows[$j][Import::ROWS]; - } - } - - /* No longer needed */ - unset($rows); - - /* Obtain the best-fit MySQL types for each column */ - $analyses = []; - - $len = count($tables); - for ($i = 0; $i < $len; ++$i) { - $analyses[] = $this->import->analyzeTable($tables[$i]); - } - - /** - * string $db_name (no backquotes) - * - * array $table = array(table_name, array() column_names, array()() rows) - * array $tables = array of "$table"s - * - * array $analysis = array(array() column_types, array() column_sizes) - * array $analyses = array of "$analysis"s - * - * array $create = array of SQL strings - * - * array $options = an associative array of options - */ - - /* Set database name to the currently selected one, if applicable */ - list($db_name, $options) = $this->getDbnameAndOptions($db, 'ODS_DB'); - - /* Non-applicable parameters */ - $create = null; - - /* Created and execute necessary SQL statements from data */ - $this->import->buildSql($db_name, $tables, $analyses, $create, $options, $sql_data); - - unset($tables); - unset($analyses); - - /* Commit any possible data in buffers */ - $this->import->runQuery('', '', $sql_data); - } - - /** - * Get value - * - * @param array $cell_attrs Cell attributes - * @param array $text Texts - * - * @return float|string - */ - protected function getValue($cell_attrs, $text) - { - if ($_REQUEST['ods_recognize_percentages'] - && ! strcmp( - 'percentage', - (string) $cell_attrs['value-type'] - ) - ) { - $value = (double) $cell_attrs['value']; - - return $value; - } elseif ($_REQUEST['ods_recognize_currency'] - && ! strcmp('currency', (string) $cell_attrs['value-type']) - ) { - $value = (double) $cell_attrs['value']; - - return $value; - } - - /* We need to concatenate all paragraphs */ - $values = []; - foreach ($text as $paragraph) { - $values[] = (string) $paragraph; - } - $value = implode("\n", $values); - - return $value; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportShp.php b/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportShp.php deleted file mode 100644 index 614cb9e..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportShp.php +++ /dev/null @@ -1,335 +0,0 @@ -setProperties(); - if (extension_loaded('zip')) { - $this->zipExtension = new ZipExtension(); - } - } - - /** - * Sets the import plugin properties. - * Called in the constructor. - * - * @return void - */ - protected function setProperties() - { - $importPluginProperties = new ImportPluginProperties(); - $importPluginProperties->setText(__('ESRI Shape File')); - $importPluginProperties->setExtension('shp'); - $importPluginProperties->setOptions([]); - $importPluginProperties->setOptionsText(__('Options')); - - $this->properties = $importPluginProperties; - } - - /** - * Handles the whole import logic - * - * @param array $sql_data 2-element array with sql data - * - * @return void - */ - public function doImport(array &$sql_data = []) - { - global $db, $error, $finished, - $import_file, $local_import_file, $message; - - $GLOBALS['finished'] = false; - - $compression = $GLOBALS['import_handle']->getCompression(); - - $shp = new ShapeFileImport(1); - // If the zip archive has more than one file, - // get the correct content to the buffer from .shp file. - if ($compression == 'application/zip' - && $this->zipExtension->getNumberOfFiles($import_file) > 1 - ) { - if ($GLOBALS['import_handle']->openZip('/^.*\.shp$/i') === false) { - $message = Message::error( - __('There was an error importing the ESRI shape file: "%s".') - ); - $message->addParam($GLOBALS['import_handle']->getError()); - - return; - } - } - - $temp_dbf_file = false; - // We need dbase extension to handle .dbf file - if (extension_loaded('dbase')) { - $temp = $GLOBALS['PMA_Config']->getTempDir('shp'); - // If we can extract the zip archive to 'TempDir' - // and use the files in it for import - if ($compression == 'application/zip' && $temp !== null) { - $dbf_file_name = $this->zipExtension->findFile( - $import_file, - '/^.*\.dbf$/i' - ); - // If the corresponding .dbf file is in the zip archive - if ($dbf_file_name) { - // Extract the .dbf file and point to it. - $extracted = $this->zipExtension->extract( - $import_file, - $dbf_file_name - ); - if ($extracted !== false) { - // remove filename extension, e.g. - // dresden_osm.shp/gis.osm_transport_a_v06.dbf - // to - // dresden_osm.shp/gis.osm_transport_a_v06 - $path_parts = pathinfo($dbf_file_name); - $dbf_file_name = $path_parts['dirname'] . '/' . $path_parts['filename']; - - // sanitize filename - $dbf_file_name = Sanitize::sanitizeFilename($dbf_file_name, true); - - // concat correct filename and extension - $dbf_file_path = $temp . '/' . $dbf_file_name . '.dbf'; - - if (file_put_contents($dbf_file_path, $extracted, LOCK_EX) !== false) { - $temp_dbf_file = true; - - // Replace the .dbf with .*, as required by the bsShapeFiles library. - $shp->FileName = substr($dbf_file_path, 0, -4) . '.*'; - } - } - } - } elseif (! empty($local_import_file) - && ! empty($GLOBALS['cfg']['UploadDir']) - && $compression == 'none' - ) { - // If file is in UploadDir, use .dbf file in the same UploadDir - // to load extra data. - // Replace the .shp with .*, - // so the bsShapeFiles library correctly locates .dbf file. - $file_name = mb_substr( - $import_file, - 0, - mb_strlen($import_file) - 4 - ) . '.*'; - $shp->FileName = $file_name; - } - } - - // It should load data before file being deleted - $shp->loadFromFile(''); - - // Delete the .dbf file extracted to 'TempDir' - if ($temp_dbf_file - && isset($dbf_file_path) - && @file_exists($dbf_file_path) - ) { - unlink($dbf_file_path); - } - - if ($shp->lastError != '') { - $error = true; - $message = Message::error( - __('There was an error importing the ESRI shape file: "%s".') - ); - $message->addParam($shp->lastError); - - return; - } - - 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; - $message = Message::error( - __('MySQL Spatial Extension does not support ESRI type "%s".') - ); - $message->addParam($shp->getShapeName()); - return; - } - - if (isset($gis_type)) { - /** @var GisMultiLineString|GisMultiPoint|GisPoint|GisPolygon $gis_obj */ - $gis_obj = GisFactory::factory($gis_type); - } else { - $gis_obj = null; - } - - $num_rows = count($shp->records); - // If .dbf file is loaded, the number of extra data columns - $num_data_cols = $shp->getDBFHeader() !== null ? count($shp->getDBFHeader()) : 0; - - $rows = []; - $col_names = []; - if ($num_rows != 0) { - foreach ($shp->records as $record) { - $tempRow = []; - if ($gis_obj == null) { - $tempRow[] = null; - } else { - $tempRow[] = "GeomFromText('" - . $gis_obj->getShape($record->SHPData) . "')"; - } - - if ($shp->getDBFHeader() !== null) { - foreach ($shp->getDBFHeader() as $c) { - $cell = trim((string) $record->DBFData[$c[0]]); - - if (! strcmp($cell, '')) { - $cell = 'NULL'; - } - - $tempRow[] = $cell; - } - } - $rows[] = $tempRow; - } - } - - if (count($rows) === 0) { - $error = true; - $message = 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->getDBFHeader()[$n][0]; - } - - // Set table name based on the number of tables - if (strlen((string) $db) > 0) { - $result = $GLOBALS['dbi']->fetchResult('SHOW TABLES'); - $table_name = 'TABLE ' . (count($result) + 1); - } else { - $table_name = 'TBL_NAME'; - } - $tables = [ - [ - $table_name, - $col_names, - $rows, - ], - ]; - - // Use data from shape file to chose best-fit MySQL types for each column - $analyses = []; - $analyses[] = $this->import->analyzeTable($tables[0]); - - $table_no = 0; - $spatial_col = 0; - $analyses[$table_no][Import::TYPES][$spatial_col] = Import::GEOMETRY; - $analyses[$table_no][Import::FORMATTEDSQL][$spatial_col] = true; - - // Set database name to the currently selected one, if applicable - if (strlen((string) $db) > 0) { - $db_name = $db; - $options = ['create_db' => false]; - } else { - $db_name = 'SHP_DB'; - $options = null; - } - - // Created and execute necessary SQL statements from data - $null_param = null; - $this->import->buildSql($db_name, $tables, $analyses, $null_param, $options, $sql_data); - - unset($tables); - unset($analyses); - - $finished = true; - $error = false; - - // Commit any possible data in buffers - $this->import->runQuery('', '', $sql_data); - } - - /** - * Returns specified number of bytes from the buffer. - * Buffer automatically fetches next chunk of data when the buffer - * falls short. - * Sets $eof when $GLOBALS['finished'] is set and the buffer falls short. - * - * @param int $length number of bytes - * - * @return string - */ - public static function readFromBuffer($length) - { - global $buffer, $eof; - - $import = new Import(); - - if (strlen((string) $buffer) < $length) { - if ($GLOBALS['finished']) { - $eof = true; - } else { - $buffer .= $import->getNextChunk(); - } - } - $result = substr($buffer, 0, $length); - $buffer = substr($buffer, $length); - - return $result; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportSql.php b/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportSql.php deleted file mode 100644 index 599db37..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportSql.php +++ /dev/null @@ -1,200 +0,0 @@ -setProperties(); - } - - /** - * Sets the import plugin properties. - * Called in the constructor. - * - * @return void - */ - protected function setProperties() - { - $importPluginProperties = new ImportPluginProperties(); - $importPluginProperties->setText('SQL'); - $importPluginProperties->setExtension('sql'); - $importPluginProperties->setOptionsText(__('Options')); - - $compats = $GLOBALS['dbi']->getCompatibilities(); - if (count($compats) > 0) { - $values = []; - foreach ($compats as $val) { - $values[$val] = $val; - } - - // create the root group that will be the options field for - // $importPluginProperties - // this will be shown as "Format specific options" - $importSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new OptionsPropertyMainGroup("general_opts"); - // create primary items and add them to the group - $leaf = new SelectPropertyItem( - "compatibility", - __('SQL compatibility mode:') - ); - $leaf->setValues($values); - $leaf->setDoc( - [ - 'manual_MySQL_Database_Administration', - 'Server_SQL_mode', - ] - ); - $generalOptions->addProperty($leaf); - $leaf = new BoolPropertyItem( - "no_auto_value_on_zero", - __('Do not use AUTO_INCREMENT for zero values') - ); - $leaf->setDoc( - [ - 'manual_MySQL_Database_Administration', - 'Server_SQL_mode', - 'sqlmode_no_auto_value_on_zero', - ] - ); - $generalOptions->addProperty($leaf); - - // add the main group to the root group - $importSpecificOptions->addProperty($generalOptions); - // set the options for the import plugin property item - $importPluginProperties->setOptions($importSpecificOptions); - } - - $this->properties = $importPluginProperties; - } - - /** - * Handles the whole import logic - * - * @param array $sql_data 2-element array with sql data - * - * @return void - */ - public function doImport(array &$sql_data = []) - { - global $error, $timeout_passed; - - // Handle compatibility options. - $this->_setSQLMode($GLOBALS['dbi'], $_REQUEST); - - $bq = new BufferedQuery(); - if (isset($_POST['sql_delimiter'])) { - $bq->setDelimiter($_POST['sql_delimiter']); - } - - /** - * Will be set in Import::getNextChunk(). - * - * @global bool $GLOBALS ['finished'] - */ - $GLOBALS['finished'] = false; - - while ((! $error) && (! $timeout_passed)) { - // Getting the first statement, the remaining data and the last - // delimiter. - $statement = $bq->extract(); - - // If there is no full statement, we are looking for more data. - if (empty($statement)) { - // Importing new data. - $newData = $this->import->getNextChunk(); - - // Subtract data we didn't handle yet and stop processing. - if ($newData === false) { - $GLOBALS['offset'] -= mb_strlen($bq->query); - break; - } - - // Checking if the input buffer has finished. - if ($newData === true) { - $GLOBALS['finished'] = true; - break; - } - - // Convert CR (but not CRLF) to LF otherwise all queries may - // not get executed on some platforms. - $bq->query .= preg_replace("/\r($|[^\n])/", "\n$1", $newData); - - continue; - } - - // Executing the query. - $this->import->runQuery($statement, $statement, $sql_data); - } - - // Extracting remaining statements. - while (! $error && ! $timeout_passed && ! empty($bq->query)) { - $statement = $bq->extract(true); - if (! empty($statement)) { - $this->import->runQuery($statement, $statement, $sql_data); - } - } - - // Finishing. - $this->import->runQuery('', '', $sql_data); - } - - /** - * Handle compatibility options - * - * @param DatabaseInterface $dbi Database interface - * @param array $request Request array - * - * @return void - */ - private function _setSQLMode($dbi, array $request) - { - $sql_modes = []; - if (isset($request['sql_compatibility']) - && 'NONE' != $request['sql_compatibility'] - ) { - $sql_modes[] = $request['sql_compatibility']; - } - if (isset($request['sql_no_auto_value_on_zero'])) { - $sql_modes[] = 'NO_AUTO_VALUE_ON_ZERO'; - } - if (count($sql_modes) > 0) { - $dbi->tryQuery( - 'SET SQL_MODE="' . implode(',', $sql_modes) . '"' - ); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportXml.php b/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportXml.php deleted file mode 100644 index 833d4e4..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ImportXml.php +++ /dev/null @@ -1,375 +0,0 @@ -setProperties(); - } - - /** - * Sets the import plugin properties. - * Called in the constructor. - * - * @return void - */ - protected function setProperties() - { - $importPluginProperties = new ImportPluginProperties(); - $importPluginProperties->setText(__('XML')); - $importPluginProperties->setExtension('xml'); - $importPluginProperties->setMimeType('text/xml'); - $importPluginProperties->setOptions([]); - $importPluginProperties->setOptionsText(__('Options')); - - $this->properties = $importPluginProperties; - } - - /** - * Handles the whole import logic - * - * @param array $sql_data 2-element array with sql data - * - * @return void - */ - public function doImport(array &$sql_data = []) - { - global $error, $timeout_passed, $finished, $db; - - $i = 0; - $len = 0; - $buffer = ""; - - /** - * Read in the file via Import::getNextChunk so that - * it can process compressed files - */ - while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { - $data = $this->import->getNextChunk(); - if ($data === false) { - /* subtract data we didn't handle yet and stop processing */ - $GLOBALS['offset'] -= strlen($buffer); - break; - } elseif ($data !== true) { - /* 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) { - 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 = []; - /** - * Row accumulator - */ - $rows = []; - - /** - * Temp arrays - */ - $tempRow = []; - $tempCells = []; - - /** - * 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(isset($namespaces['pma']) ? $namespaces['pma'] : null) - ->{'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) { - Message::error( - __( - 'The XML file specified was either malformed or incomplete.' - . ' Please correct the issue and try again.' - ) - ) - ->display(); - unset($xml); - $GLOBALS['finished'] = false; - - return; - } - - /** - * Retrieve the structure information - */ - if (isset($namespaces['pma'])) { - /** - * Get structures for all tables - * - * @var SimpleXMLElement $struct - */ - $struct = $xml->children($namespaces['pma']); - - $create = []; - - /** @var SimpleXMLElement $val1 */ - foreach ($struct as $val1) { - /** @var SimpleXMLElement $val2 */ - foreach ($val1 as $val2) { - // Need to select the correct database for the creation of - // tables, views, triggers, etc. - /** - * @todo Generating a USE here blocks importing of a table - * into another database. - */ - $attrs = $val2->attributes(); - $create[] = "USE " - . Util::backquote( - $attrs["name"] - ); - - foreach ($val2 as $val3) { - /** - * Remove the extra cosmetic spacing - */ - $val3 = str_replace(" ", "", (string) $val3); - $create[] = $val3; - } - } - } - - $struct_present = true; - } - - /** - * Move down the XML tree to the actual data - */ - $xml = $xml->children() - ->children(); - - $data_present = false; - - /** - * Only attempt to analyze/collect data if there is data present - */ - if ($xml && @count($xml->children())) { - $data_present = true; - - /** - * Process all database content - */ - foreach ($xml as $v1) { - $tbl_attr = $v1->attributes(); - - $isInTables = false; - $num_tables = count($tables); - for ($i = 0; $i < $num_tables; ++$i) { - if (! strcmp($tables[$i][Import::TBL_NAME], (string) $tbl_attr['name'])) { - $isInTables = true; - break; - } - } - - if (! $isInTables) { - $tables[] = [(string) $tbl_attr['name']]; - } - - foreach ($v1 as $v2) { - $row_attr = $v2->attributes(); - if (! array_search((string) $row_attr['name'], $tempRow)) { - $tempRow[] = (string) $row_attr['name']; - } - $tempCells[] = (string) $v2; - } - - $rows[] = [ - (string) $tbl_attr['name'], - $tempRow, - $tempCells, - ]; - - $tempRow = []; - $tempCells = []; - } - - unset($tempRow); - unset($tempCells); - unset($xml); - - /** - * Bring accumulated rows into the corresponding table - */ - $num_tables = count($tables); - for ($i = 0; $i < $num_tables; ++$i) { - $num_rows = count($rows); - for ($j = 0; $j < $num_rows; ++$j) { - if (! strcmp($tables[$i][Import::TBL_NAME], $rows[$j][Import::TBL_NAME])) { - if (! isset($tables[$i][Import::COL_NAMES])) { - $tables[$i][] = $rows[$j][Import::COL_NAMES]; - } - - $tables[$i][Import::ROWS][] = $rows[$j][Import::ROWS]; - } - } - } - - unset($rows); - - if (! $struct_present) { - $analyses = []; - - $len = count($tables); - for ($i = 0; $i < $len; ++$i) { - $analyses[] = $this->import->analyzeTable($tables[$i]); - } - } - } - - unset($xml); - unset($tempCells); - unset($rows); - - /** - * Only build SQL from data if there is data present - */ - if ($data_present) { - /** - * Set values to NULL if they were not present - * to maintain Import::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((string) $db)) { - /* Override the database name in the XML file, if one is selected */ - $db_name = $db; - $options = ['create_db' => false]; - } else { - if ($db_name === null) { - $db_name = 'XML_DB'; - } - - /* Set database collation/charset */ - $options = [ - 'db_collation' => $collation, - 'db_charset' => $charset, - ]; - } - - /* Created and execute necessary SQL statements from data */ - $this->import->buildSql($db_name, $tables, $analyses, $create, $options, $sql_data); - - unset($analyses); - unset($tables); - unset($create); - - /* Commit any possible data in buffers */ - $this->import->runQuery('', '', $sql_data); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/README b/srcs/phpmyadmin/libraries/classes/Plugins/Import/README deleted file mode 100644 index e240556..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/README +++ /dev/null @@ -1,156 +0,0 @@ -This directory holds import plugins for phpMyAdmin. Any new plugin should -basically follow the structure presented here. The messages must use our -gettext mechanism, see https://wiki.phpmyadmin.net/pma/Gettext_for_developers. - -setProperties(); - } - - /** - * Sets the import plugin properties. - * Called in the constructor. - * - * @return void - */ - protected function setProperties() - { - $importPluginProperties = new PhpMyAdmin\Properties\Plugins\ImportPluginProperties(); - $importPluginProperties->setText('[name]'); // the name of your plug-in - $importPluginProperties->setExtension('[ext]'); // extension this plug-in can handle - $importPluginProperties->setOptionsText(__('Options')); - - // create the root group that will be the options field for - // $importPluginProperties - // this will be shown as "Format specific options" - $importSpecificOptions = new - PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // general options main group - $generalOptions = new PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup( - "general_opts" - ); - - // optional : - // create primary items and add them to the group - // type - one of the classes listed in libraries/properties/options/items/ - // name - form element name - // text - description in GUI - // size - size of text element - // len - maximal size of input - // values - possible values of the item - $leaf = new PhpMyAdmin\Properties\Options\Items\RadioPropertyItem( - "structure_or_data" - ); - $leaf->setValues( - array( - 'structure' => __('structure'), - 'data' => __('data'), - 'structure_and_data' => __('structure and data') - ) - ); - $generalOptions->addProperty($leaf); - - // add the main group to the root group - $importSpecificOptions->addProperty($generalOptions); - - // set the options for the import plugin property item - $importPluginProperties->setOptions($importSpecificOptions); - $this->properties = $importPluginProperties; - } - - /** - * Handles the whole import logic - * - * @param array &$sql_data 2-element array with sql data - * - * @return void - */ - public function doImport(&$sql_data = array()) - { - // get globals (others are optional) - global $error, $timeout_passed, $finished; - - $buffer = ''; - while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { - $data = $this->import->getNextChunk(); - if ($data === false) { - // subtract data we didn't handle yet and stop processing - $GLOBALS['offset'] -= strlen($buffer); - break; - } elseif ($data === true) { - // Handle rest of buffer - } else { - // Append new data to buffer - $buffer .= $data; - } - // PARSE $buffer here, post sql queries using: - $this->import->runQuery($sql, $verbose_sql_with_comments, $sql_data); - } // End of import loop - // Commit any possible data in buffers - $this->import->runQuery('', '', $sql_data); - } - - - // optional: - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - - /** - * Getter description - * - * @return type - */ - private function _getMyOptionalVariable() - { - return $this->_myOptionalVariable; - } - - /** - * Setter description - * - * @param type $my_optional_variable description - * - * @return void - */ - private function _setMyOptionalVariable($my_optional_variable) - { - $this->_myOptionalVariable = $my_optional_variable; - } -} -?> diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ShapeFileImport.php b/srcs/phpmyadmin/libraries/classes/Plugins/Import/ShapeFileImport.php deleted file mode 100644 index 8af3f90..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/ShapeFileImport.php +++ /dev/null @@ -1,46 +0,0 @@ - $id, - 'finished' => false, - 'percent' => 0, - 'total' => 0, - 'complete' => 0, - 'plugin' => UploadApc::getIdKey(), - ]; - } - $ret = $_SESSION[$SESSION_KEY][$id]; - - if (! ImportAjax::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; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadNoplugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadNoplugin.php deleted file mode 100644 index 087b1e1..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadNoplugin.php +++ /dev/null @@ -1,60 +0,0 @@ - $id, - 'finished' => false, - 'percent' => 0, - 'total' => 0, - 'complete' => 0, - 'plugin' => UploadNoplugin::getIdKey(), - ]; - } - return $_SESSION[$SESSION_KEY][$id]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadProgress.php b/srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadProgress.php deleted file mode 100644 index 13578e0..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadProgress.php +++ /dev/null @@ -1,97 +0,0 @@ - $id, - 'finished' => false, - 'percent' => 0, - 'total' => 0, - 'complete' => 0, - 'plugin' => UploadProgress::getIdKey(), - ]; - } - $ret = $_SESSION[$SESSION_KEY][$id]; - - if (! ImportAjax::progressCheck() || $ret['finished']) { - return $ret; - } - - $status = null; - if (function_exists('uploadprogress_get_info')) { - $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 = [ - 'id' => $id, - 'finished' => true, - 'percent' => 100, - 'total' => $ret['total'], - 'complete' => $ret['total'], - 'plugin' => UploadProgress::getIdKey(), - ]; - } - - $_SESSION[$SESSION_KEY][$id] = $ret; - - return $ret; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadSession.php b/srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadSession.php deleted file mode 100644 index 133b11a..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Import/Upload/UploadSession.php +++ /dev/null @@ -1,95 +0,0 @@ - $id, - 'finished' => false, - 'percent' => 0, - 'total' => 0, - 'complete' => 0, - 'plugin' => UploadSession::getIdKey(), - ]; - } - $ret = $_SESSION[$SESSION_KEY][$id]; - - if (! ImportAjax::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 = [ - 'id' => $id, - 'finished' => true, - 'percent' => 100, - 'total' => $ret['total'], - 'complete' => $ret['total'], - 'plugin' => UploadSession::getIdKey(), - ]; - } - - $_SESSION[$SESSION_KEY][$id] = $ret; - - return $ret; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/ImportPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/ImportPlugin.php deleted file mode 100644 index 788bd42..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/ImportPlugin.php +++ /dev/null @@ -1,96 +0,0 @@ -import = new Import(); - } - - /** - * Handles the whole import logic - * - * @param array $sql_data 2-element array with sql data - * - * @return void - */ - abstract public function doImport(array &$sql_data = []); - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the import specific format plugin properties - * - * @return ImportPluginProperties - */ - public function getProperties() - { - return $this->properties; - } - - /** - * Sets the export plugins properties and is implemented by each import - * plugin - * - * @return void - */ - abstract protected function setProperties(); - - /** - * Define DB name and options - * - * @param string $currentDb DB - * @param string $defaultDb Default DB name - * - * @return array DB name and options (an associative array of options) - */ - protected function getDbnameAndOptions($currentDb, $defaultDb) - { - if (strlen((string) $currentDb) > 0) { - $db_name = $currentDb; - $options = ['create_db' => false]; - } else { - $db_name = $defaultDb; - $options = null; - } - - return [ - $db_name, - $options, - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/Dia.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/Dia.php deleted file mode 100644 index b9941a5..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/Dia.php +++ /dev/null @@ -1,190 +0,0 @@ -openMemory(); - /* - * Set indenting using three spaces, - * so output is formatted - */ - $this->setIndent(true); - $this->setIndentString(' '); - /* - * Create the XML document - */ - $this->startDocument('1.0', 'UTF-8'); - } - - /** - * Starts Dia Document - * - * dia document starts by first initializing dia:diagram tag - * then dia:diagramdata contains all the attributes that needed - * to define the document, then finally a Layer starts which - * holds all the objects. - * - * @param string $paper the size of the paper/document - * @param float $topMargin top margin of the paper/document in cm - * @param float $bottomMargin bottom margin of the paper/document in cm - * @param float $leftMargin left margin of the paper/document in cm - * @param float $rightMargin right margin of the paper/document in cm - * @param string $orientation orientation of the document, portrait or landscape - * - * @return void - * - * @access public - * @see XMLWriter::startElement(),XMLWriter::writeAttribute(), - * XMLWriter::writeRaw() - */ - public function startDiaDoc( - $paper, - $topMargin, - $bottomMargin, - $leftMargin, - $rightMargin, - $orientation - ) { - if ($orientation == 'P') { - $isPortrait = 'true'; - } else { - $isPortrait = 'false'; - } - $this->startElement('dia:diagram'); - $this->writeAttribute('xmlns:dia', 'http://www.lysator.liu.se/~alla/dia/'); - $this->startElement('dia:diagramdata'); - $this->writeRaw( - ' - - - - - - - - - #' . $paper . '# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ' - ); - $this->endElement(); - $this->startElement('dia:layer'); - $this->writeAttribute('name', 'Background'); - $this->writeAttribute('visible', 'true'); - $this->writeAttribute('active', 'true'); - } - - /** - * Ends Dia Document - * - * @return void - * @access public - * @see XMLWriter::endElement(),XMLWriter::endDocument() - */ - public function endDiaDoc() - { - $this->endElement(); - $this->endDocument(); - } - - /** - * Output Dia Document for download - * - * @param string $fileName name of the dia document - * - * @return void - * @access public - * @see XMLWriter::flush() - */ - public function showOutput($fileName) - { - if (ob_get_clean()) { - ob_end_clean(); - } - $output = $this->flush(); - Response::getInstance()->disable(); - Core::downloadHeader( - $fileName, - 'application/x-dia-diagram', - strlen($output) - ); - print $output; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/DiaRelationSchema.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/DiaRelationSchema.php deleted file mode 100644 index ee04f0d..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/DiaRelationSchema.php +++ /dev/null @@ -1,238 +0,0 @@ -setShowColor(isset($_REQUEST['dia_show_color'])); - $this->setShowKeys(isset($_REQUEST['dia_show_keys'])); - $this->setOrientation($_REQUEST['dia_orientation']); - $this->setPaper($_REQUEST['dia_paper']); - - $this->diagram->startDiaDoc( - $this->paper, - $this->_topMargin, - $this->_bottomMargin, - $this->_leftMargin, - $this->_rightMargin, - $this->orientation - ); - - $alltables = $this->getTablesFromRequest(); - - foreach ($alltables as $table) { - if (! isset($this->_tables[$table])) { - $this->_tables[$table] = new TableStatsDia( - $this->diagram, - $this->db, - $table, - $this->pageNumber, - $this->showKeys, - $this->offline - ); - } - } - - $seen_a_relation = false; - foreach ($alltables as $one_table) { - $exist_rel = $this->relation->getForeigners($this->db, $one_table, '', 'both'); - if (! $exist_rel) { - continue; - } - - $seen_a_relation = true; - foreach ($exist_rel as $master_field => $rel) { - /* put the foreign table on the schema only if selected - * by the user - * (do not use array_search() because we would have to - * to do a === false and this is not PHP3 compatible) - */ - if ($master_field != 'foreign_keys_data') { - if (in_array($rel['foreign_table'], $alltables)) { - $this->_addRelation( - $one_table, - $master_field, - $rel['foreign_table'], - $rel['foreign_field'], - $this->showKeys - ); - } - continue; - } - - foreach ($rel as $one_key) { - if (! in_array($one_key['ref_table_name'], $alltables)) { - continue; - } - - foreach ($one_key['index_list'] as $index => $one_field) { - $this->_addRelation( - $one_table, - $one_field, - $one_key['ref_table_name'], - $one_key['ref_index_list'][$index], - $this->showKeys - ); - } - } - } - } - $this->_drawTables(); - - if ($seen_a_relation) { - $this->_drawRelations(); - } - $this->diagram->endDiaDoc(); - } - - /** - * Output Dia Document for download - * - * @return void - * @access public - */ - public function showOutput() - { - $this->diagram->showOutput($this->getFileName('.dia')); - } - - /** - * Defines relation objects - * - * @param string $masterTable The master table name - * @param string $masterField The relation field in the master table - * @param string $foreignTable The foreign table name - * @param string $foreignField The relation field in the foreign table - * @param bool $showKeys Whether to display ONLY keys or not - * - * @return void - * - * @access private - * @see TableStatsDia::__construct(),RelationStatsDia::__construct() - */ - private function _addRelation( - $masterTable, - $masterField, - $foreignTable, - $foreignField, - $showKeys - ) { - if (! isset($this->_tables[$masterTable])) { - $this->_tables[$masterTable] = new TableStatsDia( - $this->diagram, - $this->db, - $masterTable, - $this->pageNumber, - $showKeys - ); - } - if (! isset($this->_tables[$foreignTable])) { - $this->_tables[$foreignTable] = new TableStatsDia( - $this->diagram, - $this->db, - $foreignTable, - $this->pageNumber, - $showKeys - ); - } - $this->_relations[] = new RelationStatsDia( - $this->diagram, - $this->_tables[$masterTable], - $masterField, - $this->_tables[$foreignTable], - $foreignField - ); - } - - /** - * Draws relation references - * - * connects master table's master field to - * foreign table's foreign field using Dia object - * type Database - Reference - * - * @return void - * - * @access private - * @see RelationStatsDia::relationDraw() - */ - private function _drawRelations() - { - foreach ($this->_relations as $relation) { - $relation->relationDraw($this->showColor); - } - } - - /** - * Draws tables - * - * Tables are generated using Dia object type Database - Table - * primary fields are underlined and bold in tables - * - * @return void - * - * @access private - * @see TableStatsDia::tableDraw() - */ - private function _drawTables() - { - foreach ($this->_tables as $table) { - $table->tableDraw($this->showColor); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/RelationStatsDia.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/RelationStatsDia.php deleted file mode 100644 index bd44532..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/RelationStatsDia.php +++ /dev/null @@ -1,228 +0,0 @@ -diagram = $diagram; - $src_pos = $this->_getXy($master_table, $master_field); - $dest_pos = $this->_getXy($foreign_table, $foreign_field); - $this->srcConnPointsLeft = $src_pos[0]; - $this->srcConnPointsRight = $src_pos[1]; - $this->destConnPointsLeft = $dest_pos[0]; - $this->destConnPointsRight = $dest_pos[1]; - $this->masterTablePos = $src_pos[2]; - $this->foreignTablePos = $dest_pos[2]; - $this->masterTableId = $master_table->tableId; - $this->foreignTableId = $foreign_table->tableId; - } - - /** - * Each Table object have connection points - * which is used to connect to other objects in Dia - * we detect the position of key in fields and - * then determines its left and right connection - * points. - * - * @param TableStatsDia $table The current table name - * @param string $column The relation column name - * - * @return array Table right,left connection points and key position - * - * @access private - */ - private function _getXy($table, $column) - { - $pos = array_search($column, $table->fields); - // left, right, position - $value = 12; - if ($pos != 0) { - return [ - $pos + $value + $pos, - $pos + $value + $pos + 1, - $pos, - ]; - } - return [ - $pos + $value, - $pos + $value + 1, - $pos, - ]; - } - - /** - * Draws relation references - * - * connects master table's master field to foreign table's - * foreign field using Dia object type Database - Reference - * Dia object is used to generate the XML of Dia Document. - * Database reference Object and their attributes are involved - * in the combination of displaying Database - reference on Dia Document. - * - * @param boolean $showColor Whether to use one color per relation or not - * if showColor is true then an array of $listOfColors - * will be used to choose the random colors for - * references lines. we can change/add more colors to - * this - * - * @return boolean|void - * - * @access public - * @see PDF - */ - public function relationDraw($showColor) - { - ++DiaRelationSchema::$objectId; - /* - * if source connection points and destination connection - * points are same then return it false and don't draw that - * relation - */ - if ($this->srcConnPointsRight == $this->destConnPointsRight) { - if ($this->srcConnPointsLeft == $this->destConnPointsLeft) { - return false; - } - } - - if ($showColor) { - $listOfColors = [ - 'FF0000', - '000099', - '00FF00', - ]; - shuffle($listOfColors); - $this->referenceColor = '#' . $listOfColors[0] . ''; - } else { - $this->referenceColor = '#000000'; - } - - $this->diagram->writeRaw( - ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #1# - - - #n# - - - - - - - - - - - - ' - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/TableStatsDia.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/TableStatsDia.php deleted file mode 100644 index b3ae5a0..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/TableStatsDia.php +++ /dev/null @@ -1,231 +0,0 @@ -tableId = ++DiaRelationSchema::$objectId; - } - - /** - * Displays an error when the table cannot be found. - * - * @return void - */ - protected function showMissingTableError() - { - ExportRelationSchema::dieSchema( - $this->pageNumber, - "DIA", - sprintf(__('The %s table doesn\'t exist!'), $this->tableName) - ); - } - - /** - * Do draw the table - * - * Tables are generated using object type Database - Table - * primary fields are underlined in tables. Dia object - * is used to generate the XML of Dia Document. Database Table - * Object and their attributes are involved in the combination - * of displaying Database - Table on Dia Document. - * - * @param boolean $showColor Whether to show color for tables text or not - * if showColor is true then an array of $listOfColors - * will be used to choose the random colors for tables - * text we can change/add more colors to this array - * - * @return void - * - * @access public - * @see Dia - */ - public function tableDraw($showColor) - { - if ($showColor) { - $listOfColors = [ - 'FF0000', - '000099', - '00FF00', - ]; - shuffle($listOfColors); - $this->tableColor = '#' . $listOfColors[0] . ''; - } else { - $this->tableColor = '#000000'; - } - - $factor = 0.1; - - $this->diagram->startElement('dia:object'); - $this->diagram->writeAttribute('type', 'Database - Table'); - $this->diagram->writeAttribute('version', '0'); - $this->diagram->writeAttribute('id', '' . $this->tableId . ''); - $this->diagram->writeRaw( - ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #' . $this->tableName . '# - - - ## - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ' - ); - - $this->diagram->startElement('dia:attribute'); - $this->diagram->writeAttribute('name', 'attributes'); - - foreach ($this->fields as $field) { - $this->diagram->writeRaw( - ' - - #' . $field . '# - - - ## - - - ## - ' - ); - unset($pm); - $pm = 'false'; - if (in_array($field, $this->primary)) { - $pm = 'true'; - } - if ($field == $this->displayfield) { - $pm = 'false'; - } - $this->diagram->writeRaw( - ' - - - - - - - - - ' - ); - } - $this->diagram->endElement(); - $this->diagram->endElement(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/Eps.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/Eps.php deleted file mode 100644 index 0679709..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/Eps.php +++ /dev/null @@ -1,280 +0,0 @@ -stringCommands = ""; - $this->stringCommands .= "%!PS-Adobe-3.0 EPSF-3.0 \n"; - } - - /** - * Set document title - * - * @param string $value sets the title text - * - * @return void - */ - public function setTitle($value) - { - $this->stringCommands .= '%%Title: ' . $value . "\n"; - } - - /** - * Set document author - * - * @param string $value sets the author - * - * @return void - */ - public function setAuthor($value) - { - $this->stringCommands .= '%%Creator: ' . $value . "\n"; - } - - /** - * Set document creation date - * - * @param string $value sets the date - * - * @return void - */ - public function setDate($value) - { - $this->stringCommands .= '%%CreationDate: ' . $value . "\n"; - } - - /** - * Set document orientation - * - * @param string $orientation sets the orientation - * - * @return void - */ - public function setOrientation($orientation) - { - $this->stringCommands .= "%%PageOrder: Ascend \n"; - if ($orientation == "L") { - $orientation = "Landscape"; - $this->stringCommands .= '%%Orientation: ' . $orientation . "\n"; - } else { - $orientation = "Portrait"; - $this->stringCommands .= '%%Orientation: ' . $orientation . "\n"; - } - $this->stringCommands .= "%%EndComments \n"; - $this->stringCommands .= "%%Pages 1 \n"; - $this->stringCommands .= "%%BoundingBox: 72 150 144 170 \n"; - } - - /** - * Set the font and size - * - * font can be set whenever needed in EPS - * - * @param string $value sets the font name e.g Arial - * @param integer $size sets the size of the font e.g 10 - * - * @return void - */ - public function setFont($value, $size) - { - $this->font = $value; - $this->fontSize = $size; - $this->stringCommands .= "/" . $value . " findfont % Get the basic font\n"; - $this->stringCommands .= "" - . $size . " scalefont % Scale the font to $size points\n"; - $this->stringCommands - .= "setfont % Make it the current font\n"; - } - - /** - * Get the font - * - * @return string return the font name e.g Arial - */ - public function getFont() - { - return $this->font; - } - - /** - * Get the font Size - * - * @return string return the size of the font e.g 10 - */ - public function getFontSize() - { - return $this->fontSize; - } - - /** - * Draw the line - * - * drawing the lines from x,y source to x,y destination and set the - * width of the line. lines helps in showing relationships of tables - * - * @param integer $x_from The x_from attribute defines the start - * left position of the element - * @param integer $y_from The y_from attribute defines the start - * right position of the element - * @param integer $x_to The x_to attribute defines the end - * left position of the element - * @param integer $y_to The y_to attribute defines the end - * right position of the element - * @param integer $lineWidth Sets the width of the line e.g 2 - * - * @return void - */ - public function line( - $x_from = 0, - $y_from = 0, - $x_to = 0, - $y_to = 0, - $lineWidth = 0 - ) { - $this->stringCommands .= $lineWidth . " setlinewidth \n"; - $this->stringCommands .= $x_from . ' ' . $y_from . " moveto \n"; - $this->stringCommands .= $x_to . ' ' . $y_to . " lineto \n"; - $this->stringCommands .= "stroke \n"; - } - - /** - * Draw the rectangle - * - * drawing the rectangle from x,y source to x,y destination and set the - * width of the line. rectangles drawn around the text shown of fields - * - * @param integer $x_from The x_from attribute defines the start - * left position of the element - * @param integer $y_from The y_from attribute defines the start - * right position of the element - * @param integer $x_to The x_to attribute defines the end - * left position of the element - * @param integer $y_to The y_to attribute defines the end - * right position of the element - * @param integer $lineWidth Sets the width of the line e.g 2 - * - * @return void - */ - public function rect($x_from, $y_from, $x_to, $y_to, $lineWidth) - { - $this->stringCommands .= $lineWidth . " setlinewidth \n"; - $this->stringCommands .= "newpath \n"; - $this->stringCommands .= $x_from . " " . $y_from . " moveto \n"; - $this->stringCommands .= "0 " . $y_to . " rlineto \n"; - $this->stringCommands .= $x_to . " 0 rlineto \n"; - $this->stringCommands .= "0 -" . $y_to . " rlineto \n"; - $this->stringCommands .= "closepath \n"; - $this->stringCommands .= "stroke \n"; - } - - /** - * Set the current point - * - * The moveto operator takes two numbers off the stack and treats - * them as x and y coordinates to which to move. The coordinates - * specified become the current point. - * - * @param integer $x The x attribute defines the left position of the element - * @param integer $y The y attribute defines the right position of the element - * - * @return void - */ - public function moveTo($x, $y) - { - $this->stringCommands .= $x . ' ' . $y . " moveto \n"; - } - - /** - * Output/Display the text - * - * @param string $text The string to be displayed - * - * @return void - */ - public function show($text) - { - $this->stringCommands .= '(' . $text . ") show \n"; - } - - /** - * Output the text at specified co-ordinates - * - * @param string $text String to be displayed - * @param integer $x X attribute defines the left position of the element - * @param integer $y Y attribute defines the right position of the element - * - * @return void - */ - public function showXY($text, $x, $y) - { - $this->moveTo($x, $y); - $this->show($text); - } - - /** - * Ends EPS Document - * - * @return void - */ - public function endEpsDoc() - { - $this->stringCommands .= "showpage \n"; - } - - /** - * Output EPS Document for download - * - * @param string $fileName name of the eps document - * - * @return void - */ - public function showOutput($fileName) - { - // if(ob_get_clean()){ - //ob_end_clean(); - //} - $output = $this->stringCommands; - Response::getInstance() - ->disable(); - Core::downloadHeader( - $fileName, - 'image/x-eps', - strlen($output) - ); - print $output; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/EpsRelationSchema.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/EpsRelationSchema.php deleted file mode 100644 index 238af1b..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/EpsRelationSchema.php +++ /dev/null @@ -1,254 +0,0 @@ -setShowColor(isset($_REQUEST['eps_show_color'])); - $this->setShowKeys(isset($_REQUEST['eps_show_keys'])); - $this->setTableDimension(isset($_REQUEST['eps_show_table_dimension'])); - $this->setAllTablesSameWidth(isset($_REQUEST['eps_all_tables_same_width'])); - $this->setOrientation($_REQUEST['eps_orientation']); - - $this->diagram->setTitle( - sprintf( - __('Schema of the %s database - Page %s'), - $this->db, - $this->pageNumber - ) - ); - $this->diagram->setAuthor('phpMyAdmin ' . PMA_VERSION); - $this->diagram->setDate(date("j F Y, g:i a")); - $this->diagram->setOrientation($this->orientation); - $this->diagram->setFont('Verdana', '10'); - - $alltables = $this->getTablesFromRequest(); - - foreach ($alltables as $table) { - if (! isset($this->_tables[$table])) { - $this->_tables[$table] = new TableStatsEps( - $this->diagram, - $this->db, - $table, - $this->diagram->getFont(), - $this->diagram->getFontSize(), - $this->pageNumber, - $this->_tablewidth, - $this->showKeys, - $this->tableDimension, - $this->offline - ); - } - - if ($this->sameWide) { - $this->_tables[$table]->width = $this->_tablewidth; - } - } - - $seen_a_relation = false; - foreach ($alltables as $one_table) { - $exist_rel = $this->relation->getForeigners($this->db, $one_table, '', 'both'); - if (! $exist_rel) { - continue; - } - - $seen_a_relation = true; - foreach ($exist_rel as $master_field => $rel) { - /* put the foreign table on the schema only if selected - * by the user - * (do not use array_search() because we would have to - * to do a === false and this is not PHP3 compatible) - */ - if ($master_field != 'foreign_keys_data') { - if (in_array($rel['foreign_table'], $alltables)) { - $this->_addRelation( - $one_table, - $this->diagram->getFont(), - $this->diagram->getFontSize(), - $master_field, - $rel['foreign_table'], - $rel['foreign_field'], - $this->tableDimension - ); - } - continue; - } - - foreach ($rel as $one_key) { - if (! in_array($one_key['ref_table_name'], $alltables)) { - continue; - } - - foreach ($one_key['index_list'] as $index => $one_field) { - $this->_addRelation( - $one_table, - $this->diagram->getFont(), - $this->diagram->getFontSize(), - $one_field, - $one_key['ref_table_name'], - $one_key['ref_index_list'][$index], - $this->tableDimension - ); - } - } - } - } - if ($seen_a_relation) { - $this->_drawRelations(); - } - - $this->_drawTables(); - $this->diagram->endEpsDoc(); - } - - /** - * Output Eps Document for download - * - * @return void - */ - public function showOutput() - { - $this->diagram->showOutput($this->getFileName('.eps')); - } - - /** - * Defines relation objects - * - * @param string $masterTable The master table name - * @param string $font The font - * @param int $fontSize The font size - * @param string $masterField The relation field in the master table - * @param string $foreignTable The foreign table name - * @param string $foreignField The relation field in the foreign table - * @param boolean $tableDimension Whether to display table position or not - * - * @return void - * - * @see _setMinMax,Table_Stats_Eps::__construct(), - * PhpMyAdmin\Plugins\Schema\Eps\RelationStatsEps::__construct() - */ - private function _addRelation( - $masterTable, - $font, - $fontSize, - $masterField, - $foreignTable, - $foreignField, - $tableDimension - ) { - if (! isset($this->_tables[$masterTable])) { - $this->_tables[$masterTable] = new TableStatsEps( - $this->diagram, - $this->db, - $masterTable, - $font, - $fontSize, - $this->pageNumber, - $this->_tablewidth, - false, - $tableDimension - ); - } - if (! isset($this->_tables[$foreignTable])) { - $this->_tables[$foreignTable] = new TableStatsEps( - $this->diagram, - $this->db, - $foreignTable, - $font, - $fontSize, - $this->pageNumber, - $this->_tablewidth, - false, - $tableDimension - ); - } - $this->_relations[] = new RelationStatsEps( - $this->diagram, - $this->_tables[$masterTable], - $masterField, - $this->_tables[$foreignTable], - $foreignField - ); - } - - /** - * Draws relation arrows and lines connects master table's master field to - * foreign table's foreign field - * - * @return void - * - * @see Relation_Stats_Eps::relationDraw() - */ - private function _drawRelations() - { - foreach ($this->_relations as $relation) { - $relation->relationDraw(); - } - } - - /** - * Draws tables - * - * @return void - * - * @see Table_Stats_Eps::Table_Stats_tableDraw() - */ - private function _drawTables() - { - foreach ($this->_tables as $table) { - $table->tableDraw($this->showColor); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/RelationStatsEps.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/RelationStatsEps.php deleted file mode 100644 index 4c50131..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/RelationStatsEps.php +++ /dev/null @@ -1,120 +0,0 @@ -wTick = 10; - parent::__construct( - $diagram, - $master_table, - $master_field, - $foreign_table, - $foreign_field - ); - $this->ySrc += 10; - $this->yDest += 10; - } - - /** - * draws relation links and arrows - * shows foreign key relations - * - * @see PMA_EPS - * - * @return void - */ - public function relationDraw() - { - // draw a line like -- to foreign field - $this->diagram->line( - $this->xSrc, - $this->ySrc, - $this->xSrc + $this->srcDir * $this->wTick, - $this->ySrc, - 1 - ); - // draw a line like -- to master field - $this->diagram->line( - $this->xDest + $this->destDir * $this->wTick, - $this->yDest, - $this->xDest, - $this->yDest, - 1 - ); - // draw a line that connects to master field line and foreign field line - $this->diagram->line( - $this->xSrc + $this->srcDir * $this->wTick, - $this->ySrc, - $this->xDest + $this->destDir * $this->wTick, - $this->yDest, - 1 - ); - $root2 = 2 * sqrt(2); - $this->diagram->line( - $this->xSrc + $this->srcDir * $this->wTick * 0.75, - $this->ySrc, - $this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick, - $this->ySrc + $this->wTick / $root2, - 1 - ); - $this->diagram->line( - $this->xSrc + $this->srcDir * $this->wTick * 0.75, - $this->ySrc, - $this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick, - $this->ySrc - $this->wTick / $root2, - 1 - ); - $this->diagram->line( - $this->xDest + $this->destDir * $this->wTick / 2, - $this->yDest, - $this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick, - $this->yDest + $this->wTick / $root2, - 1 - ); - $this->diagram->line( - $this->xDest + $this->destDir * $this->wTick / 2, - $this->yDest, - $this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick, - $this->yDest - $this->wTick / $root2, - 1 - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/TableStatsEps.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/TableStatsEps.php deleted file mode 100644 index 904d96a..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/TableStatsEps.php +++ /dev/null @@ -1,183 +0,0 @@ -_setHeightTable($fontSize); - // setWidth must me after setHeight, because title - // can include table height which changes table width - $this->_setWidthTable($font, $fontSize); - if ($same_wide_width < $this->width) { - $same_wide_width = $this->width; - } - } - - /** - * Displays an error when the table cannot be found. - * - * @return void - */ - protected function showMissingTableError() - { - ExportRelationSchema::dieSchema( - $this->pageNumber, - "EPS", - sprintf(__('The %s table doesn\'t exist!'), $this->tableName) - ); - } - - /** - * Sets the width of the table - * - * @param string $font The font name - * @param integer $fontSize The font size - * - * @return void - * - * @see PMA_EPS - */ - private function _setWidthTable($font, $fontSize) - { - foreach ($this->fields as $field) { - $this->width = max( - $this->width, - $this->font->getStringWidth($field, $font, (int) $fontSize) - ); - } - $this->width += $this->font->getStringWidth( - ' ', - $font, - (int) $fontSize - ); - /* - * it is unknown what value must be added, because - * table title is affected by the table width value - */ - while ($this->width - < $this->font->getStringWidth( - $this->getTitle(), - $font, - (int) $fontSize - )) { - $this->width += 7; - } - } - - /** - * Sets the height of the table - * - * @param integer $fontSize The font size - * - * @return void - */ - private function _setHeightTable($fontSize) - { - $this->heightCell = $fontSize + 4; - $this->height = (count($this->fields) + 1) * $this->heightCell; - } - - /** - * Draw the table - * - * @param boolean $showColor Whether to display color - * - * @return void - * - * @see PMA_EPS,PMA_EPS::line,PMA_EPS::rect - */ - public function tableDraw($showColor) - { - $this->diagram->rect( - $this->x, - $this->y + 12, - $this->width, - $this->heightCell, - 1 - ); - $this->diagram->showXY($this->getTitle(), $this->x + 5, $this->y + 14); - foreach ($this->fields as $field) { - $this->currentCell += $this->heightCell; - $this->diagram->rect( - $this->x, - $this->y + 12 + $this->currentCell, - $this->width, - $this->heightCell, - 1 - ); - $this->diagram->showXY( - $field, - $this->x + 5, - $this->y + 14 + $this->currentCell - ); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/ExportRelationSchema.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/ExportRelationSchema.php deleted file mode 100644 index c5209c4..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/ExportRelationSchema.php +++ /dev/null @@ -1,310 +0,0 @@ -db = $db; - $this->diagram = $diagram; - $this->setPageNumber($_REQUEST['page_number']); - $this->setOffline(isset($_REQUEST['offline_export'])); - $this->relation = new Relation($GLOBALS['dbi']); - } - - /** - * Set Page Number - * - * @param integer $value Page Number of the document to be created - * - * @return void - */ - public function setPageNumber($value) - { - $this->pageNumber = intval($value); - } - - /** - * Returns the schema page number - * - * @return integer schema page number - */ - public function getPageNumber() - { - return $this->pageNumber; - } - - /** - * Sets showColor - * - * @param boolean $value whether to show colors - * - * @return void - */ - public function setShowColor($value) - { - $this->showColor = $value; - } - - /** - * Returns whether to show colors - * - * @return boolean whether to show colors - */ - public function isShowColor() - { - return $this->showColor; - } - - /** - * Set Table Dimension - * - * @param boolean $value show table co-ordinates or not - * - * @return void - */ - public function setTableDimension($value) - { - $this->tableDimension = $value; - } - - /** - * Returns whether to show table dimensions - * - * @return boolean whether to show table dimensions - */ - public function isTableDimension() - { - return $this->tableDimension; - } - - /** - * Set same width of All Tables - * - * @param boolean $value set same width of all tables or not - * - * @return void - */ - public function setAllTablesSameWidth($value) - { - $this->sameWide = $value; - } - - /** - * Returns whether to use same width for all tables or not - * - * @return boolean whether to use same width for all tables or not - */ - public function isAllTableSameWidth() - { - return $this->sameWide; - } - - /** - * Set Show only keys - * - * @param boolean $value show only keys or not - * - * @return void - * - * @access public - */ - public function setShowKeys($value) - { - $this->showKeys = $value; - } - - /** - * Returns whether to show keys - * - * @return boolean whether to show keys - */ - public function isShowKeys() - { - return $this->showKeys; - } - - /** - * Set Orientation - * - * @param string $value Orientation will be portrait or landscape - * - * @return void - * - * @access public - */ - public function setOrientation($value) - { - $this->orientation = $value == 'P' ? 'P' : 'L'; - } - - /** - * Returns orientation - * - * @return string orientation - */ - public function getOrientation() - { - return $this->orientation; - } - - /** - * Set type of paper - * - * @param string $value paper type can be A4 etc - * - * @return void - * - * @access public - */ - public function setPaper($value) - { - $this->paper = $value; - } - - /** - * Returns the paper size - * - * @return string paper size - */ - public function getPaper() - { - return $this->paper; - } - - /** - * Set whether the document is generated from client side DB - * - * @param boolean $value offline or not - * - * @return void - * - * @access public - */ - public function setOffline($value) - { - $this->offline = $value; - } - - /** - * Returns whether the client side database is used - * - * @return boolean - * - * @access public - */ - public function isOffline() - { - return $this->offline; - } - - /** - * Get the table names from the request - * - * @return array an array of table names - */ - protected function getTablesFromRequest() - { - $tables = []; - if (isset($_POST['t_tbl'])) { - foreach ($_POST['t_tbl'] as $table) { - $tables[] = rawurldecode($table); - } - } - return $tables; - } - - /** - * Returns the file name - * - * @param String $extension file extension - * - * @return string file name - */ - protected function getFileName($extension) - { - $filename = $this->db . $extension; - // Get the name of this page to use as filename - if ($this->pageNumber != -1 && ! $this->offline) { - $_name_sql = 'SELECT page_descr FROM ' - . Util::backquote($GLOBALS['cfgRelation']['db']) . '.' - . Util::backquote($GLOBALS['cfgRelation']['pdf_pages']) - . ' WHERE page_nr = ' . $this->pageNumber; - $_name_rs = $this->relation->queryAsControlUser($_name_sql); - $_name_row = $GLOBALS['dbi']->fetchRow($_name_rs); - $filename = $_name_row[0] . $extension; - } - - return $filename; - } - - /** - * Displays an error message - * - * @param integer $pageNumber ID of the chosen page - * @param string $type Schema Type - * @param string $error_message The error message - * - * @access public - * - * @return void - */ - public static function dieSchema($pageNumber, $type = '', $error_message = '') - { - echo "

    " , __("SCHEMA ERROR: ") , $type , "

    " , "\n"; - if (! empty($error_message)) { - $error_message = htmlspecialchars($error_message); - } - echo '

    ' , "\n"; - echo ' ' , $error_message , "\n"; - echo '

    ' , "\n"; - echo '' , __('Back') , ''; - echo "\n"; - exit; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/Pdf.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/Pdf.php deleted file mode 100644 index e02a953..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/Pdf.php +++ /dev/null @@ -1,422 +0,0 @@ -_pageNumber = $pageNumber; - $this->_withDoc = $withDoc; - $this->_db = $db; - $this->relation = new Relation($GLOBALS['dbi']); - } - - /** - * Sets the value for margins - * - * @param float $c_margin margin - * - * @return void - */ - public function setCMargin($c_margin) - { - $this->cMargin = $c_margin; - } - - /** - * Sets the scaling factor, defines minimum coordinates and margins - * - * @param float|int $scale The scaling factor - * @param float|int $xMin The minimum X coordinate - * @param float|int $yMin The minimum Y coordinate - * @param float|int $leftMargin The left margin - * @param float|int $topMargin The top margin - * - * @return void - */ - public function setScale( - $scale = 1, - $xMin = 0, - $yMin = 0, - $leftMargin = -1, - $topMargin = -1 - ) { - $this->scale = $scale; - $this->_xMin = $xMin; - $this->_yMin = $yMin; - if ($this->leftMargin != -1) { - $this->leftMargin = $leftMargin; - } - if ($this->topMargin != -1) { - $this->topMargin = $topMargin; - } - } - - /** - * Outputs a scaled cell - * - * @param float|int $w The cell width - * @param float|int $h The cell height - * @param string $txt The text to output - * @param mixed $border Whether to add borders or not - * @param integer $ln Where to put the cursor once the output is done - * @param string $align Align mode - * @param integer $fill Whether to fill the cell with a color or not - * @param string $link Link - * - * @return void - * - * @see TCPDF::Cell() - */ - public function cellScale( - $w, - $h = 0, - $txt = '', - $border = 0, - $ln = 0, - $align = '', - $fill = 0, - $link = '' - ) { - $h /= $this->scale; - $w /= $this->scale; - $this->Cell($w, $h, $txt, $border, $ln, $align, $fill, $link); - } - - /** - * Draws a scaled line - * - * @param float $x1 The horizontal position of the starting point - * @param float $y1 The vertical position of the starting point - * @param float $x2 The horizontal position of the ending point - * @param float $y2 The vertical position of the ending point - * - * @return void - * - * @see TCPDF::Line() - */ - public function lineScale($x1, $y1, $x2, $y2) - { - $x1 = ($x1 - $this->_xMin) / $this->scale + $this->leftMargin; - $y1 = ($y1 - $this->_yMin) / $this->scale + $this->topMargin; - $x2 = ($x2 - $this->_xMin) / $this->scale + $this->leftMargin; - $y2 = ($y2 - $this->_yMin) / $this->scale + $this->topMargin; - $this->Line($x1, $y1, $x2, $y2); - } - - /** - * Sets x and y scaled positions - * - * @param float $x The x position - * @param float $y The y position - * - * @return void - * - * @see TCPDF::SetXY() - */ - public function setXyScale($x, $y) - { - $x = ($x - $this->_xMin) / $this->scale + $this->leftMargin; - $y = ($y - $this->_yMin) / $this->scale + $this->topMargin; - $this->SetXY($x, $y); - } - - /** - * Sets the X scaled positions - * - * @param float $x The x position - * - * @return void - * - * @see TCPDF::SetX() - */ - public function setXScale($x) - { - $x = ($x - $this->_xMin) / $this->scale + $this->leftMargin; - $this->SetX($x); - } - - /** - * Sets the scaled font size - * - * @param float $size The font size (in points) - * - * @return void - * - * @see TCPDF::SetFontSize() - */ - public function setFontSizeScale($size) - { - // Set font size in points - $size /= $this->scale; - $this->SetFontSize($size); - } - - /** - * Sets the scaled line width - * - * @param float $width The line width - * - * @return void - * - * @see TCPDF::SetLineWidth() - */ - public function setLineWidthScale($width) - { - $width /= $this->scale; - $this->SetLineWidth($width); - } - - /** - * This method is used to render the page header. - * - * @return void - * - * @see TCPDF::Header() - */ - // @codingStandardsIgnoreLine - public function Header() - { - // We only show this if we find something in the new pdf_pages table - - // This function must be named "Header" to work with the TCPDF library - if ($this->_withDoc) { - if ($this->_offline || $this->_pageNumber == -1) { - $pg_name = __("PDF export page"); - } else { - $test_query = 'SELECT * FROM ' - . Util::backquote($GLOBALS['cfgRelation']['db']) . '.' - . Util::backquote($GLOBALS['cfgRelation']['pdf_pages']) - . ' WHERE db_name = \'' . $GLOBALS['dbi']->escapeString($this->_db) - . '\' AND page_nr = \'' . $this->_pageNumber . '\''; - $test_rs = $this->relation->queryAsControlUser($test_query); - $pages = @$GLOBALS['dbi']->fetchAssoc($test_rs); - $pg_name = ucfirst($pages['page_descr']); - } - - $this->SetFont($this->_ff, 'B', 14); - $this->Cell(0, 6, $pg_name, 'B', 1, 'C'); - $this->SetFont($this->_ff, ''); - $this->Ln(); - } - } - - /** - * This function must be named "Footer" to work with the TCPDF library - * - * @return void - * - * @see PDF::Footer() - */ - // @codingStandardsIgnoreLine - public function Footer() - { - if ($this->_withDoc) { - parent::Footer(); - } - } - - /** - * Sets widths - * - * @param array $w array of widths - * - * @return void - */ - public function setWidths(array $w) - { - // column widths - $this->widths = $w; - } - - /** - * Generates table row. - * - * @param array $data Data for table - * @param array $links Links for table cells - * - * @return void - */ - public function row(array $data, array $links) - { - // line height - $nb = 0; - $data_cnt = count($data); - for ($i = 0; $i < $data_cnt; $i++) { - $nb = max($nb, $this->numLines($this->widths[$i], $data[$i])); - } - $il = $this->FontSize; - $h = ($il + 1) * $nb; - // page break if necessary - $this->checkPageBreak($h); - // draw the cells - $data_cnt = count($data); - for ($i = 0; $i < $data_cnt; $i++) { - $w = $this->widths[$i]; - // save current position - $x = $this->GetX(); - $y = $this->GetY(); - // draw the border - $this->Rect($x, $y, $w, $h); - if (isset($links[$i])) { - $this->Link($x, $y, $w, $h, $links[$i]); - } - // print text - $this->MultiCell($w, $il + 1, $data[$i], 0, 'L'); - // go to right side - $this->SetXY($x + $w, $y); - } - // go to line - $this->Ln($h); - } - - /** - * Compute number of lines used by a multicell of width w - * - * @param int $w width - * @param string $txt text - * - * @return int - */ - public function numLines($w, $txt) - { - $cw = &$this->CurrentFont['cw']; - if ($w == 0) { - $w = $this->w - $this->rMargin - $this->x; - } - $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize; - $s = str_replace("\r", '', $txt); - $nb = strlen($s); - if ($nb > 0 && $s[$nb - 1] == "\n") { - $nb--; - } - $sep = -1; - $i = 0; - $j = 0; - $l = 0; - $nl = 1; - while ($i < $nb) { - $c = $s[$i]; - if ($c == "\n") { - $i++; - $sep = -1; - $j = $i; - $l = 0; - $nl++; - continue; - } - if ($c == ' ') { - $sep = $i; - } - $l += isset($cw[mb_ord($c)]) ? $cw[mb_ord($c)] : 0 ; - if ($l > $wmax) { - if ($sep == -1) { - if ($i == $j) { - $i++; - } - } else { - $i = $sep + 1; - } - $sep = -1; - $j = $i; - $l = 0; - $nl++; - } else { - $i++; - } - } - return $nl; - } - - /** - * Set whether the document is generated from client side DB - * - * @param string $value whether offline - * - * @return void - * - * @access private - */ - public function setOffline($value) - { - $this->_offline = $value; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php deleted file mode 100644 index fa67885..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php +++ /dev/null @@ -1,798 +0,0 @@ -transformations = new Transformations(); - - $this->setShowGrid(isset($_REQUEST['pdf_show_grid'])); - $this->setShowColor(isset($_REQUEST['pdf_show_color'])); - $this->setShowKeys(isset($_REQUEST['pdf_show_keys'])); - $this->setTableDimension(isset($_REQUEST['pdf_show_table_dimension'])); - $this->setAllTablesSameWidth(isset($_REQUEST['pdf_all_tables_same_width'])); - $this->setWithDataDictionary(isset($_REQUEST['pdf_with_doc'])); - $this->setTableOrder($_REQUEST['pdf_table_order']); - $this->setOrientation($_REQUEST['pdf_orientation']); - $this->setPaper($_REQUEST['pdf_paper']); - - // Initializes a new document - parent::__construct( - $db, - new Pdf( - $this->orientation, - 'mm', - $this->paper, - $this->pageNumber, - $this->_withDoc, - $db - ) - ); - $this->diagram->SetTitle( - sprintf( - __('Schema of the %s database'), - $this->db - ) - ); - $this->diagram->setCMargin(0); - $this->diagram->Open(); - $this->diagram->SetAutoPageBreak('auto'); - $this->diagram->setOffline($this->offline); - - $alltables = $this->getTablesFromRequest(); - if ($this->getTableOrder() == 'name_asc') { - sort($alltables); - } elseif ($this->getTableOrder() == 'name_desc') { - rsort($alltables); - } - - if ($this->_withDoc) { - $this->diagram->SetAutoPageBreak('auto', 15); - $this->diagram->setCMargin(1); - $this->dataDictionaryDoc($alltables); - $this->diagram->SetAutoPageBreak('auto'); - $this->diagram->setCMargin(0); - } - - $this->diagram->AddPage(); - - if ($this->_withDoc) { - $this->diagram->SetLink($this->diagram->PMA_links['RT']['-'], -1); - $this->diagram->Bookmark(__('Relational schema')); - $this->diagram->setAlias('{00}', $this->diagram->PageNo()); - $this->_topMargin = 28; - $this->_bottomMargin = 28; - } - - /* snip */ - foreach ($alltables as $table) { - if (! isset($this->_tables[$table])) { - $this->_tables[$table] = new TableStatsPdf( - $this->diagram, - $this->db, - $table, - null, - $this->pageNumber, - $this->_tablewidth, - $this->showKeys, - $this->tableDimension, - $this->offline - ); - } - if ($this->sameWide) { - $this->_tables[$table]->width = $this->_tablewidth; - } - $this->_setMinMax($this->_tables[$table]); - } - - // Defines the scale factor - $innerWidth = $this->diagram->getPageWidth() - $this->_rightMargin - - $this->_leftMargin; - $innerHeight = $this->diagram->getPageHeight() - $this->_topMargin - - $this->_bottomMargin; - $this->_scale = ceil( - max( - ($this->_xMax - $this->_xMin) / $innerWidth, - ($this->_yMax - $this->_yMin) / $innerHeight - ) * 100 - ) / 100; - - $this->diagram->setScale( - $this->_scale, - $this->_xMin, - $this->_yMin, - $this->_leftMargin, - $this->_topMargin - ); - // Builds and save the PDF document - $this->diagram->setLineWidthScale(0.1); - - if ($this->_showGrid) { - $this->diagram->SetFontSize(10); - $this->_strokeGrid(); - } - $this->diagram->setFontSizeScale(14); - // previous logic was checking master tables and foreign tables - // but I think that looping on every table of the pdf page as a master - // and finding its foreigns is OK (then we can support innodb) - $seen_a_relation = false; - foreach ($alltables as $one_table) { - $exist_rel = $this->relation->getForeigners($this->db, $one_table, '', 'both'); - if (! $exist_rel) { - continue; - } - - $seen_a_relation = true; - foreach ($exist_rel as $master_field => $rel) { - // put the foreign table on the schema only if selected - // by the user - // (do not use array_search() because we would have to - // to do a === false and this is not PHP3 compatible) - if ($master_field != 'foreign_keys_data') { - if (in_array($rel['foreign_table'], $alltables)) { - $this->_addRelation( - $one_table, - $master_field, - $rel['foreign_table'], - $rel['foreign_field'] - ); - } - continue; - } - - foreach ($rel as $one_key) { - if (! in_array($one_key['ref_table_name'], $alltables)) { - continue; - } - - foreach ($one_key['index_list'] as $index => $one_field) { - $this->_addRelation( - $one_table, - $one_field, - $one_key['ref_table_name'], - $one_key['ref_index_list'][$index] - ); - } - } - } // end while - } // end while - - if ($seen_a_relation) { - $this->_drawRelations(); - } - $this->_drawTables(); - } - - /** - * Set Show Grid - * - * @param boolean $value show grid of the document or not - * - * @return void - */ - public function setShowGrid($value) - { - $this->_showGrid = $value; - } - - /** - * Returns whether to show grid - * - * @return boolean whether to show grid - */ - public function isShowGrid() - { - return $this->_showGrid; - } - - /** - * Set Data Dictionary - * - * @param boolean $value show selected database data dictionary or not - * - * @return void - */ - public function setWithDataDictionary($value) - { - $this->_withDoc = $value; - } - - /** - * Return whether to show selected database data dictionary or not - * - * @return boolean whether to show selected database data dictionary or not - */ - public function isWithDataDictionary() - { - return $this->_withDoc; - } - - /** - * Sets the order of the table in data dictionary - * - * @param string $value table order - * - * @return void - */ - public function setTableOrder($value) - { - $this->_tableOrder = $value; - } - - /** - * Returns the order of the table in data dictionary - * - * @return string table order - */ - public function getTableOrder() - { - return $this->_tableOrder; - } - - /** - * Output Pdf Document for download - * - * @return void - */ - public function showOutput() - { - $this->diagram->download($this->getFileName('.pdf')); - } - - /** - * Sets X and Y minimum and maximum for a table cell - * - * @param TableStatsPdf $table The table name of which sets XY co-ordinates - * - * @return void - */ - private function _setMinMax($table) - { - $this->_xMax = max($this->_xMax, $table->x + $table->width); - $this->_yMax = max($this->_yMax, $table->y + $table->height); - $this->_xMin = min($this->_xMin, $table->x); - $this->_yMin = min($this->_yMin, $table->y); - } - - /** - * Defines relation objects - * - * @param string $masterTable The master table name - * @param string $masterField The relation field in the master table - * @param string $foreignTable The foreign table name - * @param string $foreignField The relation field in the foreign table - * - * @return void - * - * @see _setMinMax - */ - private function _addRelation( - $masterTable, - $masterField, - $foreignTable, - $foreignField - ) { - if (! isset($this->_tables[$masterTable])) { - $this->_tables[$masterTable] = new TableStatsPdf( - $this->diagram, - $this->db, - $masterTable, - null, - $this->pageNumber, - $this->_tablewidth, - $this->showKeys, - $this->tableDimension - ); - $this->_setMinMax($this->_tables[$masterTable]); - } - if (! isset($this->_tables[$foreignTable])) { - $this->_tables[$foreignTable] = new TableStatsPdf( - $this->diagram, - $this->db, - $foreignTable, - null, - $this->pageNumber, - $this->_tablewidth, - $this->showKeys, - $this->tableDimension - ); - $this->_setMinMax($this->_tables[$foreignTable]); - } - $this->relations[] = new RelationStatsPdf( - $this->diagram, - $this->_tables[$masterTable], - $masterField, - $this->_tables[$foreignTable], - $foreignField - ); - } - - /** - * Draws the grid - * - * @return void - * - * @see PMA_Schema_PDF - */ - private function _strokeGrid() - { - $gridSize = 10; - $labelHeight = 4; - $labelWidth = 5; - if ($this->_withDoc) { - $topSpace = 6; - $bottomSpace = 15; - } else { - $topSpace = 0; - $bottomSpace = 0; - } - - $this->diagram->SetMargins(0, 0); - $this->diagram->SetDrawColor(200, 200, 200); - // Draws horizontal lines - $innerHeight = $this->diagram->getPageHeight() - $topSpace - $bottomSpace; - for ($l = 0, $size = intval($innerHeight / $gridSize); $l <= $size; $l++) { - $this->diagram->line( - 0, - $l * $gridSize + $topSpace, - $this->diagram->getPageWidth(), - $l * $gridSize + $topSpace - ); - // Avoid duplicates - if ($l > 0 - && $l <= intval(($innerHeight - $labelHeight) / $gridSize) - ) { - $this->diagram->SetXY(0, $l * $gridSize + $topSpace); - $label = (string) sprintf( - '%.0f', - ($l * $gridSize + $topSpace - $this->_topMargin) - * $this->_scale + $this->_yMin - ); - $this->diagram->Cell($labelWidth, $labelHeight, ' ' . $label); - } // end if - } // end for - // Draws vertical lines - for ($j = 0, $size = intval($this->diagram->getPageWidth() / $gridSize); $j <= $size; $j++) { - $this->diagram->line( - $j * $gridSize, - $topSpace, - $j * $gridSize, - $this->diagram->getPageHeight() - $bottomSpace - ); - $this->diagram->SetXY($j * $gridSize, $topSpace); - $label = (string) sprintf( - '%.0f', - ($j * $gridSize - $this->_leftMargin) * $this->_scale + $this->_xMin - ); - $this->diagram->Cell($labelWidth, $labelHeight, $label); - } - } - - /** - * Draws relation arrows - * - * @return void - * - * @see Relation_Stats_Pdf::relationdraw() - */ - private function _drawRelations() - { - $i = 0; - foreach ($this->relations as $relation) { - $relation->relationDraw($this->showColor, $i); - $i++; - } - } - - /** - * Draws tables - * - * @return void - * - * @see Table_Stats_Pdf::tableDraw() - */ - private function _drawTables() - { - foreach ($this->_tables as $table) { - $table->tableDraw(null, $this->_withDoc, $this->showColor); - } - } - - /** - * Generates data dictionary pages. - * - * @param array $alltables Tables to document. - * - * @return void - */ - public function dataDictionaryDoc(array $alltables) - { - // TOC - $this->diagram->AddPage($this->orientation); - $this->diagram->Cell(0, 9, __('Table of contents'), 1, 0, 'C'); - $this->diagram->Ln(15); - $i = 1; - foreach ($alltables as $table) { - $this->diagram->PMA_links['doc'][$table]['-'] - = $this->diagram->AddLink(); - $this->diagram->SetX(10); - // $this->diagram->Ln(1); - $this->diagram->Cell( - 0, - 6, - __('Page number:') . ' {' . sprintf("%02d", $i) . '}', - 0, - 0, - 'R', - 0, - $this->diagram->PMA_links['doc'][$table]['-'] - ); - $this->diagram->SetX(10); - $this->diagram->Cell( - 0, - 6, - $i . ' ' . $table, - 0, - 1, - 'L', - 0, - $this->diagram->PMA_links['doc'][$table]['-'] - ); - // $this->diagram->Ln(1); - $fields = $GLOBALS['dbi']->getColumns($this->db, $table); - foreach ($fields as $row) { - $this->diagram->SetX(20); - $field_name = $row['Field']; - $this->diagram->PMA_links['doc'][$table][$field_name] - = $this->diagram->AddLink(); - //$this->diagram->Cell( - // 0, 6, $field_name, 0, 1, - // 'L', 0, $this->diagram->PMA_links['doc'][$table][$field_name] - //); - } - $i++; - } - $this->diagram->PMA_links['RT']['-'] = $this->diagram->AddLink(); - $this->diagram->SetX(10); - $this->diagram->Cell( - 0, - 6, - __('Page number:') . ' {00}', - 0, - 0, - 'R', - 0, - $this->diagram->PMA_links['RT']['-'] - ); - $this->diagram->SetX(10); - $this->diagram->Cell( - 0, - 6, - $i . ' ' . __('Relational schema'), - 0, - 1, - 'L', - 0, - $this->diagram->PMA_links['RT']['-'] - ); - $z = 0; - foreach ($alltables as $table) { - $z++; - $this->diagram->SetAutoPageBreak(true, 15); - $this->diagram->AddPage($this->orientation); - $this->diagram->Bookmark($table); - $this->diagram->setAlias( - '{' . sprintf("%02d", $z) . '}', - $this->diagram->PageNo() - ); - $this->diagram->PMA_links['RT'][$table]['-'] - = $this->diagram->AddLink(); - $this->diagram->SetLink( - $this->diagram->PMA_links['doc'][$table]['-'], - -1 - ); - $this->diagram->SetFont($this->_ff, 'B', 18); - $this->diagram->Cell( - 0, - 8, - $z . ' ' . $table, - 1, - 1, - 'C', - 0, - $this->diagram->PMA_links['RT'][$table]['-'] - ); - $this->diagram->SetFont($this->_ff, '', 8); - $this->diagram->Ln(); - - $cfgRelation = $this->relation->getRelationsParam(); - $comments = $this->relation->getComments($this->db, $table); - if ($cfgRelation['mimework']) { - $mime_map = $this->transformations->getMime($this->db, $table, true); - } - - /** - * Gets table information - */ - $showtable = $GLOBALS['dbi']->getTable($this->db, $table) - ->getStatusInfo(); - $show_comment = isset($showtable['Comment']) - ? $showtable['Comment'] - : ''; - $create_time = isset($showtable['Create_time']) - ? Util::localisedDate( - strtotime($showtable['Create_time']) - ) - : ''; - $update_time = isset($showtable['Update_time']) - ? Util::localisedDate( - strtotime($showtable['Update_time']) - ) - : ''; - $check_time = isset($showtable['Check_time']) - ? Util::localisedDate( - strtotime($showtable['Check_time']) - ) - : ''; - - /** - * Gets fields properties - */ - $columns = $GLOBALS['dbi']->getColumns($this->db, $table); - - // Find which tables are related with the current one and write it in - // an array - $res_rel = $this->relation->getForeigners($this->db, $table); - - /** - * Displays the comments of the table if MySQL >= 3.23 - */ - - $break = false; - if (! empty($show_comment)) { - $this->diagram->Cell( - 0, - 3, - __('Table comments:') . ' ' . $show_comment, - 0, - 1 - ); - $break = true; - } - - if (! empty($create_time)) { - $this->diagram->Cell( - 0, - 3, - __('Creation:') . ' ' . $create_time, - 0, - 1 - ); - $break = true; - } - - if (! empty($update_time)) { - $this->diagram->Cell( - 0, - 3, - __('Last update:') . ' ' . $update_time, - 0, - 1 - ); - $break = true; - } - - if (! empty($check_time)) { - $this->diagram->Cell( - 0, - 3, - __('Last check:') . ' ' . $check_time, - 0, - 1 - ); - $break = true; - } - - if ($break == true) { - $this->diagram->Cell(0, 3, '', 0, 1); - $this->diagram->Ln(); - } - - $this->diagram->SetFont($this->_ff, 'B'); - if (isset($this->orientation) && $this->orientation == 'L') { - $this->diagram->Cell(25, 8, __('Column'), 1, 0, 'C'); - $this->diagram->Cell(20, 8, __('Type'), 1, 0, 'C'); - $this->diagram->Cell(20, 8, __('Attributes'), 1, 0, 'C'); - $this->diagram->Cell(10, 8, __('Null'), 1, 0, 'C'); - $this->diagram->Cell(20, 8, __('Default'), 1, 0, 'C'); - $this->diagram->Cell(25, 8, __('Extra'), 1, 0, 'C'); - $this->diagram->Cell(45, 8, __('Links to'), 1, 0, 'C'); - - if ($this->paper == 'A4') { - $comments_width = 67; - } else { - // this is really intended for 'letter' - /** - * @todo find optimal width for all formats - */ - $comments_width = 50; - } - $this->diagram->Cell($comments_width, 8, __('Comments'), 1, 0, 'C'); - $this->diagram->Cell(45, 8, 'MIME', 1, 1, 'C'); - $this->diagram->setWidths( - [ - 25, - 20, - 20, - 10, - 20, - 25, - 45, - $comments_width, - 45, - ] - ); - } else { - $this->diagram->Cell(20, 8, __('Column'), 1, 0, 'C'); - $this->diagram->Cell(20, 8, __('Type'), 1, 0, 'C'); - $this->diagram->Cell(20, 8, __('Attributes'), 1, 0, 'C'); - $this->diagram->Cell(10, 8, __('Null'), 1, 0, 'C'); - $this->diagram->Cell(15, 8, __('Default'), 1, 0, 'C'); - $this->diagram->Cell(15, 8, __('Extra'), 1, 0, 'C'); - $this->diagram->Cell(30, 8, __('Links to'), 1, 0, 'C'); - $this->diagram->Cell(30, 8, __('Comments'), 1, 0, 'C'); - $this->diagram->Cell(30, 8, 'MIME', 1, 1, 'C'); - $this->diagram->setWidths([20, 20, 20, 10, 15, 15, 30, 30, 30]); - } - $this->diagram->SetFont($this->_ff, ''); - - foreach ($columns as $row) { - $extracted_columnspec - = Util::extractColumnSpec($row['Type']); - $type = $extracted_columnspec['print_type']; - $attribute = $extracted_columnspec['attribute']; - if (! isset($row['Default'])) { - if ($row['Null'] != '' && $row['Null'] != 'NO') { - $row['Default'] = 'NULL'; - } - } - $field_name = $row['Field']; - // $this->diagram->Ln(); - $this->diagram->PMA_links['RT'][$table][$field_name] - = $this->diagram->AddLink(); - $this->diagram->Bookmark($field_name, 1, -1); - $this->diagram->SetLink( - $this->diagram->PMA_links['doc'][$table][$field_name], - -1 - ); - $foreigner = $this->relation->searchColumnInForeigners($res_rel, $field_name); - - $linksTo = ''; - if ($foreigner) { - $linksTo = '-> '; - if ($foreigner['foreign_db'] != $this->db) { - $linksTo .= $foreigner['foreign_db'] . '.'; - } - $linksTo .= $foreigner['foreign_table'] - . '.' . $foreigner['foreign_field']; - - if (isset($foreigner['on_update'])) { // not set for internal - $linksTo .= "\n" . 'ON UPDATE ' . $foreigner['on_update']; - $linksTo .= "\n" . 'ON DELETE ' . $foreigner['on_delete']; - } - } - - $diagram_row = [ - $field_name, - $type, - $attribute, - ($row['Null'] == '' || $row['Null'] == 'NO') - ? __('No') - : __('Yes'), - isset($row['Default']) ? $row['Default'] : '', - $row['Extra'], - $linksTo, - isset($comments[$field_name]) - ? $comments[$field_name] - : '', - isset($mime_map) && isset($mime_map[$field_name]) - ? str_replace('_', '/', $mime_map[$field_name]['mimetype']) - : '', - ]; - $links = []; - $links[0] = $this->diagram->PMA_links['RT'][$table][$field_name]; - if ($foreigner - && isset($this->diagram->PMA_links['doc'][$foreigner['foreign_table']][$foreigner['foreign_field']]) - ) { - $links[6] = $this->diagram->PMA_links['doc'][$foreigner['foreign_table']][$foreigner['foreign_field']]; - } else { - unset($links[6]); - } - $this->diagram->row($diagram_row, $links); - } // end foreach - $this->diagram->SetFont($this->_ff, '', 14); - } //end each - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/RelationStatsPdf.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/RelationStatsPdf.php deleted file mode 100644 index b422ce5..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/RelationStatsPdf.php +++ /dev/null @@ -1,163 +0,0 @@ -wTick = 5; - parent::__construct( - $diagram, - $master_table, - $master_field, - $foreign_table, - $foreign_field - ); - } - - /** - * draws relation links and arrows shows foreign key relations - * - * @param boolean $showColor Whether to use one color per relation or not - * @param integer $i The id of the link to draw - * - * @access public - * - * @return void - * - * @see Pdf - */ - public function relationDraw($showColor, $i) - { - if ($showColor) { - $d = $i % 6; - $j = ($i - $d) / 6; - $j %= 4; - $j++; - $case = [ - [ - 1, - 0, - 0, - ], - [ - 0, - 1, - 0, - ], - [ - 0, - 0, - 1, - ], - [ - 1, - 1, - 0, - ], - [ - 1, - 0, - 1, - ], - [ - 0, - 1, - 1, - ], - ]; - list ($a, $b, $c) = $case[$d]; - $e = (1 - ($j - 1) / 6); - $this->diagram->SetDrawColor($a * 255 * $e, $b * 255 * $e, $c * 255 * $e); - } else { - $this->diagram->SetDrawColor(0); - } - $this->diagram->setLineWidthScale(0.2); - $this->diagram->lineScale( - $this->xSrc, - $this->ySrc, - $this->xSrc + $this->srcDir * $this->wTick, - $this->ySrc - ); - $this->diagram->lineScale( - $this->xDest + $this->destDir * $this->wTick, - $this->yDest, - $this->xDest, - $this->yDest - ); - $this->diagram->setLineWidthScale(0.1); - $this->diagram->lineScale( - $this->xSrc + $this->srcDir * $this->wTick, - $this->ySrc, - $this->xDest + $this->destDir * $this->wTick, - $this->yDest - ); - /* - * Draws arrows -> - */ - $root2 = 2 * sqrt(2); - $this->diagram->lineScale( - $this->xSrc + $this->srcDir * $this->wTick * 0.75, - $this->ySrc, - $this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick, - $this->ySrc + $this->wTick / $root2 - ); - $this->diagram->lineScale( - $this->xSrc + $this->srcDir * $this->wTick * 0.75, - $this->ySrc, - $this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick, - $this->ySrc - $this->wTick / $root2 - ); - - $this->diagram->lineScale( - $this->xDest + $this->destDir * $this->wTick / 2, - $this->yDest, - $this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick, - $this->yDest + $this->wTick / $root2 - ); - $this->diagram->lineScale( - $this->xDest + $this->destDir * $this->wTick / 2, - $this->yDest, - $this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick, - $this->yDest - $this->wTick / $root2 - ); - $this->diagram->SetDrawColor(0); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/TableStatsPdf.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/TableStatsPdf.php deleted file mode 100644 index 999894c..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/TableStatsPdf.php +++ /dev/null @@ -1,233 +0,0 @@ -heightCell = 6; - $this->_setHeight(); - /* - * setWidth must me after setHeight, because title - * can include table height which changes table width - */ - $this->_setWidth($fontSize); - if ($sameWideWidth < $this->width) { - $sameWideWidth = $this->width; - } - } - - /** - * Displays an error when the table cannot be found. - * - * @return void - */ - protected function showMissingTableError() - { - ExportRelationSchema::dieSchema( - $this->pageNumber, - "PDF", - sprintf(__('The %s table doesn\'t exist!'), $this->tableName) - ); - } - - /** - * Returns title of the current table, - * title can have the dimensions of the table - * - * @return string - */ - protected function getTitle() - { - $ret = ''; - if ($this->tableDimension) { - $ret = sprintf('%.0fx%0.f', $this->width, $this->height); - } - - return $ret . ' ' . $this->tableName; - } - - /** - * Sets the width of the table - * - * @param integer $fontSize The font size - * - * @access private - * - * @return void - * - * @see PMA_Schema_PDF - */ - private function _setWidth($fontSize) - { - foreach ($this->fields as $field) { - $this->width = max($this->width, $this->diagram->GetStringWidth($field)); - } - $this->width += $this->diagram->GetStringWidth(' '); - $this->diagram->SetFont($this->_ff, 'B', $fontSize); - /* - * it is unknown what value must be added, because - * table title is affected by the table width value - */ - while ($this->width < $this->diagram->GetStringWidth($this->getTitle())) { - $this->width += 5; - } - $this->diagram->SetFont($this->_ff, '', $fontSize); - } - - /** - * Sets the height of the table - * - * @return void - * - * @access private - */ - private function _setHeight() - { - $this->height = (count($this->fields) + 1) * $this->heightCell; - } - - /** - * Do draw the table - * - * @param integer $fontSize The font size - * @param boolean $withDoc Whether to include links to documentation - * @param boolean|integer $setColor Whether to display color - * - * @access public - * - * @return void - * - * @see PMA_Schema_PDF - */ - public function tableDraw($fontSize, $withDoc, $setColor = 0) - { - $this->diagram->setXyScale($this->x, $this->y); - $this->diagram->SetFont($this->_ff, 'B', $fontSize); - if ($setColor) { - $this->diagram->SetTextColor(200); - $this->diagram->SetFillColor(0, 0, 128); - } - if ($withDoc) { - $this->diagram->SetLink( - $this->diagram->PMA_links['RT'][$this->tableName]['-'], - -1 - ); - } else { - $this->diagram->PMA_links['doc'][$this->tableName]['-'] = ''; - } - - $this->diagram->cellScale( - $this->width, - $this->heightCell, - $this->getTitle(), - 1, - 1, - 'C', - $setColor, - $this->diagram->PMA_links['doc'][$this->tableName]['-'] - ); - $this->diagram->setXScale($this->x); - $this->diagram->SetFont($this->_ff, '', $fontSize); - $this->diagram->SetTextColor(0); - $this->diagram->SetFillColor(255); - - foreach ($this->fields as $field) { - if ($setColor) { - if (in_array($field, $this->primary)) { - $this->diagram->SetFillColor(215, 121, 123); - } - if ($field == $this->displayfield) { - $this->diagram->SetFillColor(142, 159, 224); - } - } - if ($withDoc) { - $this->diagram->SetLink( - $this->diagram->PMA_links['RT'][$this->tableName][$field], - -1 - ); - } else { - $this->diagram->PMA_links['doc'][$this->tableName][$field] = ''; - } - - $this->diagram->cellScale( - $this->width, - $this->heightCell, - ' ' . $field, - 1, - 1, - 'L', - $setColor, - $this->diagram->PMA_links['doc'][$this->tableName][$field] - ); - $this->diagram->setXScale($this->x); - $this->diagram->SetFillColor(255); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/RelationStats.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/RelationStats.php deleted file mode 100644 index 848fbf4..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/RelationStats.php +++ /dev/null @@ -1,120 +0,0 @@ -diagram = $diagram; - - $src_pos = $this->_getXy($master_table, $master_field); - $dest_pos = $this->_getXy($foreign_table, $foreign_field); - /* - * [0] is x-left - * [1] is x-right - * [2] is y - */ - $src_left = $src_pos[0] - $this->wTick; - $src_right = $src_pos[1] + $this->wTick; - $dest_left = $dest_pos[0] - $this->wTick; - $dest_right = $dest_pos[1] + $this->wTick; - - $d1 = abs($src_left - $dest_left); - $d2 = abs($src_right - $dest_left); - $d3 = abs($src_left - $dest_right); - $d4 = abs($src_right - $dest_right); - $d = min($d1, $d2, $d3, $d4); - - if ($d == $d1) { - $this->xSrc = $src_pos[0]; - $this->srcDir = -1; - $this->xDest = $dest_pos[0]; - $this->destDir = -1; - } elseif ($d == $d2) { - $this->xSrc = $src_pos[1]; - $this->srcDir = 1; - $this->xDest = $dest_pos[0]; - $this->destDir = -1; - } elseif ($d == $d3) { - $this->xSrc = $src_pos[0]; - $this->srcDir = -1; - $this->xDest = $dest_pos[1]; - $this->destDir = 1; - } else { - $this->xSrc = $src_pos[1]; - $this->srcDir = 1; - $this->xDest = $dest_pos[1]; - $this->destDir = 1; - } - $this->ySrc = $src_pos[2]; - $this->yDest = $dest_pos[2]; - } - - /** - * Gets arrows coordinates - * - * @param TableStats $table The table - * @param string $column The relation column name - * - * @return array Arrows coordinates - * - * @access private - */ - private function _getXy($table, $column) - { - $pos = array_search($column, $table->fields); - - // x_left, x_right, y - return [ - $table->x, - $table->x + $table->width, - $table->y + ($pos + 1.5) * $table->heightCell, - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaDia.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaDia.php deleted file mode 100644 index 8c328d5..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaDia.php +++ /dev/null @@ -1,100 +0,0 @@ -setProperties(); - } - - /** - * Sets the schema export Dia properties - * - * @return void - */ - protected function setProperties() - { - $schemaPluginProperties = new SchemaPluginProperties(); - $schemaPluginProperties->setText('Dia'); - $schemaPluginProperties->setExtension('dia'); - $schemaPluginProperties->setMimeType('application/dia'); - - // create the root group that will be the options field for - // $schemaPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // specific options main group - $specificOptions = new OptionsPropertyMainGroup("general_opts"); - // add options common to all plugins - $this->addCommonOptions($specificOptions); - - $leaf = new SelectPropertyItem( - "orientation", - __('Orientation') - ); - $leaf->setValues( - [ - 'L' => __('Landscape'), - 'P' => __('Portrait'), - ] - ); - $specificOptions->addProperty($leaf); - - $leaf = new SelectPropertyItem( - "paper", - __('Paper size') - ); - $leaf->setValues($this->getPaperSizeArray()); - $specificOptions->addProperty($leaf); - - // add the main group to the root group - $exportSpecificOptions->addProperty($specificOptions); - - // set the options for the schema export plugin property item - $schemaPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $schemaPluginProperties; - } - - /** - * Exports the schema into DIA format. - * - * @param string $db database name - * - * @return bool Whether it succeeded - */ - public function exportSchema($db) - { - $export = new DiaRelationSchema($db); - $export->showOutput(); - return true; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaEps.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaEps.php deleted file mode 100644 index 4218376..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaEps.php +++ /dev/null @@ -1,101 +0,0 @@ -setProperties(); - } - - /** - * Sets the schema export EPS properties - * - * @return void - */ - protected function setProperties() - { - $schemaPluginProperties = new SchemaPluginProperties(); - $schemaPluginProperties->setText('EPS'); - $schemaPluginProperties->setExtension('eps'); - $schemaPluginProperties->setMimeType('application/eps'); - - // create the root group that will be the options field for - // $schemaPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // specific options main group - $specificOptions = new OptionsPropertyMainGroup("general_opts"); - // add options common to all plugins - $this->addCommonOptions($specificOptions); - - // create leaf items and add them to the group - $leaf = new BoolPropertyItem( - 'all_tables_same_width', - __('Same width for all tables') - ); - $specificOptions->addProperty($leaf); - - $leaf = new SelectPropertyItem( - "orientation", - __('Orientation') - ); - $leaf->setValues( - [ - 'L' => __('Landscape'), - 'P' => __('Portrait'), - ] - ); - $specificOptions->addProperty($leaf); - - // add the main group to the root group - $exportSpecificOptions->addProperty($specificOptions); - - // set the options for the schema export plugin property item - $schemaPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $schemaPluginProperties; - } - - /** - * Exports the schema into EPS format. - * - * @param string $db database name - * - * @return bool Whether it succeeded - */ - public function exportSchema($db) - { - $export = new EpsRelationSchema($db); - $export->showOutput(); - return true; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaPdf.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaPdf.php deleted file mode 100644 index c57fcee..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaPdf.php +++ /dev/null @@ -1,133 +0,0 @@ -setProperties(); - } - - /** - * Sets the schema export PDF properties - * - * @return void - */ - protected function setProperties() - { - $schemaPluginProperties = new SchemaPluginProperties(); - $schemaPluginProperties->setText('PDF'); - $schemaPluginProperties->setExtension('pdf'); - $schemaPluginProperties->setMimeType('application/pdf'); - - // create the root group that will be the options field for - // $schemaPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // specific options main group - $specificOptions = new OptionsPropertyMainGroup("general_opts"); - // add options common to all plugins - $this->addCommonOptions($specificOptions); - - // create leaf items and add them to the group - $leaf = new BoolPropertyItem( - 'all_tables_same_width', - __('Same width for all tables') - ); - $specificOptions->addProperty($leaf); - - $leaf = new SelectPropertyItem( - "orientation", - __('Orientation') - ); - $leaf->setValues( - [ - 'L' => __('Landscape'), - 'P' => __('Portrait'), - ] - ); - $specificOptions->addProperty($leaf); - - $leaf = new SelectPropertyItem( - "paper", - __('Paper size') - ); - $leaf->setValues($this->getPaperSizeArray()); - $specificOptions->addProperty($leaf); - - $leaf = new BoolPropertyItem( - 'show_grid', - __('Show grid') - ); - $specificOptions->addProperty($leaf); - - $leaf = new BoolPropertyItem( - 'with_doc', - __('Data dictionary') - ); - $specificOptions->addProperty($leaf); - - $leaf = new SelectPropertyItem( - "table_order", - __('Order of the tables') - ); - $leaf->setValues( - [ - '' => __('None'), - 'name_asc' => __('Name (Ascending)'), - 'name_desc' => __('Name (Descending)'), - ] - ); - $specificOptions->addProperty($leaf); - - // add the main group to the root group - $exportSpecificOptions->addProperty($specificOptions); - - // set the options for the schema export plugin property item - $schemaPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $schemaPluginProperties; - } - - /** - * Exports the schema into PDF format. - * - * @param string $db database name - * - * @return bool Whether it succeeded - */ - public function exportSchema($db) - { - $export = new PdfRelationSchema($db); - $export->showOutput(); - return true; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaSvg.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaSvg.php deleted file mode 100644 index 9466f64..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaSvg.php +++ /dev/null @@ -1,88 +0,0 @@ -setProperties(); - } - - /** - * Sets the schema export SVG properties - * - * @return void - */ - protected function setProperties() - { - $schemaPluginProperties = new SchemaPluginProperties(); - $schemaPluginProperties->setText('SVG'); - $schemaPluginProperties->setExtension('svg'); - $schemaPluginProperties->setMimeType('application/svg'); - - // create the root group that will be the options field for - // $schemaPluginProperties - // this will be shown as "Format specific options" - $exportSpecificOptions = new OptionsPropertyRootGroup( - "Format Specific Options" - ); - - // specific options main group - $specificOptions = new OptionsPropertyMainGroup("general_opts"); - // add options common to all plugins - $this->addCommonOptions($specificOptions); - - // create leaf items and add them to the group - $leaf = new BoolPropertyItem( - 'all_tables_same_width', - __('Same width for all tables') - ); - $specificOptions->addProperty($leaf); - - // add the main group to the root group - $exportSpecificOptions->addProperty($specificOptions); - - // set the options for the schema export plugin property item - $schemaPluginProperties->setOptions($exportSpecificOptions); - $this->properties = $schemaPluginProperties; - } - - /** - * Exports the schema into SVG format. - * - * @param string $db database name - * - * @return bool Whether it succeeded - */ - public function exportSchema($db) - { - $export = new SvgRelationSchema($db); - $export->showOutput(); - return true; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/RelationStatsSvg.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/RelationStatsSvg.php deleted file mode 100644 index 2e323fc..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/RelationStatsSvg.php +++ /dev/null @@ -1,140 +0,0 @@ -wTick = 10; - parent::__construct( - $diagram, - $master_table, - $master_field, - $foreign_table, - $foreign_field - ); - } - - /** - * draws relation links and arrows shows foreign key relations - * - * @param boolean $showColor Whether to use one color per relation or not - * - * @return void - * @access public - * - * @see PMA_SVG - */ - public function relationDraw($showColor) - { - if ($showColor) { - $listOfColors = [ - '#c00', - '#bbb', - '#333', - '#cb0', - '#0b0', - '#0bf', - '#b0b', - ]; - shuffle($listOfColors); - $color = $listOfColors[0]; - } else { - $color = '#333'; - } - - $this->diagram->printElementLine( - 'line', - $this->xSrc, - $this->ySrc, - $this->xSrc + $this->srcDir * $this->wTick, - $this->ySrc, - 'stroke:' . $color . ';stroke-width:1;' - ); - $this->diagram->printElementLine( - 'line', - $this->xDest + $this->destDir * $this->wTick, - $this->yDest, - $this->xDest, - $this->yDest, - 'stroke:' . $color . ';stroke-width:1;' - ); - $this->diagram->printElementLine( - 'line', - $this->xSrc + $this->srcDir * $this->wTick, - $this->ySrc, - $this->xDest + $this->destDir * $this->wTick, - $this->yDest, - 'stroke:' . $color . ';stroke-width:1;' - ); - $root2 = 2 * sqrt(2); - $this->diagram->printElementLine( - 'line', - $this->xSrc + $this->srcDir * $this->wTick * 0.75, - $this->ySrc, - $this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick, - $this->ySrc + $this->wTick / $root2, - 'stroke:' . $color . ';stroke-width:2;' - ); - $this->diagram->printElementLine( - 'line', - $this->xSrc + $this->srcDir * $this->wTick * 0.75, - $this->ySrc, - $this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick, - $this->ySrc - $this->wTick / $root2, - 'stroke:' . $color . ';stroke-width:2;' - ); - $this->diagram->printElementLine( - 'line', - $this->xDest + $this->destDir * $this->wTick / 2, - $this->yDest, - $this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick, - $this->yDest + $this->wTick / $root2, - 'stroke:' . $color . ';stroke-width:2;' - ); - $this->diagram->printElementLine( - 'line', - $this->xDest + $this->destDir * $this->wTick / 2, - $this->yDest, - $this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick, - $this->yDest - $this->wTick / $root2, - 'stroke:' . $color . ';stroke-width:2;' - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/Svg.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/Svg.php deleted file mode 100644 index 4404574..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/Svg.php +++ /dev/null @@ -1,281 +0,0 @@ -openMemory(); - /* - * Set indenting using three spaces, - * so output is formatted - */ - - $this->setIndent(true); - $this->setIndentString(' '); - /* - * Create the XML document - */ - - $this->startDocument('1.0', 'UTF-8'); - $this->startDtd( - 'svg', - '-//W3C//DTD SVG 1.1//EN', - 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' - ); - $this->endDtd(); - } - - /** - * Set document title - * - * @param string $value sets the title text - * - * @return void - */ - public function setTitle($value) - { - $this->title = $value; - } - - /** - * Set document author - * - * @param string $value sets the author - * - * @return void - */ - public function setAuthor($value) - { - $this->author = $value; - } - - /** - * Set document font - * - * @param string $value sets the font e.g Arial, Sans-serif etc - * - * @return void - */ - public function setFont($value) - { - $this->font = $value; - } - - /** - * Get document font - * - * @return string returns the font name - */ - public function getFont() - { - return $this->font; - } - - /** - * Set document font size - * - * @param integer $value sets the font size in pixels - * - * @return void - */ - public function setFontSize($value) - { - $this->fontSize = $value; - } - - /** - * Get document font size - * - * @return integer returns the font size - */ - public function getFontSize() - { - return $this->fontSize; - } - - /** - * Starts RelationStatsSvg Document - * - * svg document starts by first initializing svg tag - * which contains all the attributes and namespace that needed - * to define the svg document - * - * @param integer $width total width of the RelationStatsSvg document - * @param integer $height total height of the RelationStatsSvg document - * @param integer $x min-x of the view box - * @param integer $y min-y of the view box - * - * @return void - * - * @see XMLWriter::startElement(),XMLWriter::writeAttribute() - */ - public function startSvgDoc($width, $height, $x = 0, $y = 0) - { - $this->startElement('svg'); - - if (! is_int($width)) { - $width = intval($width); - } - - if (! is_int($height)) { - $height = intval($height); - } - - if ($x != 0 || $y != 0) { - $this->writeAttribute('viewBox', "$x $y $width $height"); - } - $this->writeAttribute('width', ($width - $x) . 'px'); - $this->writeAttribute('height', ($height - $y) . 'px'); - $this->writeAttribute('xmlns', 'http://www.w3.org/2000/svg'); - $this->writeAttribute('version', '1.1'); - } - - /** - * Ends RelationStatsSvg Document - * - * @return void - * @see XMLWriter::endElement(),XMLWriter::endDocument() - */ - public function endSvgDoc() - { - $this->endElement(); - $this->endDocument(); - } - - /** - * output RelationStatsSvg Document - * - * svg document prompted to the user for download - * RelationStatsSvg document saved in .svg extension and can be - * easily changeable by using any svg IDE - * - * @param string $fileName file name - * - * @return void - * @see XMLWriter::startElement(),XMLWriter::writeAttribute() - */ - public function showOutput($fileName) - { - //ob_get_clean(); - $output = $this->flush(); - Response::getInstance()->disable(); - Core::downloadHeader( - $fileName, - 'image/svg+xml', - strlen($output) - ); - print $output; - } - - /** - * Draws RelationStatsSvg elements - * - * SVG has some predefined shape elements like rectangle & text - * and other elements who have x,y co-ordinates are drawn. - * specify their width and height and can give styles too. - * - * @param string $name RelationStatsSvg element name - * @param int $x The x attr defines the left position of the element - * (e.g. x="0" places the element 0 pixels from the - * left of the browser window) - * @param integer $y The y attribute defines the top position of the - * element (e.g. y="0" places the element 0 pixels - * from the top of the browser window) - * @param int|string $width The width attribute defines the width the element - * @param int|string $height The height attribute defines the height the element - * @param string|null $text The text attribute defines the text the element - * @param string $styles The style attribute defines the style the element - * styles can be defined like CSS styles - * - * @return void - * - * @see XMLWriter::startElement(), XMLWriter::writeAttribute(), - * XMLWriter::text(), XMLWriter::endElement() - */ - public function printElement( - $name, - $x, - $y, - $width = '', - $height = '', - ?string $text = '', - $styles = '' - ) { - $this->startElement($name); - $this->writeAttribute('width', (string) $width); - $this->writeAttribute('height', (string) $height); - $this->writeAttribute('x', (string) $x); - $this->writeAttribute('y', (string) $y); - $this->writeAttribute('style', (string) $styles); - if (isset($text)) { - $this->writeAttribute('font-family', (string) $this->font); - $this->writeAttribute('font-size', $this->fontSize . 'px'); - $this->text($text); - } - $this->endElement(); - } - - /** - * Draws RelationStatsSvg Line element - * - * RelationStatsSvg line element is drawn for connecting the tables. - * arrows are also drawn by specify its start and ending - * co-ordinates - * - * @param string $name RelationStatsSvg element name i.e line - * @param integer $x1 Defines the start of the line on the x-axis - * @param integer $y1 Defines the start of the line on the y-axis - * @param integer $x2 Defines the end of the line on the x-axis - * @param integer $y2 Defines the end of the line on the y-axis - * @param string $styles The style attribute defines the style the element - * styles can be defined like CSS styles - * - * @return void - * - * @see XMLWriter::startElement(), XMLWriter::writeAttribute(), - * XMLWriter::endElement() - */ - public function printElementLine($name, $x1, $y1, $x2, $y2, $styles) - { - $this->startElement($name); - $this->writeAttribute('x1', $x1); - $this->writeAttribute('y1', $y1); - $this->writeAttribute('x2', $x2); - $this->writeAttribute('y2', $y2); - $this->writeAttribute('style', $styles); - $this->endElement(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/SvgRelationSchema.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/SvgRelationSchema.php deleted file mode 100644 index 9a18b6e..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/SvgRelationSchema.php +++ /dev/null @@ -1,284 +0,0 @@ -setShowColor(isset($_REQUEST['svg_show_color'])); - $this->setShowKeys(isset($_REQUEST['svg_show_keys'])); - $this->setTableDimension(isset($_REQUEST['svg_show_table_dimension'])); - $this->setAllTablesSameWidth(isset($_REQUEST['svg_all_tables_same_width'])); - - $this->diagram->setTitle( - sprintf( - __('Schema of the %s database - Page %s'), - $this->db, - $this->pageNumber - ) - ); - $this->diagram->SetAuthor('phpMyAdmin ' . PMA_VERSION); - $this->diagram->setFont('Arial'); - $this->diagram->setFontSize(16); - - $alltables = $this->getTablesFromRequest(); - - foreach ($alltables as $table) { - if (! isset($this->_tables[$table])) { - $this->_tables[$table] = new TableStatsSvg( - $this->diagram, - $this->db, - $table, - $this->diagram->getFont(), - $this->diagram->getFontSize(), - $this->pageNumber, - $this->_tablewidth, - $this->showKeys, - $this->tableDimension, - $this->offline - ); - } - - if ($this->sameWide) { - $this->_tables[$table]->width = &$this->_tablewidth; - } - $this->_setMinMax($this->_tables[$table]); - } - - $border = 15; - $this->diagram->startSvgDoc( - $this->_xMax + $border, - $this->_yMax + $border, - $this->_xMin - $border, - $this->_yMin - $border - ); - - $seen_a_relation = false; - foreach ($alltables as $one_table) { - $exist_rel = $this->relation->getForeigners($this->db, $one_table, '', 'both'); - if (! $exist_rel) { - continue; - } - - $seen_a_relation = true; - foreach ($exist_rel as $master_field => $rel) { - /* put the foreign table on the schema only if selected - * by the user - * (do not use array_search() because we would have to - * to do a === false and this is not PHP3 compatible) - */ - if ($master_field != 'foreign_keys_data') { - if (in_array($rel['foreign_table'], $alltables)) { - $this->_addRelation( - $one_table, - $this->diagram->getFont(), - $this->diagram->getFontSize(), - $master_field, - $rel['foreign_table'], - $rel['foreign_field'], - $this->tableDimension - ); - } - continue; - } - - foreach ($rel as $one_key) { - if (! in_array($one_key['ref_table_name'], $alltables)) { - continue; - } - - foreach ($one_key['index_list'] as $index => $one_field) { - $this->_addRelation( - $one_table, - $this->diagram->getFont(), - $this->diagram->getFontSize(), - $one_field, - $one_key['ref_table_name'], - $one_key['ref_index_list'][$index], - $this->tableDimension - ); - } - } - } - } - if ($seen_a_relation) { - $this->_drawRelations(); - } - - $this->_drawTables(); - $this->diagram->endSvgDoc(); - } - - /** - * Output RelationStatsSvg Document for download - * - * @return void - */ - public function showOutput() - { - $this->diagram->showOutput($this->getFileName('.svg')); - } - - /** - * Sets X and Y minimum and maximum for a table cell - * - * @param TableStatsSvg $table The table - * - * @return void - */ - private function _setMinMax($table) - { - $this->_xMax = max($this->_xMax, $table->x + $table->width); - $this->_yMax = max($this->_yMax, $table->y + $table->height); - $this->_xMin = min($this->_xMin, $table->x); - $this->_yMin = min($this->_yMin, $table->y); - } - - /** - * Defines relation objects - * - * @param string $masterTable The master table name - * @param string $font The font face - * @param int $fontSize Font size - * @param string $masterField The relation field in the master table - * @param string $foreignTable The foreign table name - * @param string $foreignField The relation field in the foreign table - * @param boolean $tableDimension Whether to display table position or not - * - * @return void - * - * @see _setMinMax,Table_Stats_Svg::__construct(), - * PhpMyAdmin\Plugins\Schema\Svg\RelationStatsSvg::__construct() - */ - private function _addRelation( - $masterTable, - $font, - $fontSize, - $masterField, - $foreignTable, - $foreignField, - $tableDimension - ) { - if (! isset($this->_tables[$masterTable])) { - $this->_tables[$masterTable] = new TableStatsSvg( - $this->diagram, - $this->db, - $masterTable, - $font, - $fontSize, - $this->pageNumber, - $this->_tablewidth, - false, - $tableDimension - ); - $this->_setMinMax($this->_tables[$masterTable]); - } - if (! isset($this->_tables[$foreignTable])) { - $this->_tables[$foreignTable] = new TableStatsSvg( - $this->diagram, - $this->db, - $foreignTable, - $font, - $fontSize, - $this->pageNumber, - $this->_tablewidth, - false, - $tableDimension - ); - $this->_setMinMax($this->_tables[$foreignTable]); - } - $this->_relations[] = new RelationStatsSvg( - $this->diagram, - $this->_tables[$masterTable], - $masterField, - $this->_tables[$foreignTable], - $foreignField - ); - } - - /** - * Draws relation arrows and lines - * connects master table's master field to - * foreign table's foreign field - * - * @return void - * - * @see Relation_Stats_Svg::relationDraw() - */ - private function _drawRelations() - { - foreach ($this->_relations as $relation) { - $relation->relationDraw($this->showColor); - } - } - - /** - * Draws tables - * - * @return void - * - * @see Table_Stats_Svg::Table_Stats_tableDraw() - */ - private function _drawTables() - { - foreach ($this->_tables as $table) { - $table->tableDraw($this->showColor); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/TableStatsSvg.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/TableStatsSvg.php deleted file mode 100644 index 13b1a82..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/TableStatsSvg.php +++ /dev/null @@ -1,204 +0,0 @@ -_setHeightTable($fontSize); - // setWidth must me after setHeight, because title - // can include table height which changes table width - $this->_setWidthTable($font, $fontSize); - if ($same_wide_width < $this->width) { - $same_wide_width = $this->width; - } - } - - /** - * Displays an error when the table cannot be found. - * - * @return void - */ - protected function showMissingTableError() - { - ExportRelationSchema::dieSchema( - $this->pageNumber, - "SVG", - sprintf(__('The %s table doesn\'t exist!'), $this->tableName) - ); - } - - /** - * Sets the width of the table - * - * @param string $font The font size - * @param integer $fontSize The font size - * - * @return void - * @access private - * - * @see PMA_SVG - */ - private function _setWidthTable($font, $fontSize) - { - foreach ($this->fields as $field) { - $this->width = max( - $this->width, - $this->font->getStringWidth($field, $font, $fontSize) - ); - } - $this->width += $this->font->getStringWidth(' ', $font, $fontSize); - - /* - * it is unknown what value must be added, because - * table title is affected by the table width value - */ - while ($this->width - < $this->font->getStringWidth($this->getTitle(), $font, $fontSize) - ) { - $this->width += 7; - } - } - - /** - * Sets the height of the table - * - * @param integer $fontSize font size - * - * @return void - */ - private function _setHeightTable($fontSize) - { - $this->heightCell = $fontSize + 4; - $this->height = (count($this->fields) + 1) * $this->heightCell; - } - - /** - * draw the table - * - * @param boolean $showColor Whether to display color - * - * @access public - * @return void - * - * @see PMA_SVG,PMA_SVG::printElement - */ - public function tableDraw($showColor) - { - $this->diagram->printElement( - 'rect', - $this->x, - $this->y, - $this->width, - $this->heightCell, - null, - 'fill:#007;stroke:black;' - ); - $this->diagram->printElement( - 'text', - $this->x + 5, - $this->y + 14, - $this->width, - $this->heightCell, - $this->getTitle(), - 'fill:#fff;' - ); - foreach ($this->fields as $field) { - $this->currentCell += $this->heightCell; - $fillColor = 'none'; - if ($showColor) { - if (in_array($field, $this->primary)) { - $fillColor = '#aea'; - } - if ($field == $this->displayfield) { - $fillColor = 'none'; - } - } - $this->diagram->printElement( - 'rect', - $this->x, - $this->y + $this->currentCell, - $this->width, - $this->heightCell, - null, - 'fill:' . $fillColor . ';stroke:black;' - ); - $this->diagram->printElement( - 'text', - $this->x + 5, - $this->y + 14 + $this->currentCell, - $this->width, - $this->heightCell, - $field, - 'fill:black;' - ); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/TableStats.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/TableStats.php deleted file mode 100644 index a3d3b5c..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/TableStats.php +++ /dev/null @@ -1,208 +0,0 @@ -diagram = $diagram; - $this->db = $db; - $this->pageNumber = $pageNumber; - $this->tableName = $tableName; - - $this->showKeys = $showKeys; - $this->tableDimension = $tableDimension; - - $this->offline = $offline; - - $this->relation = new Relation($GLOBALS['dbi']); - $this->font = new Font(); - - // checks whether the table exists - // and loads fields - $this->validateTableAndLoadFields(); - // load table coordinates - $this->loadCoordinates(); - // loads display field - $this->loadDisplayField(); - // loads primary keys - $this->loadPrimaryKey(); - } - - /** - * Validate whether the table exists. - * - * @return void - */ - protected function validateTableAndLoadFields() - { - $sql = 'DESCRIBE ' . Util::backquote($this->tableName); - $result = $GLOBALS['dbi']->tryQuery( - $sql, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - if (! $result || ! $GLOBALS['dbi']->numRows($result)) { - $this->showMissingTableError(); - } - - if ($this->showKeys) { - $indexes = Index::getFromTable($this->tableName, $this->db); - $all_columns = []; - foreach ($indexes as $index) { - $all_columns = array_merge( - $all_columns, - array_flip(array_keys($index->getColumns())) - ); - } - $this->fields = array_keys($all_columns); - } else { - while ($row = $GLOBALS['dbi']->fetchRow($result)) { - $this->fields[] = $row[0]; - } - } - } - - /** - * Displays an error when the table cannot be found. - * - * @return void - * @abstract - */ - abstract protected function showMissingTableError(); - - /** - * Loads coordinates of a table - * - * @return void - */ - protected function loadCoordinates() - { - if (isset($_POST['t_h'])) { - foreach ($_POST['t_h'] as $key => $value) { - $db = rawurldecode($_POST['t_db'][$key]); - $tbl = rawurldecode($_POST['t_tbl'][$key]); - if ($this->db . '.' . $this->tableName === $db . '.' . $tbl) { - $this->x = (double) $_POST['t_x'][$key]; - $this->y = (double) $_POST['t_y'][$key]; - break; - } - } - } - } - - /** - * Loads the table's display field - * - * @return void - */ - protected function loadDisplayField() - { - $this->displayfield = $this->relation->getDisplayField($this->db, $this->tableName); - } - - /** - * Loads the PRIMARY key. - * - * @return void - */ - protected function loadPrimaryKey() - { - $result = $GLOBALS['dbi']->query( - 'SHOW INDEX FROM ' . Util::backquote($this->tableName) . ';', - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - if ($GLOBALS['dbi']->numRows($result) > 0) { - while ($row = $GLOBALS['dbi']->fetchAssoc($result)) { - if ($row['Key_name'] == 'PRIMARY') { - $this->primary[] = $row['Column_name']; - } - } - } - } - - /** - * Returns title of the current table, - * title can have the dimensions/co-ordinates of the table - * - * @return string title of the current table - */ - protected function getTitle() - { - return ($this->tableDimension - ? sprintf('%.0fx%0.f', $this->width, $this->heightCell) - : '' - ) - . ' ' . $this->tableName; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/SchemaPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/SchemaPlugin.php deleted file mode 100644 index 12cbd40..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/SchemaPlugin.php +++ /dev/null @@ -1,90 +0,0 @@ -properties; - } - - /** - * Sets the export plugins properties and is implemented by - * each schema export plugin - * - * @return void - */ - abstract protected function setProperties(); - - /** - * Exports the schema into the specified format. - * - * @param string $db database name - * - * @return bool Whether it succeeded - */ - abstract public function exportSchema($db); - - /** - * Adds export options common to all plugins. - * - * @param OptionsPropertyMainGroup $propertyGroup property group - * - * @return void - */ - protected function addCommonOptions(OptionsPropertyMainGroup $propertyGroup) - { - $leaf = new BoolPropertyItem('show_color', __('Show color')); - $propertyGroup->addProperty($leaf); - $leaf = new BoolPropertyItem('show_keys', __('Only show keys')); - $propertyGroup->addProperty($leaf); - } - - /** - * Returns the array of paper sizes - * - * @return array array of paper sizes - */ - protected function getPaperSizeArray() - { - $ret = []; - foreach ($GLOBALS['cfg']['PDFPageSizes'] as $val) { - $ret[$val] = $val; - } - - return $ret; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/Bool2TextTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/Bool2TextTransformationsPlugin.php deleted file mode 100644 index 696aa64..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/Bool2TextTransformationsPlugin.php +++ /dev/null @@ -1,69 +0,0 @@ -getOptions($options, $cfg['DefaultTransformations']['Bool2Text']); - - if ($buffer == '0') { - return $options[1]; // return false label - } - - return $options[0]; // or true one if nonzero - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "Bool2Text"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/CodeMirrorEditorTransformationPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/CodeMirrorEditorTransformationPlugin.php deleted file mode 100644 index bbd1fff..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/CodeMirrorEditorTransformationPlugin.php +++ /dev/null @@ -1,75 +0,0 @@ -'; - } - $class = 'transform_' . strtolower(static::getName()) . '_editor'; - $html .= ''; - - return $html; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/DateFormatTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/DateFormatTransformationsPlugin.php deleted file mode 100644 index 32ed494..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/DateFormatTransformationsPlugin.php +++ /dev/null @@ -1,158 +0,0 @@ -getOptions($options, $cfg['DefaultTransformations']['DateFormat']); - - // further operations on $buffer using the $options[] array. - $options[2] = mb_strtolower($options[2]); - - if (empty($options[1])) { - if ($options[2] == 'local') { - $options[1] = __('%B %d, %Y at %I:%M %p'); - } else { - $options[1] = 'Y-m-d H:i:s'; - } - } - - $timestamp = -1; - - // INT columns will be treated as UNIX timestamps - // and need to be detected before the verification for - // MySQL TIMESTAMP - if ($meta->type == 'int') { - $timestamp = $buffer; - - // Detect TIMESTAMP(6 | 8 | 10 | 12 | 14) - // TIMESTAMP (2 | 4) not supported here. - // (Note: prior to MySQL 4.1, TIMESTAMP has a display size - // for example TIMESTAMP(8) means YYYYMMDD) - } else { - if (preg_match('/^(\d{2}){3,7}$/', $buffer)) { - if (mb_strlen($buffer) == 14 || mb_strlen($buffer) == 8) { - $offset = 4; - } else { - $offset = 2; - } - - $aDate = []; - $aDate['year'] = (int) mb_substr($buffer, 0, $offset); - $aDate['month'] = (int) mb_substr($buffer, $offset, 2); - $aDate['day'] = (int) mb_substr($buffer, $offset + 2, 2); - $aDate['hour'] = (int) mb_substr($buffer, $offset + 4, 2); - $aDate['minute'] = (int) mb_substr($buffer, $offset + 6, 2); - $aDate['second'] = (int) mb_substr($buffer, $offset + 8, 2); - - if (checkdate($aDate['month'], $aDate['day'], $aDate['year'])) { - $timestamp = mktime( - $aDate['hour'], - $aDate['minute'], - $aDate['second'], - $aDate['month'], - $aDate['day'], - $aDate['year'] - ); - } - // If all fails, assume one of the dozens of valid strtime() syntaxes - // (https://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 -= (int) $options[0] * 60 * 60; - $source = $buffer; - if ($options[2] == 'local') { - $text = Util::localisedDate( - $timestamp, - $options[1] - ); - } elseif ($options[2] == 'utc') { - $text = gmdate($options[1], $timestamp); - } else { - $text = 'INVALID DATE TYPE'; - } - return '' . htmlspecialchars((string) $text) . ''; - } - - return htmlspecialchars((string) $buffer); - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "Date Format"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/DownloadTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/DownloadTransformationsPlugin.php deleted file mode 100644 index d6c21d6..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/DownloadTransformationsPlugin.php +++ /dev/null @@ -1,93 +0,0 @@ - $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'], - htmlspecialchars(urlencode($cn)), - htmlspecialchars($cn), - htmlspecialchars($cn) - ); - } - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "Download"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/ExternalTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/ExternalTransformationsPlugin.php deleted file mode 100644 index 006ee86..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/ExternalTransformationsPlugin.php +++ /dev/null @@ -1,160 +0,0 @@ -getOptions( - $options, - $cfg['DefaultTransformations']['External'] - ); - - if (isset($allowed_programs[$options[0]])) { - $program = $allowed_programs[$options[0]]; - } else { - $program = $allowed_programs[0]; - } - - // needs PHP >= 4.3.0 - $newstring = ''; - $descriptorspec = [ - 0 => [ - "pipe", - "r", - ], - 1 => [ - "pipe", - "w", - ], - ]; - $process = proc_open($program . ' ' . $options[1], $descriptorspec, $pipes); - if (is_resource($process)) { - fwrite($pipes[0], $buffer); - fclose($pipes[0]); - - while (! feof($pipes[1])) { - $newstring .= fgets($pipes[1], 1024); - } - fclose($pipes[1]); - // we don't currently use the return value - proc_close($process); - } - - if ($options[2] == 1 || $options[2] == '2') { - $retstring = htmlspecialchars($newstring); - } else { - $retstring = $newstring; - } - - return $retstring; - } - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "External"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/FormattedTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/FormattedTransformationsPlugin.php deleted file mode 100644 index b40ffe3..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/FormattedTransformationsPlugin.php +++ /dev/null @@ -1,65 +0,0 @@ -'; - } - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "Formatted"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/HexTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/HexTransformationsPlugin.php deleted file mode 100644 index 69ce92d..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/HexTransformationsPlugin.php +++ /dev/null @@ -1,71 +0,0 @@ -getOptions($options, $cfg['DefaultTransformations']['Hex']); - $options[0] = intval($options[0]); - - if ($options[0] < 1) { - return bin2hex($buffer); - } else { - return chunk_split(bin2hex($buffer), $options[0], ' '); - } - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "Hex"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/ImageLinkTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/ImageLinkTransformationsPlugin.php deleted file mode 100644 index efcfdc5..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/ImageLinkTransformationsPlugin.php +++ /dev/null @@ -1,63 +0,0 @@ -[BLOB]'; - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "ImageLink"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/ImageUploadTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/ImageUploadTransformationsPlugin.php deleted file mode 100644 index 0e6c0fd..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/ImageUploadTransformationsPlugin.php +++ /dev/null @@ -1,121 +0,0 @@ -'; - $html .= ''; - $src = 'transformation_wrapper.php' . $options['wrapper_link']; - } - $html .= ''
-            . __('Image preview here') . ''; - $html .= '
    '; - - return $html; - } - - /** - * Returns the array of scripts (filename) required for plugin - * initialization and handling - * - * @return array javascripts to be included - */ - public function getScripts() - { - return [ - 'transformations/image_upload.js', - ]; - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "Image upload"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/InlineTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/InlineTransformationsPlugin.php deleted file mode 100644 index 102dce9..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/InlineTransformationsPlugin.php +++ /dev/null @@ -1,78 +0,0 @@ -getOptions($options, $cfg['DefaultTransformations']['Inline']); - - if (PMA_IS_GD2) { - return '[' . htmlspecialchars($buffer) . ']'; - } else { - return '[' . htmlspecialchars($buffer) . ']'; - } - } - - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "Inline"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/LongToIPv4TransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/LongToIPv4TransformationsPlugin.php deleted file mode 100644 index 03767dc..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/LongToIPv4TransformationsPlugin.php +++ /dev/null @@ -1,66 +0,0 @@ - 4294967295) { - return htmlspecialchars($buffer); - } - - return long2ip((int) $buffer); - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "Long To IPv4"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/PreApPendTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/PreApPendTransformationsPlugin.php deleted file mode 100644 index 3dbf9d8..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/PreApPendTransformationsPlugin.php +++ /dev/null @@ -1,68 +0,0 @@ -getOptions($options, $cfg['DefaultTransformations']['PreApPend']); - - //just prepend and/or append the options to the original text - return htmlspecialchars($options[0]) . htmlspecialchars($buffer) - . htmlspecialchars($options[1]); - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "PreApPend"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/RegexValidationTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/RegexValidationTransformationsPlugin.php deleted file mode 100644 index 33f0ccd..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/RegexValidationTransformationsPlugin.php +++ /dev/null @@ -1,74 +0,0 @@ -reset(); - if (! empty($options[0]) && ! preg_match($options[0], $buffer)) { - $this->success = false; - $this->error = sprintf( - __('Validation failed for the input string %s.'), - htmlspecialchars($buffer) - ); - } - - return $buffer; - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "Regex Validation"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/SQLTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/SQLTransformationsPlugin.php deleted file mode 100644 index 616a24e..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/SQLTransformationsPlugin.php +++ /dev/null @@ -1,62 +0,0 @@ -getOptions($options, $cfg['DefaultTransformations']['Substring']); - - if ($options[1] != 'all') { - $newtext = mb_substr( - $buffer, - $options[0], - $options[1] - ); - } else { - $newtext = mb_substr($buffer, $options[0]); - } - - $length = mb_strlen($newtext); - $baselength = mb_strlen($buffer); - if ($length != $baselength) { - if ($options[0] != 0) { - $newtext = $options[2] . $newtext; - } - - if (($length + (int) $options[0]) != $baselength) { - $newtext .= $options[2]; - } - } - - return htmlspecialchars($newtext); - } - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "Substring"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/TextFileUploadTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/TextFileUploadTransformationsPlugin.php deleted file mode 100644 index 76021d8..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/TextFileUploadTransformationsPlugin.php +++ /dev/null @@ -1,103 +0,0 @@ -'; - $html .= ''; - } - $html .= ''; - - return $html; - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "Text file upload"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/TextImageLinkTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/TextImageLinkTransformationsPlugin.php deleted file mode 100644 index 71fdd6a..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/TextImageLinkTransformationsPlugin.php +++ /dev/null @@ -1,75 +0,0 @@ -getOptions($options, $cfg['DefaultTransformations']['TextImageLink']); - $url = $options[0] . $buffer; - /* Do not allow javascript links */ - if (! Sanitize::checkLink($url, true, true)) { - return htmlspecialchars($url); - } - return '' - . htmlspecialchars($buffer) . ''; - } - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "Image Link"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/TextLinkTransformationsPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/TextLinkTransformationsPlugin.php deleted file mode 100644 index e29ff2c..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Abs/TextLinkTransformationsPlugin.php +++ /dev/null @@ -1,77 +0,0 @@ -getOptions($options, $cfg['DefaultTransformations']['TextLink']); - $url = (isset($options[0]) ? $options[0] : '') . ((isset($options[2]) && $options[2]) ? '' : $buffer); - /* Do not allow javascript links */ - if (! Sanitize::checkLink($url, true, true)) { - return htmlspecialchars($url); - } - return '' - . htmlspecialchars(isset($options[1]) ? $options[1] : $buffer) - . ''; - } - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "TextLink"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Image_JPEG_Upload.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Image_JPEG_Upload.php deleted file mode 100644 index 903bfd2..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Image_JPEG_Upload.php +++ /dev/null @@ -1,44 +0,0 @@ -'; - } - $class = 'transform_IPToBin'; - $html .= ''; - - return $html; - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the transformation name of the plugin - * - * @return string - */ - public static function getName() - { - return "IPv4/IPv6 To Binary"; - } - - /** - * Gets the plugin`s MIME type - * - * @return string - */ - public static function getMIMEType() - { - return "Text"; - } - - /** - * Gets the plugin`s MIME subtype - * - * @return string - */ - public static function getMIMESubtype() - { - return "Plain"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Text_Plain_JsonEditor.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Text_Plain_JsonEditor.php deleted file mode 100644 index 17d8cf6..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Input/Text_Plain_JsonEditor.php +++ /dev/null @@ -1,85 +0,0 @@ -getHeader() - ->getScripts(); - $scripts->addFile('vendor/codemirror/lib/codemirror.js'); - $scripts->addFile('vendor/codemirror/mode/javascript/javascript.js'); - $scripts->addFile('vendor/codemirror/addon/runmode/runmode.js'); - $scripts->addFile('transformations/json.js'); - } - } - - /** - * Gets the transformation description of the specific plugin - * - * @return string - */ - public static function getInfo() - { - return __( - 'Formats text as JSON with syntax highlighting.' - ); - } - - /** - * Does the actual work of each specific transformations plugin. - * - * @param string $buffer text to be transformed - * @param array $options transformation options - * @param stdClass|null $meta meta information - * - * @return string - */ - public function applyTransformation($buffer, array $options = [], ?stdClass $meta = null) - { - return '
    ' . "\n"
    -        . htmlspecialchars($buffer) . "\n"
    -        . '
    '; - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the plugin`s MIME type - * - * @return string - */ - public static function getMIMEType() - { - return "Text"; - } - - /** - * Gets the plugin`s MIME subtype - * - * @return string - */ - public static function getMIMESubtype() - { - return "Plain"; - } - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "JSON"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Sql.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Sql.php deleted file mode 100644 index 2c39e03..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Sql.php +++ /dev/null @@ -1,60 +0,0 @@ -getHeader() - ->getScripts(); - $scripts->addFile('vendor/codemirror/lib/codemirror.js'); - $scripts->addFile('vendor/codemirror/mode/sql/sql.js'); - $scripts->addFile('vendor/codemirror/addon/runmode/runmode.js'); - $scripts->addFile('functions.js'); - } - } - - /** - * Gets the plugin`s MIME type - * - * @return string - */ - public static function getMIMEType() - { - return "Text"; - } - - /** - * Gets the plugin`s MIME subtype - * - * @return string - */ - public static function getMIMESubtype() - { - return "Plain"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Xml.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Xml.php deleted file mode 100644 index fc06744..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Output/Text_Plain_Xml.php +++ /dev/null @@ -1,101 +0,0 @@ -getHeader() - ->getScripts(); - $scripts->addFile('vendor/codemirror/lib/codemirror.js'); - $scripts->addFile('vendor/codemirror/mode/xml/xml.js'); - $scripts->addFile('vendor/codemirror/addon/runmode/runmode.js'); - $scripts->addFile('transformations/xml.js'); - } - } - - /** - * Gets the transformation description of the specific plugin - * - * @return string - */ - public static function getInfo() - { - return __( - 'Formats text as XML with syntax highlighting.' - ); - } - - /** - * Does the actual work of each specific transformations plugin. - * - * @param string $buffer text to be transformed - * @param array $options transformation options - * @param stdClass|null $meta meta information - * - * @return string - */ - public function applyTransformation($buffer, array $options = [], ?stdClass $meta = null) - { - return '
    ' . "\n"
    -        . htmlspecialchars($buffer) . "\n"
    -        . '
    '; - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the plugin`s MIME type - * - * @return string - */ - public static function getMIMEType() - { - return "Text"; - } - - /** - * Gets the plugin`s MIME subtype - * - * @return string - */ - public static function getMIMESubtype() - { - return "Plain"; - } - - /** - * Gets the transformation name of the specific plugin - * - * @return string - */ - public static function getName() - { - return "XML"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/README b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/README deleted file mode 100644 index 7d7a125..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/README +++ /dev/null @@ -1,4 +0,0 @@ -TRANSFORMATION USAGE (Garvin Hicking, ) -==================== - -See the documentation for complete instructions on how to use transformation plugins. diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/TEMPLATE b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/TEMPLATE deleted file mode 100644 index 7d2b2ff..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/TEMPLATE +++ /dev/null @@ -1,45 +0,0 @@ - diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/TEMPLATE_ABSTRACT b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/TEMPLATE_ABSTRACT deleted file mode 100644 index 4087ac9..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/TEMPLATE_ABSTRACT +++ /dev/null @@ -1,73 +0,0 @@ -mimetype contains the original MimeType of the field (i.e. 'text/plain', 'image/jpeg' etc.) - - return $buffer; - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - - /** - * Gets the TransformationName of the specific plugin - * - * @return string - */ - public static function getName() - { - return "[TransformationName]"; - } -} -?> diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Text_Plain_Link.php b/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Text_Plain_Link.php deleted file mode 100644 index 298919b..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/Transformations/Text_Plain_Link.php +++ /dev/null @@ -1,43 +0,0 @@ - $value) { - if (isset($options[$key]) && $options[$key] !== '') { - $result[$key] = $options[$key]; - } else { - $result[$key] = $value; - } - } - - return $result; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Application.php b/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Application.php deleted file mode 100644 index 15e99b9..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Application.php +++ /dev/null @@ -1,162 +0,0 @@ -_google2fa = new Google2FA(); - } else { - $this->_google2fa = new Google2FA(new SvgImageBackEnd()); - } - $this->_google2fa->setWindow(8); - if (! isset($this->_twofactor->config['settings']['secret'])) { - $this->_twofactor->config['settings']['secret'] = ''; - } - } - - /** - * Get any property of this class - * - * @param string $property name of the property - * - * @return mixed|void if property exist, value of the relevant property - */ - public function __get($property) - { - switch ($property) { - case 'google2fa': - return $this->_google2fa; - } - } - - /** - * Checks authentication, returns true on success - * - * @return boolean - * @throws IncompatibleWithGoogleAuthenticatorException - * @throws InvalidCharactersException - * @throws SecretKeyTooShortException - */ - public function check() - { - $this->_provided = false; - if (! isset($_POST['2fa_code'])) { - return false; - } - $this->_provided = true; - return $this->_google2fa->verifyKey( - $this->_twofactor->config['settings']['secret'], - $_POST['2fa_code'] - ); - } - - /** - * Renders user interface to enter two-factor authentication - * - * @return string HTML code - */ - public function render() - { - return $this->template->render('login/twofactor/application'); - } - - /** - * Renders user interface to configure two-factor authentication - * - * @return string HTML code - */ - public function setup() - { - $secret = $this->_twofactor->config['settings']['secret']; - $inlineUrl = $this->_google2fa->getQRCodeInline( - 'phpMyAdmin (' . $this->getAppId(false) . ')', - $this->_twofactor->user, - $secret - ); - return $this->template->render('login/twofactor/application_configure', [ - 'image' => $inlineUrl, - 'secret' => $secret, - 'has_imagick' => extension_loaded('imagick'), - ]); - } - - /** - * Performs backend configuration - * - * @return boolean - * @throws IncompatibleWithGoogleAuthenticatorException - * @throws InvalidCharactersException - * @throws SecretKeyTooShortException - */ - public function configure() - { - if (! isset($_SESSION['2fa_application_key'])) { - $_SESSION['2fa_application_key'] = $this->_google2fa->generateSecretKey(); - } - $this->_twofactor->config['settings']['secret'] = $_SESSION['2fa_application_key']; - - $result = $this->check(); - if ($result) { - unset($_SESSION['2fa_application_key']); - } - return $result; - } - - /** - * Get user visible name - * - * @return string - */ - public static function getName() - { - return __('Authentication Application (2FA)'); - } - - /** - * Get user visible description - * - * @return string - */ - public static function getDescription() - { - return __('Provides authentication using HOTP and TOTP applications such as FreeOTP, Google Authenticator or Authy.'); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Invalid.php b/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Invalid.php deleted file mode 100644 index 31fffc0..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Invalid.php +++ /dev/null @@ -1,68 +0,0 @@ -template->render('login/twofactor/invalid'); - } - - /** - * Get user visible name - * - * @return string - */ - public static function getName() - { - return 'Invalid two-factor authentication'; - } - - /** - * Get user visible description - * - * @return string - */ - public static function getDescription() - { - return 'Error fallback only!'; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Key.php b/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Key.php deleted file mode 100644 index cbb118c..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Key.php +++ /dev/null @@ -1,213 +0,0 @@ -_twofactor->config['settings']['registrations'])) { - $this->_twofactor->config['settings']['registrations'] = []; - } - } - - /** - * Returns array of U2F registration objects - * - * @return array - */ - public function getRegistrations() - { - $result = []; - foreach ($this->_twofactor->config['settings']['registrations'] as $index => $data) { - $reg = new stdClass(); - $reg->keyHandle = $data['keyHandle']; - $reg->publicKey = $data['publicKey']; - $reg->certificate = $data['certificate']; - $reg->counter = $data['counter']; - $reg->index = $index; - $result[] = $reg; - } - return $result; - } - - /** - * Checks authentication, returns true on success - * - * @return boolean - */ - public function check() - { - $this->_provided = false; - if (! isset($_POST['u2f_authentication_response']) || ! isset($_SESSION['authenticationRequest'])) { - return false; - } - $this->_provided = true; - try { - $response = json_decode($_POST['u2f_authentication_response']); - if ($response === null) { - return false; - } - $authentication = U2FServer::authenticate( - $_SESSION['authenticationRequest'], - $this->getRegistrations(), - $response - ); - $this->_twofactor->config['settings']['registrations'][$authentication->index]['counter'] = $authentication->counter; - $this->_twofactor->save(); - return true; - } catch (U2FException $e) { - $this->_message = $e->getMessage(); - return false; - } - } - - /** - * Loads needed javascripts into the page - * - * @return void - */ - public function loadScripts() - { - $response = Response::getInstance(); - $scripts = $response->getHeader()->getScripts(); - $scripts->addFile('vendor/u2f-api-polyfill.js'); - $scripts->addFile('u2f.js'); - } - - /** - * Renders user interface to enter two-factor authentication - * - * @return string HTML code - */ - public function render() - { - $request = U2FServer::makeAuthentication( - $this->getRegistrations(), - $this->getAppId(true) - ); - $_SESSION['authenticationRequest'] = $request; - $this->loadScripts(); - return $this->template->render('login/twofactor/key', [ - 'request' => json_encode($request), - 'is_https' => $GLOBALS['PMA_Config']->isHttps(), - ]); - } - - /** - * Renders user interface to configure two-factor authentication - * - * @return string HTML code - * @throws U2FException - * @throws Throwable - * @throws Twig_Error_Loader - * @throws Twig_Error_Runtime - * @throws Twig_Error_Syntax - */ - public function setup() - { - $registrationData = U2FServer::makeRegistration( - $this->getAppId(true), - $this->getRegistrations() - ); - $_SESSION['registrationRequest'] = $registrationData['request']; - - $this->loadScripts(); - return $this->template->render('login/twofactor/key_configure', [ - 'request' => json_encode($registrationData['request']), - 'signatures' => json_encode($registrationData['signatures']), - 'is_https' => $GLOBALS['PMA_Config']->isHttps(), - ]); - } - - /** - * Performs backend configuration - * - * @return boolean - */ - public function configure() - { - $this->_provided = false; - if (! isset($_POST['u2f_registration_response']) || ! isset($_SESSION['registrationRequest'])) { - return false; - } - $this->_provided = true; - try { - $response = json_decode($_POST['u2f_registration_response']); - if ($response === null) { - return false; - } - $registration = U2FServer::register( - $_SESSION['registrationRequest'], - $response - ); - $this->_twofactor->config['settings']['registrations'][] = [ - 'keyHandle' => $registration->getKeyHandle(), - 'publicKey' => $registration->getPublicKey(), - 'certificate' => $registration->getCertificate(), - 'counter' => $registration->getCounter(), - ]; - return true; - } catch (U2FException $e) { - $this->_message = $e->getMessage(); - return false; - } - } - - /** - * Get user visible name - * - * @return string - */ - public static function getName() - { - return __('Hardware Security Key (FIDO U2F)'); - } - - /** - * Get user visible description - * - * @return string - */ - public static function getDescription() - { - return __('Provides authentication using hardware security tokens supporting FIDO U2F.'); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Simple.php b/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Simple.php deleted file mode 100644 index 721d602..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactor/Simple.php +++ /dev/null @@ -1,68 +0,0 @@ -template->render('login/twofactor/simple'); - } - - /** - * Get user visible name - * - * @return string - */ - public static function getName() - { - return __('Simple two-factor authentication'); - } - - /** - * Get user visible description - * - * @return string - */ - public static function getDescription() - { - return __('For testing purposes only!'); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactorPlugin.php b/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactorPlugin.php deleted file mode 100644 index 23534a1..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/TwoFactorPlugin.php +++ /dev/null @@ -1,183 +0,0 @@ -_twofactor = $twofactor; - $this->_provided = false; - $this->_message = ''; - $this->template = new Template(); - } - - /** - * Returns authentication error message - * - * @return string - */ - public function getError() - { - if ($this->_provided) { - if (! empty($this->_message)) { - return Message::rawError( - sprintf(__('Two-factor authentication failed: %s'), $this->_message) - )->getDisplay(); - } - return Message::rawError( - __('Two-factor authentication failed.') - )->getDisplay(); - } - return ''; - } - - /** - * Checks authentication, returns true on success - * - * @return boolean - */ - public function check() - { - return true; - } - - /** - * Renders user interface to enter two-factor authentication - * - * @return string HTML code - */ - public function render() - { - return ''; - } - - /** - * Renders user interface to configure two-factor authentication - * - * @return string HTML code - */ - public function setup() - { - return ''; - } - - /** - * Performs backend configuration - * - * @return boolean - */ - public function configure() - { - return true; - } - - /** - * Get user visible name - * - * @return string - */ - public static function getName() - { - return __('No Two-Factor Authentication'); - } - - /** - * Get user visible description - * - * @return string - */ - public static function getDescription() - { - return __('Login using password only.'); - } - - /** - * Return an applicaiton ID - * - * Either hostname or hostname with scheme. - * - * @param boolean $return_url Whether to generate URL - * - * @return string - */ - public function getAppId($return_url) - { - /** @var Config $PMA_Config */ - global $PMA_Config; - - $url = $PMA_Config->get('PmaAbsoluteUri'); - $parsed = []; - if (! empty($url)) { - $parsed = parse_url($url); - } - if (empty($parsed['scheme'])) { - $parsed['scheme'] = $PMA_Config->isHttps() ? 'https' : 'http'; - } - if (empty($parsed['host'])) { - $parsed['host'] = Core::getenv('HTTP_HOST'); - } - if ($return_url) { - return $parsed['scheme'] . '://' . $parsed['host'] . (! empty($parsed['port']) ? ':' . $parsed['port'] : ''); - } else { - return $parsed['host']; - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/UploadInterface.php b/srcs/phpmyadmin/libraries/classes/Plugins/UploadInterface.php deleted file mode 100644 index 3839aab..0000000 --- a/srcs/phpmyadmin/libraries/classes/Plugins/UploadInterface.php +++ /dev/null @@ -1,35 +0,0 @@ -upload plugins - * - * @package PhpMyAdmin - */ -declare(strict_types=1); - -namespace PhpMyAdmin\Plugins; - -/** - * Provides a common interface that will have to implemented by all of the - * import->upload plugins. - * - * @package PhpMyAdmin - */ -interface UploadInterface -{ - /** - * Gets the specific upload ID Key - * - * @return string ID Key - */ - public static function getIdKey(); - - /** - * Returns upload status. - * - * @param string $id upload id - * - * @return array|null - */ - public static function getUploadStatus($id); -} diff --git a/srcs/phpmyadmin/libraries/classes/Properties/Options/Groups/OptionsPropertyMainGroup.php b/srcs/phpmyadmin/libraries/classes/Properties/Options/Groups/OptionsPropertyMainGroup.php deleted file mode 100644 index 99d3546..0000000 --- a/srcs/phpmyadmin/libraries/classes/Properties/Options/Groups/OptionsPropertyMainGroup.php +++ /dev/null @@ -1,35 +0,0 @@ -_subgroupHeader; - } - - /** - * Sets the subgroup header - * - * @param PropertyItem $subgroupHeader subgroup header - * - * @return void - */ - public function setSubgroupHeader($subgroupHeader) - { - $this->_subgroupHeader = $subgroupHeader; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Properties/Options/Items/BoolPropertyItem.php b/srcs/phpmyadmin/libraries/classes/Properties/Options/Items/BoolPropertyItem.php deleted file mode 100644 index 7441243..0000000 --- a/srcs/phpmyadmin/libraries/classes/Properties/Options/Items/BoolPropertyItem.php +++ /dev/null @@ -1,35 +0,0 @@ -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_diff( - $this->getProperties(), - [$property] - ); - } - - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the instance of the class - * - * @return OptionsPropertyGroup - */ - 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() - { - if ($this->_properties === null) { - return 0; - } - return count($this->_properties); - } - - /** - * Countable interface implementation. - * - * @return int - */ - public function count() - { - return $this->getNrOfProperties(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Properties/Options/OptionsPropertyItem.php b/srcs/phpmyadmin/libraries/classes/Properties/Options/OptionsPropertyItem.php deleted file mode 100644 index 829f6d9..0000000 --- a/srcs/phpmyadmin/libraries/classes/Properties/Options/OptionsPropertyItem.php +++ /dev/null @@ -1,136 +0,0 @@ -_name = $name; - } - if ($text) { - $this->_text = $text; - } - } - - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the name - * - * @return string - */ - public function getName() - { - return $this->_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 parameter - * - * @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"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Properties/Options/OptionsPropertyOneItem.php b/srcs/phpmyadmin/libraries/classes/Properties/Options/OptionsPropertyOneItem.php deleted file mode 100644 index 2ffca61..0000000 --- a/srcs/phpmyadmin/libraries/classes/Properties/Options/OptionsPropertyOneItem.php +++ /dev/null @@ -1,161 +0,0 @@ -_force_one; - } - - /** - * Sets the force parameter - * - * @param bool $force force parameter - * - * @return void - */ - public function setForce($force) - { - $this->_force_one = $force; - } - - /** - * Gets the values - * - * @return array - */ - public function getValues() - { - return $this->_values; - } - - /** - * Sets the values - * - * @param array $values values - * - * @return void - */ - public function setValues(array $values) - { - $this->_values = $values; - } - - /** - * Gets MySQL documentation pointer - * - * @return string - */ - public function getDoc() - { - return $this->_doc; - } - - /** - * Sets the doc - * - * @param string $doc MySQL documentation pointer - * - * @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; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Properties/Plugins/ExportPluginProperties.php b/srcs/phpmyadmin/libraries/classes/Properties/Plugins/ExportPluginProperties.php deleted file mode 100644 index 4ae4e03..0000000 --- a/srcs/phpmyadmin/libraries/classes/Properties/Plugins/ExportPluginProperties.php +++ /dev/null @@ -1,64 +0,0 @@ -_forceFile; - } - - /** - * Sets the force file parameter - * - * @param bool $forceFile the force file parameter - * - * @return void - */ - public function setForceFile($forceFile) - { - $this->_forceFile = $forceFile; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Properties/Plugins/ImportPluginProperties.php b/srcs/phpmyadmin/libraries/classes/Properties/Plugins/ImportPluginProperties.php deleted file mode 100644 index b270951..0000000 --- a/srcs/phpmyadmin/libraries/classes/Properties/Plugins/ImportPluginProperties.php +++ /dev/null @@ -1,33 +0,0 @@ -_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; - } - - /** - * Returns the property type ( either "options", or "plugin" ). - * - * @return string - */ - public function getPropertyType() - { - return "plugin"; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Properties/Plugins/SchemaPluginProperties.php b/srcs/phpmyadmin/libraries/classes/Properties/Plugins/SchemaPluginProperties.php deleted file mode 100644 index 28d187e..0000000 --- a/srcs/phpmyadmin/libraries/classes/Properties/Plugins/SchemaPluginProperties.php +++ /dev/null @@ -1,46 +0,0 @@ -relation = new Relation($GLOBALS['dbi']); - $this->_tableType = $type; - $server_id = $GLOBALS['server']; - if (! isset($_SESSION['tmpval'][$this->_tableType . 'Tables'][$server_id]) - ) { - $_SESSION['tmpval'][$this->_tableType . 'Tables'][$server_id] - = $this->_getPmaTable() ? $this->getFromDb() : []; - } - $this->_tables - =& $_SESSION['tmpval'][$this->_tableType . 'Tables'][$server_id]; - } - - /** - * Returns class instance. - * - * @param string $type the table type - * - * @return RecentFavoriteTable - */ - public static function getInstance($type) - { - if (! array_key_exists($type, self::$_instances)) { - self::$_instances[$type] = new RecentFavoriteTable($type); - } - return self::$_instances[$type]; - } - - /** - * Returns the recent/favorite tables array - * - * @return array - */ - public function getTables() - { - return $this->_tables; - } - - /** - * Returns recently used tables or favorite from phpMyAdmin database. - * - * @return array - */ - public function getFromDb() - { - // Read from phpMyAdmin database, if recent tables is not in session - $sql_query - = " SELECT `tables` FROM " . $this->_getPmaTable() . - " WHERE `username` = '" . $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['user']) . "'"; - - $return = []; - $result = $this->relation->queryAsControlUser($sql_query, false); - if ($result) { - $row = $GLOBALS['dbi']->fetchArray($result); - if (isset($row[0])) { - $return = json_decode($row[0], true); - } - } - return $return; - } - - /** - * Save recent/favorite tables into phpMyAdmin database. - * - * @return true|Message - */ - public function saveToDb() - { - $username = $GLOBALS['cfg']['Server']['user']; - $sql_query - = " REPLACE INTO " . $this->_getPmaTable() . " (`username`, `tables`)" . - " VALUES ('" . $GLOBALS['dbi']->escapeString($username) . "', '" - . $GLOBALS['dbi']->escapeString( - json_encode($this->_tables) - ) . "')"; - - $success = $GLOBALS['dbi']->tryQuery($sql_query, DatabaseInterface::CONNECT_CONTROL); - - if (! $success) { - $error_msg = ''; - switch ($this->_tableType) { - case 'recent': - $error_msg = __('Could not save recent table!'); - break; - - case 'favorite': - $error_msg = __('Could not save favorite table!'); - break; - } - $message = Message::error($error_msg); - $message->addMessage( - Message::rawError( - $GLOBALS['dbi']->getError(DatabaseInterface::CONNECT_CONTROL) - ), - '

    ' - ); - return $message; - } - return true; - } - - /** - * Trim recent.favorite table according to the - * NumRecentTables/NumFavoriteTables configuration. - * - * @return boolean True if trimming occurred - */ - public function trim() - { - $max = max( - $GLOBALS['cfg']['Num' . ucfirst($this->_tableType) . 'Tables'], - 0 - ); - $trimming_occurred = count($this->_tables) > $max; - while (count($this->_tables) > $max) { - array_pop($this->_tables); - } - return $trimming_occurred; - } - - /** - * Return HTML ul. - * - * @return string - */ - public function getHtmlList() - { - $html = ''; - if (count($this->_tables)) { - if ($this->_tableType == 'recent') { - foreach ($this->_tables as $table) { - $html .= '
  • '; - } - } else { - foreach ($this->_tables as $table) { - $html .= ''; - } - } - } else { - $html .= ''; - } - return $html; - } - - /** - * Return HTML. - * - * @return string - */ - public function getHtml() - { - $html = '
    '; - if ($this->_tableType == 'recent') { - $html .= '
      '; - } else { - $html .= '
        '; - } - $html .= $this->getHtmlList(); - $html .= '
    '; - return $html; - } - - /** - * Add recently used or favorite tables. - * - * @param string $db database name where the table is located - * @param string $table table name - * - * @return true|Message True if success, Message if not - */ - public function add($db, $table) - { - // If table does not exist, do not add._getPmaTable() - if (! $GLOBALS['dbi']->getColumns($db, $table)) { - return true; - } - - $table_arr = []; - $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 ($this->_getPmaTable()) { - return $this->saveToDb(); - } - } - return true; - } - - /** - * Removes recent/favorite tables that don't exist. - * - * @param string $db database - * @param string $table table - * - * @return boolean|Message True if invalid and removed, False if not invalid, - * Message if error while removing - */ - public function removeIfInvalid($db, $table) - { - foreach ($this->_tables as $tbl) { - if ($tbl['db'] == $db && $tbl['table'] == $table) { - // TODO Figure out a better way to find the existence of a table - if (! $GLOBALS['dbi']->getColumns($tbl['db'], $tbl['table'])) { - return $this->remove($tbl['db'], $tbl['table']); - } - } - } - return false; - } - - /** - * Remove favorite tables. - * - * @param string $db database name where the table is located - * @param string $table table name - * - * @return true|Message True if success, Message if not - */ - public function remove($db, $table) - { - foreach ($this->_tables as $key => $value) { - if ($value['db'] == $db && $value['table'] == $table) { - unset($this->_tables[$key]); - } - } - if ($this->_getPmaTable()) { - return $this->saveToDb(); - } - return true; - } - - /** - * Generate Html for sync Favorite tables anchor. (from localStorage to pmadb) - * - * @return string - */ - public function getHtmlSyncFavoriteTables() - { - $retval = ''; - $server_id = $GLOBALS['server']; - if ($server_id == 0) { - return ''; - } - $cfgRelation = $this->relation->getRelationsParam(); - // Not to show this once list is synchronized. - if ($cfgRelation['favoritework'] && ! isset($_SESSION['tmpval']['favorites_synced'][$server_id])) { - $params = [ - 'ajax_request' => true, - 'favorite_table' => true, - 'sync_favorite_tables' => true, - ]; - $url = 'db_structure.php' . Url::getCommon($params); - $retval = ''; - } - return $retval; - } - - /** - * Generate Html to update recent tables. - * - * @return string html - */ - public static function getHtmlUpdateRecentTables() - { - $params = [ - 'ajax_request' => true, - 'recent_table' => true, - ]; - $url = 'index.php' . Url::getCommon($params); - $retval = ''; - return $retval; - } - - /** - * Return the name of the configuration storage table - * - * @return string|null pma table name - */ - private function _getPmaTable(): ?string - { - $cfgRelation = $this->relation->getRelationsParam(); - if (! $cfgRelation['recentwork']) { - return null; - } - - if (! empty($cfgRelation['db']) - && ! empty($cfgRelation[$this->_tableType]) - ) { - return Util::backquote($cfgRelation['db']) . "." - . Util::backquote($cfgRelation[$this->_tableType]); - } - return null; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Relation.php b/srcs/phpmyadmin/libraries/classes/Relation.php deleted file mode 100644 index 2e05aff..0000000 --- a/srcs/phpmyadmin/libraries/classes/Relation.php +++ /dev/null @@ -1,2280 +0,0 @@ -dbi = $dbi; - $this->template = $template ?? new Template(); - } - - /** - * Executes a query as controluser if possible, otherwise as normal user - * - * @param string $sql the query to execute - * @param boolean $show_error whether to display SQL error messages or not - * @param int $options query options - * - * @return resource|boolean the result set, or false if no result set - * - * @access public - * - */ - public function queryAsControlUser($sql, $show_error = true, $options = 0) - { - // Avoid caching of the number of rows affected; for example, this function - // is called for tracking purposes but we want to display the correct number - // of rows affected by the original query, not by the query generated for - // tracking. - $cache_affected_rows = false; - - if ($show_error) { - $result = $this->dbi->query( - $sql, - DatabaseInterface::CONNECT_CONTROL, - $options, - $cache_affected_rows - ); - } else { - $result = @$this->dbi->tryQuery( - $sql, - DatabaseInterface::CONNECT_CONTROL, - $options, - $cache_affected_rows - ); - } // end if... else... - - if ($result) { - return $result; - } - - return false; - } - - /** - * Returns current relation parameters - * - * @return array - */ - public function getRelationsParam() - { - if (empty($_SESSION['relation'][$GLOBALS['server']]) - || empty($_SESSION['relation'][$GLOBALS['server']]['PMA_VERSION']) - || $_SESSION['relation'][$GLOBALS['server']]['PMA_VERSION'] != PMA_VERSION - ) { - $_SESSION['relation'][$GLOBALS['server']] = $this->checkRelationsParam(); - } - - // just for BC but needs to be before getRelationsParamDiagnostic() - // which uses it - $GLOBALS['cfgRelation'] = $_SESSION['relation'][$GLOBALS['server']]; - - return $_SESSION['relation'][$GLOBALS['server']]; - } - - /** - * prints out diagnostic info for pma relation feature - * - * @param array $cfgRelation Relation configuration - * - * @return string - */ - public function getRelationsParamDiagnostic(array $cfgRelation) - { - $retval = '
    '; - - $messages = []; - $messages['error'] = '' - . __('not OK') - . ''; - - $messages['ok'] = '' - . _pgettext('Correctly working', 'OK') - . ''; - - $messages['enabled'] = '' . __('Enabled') . ''; - $messages['disabled'] = '' . __('Disabled') . ''; - - if (strlen((string) $cfgRelation['db']) == 0) { - $retval .= __('Configuration of pmadb…') . ' ' - . $messages['error'] - . Util::showDocu('setup', 'linked-tables') - . '
    ' . "\n" - . __('General relation features') - . ' ' . __('Disabled') - . '' . "\n"; - if ($GLOBALS['cfg']['ZeroConf']) { - if (strlen($GLOBALS['db']) == 0) { - $retval .= $this->getHtmlFixPmaTables(true, true); - } else { - $retval .= $this->getHtmlFixPmaTables(true); - } - } - } else { - $retval .= '' . "\n"; - - if (! $cfgRelation['allworks'] - && $GLOBALS['cfg']['ZeroConf'] - // Avoid showing a "Create missing tables" link if it's a - // problem of missing definition - && $this->arePmadbTablesDefined() - ) { - $retval .= $this->getHtmlFixPmaTables(false); - $retval .= '
    '; - } - - $retval .= $this->getDiagMessageForParameter( - 'pmadb', - $cfgRelation['db'], - $messages, - 'pmadb' - ); - $retval .= $this->getDiagMessageForParameter( - 'relation', - isset($cfgRelation['relation']), - $messages, - 'relation' - ); - $retval .= $this->getDiagMessageForFeature( - __('General relation features'), - 'relwork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'table_info', - isset($cfgRelation['table_info']), - $messages, - 'table_info' - ); - $retval .= $this->getDiagMessageForFeature( - __('Display Features'), - 'displaywork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'table_coords', - isset($cfgRelation['table_coords']), - $messages, - 'table_coords' - ); - $retval .= $this->getDiagMessageForParameter( - 'pdf_pages', - isset($cfgRelation['pdf_pages']), - $messages, - 'pdf_pages' - ); - $retval .= $this->getDiagMessageForFeature( - __('Designer and creation of PDFs'), - 'pdfwork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'column_info', - isset($cfgRelation['column_info']), - $messages, - 'column_info' - ); - $retval .= $this->getDiagMessageForFeature( - __('Displaying Column Comments'), - 'commwork', - $messages, - false - ); - $retval .= $this->getDiagMessageForFeature( - __('Browser transformation'), - 'mimework', - $messages - ); - if ($cfgRelation['commwork'] && ! $cfgRelation['mimework']) { - $retval .= ''; - } - $retval .= $this->getDiagMessageForParameter( - 'bookmarktable', - isset($cfgRelation['bookmark']), - $messages, - 'bookmark' - ); - $retval .= $this->getDiagMessageForFeature( - __('Bookmarked SQL query'), - 'bookmarkwork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'history', - isset($cfgRelation['history']), - $messages, - 'history' - ); - $retval .= $this->getDiagMessageForFeature( - __('SQL history'), - 'historywork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'recent', - isset($cfgRelation['recent']), - $messages, - 'recent' - ); - $retval .= $this->getDiagMessageForFeature( - __('Persistent recently used tables'), - 'recentwork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'favorite', - isset($cfgRelation['favorite']), - $messages, - 'favorite' - ); - $retval .= $this->getDiagMessageForFeature( - __('Persistent favorite tables'), - 'favoritework', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'table_uiprefs', - isset($cfgRelation['table_uiprefs']), - $messages, - 'table_uiprefs' - ); - $retval .= $this->getDiagMessageForFeature( - __('Persistent tables\' UI preferences'), - 'uiprefswork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'tracking', - isset($cfgRelation['tracking']), - $messages, - 'tracking' - ); - $retval .= $this->getDiagMessageForFeature( - __('Tracking'), - 'trackingwork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'userconfig', - isset($cfgRelation['userconfig']), - $messages, - 'userconfig' - ); - $retval .= $this->getDiagMessageForFeature( - __('User preferences'), - 'userconfigwork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'users', - isset($cfgRelation['users']), - $messages, - 'users' - ); - $retval .= $this->getDiagMessageForParameter( - 'usergroups', - isset($cfgRelation['usergroups']), - $messages, - 'usergroups' - ); - $retval .= $this->getDiagMessageForFeature( - __('Configurable menus'), - 'menuswork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'navigationhiding', - isset($cfgRelation['navigationhiding']), - $messages, - 'navigationhiding' - ); - $retval .= $this->getDiagMessageForFeature( - __('Hide/show navigation items'), - 'navwork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'savedsearches', - isset($cfgRelation['savedsearches']), - $messages, - 'savedsearches' - ); - $retval .= $this->getDiagMessageForFeature( - __('Saving Query-By-Example searches'), - 'savedsearcheswork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'central_columns', - isset($cfgRelation['central_columns']), - $messages, - 'central_columns' - ); - $retval .= $this->getDiagMessageForFeature( - __('Managing Central list of columns'), - 'centralcolumnswork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'designer_settings', - isset($cfgRelation['designer_settings']), - $messages, - 'designer_settings' - ); - $retval .= $this->getDiagMessageForFeature( - __('Remembering Designer Settings'), - 'designersettingswork', - $messages - ); - $retval .= $this->getDiagMessageForParameter( - 'export_templates', - isset($cfgRelation['export_templates']), - $messages, - 'export_templates' - ); - $retval .= $this->getDiagMessageForFeature( - __('Saving export templates'), - 'exporttemplateswork', - $messages - ); - $retval .= '
    '; - $retval .= __( - 'Please see the documentation on how to' - . ' update your column_info table.' - ); - $retval .= Util::showDocu( - 'config', - 'cfg_Servers_column_info' - ); - $retval .= '
    ' . "\n"; - - if (! $cfgRelation['allworks']) { - $retval .= '

    ' . __('Quick steps to set up advanced features:') - . '

    '; - - $items = []; - $items[] = sprintf( - __( - 'Create the needed tables with the ' - . '%screate_tables.sql.' - ), - htmlspecialchars(SQL_DIR) - ) . ' ' . Util::showDocu('setup', 'linked-tables'); - $items[] = __('Create a pma user and give access to these tables.') . ' ' - . Util::showDocu('config', 'cfg_Servers_controluser'); - $items[] = __( - 'Enable advanced features in configuration file ' - . '(config.inc.php), for example by ' - . 'starting from config.sample.inc.php.' - ) . ' ' . Util::showDocu('setup', 'quick-install'); - $items[] = __( - 'Re-login to phpMyAdmin to load the updated configuration file.' - ); - - $retval .= $this->template->render('list/unordered', ['items' => $items]); - } - } - - 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 - */ - public function getDiagMessageForFeature( - $feature_name, - $relation_parameter, - array $messages, - $skip_line = true - ) { - $retval = ' ' . $feature_name . ': '; - if (isset($GLOBALS['cfgRelation'][$relation_parameter]) - && $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 $relationParameterSet whether this parameter is set - * @param array $messages utility messages - * @param string $docAnchor anchor in documentation - * - * @return string - */ - public function getDiagMessageForParameter( - $parameter, - $relationParameterSet, - array $messages, - $docAnchor - ) { - $retval = ''; - $retval .= '$cfg[\'Servers\'][$i][\'' . $parameter . '\'] ... '; - $retval .= ''; - if ($relationParameterSet) { - $retval .= $messages['ok']; - } else { - $retval .= sprintf( - $messages['error'], - Util::getDocuLink('config', 'cfg_Servers_' . $docAnchor) - ); - } - $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 - */ - public function checkRelationsParam() - { - $cfgRelation = []; - $cfgRelation['PMA_VERSION'] = PMA_VERSION; - - $workToTable = [ - 'relwork' => 'relation', - 'displaywork' => [ - 'relation', - 'table_info', - ], - 'bookmarkwork' => 'bookmarktable', - 'pdfwork' => [ - 'table_coords', - 'pdf_pages', - ], - 'commwork' => 'column_info', - 'mimework' => 'column_info', - 'historywork' => 'history', - 'recentwork' => 'recent', - 'favoritework' => 'favorite', - 'uiprefswork' => 'table_uiprefs', - 'trackingwork' => 'tracking', - 'userconfigwork' => 'userconfig', - 'menuswork' => [ - 'users', - 'usergroups', - ], - 'navwork' => 'navigationhiding', - 'savedsearcheswork' => 'savedsearches', - 'centralcolumnswork' => 'central_columns', - 'designersettingswork' => 'designer_settings', - 'exporttemplateswork' => 'export_templates', - ]; - - foreach ($workToTable as $work => $table) { - $cfgRelation[$work] = false; - } - $cfgRelation['allworks'] = false; - $cfgRelation['user'] = null; - $cfgRelation['db'] = null; - - if ($GLOBALS['server'] == 0 - || empty($GLOBALS['cfg']['Server']['pmadb']) - || ! $this->dbi->selectDb( - $GLOBALS['cfg']['Server']['pmadb'], - DatabaseInterface::CONNECT_CONTROL - ) - ) { - // No server selected -> no bookmark table - // we return the array with the falses in it, - // to avoid some 'Uninitialized 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 ' - . Util::backquote( - $GLOBALS['cfg']['Server']['pmadb'] - ); - $tab_rs = $this->queryAsControlUser( - $tab_query, - false, - DatabaseInterface::QUERY_STORE - ); - - if (! $tab_rs) { - // query failed ... ? - //$GLOBALS['cfg']['Server']['pmadb'] = false; - return $cfgRelation; - } - - while ($curr_table = @$this->dbi->fetchRow($tab_rs)) { - if ($curr_table[0] == $GLOBALS['cfg']['Server']['bookmarktable']) { - $cfgRelation['bookmark'] = $curr_table[0]; - } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['relation']) { - $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']['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']['favorite']) { - $cfgRelation['favorite'] = $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]; - } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['users']) { - $cfgRelation['users'] = $curr_table[0]; - } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['usergroups']) { - $cfgRelation['usergroups'] = $curr_table[0]; - } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['navigationhiding']) { - $cfgRelation['navigationhiding'] = $curr_table[0]; - } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['savedsearches']) { - $cfgRelation['savedsearches'] = $curr_table[0]; - } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['central_columns']) { - $cfgRelation['central_columns'] = $curr_table[0]; - } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['designer_settings']) { - $cfgRelation['designer_settings'] = $curr_table[0]; - } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['export_templates']) { - $cfgRelation['export_templates'] = $curr_table[0]; - } - } // end while - $this->dbi->freeResult($tab_rs); - - if (isset($cfgRelation['relation'])) { - if ($this->canAccessStorageTable($cfgRelation['relation'])) { - $cfgRelation['relwork'] = true; - } - } - - if (isset($cfgRelation['relation']) && isset($cfgRelation['table_info'])) { - if ($this->canAccessStorageTable($cfgRelation['table_info'])) { - $cfgRelation['displaywork'] = true; - } - } - - if (isset($cfgRelation['table_coords']) && isset($cfgRelation['pdf_pages'])) { - if ($this->canAccessStorageTable($cfgRelation['table_coords'])) { - if ($this->canAccessStorageTable($cfgRelation['pdf_pages'])) { - $cfgRelation['pdfwork'] = true; - } - } - } - - if (isset($cfgRelation['column_info'])) { - if ($this->canAccessStorageTable($cfgRelation['column_info'])) { - $cfgRelation['commwork'] = true; - // phpMyAdmin 4.3+ - // Check for input transformations upgrade. - $cfgRelation['mimework'] = $this->tryUpgradeTransformations(); - } - } - - if (isset($cfgRelation['history'])) { - if ($this->canAccessStorageTable($cfgRelation['history'])) { - $cfgRelation['historywork'] = true; - } - } - - if (isset($cfgRelation['recent'])) { - if ($this->canAccessStorageTable($cfgRelation['recent'])) { - $cfgRelation['recentwork'] = true; - } - } - - if (isset($cfgRelation['favorite'])) { - if ($this->canAccessStorageTable($cfgRelation['favorite'])) { - $cfgRelation['favoritework'] = true; - } - } - - if (isset($cfgRelation['table_uiprefs'])) { - if ($this->canAccessStorageTable($cfgRelation['table_uiprefs'])) { - $cfgRelation['uiprefswork'] = true; - } - } - - if (isset($cfgRelation['tracking'])) { - if ($this->canAccessStorageTable($cfgRelation['tracking'])) { - $cfgRelation['trackingwork'] = true; - } - } - - if (isset($cfgRelation['userconfig'])) { - if ($this->canAccessStorageTable($cfgRelation['userconfig'])) { - $cfgRelation['userconfigwork'] = true; - } - } - - if (isset($cfgRelation['bookmark'])) { - if ($this->canAccessStorageTable($cfgRelation['bookmark'])) { - $cfgRelation['bookmarkwork'] = true; - } - } - - if (isset($cfgRelation['users']) && isset($cfgRelation['usergroups'])) { - if ($this->canAccessStorageTable($cfgRelation['users'])) { - if ($this->canAccessStorageTable($cfgRelation['usergroups'])) { - $cfgRelation['menuswork'] = true; - } - } - } - - if (isset($cfgRelation['navigationhiding'])) { - if ($this->canAccessStorageTable($cfgRelation['navigationhiding'])) { - $cfgRelation['navwork'] = true; - } - } - - if (isset($cfgRelation['savedsearches'])) { - if ($this->canAccessStorageTable($cfgRelation['savedsearches'])) { - $cfgRelation['savedsearcheswork'] = true; - } - } - - if (isset($cfgRelation['central_columns'])) { - if ($this->canAccessStorageTable($cfgRelation['central_columns'])) { - $cfgRelation['centralcolumnswork'] = true; - } - } - - if (isset($cfgRelation['designer_settings'])) { - if ($this->canAccessStorageTable($cfgRelation['designer_settings'])) { - $cfgRelation['designersettingswork'] = true; - } - } - - if (isset($cfgRelation['export_templates'])) { - if ($this->canAccessStorageTable($cfgRelation['export_templates'])) { - $cfgRelation['exporttemplateswork'] = true; - } - } - - $allWorks = true; - foreach ($workToTable as $work => $table) { - if (! $cfgRelation[$work]) { - if (is_string($table)) { - if (isset($GLOBALS['cfg']['Server'][$table]) - && $GLOBALS['cfg']['Server'][$table] !== false - ) { - $allWorks = false; - break; - } - } elseif (is_array($table)) { - $oneNull = false; - foreach ($table as $t) { - if (isset($GLOBALS['cfg']['Server'][$t]) - && $GLOBALS['cfg']['Server'][$t] === false - ) { - $oneNull = true; - break; - } - } - if (! $oneNull) { - $allWorks = false; - break; - } - } - } - } - $cfgRelation['allworks'] = $allWorks; - - return $cfgRelation; - } - - /** - * Check if the table is accessible - * - * @param string $tableDbName The table or table.db - * @return boolean The table is accessible - */ - public function canAccessStorageTable($tableDbName) - { - $result = $this->queryAsControlUser( - 'SELECT NULL FROM ' . $tableDbName . ' LIMIT 0', - false, - DatabaseInterface::QUERY_STORE - ); - return $result !== false; - } - - /** - * Check whether column_info table input transformation - * upgrade is required and try to upgrade silently - * - * @return bool false if upgrade failed - * - * @access public - */ - public function tryUpgradeTransformations() - { - // From 4.3, new input oriented transformation feature was introduced. - // Check whether column_info table has input transformation columns - $new_cols = [ - "input_transformation", - "input_transformation_options", - ]; - $query = 'SHOW COLUMNS FROM ' - . Util::backquote($GLOBALS['cfg']['Server']['pmadb']) - . '.' . Util::backquote( - $GLOBALS['cfg']['Server']['column_info'] - ) - . ' WHERE Field IN (\'' . implode('\', \'', $new_cols) . '\')'; - $result = $this->queryAsControlUser( - $query, - false, - DatabaseInterface::QUERY_STORE - ); - if ($result) { - $rows = $this->dbi->numRows($result); - $this->dbi->freeResult($result); - // input transformations are present - // no need to upgrade - if ($rows === 2) { - return true; - // try silent upgrade without disturbing the user - } - - // read upgrade query file - $query = @file_get_contents(SQL_DIR . 'upgrade_column_info_4_3_0+.sql'); - // replace database name from query to with set in config.inc.php - // replace pma__column_info table name from query - // to with set in config.inc.php - $query = str_replace( - [ - '`phpmyadmin`', - '`pma__column_info`', - ], - [ - Util::backquote($GLOBALS['cfg']['Server']['pmadb']), - Util::backquote($GLOBALS['cfg']['Server']['column_info']), - ], - $query - ); - $this->dbi->tryMultiQuery($query, DatabaseInterface::CONNECT_CONTROL); - // skips result sets of query as we are not interested in it - do { - $hasResult = ( - $this->dbi->moreResults(DatabaseInterface::CONNECT_CONTROL) - && $this->dbi->nextResult(DatabaseInterface::CONNECT_CONTROL) - ); - } while ($hasResult); - $error = $this->dbi->getError(DatabaseInterface::CONNECT_CONTROL); - // return true if no error exists otherwise false - return empty($error); - } - // some failure, either in upgrading or something else - // make some noise, time to wake up user. - return false; - } - - /** - * 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 - */ - public function getForeigners($db, $table, $column = '', $source = 'both') - { - $cfgRelation = $this->getRelationsParam(); - $foreign = []; - - if ($cfgRelation['relwork'] && ($source == 'both' || $source == 'internal')) { - $rel_query = ' - SELECT `master_field`, - `foreign_db`, - `foreign_table`, - `foreign_field` - FROM ' . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['relation']) . ' - WHERE `master_db` = \'' . $this->dbi->escapeString($db) . '\' - AND `master_table` = \'' . $this->dbi->escapeString($table) - . '\' '; - if (strlen($column) > 0) { - $rel_query .= ' AND `master_field` = ' - . '\'' . $this->dbi->escapeString($column) . '\''; - } - $foreign = $this->dbi->fetchResult( - $rel_query, - 'master_field', - null, - DatabaseInterface::CONNECT_CONTROL - ); - } - - if (($source == 'both' || $source == 'foreign') && strlen($table) > 0) { - $tableObj = new Table($table, $db); - $show_create_table = $tableObj->showCreate(); - if ($show_create_table) { - $parser = new Parser($show_create_table); - /** - * @var CreateStatement $stmt - */ - $stmt = $parser->statements[0]; - $foreign['foreign_keys_data'] = TableUtils::getForeignKeys( - $stmt - ); - } - } - - /** - * Emulating relations for some information_schema tables - */ - $isInformationSchema = mb_strtolower($db) == 'information_schema'; - $isMysql = mb_strtolower($db) == 'mysql'; - if (($isInformationSchema || $isMysql) - && ($source == 'internal' || $source == 'both') - ) { - if ($isInformationSchema) { - $internalRelations = InternalRelations::getInformationSchema(); - } else { - $internalRelations = InternalRelations::getMySql(); - } - if (isset($internalRelations[$table])) { - foreach ($internalRelations[$table] as $field => $relations) { - if ((strlen($column) === 0 || $column == $field) - && (! isset($foreign[$field]) - || strlen($foreign[$field]) === 0) - ) { - $foreign[$field] = $relations; - } - } - } - } - - return $foreign; - } - - /** - * 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|false field name or false - * - * @access public - */ - public function getDisplayField($db, $table) - { - $cfgRelation = $this->getRelationsParam(); - - /** - * Try to fetch the display field from DB. - */ - if ($cfgRelation['displaywork']) { - $disp_query = ' - SELECT `display_field` - FROM ' . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['table_info']) . ' - WHERE `db_name` = \'' . $this->dbi->escapeString((string) $db) . '\' - AND `table_name` = \'' . $this->dbi->escapeString((string) $table) - . '\''; - - $row = $this->dbi->fetchSingleRow( - $disp_query, - 'ASSOC', - DatabaseInterface::CONNECT_CONTROL - ); - 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'; - } - } - - /** - * Pick first char field - */ - $columns = $this->dbi->getColumnsFull($db, $table); - if ($columns) { - foreach ($columns as $column) { - if ($this->dbi->types->getTypeClass($column['DATA_TYPE']) == 'CHAR') { - return $column['COLUMN_NAME']; - } - } - } - return false; - } - - /** - * 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 - */ - public function getComments($db, $table = '') - { - $comments = []; - - if ($table != '') { - // MySQL native column comments - $columns = $this->dbi->getColumns($db, $table, null, true); - if ($columns) { - foreach ($columns as $column) { - if (! empty($column['Comment'])) { - $comments[$column['Field']] = $column['Comment']; - } - } - } - } else { - $comments[] = $this->getDbComment($db); - } - - return $comments; - } - - /** - * Gets the comment for a db - * - * @param string $db the name of the db to check for - * - * @return string comment - * - * @access public - */ - public function getDbComment($db) - { - $cfgRelation = $this->getRelationsParam(); - $comment = ''; - - if ($cfgRelation['commwork']) { - // pmadb internal db comment - $com_qry = " - SELECT `comment` - FROM " . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['column_info']) - . " - WHERE db_name = '" . $this->dbi->escapeString($db) . "' - AND table_name = '' - AND column_name = '(db_comment)'"; - $com_rs = $this->queryAsControlUser( - $com_qry, - false, - DatabaseInterface::QUERY_STORE - ); - - if ($com_rs && $this->dbi->numRows($com_rs) > 0) { - $row = $this->dbi->fetchAssoc($com_rs); - $comment = $row['comment']; - } - $this->dbi->freeResult($com_rs); - } - - return $comment; - } - - /** - * Gets the comment for a db - * - * @access public - * - * @return array comments - */ - public function getDbComments() - { - $cfgRelation = $this->getRelationsParam(); - $comments = []; - - if ($cfgRelation['commwork']) { - // pmadb internal db comment - $com_qry = " - SELECT `db_name`, `comment` - FROM " . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['column_info']) - . " - WHERE `column_name` = '(db_comment)'"; - $com_rs = $this->queryAsControlUser( - $com_qry, - false, - DatabaseInterface::QUERY_STORE - ); - - if ($com_rs && $this->dbi->numRows($com_rs) > 0) { - while ($row = $this->dbi->fetchAssoc($com_rs)) { - $comments[$row['db_name']] = $row['comment']; - } - } - $this->dbi->freeResult($com_rs); - } - - return $comments; - } - - /** - * 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 - */ - public function setDbComment($db, $comment = '') - { - $cfgRelation = $this->getRelationsParam(); - - if (! $cfgRelation['commwork']) { - return false; - } - - if (strlen($comment) > 0) { - $upd_query = 'INSERT INTO ' - . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['column_info']) - . ' (`db_name`, `table_name`, `column_name`, `comment`)' - . ' VALUES (\'' - . $this->dbi->escapeString($db) - . "', '', '(db_comment)', '" - . $this->dbi->escapeString($comment) - . "') " - . ' ON DUPLICATE KEY UPDATE ' - . "`comment` = '" . $this->dbi->escapeString($comment) . "'"; - } else { - $upd_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['column_info']) - . ' WHERE `db_name` = \'' . $this->dbi->escapeString($db) - . '\' - AND `table_name` = \'\' - AND `column_name` = \'(db_comment)\''; - } - - return $this->queryAsControlUser($upd_query); - } - - /** - * 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 - */ - public function setHistory($db, $table, $username, $sqlquery) - { - $maxCharactersInDisplayedSQL = $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']; - // Prevent to run this automatically on Footer class destroying in testsuite - if (defined('TESTSUITE') - || mb_strlen($sqlquery) > $maxCharactersInDisplayedSQL - ) { - return; - } - - $cfgRelation = $this->getRelationsParam(); - - if (! isset($_SESSION['sql_history'])) { - $_SESSION['sql_history'] = []; - } - - $_SESSION['sql_history'][] = [ - '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; - } - - $this->queryAsControlUser( - 'INSERT INTO ' - . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['history']) . ' - (`username`, - `db`, - `table`, - `timevalue`, - `sqlquery`) - VALUES - (\'' . $this->dbi->escapeString($username) . '\', - \'' . $this->dbi->escapeString($db) . '\', - \'' . $this->dbi->escapeString($table) . '\', - NOW(), - \'' . $this->dbi->escapeString($sqlquery) . '\')' - ); - - $this->purgeHistory($username); - } - - /** - * Gets a SQL history entry - * - * @param string $username the username - * - * @return array|bool list of history items - * - * @access public - */ - public function getHistory($username) - { - $cfgRelation = $this->getRelationsParam(); - - if (! $cfgRelation['historywork']) { - return false; - } - - /** - * if db-based history is disabled but there exists a session-based - * history, use it - */ - if (! $GLOBALS['cfg']['QueryHistoryDB']) { - if (isset($_SESSION['sql_history'])) { - return array_reverse($_SESSION['sql_history']); - } - return false; - } - - $hist_query = ' - SELECT `db`, - `table`, - `sqlquery`, - `timevalue` - FROM ' . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['history']) . ' - WHERE `username` = \'' . $this->dbi->escapeString($username) . '\' - ORDER BY `id` DESC'; - - return $this->dbi->fetchResult( - $hist_query, - null, - null, - DatabaseInterface::CONNECT_CONTROL - ); - } - - /** - * purges SQL history - * - * deletes entries that exceeds $cfg['QueryHistoryMax'], oldest first, for the - * given user - * - * @param string $username the username - * - * @return void - * - * @access public - */ - public function purgeHistory($username) - { - $cfgRelation = $this->getRelationsParam(); - if (! $GLOBALS['cfg']['QueryHistoryDB'] || ! $cfgRelation['historywork']) { - return; - } - - if (! $cfgRelation['historywork']) { - return; - } - - $search_query = ' - SELECT `timevalue` - FROM ' . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['history']) . ' - WHERE `username` = \'' . $this->dbi->escapeString($username) . '\' - ORDER BY `timevalue` DESC - LIMIT ' . $GLOBALS['cfg']['QueryHistoryMax'] . ', 1'; - - if ($max_time = $this->dbi->fetchValue( - $search_query, - 0, - 0, - DatabaseInterface::CONNECT_CONTROL - )) { - $this->queryAsControlUser( - 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['history']) . ' - WHERE `username` = \'' . $this->dbi->escapeString($username) - . '\' - AND `timevalue` <= \'' . $max_time . '\'' - ); - } - } - - /** - * 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 . '>' - . $key . ' - ' . $value . ''; - } elseif ($mode == 'id-only') { - $reloptions[] = $reloption . '>' - . $key . ''; - } - } // end foreach - - return $reloptions; - } - - /** - * 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; - } - - /** - * Gets foreign keys in preparation for a drop-down selector - * - * @param array|boolean $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 - * @param bool $get_total optional, whether to get total num of rows - * in $foreignData['the_total;] - * (has an effect of performance) - * - * @return array data about the foreign keys - * - * @access public - */ - public function getForeignData( - $foreigners, - $field, - $override_total, - $foreign_filter, - $foreign_limit, - $get_total = false - ) { - // 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; - do { - if (! $foreigners) { - break; - } - $foreigner = $this->searchColumnInForeigners($foreigners, $field); - if ($foreigner != false) { - $foreign_db = $foreigner['foreign_db']; - $foreign_table = $foreigner['foreign_table']; - $foreign_field = $foreigner['foreign_field']; - } else { - break; - } - - // 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. - - // Check if table has more rows than specified by - // $GLOBALS['cfg']['ForeignKeyMaxLimit'] - $moreThanLimit = $this->dbi->getTable($foreign_db, $foreign_table) - ->checkIfMinRecordsExist($GLOBALS['cfg']['ForeignKeyMaxLimit']); - - if ($override_total === true - || ! $moreThanLimit - ) { - // foreign_display can be false if no display field defined: - $foreign_display = $this->getDisplayField($foreign_db, $foreign_table); - - $f_query_main = 'SELECT ' . Util::backquote($foreign_field) - . ( - $foreign_display === false - ? '' - : ', ' . Util::backquote($foreign_display) - ); - $f_query_from = ' FROM ' . Util::backquote($foreign_db) - . '.' . Util::backquote($foreign_table); - $f_query_filter = empty($foreign_filter) ? '' : ' WHERE ' - . Util::backquote($foreign_field) - . ' LIKE "%' . $this->dbi->escapeString($foreign_filter) . '%"' - . ( - $foreign_display === false - ? '' - : ' OR ' . Util::backquote($foreign_display) - . ' LIKE "%' . $this->dbi->escapeString($foreign_filter) - . '%"' - ); - $f_query_order = $foreign_display === false ? '' : ' ORDER BY ' - . Util::backquote($foreign_table) . '.' - . Util::backquote($foreign_display); - - $f_query_limit = ! empty($foreign_limit) ? $foreign_limit : ''; - - if (! empty($foreign_filter)) { - $the_total = $this->dbi->fetchValue( - 'SELECT COUNT(*)' . $f_query_from . $f_query_filter - ); - if ($the_total === false) { - $the_total = 0; - } - } - - $disp = $this->dbi->tryQuery( - $f_query_main . $f_query_from . $f_query_filter - . $f_query_order . $f_query_limit - ); - if ($disp && $this->dbi->numRows($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 = []; - while ($single_disp_row = @$this->dbi->fetchAssoc($disp)) { - $disp_row[] = $single_disp_row; - } - @$this->dbi->freeResult($disp); - } else { - // Either no data in the foreign table or - // user does not have select permission to foreign table/field - // Show an input field with a 'Browse foreign values' link - $disp_row = null; - $foreign_link = true; - } - } else { - $disp_row = null; - $foreign_link = true; - } - } while (false); - - if ($get_total) { - $the_total = $this->dbi->getTable($foreign_db, $foreign_table) - ->countRecords(true); - } - - $foreignData = []; - $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; - } - - /** - * Rename a field in relation tables - * - * usually called after a column in a table was renamed - * - * @param string $db database name - * @param string $table table name - * @param string $field old field name - * @param string $new_name new field name - * - * @return void - */ - public function renameField($db, $table, $field, $new_name) - { - $cfgRelation = $this->getRelationsParam(); - - if ($cfgRelation['displaywork']) { - $table_query = 'UPDATE ' - . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['table_info']) - . ' SET display_field = \'' . $this->dbi->escapeString( - $new_name - ) . '\'' - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) - . '\'' - . ' AND table_name = \'' . $this->dbi->escapeString($table) - . '\'' - . ' AND display_field = \'' . $this->dbi->escapeString($field) - . '\''; - $this->queryAsControlUser($table_query); - } - - if ($cfgRelation['relwork']) { - $table_query = 'UPDATE ' - . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['relation']) - . ' SET master_field = \'' . $this->dbi->escapeString( - $new_name - ) . '\'' - . ' WHERE master_db = \'' . $this->dbi->escapeString($db) - . '\'' - . ' AND master_table = \'' . $this->dbi->escapeString($table) - . '\'' - . ' AND master_field = \'' . $this->dbi->escapeString($field) - . '\''; - $this->queryAsControlUser($table_query); - - $table_query = 'UPDATE ' - . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['relation']) - . ' SET foreign_field = \'' . $this->dbi->escapeString( - $new_name - ) . '\'' - . ' WHERE foreign_db = \'' . $this->dbi->escapeString($db) - . '\'' - . ' AND foreign_table = \'' . $this->dbi->escapeString($table) - . '\'' - . ' AND foreign_field = \'' . $this->dbi->escapeString($field) - . '\''; - $this->queryAsControlUser($table_query); - } - } - - - /** - * 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 void - */ - public function renameSingleTable( - $table, - $source_db, - $target_db, - $source_table, - $target_table, - $db_field, - $table_field - ) { - $query = 'UPDATE ' - . Util::backquote($GLOBALS['cfgRelation']['db']) . '.' - . Util::backquote($GLOBALS['cfgRelation'][$table]) - . ' SET ' - . $db_field . ' = \'' . $this->dbi->escapeString($target_db) - . '\', ' - . $table_field . ' = \'' . $this->dbi->escapeString($target_table) - . '\'' - . ' WHERE ' - . $db_field . ' = \'' . $this->dbi->escapeString($source_db) . '\'' - . ' AND ' - . $table_field . ' = \'' . $this->dbi->escapeString($source_table) - . '\''; - $this->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 void - */ - public function renameTable($source_db, $target_db, $source_table, $target_table) - { - // Move old entries from PMA-DBs to new table - if ($GLOBALS['cfgRelation']['commwork']) { - $this->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']) { - $this->renameSingleTable( - 'table_info', - $source_db, - $target_db, - $source_table, - $target_table, - 'db_name', - 'table_name' - ); - } - - if ($GLOBALS['cfgRelation']['relwork']) { - $this->renameSingleTable( - 'relation', - $source_db, - $target_db, - $source_table, - $target_table, - 'foreign_db', - 'foreign_table' - ); - - $this->renameSingleTable( - 'relation', - $source_db, - $target_db, - $source_table, - $target_table, - 'master_db', - 'master_table' - ); - } - - if ($GLOBALS['cfgRelation']['pdfwork']) { - if ($source_db == $target_db) { - // rename within the database can be handled - $this->renameSingleTable( - 'table_coords', - $source_db, - $target_db, - $source_table, - $target_table, - 'db_name', - 'table_name' - ); - } else { - // if the table is moved out of the database we can no loger keep the - // record for table coordinate - $remove_query = "DELETE FROM " - . Util::backquote($GLOBALS['cfgRelation']['db']) . "." - . Util::backquote($GLOBALS['cfgRelation']['table_coords']) - . " WHERE db_name = '" . $this->dbi->escapeString($source_db) . "'" - . " AND table_name = '" . $this->dbi->escapeString($source_table) - . "'"; - $this->queryAsControlUser($remove_query); - } - } - - if ($GLOBALS['cfgRelation']['uiprefswork']) { - $this->renameSingleTable( - 'table_uiprefs', - $source_db, - $target_db, - $source_table, - $target_table, - 'db_name', - 'table_name' - ); - } - - if ($GLOBALS['cfgRelation']['navwork']) { - // update hidden items inside table - $this->renameSingleTable( - 'navigationhiding', - $source_db, - $target_db, - $source_table, - $target_table, - 'db_name', - 'table_name' - ); - - // update data for hidden table - $query = "UPDATE " - . Util::backquote($GLOBALS['cfgRelation']['db']) . "." - . Util::backquote( - $GLOBALS['cfgRelation']['navigationhiding'] - ) - . " SET db_name = '" . $this->dbi->escapeString($target_db) - . "'," - . " item_name = '" . $this->dbi->escapeString($target_table) - . "'" - . " WHERE db_name = '" . $this->dbi->escapeString($source_db) - . "'" - . " AND item_name = '" . $this->dbi->escapeString($source_table) - . "'" - . " AND item_type = 'table'"; - $this->queryAsControlUser($query); - } - } - - /** - * Create a PDF page - * - * @param string|null $newpage name of the new PDF page - * @param array $cfgRelation Relation configuration - * @param string $db database name - * - * @return int - */ - public function createPage(?string $newpage, array $cfgRelation, $db) - { - if (! isset($newpage) || $newpage == '') { - $newpage = __('no description'); - } - $ins_query = 'INSERT INTO ' - . Util::backquote($GLOBALS['cfgRelation']['db']) . '.' - . Util::backquote($cfgRelation['pdf_pages']) - . ' (db_name, page_descr)' - . ' VALUES (\'' - . $this->dbi->escapeString($db) . '\', \'' - . $this->dbi->escapeString($newpage) . '\')'; - $this->queryAsControlUser($ins_query, false); - - return $this->dbi->insertId(DatabaseInterface::CONNECT_CONTROL); - } - - /** - * Get child table references for a table column. - * This works only if 'DisableIS' is false. An empty array is returned otherwise. - * - * @param string $db name of master table db. - * @param string $table name of master table. - * @param string $column name of master table column. - * - * @return array - */ - public function getChildReferences($db, $table, $column = '') - { - $child_references = []; - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $rel_query = "SELECT `column_name`, `table_name`," - . " `table_schema`, `referenced_column_name`" - . " FROM `information_schema`.`key_column_usage`" - . " WHERE `referenced_table_name` = '" - . $this->dbi->escapeString($table) . "'" - . " AND `referenced_table_schema` = '" - . $this->dbi->escapeString($db) . "'"; - if ($column) { - $rel_query .= " AND `referenced_column_name` = '" - . $this->dbi->escapeString($column) . "'"; - } - - $child_references = $this->dbi->fetchResult( - $rel_query, - [ - 'referenced_column_name', - null, - ] - ); - } - return $child_references; - } - - /** - * Check child table references and foreign key for a table column. - * - * @param string $db name of master table db. - * @param string $table name of master table. - * @param string $column name of master table column. - * @param array|null $foreigners_full foreiners array for the whole table. - * @param array|null $child_references_full child references for the whole table. - * - * @return array telling about references if foreign key. - */ - public function checkChildForeignReferences( - $db, - $table, - $column, - $foreigners_full = null, - $child_references_full = null - ) { - $column_status = []; - $column_status['isEditable'] = false; - $column_status['isReferenced'] = false; - $column_status['isForeignKey'] = false; - $column_status['references'] = []; - - $foreigners = []; - if ($foreigners_full !== null) { - if (isset($foreigners_full[$column])) { - $foreigners[$column] = $foreigners_full[$column]; - } - if (isset($foreigners_full['foreign_keys_data'])) { - $foreigners['foreign_keys_data'] = $foreigners_full['foreign_keys_data']; - } - } else { - $foreigners = $this->getForeigners($db, $table, $column, 'foreign'); - } - $foreigner = $this->searchColumnInForeigners($foreigners, $column); - - $child_references = []; - if ($child_references_full !== null) { - if (isset($child_references_full[$column])) { - $child_references = $child_references_full[$column]; - } - } else { - $child_references = $this->getChildReferences($db, $table, $column); - } - - if (count($child_references) > 0 - || $foreigner - ) { - if (count($child_references) > 0) { - $column_status['isReferenced'] = true; - foreach ($child_references as $columns) { - $column_status['references'][] = Util::backquote($columns['table_schema']) - . '.' . Util::backquote($columns['table_name']); - } - } - - if ($foreigner) { - $column_status['isForeignKey'] = true; - } - } else { - $column_status['isEditable'] = true; - } - - return $column_status; - } - - /** - * Search a table column in foreign data. - * - * @param array $foreigners Table Foreign data - * @param string $column Column name - * - * @return bool|array - */ - public function searchColumnInForeigners(array $foreigners, $column) - { - if (isset($foreigners[$column])) { - return $foreigners[$column]; - } - - $foreigner = []; - foreach ($foreigners['foreign_keys_data'] as $one_key) { - $column_index = array_search($column, $one_key['index_list']); - if ($column_index !== false) { - $foreigner['foreign_field'] - = $one_key['ref_index_list'][$column_index]; - $foreigner['foreign_db'] = isset($one_key['ref_db_name']) - ? $one_key['ref_db_name'] - : $GLOBALS['db']; - $foreigner['foreign_table'] = $one_key['ref_table_name']; - $foreigner['constraint'] = $one_key['constraint']; - $foreigner['on_update'] = isset($one_key['on_update']) - ? $one_key['on_update'] - : 'RESTRICT'; - $foreigner['on_delete'] = isset($one_key['on_delete']) - ? $one_key['on_delete'] - : 'RESTRICT'; - - return $foreigner; - } - } - - return false; - } - - /** - * Returns default PMA table names and their create queries. - * - * @return array table name, create query - */ - public function getDefaultPmaTableNames() - { - $pma_tables = []; - $create_tables_file = file_get_contents( - SQL_DIR . 'create_tables.sql' - ); - - $queries = explode(';', $create_tables_file); - - foreach ($queries as $query) { - if (preg_match( - '/CREATE TABLE IF NOT EXISTS `(.*)` \(/', - $query, - $table - ) - ) { - $pma_tables[$table[1]] = $query . ';'; - } - } - - return $pma_tables; - } - - /** - * Create a table named phpmyadmin to be used as configuration storage - * - * @return bool - */ - public function createPmaDatabase() - { - $this->dbi->tryQuery("CREATE DATABASE IF NOT EXISTS `phpmyadmin`"); - if ($error = $this->dbi->getError()) { - if ($GLOBALS['errno'] == 1044) { - $GLOBALS['message'] = __( - 'You do not have necessary privileges to create a database named' - . ' \'phpmyadmin\'. You may go to \'Operations\' tab of any' - . ' database to set up the phpMyAdmin configuration storage there.' - ); - } else { - $GLOBALS['message'] = $error; - } - return false; - } - return true; - } - - /** - * Creates PMA tables in the given db, updates if already exists. - * - * @param string $db database - * @param boolean $create whether to create tables if they don't exist. - * - * @return void - */ - public function fixPmaTables($db, $create = true) - { - $tablesToFeatures = [ - 'pma__bookmark' => 'bookmarktable', - 'pma__relation' => 'relation', - 'pma__table_info' => 'table_info', - 'pma__table_coords' => 'table_coords', - 'pma__pdf_pages' => 'pdf_pages', - 'pma__column_info' => 'column_info', - 'pma__history' => 'history', - 'pma__recent' => 'recent', - 'pma__favorite' => 'favorite', - 'pma__table_uiprefs' => 'table_uiprefs', - 'pma__tracking' => 'tracking', - 'pma__userconfig' => 'userconfig', - 'pma__users' => 'users', - 'pma__usergroups' => 'usergroups', - 'pma__navigationhiding' => 'navigationhiding', - 'pma__savedsearches' => 'savedsearches', - 'pma__central_columns' => 'central_columns', - 'pma__designer_settings' => 'designer_settings', - 'pma__export_templates' => 'export_templates', - ]; - - $existingTables = $this->dbi->getTables($db, DatabaseInterface::CONNECT_CONTROL); - - $createQueries = null; - $foundOne = false; - foreach ($tablesToFeatures as $table => $feature) { - if (! in_array($table, $existingTables)) { - if ($create) { - if ($createQueries == null) { // first create - $createQueries = $this->getDefaultPmaTableNames(); - $this->dbi->selectDb($db); - } - $this->dbi->tryQuery($createQueries[$table]); - if ($error = $this->dbi->getError()) { - $GLOBALS['message'] = $error; - return; - } - $foundOne = true; - $GLOBALS['cfg']['Server'][$feature] = $table; - } - } else { - $foundOne = true; - $GLOBALS['cfg']['Server'][$feature] = $table; - } - } - - if (! $foundOne) { - return; - } - $GLOBALS['cfg']['Server']['pmadb'] = $db; - $_SESSION['relation'][$GLOBALS['server']] = $this->checkRelationsParam(); - - $cfgRelation = $this->getRelationsParam(); - if ($cfgRelation['recentwork'] || $cfgRelation['favoritework']) { - // Since configuration storage is updated, we need to - // re-initialize the favorite and recent tables stored in the - // session from the current configuration storage. - if ($cfgRelation['favoritework']) { - $fav_tables = RecentFavoriteTable::getInstance('favorite'); - $_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] - = $fav_tables->getFromDb(); - } - - if ($cfgRelation['recentwork']) { - $recent_tables = RecentFavoriteTable::getInstance('recent'); - $_SESSION['tmpval']['recentTables'][$GLOBALS['server']] - = $recent_tables->getFromDb(); - } - - // Reload navi panel to update the recent/favorite lists. - $GLOBALS['reload'] = true; - } - } - - /** - * Get Html for PMA tables fixing anchor. - * - * @param boolean $allTables whether to create all tables - * @param boolean $createDb whether to create the pmadb also - * - * @return string Html - */ - public function getHtmlFixPmaTables($allTables, $createDb = false) - { - $retval = ''; - - $url_query = Url::getCommon(['db' => $GLOBALS['db']], ''); - if ($allTables) { - if ($createDb) { - $url_query .= '&goto=db_operations.php&create_pmadb=1'; - $message = Message::notice( - __( - '%sCreate%s a database named \'phpmyadmin\' and setup ' - . 'the phpMyAdmin configuration storage there.' - ) - ); - } else { - $url_query .= '&goto=db_operations.php&fixall_pmadb=1'; - $message = Message::notice( - __( - '%sCreate%s the phpMyAdmin configuration storage in the ' - . 'current database.' - ) - ); - } - } else { - $url_query .= '&goto=db_operations.php&fix_pmadb=1'; - $message = Message::notice( - __('%sCreate%s missing phpMyAdmin configuration storage tables.') - ); - } - $message->addParamHtml(''); - $message->addParamHtml(''); - - $retval .= $message->getDisplay(); - - return $retval; - } - - /** - * Gets the relations info and status, depending on the condition - * - * @param boolean $condition whether to look for foreigners or not - * @param string $db database name - * @param string $table table name - * - * @return array ($res_rel, $have_rel) - */ - public function getRelationsAndStatus($condition, $db, $table) - { - if ($condition) { - // Find which tables are related with the current one and write it in - // an array - $res_rel = $this->getForeigners($db, $table); - - if (count($res_rel) > 0) { - $have_rel = true; - } else { - $have_rel = false; - } - } else { - $have_rel = false; - $res_rel = []; - } // end if - return [ - $res_rel, - $have_rel, - ]; - } - - /** - * Verifies if all the pmadb tables are defined - * - * @return boolean - */ - public function arePmadbTablesDefined() - { - return ! (empty($GLOBALS['cfg']['Server']['bookmarktable']) - || empty($GLOBALS['cfg']['Server']['relation']) - || empty($GLOBALS['cfg']['Server']['table_info']) - || empty($GLOBALS['cfg']['Server']['table_coords']) - || empty($GLOBALS['cfg']['Server']['column_info']) - || empty($GLOBALS['cfg']['Server']['pdf_pages']) - || empty($GLOBALS['cfg']['Server']['history']) - || empty($GLOBALS['cfg']['Server']['recent']) - || empty($GLOBALS['cfg']['Server']['favorite']) - || empty($GLOBALS['cfg']['Server']['table_uiprefs']) - || empty($GLOBALS['cfg']['Server']['tracking']) - || empty($GLOBALS['cfg']['Server']['userconfig']) - || empty($GLOBALS['cfg']['Server']['users']) - || empty($GLOBALS['cfg']['Server']['usergroups']) - || empty($GLOBALS['cfg']['Server']['navigationhiding']) - || empty($GLOBALS['cfg']['Server']['savedsearches']) - || empty($GLOBALS['cfg']['Server']['central_columns']) - || empty($GLOBALS['cfg']['Server']['designer_settings']) - || empty($GLOBALS['cfg']['Server']['export_templates'])); - } - - /** - * Get tables for foreign key constraint - * - * @param string $foreignDb Database name - * @param string $tblStorageEngine Table storage engine - * - * @return array Table names - */ - public function getTables($foreignDb, $tblStorageEngine) - { - $tables = []; - $tablesRows = $this->dbi->query( - 'SHOW TABLE STATUS FROM ' . Util::backquote($foreignDb), - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - while ($row = $this->dbi->fetchRow($tablesRows)) { - if (isset($row[1]) && mb_strtoupper($row[1]) == $tblStorageEngine) { - $tables[] = $row[0]; - } - } - if ($GLOBALS['cfg']['NaturalOrder']) { - usort($tables, 'strnatcasecmp'); - } - return $tables; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/RelationCleanup.php b/srcs/phpmyadmin/libraries/classes/RelationCleanup.php deleted file mode 100644 index ce98ee4..0000000 --- a/srcs/phpmyadmin/libraries/classes/RelationCleanup.php +++ /dev/null @@ -1,392 +0,0 @@ -dbi = $dbi; - $this->relation = $relation; - } - - /** - * Cleanup column related relation stuff - * - * @param string $db database name - * @param string $table table name - * @param string $column column name - * - * @return void - */ - public function column($db, $table, $column) - { - $cfgRelation = $this->relation->getRelationsParam(); - - if ($cfgRelation['commwork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['column_info']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\'' - . ' AND table_name = \'' . $this->dbi->escapeString($table) - . '\'' - . ' AND column_name = \'' . $this->dbi->escapeString($column) - . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['displaywork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['table_info']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\'' - . ' AND table_name = \'' . $this->dbi->escapeString($table) - . '\'' - . ' AND display_field = \'' . $this->dbi->escapeString($column) - . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['relwork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['relation']) - . ' WHERE master_db = \'' . $this->dbi->escapeString($db) - . '\'' - . ' AND master_table = \'' . $this->dbi->escapeString($table) - . '\'' - . ' AND master_field = \'' . $this->dbi->escapeString($column) - . '\''; - $this->relation->queryAsControlUser($remove_query); - - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['relation']) - . ' WHERE foreign_db = \'' . $this->dbi->escapeString($db) - . '\'' - . ' AND foreign_table = \'' . $this->dbi->escapeString($table) - . '\'' - . ' AND foreign_field = \'' . $this->dbi->escapeString($column) - . '\''; - $this->relation->queryAsControlUser($remove_query); - } - } - - /** - * Cleanup table related relation stuff - * - * @param string $db database name - * @param string $table table name - * - * @return void - */ - public function table($db, $table) - { - $cfgRelation = $this->relation->getRelationsParam(); - - if ($cfgRelation['commwork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['column_info']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\'' - . ' AND table_name = \'' . $this->dbi->escapeString($table) - . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['displaywork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['table_info']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\'' - . ' AND table_name = \'' . $this->dbi->escapeString($table) - . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['pdfwork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['table_coords']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\'' - . ' AND table_name = \'' . $this->dbi->escapeString($table) - . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['relwork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['relation']) - . ' WHERE master_db = \'' . $this->dbi->escapeString($db) - . '\'' - . ' AND master_table = \'' . $this->dbi->escapeString($table) - . '\''; - $this->relation->queryAsControlUser($remove_query); - - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['relation']) - . ' WHERE foreign_db = \'' . $this->dbi->escapeString($db) - . '\'' - . ' AND foreign_table = \'' . $this->dbi->escapeString($table) - . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['uiprefswork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['table_uiprefs']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\'' - . ' AND table_name = \'' . $this->dbi->escapeString($table) - . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['navwork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['navigationhiding']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\'' - . ' AND (table_name = \'' . $this->dbi->escapeString($table) - . '\'' - . ' OR (item_name = \'' . $this->dbi->escapeString($table) - . '\'' - . ' AND item_type = \'table\'))'; - $this->relation->queryAsControlUser($remove_query); - } - } - - /** - * Cleanup database related relation stuff - * - * @param string $db database name - * - * @return void - */ - public function database($db) - { - $cfgRelation = $this->relation->getRelationsParam(); - - if ($cfgRelation['commwork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['column_info']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['bookmarkwork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['bookmark']) - . ' WHERE dbase = \'' . $this->dbi->escapeString($db) . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['displaywork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['table_info']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['pdfwork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['pdf_pages']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\''; - $this->relation->queryAsControlUser($remove_query); - - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['table_coords']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['relwork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['relation']) - . ' WHERE master_db = \'' - . $this->dbi->escapeString($db) . '\''; - $this->relation->queryAsControlUser($remove_query); - - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['relation']) - . ' WHERE foreign_db = \'' . $this->dbi->escapeString($db) - . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['uiprefswork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['table_uiprefs']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['navwork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['navigationhiding']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['savedsearcheswork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['savedsearches']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\''; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['centralcolumnswork']) { - $remove_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['central_columns']) - . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\''; - $this->relation->queryAsControlUser($remove_query); - } - } - - /** - * Cleanup user related relation stuff - * - * @param string $username username - * - * @return void - */ - public function user($username) - { - $cfgRelation = $this->relation->getRelationsParam(); - - if ($cfgRelation['bookmarkwork']) { - $remove_query = "DELETE FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['bookmark']) - . " WHERE `user` = '" . $this->dbi->escapeString($username) - . "'"; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['historywork']) { - $remove_query = "DELETE FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['history']) - . " WHERE `username` = '" . $this->dbi->escapeString($username) - . "'"; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['recentwork']) { - $remove_query = "DELETE FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['recent']) - . " WHERE `username` = '" . $this->dbi->escapeString($username) - . "'"; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['favoritework']) { - $remove_query = "DELETE FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['favorite']) - . " WHERE `username` = '" . $this->dbi->escapeString($username) - . "'"; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['uiprefswork']) { - $remove_query = "DELETE FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['table_uiprefs']) - . " WHERE `username` = '" . $this->dbi->escapeString($username) - . "'"; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['userconfigwork']) { - $remove_query = "DELETE FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['userconfig']) - . " WHERE `username` = '" . $this->dbi->escapeString($username) - . "'"; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['menuswork']) { - $remove_query = "DELETE FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['users']) - . " WHERE `username` = '" . $this->dbi->escapeString($username) - . "'"; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['navwork']) { - $remove_query = "DELETE FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['navigationhiding']) - . " WHERE `username` = '" . $this->dbi->escapeString($username) - . "'"; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['savedsearcheswork']) { - $remove_query = "DELETE FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['savedsearches']) - . " WHERE `username` = '" . $this->dbi->escapeString($username) - . "'"; - $this->relation->queryAsControlUser($remove_query); - } - - if ($cfgRelation['designersettingswork']) { - $remove_query = "DELETE FROM " - . Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['designer_settings']) - . " WHERE `username` = '" . $this->dbi->escapeString($username) - . "'"; - $this->relation->queryAsControlUser($remove_query); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Replication.php b/srcs/phpmyadmin/libraries/classes/Replication.php deleted file mode 100644 index 4fa68f2..0000000 --- a/srcs/phpmyadmin/libraries/classes/Replication.php +++ /dev/null @@ -1,190 +0,0 @@ -tryQuery($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 string output of CHANGE MASTER mysql command - */ - public function slaveChangeMaster( - $user, - $password, - $host, - $port, - array $pos, - $stop = true, - $start = true, - $link = null - ) { - if ($stop) { - $this->slaveControl("STOP", null, $link); - } - - $out = $GLOBALS['dbi']->tryQuery( - '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) { - $this->slaveControl("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 mysql link on success - */ - public function connectToMaster( - $user, - $password, - $host = null, - $port = null, - $socket = null - ) { - $server = []; - $server['user'] = $user; - $server['password'] = $password; - $server["host"] = Core::sanitizeMySQLHost($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 $GLOBALS['dbi']->connect(DatabaseInterface::CONNECT_AUXILIARY, $server); - } - - /** - * 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 slaveChangeMaster() - */ - public function slaveBinLogMaster($link = null) - { - $data = $GLOBALS['dbi']->fetchResult('SHOW MASTER STATUS', null, null, $link); - $output = []; - - if (! empty($data)) { - $output["File"] = $data[0]["File"]; - $output["Position"] = $data[0]["Position"]; - } - return $output; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/ReplicationGui.php b/srcs/phpmyadmin/libraries/classes/ReplicationGui.php deleted file mode 100644 index a6cbf58..0000000 --- a/srcs/phpmyadmin/libraries/classes/ReplicationGui.php +++ /dev/null @@ -1,602 +0,0 @@ -replication = $replication; - $this->template = $template; - } - - /** - * returns HTML for error message - * - * @return string HTML code - */ - public function getHtmlForErrorMessage() - { - $html = ''; - if (isset($_SESSION['replication']['sr_action_status']) - && isset($_SESSION['replication']['sr_action_info']) - ) { - if ($_SESSION['replication']['sr_action_status'] == 'error') { - $error_message = $_SESSION['replication']['sr_action_info']; - $html .= Message::error($error_message)->getDisplay(); - $_SESSION['replication']['sr_action_status'] = 'unknown'; - } elseif ($_SESSION['replication']['sr_action_status'] == 'success') { - $success_message = $_SESSION['replication']['sr_action_info']; - $html .= Message::success($success_message)->getDisplay(); - $_SESSION['replication']['sr_action_status'] = 'unknown'; - } - } - return $html; - } - - /** - * returns HTML for master replication - * - * @return string HTML code - */ - public function getHtmlForMasterReplication() - { - if (! isset($_POST['repl_clear_scr'])) { - $masterStatusTable = $this->getHtmlForReplicationStatusTable('master', true, false); - $slaves = $GLOBALS['dbi']->fetchResult('SHOW SLAVE HOSTS', null, null); - - $urlParams = $GLOBALS['url_params']; - $urlParams['mr_adduser'] = true; - $urlParams['repl_clear_scr'] = true; - } - - if (isset($_POST['mr_adduser'])) { - $masterAddSlaveUser = $this->getHtmlForReplicationMasterAddSlaveUser(); - } - - return $this->template->render('server/replication/master_replication', [ - 'clear_screen' => isset($_POST['repl_clear_scr']), - 'master_status_table' => $masterStatusTable ?? '', - 'slaves' => $slaves ?? [], - 'url_params' => $urlParams ?? [], - 'master_add_user' => isset($_POST['mr_adduser']), - 'master_add_slave_user' => $masterAddSlaveUser ?? '', - ]); - } - - /** - * returns HTML for master replication configuration - * - * @return string HTML code - */ - public function getHtmlForMasterConfiguration() - { - $databaseMultibox = $this->getHtmlForReplicationDbMultibox(); - - return $this->template->render('server/replication/master_configuration', [ - 'database_multibox' => $databaseMultibox, - ]); - } - - /** - * returns HTML for slave replication configuration - * - * @param bool $serverSlaveStatus Whether it is Master or Slave - * @param array $serverSlaveReplication Slave replication - * - * @return string HTML code - */ - public function getHtmlForSlaveConfiguration( - $serverSlaveStatus, - array $serverSlaveReplication - ) { - $serverSlaveMultiReplication = $GLOBALS['dbi']->fetchResult( - 'SHOW ALL SLAVES STATUS' - ); - if ($serverSlaveStatus) { - $urlParams = $GLOBALS['url_params']; - $urlParams['sr_take_action'] = true; - $urlParams['sr_slave_server_control'] = true; - - if ($serverSlaveReplication[0]['Slave_IO_Running'] == 'No') { - $urlParams['sr_slave_action'] = 'start'; - } else { - $urlParams['sr_slave_action'] = 'stop'; - } - - $urlParams['sr_slave_control_parm'] = 'IO_THREAD'; - $slaveControlIoLink = Url::getCommon($urlParams, ''); - - if ($serverSlaveReplication[0]['Slave_SQL_Running'] == 'No') { - $urlParams['sr_slave_action'] = 'start'; - } else { - $urlParams['sr_slave_action'] = 'stop'; - } - - $urlParams['sr_slave_control_parm'] = 'SQL_THREAD'; - $slaveControlSqlLink = Url::getCommon($urlParams, ''); - - if ($serverSlaveReplication[0]['Slave_IO_Running'] == 'No' - || $serverSlaveReplication[0]['Slave_SQL_Running'] == 'No' - ) { - $urlParams['sr_slave_action'] = 'start'; - } else { - $urlParams['sr_slave_action'] = 'stop'; - } - - $urlParams['sr_slave_control_parm'] = null; - $slaveControlFullLink = Url::getCommon($urlParams, ''); - - $urlParams['sr_slave_action'] = 'reset'; - $slaveControlResetLink = Url::getCommon($urlParams, ''); - - $urlParams = $GLOBALS['url_params']; - $urlParams['sr_take_action'] = true; - $urlParams['sr_slave_skip_error'] = true; - $slaveSkipErrorLink = Url::getCommon($urlParams, ''); - - $urlParams = $GLOBALS['url_params']; - $urlParams['sl_configure'] = true; - $urlParams['repl_clear_scr'] = true; - - $reconfigureMasterLink = Url::getCommon($urlParams, ''); - - $slaveStatusTable = $this->getHtmlForReplicationStatusTable('slave', true, false); - - $slaveIoRunning = $serverSlaveReplication[0]['Slave_IO_Running'] !== 'No'; - $slaveSqlRunning = $serverSlaveReplication[0]['Slave_SQL_Running'] !== 'No'; - } - - return $this->template->render('server/replication/slave_configuration', [ - 'server_slave_multi_replication' => $serverSlaveMultiReplication, - 'url_params' => $GLOBALS['url_params'], - 'master_connection' => $_POST['master_connection'] ?? '', - 'server_slave_status' => $serverSlaveStatus, - 'slave_status_table' => $slaveStatusTable ?? '', - 'slave_sql_running' => $slaveSqlRunning ?? false, - 'slave_io_running' => $slaveIoRunning ?? false, - 'slave_control_full_link' => $slaveControlFullLink ?? '', - 'slave_control_reset_link' => $slaveControlResetLink ?? '', - 'slave_control_sql_link' => $slaveControlSqlLink ?? '', - 'slave_control_io_link' => $slaveControlIoLink ?? '', - 'slave_skip_error_link' => $slaveSkipErrorLink ?? '', - 'reconfigure_master_link' => $reconfigureMasterLink ?? '', - 'has_slave_configure' => isset($_POST['sl_configure']), - ]); - } - - /** - * returns HTML code for selecting databases - * - * @return string HTML code - */ - public function getHtmlForReplicationDbMultibox() - { - $databases = []; - foreach ($GLOBALS['dblist']->databases as $database) { - if (! $GLOBALS['dbi']->isSystemSchema($database)) { - $databases[] = $database; - } - } - - return $this->template->render('server/replication/database_multibox', [ - 'databases' => $databases, - ]); - } - - /** - * returns HTML for changing master - * - * @param string $submitName submit button name - * - * @return string HTML code - */ - public function getHtmlForReplicationChangeMaster($submitName) - { - list( - $usernameLength, - $hostnameLength - ) = $this->getUsernameHostnameLength(); - - return $this->template->render('server/replication/change_master', [ - 'server_id' => time(), - 'username_length' => $usernameLength, - 'hostname_length' => $hostnameLength, - 'submit_name' => $submitName, - ]); - } - - /** - * This function returns html code for table with replication status. - * - * @param string $type either master or slave - * @param boolean $isHidden if true, then default style is set to hidden, - * default value false - * @param boolean $hasTitle if true, then title is displayed, default true - * - * @return string HTML code - */ - public function getHtmlForReplicationStatusTable( - $type, - $isHidden = false, - $hasTitle = true - ): string { - global $master_variables, $slave_variables; - global $master_variables_alerts, $slave_variables_alerts; - global $master_variables_oks, $slave_variables_oks; - global $server_master_replication, $server_slave_replication; - - $replicationVariables = $master_variables; - $variablesAlerts = $master_variables_alerts; - $variablesOks = $master_variables_oks; - $serverReplication = $server_master_replication; - if ($type === 'slave') { - $replicationVariables = $slave_variables; - $variablesAlerts = $slave_variables_alerts; - $variablesOks = $slave_variables_oks; - $serverReplication = $server_slave_replication; - } - - $variables = []; - foreach ($replicationVariables as $variable) { - $serverReplicationVariable = is_array($serverReplication) && isset($serverReplication[0]) ? $serverReplication[0][$variable] : ''; - - $variables[$variable] = [ - 'name' => $variable, - 'status' => '', - 'value' => $serverReplicationVariable, - ]; - - if (isset($variablesAlerts[$variable]) - && $variablesAlerts[$variable] === $serverReplicationVariable - ) { - $variables[$variable]['status'] = 'attention'; - } elseif (isset($variablesOks[$variable]) - && $variablesOks[$variable] === $serverReplicationVariable - ) { - $variables[$variable]['status'] = 'allfine'; - } - - $variablesWrap = [ - 'Replicate_Do_DB', - 'Replicate_Ignore_DB', - 'Replicate_Do_Table', - 'Replicate_Ignore_Table', - 'Replicate_Wild_Do_Table', - 'Replicate_Wild_Ignore_Table', - ]; - if (in_array($variable, $variablesWrap)) { - $variables[$variable]['value'] = str_replace( - ',', - ', ', - $serverReplicationVariable - ); - } - } - - return $this->template->render('server/replication/status_table', [ - 'type' => $type, - 'is_hidden' => $isHidden, - 'has_title' => $hasTitle, - 'variables' => $variables, - ]); - } - - /** - * get the correct username and hostname lengths for this MySQL server - * - * @return array username length, hostname length - */ - public function getUsernameHostnameLength() - { - $fields_info = $GLOBALS['dbi']->getColumns('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 [ - $username_length, - $hostname_length, - ]; - } - - /** - * returns html code to add a replication slave user to the master - * - * @return string HTML code - */ - public function getHtmlForReplicationMasterAddSlaveUser() - { - list( - $usernameLength, - $hostnameLength - ) = $this->getUsernameHostnameLength(); - - if (isset($_POST['username']) && strlen($_POST['username']) === 0) { - $GLOBALS['pred_username'] = 'any'; - } - - $username = ''; - if (! empty($_POST['username'])) { - $username = $GLOBALS['new_username'] ?? $_POST['username']; - } - - $currentUser = $GLOBALS['dbi']->fetchValue('SELECT USER();'); - if (! empty($currentUser)) { - $userHost = str_replace( - "'", - '', - mb_substr( - $currentUser, - mb_strrpos($currentUser, '@') + 1 - ) - ); - if ($userHost !== 'localhost' && $userHost !== '127.0.0.1') { - $thisHost = $userHost; - } - } - - // when we start editing a user, $GLOBALS['pred_hostname'] is not defined - if (! isset($GLOBALS['pred_hostname']) && isset($_POST['hostname'])) { - switch (mb_strtolower($_POST['hostname'])) { - case 'localhost': - case '127.0.0.1': - $GLOBALS['pred_hostname'] = 'localhost'; - break; - case '%': - $GLOBALS['pred_hostname'] = 'any'; - break; - default: - $GLOBALS['pred_hostname'] = 'userdefined'; - break; - } - } - - return $this->template->render('server/replication/master_add_slave_user', [ - 'username_length' => $usernameLength, - 'hostname_length' => $hostnameLength, - 'has_username' => isset($_POST['username']), - 'username' => $username, - 'hostname' => $_POST['hostname'] ?? '', - 'predefined_username' => $GLOBALS['pred_username'] ?? '', - 'predefined_hostname' => $GLOBALS['pred_hostname'] ?? '', - 'this_host' => $thisHost ?? null, - ]); - } - - /** - * handle control requests - * - * @return void - */ - public function handleControlRequest() - { - if (isset($_POST['sr_take_action'])) { - $refresh = false; - $result = false; - $messageSuccess = null; - $messageError = null; - - if (isset($_POST['slave_changemaster']) && ! $GLOBALS['cfg']['AllowArbitraryServer']) { - $_SESSION['replication']['sr_action_status'] = 'error'; - $_SESSION['replication']['sr_action_info'] = __('Connection to server is disabled, please enable $cfg[\'AllowArbitraryServer\'] in phpMyAdmin configuration.'); - } elseif (isset($_POST['slave_changemaster'])) { - $result = $this->handleRequestForSlaveChangeMaster(); - } elseif (isset($_POST['sr_slave_server_control'])) { - $result = $this->handleRequestForSlaveServerControl(); - $refresh = true; - - switch ($_POST['sr_slave_action']) { - case 'start': - $messageSuccess = __('Replication started successfully.'); - $messageError = __('Error starting replication.'); - break; - case 'stop': - $messageSuccess = __('Replication stopped successfully.'); - $messageError = __('Error stopping replication.'); - break; - case 'reset': - $messageSuccess = __('Replication resetting successfully.'); - $messageError = __('Error resetting replication.'); - break; - default: - $messageSuccess = __('Success.'); - $messageError = __('Error.'); - break; - } - } elseif (isset($_POST['sr_slave_skip_error'])) { - $result = $this->handleRequestForSlaveSkipError(); - } - - if ($refresh) { - $response = Response::getInstance(); - if ($response->isAjax()) { - $response->setRequestStatus($result); - $response->addJSON( - 'message', - $result - ? Message::success($messageSuccess) - : Message::error($messageError) - ); - } else { - Core::sendHeaderLocation( - './server_replication.php' - . Url::getCommonRaw($GLOBALS['url_params']) - ); - } - } - unset($refresh); - } - } - - /** - * handle control requests for Slave Change Master - * - * @return boolean - */ - public function handleRequestForSlaveChangeMaster() - { - $sr = []; - $_SESSION['replication']['m_username'] = $sr['username'] - = $GLOBALS['dbi']->escapeString($_POST['username']); - $_SESSION['replication']['m_password'] = $sr['pma_pw'] - = $GLOBALS['dbi']->escapeString($_POST['pma_pw']); - $_SESSION['replication']['m_hostname'] = $sr['hostname'] - = $GLOBALS['dbi']->escapeString($_POST['hostname']); - $_SESSION['replication']['m_port'] = $sr['port'] - = $GLOBALS['dbi']->escapeString($_POST['text_port']); - $_SESSION['replication']['m_correct'] = ''; - $_SESSION['replication']['sr_action_status'] = 'error'; - $_SESSION['replication']['sr_action_info'] = __('Unknown error'); - - // Attempt to connect to the new master server - $link_to_master = $this->replication->connectToMaster( - $sr['username'], - $sr['pma_pw'], - $sr['hostname'], - $sr['port'] - ); - - if (! $link_to_master) { - $_SESSION['replication']['sr_action_status'] = 'error'; - $_SESSION['replication']['sr_action_info'] = sprintf( - __('Unable to connect to master %s.'), - htmlspecialchars($sr['hostname']) - ); - } else { - // Read the current master position - $position = $this->replication->slaveBinLogMaster($link_to_master); - - if (empty($position)) { - $_SESSION['replication']['sr_action_status'] = 'error'; - $_SESSION['replication']['sr_action_info'] - = __( - 'Unable to read master log position. ' - . 'Possible privilege problem on master.' - ); - } else { - $_SESSION['replication']['m_correct'] = true; - - if (! $this->replication->slaveChangeMaster( - $sr['username'], - $sr['pma_pw'], - $sr['hostname'], - $sr['port'], - $position, - true, - false - ) - ) { - $_SESSION['replication']['sr_action_status'] = 'error'; - $_SESSION['replication']['sr_action_info'] - = __('Unable to change master!'); - } else { - $_SESSION['replication']['sr_action_status'] = 'success'; - $_SESSION['replication']['sr_action_info'] = sprintf( - __('Master server changed successfully to %s.'), - htmlspecialchars($sr['hostname']) - ); - } - } - } - - return $_SESSION['replication']['sr_action_status'] === 'success'; - } - - /** - * handle control requests for Slave Server Control - * - * @return boolean - */ - public function handleRequestForSlaveServerControl() - { - if (empty($_POST['sr_slave_control_parm'])) { - $_POST['sr_slave_control_parm'] = null; - } - if ($_POST['sr_slave_action'] == 'reset') { - $qStop = $this->replication->slaveControl("STOP", null, DatabaseInterface::CONNECT_USER); - $qReset = $GLOBALS['dbi']->tryQuery("RESET SLAVE;"); - $qStart = $this->replication->slaveControl("START", null, DatabaseInterface::CONNECT_USER); - - $result = ($qStop !== false && $qStop !== -1 && - $qReset !== false && $qReset !== -1 && - $qStart !== false && $qStart !== -1); - } else { - $qControl = $this->replication->slaveControl( - $_POST['sr_slave_action'], - $_POST['sr_slave_control_parm'], - DatabaseInterface::CONNECT_USER - ); - - $result = ($qControl !== false && $qControl !== -1); - } - - return $result; - } - - /** - * handle control requests for Slave Skip Error - * - * @return boolean - */ - public function handleRequestForSlaveSkipError() - { - $count = 1; - if (isset($_POST['sr_skip_errors_count'])) { - $count = $_POST['sr_skip_errors_count'] * 1; - } - - $qStop = $this->replication->slaveControl("STOP", null, DatabaseInterface::CONNECT_USER); - $qSkip = $GLOBALS['dbi']->tryQuery( - "SET GLOBAL SQL_SLAVE_SKIP_COUNTER = " . $count . ";" - ); - $qStart = $this->replication->slaveControl("START", null, DatabaseInterface::CONNECT_USER); - - $result = ($qStop !== false && $qStop !== -1 && - $qSkip !== false && $qSkip !== -1 && - $qStart !== false && $qStart !== -1); - - return $result; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Response.php b/srcs/phpmyadmin/libraries/classes/Response.php deleted file mode 100644 index be9313b..0000000 --- a/srcs/phpmyadmin/libraries/classes/Response.php +++ /dev/null @@ -1,614 +0,0 @@ - - * @see http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml - */ - protected static $httpStatusMessages = [ - // Informational - 100 => 'Continue', - 101 => 'Switching Protocols', - 102 => 'Processing', - 103 => 'Early Hints', - // Success - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 207 => 'Multi-Status', - 208 => 'Already Reported', - 226 => 'IM Used', - // Redirection - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 307 => 'Temporary Redirect', - 308 => 'Permanent Redirect', - // Client Error - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Payload Too Large', - 414 => 'URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Range Not Satisfiable', - 417 => 'Expectation Failed', - 421 => 'Misdirected Request', - 422 => 'Unprocessable Entity', - 423 => 'Locked', - 424 => 'Failed Dependency', - 425 => 'Too Early', - 426 => 'Upgrade Required', - 427 => 'Unassigned', - 428 => 'Precondition Required', - 429 => 'Too Many Requests', - 430 => 'Unassigned', - 431 => 'Request Header Fields Too Large', - 451 => 'Unavailable For Legal Reasons', - // Server Error - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported', - 506 => 'Variant Also Negotiates', - 507 => 'Insufficient Storage', - 508 => 'Loop Detected', - 509 => 'Unassigned', - 510 => 'Not Extended', - 511 => 'Network Authentication Required', - ]; - - /** - * Creates a new class instance - */ - private function __construct() - { - if (! defined('TESTSUITE')) { - $buffer = OutputBuffering::getInstance(); - $buffer->start(); - register_shutdown_function([$this, 'response']); - } - $this->_header = new Header(); - $this->_HTML = ''; - $this->_JSON = []; - $this->_footer = new Footer(); - - $this->_isSuccess = true; - $this->_isDisabled = false; - $this->setAjax(! empty($_REQUEST['ajax_request'])); - $this->_CWD = getcwd(); - } - - /** - * Set the ajax flag to indicate whether - * we are servicing an ajax request - * - * @param bool $isAjax Whether we are servicing an ajax request - * - * @return void - */ - public function setAjax(bool $isAjax): void - { - $this->_isAjax = $isAjax; - $this->_header->setAjax($this->_isAjax); - $this->_footer->setAjax($this->_isAjax); - } - - /** - * Returns the singleton Response object - * - * @return Response object - */ - public static function getInstance() - { - if (empty(self::$_instance)) { - self::$_instance = new 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 setRequestStatus(bool $state): void - { - $this->_isSuccess = ($state === true); - } - - /** - * Returns true or false depending on whether - * we are servicing an ajax request - * - * @return bool - */ - public function isAjax(): bool - { - 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(); - $this->_isDisabled = true; - } - - /** - * Returns a PhpMyAdmin\Header object - * - * @return Header - */ - public function getHeader() - { - return $this->_header; - } - - /** - * Returns a PhpMyAdmin\Footer object - * - * @return Footer - */ - public function getFooter() - { - return $this->_footer; - } - - /** - * Add HTML code to the response - * - * @param string $content A string to be appended to - * the current output buffer - * - * @return void - */ - public function addHTML($content) - { - if (is_array($content)) { - foreach ($content as $msg) { - $this->addHTML($msg); - } - } elseif ($content instanceof 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 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 its 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() - { - /* Avoid wrapping in case we're disabled */ - if ($this->_isDisabled) { - echo $this->_getDisplay(); - return; - } - - if (! isset($this->_JSON['message'])) { - $this->_JSON['message'] = $this->_getDisplay(); - } elseif ($this->_JSON['message'] instanceof 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->_isSuccess) { - $this->addJSON('title', '' . $this->getHeader()->getPageTitle() . ''); - - if (isset($GLOBALS['dbi'])) { - $menuHash = $this->getHeader()->getMenu()->getHash(); - $this->addJSON('menuHash', $menuHash); - $hashes = []; - 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()); - $this->addJSON('displayMessage', $this->getHeader()->getMessage()); - - $debug = $this->_footer->getDebugMessage(); - if (empty($_REQUEST['no_debug']) - && strlen($debug) > 0 - ) { - $this->addJSON('debug', $debug); - } - - $errors = $this->_footer->getErrorMessages(); - if (strlen($errors) > 0) { - $this->addJSON('errors', $errors); - } - $promptPhpErrors = $GLOBALS['error_handler']->hasErrorsForPrompt(); - $this->addJSON('promptPhpErrors', $promptPhpErrors); - - if (empty($GLOBALS['error_message'])) { - // set current db, table and sql query in the querywindow - // (this is for the bottom console) - $query = ''; - $maxChars = $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']; - if (isset($GLOBALS['sql_query']) - && mb_strlen($GLOBALS['sql_query']) < $maxChars - ) { - $query = $GLOBALS['sql_query']; - } - $this->addJSON( - 'reloadQuerywindow', - [ - 'db' => Core::ifSetOr($GLOBALS['db'], ''), - 'table' => Core::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. - Core::headerJSON(); - - $result = json_encode($this->_JSON); - if ($result === false) { - switch (json_last_error()) { - case JSON_ERROR_NONE: - $error = 'No errors'; - break; - case JSON_ERROR_DEPTH: - $error = 'Maximum stack depth exceeded'; - break; - case JSON_ERROR_STATE_MISMATCH: - $error = 'Underflow or the modes mismatch'; - break; - case JSON_ERROR_CTRL_CHAR: - $error = 'Unexpected control character found'; - break; - case JSON_ERROR_SYNTAX: - $error = 'Syntax error, malformed JSON'; - break; - case JSON_ERROR_UTF8: - $error = 'Malformed UTF-8 characters, possibly incorrectly encoded'; - break; - case JSON_ERROR_RECURSION: - $error = 'One or more recursive references in the value to be encoded'; - break; - case JSON_ERROR_INF_OR_NAN: - $error = 'One or more NAN or INF values in the value to be encoded'; - break; - case JSON_ERROR_UNSUPPORTED_TYPE: - $error = 'A value of a type that cannot be encoded was given'; - break; - default: - $error = 'Unknown error'; - break; - } - echo json_encode([ - 'success' => false, - 'error' => 'JSON encoding failed: ' . $error, - ]); - } else { - echo $result; - } - } - - /** - * Sends an HTML response to the browser - * - * @return void - */ - public function response() - { - chdir($this->getCWD()); - $buffer = OutputBuffering::getInstance(); - if (empty($this->_HTML)) { - $this->_HTML = $buffer->getContents(); - } - if ($this->isAjax()) { - $this->_ajaxResponse(); - } else { - $this->_htmlResponse(); - } - $buffer->flush(); - exit; - } - - /** - * Wrapper around PHP's header() function. - * - * @param string $text header string - * - * @return void - */ - public function header($text) - { - header($text); - } - - /** - * Wrapper around PHP's headers_sent() function. - * - * @return bool - */ - public function headersSent() - { - return headers_sent(); - } - - /** - * Wrapper around PHP's http_response_code() function. - * - * @param int $response_code will set the response code. - * - * @return void - */ - public function httpResponseCode($response_code) - { - http_response_code($response_code); - } - - /** - * Sets http response code. - * - * @param int $responseCode will set the response code. - * - * @return void - */ - public function setHttpResponseCode(int $responseCode): void - { - $this->httpResponseCode($responseCode); - $header = 'status: ' . $responseCode . ' '; - if (isset(static::$httpStatusMessages[$responseCode])) { - $header .= static::$httpStatusMessages[$responseCode]; - } else { - $header .= 'Web server is down'; - } - if (PHP_SAPI !== 'cgi-fcgi') { - $this->header($header); - } - } - - /** - * Generate header for 303 - * - * @param string $location will set location to redirect. - * - * @return void - */ - public function generateHeader303($location) - { - $this->setHttpResponseCode(303); - $this->header('Location: ' . $location); - if (! defined('TESTSUITE')) { - exit; - } - } - - /** - * Configures response for the login page - * - * @return bool Whether caller should exit - */ - public function loginPage() - { - /* Handle AJAX redirection */ - if ($this->isAjax()) { - $this->setRequestStatus(false); - // redirect_flag redirects to the login page - $this->addJSON('redirect_flag', '1'); - return true; - } - - $this->getFooter()->setMinimal(); - $header = $this->getHeader(); - $header->setBodyId('loginform'); - $header->setTitle('phpMyAdmin'); - $header->disableMenuAndConsole(); - $header->disableWarnings(); - return false; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Rte/Events.php b/srcs/phpmyadmin/libraries/classes/Rte/Events.php deleted file mode 100644 index bb0d52b..0000000 --- a/srcs/phpmyadmin/libraries/classes/Rte/Events.php +++ /dev/null @@ -1,680 +0,0 @@ -dbi = $dbi; - $this->export = new Export($this->dbi); - $this->footer = new Footer($this->dbi); - $this->general = new General($this->dbi); - $this->rteList = new RteList($this->dbi); - $this->words = new Words(); - } - - /** - * Sets required globals - * - * @return void - */ - public function setGlobals() - { - global $event_status, $event_type, $event_interval; - - $event_status = [ - 'query' => [ - 'ENABLE', - 'DISABLE', - 'DISABLE ON SLAVE', - ], - 'display' => [ - 'ENABLED', - 'DISABLED', - 'SLAVESIDE_DISABLED', - ], - ]; - $event_type = [ - 'RECURRING', - 'ONE TIME', - ]; - $event_interval = [ - '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 - */ - public function main() - { - global $db; - - $this->setGlobals(); - /** - * Process all requests - */ - $this->handleEditor(); - $this->export->events(); - /** - * Display a list of available events - */ - $items = $this->dbi->getEvents($db); - echo $this->rteList->get('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 $this->footer->events(); - } - - /** - * Handles editor requests for adding or editing an item - * - * @return void - */ - public function handleEditor() - { - global $errors, $db; - - if (! empty($_POST['editor_process_add']) - || ! empty($_POST['editor_process_edit']) - ) { - $sql_query = ''; - - $item_query = $this->getQueryFromRequest(); - - if (! count($errors)) { // set by PhpMyAdmin\Rte\Routines::getQueryFromRequest() - // Execute the created query - if (! empty($_POST['editor_process_edit'])) { - // Backup the old trigger, in case something goes wrong - $create_item = $this->dbi->getDefinition( - $db, - 'EVENT', - $_POST['item_original_name'] - ); - $drop_item = "DROP EVENT " - . Util::backquote($_POST['item_original_name']) - . ";\n"; - $result = $this->dbi->tryQuery($drop_item); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($drop_item) - ) - . '
    ' - . __('MySQL said: ') . $this->dbi->getError(); - } else { - $result = $this->dbi->tryQuery($item_query); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($item_query) - ) - . '
    ' - . __('MySQL said: ') . $this->dbi->getError(); - // We dropped the old item, but were unable to create - // the new one. Try to restore the backup query - $result = $this->dbi->tryQuery($create_item); - $errors = $this->general->checkResult( - $result, - __( - 'Sorry, we failed to restore the dropped event.' - ), - $create_item, - $errors - ); - } else { - $message = Message::success( - __('Event %1$s has been modified.') - ); - $message->addParam( - Util::backquote($_POST['item_name']) - ); - $sql_query = $drop_item . $item_query; - } - } - } else { - // 'Add a new item' mode - $result = $this->dbi->tryQuery($item_query); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($item_query) - ) - . '

    ' - . __('MySQL said: ') . $this->dbi->getError(); - } else { - $message = Message::success( - __('Event %1$s has been created.') - ); - $message->addParam( - Util::backquote($_POST['item_name']) - ); - $sql_query = $item_query; - } - } - } - - if (count($errors)) { - $message = Message::error( - '' - . __( - 'One or more errors have occurred while processing your request:' - ) - . '' - ); - $message->addHtml('
      '); - foreach ($errors as $string) { - $message->addHtml('
    • ' . $string . '
    • '); - } - $message->addHtml('
    '); - } - - $output = Util::getMessage($message, $sql_query); - $response = Response::getInstance(); - if ($response->isAjax()) { - if ($message->isSuccess()) { - $events = $this->dbi->getEvents($db, $_POST['item_name']); - $event = $events[0]; - $response->addJSON( - 'name', - htmlspecialchars( - mb_strtoupper($_POST['item_name']) - ) - ); - if (! empty($event)) { - $response->addJSON('new_row', $this->rteList->getEventRow($event)); - } - $response->addJSON('insert', ! empty($event)); - $response->addJSON('message', $output); - } else { - $response->setRequestStatus(false); - $response->addJSON('message', $message); - } - exit; - } - } - /** - * Display a form used to add/edit a trigger, if necessary - */ - if (count($errors) - || (empty($_POST['editor_process_add']) - && empty($_POST['editor_process_edit']) - && (! empty($_REQUEST['add_item']) - || ! empty($_REQUEST['edit_item']) - || ! empty($_POST['item_changetype']))) - ) { // FIXME: this must be simpler than that - $operation = ''; - if (! empty($_POST['item_changetype'])) { - $operation = 'change'; - } - // Get the data for the form (if any) - if (! empty($_REQUEST['add_item'])) { - $title = $this->words->get('add'); - $item = $this->getDataFromRequest(); - $mode = 'add'; - } elseif (! empty($_REQUEST['edit_item'])) { - $title = __("Edit event"); - if (! empty($_REQUEST['item_name']) - && empty($_POST['editor_process_edit']) - && empty($_POST['item_changetype']) - ) { - $item = $this->getDataFromName($_REQUEST['item_name']); - if ($item !== false) { - $item['item_original_name'] = $item['item_name']; - } - } else { - $item = $this->getDataFromRequest(); - } - $mode = 'edit'; - } - $this->general->sendEditor('EVN', $mode, $item, $title, $db, $operation); - } - } - - /** - * This function will generate the values that are required to for the editor - * - * @return array Data necessary to create the editor. - */ - public function getDataFromRequest() - { - $retval = []; - $indices = [ - '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($_POST[$index]) ? $_POST[$index] : ''; - } - $retval['item_type'] = 'ONE TIME'; - $retval['item_type_toggle'] = 'RECURRING'; - if (isset($_POST['item_type']) && $_POST['item_type'] == 'RECURRING') { - $retval['item_type'] = 'RECURRING'; - $retval['item_type_toggle'] = 'ONE TIME'; - } - return $retval; - } - - /** - * 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|bool Data necessary to create the editor. - */ - public function getDataFromName($name) - { - global $db; - - $retval = []; - $columns = "`EVENT_NAME`, `STATUS`, `EVENT_TYPE`, `EXECUTE_AT`, " - . "`INTERVAL_VALUE`, `INTERVAL_FIELD`, `STARTS`, `ENDS`, " - . "`EVENT_DEFINITION`, `ON_COMPLETION`, `DEFINER`, `EVENT_COMMENT`"; - $where = "EVENT_SCHEMA " . Util::getCollateForIS() . "=" - . "'" . $this->dbi->escapeString($db) . "' " - . "AND EVENT_NAME='" . $this->dbi->escapeString($name) . "'"; - $query = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE $where;"; - $item = $this->dbi->fetchSingleRow($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; - } - - /** - * Displays a form used to add/edit an event - * - * @param string $mode If the editor will be used to 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 - * getDataFromRequest() or getDataFromName() - * - * @return string HTML code for the editor. - */ - public function getEditorForm($mode, $operation, array $item) - { - global $db, $table, $event_status, $event_type, $event_interval; - - $modeToUpper = mb_strtoupper($mode); - - $response = Response::getInstance(); - - // Escape special characters - $need_escape = [ - '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((string) $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 .= Url::getHiddenInputs($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 .= " "; - } - return $output; - } - - /** - * Creates the HTML code that shows the routine execution dialog. - * - * @param array $routine Data for the routine returned by - * getDataFromName() - * - * @return string HTML code for the routine execution dialog. - */ - public function getExecuteForm(array $routine) - { - global $db, $cfg; - - $response = Response::getInstance(); - - // 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 .= "isAjax()) { - $retval .= "{$routine['item_name']}\n"; - $retval .= "
    " . __('Event name') . "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "
    " . __('Event type') . "\n"; - if ($response->isAjax()) { - $retval .= " \n"; - } else { - $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 .= " isAjax()) { - $retval .= "\n"; - $retval .= "\n"; - } - $retval .= "\n\n"; - $retval .= "\n\n"; - - return $retval; - } - - /** - * Composes the query necessary to create an event from an HTTP request. - * - * @return string The CREATE EVENT query. - */ - public function getQueryFromRequest() - { - global $errors, $event_status, $event_type, $event_interval; - - $query = 'CREATE '; - if (! empty($_POST['item_definer'])) { - if (mb_strpos($_POST['item_definer'], '@') !== false - ) { - $arr = explode('@', $_POST['item_definer']); - $query .= 'DEFINER=' . Util::backquote($arr[0]); - $query .= '@' . Util::backquote($arr[1]) . ' '; - } else { - $errors[] = __('The definer must be in the "username@hostname" format!'); - } - } - $query .= 'EVENT '; - if (! empty($_POST['item_name'])) { - $query .= Util::backquote($_POST['item_name']) . ' '; - } else { - $errors[] = __('You must provide an event name!'); - } - $query .= 'ON SCHEDULE '; - if (! empty($_POST['item_type']) - && in_array($_POST['item_type'], $event_type) - ) { - if ($_POST['item_type'] == 'RECURRING') { - if (! empty($_POST['item_interval_value']) - && ! empty($_POST['item_interval_field']) - && in_array($_POST['item_interval_field'], $event_interval) - ) { - $query .= 'EVERY ' . intval($_POST['item_interval_value']) . ' '; - $query .= $_POST['item_interval_field'] . ' '; - } else { - $errors[] - = __('You must provide a valid interval value for the event.'); - } - if (! empty($_POST['item_starts'])) { - $query .= "STARTS '" - . $this->dbi->escapeString($_POST['item_starts']) - . "' "; - } - if (! empty($_POST['item_ends'])) { - $query .= "ENDS '" - . $this->dbi->escapeString($_POST['item_ends']) - . "' "; - } - } else { - if (! empty($_POST['item_execute_at'])) { - $query .= "AT '" - . $this->dbi->escapeString($_POST['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($_POST['item_preserve'])) { - $query .= 'NOT '; - } - $query .= 'PRESERVE '; - if (! empty($_POST['item_status'])) { - foreach ($event_status['display'] as $key => $value) { - if ($value == $_POST['item_status']) { - $query .= $event_status['query'][$key] . ' '; - break; - } - } - } - if (! empty($_POST['item_comment'])) { - $query .= "COMMENT '" . $this->dbi->escapeString( - $_POST['item_comment'] - ) . "' "; - } - $query .= 'DO '; - if (! empty($_POST['item_definition'])) { - $query .= $_POST['item_definition']; - } else { - $errors[] = __('You must provide an event definition.'); - } - - return $query; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Rte/Export.php b/srcs/phpmyadmin/libraries/classes/Rte/Export.php deleted file mode 100644 index 2ae19e6..0000000 --- a/srcs/phpmyadmin/libraries/classes/Rte/Export.php +++ /dev/null @@ -1,168 +0,0 @@ -dbi = $dbi; - $this->words = new Words(); - } - - /** - * This function is called from one of the other functions in this file - * and it completes the handling of the export functionality. - * - * @param string $export_data The SQL query to create the requested item - * - * @return void - */ - private function handle($export_data) - { - global $db; - - $response = Response::getInstance(); - - $item_name = htmlspecialchars(Util::backquote($_GET['item_name'])); - if ($export_data !== false) { - $export_data = htmlspecialchars(trim($export_data)); - $title = sprintf($this->words->get('export'), $item_name); - if ($response->isAjax()) { - $response->addJSON('message', $export_data); - $response->addJSON('title', $title); - exit; - } else { - $export_data = ''; - echo "
    \n" - , "$title\n" - , $export_data - , "
    \n"; - } - } else { - $_db = htmlspecialchars(Util::backquote($db)); - $message = __('Error in processing request:') . ' ' - . sprintf($this->words->get('no_view'), $item_name, $_db); - $message = Message::error($message); - - if ($response->isAjax()) { - $response->setRequestStatus(false); - $response->addJSON('message', $message); - exit; - } else { - $message->display(); - } - } - } - - /** - * If necessary, prepares event information and passes - * it to handle() for the actual export. - * - * @return void - */ - public function events() - { - global $db; - - if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) { - $item_name = $_GET['item_name']; - $export_data = $this->dbi->getDefinition($db, 'EVENT', $item_name); - if (! $export_data) { - $export_data = false; - } - $this->handle($export_data); - } - } - - /** - * If necessary, prepares routine information and passes - * it to handle() for the actual export. - * - * @return void - */ - public function routines() - { - global $db; - - if (! empty($_GET['export_item']) - && ! empty($_GET['item_name']) - && ! empty($_GET['item_type']) - ) { - if ($_GET['item_type'] == 'FUNCTION' || $_GET['item_type'] == 'PROCEDURE') { - $rtn_definition - = $this->dbi->getDefinition( - $db, - $_GET['item_type'], - $_GET['item_name'] - ); - if ($rtn_definition === null) { - $export_data = false; - } else { - $export_data = "DELIMITER $$\n" - . $rtn_definition - . "$$\nDELIMITER ;\n"; - } - - $this->handle($export_data); - } - } - } - - /** - * If necessary, prepares trigger information and passes - * it to handle() for the actual export. - * - * @return void - */ - public function triggers() - { - global $db, $table; - - if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) { - $item_name = $_GET['item_name']; - $triggers = $this->dbi->getTriggers($db, $table, ''); - $export_data = false; - foreach ($triggers as $trigger) { - if ($trigger['name'] === $item_name) { - $export_data = $trigger['create']; - break; - } - } - $this->handle($export_data); - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Rte/Footer.php b/srcs/phpmyadmin/libraries/classes/Rte/Footer.php deleted file mode 100644 index 5181b00..0000000 --- a/srcs/phpmyadmin/libraries/classes/Rte/Footer.php +++ /dev/null @@ -1,160 +0,0 @@ -dbi = $dbi; - $this->words = new Words(); - } - - /** - * Creates a fieldset for adding a new item, if the user has the privileges. - * - * @param string $docu String used to create a link to the MySQL docs - * @param string $priv Privilege to check for adding a new item - * @param string $name MySQL name of the item - * - * @return string An HTML snippet with the link to add a new item - */ - private function getLinks($docu, $priv, $name) - { - global $db, $table, $url_query; - - $icon = mb_strtolower($name) . '_add'; - $retval = ""; - $retval .= "\n"; - $retval .= "
    \n"; - $retval .= "" . _pgettext('Create new procedure', 'New') . "\n"; - $retval .= "
    \n"; - if (Util::currentUserHasPrivilege($priv, $db, $table)) { - $retval .= ' words->get('add') . "\n"; - } else { - $icon = 'bd_' . $icon; - $retval .= Util::getIcon($icon); - $retval .= $this->words->get('add') . "\n"; - } - $retval .= " " . Util::showMySQLDocu($docu) . "\n"; - $retval .= "
    \n"; - $retval .= "
    \n"; - $retval .= "\n\n"; - - return $retval; - } - - /** - * Creates a fieldset for adding a new routine, if the user has the privileges. - * - * @return string HTML code with containing the footer fieldset - */ - public function routines() - { - return $this->getLinks('CREATE_PROCEDURE', 'CREATE ROUTINE', 'ROUTINE'); - } - - /** - * Creates a fieldset for adding a new trigger, if the user has the privileges. - * - * @return string HTML code with containing the footer fieldset - */ - public function triggers() - { - return $this->getLinks('CREATE_TRIGGER', 'TRIGGER', 'TRIGGER'); - } - - /** - * Creates a fieldset for adding a new event, if the user has the privileges. - * - * @return string HTML code with containing the footer fieldset - */ - public function events() - { - 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 = $this->dbi->fetchValue( - "SHOW GLOBAL VARIABLES LIKE 'event_scheduler'", - 0, - 1 - ); - $es_state = mb_strtolower($es_state); - $options = [ - 0 => [ - 'label' => __('OFF'), - 'value' => "SET GLOBAL event_scheduler=\"OFF\"", - 'selected' => $es_state != 'on', - ], - 1 => [ - 'label' => __('ON'), - 'value' => "SET GLOBAL event_scheduler=\"ON\"", - 'selected' => $es_state == 'on', - ], - ]; - // Generate output - $retval = "\n"; - $retval .= "
    \n"; - // show the usual footer - $retval .= $this->getLinks('CREATE_EVENT', 'EVENT', 'EVENT'); - $retval .= "
    \n"; - $retval .= " \n"; - $retval .= " " . __('Event scheduler status') . "\n"; - $retval .= " \n"; - $retval .= "
    \n"; - // show the toggle button - $retval .= Util::toggleButton( - "sql.php$url_query&goto=db_events.php" . urlencode("?db=$db"), - 'sql_query', - $options, - 'Functions.slidingMessage(data.sql_query);' - ); - $retval .= "
    \n"; - $retval .= "
    \n"; - $retval .= "
    \n"; - $retval .= "
    "; - $retval .= "\n"; - - return $retval; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Rte/General.php b/srcs/phpmyadmin/libraries/classes/Rte/General.php deleted file mode 100644 index 37962b5..0000000 --- a/srcs/phpmyadmin/libraries/classes/Rte/General.php +++ /dev/null @@ -1,118 +0,0 @@ -dbi = $dbi; - } - - /** - * Check result - * - * @param resource|bool $result Query result - * @param string $error Error to add - * @param string $createStatement Query - * @param array $errors Errors - * - * @return array - */ - public function checkResult($result, $error, $createStatement, array $errors) - { - if ($result) { - return $errors; - } - - // 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[] = $error . '
    ' - . __('The backed up query was:') - . "\"" . htmlspecialchars($createStatement) . "\"" . '
    ' - . __('MySQL said: ') . $this->dbi->getError(); - - return $errors; - } - - /** - * Send TRI or EVN editor via ajax or by echoing. - * - * @param string $type TRI or EVN - * @param string $mode Editor mode 'add' or 'edit' - * @param array $item Data necessary to create the editor - * @param string $title Title of the editor - * @param string $db Database - * @param string $operation Operation 'change' or '' - * - * @return void - */ - public function sendEditor($type, $mode, array $item, $title, $db, $operation = null) - { - $events = new Events($this->dbi); - $triggers = new Triggers($this->dbi); - $words = new Words(); - $response = Response::getInstance(); - if ($item !== false) { - // Show form - if ($type == 'TRI') { - $editor = $triggers->getEditorForm($mode, $item); - } else { // EVN - $editor = $events->getEditorForm($mode, $operation, $item); - } - if ($response->isAjax()) { - $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( - $words->get('not_found'), - htmlspecialchars(Util::backquote($_REQUEST['item_name'])), - htmlspecialchars(Util::backquote($db)) - ); - $message = Message::error($message); - if ($response->isAjax()) { - $response->setRequestStatus(false); - $response->addJSON('message', $message); - exit; - } else { - $message->display(); - } - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Rte/Routines.php b/srcs/phpmyadmin/libraries/classes/Rte/Routines.php deleted file mode 100644 index 24b0dd5..0000000 --- a/srcs/phpmyadmin/libraries/classes/Rte/Routines.php +++ /dev/null @@ -1,1743 +0,0 @@ -dbi = $dbi; - $this->export = new Export($this->dbi); - $this->footer = new Footer($this->dbi); - $this->general = new General($this->dbi); - $this->rteList = new RteList($this->dbi); - $this->words = new Words(); - } - - /** - * Sets required globals - * - * @return void - */ - public function setGlobals() - { - global $param_directions, $param_opts_num, $param_sqldataaccess; - - $param_directions = [ - 'IN', - 'OUT', - 'INOUT', - ]; - $param_opts_num = [ - 'UNSIGNED', - 'ZEROFILL', - 'UNSIGNED ZEROFILL', - ]; - $param_sqldataaccess = [ - 'NO SQL', - 'CONTAINS SQL', - 'READS SQL DATA', - 'MODIFIES SQL DATA', - ]; - } - - /** - * Main function for the routines functionality - * - * @param string $type 'FUNCTION' for functions, - * 'PROCEDURE' for procedures, - * null for both - * - * @return void - */ - public function main($type) - { - global $db; - - $this->setGlobals(); - /** - * Process all requests - */ - $this->handleEditor(); - $this->handleExecute(); - $this->export->routines(); - /** - * Display a list of available routines - */ - if (! Core::isValid($type, ['FUNCTION', 'PROCEDURE'])) { - $type = null; - } - $items = $this->dbi->getRoutines($db, $type); - echo $this->rteList->get('routine', $items); - /** - * Display the form for adding a new routine, if the user has the privileges. - */ - echo $this->footer->routines(); - /** - * Display a warning for users with PHP's old "mysql" extension. - */ - if (! DatabaseInterface::checkDbExtension('mysqli')) { - trigger_error( - __( - 'You are using PHP\'s deprecated \'mysql\' extension, ' - . 'which is not capable of handling multi queries. ' - . '[strong]The execution of some stored routines may fail![/strong] ' - . 'Please use the improved \'mysqli\' extension to ' - . 'avoid any problems.' - ), - E_USER_WARNING - ); - } - } - - /** - * Handles editor requests for adding or editing an item - * - * @return void - */ - public function handleEditor() - { - global $db, $errors; - - $errors = $this->handleRequestCreateOrEdit($errors, $db); - $response = Response::getInstance(); - - /** - * Display a form used to add/edit a routine, if necessary - */ - // FIXME: this must be simpler than that - if (count($errors) - || ( empty($_POST['editor_process_add']) - && empty($_POST['editor_process_edit']) - && (! empty($_REQUEST['add_item']) || ! empty($_REQUEST['edit_item']) - || ! empty($_POST['routine_addparameter']) - || ! empty($_POST['routine_removeparameter']) - || ! empty($_POST['routine_changetype']))) - ) { - // Handle requests to add/remove parameters and changing routine type - // This is necessary when JS is disabled - $operation = ''; - if (! empty($_POST['routine_addparameter'])) { - $operation = 'add'; - } elseif (! empty($_POST['routine_removeparameter'])) { - $operation = 'remove'; - } elseif (! empty($_POST['routine_changetype'])) { - $operation = 'change'; - } - // Get the data for the form (if any) - if (! empty($_REQUEST['add_item'])) { - $title = $this->words->get('add'); - $routine = $this->getDataFromRequest(); - $mode = 'add'; - } elseif (! empty($_REQUEST['edit_item'])) { - $title = __("Edit routine"); - if (! $operation && ! empty($_GET['item_name']) - && empty($_POST['editor_process_edit']) - ) { - $routine = $this->getDataFromName( - $_GET['item_name'], - $_GET['item_type'] - ); - if ($routine !== false) { - $routine['item_original_name'] = $routine['item_name']; - $routine['item_original_type'] = $routine['item_type']; - } - } else { - $routine = $this->getDataFromRequest(); - } - $mode = 'edit'; - } - if ($routine !== false) { - // Show form - $editor = $this->getEditorForm($mode, $operation, $routine); - if ($response->isAjax()) { - $response->addJSON('message', $editor); - $response->addJSON('title', $title); - $response->addJSON('paramTemplate', $this->getParameterRow()); - $response->addJSON('type', $routine['item_type']); - } else { - echo "\n\n

    $title

    \n\n$editor"; - } - exit; - } else { - $message = __('Error in processing request:') . ' '; - $message .= sprintf( - $this->words->get('no_edit'), - htmlspecialchars( - Util::backquote($_REQUEST['item_name']) - ), - htmlspecialchars(Util::backquote($db)) - ); - - $message = Message::error($message); - if ($response->isAjax()) { - $response->setRequestStatus(false); - $response->addJSON('message', $message); - exit; - } else { - $message->display(); - } - } - } - } - - /** - * Handle request to create or edit a routine - * - * @param array $errors Errors - * @param string $db DB name - * - * @return array - */ - public function handleRequestCreateOrEdit(array $errors, $db) - { - if (empty($_POST['editor_process_add']) - && empty($_POST['editor_process_edit']) - ) { - return $errors; - } - - $sql_query = ''; - $routine_query = $this->getQueryFromRequest(); - if (! count($errors)) { - // Execute the created query - if (! empty($_POST['editor_process_edit'])) { - $isProcOrFunc = in_array( - $_POST['item_original_type'], - [ - 'PROCEDURE', - 'FUNCTION', - ] - ); - - if (! $isProcOrFunc) { - $errors[] = sprintf( - __('Invalid routine type: "%s"'), - htmlspecialchars($_POST['item_original_type']) - ); - } else { - // Backup the old routine, in case something goes wrong - $create_routine = $this->dbi->getDefinition( - $db, - $_POST['item_original_type'], - $_POST['item_original_name'] - ); - - $privilegesBackup = $this->backupPrivileges(); - - $drop_routine = "DROP {$_POST['item_original_type']} " - . Util::backquote($_POST['item_original_name']) - . ";\n"; - $result = $this->dbi->tryQuery($drop_routine); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($drop_routine) - ) - . '
    ' - . __('MySQL said: ') . $this->dbi->getError(); - } else { - list($newErrors, $message) = $this->create( - $routine_query, - $create_routine, - $privilegesBackup - ); - if (empty($newErrors)) { - $sql_query = $drop_routine . $routine_query; - } else { - $errors = array_merge($errors, $newErrors); - } - unset($newErrors); - if (null === $message) { - unset($message); - } - } - } - } else { - // 'Add a new routine' mode - $result = $this->dbi->tryQuery($routine_query); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($routine_query) - ) - . '

    ' - . __('MySQL said: ') . $this->dbi->getError(); - } else { - $message = Message::success( - __('Routine %1$s has been created.') - ); - $message->addParam( - Util::backquote($_POST['item_name']) - ); - $sql_query = $routine_query; - } - } - } - - if (count($errors)) { - $message = Message::error( - __( - 'One or more errors have occurred while' - . ' processing your request:' - ) - ); - $message->addHtml('
      '); - foreach ($errors as $string) { - $message->addHtml('
    • ' . $string . '
    • '); - } - $message->addHtml('
    '); - } - - $output = Util::getMessage($message, $sql_query); - $response = Response::getInstance(); - if (! $response->isAjax()) { - return $errors; - } - - if (! $message->isSuccess()) { - $response->setRequestStatus(false); - $response->addJSON('message', $output); - exit; - } - - $routines = $this->dbi->getRoutines( - $db, - $_POST['item_type'], - $_POST['item_name'] - ); - $routine = $routines[0]; - $response->addJSON( - 'name', - htmlspecialchars( - mb_strtoupper($_POST['item_name']) - ) - ); - $response->addJSON('new_row', $this->rteList->getRoutineRow($routine)); - $response->addJSON('insert', ! empty($routine)); - $response->addJSON('message', $output); - exit; - } - - /** - * Backup the privileges - * - * @return array - */ - public function backupPrivileges() - { - if (! $GLOBALS['proc_priv'] || ! $GLOBALS['is_reload_priv']) { - return []; - } - - // Backup the Old Privileges before dropping - // if $_POST['item_adjust_privileges'] set - if (! isset($_POST['item_adjust_privileges']) - || empty($_POST['item_adjust_privileges']) - ) { - return []; - } - - $privilegesBackupQuery = 'SELECT * FROM ' . Util::backquote( - 'mysql' - ) - . '.' . Util::backquote('procs_priv') - . ' where Routine_name = "' . $_POST['item_original_name'] - . '" AND Routine_type = "' . $_POST['item_original_type'] - . '";'; - - $privilegesBackup = $this->dbi->fetchResult( - $privilegesBackupQuery, - 0 - ); - - return $privilegesBackup; - } - - /** - * Create the routine - * - * @param string $routine_query Query to create routine - * @param string $create_routine Query to restore routine - * @param array $privilegesBackup Privileges backup - * - * @return array - */ - public function create( - $routine_query, - $create_routine, - array $privilegesBackup - ) { - $result = $this->dbi->tryQuery($routine_query); - if (! $result) { - $errors = []; - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($routine_query) - ) - . '
    ' - . __('MySQL said: ') . $this->dbi->getError(); - // We dropped the old routine, - // but were unable to create the new one - // Try to restore the backup query - $result = $this->dbi->tryQuery($create_routine); - $errors = $this->general->checkResult( - $result, - __( - 'Sorry, we failed to restore' - . ' the dropped routine.' - ), - $create_routine, - $errors - ); - - return [ - $errors, - null, - ]; - } - - // Default value - $resultAdjust = false; - - if ($GLOBALS['proc_priv'] - && $GLOBALS['is_reload_priv'] - ) { - // Insert all the previous privileges - // but with the new name and the new type - foreach ($privilegesBackup as $priv) { - $adjustProcPrivilege = 'INSERT INTO ' - . Util::backquote('mysql') . '.' - . Util::backquote('procs_priv') - . ' VALUES("' . $priv[0] . '", "' - . $priv[1] . '", "' . $priv[2] . '", "' - . $_POST['item_name'] . '", "' - . $_POST['item_type'] . '", "' - . $priv[5] . '", "' - . $priv[6] . '", "' - . $priv[7] . '");'; - $resultAdjust = $this->dbi->query( - $adjustProcPrivilege - ); - } - } - - $message = $this->flushPrivileges($resultAdjust); - - return [ - [], - $message, - ]; - } - - /** - * Flush privileges and get message - * - * @param bool $flushPrivileges Flush privileges - * - * @return Message - */ - public function flushPrivileges($flushPrivileges) - { - if ($flushPrivileges) { - // Flush the Privileges - $flushPrivQuery = 'FLUSH PRIVILEGES;'; - $this->dbi->query($flushPrivQuery); - - $message = Message::success( - __( - 'Routine %1$s has been modified. Privileges have been adjusted.' - ) - ); - } else { - $message = Message::success( - __('Routine %1$s has been modified.') - ); - } - $message->addParam( - Util::backquote($_POST['item_name']) - ); - - return $message; - } - - /** - * 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. - */ - public function getDataFromRequest() - { - global $param_directions, $param_sqldataaccess; - - $retval = []; - $indices = [ - 'item_name', - 'item_original_name', - 'item_returnlength', - 'item_returnopts_num', - 'item_returnopts_text', - 'item_definition', - 'item_comment', - 'item_definer', - ]; - foreach ($indices as $index) { - $retval[$index] = isset($_POST[$index]) ? $_POST[$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($_POST['item_original_type']) - && $_POST['item_original_type'] == 'FUNCTION' - ) { - $retval['item_original_type'] = 'FUNCTION'; - } - $retval['item_num_params'] = 0; - $retval['item_param_dir'] = []; - $retval['item_param_name'] = []; - $retval['item_param_type'] = []; - $retval['item_param_length'] = []; - $retval['item_param_opts_num'] = []; - $retval['item_param_opts_text'] = []; - if (isset($_POST['item_param_name']) - && isset($_POST['item_param_type']) - && isset($_POST['item_param_length']) - && isset($_POST['item_param_opts_num']) - && isset($_POST['item_param_opts_text']) - && is_array($_POST['item_param_name']) - && is_array($_POST['item_param_type']) - && is_array($_POST['item_param_length']) - && is_array($_POST['item_param_opts_num']) - && is_array($_POST['item_param_opts_text']) - ) { - if ($_POST['item_type'] == 'PROCEDURE') { - $retval['item_param_dir'] = $_POST['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'] = $_POST['item_param_name']; - $retval['item_param_type'] = $_POST['item_param_type']; - foreach ($retval['item_param_type'] as $key => $value) { - if (! in_array($value, Util::getSupportedDatatypes(), true)) { - $retval['item_param_type'][$key] = ''; - } - } - $retval['item_param_length'] = $_POST['item_param_length']; - $retval['item_param_opts_num'] = $_POST['item_param_opts_num']; - $retval['item_param_opts_text'] = $_POST['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($_POST['item_returntype']) - && in_array($_POST['item_returntype'], Util::getSupportedDatatypes()) - ) { - $retval['item_returntype'] = $_POST['item_returntype']; - } - - $retval['item_isdeterministic'] = ''; - if (isset($_POST['item_isdeterministic']) - && mb_strtolower($_POST['item_isdeterministic']) == 'on' - ) { - $retval['item_isdeterministic'] = " checked='checked'"; - } - $retval['item_securitytype_definer'] = ''; - $retval['item_securitytype_invoker'] = ''; - if (isset($_POST['item_securitytype'])) { - if ($_POST['item_securitytype'] === 'DEFINER') { - $retval['item_securitytype_definer'] = " selected='selected'"; - } elseif ($_POST['item_securitytype'] === 'INVOKER') { - $retval['item_securitytype_invoker'] = " selected='selected'"; - } - } - $retval['item_sqldataaccess'] = ''; - if (isset($_POST['item_sqldataaccess']) - && in_array($_POST['item_sqldataaccess'], $param_sqldataaccess, true) - ) { - $retval['item_sqldataaccess'] = $_POST['item_sqldataaccess']; - } - - return $retval; - } - - /** - * 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|bool Data necessary to create the routine editor. - */ - public function getDataFromName($name, $type, $all = true) - { - global $db; - - $retval = []; - - // 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 " . Util::getCollateForIS() . "=" - . "'" . $this->dbi->escapeString($db) . "' " - . "AND SPECIFIC_NAME='" . $this->dbi->escapeString($name) . "'" - . "AND ROUTINE_TYPE='" . $this->dbi->escapeString($type) . "'"; - $query = "SELECT $fields FROM INFORMATION_SCHEMA.ROUTINES WHERE $where;"; - - $routine = $this->dbi->fetchSingleRow($query, 'ASSOC'); - - if (! $routine) { - return false; - } - - // Get required data - $retval['item_name'] = $routine['SPECIFIC_NAME']; - $retval['item_type'] = $routine['ROUTINE_TYPE']; - - $definition - = $this->dbi->getDefinition( - $db, - $routine['ROUTINE_TYPE'], - $routine['SPECIFIC_NAME'] - ); - - if ($definition === null) { - return false; - } - - $parser = new Parser($definition); - - /** - * @var CreateStatement $stmt - */ - $stmt = $parser->statements[0]; - - $params = Routine::getParameters($stmt); - $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_length_arr'] = $params['length_arr']; - $retval['item_param_opts_num'] = $params['opts']; - $retval['item_param_opts_text'] = $params['opts']; - - // Get extra data - if (! $all) { - return $retval; - } - - 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'])) { - $options = []; - foreach ($stmt->return->options->options as $opt) { - $options[] = is_string($opt) ? $opt : $opt['value']; - } - - $retval['item_returntype'] = $stmt->return->name; - $retval['item_returnlength'] = implode(',', $stmt->return->parameters); - $retval['item_returnopts_num'] = implode(' ', $options); - $retval['item_returnopts_text'] = implode(' ', $options); - } - - $retval['item_definer'] = $stmt->options->has('DEFINER'); - $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'"; - } elseif ($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; - } - - /** - * Creates one row for the parameter table used in the routine editor. - * - * @param array $routine Data for the routine returned by - * getDataFromRequest() or 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. - */ - public function getParameterRow(array $routine = [], $index = null, $class = '') - { - global $param_directions, $param_opts_num; - - if ($index === null) { - // template row for AJAX request - $i = 0; - $index = '%s'; - $drop_class = ''; - $routine = [ - 'item_param_dir' => [0 => ''], - 'item_param_name' => [0 => ''], - 'item_param_type' => [0 => ''], - 'item_param_length' => [0 => ''], - 'item_param_opts_num' => [0 => ''], - 'item_param_opts_text' => [0 => ''], - ]; - } elseif (! 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 ''; - } - - $allCharsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); - $charsets = []; - /** @var Charset $charset */ - foreach ($allCharsets as $charset) { - $charsets[] = [ - 'name' => $charset->getName(), - 'description' => $charset->getDescription(), - 'is_selected' => $charset->getName() === $routine['item_param_opts_text'][$i], - ]; - } - - $template = new Template(); - return $template->render('rte/routines/parameter_row', [ - 'class' => $class, - 'index' => $index, - 'param_directions' => $param_directions, - 'param_opts_num' => $param_opts_num, - 'item_param_dir' => $routine['item_param_dir'][$i] ?? '', - 'item_param_name' => $routine['item_param_name'][$i] ?? '', - 'item_param_length' => $routine['item_param_length'][$i] ?? '', - 'item_param_opts_num' => $routine['item_param_opts_num'][$i] ?? '', - 'supported_datatypes' => Util::getSupportedDatatypes( - true, - $routine['item_param_type'][$i] - ), - 'charsets' => $charsets, - 'drop_class' => $drop_class, - ]); - } - - /** - * Displays a form used to add/edit a routine - * - * @param string $mode If the editor will be used to 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 - * getDataFromRequest() or getDataFromName() - * - * @return string HTML code for the editor. - */ - public function getEditorForm($mode, $operation, array $routine) - { - global $db, $errors, $param_sqldataaccess, $param_opts_num; - - $response = Response::getInstance(); - - // Escape special characters - $need_escape = [ - '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'; - } - } elseif ($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']++; - } elseif ($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']--; - } - $disableRemoveParam = ''; - if (! $routine['item_num_params']) { - $disableRemoveParam = " class='isdisableremoveparam_class' 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 .= Url::getHiddenInputs($db) . "\n"; - $retval .= "
    \n"; - $retval .= "" . __('Details') . "\n"; - $retval .= "\n"; - $retval .= "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "\n"; - $retval .= "\n"; - $retval .= " \n"; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - // parameter handling end - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - if (isset($_REQUEST['edit_item']) - && ! empty($_REQUEST['edit_item']) - ) { - $retval .= ""; - $retval .= " "; - if ($GLOBALS['proc_priv'] - && $GLOBALS['is_reload_priv'] - ) { - $retval .= " "; - } else { - $retval .= " "; - } - $retval .= ""; - } - - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= "
    " . __('Routine name') . "\n"; - $retval .= " \n"; - if ($response->isAjax()) { - $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 .= " \n"; - $retval .= " \n"; - $retval .= " "; - $retval .= " \n"; - $retval .= " \n"; - for ($i = 0; $i < $routine['item_num_params']; $i++) { // each parameter - $retval .= $this->getParameterRow($routine, $i, $isprocedure_class); - } - $retval .= " \n"; - $retval .= "
    " - . __('Direction') . "" . __('Name') . "" . __('Type') . "" . __('Length/Values') . "" . __('Options') . " 
    "; - $retval .= "
     "; - $retval .= " "; - $retval .= " "; - $retval .= "
    " . __('Return type') . "
    " . __('Return length/values') . "---
    " . __('Return options') . "
    "; - $retval .= '' . "\n"; - $retval .= "
    "; - $retval .= "
    "; - $retval .= "
    ---
    "; - $retval .= "
    " . __('Definition') . "
    " . __('Is deterministic') . "
    " . __('Adjust privileges'); - $retval .= Util::showDocu('faq', 'faq6-39'); - $retval .= "
    " . __('Definer') . "
    " . __('Security type') . "
    " . __('SQL data access') . "
    " . __('Comment') . "
    "; - $retval .= "
    "; - if ($response->isAjax()) { - $retval .= ""; - $retval .= ""; - } - $retval .= "
    "; - $retval .= ""; - - return $retval; - } - - /** - * Composes the query necessary to create a routine from an HTTP request. - * - * @return string The CREATE [ROUTINE | PROCEDURE] query. - */ - public function getQueryFromRequest() - { - global $errors, $param_sqldataaccess, $param_directions, $dbi; - - $_POST['item_type'] = isset($_POST['item_type']) - ? $_POST['item_type'] : ''; - - $query = 'CREATE '; - if (! empty($_POST['item_definer'])) { - if (mb_strpos($_POST['item_definer'], '@') !== false) { - $arr = explode('@', $_POST['item_definer']); - - $do_backquote = true; - if (substr($arr[0], 0, 1) === "`" - && substr($arr[0], -1) === "`" - ) { - $do_backquote = false; - } - $query .= 'DEFINER=' . Util::backquote($arr[0], $do_backquote); - - $do_backquote = true; - if (substr($arr[1], 0, 1) === "`" - && substr($arr[1], -1) === "`" - ) { - $do_backquote = false; - } - $query .= '@' . Util::backquote($arr[1], $do_backquote) . ' '; - } else { - $errors[] = __('The definer must be in the "username@hostname" format!'); - } - } - if ($_POST['item_type'] == 'FUNCTION' - || $_POST['item_type'] == 'PROCEDURE' - ) { - $query .= $_POST['item_type'] . ' '; - } else { - $errors[] = sprintf( - __('Invalid routine type: "%s"'), - htmlspecialchars($_POST['item_type']) - ); - } - if (! empty($_POST['item_name'])) { - $query .= Util::backquote($_POST['item_name']); - } else { - $errors[] = __('You must provide a routine name!'); - } - $params = ''; - $warned_about_dir = false; - $warned_about_length = false; - - if (! empty($_POST['item_param_name']) - && ! empty($_POST['item_param_type']) - && ! empty($_POST['item_param_length']) - && is_array($_POST['item_param_name']) - && is_array($_POST['item_param_type']) - && is_array($_POST['item_param_length']) - ) { - $item_param_name = $_POST['item_param_name']; - $item_param_type = $_POST['item_param_type']; - $item_param_length = $_POST['item_param_length']; - - for ($i = 0, $nb = count($item_param_name); $i < $nb; $i++) { - if (! empty($item_param_name[$i]) - && ! empty($item_param_type[$i]) - ) { - if ($_POST['item_type'] == 'PROCEDURE' - && ! empty($_POST['item_param_dir'][$i]) - && in_array($_POST['item_param_dir'][$i], $param_directions) - ) { - $params .= $_POST['item_param_dir'][$i] . " " - . Util::backquote($item_param_name[$i]) - . " " . $item_param_type[$i]; - } elseif ($_POST['item_type'] == 'FUNCTION') { - $params .= Util::backquote($item_param_name[$i]) - . " " . $item_param_type[$i]; - } elseif (! $warned_about_dir) { - $warned_about_dir = true; - $errors[] = sprintf( - __('Invalid direction "%s" given for parameter.'), - htmlspecialchars($_POST['item_param_dir'][$i]) - ); - } - if ($item_param_length[$i] != '' - && ! preg_match( - '@^(DATE|TINYBLOB|TINYTEXT|BLOB|TEXT|' - . 'MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|' - . 'SERIAL|BOOLEAN)$@i', - $item_param_type[$i] - ) - ) { - $params .= "(" . $item_param_length[$i] . ")"; - } elseif ($item_param_length[$i] == '' - && preg_match( - '@^(ENUM|SET|VARCHAR|VARBINARY)$@i', - $item_param_type[$i] - ) - ) { - 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($_POST['item_param_opts_text'][$i])) { - if ($dbi->types->getTypeClass($item_param_type[$i]) == 'CHAR') { - if (! in_array($item_param_type[$i], ['VARBINARY', 'BINARY'])) { - $params .= ' CHARSET ' - . mb_strtolower( - $_POST['item_param_opts_text'][$i] - ); - } - } - } - if (! empty($_POST['item_param_opts_num'][$i])) { - if ($dbi->types->getTypeClass($item_param_type[$i]) == 'NUMBER') { - $params .= ' ' - . mb_strtoupper( - $_POST['item_param_opts_num'][$i] - ); - } - } - if ($i != (count($item_param_name) - 1)) { - $params .= ", "; - } - } else { - $errors[] = __( - 'You must provide a name and a type for each routine parameter.' - ); - break; - } - } - } - $query .= "(" . $params . ") "; - if ($_POST['item_type'] == 'FUNCTION') { - $item_returntype = isset($_POST['item_returntype']) - ? $_POST['item_returntype'] - : null; - - if (! empty($item_returntype) - && in_array( - $item_returntype, - Util::getSupportedDatatypes() - ) - ) { - $query .= "RETURNS " . $item_returntype; - } else { - $errors[] = __('You must provide a valid return type for the routine.'); - } - if (! empty($_POST['item_returnlength']) - && ! preg_match( - '@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|' - . 'MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|SERIAL|BOOLEAN)$@i', - $item_returntype - ) - ) { - $query .= "(" . $_POST['item_returnlength'] . ")"; - } elseif (empty($_POST['item_returnlength']) - && preg_match( - '@^(ENUM|SET|VARCHAR|VARBINARY)$@i', - $item_returntype - ) - ) { - if (! $warned_about_length) { - $errors[] = __( - 'You must provide length/values for routine parameters' - . ' of type ENUM, SET, VARCHAR and VARBINARY.' - ); - } - } - if (! empty($_POST['item_returnopts_text'])) { - if ($dbi->types->getTypeClass($item_returntype) == 'CHAR') { - $query .= ' CHARSET ' - . mb_strtolower($_POST['item_returnopts_text']); - } - } - if (! empty($_POST['item_returnopts_num'])) { - if ($dbi->types->getTypeClass($item_returntype) == 'NUMBER') { - $query .= ' ' - . mb_strtoupper($_POST['item_returnopts_num']); - } - } - $query .= ' '; - } - if (! empty($_POST['item_comment'])) { - $query .= "COMMENT '" . $this->dbi->escapeString($_POST['item_comment']) - . "' "; - } - if (isset($_POST['item_isdeterministic'])) { - $query .= 'DETERMINISTIC '; - } else { - $query .= 'NOT DETERMINISTIC '; - } - if (! empty($_POST['item_sqldataaccess']) - && in_array($_POST['item_sqldataaccess'], $param_sqldataaccess) - ) { - $query .= $_POST['item_sqldataaccess'] . ' '; - } - if (! empty($_POST['item_securitytype'])) { - if ($_POST['item_securitytype'] == 'DEFINER' - || $_POST['item_securitytype'] == 'INVOKER' - ) { - $query .= 'SQL SECURITY ' . $_POST['item_securitytype'] . ' '; - } - } - if (! empty($_POST['item_definition'])) { - $query .= $_POST['item_definition']; - } else { - $errors[] = __('You must provide a routine definition.'); - } - - return $query; - } - - /** - * Handles requests for executing a routine - * - * @return void - */ - public function handleExecute() - { - global $db; - - $response = Response::getInstance(); - - /** - * Handle all user requests other than the default of listing routines - */ - if (! empty($_POST['execute_routine']) && ! empty($_POST['item_name'])) { - // Build the queries - $routine = $this->getDataFromName( - $_POST['item_name'], - $_POST['item_type'], - false - ); - if ($routine === false) { - $message = __('Error in processing request:') . ' '; - $message .= sprintf( - $this->words->get('not_found'), - htmlspecialchars(Util::backquote($_POST['item_name'])), - htmlspecialchars(Util::backquote($db)) - ); - $message = Message::error($message); - if ($response->isAjax()) { - $response->setRequestStatus(false); - $response->addJSON('message', $message); - exit; - } else { - echo $message->getDisplay(); - unset($_POST); - } - } - - $queries = []; - $end_query = []; - $args = []; - $all_functions = $this->dbi->types->getAllFunctions(); - for ($i = 0; $i < $routine['item_num_params']; $i++) { - if (isset($_POST['params'][$routine['item_param_name'][$i]])) { - $value = $_POST['params'][$routine['item_param_name'][$i]]; - if (is_array($value)) { // is SET type - $value = implode(',', $value); - } - $value = $this->dbi->escapeString($value); - if (! empty($_POST['funcs'][$routine['item_param_name'][$i]]) - && in_array( - $_POST['funcs'][$routine['item_param_name'][$i]], - $all_functions - ) - ) { - $queries[] = "SET @p$i=" - . $_POST['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 " - . Util::backquote($routine['item_param_name'][$i]); - } - } - } - if ($routine['item_type'] == 'PROCEDURE') { - $queries[] = "CALL " . Util::backquote($routine['item_name']) - . "(" . implode(', ', $args) . ");\n"; - if (count($end_query)) { - $queries[] = "SELECT " . implode(', ', $end_query) . ";\n"; - } - } else { - $queries[] = "SELECT " . Util::backquote($routine['item_name']) - . "(" . implode(', ', $args) . ") " - . "AS " . 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 (! $this->dbi->tryMultiQuery($multiple_query)) { - $outcome = false; - } - - // Generate output - if ($outcome) { - // Pass the SQL queries through the "pretty printer" - $output = Util::formatSql(implode($queries, "\n")); - - // Display results - $output .= "
    "; - $output .= sprintf( - __('Execution results of routine %s'), - Util::backquote(htmlspecialchars($routine['item_name'])) - ); - $output .= ""; - - $nbResultsetToDisplay = 0; - - do { - $result = $this->dbi->storeResult(); - $num_rows = $this->dbi->numRows($result); - - if (($result !== false) && ($num_rows > 0)) { - $output .= ""; - foreach ($this->dbi->getFieldsMeta($result) as $field) { - $output .= ""; - } - $output .= ""; - - while ($row = $this->dbi->fetchAssoc($result)) { - $output .= "" . $this->browseRow($row) . ""; - } - - $output .= "
    "; - $output .= htmlspecialchars($field->name); - $output .= "
    "; - $nbResultsetToDisplay++; - $affected = $num_rows; - } - - if (! $this->dbi->moreResults()) { - break; - } - - $output .= "
    "; - - $this->dbi->freeResult($result); - } while ($outcome = $this->dbi->nextResult()); - } - - if ($outcome) { - $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 = Message::success($message); - - if ($nbResultsetToDisplay == 0) { - $notice = __( - 'MySQL returned an empty result set (i.e. zero rows).' - ); - $output .= Message::notice($notice)->getDisplay(); - } - } else { - $output = ''; - $message = Message::error( - sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($multiple_query) - ) - . '

    ' - . __('MySQL said: ') . $this->dbi->getError() - ); - } - - // Print/send output - if ($response->isAjax()) { - $response->setRequestStatus($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 - } - return; - } elseif (! empty($_GET['execute_dialog']) && ! empty($_GET['item_name'])) { - /** - * Display the execute form for a routine. - */ - $routine = $this->getDataFromName( - $_GET['item_name'], - $_GET['item_type'], - true - ); - if ($routine !== false) { - $form = $this->getExecuteForm($routine); - if ($response->isAjax()) { - $title = __("Execute routine") . " " . Util::backquote( - htmlentities($_GET['item_name'], ENT_QUOTES) - ); - $response->addJSON('message', $form); - $response->addJSON('title', $title); - $response->addJSON('dialog', true); - } else { - echo "\n\n

    " . __("Execute routine") . "

    \n\n"; - echo $form; - } - exit; - } elseif ($response->isAjax()) { - $message = __('Error in processing request:') . ' '; - $message .= sprintf( - $this->words->get('not_found'), - htmlspecialchars(Util::backquote($_GET['item_name'])), - htmlspecialchars(Util::backquote($db)) - ); - $message = Message::error($message); - - $response->setRequestStatus(false); - $response->addJSON('message', $message); - exit; - } - } - } - - /** - * Browse row array - * - * @param array $row Columns - * - * @return string - */ - private function browseRow(array $row) - { - $output = null; - foreach ($row as $value) { - if ($value === null) { - $value = 'NULL'; - } else { - $value = htmlspecialchars($value); - } - $output .= "
    " . $value . "
    \n"; - $retval .= "\n"; - } else { - $retval .= "" . __('Routine parameters') . "\n"; - $retval .= "
    \n"; - $retval .= __('Routine parameters'); - $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 = 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; - } - $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'; - } elseif ($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 (false !== stripos($routine['item_param_type'][$i], 'enum') - || false !== stripos($routine['item_param_type'][$i], 'set') - || in_array( - mb_strtolower($routine['item_param_type'][$i]), - $no_support_types - ) - ) { - $retval .= "--\n"; - } else { - $field = [ - 'True_Type' => mb_strtolower( - $routine['item_param_type'][$i] - ), - 'Type' => '', - 'Key' => '', - 'Field' => '', - 'Default' => '', - 'first_timestamp' => false, - ]; - $retval .= ""; - } - $retval .= "\n"; - if (in_array($routine['item_param_type'][$i], ['ENUM', 'SET'])) { - if ($routine['item_param_type'][$i] == 'ENUM') { - $input_type = 'radio'; - } else { - $input_type = 'checkbox'; - } - foreach ($routine['item_param_length_arr'][$i] as $value) { - $value = htmlentities(Util::unQuote($value), ENT_QUOTES); - $retval .= "" - . $value . "
    \n"; - } - } elseif (in_array( - mb_strtolower($routine['item_param_type'][$i]), - $no_support_types - )) { - $retval .= "\n"; - } else { - $retval .= "\n"; - } - $retval .= "
    \n"; - if (! $response->isAjax()) { - $retval .= "
    \n\n"; - $retval .= "
    \n"; - $retval .= " \n"; - $retval .= "
    \n"; - } else { - $retval .= ""; - $retval .= ""; - } - $retval .= "\n\n"; - $retval .= "\n\n"; - - return $retval; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Rte/RteList.php b/srcs/phpmyadmin/libraries/classes/Rte/RteList.php deleted file mode 100644 index 0e87c6c..0000000 --- a/srcs/phpmyadmin/libraries/classes/Rte/RteList.php +++ /dev/null @@ -1,518 +0,0 @@ -dbi = $dbi; - $this->words = new Words(); - $this->template = new Template(); - } - - /** - * Creates a list of items containing the relevant - * information and some action links. - * - * @param string $type One of ['routine'|'trigger'|'event'] - * @param array $items An array of items - * - * @return string HTML code of the list of items - */ - public function get($type, array $items) - { - global $table; - - /** - * Conditional classes switch the list on or off - */ - $class1 = 'hide'; - $class2 = ''; - if (! $items) { - $class1 = ''; - $class2 = ' hide'; - } - /** - * Generate output - */ - $retval = "\n"; - $retval .= '
    '; - $retval .= Url::getHiddenInputs($GLOBALS['db'], $GLOBALS['table']); - $retval .= "
    \n"; - $retval .= " \n"; - $retval .= " " . $this->words->get('title') . "\n"; - $retval .= " " - . Util::showMySQLDocu($this->words->get('docu')) . "\n"; - $retval .= " \n"; - $retval .= "
    \n"; - $retval .= " " . $this->words->get('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"; - $retval .= " \n"; // see comment above - for ($i = 0; $i < 7; $i++) { - $retval .= " \n"; - } - break; - case 'trigger': - $retval .= " \n"; - $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"; - $retval .= " \n"; // see comment above - for ($i = 0; $i < 6; $i++) { - $retval .= " \n"; - } - break; - default: - break; - } - $retval .= " \n"; - $retval .= " \n"; - $response = Response::getInstance(); - foreach ($items as $item) { - if ($response->isAjax() && empty($_REQUEST['ajax_page_request'])) { - $rowclass = 'ajaxInsert hide'; - } else { - $rowclass = ''; - } - // Get each row from the correct function - switch ($type) { - case 'routine': - $retval .= $this->getRoutineRow($item, $rowclass); - break; - case 'trigger': - $retval .= $this->getTriggerRow($item, $rowclass); - break; - case 'event': - $retval .= $this->getEventRow($item, $rowclass); - break; - default: - break; - } - } - $retval .= "
    " . __('Name') . "" . __('Action') . "" . __('Type') . "" . __('Returns') . "
    " . __('Name') . "" . __('Table') . "" . __('Action') . "" . __('Time') . "" . __('Event') . "
    " . __('Name') . "" . __('Status') . "" . __('Action') . "" . __('Type') . "
    \n"; - - if (count($items)) { - $retval .= '
    '; - $retval .= $this->template->render('select_all', [ - 'pma_theme_image' => $GLOBALS['pmaThemeImage'], - 'text_dir' => $GLOBALS['text_dir'], - 'form_name' => 'rteListForm', - ]); - $retval .= Util::getButtonOrImage( - 'submit_mult', - 'mult_submit', - __('Export'), - 'b_export', - 'export' - ); - $retval .= Util::getButtonOrImage( - 'submit_mult', - 'mult_submit', - __('Drop'), - 'b_drop', - 'drop' - ); - $retval .= '
    '; - } - - $retval .= "
    \n"; - $retval .= "
    \n"; - $retval .= "\n"; - - return $retval; - } - - /** - * Creates the contents for a row in the list of routines - * - * @param array $routine An array of routine data - * @param string $rowclass Additional class - * - * @return string HTML code of a row for the list of routines - */ - public function getRoutineRow(array $routine, $rowclass = '') - { - global $url_query, $db, $titles; - - $sql_drop = sprintf( - 'DROP %s IF EXISTS %s', - $routine['type'], - Util::backquote($routine['name']) - ); - $type_link = "item_type={$routine['type']}"; - - $retval = " \n"; - $retval .= " \n"; - $retval .= ' '; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " " - . htmlspecialchars($sql_drop) . "\n"; - $retval .= " \n"; - $retval .= " " - . htmlspecialchars($routine['name']) . "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - - // this is for our purpose to decide whether to - // show the edit link or not, so we need the DEFINER for the routine - $where = "ROUTINE_SCHEMA " . Util::getCollateForIS() . "=" - . "'" . $this->dbi->escapeString($db) . "' " - . "AND SPECIFIC_NAME='" . $this->dbi->escapeString($routine['name']) . "'" - . "AND ROUTINE_TYPE='" . $this->dbi->escapeString($routine['type']) . "'"; - $query = "SELECT `DEFINER` FROM INFORMATION_SCHEMA.ROUTINES WHERE $where;"; - $routine_definer = $this->dbi->fetchValue($query); - - $curr_user = $this->dbi->getCurrentUser(); - - // Since editing a procedure involved dropping and recreating, check also for - // CREATE ROUTINE privilege to avoid lost procedures. - if ((Util::currentUserHasPrivilege('CREATE ROUTINE', $db) - && $curr_user == $routine_definer) - || $this->dbi->isSuperuser() - ) { - $retval .= ' ' . $titles['Edit'] . "\n"; - } else { - $retval .= " {$titles['NoEdit']}\n"; - } - $retval .= " \n"; - $retval .= " \n"; - - // There is a problem with Util::currentUserHasPrivilege(): - // it does not detect all kinds of privileges, for example - // a direct privilege on a specific routine. So, at this point, - // we show the Execute link, hoping that the user has the correct rights. - // Also, information_schema might be hiding the ROUTINE_DEFINITION - // but a routine with no input parameters can be nonetheless executed. - - // Check if the 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. - - $definition = $this->dbi->getDefinition( - $db, - $routine['type'], - $routine['name'] - ); - if ($definition !== null) { - $parser = new Parser($definition); - - /** - * @var CreateStatement $stmt - */ - $stmt = $parser->statements[0]; - - $params = Routine::getParameters($stmt); - - if (Util::currentUserHasPrivilege('EXECUTE', $db)) { - $execute_action = 'execute_routine'; - for ($i = 0; $i < $params['num']; $i++) { - if ($routine['type'] == 'PROCEDURE' - && $params['dir'][$i] == 'OUT' - ) { - continue; - } - $execute_action = 'execute_dialog'; - break; - } - $query_part = $execute_action . '=1&item_name=' - . urlencode($routine['name']) . '&' . $type_link; - $retval .= ' ' . $titles['Execute'] . "\n"; - } else { - $retval .= " {$titles['NoExecute']}\n"; - } - } - - $retval .= " \n"; - $retval .= " \n"; - if ((Util::currentUserHasPrivilege('CREATE ROUTINE', $db) - && $curr_user == $routine_definer) - || $this->dbi->isSuperuser() - ) { - $retval .= ' ' . $titles['Export'] . "\n"; - } else { - $retval .= " {$titles['NoExport']}\n"; - } - $retval .= " \n"; - $retval .= " \n"; - $retval .= Util::linkOrButton( - 'sql.php' . $url_query . '&sql_query=' . urlencode($sql_drop) . '&goto=db_routines.php' . urlencode("?db={$db}"), - $titles['Drop'], - ['class' => 'ajax drop_anchor'] - ); - $retval .= " \n"; - $retval .= " \n"; - $retval .= " {$routine['type']}\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " " - . htmlspecialchars($routine['returns']) . "\n"; - $retval .= " \n"; - $retval .= " \n"; - - return $retval; - } - - /** - * Creates the contents for a row in the list of triggers - * - * @param array $trigger An array of routine data - * @param string $rowclass Additional class - * - * @return string HTML code of a cell for the list of triggers - */ - public function getTriggerRow(array $trigger, $rowclass = '') - { - global $url_query, $db, $table, $titles; - - $retval = " \n"; - $retval .= " \n"; - $retval .= ' '; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " " - . htmlspecialchars($trigger['drop']) . "\n"; - $retval .= " \n"; - $retval .= " " . htmlspecialchars($trigger['name']) . "\n"; - $retval .= " \n"; - $retval .= " \n"; - if (empty($table)) { - $retval .= " \n"; - $retval .= "" - . htmlspecialchars($trigger['table']) . ""; - $retval .= " \n"; - } - $retval .= " \n"; - if (Util::currentUserHasPrivilege('TRIGGER', $db, $table)) { - $retval .= ' ' . $titles['Edit'] . "\n"; - } else { - $retval .= " {$titles['NoEdit']}\n"; - } - $retval .= " \n"; - $retval .= " \n"; - $retval .= ' ' . $titles['Export'] . "\n"; - $retval .= " \n"; - $retval .= " \n"; - if (Util::currentUserHasPrivilege('TRIGGER', $db)) { - $retval .= Util::linkOrButton( - 'sql.php' . $url_query . '&sql_query=' . urlencode($trigger['drop']) . '&goto=db_triggers.php' . urlencode("?db={$db}"), - $titles['Drop'], - ['class' => 'ajax drop_anchor'] - ); - } else { - $retval .= " {$titles['NoDrop']}\n"; - } - $retval .= " \n"; - $retval .= " \n"; - $retval .= " {$trigger['action_timing']}\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " {$trigger['event_manipulation']}\n"; - $retval .= " \n"; - $retval .= " \n"; - - return $retval; - } - - /** - * Creates the contents for a row in the list of events - * - * @param array $event An array of routine data - * @param string $rowclass Additional class - * - * @return string HTML code of a cell for the list of events - */ - public function getEventRow(array $event, $rowclass = '') - { - global $url_query, $db, $titles; - - $sql_drop = sprintf( - 'DROP EVENT IF EXISTS %s', - Util::backquote($event['name']) - ); - - $retval = " \n"; - $retval .= " \n"; - $retval .= ' '; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " " - . htmlspecialchars($sql_drop) . "\n"; - $retval .= " \n"; - $retval .= " " - . htmlspecialchars($event['name']) . "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " {$event['status']}\n"; - $retval .= " \n"; - $retval .= " \n"; - if (Util::currentUserHasPrivilege('EVENT', $db)) { - $retval .= ' ' . $titles['Edit'] . "\n"; - } else { - $retval .= " {$titles['NoEdit']}\n"; - } - $retval .= " \n"; - $retval .= " \n"; - $retval .= ' ' . $titles['Export'] . "\n"; - $retval .= " \n"; - $retval .= " \n"; - if (Util::currentUserHasPrivilege('EVENT', $db)) { - $retval .= Util::linkOrButton( - 'sql.php' . $url_query . '&sql_query=' . urlencode($sql_drop) . '&goto=db_events.php' . urlencode("?db={$db}"), - $titles['Drop'], - ['class' => 'ajax drop_anchor'] - ); - } else { - $retval .= " {$titles['NoDrop']}\n"; - } - $retval .= " \n"; - $retval .= " \n"; - $retval .= " {$event['type']}\n"; - $retval .= " \n"; - $retval .= " \n"; - - return $retval; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Rte/Triggers.php b/srcs/phpmyadmin/libraries/classes/Rte/Triggers.php deleted file mode 100644 index 45ce02f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Rte/Triggers.php +++ /dev/null @@ -1,527 +0,0 @@ -dbi = $dbi; - $this->export = new Export($this->dbi); - $this->footer = new Footer($this->dbi); - $this->general = new General($this->dbi); - $this->rteList = new RteList($this->dbi); - $this->words = new Words(); - } - - /** - * Sets required globals - * - * @return void - */ - public function setGlobals() - { - global $action_timings, $event_manipulations; - - // Some definitions for triggers - $action_timings = [ - 'BEFORE', - 'AFTER', - ]; - $event_manipulations = [ - 'INSERT', - 'UPDATE', - 'DELETE', - ]; - } - - /** - * Main function for the triggers functionality - * - * @return void - */ - public function main() - { - global $db, $table; - - $this->setGlobals(); - /** - * Process all requests - */ - $this->handleEditor(); - $this->export->triggers(); - /** - * Display a list of available triggers - */ - $items = $this->dbi->getTriggers($db, $table); - echo $this->rteList->get('trigger', $items); - /** - * Display a link for adding a new trigger, - * if the user has the necessary privileges - */ - echo $this->footer->triggers(); - } - - /** - * Handles editor requests for adding or editing an item - * - * @return void - */ - public function handleEditor() - { - global $errors, $db, $table; - - if (! empty($_POST['editor_process_add']) - || ! empty($_POST['editor_process_edit']) - ) { - $sql_query = ''; - - $item_query = $this->getQueryFromRequest(); - - if (! count($errors)) { // set by PhpMyAdmin\Rte\Routines::getQueryFromRequest() - // Execute the created query - if (! empty($_POST['editor_process_edit'])) { - // Backup the old trigger, in case something goes wrong - $trigger = $this->getDataFromName($_POST['item_original_name']); - $create_item = $trigger['create']; - $drop_item = $trigger['drop'] . ';'; - $result = $this->dbi->tryQuery($drop_item); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($drop_item) - ) - . '
    ' - . __('MySQL said: ') . $this->dbi->getError(); - } else { - $result = $this->dbi->tryQuery($item_query); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($item_query) - ) - . '
    ' - . __('MySQL said: ') . $this->dbi->getError(); - // We dropped the old item, but were unable to create the - // new one. Try to restore the backup query. - $result = $this->dbi->tryQuery($create_item); - - $errors = $this->general->checkResult( - $result, - __( - 'Sorry, we failed to restore the dropped trigger.' - ), - $create_item, - $errors - ); - } else { - $message = Message::success( - __('Trigger %1$s has been modified.') - ); - $message->addParam( - Util::backquote($_POST['item_name']) - ); - $sql_query = $drop_item . $item_query; - } - } - } else { - // 'Add a new item' mode - $result = $this->dbi->tryQuery($item_query); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($item_query) - ) - . '

    ' - . __('MySQL said: ') . $this->dbi->getError(); - } else { - $message = Message::success( - __('Trigger %1$s has been created.') - ); - $message->addParam( - Util::backquote($_POST['item_name']) - ); - $sql_query = $item_query; - } - } - } - - if (count($errors)) { - $message = Message::error( - '' - . __( - 'One or more errors have occurred while processing your request:' - ) - . '' - ); - $message->addHtml('
      '); - foreach ($errors as $string) { - $message->addHtml('
    • ' . $string . '
    • '); - } - $message->addHtml('
    '); - } - - $output = Util::getMessage($message, $sql_query); - $response = Response::getInstance(); - if ($response->isAjax()) { - if ($message->isSuccess()) { - $items = $this->dbi->getTriggers($db, $table, ''); - $trigger = false; - foreach ($items as $value) { - if ($value['name'] == $_POST['item_name']) { - $trigger = $value; - } - } - $insert = false; - if (empty($table) - || ($trigger !== false && $table == $trigger['table']) - ) { - $insert = true; - $response->addJSON('new_row', $this->rteList->getTriggerRow($trigger)); - $response->addJSON( - 'name', - htmlspecialchars( - mb_strtoupper( - $_POST['item_name'] - ) - ) - ); - } - $response->addJSON('insert', $insert); - $response->addJSON('message', $output); - } else { - $response->addJSON('message', $message); - $response->setRequestStatus(false); - } - exit; - } - } - - /** - * Display a form used to add/edit a trigger, if necessary - */ - if (count($errors) - || (empty($_POST['editor_process_add']) - && empty($_POST['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 = $this->words->get('add'); - $item = $this->getDataFromRequest(); - $mode = 'add'; - } elseif (! empty($_REQUEST['edit_item'])) { - $title = __("Edit trigger"); - if (! empty($_REQUEST['item_name']) - && empty($_POST['editor_process_edit']) - ) { - $item = $this->getDataFromName($_REQUEST['item_name']); - if ($item !== false) { - $item['item_original_name'] = $item['item_name']; - } - } else { - $item = $this->getDataFromRequest(); - } - $mode = 'edit'; - } - $this->general->sendEditor('TRI', $mode, $item, $title, $db); - } - } - - /** - * This function will generate the values that are required to for the editor - * - * @return array Data necessary to create the editor. - */ - public function getDataFromRequest() - { - $retval = []; - $indices = [ - 'item_name', - 'item_table', - 'item_original_name', - 'item_action_timing', - 'item_event_manipulation', - 'item_definition', - 'item_definer', - ]; - foreach ($indices as $index) { - $retval[$index] = isset($_POST[$index]) ? $_POST[$index] : ''; - } - return $retval; - } - - /** - * 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|bool Data necessary to create the editor. - */ - public function getDataFromName($name) - { - global $db, $table; - - $temp = []; - $items = $this->dbi->getTriggers($db, $table, ''); - foreach ($items as $value) { - if ($value['name'] == $name) { - $temp = $value; - } - } - if (empty($temp)) { - return false; - } else { - $retval = []; - $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; - } - } - - /** - * Displays a form used to add/edit a trigger - * - * @param string $mode If the editor will be used to edit a trigger - * or add a new one: 'edit' or 'add'. - * @param array $item Data for the trigger returned by getDataFromRequest() - * or getDataFromName() - * - * @return string HTML code for the editor. - */ - public function getEditorForm($mode, array $item) - { - global $db, $table, $event_manipulations, $action_timings; - - $modeToUpper = mb_strtoupper($mode); - $response = Response::getInstance(); - - // Escape special characters - $need_escape = [ - '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`='" . $this->dbi->escapeString($db) . "' "; - $query .= "AND `TABLE_TYPE` IN ('BASE TABLE', 'SYSTEM VERSIONED')"; - $tables = $this->dbi->fetchResult($query); - - // Create the output - $retval = ""; - $retval .= "\n\n"; - $retval .= "
    \n"; - $retval .= "\n"; - $retval .= $original_data; - $retval .= Url::getHiddenInputs($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 .= " '; - - $html_output .= ''; - - $html_output .= '' - . '' - . '' - . '' - . ''; - $current_user = $row['User']; - $current_host = $row['Host']; - $routine = $row['Routine_name']; - $html_output .= ''; - $html_output .= ''; - - $html_output .= ''; - } - return $html_output; - } - - /** - * Get the HTML for user form and check the privileges for a particular database. - * - * @param string $db database name - * - * @return string - */ - public function getHtmlForSpecificDbPrivileges($db) - { - $html_output = ''; - - if ($this->dbi->isSuperuser()) { - // check the privileges for a particular database. - $html_output = ''; - $html_output .= Url::getHiddenInputs($db); - $html_output .= '
    '; - $html_output .= '
    '; - $html_output .= '' . "\n" - . Util::getIcon('b_usrcheck') - . ' ' - . sprintf( - __('Users having access to "%s"'), - '' - . htmlspecialchars($db) - . '' - ) - . "\n" - . '' . "\n"; - - $html_output .= '
    '; - $html_output .= '
    " . __('Trigger name') . "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "
    " . _pgettext('Trigger action time', 'Time') . "
    " . __('Event') . "
    " . __('Definition') . "
    " . __('Definer') . "isAjax()) { - $retval .= "\n"; - $retval .= "\n"; - } - $retval .= "\n\n"; - $retval .= "\n\n"; - - return $retval; - } - - /** - * Composes the query necessary to create a trigger from an HTTP request. - * - * @return string The CREATE TRIGGER query. - */ - public function getQueryFromRequest() - { - global $db, $errors, $action_timings, $event_manipulations; - - $query = 'CREATE '; - if (! empty($_POST['item_definer'])) { - if (mb_strpos($_POST['item_definer'], '@') !== false - ) { - $arr = explode('@', $_POST['item_definer']); - $query .= 'DEFINER=' . Util::backquote($arr[0]); - $query .= '@' . Util::backquote($arr[1]) . ' '; - } else { - $errors[] = __('The definer must be in the "username@hostname" format!'); - } - } - $query .= 'TRIGGER '; - if (! empty($_POST['item_name'])) { - $query .= Util::backquote($_POST['item_name']) . ' '; - } else { - $errors[] = __('You must provide a trigger name!'); - } - if (! empty($_POST['item_timing']) - && in_array($_POST['item_timing'], $action_timings) - ) { - $query .= $_POST['item_timing'] . ' '; - } else { - $errors[] = __('You must provide a valid timing for the trigger!'); - } - if (! empty($_POST['item_event']) - && in_array($_POST['item_event'], $event_manipulations) - ) { - $query .= $_POST['item_event'] . ' '; - } else { - $errors[] = __('You must provide a valid event for the trigger!'); - } - $query .= 'ON '; - if (! empty($_POST['item_table']) - && in_array($_POST['item_table'], $this->dbi->getTables($db)) - ) { - $query .= Util::backquote($_POST['item_table']); - } else { - $errors[] = __('You must provide a valid table name!'); - } - $query .= ' FOR EACH ROW '; - if (! empty($_POST['item_definition'])) { - $query .= $_POST['item_definition']; - } else { - $errors[] = __('You must provide a trigger definition.'); - } - - return $query; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Rte/Words.php b/srcs/phpmyadmin/libraries/classes/Rte/Words.php deleted file mode 100644 index f308003..0000000 --- a/srcs/phpmyadmin/libraries/classes/Rte/Words.php +++ /dev/null @@ -1,89 +0,0 @@ - __('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.' - ), - 'no_edit' => __( - 'No routine with name %1$s found in database %2$s. ' - . 'You might be lacking the necessary privileges to edit this routine.' - ), - 'no_view' => __( - 'No routine with name %1$s found in database %2$s. ' - . 'You might be lacking the necessary privileges to view/export this 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 = [ - '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 = [ - '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 = []; - break; - } - - return isset($words[$index]) ? $words[$index] : ''; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Sanitize.php b/srcs/phpmyadmin/libraries/classes/Sanitize.php deleted file mode 100644 index bbb58c4..0000000 --- a/srcs/phpmyadmin/libraries/classes/Sanitize.php +++ /dev/null @@ -1,469 +0,0 @@ -get('is_setup'); - // Adjust path to setup script location - if ($is_setup) { - foreach ($valid_starts as $key => $value) { - if (substr($value, 0, 2) === './') { - $valid_starts[$key] = '.' . $value; - } - } - } - if ($other) { - $valid_starts[] = 'mailto:'; - $valid_starts[] = 'ftp://'; - } - if ($http) { - $valid_starts[] = 'http://'; - } - if ($is_setup) { - $valid_starts[] = '?page=form&'; - $valid_starts[] = '?page=servers&'; - } - foreach ($valid_starts as $val) { - if (substr($url, 0, strlen($val)) == $val) { - return true; - } - } - return false; - } - - /** - * Callback function for replacing [a@link@target] links in bb code. - * - * @param array $found Array of preg matches - * - * @return string Replaced string - */ - public static function replaceBBLink(array $found) - { - /* Check for valid link */ - if (! self::checkLink($found[1])) { - return $found[0]; - } - /* a-z and _ allowed in target */ - if (! empty($found[3]) && preg_match('/[^a-z_]+/i', $found[3])) { - return $found[0]; - } - - /* Construct target */ - $target = ''; - if (! empty($found[3])) { - $target = ' target="' . $found[3] . '"'; - if ($found[3] == '_blank') { - $target .= ' rel="noopener noreferrer"'; - } - } - - /* Construct url */ - if (substr($found[1], 0, 4) == 'http') { - $url = Core::linkURL($found[1]); - } else { - $url = $found[1]; - } - - return ''; - } - - /** - * Callback function for replacing [doc@anchor] links in bb code. - * - * @param array $found Array of preg matches - * - * @return string Replaced string - */ - public static function replaceDocLink(array $found) - { - if (count($found) >= 4) { - $page = $found[1]; - $anchor = $found[3]; - } else { - $anchor = $found[1]; - if (strncmp('faq', $anchor, 3) == 0) { - $page = 'faq'; - } elseif (strncmp('cfg', $anchor, 3) == 0) { - $page = 'config'; - } else { - /* Guess */ - $page = 'setup'; - } - } - $link = 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 - */ - public static function sanitizeMessage($message, $escape = false, $safe = false) - { - if (! $safe) { - $message = strtr((string) $message, ['<' => '<', '>' => '>']); - } - - /* Interpret bb code */ - $replace_pairs = [ - '[em]' => '', - '[/em]' => '', - '[strong]' => '', - '[/strong]' => '', - '[code]' => '', - '[/code]' => '', - '[kbd]' => '', - '[/kbd]' => '', - '[br]' => '
    ', - '[/a]' => '', - '[/doc]' => '', - '[sup]' => '', - '[/sup]' => '', - // used in common.inc.php: - '[conferr]' => '', - // used in libraries/Util.php - '[dochelpicon]' => Util::getImage('b_help', __('Documentation')), - ]; - - $message = strtr($message, $replace_pairs); - - /* Match links in bb code ([a@url@target], where @target is options) */ - $pattern = '/\[a@([^]"@]*)(@([^]"]*))?\]/'; - - /* Find and replace all links */ - $message = preg_replace_callback($pattern, function ($match) { - return self::replaceBBLink($match); - }, $message); - - /* Replace documentation links */ - $message = preg_replace_callback( - '/\[doc@([a-zA-Z0-9_-]+)(@([a-zA-Z0-9_-]*))?\]/', - function ($match) { - return self::replaceDocLink($match); - }, - $message - ); - - /* Possibly escape result */ - if ($escape) { - $message = htmlspecialchars($message); - } - - return $message; - } - - - /** - * Sanitize a filename by removing anything besides legit characters - * - * Intended usecase: - * When using a filename in a Content-Disposition header - * the value should not contain ; or " - * - * When exporting, avoiding generation of an unexpected double-extension file - * - * @param string $filename The filename - * @param boolean $replaceDots Whether to also replace dots - * - * @return string the sanitized filename - * - */ - public static function sanitizeFilename($filename, $replaceDots = false) - { - $pattern = '/[^A-Za-z0-9_'; - // if we don't have to replace dots - if (! $replaceDots) { - // then add the dot to the list of legit characters - $pattern .= '.'; - } - $pattern .= '-]/'; - $filename = preg_replace($pattern, '_', $filename); - return $filename; - } - - /** - * Format a string so it can be a string inside JavaScript code inside an - * eventhandler (onclick, onchange, on..., ). - * This function is used to displays a javascript confirmation box for - * "DROP/DELETE/ALTER" queries. - * - * @param string $a_string the string to format - * @param boolean $add_backquotes whether to add backquotes to the string or not - * - * @return string the formatted string - * - * @access public - */ - public static function jsFormat($a_string = '', $add_backquotes = true) - { - $a_string = htmlspecialchars((string) $a_string); - $a_string = self::escapeJsString($a_string); - // Needed for inline javascript to prevent some browsers - // treating it as a anchor - $a_string = str_replace('#', '\\#', $a_string); - - return $add_backquotes - ? Util::backquote($a_string) - : $a_string; - } // end of the 'jsFormat' function - - /** - * escapes a string to be inserted as string a JavaScript block - * enclosed by - * 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. - */ - public static function formatJsVal($value) - { - if (is_bool($value)) { - if ($value) { - return 'true'; - } - - return 'false'; - } - - if (is_int($value)) { - return (int) $value; - } - - return '"' . self::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. - */ - public static function getJsValue($key, $value, $escape = true) - { - $result = $key . ' = '; - if (! $escape) { - $result .= $value; - } elseif (is_array($value)) { - $result .= '['; - foreach ($value as $val) { - $result .= self::formatJsVal($val) . ","; - } - $result .= "];\n"; - } else { - $result .= self::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 - */ - public static function printJsValue($key, $value) - { - echo self::getJsValue($key, $value); - } - - /** - * Formats javascript assignment for form validation api - * with proper escaping of a value. - * - * @param string $key Name of value to set - * @param string $value Value to set - * @param boolean $addOn Check if $.validator.format is required or not - * @param boolean $comma Check if comma is required - * - * @return string Javascript code. - */ - public static function getJsValueForFormValidation($key, $value, $addOn, $comma) - { - $result = $key . ': '; - if ($addOn) { - $result .= '$.validator.format('; - } - $result .= self::formatJsVal($value); - if ($addOn) { - $result .= ')'; - } - if ($comma) { - $result .= ', '; - } - return $result; - } - - /** - * Prints javascript assignment for form validation api - * with proper escaping of a value. - * - * @param string $key Name of value to set - * @param string $value Value to set - * @param boolean $addOn Check if $.validator.format is required or not - * @param boolean $comma Check if comma is required - * - * @return void - */ - public static function printJsValueForFormValidation($key, $value, $addOn = false, $comma = true) - { - echo self::getJsValueForFormValidation($key, $value, $addOn, $comma); - } - - /** - * Removes all variables from request except whitelisted ones. - * - * @param string[] $whitelist list of variables to allow - * - * @return void - * @access public - */ - public static function removeRequestVars(&$whitelist): void - { - // do not check only $_REQUEST because it could have been overwritten - // and use type casting because the variables could have become - // strings - if (! isset($_REQUEST)) { - $_REQUEST = []; - } - if (! isset($_GET)) { - $_GET = []; - } - if (! isset($_POST)) { - $_POST = []; - } - if (! isset($_COOKIE)) { - $_COOKIE = []; - } - $keys = array_keys( - array_merge((array) $_REQUEST, (array) $_GET, (array) $_POST, (array) $_COOKIE) - ); - - foreach ($keys as $key) { - if (! in_array($key, $whitelist)) { - unset($_REQUEST[$key], $_GET[$key], $_POST[$key]); - continue; - } - - // allowed stuff could be compromised so escape it - // we require it to be a string - if (isset($_REQUEST[$key]) && ! is_string($_REQUEST[$key])) { - unset($_REQUEST[$key]); - } - if (isset($_POST[$key]) && ! is_string($_POST[$key])) { - unset($_POST[$key]); - } - if (isset($_COOKIE[$key]) && ! is_string($_COOKIE[$key])) { - unset($_COOKIE[$key]); - } - if (isset($_GET[$key]) && ! is_string($_GET[$key])) { - unset($_GET[$key]); - } - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/SavedSearches.php b/srcs/phpmyadmin/libraries/classes/SavedSearches.php deleted file mode 100644 index a89d661..0000000 --- a/srcs/phpmyadmin/libraries/classes/SavedSearches.php +++ /dev/null @@ -1,466 +0,0 @@ -setConfig($config); - $this->relation = $relation; - } - - /** - * Setter of id - * - * @param int|null $searchId Id of search - * - * @return static - */ - public function setId($searchId) - { - $searchId = (int) $searchId; - if (empty($searchId)) { - $searchId = null; - } - - $this->_id = $searchId; - return $this; - } - - /** - * Getter of id - * - * @return int|null - */ - public function getId() - { - return $this->_id; - } - - /** - * Setter of searchName - * - * @param string $searchName Saved search name - * - * @return static - */ - public function setSearchName($searchName) - { - $this->_searchName = $searchName; - return $this; - } - - /** - * Getter of searchName - * - * @return string - */ - public function getSearchName() - { - return $this->_searchName; - } - - /** - * Setter of config - * - * @param array $config Global configuration - * - * @return static - */ - public function setConfig(array $config) - { - $this->_config = $config; - return $this; - } - - /** - * Getter of config - * - * @return array - */ - public function getConfig() - { - return $this->_config; - } - - /** - * Setter for criterias - * - * @param array|string $criterias Criterias of saved searches - * @param bool $json Criterias are in JSON format - * - * @return static - */ - public function setCriterias($criterias, $json = false) - { - if (true === $json && is_string($criterias)) { - $this->_criterias = json_decode($criterias, true); - return $this; - } - - $aListFieldsToGet = [ - 'criteriaColumn', - 'criteriaSort', - 'criteriaShow', - 'criteria', - 'criteriaAndOrRow', - 'criteriaAndOrColumn', - 'rows', - 'TableList', - ]; - - $data = []; - - $data['criteriaColumnCount'] = count($criterias['criteriaColumn']); - - foreach ($aListFieldsToGet as $field) { - if (isset($criterias[$field])) { - $data[$field] = $criterias[$field]; - } - } - - /* Limit amount of rows */ - if (! isset($data['rows'])) { - $data['rows'] = 0; - } else { - $data['rows'] = min( - max(0, intval($data['rows'])), - 100 - ); - } - - for ($i = 0; $i <= $data['rows']; $i++) { - $data['Or' . $i] = $criterias['Or' . $i]; - } - - $this->_criterias = $data; - return $this; - } - - /** - * Getter for criterias - * - * @return array - */ - public function getCriterias() - { - return $this->_criterias; - } - - /** - * Setter for username - * - * @param string $username Username - * - * @return static - */ - public function setUsername($username) - { - $this->_username = $username; - return $this; - } - - /** - * Getter for username - * - * @return string - */ - public function getUsername() - { - return $this->_username; - } - - /** - * Setter for DB name - * - * @param string $dbname DB name - * - * @return static - */ - public function setDbname($dbname) - { - $this->_dbname = $dbname; - return $this; - } - - /** - * Getter for DB name - * - * @return string - */ - public function getDbname() - { - return $this->_dbname; - } - - /** - * Save the search - * - * @return boolean - */ - public function save() - { - if (null == $this->getSearchName()) { - $message = Message::error( - __('Please provide a name for this bookmarked search.') - ); - $response = Response::getInstance(); - $response->setRequestStatus($message->isSuccess()); - $response->addJSON('fieldWithError', 'searchName'); - $response->addJSON('message', $message); - exit; - } - - if (null == $this->getUsername() - || null == $this->getDbname() - || null == $this->getSearchName() - || null == $this->getCriterias() - ) { - $message = Message::error( - __('Missing information to save the bookmarked search.') - ); - $response = Response::getInstance(); - $response->setRequestStatus($message->isSuccess()); - $response->addJSON('message', $message); - exit; - } - - $savedSearchesTbl - = Util::backquote($this->_config['cfgRelation']['db']) . "." - . Util::backquote($this->_config['cfgRelation']['savedsearches']); - - //If it's an insert. - if (null === $this->getId()) { - $wheres = [ - "search_name = '" . $GLOBALS['dbi']->escapeString($this->getSearchName()) - . "'", - ]; - $existingSearches = $this->getList($wheres); - - if (! empty($existingSearches)) { - $message = Message::error( - __('An entry with this name already exists.') - ); - $response = Response::getInstance(); - $response->setRequestStatus($message->isSuccess()); - $response->addJSON('fieldWithError', 'searchName'); - $response->addJSON('message', $message); - exit; - } - - $sqlQuery = "INSERT INTO " . $savedSearchesTbl - . "(`username`, `db_name`, `search_name`, `search_data`)" - . " VALUES (" - . "'" . $GLOBALS['dbi']->escapeString($this->getUsername()) . "'," - . "'" . $GLOBALS['dbi']->escapeString($this->getDbname()) . "'," - . "'" . $GLOBALS['dbi']->escapeString($this->getSearchName()) . "'," - . "'" . $GLOBALS['dbi']->escapeString(json_encode($this->getCriterias())) - . "')"; - - $result = (bool) $this->relation->queryAsControlUser($sqlQuery); - if (! $result) { - return false; - } - - $this->setId($GLOBALS['dbi']->insertId()); - - return true; - } - - //Else, it's an update. - $wheres = [ - "id != " . $this->getId(), - "search_name = '" . $GLOBALS['dbi']->escapeString($this->getSearchName()) . "'", - ]; - $existingSearches = $this->getList($wheres); - - if (! empty($existingSearches)) { - $message = Message::error( - __('An entry with this name already exists.') - ); - $response = Response::getInstance(); - $response->setRequestStatus($message->isSuccess()); - $response->addJSON('fieldWithError', 'searchName'); - $response->addJSON('message', $message); - exit; - } - - $sqlQuery = "UPDATE " . $savedSearchesTbl - . "SET `search_name` = '" - . $GLOBALS['dbi']->escapeString($this->getSearchName()) . "', " - . "`search_data` = '" - . $GLOBALS['dbi']->escapeString(json_encode($this->getCriterias())) . "' " - . "WHERE id = " . $this->getId(); - return (bool) $this->relation->queryAsControlUser($sqlQuery); - } - - /** - * Delete the search - * - * @return boolean - */ - public function delete() - { - if (null == $this->getId()) { - $message = Message::error( - __('Missing information to delete the search.') - ); - $response = Response::getInstance(); - $response->setRequestStatus($message->isSuccess()); - $response->addJSON('fieldWithError', 'searchId'); - $response->addJSON('message', $message); - exit; - } - - $savedSearchesTbl - = Util::backquote($this->_config['cfgRelation']['db']) . "." - . Util::backquote($this->_config['cfgRelation']['savedsearches']); - - $sqlQuery = "DELETE FROM " . $savedSearchesTbl - . "WHERE id = '" . $GLOBALS['dbi']->escapeString($this->getId()) . "'"; - - return (bool) $this->relation->queryAsControlUser($sqlQuery); - } - - /** - * Load the current search from an id. - * - * @return bool Success - */ - public function load() - { - if (null == $this->getId()) { - $message = Message::error( - __('Missing information to load the search.') - ); - $response = Response::getInstance(); - $response->setRequestStatus($message->isSuccess()); - $response->addJSON('fieldWithError', 'searchId'); - $response->addJSON('message', $message); - exit; - } - - $savedSearchesTbl = Util::backquote($this->_config['cfgRelation']['db']) - . "." - . Util::backquote($this->_config['cfgRelation']['savedsearches']); - $sqlQuery = "SELECT id, search_name, search_data " - . "FROM " . $savedSearchesTbl . " " - . "WHERE id = '" . $GLOBALS['dbi']->escapeString($this->getId()) . "' "; - - $resList = $this->relation->queryAsControlUser($sqlQuery); - - if (false === ($oneResult = $GLOBALS['dbi']->fetchArray($resList))) { - $message = Message::error(__('Error while loading the search.')); - $response = Response::getInstance(); - $response->setRequestStatus($message->isSuccess()); - $response->addJSON('fieldWithError', 'searchId'); - $response->addJSON('message', $message); - exit; - } - - $this->setSearchName($oneResult['search_name']) - ->setCriterias($oneResult['search_data'], true); - - return true; - } - - /** - * Get the list of saved searches of a user on a DB - * - * @param string[] $wheres List of filters - * - * @return array List of saved searches or empty array on failure - */ - public function getList(array $wheres = []) - { - if (null == $this->getUsername() - || null == $this->getDbname() - ) { - return []; - } - - $savedSearchesTbl = Util::backquote($this->_config['cfgRelation']['db']) - . "." - . Util::backquote($this->_config['cfgRelation']['savedsearches']); - $sqlQuery = "SELECT id, search_name " - . "FROM " . $savedSearchesTbl . " " - . "WHERE " - . "username = '" . $GLOBALS['dbi']->escapeString($this->getUsername()) . "' " - . "AND db_name = '" . $GLOBALS['dbi']->escapeString($this->getDbname()) . "' "; - - foreach ($wheres as $where) { - $sqlQuery .= "AND " . $where . " "; - } - - $sqlQuery .= "order by search_name ASC "; - - $resList = $this->relation->queryAsControlUser($sqlQuery); - - $list = []; - while ($oneResult = $GLOBALS['dbi']->fetchArray($resList)) { - $list[$oneResult['id']] = $oneResult['search_name']; - } - - return $list; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Scripts.php b/srcs/phpmyadmin/libraries/classes/Scripts.php deleted file mode 100644 index 498f419..0000000 --- a/srcs/phpmyadmin/libraries/classes/Scripts.php +++ /dev/null @@ -1,164 +0,0 @@ -template = new Template(); - $this->_files = []; - $this->_code = ''; - } - - /** - * Adds a new file to the list of scripts - * - * @param string $filename The name of the file to include - * @param array $params Additional parameters to pass to the file - * - * @return void - */ - public function addFile( - $filename, - array $params = [] - ) { - $hash = md5($filename); - if (! empty($this->_files[$hash])) { - return; - } - - $has_onload = $this->_eventBlacklist($filename); - $this->_files[$hash] = [ - 'has_onload' => $has_onload, - 'filename' => $filename, - 'params' => $params, - ]; - } - - /** - * Add new files to the list of scripts - * - * @param array $filelist The array of file names - * - * @return void - */ - public function addFiles(array $filelist) - { - foreach ($filelist as $filename) { - $this->addFile($filename); - } - } - - /** - * 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, 'cross_framing_protection.js') !== false - ) { - return 0; - } - - 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"; - } - - /** - * Returns a list with filenames and a flag to indicate - * whether to register onload events for this file - * - * @return array - */ - public function getFiles() - { - $retval = []; - foreach ($this->_files as $file) { - //If filename contains a "?", continue. - if (strpos($file['filename'], "?") !== false) { - continue; - } - $retval[] = [ - 'name' => $file['filename'], - 'fire' => $file['has_onload'], - ]; - } - return $retval; - } - - /** - * Renders all the JavaScript file inclusions, code and events - * - * @return string - */ - public function getDisplay() - { - return $this->template->render('scripts', [ - 'files' => $this->_files, - 'version' => PMA_VERSION, - 'code' => $this->_code, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Server/Plugin.php b/srcs/phpmyadmin/libraries/classes/Server/Plugin.php deleted file mode 100644 index 9b45297..0000000 --- a/srcs/phpmyadmin/libraries/classes/Server/Plugin.php +++ /dev/null @@ -1,274 +0,0 @@ -name = $name; - $this->version = $version; - $this->status = $status; - $this->type = $type; - $this->typeVersion = $typeVersion; - $this->library = $library; - $this->libraryVersion = $libraryVersion; - $this->author = $author; - $this->description = $description; - $this->license = $license; - $this->loadOption = $loadOption; - $this->maturity = $maturity; - $this->authVersion = $authVersion; - } - - /** - * @param array $state array with the properties - * @return self - */ - public static function fromState(array $state): self - { - return new self( - $state['name'] ?? '', - $state['version'] ?? null, - $state['status'] ?? '', - $state['type'] ?? '', - $state['typeVersion'] ?? null, - $state['library'] ?? null, - $state['libraryVersion'] ?? null, - $state['author'] ?? null, - $state['description'] ?? null, - $state['license'] ?? '', - $state['loadOption'] ?? null, - $state['maturity'] ?? null, - $state['authVersion'] ?? null - ); - } - - /** - * @return array - */ - public function toArray(): array - { - return [ - 'name' => $this->getName(), - 'version' => $this->getVersion(), - 'status' => $this->getStatus(), - 'type' => $this->getType(), - 'type_version' => $this->getTypeVersion(), - 'library' => $this->getLibrary(), - 'library_version' => $this->getLibraryVersion(), - 'author' => $this->getAuthor(), - 'description' => $this->getDescription(), - 'license' => $this->getLicense(), - 'load_option' => $this->getLoadOption(), - 'maturity' => $this->getMaturity(), - 'auth_version' => $this->getAuthVersion(), - ]; - } - - /** - * @return string - */ - public function getName(): string - { - return $this->name; - } - - /** - * @return string|null - */ - public function getVersion(): ?string - { - return $this->version; - } - - /** - * @return string - */ - public function getStatus(): string - { - return $this->status; - } - - /** - * @return string - */ - public function getType(): string - { - return $this->type; - } - - /** - * @return string|null - */ - public function getTypeVersion(): ?string - { - return $this->typeVersion; - } - - /** - * @return string|null - */ - public function getLibrary(): ?string - { - return $this->library; - } - - /** - * @return string|null - */ - public function getLibraryVersion(): ?string - { - return $this->libraryVersion; - } - - /** - * @return string|null - */ - public function getAuthor(): ?string - { - return $this->author; - } - - /** - * @return string|null - */ - public function getDescription(): ?string - { - return $this->description; - } - - /** - * @return string - */ - public function getLicense(): string - { - return $this->license; - } - - /** - * @return string|null - */ - public function getLoadOption(): ?string - { - return $this->loadOption; - } - - /** - * @return string|null - */ - public function getMaturity(): ?string - { - return $this->maturity; - } - - /** - * @return string|null - */ - public function getAuthVersion(): ?string - { - return $this->authVersion; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Server/Plugins.php b/srcs/phpmyadmin/libraries/classes/Server/Plugins.php deleted file mode 100644 index eb8e85a..0000000 --- a/srcs/phpmyadmin/libraries/classes/Server/Plugins.php +++ /dev/null @@ -1,74 +0,0 @@ -dbi = $dbi; - } - - /** - * @return Plugin[] - */ - public function getAll(): array - { - global $cfg; - - $sql = 'SHOW PLUGINS'; - if (! $cfg['Server']['DisableIS']) { - $sql = 'SELECT * FROM information_schema.PLUGINS ORDER BY PLUGIN_TYPE, PLUGIN_NAME'; - } - $result = $this->dbi->query($sql); - $plugins = []; - while ($row = $this->dbi->fetchAssoc($result)) { - $plugins[] = $this->mapRowToPlugin($row); - } - $this->dbi->freeResult($result); - - return $plugins; - } - - /** - * @param array $row Row fetched from database - * @return Plugin - */ - private function mapRowToPlugin(array $row): Plugin - { - return Plugin::fromState([ - 'name' => $row['PLUGIN_NAME'] ?? $row['Name'], - 'version' => $row['PLUGIN_VERSION'] ?? null, - 'status' => $row['PLUGIN_STATUS'] ?? $row['Status'], - 'type' => $row['PLUGIN_TYPE'] ?? $row['Type'], - 'typeVersion' => $row['PLUGIN_TYPE_VERSION'] ?? null, - 'library' => $row['PLUGIN_LIBRARY'] ?? $row['Library'] ?? null, - 'libraryVersion' => $row['PLUGIN_LIBRARY_VERSION'] ?? null, - 'author' => $row['PLUGIN_AUTHOR'] ?? null, - 'description' => $row['PLUGIN_DESCRIPTION'] ?? null, - 'license' => $row['PLUGIN_LICENSE'] ?? $row['License'], - 'loadOption' => $row['LOAD_OPTION'] ?? null, - 'maturity' => $row['PLUGIN_MATURITY'] ?? null, - 'authVersion' => $row['PLUGIN_AUTH_VERSION'] ?? null, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Server/Privileges.php b/srcs/phpmyadmin/libraries/classes/Server/Privileges.php deleted file mode 100644 index 1e50fbb..0000000 --- a/srcs/phpmyadmin/libraries/classes/Server/Privileges.php +++ /dev/null @@ -1,5649 +0,0 @@ -template = $template; - $this->dbi = $dbi; - $this->relation = $relation; - $this->relationCleanup = $relationCleanup; - } - - /** - * Get Html for User Group Dialog - * - * @param string $username username - * @param bool $is_menuswork Is menuswork set in configuration - * - * @return string html - */ - public function getHtmlForUserGroupDialog($username, $is_menuswork) - { - $html = ''; - if (! empty($_GET['edit_user_group_dialog']) && $is_menuswork) { - $dialog = $this->getHtmlToChooseUserGroup($username); - $response = Response::getInstance(); - if ($response->isAjax()) { - $response->addJSON('message', $dialog); - exit; - } else { - $html .= $dialog; - } - } - - return $html; - } - - /** - * Escapes wildcard in a database+table specification - * before using it in a GRANT statement. - * - * Escaping a wildcard character in a GRANT is only accepted at the global - * or database level, not at table level; this is why I remove - * the escaping character. Internally, in mysql.tables_priv.Db there are - * no escaping (for example test_db) but in mysql.db you'll see test\_db - * for a db-specific privilege. - * - * @param string $dbname Database name - * @param string $tablename Table name - * - * @return string the escaped (if necessary) database.table - */ - public function wildcardEscapeForGrant($dbname, $tablename) - { - if (strlen($dbname) === 0) { - $db_and_table = '*.*'; - } else { - if (strlen($tablename) > 0) { - $db_and_table = Util::backquote( - Util::unescapeMysqlWildcards($dbname) - ) - . '.' . Util::backquote($tablename); - } else { - $db_and_table = Util::backquote($dbname) . '.*'; - } - } - return $db_and_table; - } - - /** - * Generates a condition on the user name - * - * @param string $initial the user's initial - * - * @return string the generated condition - */ - public function rangeOfUsers($initial = '') - { - // strtolower() is used because the User field - // might be BINARY, so LIKE would be case sensitive - if ($initial === null || $initial === '') { - return ''; - } - - $ret = " WHERE `User` LIKE '" - . $this->dbi->escapeString($initial) . "%'" - . " OR `User` LIKE '" - . $this->dbi->escapeString(mb_strtolower($initial)) - . "%'"; - return $ret; - } // end function - - /** - * Formats privilege name for a display - * - * @param array $privilege Privilege information - * @param boolean $html Whether to use HTML - * - * @return string - */ - public function formatPrivilege(array $privilege, $html) - { - if ($html) { - return '' - . $privilege[1] . ''; - } - - return $privilege[1]; - } - - /** - * Parses privileges into an array, it modifies the array - * - * @param array $row Results row from - * - * @return void - */ - public function fillInTablePrivileges(array &$row) - { - $row1 = $this->dbi->fetchSingleRow( - 'SHOW COLUMNS FROM `mysql`.`tables_priv` LIKE \'Table_priv\';', - 'ASSOC' - ); - // note: in MySQL 5.0.3 we get "Create View', 'Show view'; - // the View for Create is spelled with uppercase V - // the view for Show is spelled with lowercase v - // and there is a space between the words - - $av_grants = explode( - '\',\'', - mb_substr( - $row1['Type'], - mb_strpos($row1['Type'], '(') + 2, - mb_strpos($row1['Type'], ')') - - mb_strpos($row1['Type'], '(') - 3 - ) - ); - - $users_grants = explode(',', $row['Table_priv']); - - foreach ($av_grants as $current_grant) { - $row[$current_grant . '_priv'] - = in_array($current_grant, $users_grants) ? 'Y' : 'N'; - } - unset($row['Table_priv']); - } - - - /** - * Extracts the privilege information of a priv table row - * - * @param array|null $row the row - * @param boolean $enableHTML add tag with tooltips - * @param boolean $tablePrivs whether row contains table privileges - * - * @global resource $user_link the database connection - * - * @return array - */ - public function extractPrivInfo($row = null, $enableHTML = false, $tablePrivs = false) - { - if ($tablePrivs) { - $grants = $this->getTableGrantsArray(); - } else { - $grants = $this->getGrantsArray(); - } - - if ($row !== null && isset($row['Table_priv'])) { - $this->fillInTablePrivileges($row); - } - - $privs = []; - $allPrivileges = true; - foreach ($grants as $current_grant) { - if (($row !== null && isset($row[$current_grant[0]])) - || ($row === null && isset($GLOBALS[$current_grant[0]])) - ) { - if (($row !== null && $row[$current_grant[0]] == 'Y') - || ($row === null - && ($GLOBALS[$current_grant[0]] == 'Y' - || (is_array($GLOBALS[$current_grant[0]]) - && count($GLOBALS[$current_grant[0]]) == $_REQUEST['column_count'] - && empty($GLOBALS[$current_grant[0] . '_none'])))) - ) { - $privs[] = $this->formatPrivilege($current_grant, $enableHTML); - } elseif (! empty($GLOBALS[$current_grant[0]]) - && is_array($GLOBALS[$current_grant[0]]) - && empty($GLOBALS[$current_grant[0] . '_none']) - ) { - // Required for proper escaping of ` (backtick) in a column name - $grant_cols = array_map( - function ($val) { - return Util::backquote($val); - }, - $GLOBALS[$current_grant[0]] - ); - - $privs[] = $this->formatPrivilege($current_grant, $enableHTML) - . ' (' . implode(', ', $grant_cols) . ')'; - } else { - $allPrivileges = false; - } - } - } - if (empty($privs)) { - if ($enableHTML) { - $privs[] = 'USAGE'; - } else { - $privs[] = 'USAGE'; - } - } elseif ($allPrivileges - && (! isset($_POST['grant_count']) || count($privs) == $_POST['grant_count']) - ) { - if ($enableHTML) { - $privs = ['ALL PRIVILEGES', - ]; - } else { - $privs = ['ALL PRIVILEGES']; - } - } - return $privs; - } - - /** - * Returns an array of table grants and their descriptions - * - * @return array array of table grants - */ - public function getTableGrantsArray() - { - return [ - [ - 'Delete', - 'DELETE', - $GLOBALS['strPrivDescDelete'], - ], - [ - 'Create', - 'CREATE', - $GLOBALS['strPrivDescCreateTbl'], - ], - [ - 'Drop', - 'DROP', - $GLOBALS['strPrivDescDropTbl'], - ], - [ - 'Index', - 'INDEX', - $GLOBALS['strPrivDescIndex'], - ], - [ - 'Alter', - 'ALTER', - $GLOBALS['strPrivDescAlter'], - ], - [ - 'Create View', - 'CREATE_VIEW', - $GLOBALS['strPrivDescCreateView'], - ], - [ - 'Show view', - 'SHOW_VIEW', - $GLOBALS['strPrivDescShowView'], - ], - [ - 'Trigger', - 'TRIGGER', - $GLOBALS['strPrivDescTrigger'], - ], - ]; - } - - /** - * Get the grants array which contains all the privilege types - * and relevant grant messages - * - * @return array - */ - public function getGrantsArray() - { - return [ - [ - 'Select_priv', - 'SELECT', - __('Allows reading data.'), - ], - [ - 'Insert_priv', - 'INSERT', - __('Allows inserting and replacing data.'), - ], - [ - 'Update_priv', - 'UPDATE', - __('Allows changing data.'), - ], - [ - 'Delete_priv', - 'DELETE', - __('Allows deleting data.'), - ], - [ - 'Create_priv', - 'CREATE', - __('Allows creating new databases and tables.'), - ], - [ - 'Drop_priv', - 'DROP', - __('Allows dropping databases and tables.'), - ], - [ - 'Reload_priv', - 'RELOAD', - __('Allows reloading server settings and flushing the server\'s caches.'), - ], - [ - 'Shutdown_priv', - 'SHUTDOWN', - __('Allows shutting down the server.'), - ], - [ - 'Process_priv', - 'PROCESS', - __('Allows viewing processes of all users.'), - ], - [ - 'File_priv', - 'FILE', - __('Allows importing data from and exporting data into files.'), - ], - [ - 'References_priv', - 'REFERENCES', - __('Has no effect in this MySQL version.'), - ], - [ - 'Index_priv', - 'INDEX', - __('Allows creating and dropping indexes.'), - ], - [ - 'Alter_priv', - 'ALTER', - __('Allows altering the structure of existing tables.'), - ], - [ - 'Show_db_priv', - 'SHOW DATABASES', - __('Gives access to the complete list of databases.'), - ], - [ - 'Super_priv', - 'SUPER', - __( - 'Allows connecting, even if maximum number of connections ' - . 'is reached; required for most administrative operations ' - . 'like setting global variables or killing threads of other users.' - ), - ], - [ - 'Create_tmp_table_priv', - 'CREATE TEMPORARY TABLES', - __('Allows creating temporary tables.'), - ], - [ - 'Lock_tables_priv', - 'LOCK TABLES', - __('Allows locking tables for the current thread.'), - ], - [ - 'Repl_slave_priv', - 'REPLICATION SLAVE', - __('Needed for the replication slaves.'), - ], - [ - 'Repl_client_priv', - 'REPLICATION CLIENT', - __('Allows the user to ask where the slaves / masters are.'), - ], - [ - 'Create_view_priv', - 'CREATE VIEW', - __('Allows creating new views.'), - ], - [ - 'Event_priv', - 'EVENT', - __('Allows to set up events for the event scheduler.'), - ], - [ - 'Trigger_priv', - 'TRIGGER', - __('Allows creating and dropping triggers.'), - ], - // for table privs: - [ - 'Create View_priv', - 'CREATE VIEW', - __('Allows creating new views.'), - ], - [ - 'Show_view_priv', - 'SHOW VIEW', - __('Allows performing SHOW CREATE VIEW queries.'), - ], - // for table privs: - [ - 'Show view_priv', - 'SHOW VIEW', - __('Allows performing SHOW CREATE VIEW queries.'), - ], - [ - 'Delete_history_priv', - 'DELETE HISTORY', - $GLOBALS['strPrivDescDeleteHistoricalRows'], - ], - [ - 'Delete versioning rows_priv', - 'DELETE HISTORY', - $GLOBALS['strPrivDescDeleteHistoricalRows'], - ], - [ - 'Create_routine_priv', - 'CREATE ROUTINE', - __('Allows creating stored routines.'), - ], - [ - 'Alter_routine_priv', - 'ALTER ROUTINE', - __('Allows altering and dropping stored routines.'), - ], - [ - 'Create_user_priv', - 'CREATE USER', - __('Allows creating, dropping and renaming user accounts.'), - ], - [ - 'Execute_priv', - 'EXECUTE', - __('Allows executing stored routines.'), - ], - ]; - } - - /** - * Displays on which column(s) a table-specific privilege is granted - * - * @param array $columns columns array - * @param array $row first row from result or boolean false - * @param string $name_for_select privilege types - Select_priv, Insert_priv - * Update_priv, References_priv - * @param string $priv_for_header privilege for header - * @param string $name privilege name: insert, select, update, references - * @param string $name_for_dfn name for dfn - * @param string $name_for_current name for current - * - * @return string html snippet - */ - public function getHtmlForColumnPrivileges( - array $columns, - array $row, - $name_for_select, - $priv_for_header, - $name, - $name_for_dfn, - $name_for_current - ) { - return $this->template->render('server/privileges/column_privileges', [ - 'columns' => $columns, - 'row' => $row, - 'name_for_select' => $name_for_select, - 'priv_for_header' => $priv_for_header, - 'name' => $name, - 'name_for_dfn' => $name_for_dfn, - 'name_for_current' => $name_for_current, - ]); - } - - /** - * Get sql query for display privileges table - * - * @param string $db the database - * @param string $table the table - * @param string $username username for database connection - * @param string $hostname hostname for database connection - * - * @return string sql query - */ - public function getSqlQueryForDisplayPrivTable($db, $table, $username, $hostname) - { - if ($db == '*') { - return "SELECT * FROM `mysql`.`user`" - . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" - . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "';"; - } elseif ($table == '*') { - return "SELECT * FROM `mysql`.`db`" - . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" - . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "'" - . " AND '" . $this->dbi->escapeString(Util::unescapeMysqlWildcards($db)) . "'" - . " LIKE `Db`;"; - } - return "SELECT `Table_priv`" - . " FROM `mysql`.`tables_priv`" - . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" - . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "'" - . " AND `Db` = '" . $this->dbi->escapeString(Util::unescapeMysqlWildcards($db)) . "'" - . " AND `Table_name` = '" . $this->dbi->escapeString($table) . "';"; - } - - /** - * Displays a dropdown to select the user group - * with menu items configured to each of them. - * - * @param string $username username - * - * @return string html to select the user group - */ - public function getHtmlToChooseUserGroup($username) - { - $cfgRelation = $this->relation->getRelationsParam(); - $groupTable = Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['usergroups']); - $userTable = Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['users']); - - $userGroup = ''; - if (isset($GLOBALS['username'])) { - $sql_query = "SELECT `usergroup` FROM " . $userTable - . " WHERE `username` = '" . $this->dbi->escapeString($username) . "'"; - $userGroup = $this->dbi->fetchValue( - $sql_query, - 0, - 0, - DatabaseInterface::CONNECT_CONTROL - ); - } - - $allUserGroups = ['' => '']; - $sql_query = "SELECT DISTINCT `usergroup` FROM " . $groupTable; - $result = $this->relation->queryAsControlUser($sql_query, false); - if ($result) { - while ($row = $this->dbi->fetchRow($result)) { - $allUserGroups[$row[0]] = $row[0]; - } - } - $this->dbi->freeResult($result); - - return $this->template->render('server/privileges/choose_user_group', [ - 'all_user_groups' => $allUserGroups, - 'user_group' => $userGroup, - 'params' => ['username' => $username], - ]); - } - - /** - * Sets the user group from request values - * - * @param string $username username - * @param string $userGroup user group to set - * - * @return void - */ - public function setUserGroup($username, $userGroup) - { - $userGroup = $userGroup === null ? '' : $userGroup; - $cfgRelation = $this->relation->getRelationsParam(); - if (empty($cfgRelation['db']) || empty($cfgRelation['users']) || empty($cfgRelation['usergroups'])) { - return; - } - - $userTable = Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['users']); - - $sql_query = "SELECT `usergroup` FROM " . $userTable - . " WHERE `username` = '" . $this->dbi->escapeString($username) . "'"; - $oldUserGroup = $this->dbi->fetchValue( - $sql_query, - 0, - 0, - DatabaseInterface::CONNECT_CONTROL - ); - - if ($oldUserGroup === false) { - $upd_query = "INSERT INTO " . $userTable . "(`username`, `usergroup`)" - . " VALUES ('" . $this->dbi->escapeString($username) . "', " - . "'" . $this->dbi->escapeString($userGroup) . "')"; - } else { - if (empty($userGroup)) { - $upd_query = "DELETE FROM " . $userTable - . " WHERE `username`='" . $this->dbi->escapeString($username) . "'"; - } elseif ($oldUserGroup != $userGroup) { - $upd_query = "UPDATE " . $userTable - . " SET `usergroup`='" . $this->dbi->escapeString($userGroup) . "'" - . " WHERE `username`='" . $this->dbi->escapeString($username) . "'"; - } - } - if (isset($upd_query)) { - $this->relation->queryAsControlUser($upd_query); - } - } - - /** - * Displays the privileges form table - * - * @param string $db the database - * @param string $table the table - * @param boolean $submit whether to display the submit button or not - * - * @global array $cfg the phpMyAdmin configuration - * @global resource $user_link the database connection - * - * @return string html snippet - */ - public function getHtmlToDisplayPrivilegesTable( - $db = '*', - $table = '*', - $submit = true - ) { - $html_output = ''; - $sql_query = ''; - - if ($db == '*') { - $table = '*'; - } - $username = ''; - $hostname = ''; - if (isset($GLOBALS['username'])) { - $username = $GLOBALS['username']; - $hostname = $GLOBALS['hostname']; - $sql_query = $this->getSqlQueryForDisplayPrivTable( - $db, - $table, - $username, - $hostname - ); - $row = $this->dbi->fetchSingleRow($sql_query); - } - if (empty($row)) { - if ($table == '*' && $this->dbi->isSuperuser()) { - $row = []; - if ($db == '*') { - $sql_query = 'SHOW COLUMNS FROM `mysql`.`user`;'; - } elseif ($table == '*') { - $sql_query = 'SHOW COLUMNS FROM `mysql`.`db`;'; - } - $res = $this->dbi->query($sql_query); - while ($row1 = $this->dbi->fetchRow($res)) { - if (mb_substr($row1[0], 0, 4) == 'max_') { - $row[$row1[0]] = 0; - } elseif (mb_substr($row1[0], 0, 5) == 'x509_' - || mb_substr($row1[0], 0, 4) == 'ssl_' - ) { - $row[$row1[0]] = ''; - } else { - $row[$row1[0]] = 'N'; - } - } - $this->dbi->freeResult($res); - } elseif ($table == '*') { - $row = []; - } else { - $row = ['Table_priv' => '']; - } - } - if (isset($row['Table_priv'])) { - $this->fillInTablePrivileges($row); - - // get columns - $res = $this->dbi->tryQuery( - 'SHOW COLUMNS FROM ' - . Util::backquote( - Util::unescapeMysqlWildcards($db) - ) - . '.' . Util::backquote($table) . ';' - ); - $columns = []; - if ($res) { - while ($row1 = $this->dbi->fetchRow($res)) { - $columns[$row1[0]] = [ - 'Select' => false, - 'Insert' => false, - 'Update' => false, - 'References' => false, - ]; - } - $this->dbi->freeResult($res); - } - unset($res, $row1); - } - // table-specific privileges - if (! empty($columns)) { - $html_output .= $this->getHtmlForTableSpecificPrivileges( - $username, - $hostname, - $db, - $table, - $columns, - $row - ); - } else { - // global or db-specific - $html_output .= $this->getHtmlForGlobalOrDbSpecificPrivs($db, $table, $row); - } - $html_output .= '' . "\n"; - if ($submit) { - $html_output .= '' . "\n"; - } - return $html_output; - } // end of the 'PMA_displayPrivTable()' function - - /** - * Get HTML for "Require" - * - * @param array $row privilege array - * - * @return string html snippet - */ - public function getHtmlForRequires(array $row) - { - $specified = (isset($row['ssl_type']) && $row['ssl_type'] == 'SPECIFIED'); - $require_options = [ - [ - 'name' => 'ssl_type', - 'value' => 'NONE', - 'description' => __( - 'Does not require SSL-encrypted connections.' - ), - 'label' => 'REQUIRE NONE', - 'checked' => isset($row['ssl_type']) - && ($row['ssl_type'] == 'NONE' - || $row['ssl_type'] == '') - ? 'checked="checked"' - : '', - 'disabled' => false, - 'radio' => true, - ], - [ - 'name' => 'ssl_type', - 'value' => 'ANY', - 'description' => __( - 'Requires SSL-encrypted connections.' - ), - 'label' => 'REQUIRE SSL', - 'checked' => isset($row['ssl_type']) && ($row['ssl_type'] == 'ANY') - ? 'checked="checked"' - : '', - 'disabled' => false, - 'radio' => true, - ], - [ - 'name' => 'ssl_type', - 'value' => 'X509', - 'description' => __( - 'Requires a valid X509 certificate.' - ), - 'label' => 'REQUIRE X509', - 'checked' => isset($row['ssl_type']) && ($row['ssl_type'] == 'X509') - ? 'checked="checked"' - : '', - 'disabled' => false, - 'radio' => true, - ], - [ - 'name' => 'ssl_type', - 'value' => 'SPECIFIED', - 'description' => '', - 'label' => 'SPECIFIED', - 'checked' => $specified ? 'checked="checked"' : '', - 'disabled' => false, - 'radio' => true, - ], - [ - 'name' => 'ssl_cipher', - 'value' => isset($row['ssl_cipher']) - ? htmlspecialchars($row['ssl_cipher']) : '', - 'description' => __( - 'Requires that a specific cipher method be used for a connection.' - ), - 'label' => 'REQUIRE CIPHER', - 'checked' => '', - 'disabled' => ! $specified, - 'radio' => false, - ], - [ - 'name' => 'x509_issuer', - 'value' => isset($row['x509_issuer']) - ? htmlspecialchars($row['x509_issuer']) : '', - 'description' => __( - 'Requires that a valid X509 certificate issued by this CA be presented.' - ), - 'label' => 'REQUIRE ISSUER', - 'checked' => '', - 'disabled' => ! $specified, - 'radio' => false, - ], - [ - 'name' => 'x509_subject', - 'value' => isset($row['x509_subject']) - ? htmlspecialchars($row['x509_subject']) : '', - 'description' => __( - 'Requires that a valid X509 certificate with this subject be presented.' - ), - 'label' => 'REQUIRE SUBJECT', - 'checked' => '', - 'disabled' => ! $specified, - 'radio' => false, - ], - ]; - - return $this->template->render('server/privileges/require_options', [ - 'require_options' => $require_options, - ]); - } - - /** - * Get HTML for "Resource limits" - * - * @param array $row first row from result or boolean false - * - * @return string html snippet - */ - public function getHtmlForResourceLimits(array $row) - { - $limits = [ - [ - 'input_name' => 'max_questions', - 'name_main' => 'MAX QUERIES PER HOUR', - 'value' => isset($row['max_questions']) ? $row['max_questions'] : '0', - 'description' => __( - 'Limits the number of queries the user may send to the server per hour.' - ), - ], - [ - 'input_name' => 'max_updates', - 'name_main' => 'MAX UPDATES PER HOUR', - 'value' => isset($row['max_updates']) ? $row['max_updates'] : '0', - 'description' => __( - 'Limits the number of commands that change any table ' - . 'or database the user may execute per hour.' - ), - ], - [ - 'input_name' => 'max_connections', - 'name_main' => 'MAX CONNECTIONS PER HOUR', - 'value' => isset($row['max_connections']) ? $row['max_connections'] : '0', - 'description' => __( - 'Limits the number of new connections the user may open per hour.' - ), - ], - [ - 'input_name' => 'max_user_connections', - 'name_main' => 'MAX USER_CONNECTIONS', - 'value' => isset($row['max_user_connections']) ? - $row['max_user_connections'] : '0', - 'description' => __( - 'Limits the number of simultaneous connections ' - . 'the user may have.' - ), - ], - ]; - - return $this->template->render('server/privileges/resource_limits', [ - 'limits' => $limits, - ]); - } - - /** - * Get the HTML snippet for routine specific privileges - * - * @param string $username username for database connection - * @param string $hostname hostname for database connection - * @param string $db the database - * @param string $routine the routine - * @param string $url_dbname url encoded db name - * - * @return string - */ - public function getHtmlForRoutineSpecificPrivileges( - $username, - $hostname, - $db, - $routine, - $url_dbname - ) { - $header = $this->getHtmlHeaderForUserProperties( - false, - $url_dbname, - $db, - $username, - $hostname, - $routine, - 'routine' - ); - - $sql = "SELECT `Proc_priv`" - . " FROM `mysql`.`procs_priv`" - . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" - . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "'" - . " AND `Db` = '" - . $this->dbi->escapeString(Util::unescapeMysqlWildcards($db)) . "'" - . " AND `Routine_name` LIKE '" . $this->dbi->escapeString($routine) . "';"; - $res = $this->dbi->fetchValue($sql); - - $privs = $this->parseProcPriv($res); - - $routineArray = [$this->getTriggerPrivilegeTable()]; - $privTableNames = [__('Routine')]; - $privCheckboxes = $this->getHtmlForGlobalPrivTableWithCheckboxes( - $routineArray, - $privTableNames, - $privs - ); - - return $this->template->render('server/privileges/edit_routine_privileges', [ - 'username' => $username, - 'hostname' => $hostname, - 'database' => $db, - 'routine' => $routine, - 'grant_count' => count($privs), - 'priv_checkboxes' => $privCheckboxes, - 'header' => $header, - ]); - } - - /** - * Get routine privilege table as an array - * - * @return array privilege type array - */ - public function getTriggerPrivilegeTable() - { - $routinePrivTable = [ - [ - 'Grant', - 'GRANT', - __( - 'Allows user to give to other users or remove from other users ' - . 'privileges that user possess on this routine.' - ), - ], - [ - 'Alter_routine', - 'ALTER ROUTINE', - __('Allows altering and dropping this routine.'), - ], - [ - 'Execute', - 'EXECUTE', - __('Allows executing this routine.'), - ], - ]; - return $routinePrivTable; - } - - /** - * Get the HTML snippet for table specific privileges - * - * @param string $username username for database connection - * @param string $hostname hostname for database connection - * @param string $db the database - * @param string $table the table - * @param array $columns columns array - * @param array $row current privileges row - * - * @return string - */ - public function getHtmlForTableSpecificPrivileges( - $username, - $hostname, - $db, - $table, - array $columns, - array $row - ) { - $res = $this->dbi->query( - 'SELECT `Column_name`, `Column_priv`' - . ' FROM `mysql`.`columns_priv`' - . ' WHERE `User`' - . ' = \'' . $this->dbi->escapeString($username) . "'" - . ' AND `Host`' - . ' = \'' . $this->dbi->escapeString($hostname) . "'" - . ' AND `Db`' - . ' = \'' . $this->dbi->escapeString( - Util::unescapeMysqlWildcards($db) - ) . "'" - . ' AND `Table_name`' - . ' = \'' . $this->dbi->escapeString($table) . '\';' - ); - - while ($row1 = $this->dbi->fetchRow($res)) { - $row1[1] = explode(',', $row1[1]); - foreach ($row1[1] as $current) { - $columns[$row1[0]][$current] = true; - } - } - $this->dbi->freeResult($res); - unset($res, $row1, $current); - - $html_output = '' . "\n" - . '' . "\n" - . '
    ' . "\n" - . '' . __('Table-specific privileges') - . '' - . '

    ' - . __('Note: MySQL privilege names are expressed in English.') - . '

    '; - - // privs that are attached to a specific column - $html_output .= $this->getHtmlForAttachedPrivilegesToTableSpecificColumn( - $columns, - $row - ); - - // privs that are not attached to a specific column - $html_output .= '
    ' . "\n" - . $this->getHtmlForNotAttachedPrivilegesToTableSpecificColumn($row) - . '
    ' . "\n"; - - // for Safari 2.0.2 - $html_output .= '
    ' . "\n"; - - return $html_output; - } - - /** - * Get HTML snippet for privileges that are attached to a specific column - * - * @param array $columns columns array - * @param array $row first row from result or boolean false - * - * @return string - */ - public function getHtmlForAttachedPrivilegesToTableSpecificColumn(array $columns, array $row) - { - $html_output = $this->getHtmlForColumnPrivileges( - $columns, - $row, - 'Select_priv', - 'SELECT', - 'select', - __('Allows reading data.'), - 'Select' - ); - - $html_output .= $this->getHtmlForColumnPrivileges( - $columns, - $row, - 'Insert_priv', - 'INSERT', - 'insert', - __('Allows inserting and replacing data.'), - 'Insert' - ); - - $html_output .= $this->getHtmlForColumnPrivileges( - $columns, - $row, - 'Update_priv', - 'UPDATE', - 'update', - __('Allows changing data.'), - 'Update' - ); - - $html_output .= $this->getHtmlForColumnPrivileges( - $columns, - $row, - 'References_priv', - 'REFERENCES', - 'references', - __('Has no effect in this MySQL version.'), - 'References' - ); - return $html_output; - } - - /** - * Get HTML for privileges that are not attached to a specific column - * - * @param array $row first row from result or boolean false - * - * @return string - */ - public function getHtmlForNotAttachedPrivilegesToTableSpecificColumn(array $row) - { - $html_output = ''; - - foreach ($row as $current_grant => $current_grant_value) { - $grant_type = substr($current_grant, 0, -5); - if (in_array($grant_type, ['Select', 'Insert', 'Update', 'References']) - ) { - continue; - } - // make a substitution to match the messages variables; - // also we must substitute the grant we get, because we can't generate - // a form variable containing blanks (those would get changed to - // an underscore when receiving the POST) - if ($current_grant == 'Create View_priv') { - $tmp_current_grant = 'CreateView_priv'; - $current_grant = 'Create_view_priv'; - } elseif ($current_grant == 'Show view_priv') { - $tmp_current_grant = 'ShowView_priv'; - $current_grant = 'Show_view_priv'; - } elseif ($current_grant == 'Delete versioning rows_priv') { - $tmp_current_grant = 'DeleteHistoricalRows_priv'; - $current_grant = 'Delete_history_priv'; - } else { - $tmp_current_grant = $current_grant; - } - - $html_output .= '
    ' . "\n" - . '' . "\n"; - - $privGlobalName1 = 'strPrivDesc' - . mb_substr( - $tmp_current_grant, - 0, - - 5 - ); - $html_output .= '' . "\n" - . '
    ' . "\n"; - } // end foreach () - return $html_output; - } - - /** - * Get HTML for global or database specific privileges - * - * @param string $db the database - * @param string $table the table - * @param array $row first row from result or boolean false - * - * @return string - */ - public function getHtmlForGlobalOrDbSpecificPrivs($db, $table, array $row) - { - $privTable_names = [ - 0 => __('Data'), - 1 => __('Structure'), - 2 => __('Administration'), - ]; - $privTable = []; - $privTable[0] = $this->getDataPrivilegeTable($db); - $privTable[1] = $this->getStructurePrivilegeTable($table, $row); - $privTable[2] = $this->getAdministrationPrivilegeTable($db); - - $html_output = ''; - if ($db == '*') { - $legend = __('Global privileges'); - $menu_label = __('Global'); - } elseif ($table == '*') { - $legend = __('Database-specific privileges'); - $menu_label = __('Database'); - } else { - $legend = __('Table-specific privileges'); - $menu_label = __('Table'); - } - $html_output .= '
    ' - . '' . $legend - . ' ' - . ' ' - . '' - . '

    ' - . __('Note: MySQL privilege names are expressed in English.') - . '

    '; - - // Output the Global privilege tables with checkboxes - $html_output .= $this->getHtmlForGlobalPrivTableWithCheckboxes( - $privTable, - $privTable_names, - $row - ); - - // The "Resource limits" box is not displayed for db-specific privs - if ($db == '*') { - $html_output .= $this->getHtmlForResourceLimits($row); - $html_output .= $this->getHtmlForRequires($row); - } - // for Safari 2.0.2 - $html_output .= '
    '; - - return $html_output; - } - - /** - * Get data privilege table as an array - * - * @param string $db the database - * - * @return array data privilege table - */ - public function getDataPrivilegeTable($db) - { - $data_privTable = [ - [ - 'Select', - 'SELECT', - __('Allows reading data.'), - ], - [ - 'Insert', - 'INSERT', - __('Allows inserting and replacing data.'), - ], - [ - 'Update', - 'UPDATE', - __('Allows changing data.'), - ], - [ - 'Delete', - 'DELETE', - __('Allows deleting data.'), - ], - ]; - if ($db == '*') { - $data_privTable[] - = [ - 'File', - 'FILE', - __('Allows importing data from and exporting data into files.'), - ]; - } - return $data_privTable; - } - - /** - * Get structure privilege table as an array - * - * @param string $table the table - * @param array $row first row from result or boolean false - * - * @return array structure privilege table - */ - public function getStructurePrivilegeTable($table, array $row) - { - $structure_privTable = [ - [ - 'Create', - 'CREATE', - $table == '*' - ? __('Allows creating new databases and tables.') - : __('Allows creating new tables.'), - ], - [ - 'Alter', - 'ALTER', - __('Allows altering the structure of existing tables.'), - ], - [ - 'Index', - 'INDEX', - __('Allows creating and dropping indexes.'), - ], - [ - 'Drop', - 'DROP', - $table == '*' - ? __('Allows dropping databases and tables.') - : __('Allows dropping tables.'), - ], - [ - 'Create_tmp_table', - 'CREATE TEMPORARY TABLES', - __('Allows creating temporary tables.'), - ], - [ - 'Show_view', - 'SHOW VIEW', - __('Allows performing SHOW CREATE VIEW queries.'), - ], - [ - 'Create_routine', - 'CREATE ROUTINE', - __('Allows creating stored routines.'), - ], - [ - 'Alter_routine', - 'ALTER ROUTINE', - __('Allows altering and dropping stored routines.'), - ], - [ - 'Execute', - 'EXECUTE', - __('Allows executing stored routines.'), - ], - ]; - // this one is for a db-specific priv: Create_view_priv - if (isset($row['Create_view_priv'])) { - $structure_privTable[] = [ - 'Create_view', - 'CREATE VIEW', - __('Allows creating new views.'), - ]; - } - // this one is for a table-specific priv: Create View_priv - if (isset($row['Create View_priv'])) { - $structure_privTable[] = [ - 'Create View', - 'CREATE VIEW', - __('Allows creating new views.'), - ]; - } - if (isset($row['Event_priv'])) { - // MySQL 5.1.6 - $structure_privTable[] = [ - 'Event', - 'EVENT', - __('Allows to set up events for the event scheduler.'), - ]; - $structure_privTable[] = [ - 'Trigger', - 'TRIGGER', - __('Allows creating and dropping triggers.'), - ]; - } - return $structure_privTable; - } - - /** - * Get administration privilege table as an array - * - * @param string $db the table - * - * @return array administration privilege table - */ - public function getAdministrationPrivilegeTable($db) - { - if ($db == '*') { - $adminPrivTable = [ - [ - 'Grant', - 'GRANT', - __( - 'Allows adding users and privileges ' - . 'without reloading the privilege tables.' - ), - ], - ]; - $adminPrivTable[] = [ - 'Super', - 'SUPER', - __( - 'Allows connecting, even if maximum number ' - . 'of connections is reached; required for ' - . 'most administrative operations like ' - . 'setting global variables or killing threads of other users.' - ), - ]; - $adminPrivTable[] = [ - 'Process', - 'PROCESS', - __('Allows viewing processes of all users.'), - ]; - $adminPrivTable[] = [ - 'Reload', - 'RELOAD', - __('Allows reloading server settings and flushing the server\'s caches.'), - ]; - $adminPrivTable[] = [ - 'Shutdown', - 'SHUTDOWN', - __('Allows shutting down the server.'), - ]; - $adminPrivTable[] = [ - 'Show_db', - 'SHOW DATABASES', - __('Gives access to the complete list of databases.'), - ]; - } else { - $adminPrivTable = [ - [ - 'Grant', - 'GRANT', - __( - 'Allows user to give to other users or remove from other' - . ' users the privileges that user possess yourself.' - ), - ], - ]; - } - $adminPrivTable[] = [ - 'Lock_tables', - 'LOCK TABLES', - __('Allows locking tables for the current thread.'), - ]; - $adminPrivTable[] = [ - 'References', - 'REFERENCES', - __('Has no effect in this MySQL version.'), - ]; - if ($db == '*') { - $adminPrivTable[] = [ - 'Repl_client', - 'REPLICATION CLIENT', - __('Allows the user to ask where the slaves / masters are.'), - ]; - $adminPrivTable[] = [ - 'Repl_slave', - 'REPLICATION SLAVE', - __('Needed for the replication slaves.'), - ]; - $adminPrivTable[] = [ - 'Create_user', - 'CREATE USER', - __('Allows creating, dropping and renaming user accounts.'), - ]; - } - return $adminPrivTable; - } - - /** - * Get HTML snippet for global privileges table with check boxes - * - * @param array $privTable privileges table array - * @param array $privTableNames names of the privilege tables - * (Data, Structure, Administration) - * @param array $row first row from result or boolean false - * - * @return string - */ - public function getHtmlForGlobalPrivTableWithCheckboxes( - array $privTable, - array $privTableNames, - array $row - ) { - return $this->template->render('server/privileges/global_priv_table', [ - 'priv_table' => $privTable, - 'priv_table_names' => $privTableNames, - 'row' => $row, - ]); - } - - /** - * Gets the currently active authentication plugins - * - * @param string $orig_auth_plugin Default Authentication plugin - * @param string $mode are we creating a new user or are we just - * changing one? - * (allowed values: 'new', 'edit', 'change_pw') - * @param string $versions Is MySQL version newer or older than 5.5.7 - * - * @return string - */ - public function getHtmlForAuthPluginsDropdown( - $orig_auth_plugin, - $mode = 'new', - $versions = 'new' - ) { - $select_id = 'select_authentication_plugin' - . ($mode == 'change_pw' ? '_cp' : ''); - - if ($versions == 'new') { - $active_auth_plugins = $this->getActiveAuthPlugins(); - - if (isset($active_auth_plugins['mysql_old_password'])) { - unset($active_auth_plugins['mysql_old_password']); - } - } else { - $active_auth_plugins = [ - 'mysql_native_password' => __('Native MySQL authentication'), - ]; - } - - $html_output = Util::getDropdown( - 'authentication_plugin', - $active_auth_plugins, - $orig_auth_plugin, - $select_id - ); - - return $html_output; - } - - /** - * Gets the currently active authentication plugins - * - * @return array array of plugin names and descriptions - */ - public function getActiveAuthPlugins() - { - $get_plugins_query = "SELECT `PLUGIN_NAME`, `PLUGIN_DESCRIPTION`" - . " FROM `information_schema`.`PLUGINS` " - . "WHERE `PLUGIN_TYPE` = 'AUTHENTICATION';"; - $resultset = $this->dbi->query($get_plugins_query); - - $result = []; - - while ($row = $this->dbi->fetchAssoc($resultset)) { - // if description is known, enable its translation - if ('mysql_native_password' == $row['PLUGIN_NAME']) { - $row['PLUGIN_DESCRIPTION'] = __('Native MySQL authentication'); - } elseif ('sha256_password' == $row['PLUGIN_NAME']) { - $row['PLUGIN_DESCRIPTION'] = __('SHA256 password authentication'); - } - - $result[$row['PLUGIN_NAME']] = $row['PLUGIN_DESCRIPTION']; - } - - return $result; - } - - /** - * Displays the fields used by the "new user" form as well as the - * "change login information / copy user" form. - * - * @param string $mode are we creating a new user or are we just - * changing one? (allowed values: 'new', 'change') - * @param string $username User name - * @param string $hostname Host name - * - * @global array $cfg the phpMyAdmin configuration - * @global resource $user_link the database connection - * - * @return string a HTML snippet - */ - public function getHtmlForLoginInformationFields( - $mode = 'new', - $username = null, - $hostname = null - ) { - list($username_length, $hostname_length) = $this->getUsernameAndHostnameLength(); - - if (isset($GLOBALS['username']) && strlen($GLOBALS['username']) === 0) { - $GLOBALS['pred_username'] = 'any'; - } - $html_output = '
    ' . "\n" - . '' . __('Login Information') . '' . "\n" - . '
    ' . "\n" - . '' . "\n" - . '' . "\n"; - - $html_output .= '' . "\n" - . '' . "\n"; - - $html_output .= '' . "\n"; - - $html_output .= '
    ' - . Message::notice( - __( - 'An account already exists with the same username ' - . 'but possibly a different hostname.' - ) - )->getDisplay() - . '
    '; - $html_output .= '
    '; - - $html_output .= '
    ' . "\n" - . '' . "\n"; - - $html_output .= '' . "\n" - . ' ' . "\n" - . '' . "\n"; - - $html_output .= '' . "\n" - . Util::showHint( - __( - 'When Host table is used, this field is ignored ' - . 'and values stored in Host table are used instead.' - ) - ) - . '
    ' . "\n"; - - $html_output .= '
    ' . "\n" - . '' . "\n" - . '' . "\n" - . '' . "\n" - . '' . "\n" - . '' . "\n" - . 'Strength: ' - . ' ' - . '' . "\n" - . '
    ' . "\n"; - - $html_output .= '
    ' . "\n" - . '' . "\n" - . ' ' . "\n" - . '' . "\n" - . '
    ' . "\n" - . '
    ' - . ' ' . "\n"; - - $auth_plugin_dropdown = $this->getHtmlForAuthPluginsDropdown( - $orig_auth_plugin, - $mode, - 'new' - ); - } else { - $html_output .= __('Password Hashing Method') - . ' ' . "\n"; - $auth_plugin_dropdown = $this->getHtmlForAuthPluginsDropdown( - $orig_auth_plugin, - $mode, - 'old' - ); - } - $html_output .= $auth_plugin_dropdown; - - $html_output .= '' - . Message::notice( - __( - 'This method requires using an \'SSL connection\' ' - . 'or an \'unencrypted connection that encrypts the password ' - . 'using RSA\'; while connecting to the server.' - ) - . Util::showMySQLDocu('sha256-authentication-plugin') - ) - ->getDisplay() - . '
    '; - - $html_output .= '' . "\n" - // Generate password added here via jQuery - . '
    ' . "\n"; - - return $html_output; - } - - /** - * Get username and hostname length - * - * @return array username length and hostname length - */ - public function getUsernameAndHostnameLength() - { - /* Fallback values */ - $username_length = 16; - $hostname_length = 41; - - /* Try to get real lengths from the database */ - $fields_info = $this->dbi->fetchResult( - 'SELECT COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH ' - . 'FROM information_schema.columns ' - . "WHERE table_schema = 'mysql' AND table_name = 'user' " - . "AND COLUMN_NAME IN ('User', 'Host')" - ); - foreach ($fields_info as $val) { - if ($val['COLUMN_NAME'] == 'User') { - $username_length = $val['CHARACTER_MAXIMUM_LENGTH']; - } elseif ($val['COLUMN_NAME'] == 'Host') { - $hostname_length = $val['CHARACTER_MAXIMUM_LENGTH']; - } - } - return [ - $username_length, - $hostname_length, - ]; - } - - /** - * Get current authentication plugin in use - for a user or globally - * - * @param string $mode are we creating a new user or are we just - * changing one? (allowed values: 'new', 'change') - * @param string $username User name - * @param string $hostname Host name - * - * @return string authentication plugin in use - */ - public function getCurrentAuthenticationPlugin( - $mode = 'new', - $username = null, - $hostname = null - ) { - /* Fallback (standard) value */ - $authentication_plugin = 'mysql_native_password'; - $serverVersion = $this->dbi->getVersion(); - - if (isset($username) && isset($hostname) - && $mode == 'change' - ) { - $row = $this->dbi->fetchSingleRow( - 'SELECT `plugin` FROM `mysql`.`user` WHERE ' - . '`User` = "' . $username . '" AND `Host` = "' . $hostname . '" LIMIT 1' - ); - // Table 'mysql'.'user' may not exist for some previous - // versions of MySQL - in that case consider fallback value - if (is_array($row) && isset($row['plugin'])) { - $authentication_plugin = $row['plugin']; - } - } elseif ($mode == 'change') { - list($username, $hostname) = $this->dbi->getCurrentUserAndHost(); - - $row = $this->dbi->fetchSingleRow( - 'SELECT `plugin` FROM `mysql`.`user` WHERE ' - . '`User` = "' . $username . '" AND `Host` = "' . $hostname . '"' - ); - if (is_array($row) && isset($row['plugin'])) { - $authentication_plugin = $row['plugin']; - } - } elseif ($serverVersion >= 50702) { - $row = $this->dbi->fetchSingleRow( - 'SELECT @@default_authentication_plugin' - ); - $authentication_plugin = is_array($row) ? $row['@@default_authentication_plugin'] : null; - } - - return $authentication_plugin; - } - - /** - * Returns all the grants for a certain user on a certain host - * Used in the export privileges for all users section - * - * @param string $user User name - * @param string $host Host name - * - * @return string containing all the grants text - */ - public function getGrants($user, $host) - { - $grants = $this->dbi->fetchResult( - "SHOW GRANTS FOR '" - . $this->dbi->escapeString($user) . "'@'" - . $this->dbi->escapeString($host) . "'" - ); - $response = ''; - foreach ($grants as $one_grant) { - $response .= $one_grant . ";\n\n"; - } - return $response; - } - - /** - * Update password and get message for password updating - * - * @param string $err_url error url - * @param string $username username - * @param string $hostname hostname - * - * @return Message success or error message after updating password - */ - public function updatePassword($err_url, $username, $hostname) - { - // similar logic in user_password.php - $message = null; - - if (empty($_POST['nopass']) - && isset($_POST['pma_pw']) - && isset($_POST['pma_pw2']) - ) { - if ($_POST['pma_pw'] != $_POST['pma_pw2']) { - $message = Message::error(__('The passwords aren\'t the same!')); - } elseif (empty($_POST['pma_pw']) || empty($_POST['pma_pw2'])) { - $message = Message::error(__('The password is empty!')); - } - } - - // here $nopass could be == 1 - if ($message === null) { - $hashing_function = 'PASSWORD'; - $serverType = Util::getServerType(); - $serverVersion = $this->dbi->getVersion(); - $authentication_plugin - = (isset($_POST['authentication_plugin']) - ? $_POST['authentication_plugin'] - : $this->getCurrentAuthenticationPlugin( - 'change', - $username, - $hostname - )); - - // Use 'ALTER USER ...' syntax for MySQL 5.7.6+ - if ($serverType == 'MySQL' - && $serverVersion >= 50706 - ) { - if ($authentication_plugin != 'mysql_old_password') { - $query_prefix = "ALTER USER '" - . $this->dbi->escapeString($username) - . "'@'" . $this->dbi->escapeString($hostname) . "'" - . " IDENTIFIED WITH " - . $authentication_plugin - . " BY '"; - } else { - $query_prefix = "ALTER USER '" - . $this->dbi->escapeString($username) - . "'@'" . $this->dbi->escapeString($hostname) . "'" - . " IDENTIFIED BY '"; - } - - // in $sql_query which will be displayed, hide the password - $sql_query = $query_prefix . "*'"; - - $local_query = $query_prefix - . $this->dbi->escapeString($_POST['pma_pw']) . "'"; - } elseif ($serverType == 'MariaDB' && $serverVersion >= 10000) { - // MariaDB uses "SET PASSWORD" syntax to change user password. - // On Galera cluster only DDL queries are replicated, since - // users are stored in MyISAM storage engine. - $query_prefix = "SET PASSWORD FOR '" - . $this->dbi->escapeString($username) - . "'@'" . $this->dbi->escapeString($hostname) . "'" - . " = PASSWORD ('"; - $sql_query = $local_query = $query_prefix - . $this->dbi->escapeString($_POST['pma_pw']) . "')"; - } elseif ($serverType == 'MariaDB' - && $serverVersion >= 50200 - && $this->dbi->isSuperuser() - ) { - // Use 'UPDATE `mysql`.`user` ...' Syntax for MariaDB 5.2+ - if ($authentication_plugin == 'mysql_native_password') { - // Set the hashing method used by PASSWORD() - // to be 'mysql_native_password' type - $this->dbi->tryQuery('SET old_passwords = 0;'); - } elseif ($authentication_plugin == 'sha256_password') { - // Set the hashing method used by PASSWORD() - // to be 'sha256_password' type - $this->dbi->tryQuery('SET `old_passwords` = 2;'); - } - - $hashedPassword = $this->getHashedPassword($_POST['pma_pw']); - - $sql_query = 'SET PASSWORD FOR \'' - . $this->dbi->escapeString($username) - . '\'@\'' . $this->dbi->escapeString($hostname) . '\' = ' - . ($_POST['pma_pw'] == '' - ? '\'\'' - : $hashing_function . '(\'' - . preg_replace('@.@s', '*', $_POST['pma_pw']) . '\')'); - - $local_query = "UPDATE `mysql`.`user` SET " - . " `authentication_string` = '" . $hashedPassword - . "', `Password` = '', " - . " `plugin` = '" . $authentication_plugin . "'" - . " WHERE `User` = '" . $username . "' AND Host = '" - . $hostname . "';"; - } else { - // USE 'SET PASSWORD ...' syntax for rest of the versions - // Backup the old value, to be reset later - $row = $this->dbi->fetchSingleRow( - 'SELECT @@old_passwords;' - ); - $orig_value = $row['@@old_passwords']; - $update_plugin_query = "UPDATE `mysql`.`user` SET" - . " `plugin` = '" . $authentication_plugin . "'" - . " WHERE `User` = '" . $username . "' AND Host = '" - . $hostname . "';"; - - // Update the plugin for the user - if (! $this->dbi->tryQuery($update_plugin_query)) { - Util::mysqlDie( - $this->dbi->getError(), - $update_plugin_query, - false, - $err_url - ); - } - $this->dbi->tryQuery("FLUSH PRIVILEGES;"); - - if ($authentication_plugin == 'mysql_native_password') { - // Set the hashing method used by PASSWORD() - // to be 'mysql_native_password' type - $this->dbi->tryQuery('SET old_passwords = 0;'); - } elseif ($authentication_plugin == 'sha256_password') { - // Set the hashing method used by PASSWORD() - // to be 'sha256_password' type - $this->dbi->tryQuery('SET `old_passwords` = 2;'); - } - $sql_query = 'SET PASSWORD FOR \'' - . $this->dbi->escapeString($username) - . '\'@\'' . $this->dbi->escapeString($hostname) . '\' = ' - . ($_POST['pma_pw'] == '' - ? '\'\'' - : $hashing_function . '(\'' - . preg_replace('@.@s', '*', $_POST['pma_pw']) . '\')'); - - $local_query = 'SET PASSWORD FOR \'' - . $this->dbi->escapeString($username) - . '\'@\'' . $this->dbi->escapeString($hostname) . '\' = ' - . ($_POST['pma_pw'] == '' ? '\'\'' : $hashing_function - . '(\'' . $this->dbi->escapeString($_POST['pma_pw']) . '\')'); - } - - if (! $this->dbi->tryQuery($local_query)) { - Util::mysqlDie( - $this->dbi->getError(), - $sql_query, - false, - $err_url - ); - } - // Flush privileges after successful password change - $this->dbi->tryQuery("FLUSH PRIVILEGES;"); - - $message = Message::success( - __('The password for %s was changed successfully.') - ); - $message->addParam('\'' . $username . '\'@\'' . $hostname . '\''); - if (isset($orig_value)) { - $this->dbi->tryQuery( - 'SET `old_passwords` = ' . $orig_value . ';' - ); - } - } - return $message; - } - - /** - * Revokes privileges and get message and SQL query for privileges revokes - * - * @param string $dbname database name - * @param string $tablename table name - * @param string $username username - * @param string $hostname host name - * @param string $itemType item type - * - * @return array ($message, $sql_query) - */ - public function getMessageAndSqlQueryForPrivilegesRevoke( - $dbname, - $tablename, - $username, - $hostname, - $itemType - ) { - $db_and_table = $this->wildcardEscapeForGrant($dbname, $tablename); - - $sql_query0 = 'REVOKE ALL PRIVILEGES ON ' . $itemType . ' ' . $db_and_table - . ' FROM \'' - . $this->dbi->escapeString($username) . '\'@\'' - . $this->dbi->escapeString($hostname) . '\';'; - - $sql_query1 = 'REVOKE GRANT OPTION ON ' . $itemType . ' ' . $db_and_table - . ' FROM \'' . $this->dbi->escapeString($username) . '\'@\'' - . $this->dbi->escapeString($hostname) . '\';'; - - $this->dbi->query($sql_query0); - if (! $this->dbi->tryQuery($sql_query1)) { - // this one may fail, too... - $sql_query1 = ''; - } - $sql_query = $sql_query0 . ' ' . $sql_query1; - $message = Message::success( - __('You have revoked the privileges for %s.') - ); - $message->addParam('\'' . $username . '\'@\'' . $hostname . '\''); - - return [ - $message, - $sql_query, - ]; - } - - /** - * Get REQUIRE cluase - * - * @return string REQUIRE clause - */ - public function getRequireClause() - { - $arr = isset($_POST['ssl_type']) ? $_POST : $GLOBALS; - if (isset($arr['ssl_type']) && $arr['ssl_type'] == 'SPECIFIED') { - $require = []; - if (! empty($arr['ssl_cipher'])) { - $require[] = "CIPHER '" - . $this->dbi->escapeString($arr['ssl_cipher']) . "'"; - } - if (! empty($arr['x509_issuer'])) { - $require[] = "ISSUER '" - . $this->dbi->escapeString($arr['x509_issuer']) . "'"; - } - if (! empty($arr['x509_subject'])) { - $require[] = "SUBJECT '" - . $this->dbi->escapeString($arr['x509_subject']) . "'"; - } - if (count($require)) { - $require_clause = " REQUIRE " . implode(" AND ", $require); - } else { - $require_clause = " REQUIRE NONE"; - } - } elseif (isset($arr['ssl_type']) && $arr['ssl_type'] == 'X509') { - $require_clause = " REQUIRE X509"; - } elseif (isset($arr['ssl_type']) && $arr['ssl_type'] == 'ANY') { - $require_clause = " REQUIRE SSL"; - } else { - $require_clause = " REQUIRE NONE"; - } - - return $require_clause; - } - - /** - * Get a WITH clause for 'update privileges' and 'add user' - * - * @return string - */ - public function getWithClauseForAddUserAndUpdatePrivs() - { - $sql_query = ''; - if (((isset($_POST['Grant_priv']) && $_POST['Grant_priv'] == 'Y') - || (isset($GLOBALS['Grant_priv']) && $GLOBALS['Grant_priv'] == 'Y')) - && ! ((Util::getServerType() == 'MySQL' || Util::getServerType() == 'Percona Server') - && $this->dbi->getVersion() >= 80011) - ) { - $sql_query .= ' GRANT OPTION'; - } - if (isset($_POST['max_questions']) || isset($GLOBALS['max_questions'])) { - $max_questions = isset($_POST['max_questions']) - ? (int) $_POST['max_questions'] : (int) $GLOBALS['max_questions']; - $max_questions = max(0, $max_questions); - $sql_query .= ' MAX_QUERIES_PER_HOUR ' . $max_questions; - } - if (isset($_POST['max_connections']) || isset($GLOBALS['max_connections'])) { - $max_connections = isset($_POST['max_connections']) - ? (int) $_POST['max_connections'] : (int) $GLOBALS['max_connections']; - $max_connections = max(0, $max_connections); - $sql_query .= ' MAX_CONNECTIONS_PER_HOUR ' . $max_connections; - } - if (isset($_POST['max_updates']) || isset($GLOBALS['max_updates'])) { - $max_updates = isset($_POST['max_updates']) - ? (int) $_POST['max_updates'] : (int) $GLOBALS['max_updates']; - $max_updates = max(0, $max_updates); - $sql_query .= ' MAX_UPDATES_PER_HOUR ' . $max_updates; - } - if (isset($_POST['max_user_connections']) - || isset($GLOBALS['max_user_connections']) - ) { - $max_user_connections = isset($_POST['max_user_connections']) - ? (int) $_POST['max_user_connections'] - : (int) $GLOBALS['max_user_connections']; - $max_user_connections = max(0, $max_user_connections); - $sql_query .= ' MAX_USER_CONNECTIONS ' . $max_user_connections; - } - return (! empty($sql_query) ? ' WITH' . $sql_query : ''); - } - - /** - * Get HTML for addUsersForm, This function call if isset($_GET['adduser']) - * - * @param string $dbname database name - * - * @return string HTML for addUserForm - */ - public function getHtmlForAddUser($dbname) - { - $html_output = '

    ' . "\n" - . Util::getIcon('b_usradd') . __('Add user account') . "\n" - . '

    ' . "\n" - . '
    ' . "\n" - . Url::getHiddenInputs('', '') - . $this->getHtmlForLoginInformationFields('new'); - - $html_output .= '
    ' . "\n" - . '' . __('Database for user account') . '' . "\n"; - - $html_output .= $this->template->render('checkbox', [ - 'html_field_name' => 'createdb-1', - 'label' => __('Create database with same name and grant all privileges.'), - 'checked' => false, - 'onclick' => false, - 'html_field_id' => 'createdb-1', - ]); - $html_output .= '
    ' . "\n"; - $html_output .= $this->template->render('checkbox', [ - 'html_field_name' => 'createdb-2', - 'label' => __('Grant all privileges on wildcard name (username\\_%).'), - 'checked' => false, - 'onclick' => false, - 'html_field_id' => 'createdb-2', - ]); - $html_output .= '
    ' . "\n"; - - if (! empty($dbname)) { - $html_output .= $this->template->render('checkbox', [ - 'html_field_name' => 'createdb-3', - 'label' => sprintf(__('Grant all privileges on database %s.'), htmlspecialchars($dbname)), - 'checked' => true, - 'onclick' => false, - 'html_field_id' => 'createdb-3', - ]); - $html_output .= '' . "\n"; - $html_output .= '
    ' . "\n"; - } - - $html_output .= '
    ' . "\n"; - if ($GLOBALS['is_grantuser']) { - $html_output .= $this->getHtmlToDisplayPrivilegesTable('*', '*', false); - } - $html_output .= '' . "\n" - . '
    ' . "\n"; - - return $html_output; - } - - /** - * Get the list of privileges and list of compared privileges as strings - * and return a array that contains both strings - * - * @return array $list_of_privileges, $list_of_compared_privileges - */ - public function getListOfPrivilegesAndComparedPrivileges() - { - $list_of_privileges - = '`User`, ' - . '`Host`, ' - . '`Select_priv`, ' - . '`Insert_priv`, ' - . '`Update_priv`, ' - . '`Delete_priv`, ' - . '`Create_priv`, ' - . '`Drop_priv`, ' - . '`Grant_priv`, ' - . '`Index_priv`, ' - . '`Alter_priv`, ' - . '`References_priv`, ' - . '`Create_tmp_table_priv`, ' - . '`Lock_tables_priv`, ' - . '`Create_view_priv`, ' - . '`Show_view_priv`, ' - . '`Create_routine_priv`, ' - . '`Alter_routine_priv`, ' - . '`Execute_priv`'; - - $listOfComparedPrivs - = '`Select_priv` = \'N\'' - . ' AND `Insert_priv` = \'N\'' - . ' AND `Update_priv` = \'N\'' - . ' AND `Delete_priv` = \'N\'' - . ' AND `Create_priv` = \'N\'' - . ' AND `Drop_priv` = \'N\'' - . ' AND `Grant_priv` = \'N\'' - . ' AND `References_priv` = \'N\'' - . ' AND `Create_tmp_table_priv` = \'N\'' - . ' AND `Lock_tables_priv` = \'N\'' - . ' AND `Create_view_priv` = \'N\'' - . ' AND `Show_view_priv` = \'N\'' - . ' AND `Create_routine_priv` = \'N\'' - . ' AND `Alter_routine_priv` = \'N\'' - . ' AND `Execute_priv` = \'N\''; - - $list_of_privileges .= - ', `Event_priv`, ' - . '`Trigger_priv`'; - $listOfComparedPrivs .= - ' AND `Event_priv` = \'N\'' - . ' AND `Trigger_priv` = \'N\''; - return [ - $list_of_privileges, - $listOfComparedPrivs, - ]; - } - - /** - * Get the HTML for routine based privileges - * - * @param string $db database name - * @param string $index_checkbox starting index for rows to be added - * - * @return string - */ - public function getHtmlTableBodyForSpecificDbRoutinePrivs($db, $index_checkbox) - { - $sql_query = 'SELECT * FROM `mysql`.`procs_priv` WHERE Db = \'' . $this->dbi->escapeString($db) . '\';'; - $res = $this->dbi->query($sql_query); - $html_output = ''; - while ($row = $this->dbi->fetchAssoc($res)) { - $html_output .= '
    ' . htmlspecialchars($row['User']) - . '' . htmlspecialchars($row['Host']) - . 'routine' - . '' . htmlspecialchars($row['Routine_name']) . '' - . 'Yes' - . ''; - $specific_db = ''; - $specific_table = ''; - if ($GLOBALS['is_grantuser']) { - $specific_db = isset($row['Db']) && $row['Db'] != '*' - ? $row['Db'] : ''; - $specific_table = isset($row['Table_name']) - && $row['Table_name'] != '*' - ? $row['Table_name'] : ''; - $html_output .= $this->getUserLink( - 'edit', - $current_user, - $current_host, - $specific_db, - $specific_table, - $routine - ); - } - $html_output .= ''; - $html_output .= $this->getUserLink( - 'export', - $current_user, - $current_host, - $specific_db, - $specific_table, - $routine - ); - $html_output .= '
    '; - $html_output .= $this->getHtmlForPrivsTableHead(); - $privMap = $this->getPrivMap($db); - $html_output .= $this->getHtmlTableBodyForSpecificDbOrTablePrivs($privMap, $db); - $html_output .= '
    '; - $html_output .= ''; - - $html_output .= '
    '; - $html_output .= $this->template->render('select_all', [ - 'pma_theme_image' => $GLOBALS['pmaThemeImage'], - 'text_dir' => $GLOBALS['text_dir'], - 'form_name' => "usersForm", - ]); - $html_output .= Util::getButtonOrImage( - 'submit_mult', - 'mult_submit', - __('Export'), - 'b_tblexport', - 'export' - ); - - $html_output .= '
    '; - $html_output .= ''; - $html_output .= ''; - } else { - $html_output .= $this->getHtmlForViewUsersError(); - } - - $response = Response::getInstance(); - if ($response->isAjax() === true - && empty($_REQUEST['ajax_page_request']) - ) { - $message = Message::success(__('User has been added.')); - $response->addJSON('message', $message); - $response->addJSON('user_form', $html_output); - exit; - } else { - // Offer to create a new user for the current database - $html_output .= $this->getAddUserHtmlFieldset($db); - } - return $html_output; - } - - /** - * Get the HTML for user form and check the privileges for a particular table. - * - * @param string $db database name - * @param string $table table name - * - * @return string - */ - public function getHtmlForSpecificTablePrivileges($db, $table) - { - $html_output = ''; - if ($this->dbi->isSuperuser()) { - // check the privileges for a particular table. - $html_output = '
    '; - $html_output .= Url::getHiddenInputs($db, $table); - $html_output .= '
    '; - $html_output .= '' - . Util::getIcon('b_usrcheck') - . sprintf( - __('Users having access to "%s"'), - '' - . htmlspecialchars($db) . '.' . htmlspecialchars($table) - . '' - ) - . ''; - - $html_output .= '
    '; - $html_output .= ''; - $html_output .= $this->getHtmlForPrivsTableHead(); - $privMap = $this->getPrivMap($db); - $sql_query = "SELECT `User`, `Host`, `Db`," - . " 't' AS `Type`, `Table_name`, `Table_priv`" - . " FROM `mysql`.`tables_priv`" - . " WHERE '" . $this->dbi->escapeString($db) . "' LIKE `Db`" - . " AND '" . $this->dbi->escapeString($table) . "' LIKE `Table_name`" - . " AND NOT (`Table_priv` = '' AND Column_priv = '')" - . " ORDER BY `User` ASC, `Host` ASC, `Db` ASC, `Table_priv` ASC;"; - $res = $this->dbi->query($sql_query); - $this->mergePrivMapFromResult($privMap, $res); - $html_output .= $this->getHtmlTableBodyForSpecificDbOrTablePrivs($privMap, $db); - $html_output .= '
    '; - - $html_output .= '
    '; - $html_output .= $this->template->render('select_all', [ - 'pma_theme_image' => $GLOBALS['pmaThemeImage'], - 'text_dir' => $GLOBALS['text_dir'], - 'form_name' => "usersForm", - ]); - $html_output .= Util::getButtonOrImage( - 'submit_mult', - 'mult_submit', - __('Export'), - 'b_tblexport', - 'export' - ); - - $html_output .= '
    '; - $html_output .= '
    '; - } else { - $html_output .= $this->getHtmlForViewUsersError(); - } - // Offer to create a new user for the current database - $html_output .= $this->getAddUserHtmlFieldset($db, $table); - return $html_output; - } - - /** - * gets privilege map - * - * @param string $db the database - * - * @return array the privilege map - */ - public function getPrivMap($db) - { - list($listOfPrivs, $listOfComparedPrivs) - = $this->getListOfPrivilegesAndComparedPrivileges(); - $sql_query - = "(" - . " SELECT " . $listOfPrivs . ", '*' AS `Db`, 'g' AS `Type`" - . " FROM `mysql`.`user`" - . " WHERE NOT (" . $listOfComparedPrivs . ")" - . ")" - . " UNION " - . "(" - . " SELECT " . $listOfPrivs . ", `Db`, 'd' AS `Type`" - . " FROM `mysql`.`db`" - . " WHERE '" . $this->dbi->escapeString($db) . "' LIKE `Db`" - . " AND NOT (" . $listOfComparedPrivs . ")" - . ")" - . " ORDER BY `User` ASC, `Host` ASC, `Db` ASC;"; - $res = $this->dbi->query($sql_query); - $privMap = []; - $this->mergePrivMapFromResult($privMap, $res); - return $privMap; - } - - /** - * merge privilege map and rows from resultset - * - * @param array $privMap the privilege map reference - * @param object $result the resultset of query - * - * @return void - */ - public function mergePrivMapFromResult(array &$privMap, $result) - { - while ($row = $this->dbi->fetchAssoc($result)) { - $user = $row['User']; - $host = $row['Host']; - if (! isset($privMap[$user])) { - $privMap[$user] = []; - } - if (! isset($privMap[$user][$host])) { - $privMap[$user][$host] = []; - } - $privMap[$user][$host][] = $row; - } - } - - /** - * Get HTML snippet for privileges table head - * - * @return string - */ - public function getHtmlForPrivsTableHead() - { - return '' - . '' - . '' - . '' . __('User name') . '' - . '' . __('Host name') . '' - . '' . __('Type') . '' - . '' . __('Privileges') . '' - . '' . __('Grant') . '' - . '' . __('Action') . '' - . '' - . ''; - } - - /** - * Get HTML error for View Users form - * For non superusers such as grant/create users - * - * @return string - */ - public function getHtmlForViewUsersError() - { - return Message::error( - __('Not enough privilege to view users.') - )->getDisplay(); - } - - /** - * Get HTML snippet for table body of specific database or table privileges - * - * @param array $privMap privilege map - * @param string $db database - * - * @return string - */ - public function getHtmlTableBodyForSpecificDbOrTablePrivs($privMap, $db) - { - $html_output = ''; - $index_checkbox = 0; - if (empty($privMap)) { - $html_output .= '' - . '' - . __('No user found.') - . '' - . '' - . ''; - return $html_output; - } - - foreach ($privMap as $current_user => $val) { - foreach ($val as $current_host => $current_privileges) { - $nbPrivileges = count($current_privileges); - $html_output .= ''; - - $value = htmlspecialchars($current_user . '&#27;' . $current_host); - $html_output .= ' 1) { - $html_output .= ' rowspan="' . $nbPrivileges . '"'; - } - $html_output .= '>'; - $html_output .= '' . "\n"; - - // user - $html_output .= ' 1) { - $html_output .= ' rowspan="' . $nbPrivileges . '"'; - } - $html_output .= '>'; - if (empty($current_user)) { - $html_output .= '' - . __('Any') . ''; - } else { - $html_output .= htmlspecialchars($current_user); - } - $html_output .= ''; - - // host - $html_output .= ' 1) { - $html_output .= ' rowspan="' . $nbPrivileges . '"'; - } - $html_output .= '>'; - $html_output .= htmlspecialchars($current_host); - $html_output .= ''; - - $html_output .= $this->getHtmlListOfPrivs( - $db, - $current_privileges, - $current_user, - $current_host - ); - } - } - - //For fetching routine based privileges - $html_output .= $this->getHtmlTableBodyForSpecificDbRoutinePrivs($db, $index_checkbox); - $html_output .= ''; - - return $html_output; - } - - /** - * Get HTML to display privileges - * - * @param string $db Database name - * @param array $current_privileges List of privileges - * @param string $current_user Current user - * @param string $current_host Current host - * - * @return string HTML to display privileges - */ - public function getHtmlListOfPrivs( - $db, - array $current_privileges, - $current_user, - $current_host - ) { - $nbPrivileges = count($current_privileges); - $html_output = null; - for ($i = 0; $i < $nbPrivileges; $i++) { - $current = $current_privileges[$i]; - - // type - $html_output .= ''; - if ($current['Type'] == 'g') { - $html_output .= __('global'); - } elseif ($current['Type'] == 'd') { - if ($current['Db'] == Util::escapeMysqlWildcards($db)) { - $html_output .= __('database-specific'); - } else { - $html_output .= __('wildcard') . ': ' - . '' - . htmlspecialchars($current['Db']) - . ''; - } - } elseif ($current['Type'] == 't') { - $html_output .= __('table-specific'); - } - $html_output .= ''; - - // privileges - $html_output .= ''; - if (isset($current['Table_name'])) { - $privList = explode(',', $current['Table_priv']); - $privs = []; - $grantsArr = $this->getTableGrantsArray(); - foreach ($grantsArr as $grant) { - $privs[$grant[0]] = 'N'; - foreach ($privList as $priv) { - if ($grant[0] == $priv) { - $privs[$grant[0]] = 'Y'; - } - } - } - $html_output .= '' - . implode( - ',', - $this->extractPrivInfo($privs, true, true) - ) - . ''; - } else { - $html_output .= '' - . implode( - ',', - $this->extractPrivInfo($current, true, false) - ) - . ''; - } - $html_output .= ''; - - // grant - $html_output .= ''; - $containsGrant = false; - if (isset($current['Table_name'])) { - $privList = explode(',', $current['Table_priv']); - foreach ($privList as $priv) { - if ($priv == 'Grant') { - $containsGrant = true; - } - } - } else { - $containsGrant = $current['Grant_priv'] == 'Y'; - } - $html_output .= ($containsGrant ? __('Yes') : __('No')); - $html_output .= ''; - - // action - $html_output .= ''; - $specific_db = isset($current['Db']) && $current['Db'] != '*' - ? $current['Db'] : ''; - $specific_table = isset($current['Table_name']) - && $current['Table_name'] != '*' - ? $current['Table_name'] : ''; - if ($GLOBALS['is_grantuser']) { - $html_output .= $this->getUserLink( - 'edit', - $current_user, - $current_host, - $specific_db, - $specific_table - ); - } - $html_output .= ''; - $html_output .= '' - . $this->getUserLink( - 'export', - $current_user, - $current_host, - $specific_db, - $specific_table - ) - . ''; - - $html_output .= ''; - if (($i + 1) < $nbPrivileges) { - $html_output .= ''; - } - } - return $html_output; - } - - /** - * Returns edit, revoke or export link for a user. - * - * @param string $linktype The link type (edit | revoke | export) - * @param string $username User name - * @param string $hostname Host name - * @param string $dbname Database name - * @param string $tablename Table name - * @param string $routinename Routine name - * @param string $initial Initial value - * - * @return string HTML code with link - */ - public function getUserLink( - $linktype, - $username, - $hostname, - $dbname = '', - $tablename = '', - $routinename = '', - $initial = '' - ) { - $html = ' $username, - 'hostname' => $hostname, - ]; - switch ($linktype) { - case 'edit': - $params['dbname'] = $dbname; - $params['tablename'] = $tablename; - $params['routinename'] = $routinename; - break; - case 'revoke': - $params['dbname'] = $dbname; - $params['tablename'] = $tablename; - $params['routinename'] = $routinename; - $params['revokeall'] = 1; - break; - case 'export': - $params['initial'] = $initial; - $params['export'] = 1; - break; - } - - $html .= ' href="server_privileges.php'; - if ($linktype == 'revoke') { - $html .= '" data-post="' . Url::getCommon($params, ''); - } else { - $html .= Url::getCommon($params); - } - $html .= '">'; - - switch ($linktype) { - case 'edit': - $html .= Util::getIcon('b_usredit', __('Edit privileges')); - break; - case 'revoke': - $html .= Util::getIcon('b_usrdrop', __('Revoke')); - break; - case 'export': - $html .= Util::getIcon('b_tblexport', __('Export')); - break; - } - $html .= ''; - - return $html; - } - - /** - * Returns user group edit link - * - * @param string $username User name - * - * @return string HTML code with link - */ - public function getUserGroupEditLink($username) - { - return '' - . Util::getIcon('b_usrlist', __('Edit user group')) - . ''; - } - - /** - * Returns number of defined user groups - * - * @return integer - */ - public function getUserGroupCount() - { - $cfgRelation = $this->relation->getRelationsParam(); - $user_group_table = Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['usergroups']); - $sql_query = 'SELECT COUNT(*) FROM ' . $user_group_table; - $user_group_count = $this->dbi->fetchValue( - $sql_query, - 0, - 0, - DatabaseInterface::CONNECT_CONTROL - ); - - return $user_group_count; - } - - /** - * Returns name of user group that user is part of - * - * @param string $username User name - * - * @return mixed usergroup if found or null if not found - */ - public function getUserGroupForUser($username) - { - $cfgRelation = $this->relation->getRelationsParam(); - - if (empty($cfgRelation['db']) - || empty($cfgRelation['users']) - ) { - return null; - } - - $user_table = Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['users']); - $sql_query = 'SELECT `usergroup` FROM ' . $user_table - . ' WHERE `username` = \'' . $username . '\'' - . ' LIMIT 1'; - - $usergroup = $this->dbi->fetchValue( - $sql_query, - 0, - 0, - DatabaseInterface::CONNECT_CONTROL - ); - - if ($usergroup === false) { - return null; - } - - return $usergroup; - } - - /** - * This function return the extra data array for the ajax behavior - * - * @param string $password password - * @param string $sql_query sql query - * @param string $hostname hostname - * @param string $username username - * - * @return array - */ - public function getExtraDataForAjaxBehavior( - $password, - $sql_query, - $hostname, - $username - ) { - if (isset($GLOBALS['dbname'])) { - //if (preg_match('/\\\\(?:_|%)/i', $dbname)) { - if (preg_match('/(?getUserGroupCount(); - } - - $extra_data = []; - if (strlen($sql_query) > 0) { - $extra_data['sql_query'] = Util::getMessage(null, $sql_query); - } - - if (isset($_POST['change_copy'])) { - /** - * generate html on the fly for the new user that was just created. - */ - $new_user_string = '' . "\n" - . ' ' - . '' . "\n" - . '' . "\n" - . '' . htmlspecialchars($hostname) . '' . "\n"; - - $new_user_string .= ''; - - if (! empty($password) || isset($_POST['pma_pw'])) { - $new_user_string .= __('Yes'); - } else { - $new_user_string .= '' - . __('No') - . ''; - } - - $new_user_string .= '' . "\n"; - $new_user_string .= '' - . '' . implode(', ', $this->extractPrivInfo(null, true)) . '' - . ''; //Fill in privileges here - - // if $cfg['Servers'][$i]['users'] and $cfg['Servers'][$i]['usergroups'] are - // enabled - $cfgRelation = $this->relation->getRelationsParam(); - if (! empty($cfgRelation['users']) && ! empty($cfgRelation['usergroups'])) { - $new_user_string .= ''; - } - - $new_user_string .= ''; - if (isset($_POST['Grant_priv']) && $_POST['Grant_priv'] == 'Y') { - $new_user_string .= __('Yes'); - } else { - $new_user_string .= __('No'); - } - $new_user_string .= ''; - - if ($GLOBALS['is_grantuser']) { - $new_user_string .= '' - . $this->getUserLink('edit', $username, $hostname) - . '' . "\n"; - } - - if ($cfgRelation['menuswork'] && $user_group_count > 0) { - $new_user_string .= '' - . $this->getUserGroupEditLink($username) - . '' . "\n"; - } - - $new_user_string .= '' - . $this->getUserLink( - 'export', - $username, - $hostname, - '', - '', - '', - isset($_GET['initial']) ? $_GET['initial'] : '' - ) - . '' . "\n"; - - $new_user_string .= ''; - - $extra_data['new_user_string'] = $new_user_string; - - /** - * Generate the string for this alphabet's initial, to update the user - * pagination - */ - $new_user_initial = mb_strtoupper( - mb_substr($username, 0, 1) - ); - $newUserInitialString = '' - . $new_user_initial . ''; - $extra_data['new_user_initial'] = $new_user_initial; - $extra_data['new_user_initial_string'] = $newUserInitialString; - } - - if (isset($_POST['update_privs'])) { - $extra_data['db_specific_privs'] = false; - $extra_data['db_wildcard_privs'] = false; - if (isset($dbname_is_wildcard)) { - $extra_data['db_specific_privs'] = ! $dbname_is_wildcard; - $extra_data['db_wildcard_privs'] = $dbname_is_wildcard; - } - $new_privileges = implode(', ', $this->extractPrivInfo(null, true)); - - $extra_data['new_privileges'] = $new_privileges; - } - - if (isset($_GET['validate_username'])) { - $sql_query = "SELECT * FROM `mysql`.`user` WHERE `User` = '" - . $this->dbi->escapeString($_GET['username']) . "';"; - $res = $this->dbi->query($sql_query); - $row = $this->dbi->fetchRow($res); - if (empty($row)) { - $extra_data['user_exists'] = false; - } else { - $extra_data['user_exists'] = true; - } - } - - return $extra_data; - } - - /** - * Get the HTML snippet for change user login information - * - * @param string $username username - * @param string $hostname host name - * - * @return string HTML snippet - */ - public function getChangeLoginInformationHtmlForm($username, $hostname) - { - $choices = [ - '4' => __('… keep the old one.'), - '1' => __('… delete the old one from the user tables.'), - '2' => __( - '… revoke all active privileges from ' - . 'the old one and delete it afterwards.' - ), - '3' => __( - '… delete the old one from the user tables ' - . 'and reload the privileges afterwards.' - ), - ]; - - $html_output = '' . "\n"; - - return $html_output; - } - - /** - * Provide a line with links to the relevant database and table - * - * @param string $url_dbname url database name that urlencode() string - * @param string $dbname database name - * @param string $tablename table name - * - * @return string HTML snippet - */ - public function getLinkToDbAndTable($url_dbname, $dbname, $tablename) - { - $html_output = '[ ' . __('Database') - . ' ' - . htmlspecialchars(Util::unescapeMysqlWildcards($dbname)) . ': ' - . Util::getTitleForTarget( - $GLOBALS['cfg']['DefaultTabDatabase'] - ) - . " ]\n"; - - if (strlen($tablename) > 0) { - $html_output .= ' [ ' . __('Table') . ' ' . htmlspecialchars($tablename) . ': ' - . Util::getTitleForTarget( - $GLOBALS['cfg']['DefaultTabTable'] - ) - . " ]\n"; - } - return $html_output; - } - - /** - * no db name given, so we want all privs for the given user - * db name was given, so we want all user specific rights for this db - * So this function returns user rights as an array - * - * @param string $username username - * @param string $hostname host name - * @param string $type database or table - * @param string $dbname database name - * - * @return array database rights - */ - public function getUserSpecificRights($username, $hostname, $type, $dbname = '') - { - $user_host_condition = " WHERE `User`" - . " = '" . $this->dbi->escapeString($username) . "'" - . " AND `Host`" - . " = '" . $this->dbi->escapeString($hostname) . "'"; - - if ($type == 'database') { - $tables_to_search_for_users = [ - 'tables_priv', - 'columns_priv', - 'procs_priv', - ]; - $dbOrTableName = 'Db'; - } elseif ($type == 'table') { - $user_host_condition .= " AND `Db` LIKE '" - . $this->dbi->escapeString($dbname) . "'"; - $tables_to_search_for_users = ['columns_priv']; - $dbOrTableName = 'Table_name'; - } else { // routine - $user_host_condition .= " AND `Db` LIKE '" - . $this->dbi->escapeString($dbname) . "'"; - $tables_to_search_for_users = ['procs_priv']; - $dbOrTableName = 'Routine_name'; - } - - // we also want privileges for this user not in table `db` but in other table - $tables = $this->dbi->fetchResult('SHOW TABLES FROM `mysql`;'); - - $db_rights_sqls = []; - foreach ($tables_to_search_for_users as $table_search_in) { - if (in_array($table_search_in, $tables)) { - $db_rights_sqls[] = ' - SELECT DISTINCT `' . $dbOrTableName . '` - FROM `mysql`.' . Util::backquote($table_search_in) - . $user_host_condition; - } - } - - $user_defaults = [ - $dbOrTableName => '', - 'Grant_priv' => 'N', - 'privs' => ['USAGE'], - 'Column_priv' => true, - ]; - - // for the rights - $db_rights = []; - - $db_rights_sql = '(' . implode(') UNION (', $db_rights_sqls) . ')' - . ' ORDER BY `' . $dbOrTableName . '` ASC'; - - $db_rights_result = $this->dbi->query($db_rights_sql); - - while ($db_rights_row = $this->dbi->fetchAssoc($db_rights_result)) { - $db_rights_row = array_merge($user_defaults, $db_rights_row); - if ($type == 'database') { - // only Db names in the table `mysql`.`db` uses wildcards - // as we are in the db specific rights display we want - // all db names escaped, also from other sources - $db_rights_row['Db'] = Util::escapeMysqlWildcards( - $db_rights_row['Db'] - ); - } - $db_rights[$db_rights_row[$dbOrTableName]] = $db_rights_row; - } - - $this->dbi->freeResult($db_rights_result); - - if ($type == 'database') { - $sql_query = 'SELECT * FROM `mysql`.`db`' - . $user_host_condition . ' ORDER BY `Db` ASC'; - } elseif ($type == 'table') { - $sql_query = 'SELECT `Table_name`,' - . ' `Table_priv`,' - . ' IF(`Column_priv` = _latin1 \'\', 0, 1)' - . ' AS \'Column_priv\'' - . ' FROM `mysql`.`tables_priv`' - . $user_host_condition - . ' ORDER BY `Table_name` ASC;'; - } else { - $sql_query = "SELECT `Routine_name`, `Proc_priv`" - . " FROM `mysql`.`procs_priv`" - . $user_host_condition - . " ORDER BY `Routine_name`"; - } - - $result = $this->dbi->query($sql_query); - - while ($row = $this->dbi->fetchAssoc($result)) { - if (isset($db_rights[$row[$dbOrTableName]])) { - $db_rights[$row[$dbOrTableName]] - = array_merge($db_rights[$row[$dbOrTableName]], $row); - } else { - $db_rights[$row[$dbOrTableName]] = $row; - } - if ($type == 'database') { - // there are db specific rights for this user - // so we can drop this db rights - $db_rights[$row['Db']]['can_delete'] = true; - } - } - $this->dbi->freeResult($result); - return $db_rights; - } - - /** - * Parses Proc_priv data - * - * @param string $privs Proc_priv - * - * @return array - */ - public function parseProcPriv($privs) - { - $result = [ - 'Alter_routine_priv' => 'N', - 'Execute_priv' => 'N', - 'Grant_priv' => 'N', - ]; - foreach (explode(',', (string) $privs) as $priv) { - if ($priv == 'Alter Routine') { - $result['Alter_routine_priv'] = 'Y'; - } else { - $result[$priv . '_priv'] = 'Y'; - } - } - return $result; - } - - /** - * Get a HTML table for display user's tabel specific or database specific rights - * - * @param string $username username - * @param string $hostname host name - * @param string $type database, table or routine - * @param string $dbname database name - * - * @return string - */ - public function getHtmlForAllTableSpecificRights( - $username, - $hostname, - $type, - $dbname = '' - ) { - $uiData = [ - 'database' => [ - 'form_id' => 'database_specific_priv', - 'sub_menu_label' => __('Database'), - 'legend' => __('Database-specific privileges'), - 'type_label' => __('Database'), - ], - 'table' => [ - 'form_id' => 'table_specific_priv', - 'sub_menu_label' => __('Table'), - 'legend' => __('Table-specific privileges'), - 'type_label' => __('Table'), - ], - 'routine' => [ - 'form_id' => 'routine_specific_priv', - 'sub_menu_label' => __('Routine'), - 'legend' => __('Routine-specific privileges'), - 'type_label' => __('Routine'), - ], - ]; - - /** - * no db name given, so we want all privs for the given user - * db name was given, so we want all user specific rights for this db - */ - $db_rights = $this->getUserSpecificRights($username, $hostname, $type, $dbname); - ksort($db_rights); - - $foundRows = []; - $privileges = []; - foreach ($db_rights as $row) { - $onePrivilege = []; - - $paramTableName = ''; - $paramRoutineName = ''; - - if ($type == 'database') { - $name = $row['Db']; - $onePrivilege['grant'] = $row['Grant_priv'] == 'Y'; - $onePrivilege['table_privs'] = ! empty($row['Table_priv']) - || ! empty($row['Column_priv']); - $onePrivilege['privileges'] = implode(',', $this->extractPrivInfo($row, true)); - - $paramDbName = $row['Db']; - } elseif ($type == 'table') { - $name = $row['Table_name']; - $onePrivilege['grant'] = in_array( - 'Grant', - explode(',', $row['Table_priv']) - ); - $onePrivilege['column_privs'] = ! empty($row['Column_priv']); - $onePrivilege['privileges'] = implode(',', $this->extractPrivInfo($row, true)); - - $paramDbName = $dbname; - $paramTableName = $row['Table_name']; - } else { // routine - $name = $row['Routine_name']; - $onePrivilege['grant'] = in_array( - 'Grant', - explode(',', $row['Proc_priv']) - ); - - $privs = $this->parseProcPriv($row['Proc_priv']); - $onePrivilege['privileges'] = implode( - ',', - $this->extractPrivInfo($privs, true) - ); - - $paramDbName = $dbname; - $paramRoutineName = $row['Routine_name']; - } - - $foundRows[] = $name; - $onePrivilege['name'] = $name; - - $onePrivilege['edit_link'] = ''; - if ($GLOBALS['is_grantuser']) { - $onePrivilege['edit_link'] = $this->getUserLink( - 'edit', - $username, - $hostname, - $paramDbName, - $paramTableName, - $paramRoutineName - ); - } - - $onePrivilege['revoke_link'] = ''; - if ($type != 'database' || ! empty($row['can_delete'])) { - $onePrivilege['revoke_link'] = $this->getUserLink( - 'revoke', - $username, - $hostname, - $paramDbName, - $paramTableName, - $paramRoutineName - ); - } - - $privileges[] = $onePrivilege; - } - - $data = $uiData[$type]; - $data['privileges'] = $privileges; - $data['username'] = $username; - $data['hostname'] = $hostname; - $data['database'] = $dbname; - $data['type'] = $type; - - if ($type == 'database') { - // we already have the list of databases from libraries/common.inc.php - // via $pma = new PMA; - $pred_db_array = $GLOBALS['dblist']->databases; - $databases_to_skip = [ - 'information_schema', - 'performance_schema', - ]; - - $databases = []; - if (! empty($pred_db_array)) { - foreach ($pred_db_array as $current_db) { - if (in_array($current_db, $databases_to_skip)) { - continue; - } - $current_db_escaped = Util::escapeMysqlWildcards($current_db); - // cannot use array_diff() once, outside of the loop, - // because the list of databases has special characters - // already escaped in $foundRows, - // contrary to the output of SHOW DATABASES - if (! in_array($current_db_escaped, $foundRows)) { - $databases[] = $current_db; - } - } - } - $data['databases'] = $databases; - } elseif ($type == 'table') { - $result = @$this->dbi->tryQuery( - "SHOW TABLES FROM " . Util::backquote($dbname), - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - - $tables = []; - if ($result) { - while ($row = $this->dbi->fetchRow($result)) { - if (! in_array($row[0], $foundRows)) { - $tables[] = $row[0]; - } - } - $this->dbi->freeResult($result); - } - $data['tables'] = $tables; - } else { // routine - $routineData = $this->dbi->getRoutines($dbname); - - $routines = []; - foreach ($routineData as $routine) { - if (! in_array($routine['name'], $foundRows)) { - $routines[] = $routine['name']; - } - } - $data['routines'] = $routines; - } - - return $this->template->render('server/privileges/privileges_summary', $data); - } - - /** - * Get HTML for display the users overview - * (if less than 50 users, display them immediately) - * - * @param array $result ran sql query - * @param array $db_rights user's database rights array - * @param string $pmaThemeImage a image source link - * @param string $text_dir text directory - * - * @return string HTML snippet - */ - public function getUsersOverview($result, array $db_rights, $pmaThemeImage, $text_dir) - { - while ($row = $this->dbi->fetchAssoc($result)) { - $row['privs'] = $this->extractPrivInfo($row, true); - $db_rights[$row['User']][$row['Host']] = $row; - } - $this->dbi->freeResult($result); - $user_group_count = 0; - if ($GLOBALS['cfgRelation']['menuswork']) { - $user_group_count = $this->getUserGroupCount(); - } - - $html_output - = '
    ' . "\n" - . Url::getHiddenInputs('', '') - . '
    ' - . '' . "\n" - . '' . "\n" - . '' . "\n" - . '' . "\n" - . '' . "\n" - . '' . "\n" - . '' . "\n"; - if ($GLOBALS['cfgRelation']['menuswork']) { - $html_output .= '' . "\n"; - } - $html_output .= '' . "\n" - . '' . "\n" - . '' . "\n" - . '' . "\n"; - - $html_output .= '' . "\n"; - $html_output .= $this->getHtmlTableBodyForUserRights($db_rights); - $html_output .= '' - . '
    ' . __('User name') . '' . __('Host name') . '' . __('Password') . '' . __('Global privileges') . ' ' - . Util::showHint( - __('Note: MySQL privilege names are expressed in English.') - ) - . '' . __('User group') . '' . __('Grant') . '' - . __('Action') . '
    ' . "\n"; - - $html_output .= '
    ' - . $this->template->render('select_all', [ - 'pma_theme_image' => $pmaThemeImage, - 'text_dir' => $text_dir, - 'form_name' => 'usersForm', - ]) . "\n"; - $html_output .= Util::getButtonOrImage( - 'submit_mult', - 'mult_submit', - __('Export'), - 'b_tblexport', - 'export' - ); - $html_output .= ''; - $html_output .= '
    ' - . '
    '; - - // add/delete user fieldset - $html_output .= $this->getFieldsetForAddDeleteUser(); - $html_output .= '
    ' . "\n"; - - return $html_output; - } - - /** - * Get table body for 'tableuserrights' table in userform - * - * @param array $db_rights user's database rights array - * - * @return string HTML snippet - */ - public function getHtmlTableBodyForUserRights(array $db_rights) - { - $cfgRelation = $this->relation->getRelationsParam(); - $user_group_count = 0; - if ($cfgRelation['menuswork']) { - $users_table = Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['users']); - $sql_query = 'SELECT * FROM ' . $users_table; - $result = $this->relation->queryAsControlUser($sql_query, false); - $group_assignment = []; - if ($result) { - while ($row = $this->dbi->fetchAssoc($result)) { - $group_assignment[$row['username']] = $row['usergroup']; - } - } - $this->dbi->freeResult($result); - - $user_group_count = $this->getUserGroupCount(); - } - - $index_checkbox = 0; - $html_output = ''; - foreach ($db_rights as $user) { - ksort($user); - foreach ($user as $host) { - $index_checkbox++; - $html_output .= '' - . "\n"; - $html_output .= '' - . '' . "\n"; - - $html_output .= '' . "\n" - . '' . htmlspecialchars($host['Host']) . '' . "\n"; - - $html_output .= ''; - - $password_column = 'Password'; - - $check_plugin_query = "SELECT * FROM `mysql`.`user` WHERE " - . "`User` = '" . $host['User'] . "' AND `Host` = '" - . $host['Host'] . "'"; - $res = $this->dbi->fetchSingleRow($check_plugin_query); - - if ((isset($res['authentication_string']) - && ! empty($res['authentication_string'])) - || (isset($res['Password']) - && ! empty($res['Password'])) - ) { - $host[$password_column] = 'Y'; - } else { - $host[$password_column] = 'N'; - } - - switch ($host[$password_column]) { - case 'Y': - $html_output .= __('Yes'); - break; - case 'N': - $html_output .= '' . __('No') - . ''; - break; - // this happens if this is a definition not coming from mysql.user - default: - $html_output .= '--'; // in future version, replace by "not present" - break; - } // end switch - - if (! isset($host['Select_priv'])) { - $html_output .= Util::showHint( - __('The selected user was not found in the privilege table.') - ); - } - - $html_output .= '' . "\n"; - - $html_output .= '' . "\n" - . '' . implode(',' . "\n" . ' ', $host['privs']) . "\n" - . '' . "\n"; - if ($cfgRelation['menuswork']) { - $html_output .= '' . "\n" - . (isset($group_assignment[$host['User']]) - ? htmlspecialchars($group_assignment[$host['User']]) - : '' - ) - . '' . "\n"; - } - $html_output .= '' - . ($host['Grant_priv'] == 'Y' ? __('Yes') : __('No')) - . '' . "\n"; - - if ($GLOBALS['is_grantuser']) { - $html_output .= '' - . $this->getUserLink( - 'edit', - $host['User'], - $host['Host'] - ) - . ''; - } - if ($cfgRelation['menuswork'] && $user_group_count > 0) { - if (empty($host['User'])) { - $html_output .= ''; - } else { - $html_output .= '' - . $this->getUserGroupEditLink($host['User']) - . ''; - } - } - $html_output .= '' - . $this->getUserLink( - 'export', - $host['User'], - $host['Host'], - '', - '', - '', - isset($_GET['initial']) ? $_GET['initial'] : '' - ) - . ''; - $html_output .= ''; - } - } - return $html_output; - } - - /** - * Get HTML fieldset for Add/Delete user - * - * @return string HTML snippet - */ - public function getFieldsetForAddDeleteUser() - { - $html_output = $this->getAddUserHtmlFieldset(); - - $html_output .= $this->template->render('server/privileges/delete_user_fieldset'); - - return $html_output; - } - - /** - * Get HTML for Displays the initials - * - * @param array $array_initials array for all initials, even non A-Z - * - * @return string HTML snippet - */ - public function getHtmlForInitials(array $array_initials) - { - // initialize to false the letters A-Z - for ($letter_counter = 1; $letter_counter < 27; $letter_counter++) { - if (! isset($array_initials[mb_chr($letter_counter + 64)])) { - $array_initials[mb_chr($letter_counter + 64)] = false; - } - } - - $initials = $this->dbi->tryQuery( - 'SELECT DISTINCT UPPER(LEFT(`User`,1)) FROM `user`' - . ' ORDER BY UPPER(LEFT(`User`,1)) ASC', - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - if ($initials) { - while (list($tmp_initial) = $this->dbi->fetchRow($initials)) { - $array_initials[$tmp_initial] = true; - } - } - - // Display the initials, which can be any characters, not - // just letters. For letters A-Z, we add the non-used letters - // as greyed out. - - uksort($array_initials, "strnatcasecmp"); - - return $this->template->render('server/privileges/initials_row', [ - 'array_initials' => $array_initials, - 'initial' => isset($_GET['initial']) ? $_GET['initial'] : null, - ]); - } - - /** - * Get the database rights array for Display user overview - * - * @return array database rights array - */ - public function getDbRightsForUserOverview() - { - // we also want users not in table `user` but in other table - $tables = $this->dbi->fetchResult('SHOW TABLES FROM `mysql`;'); - - $tablesSearchForUsers = [ - 'user', - 'db', - 'tables_priv', - 'columns_priv', - 'procs_priv', - ]; - - $db_rights_sqls = []; - foreach ($tablesSearchForUsers as $table_search_in) { - if (in_array($table_search_in, $tables)) { - $db_rights_sqls[] = 'SELECT DISTINCT `User`, `Host` FROM `mysql`.`' - . $table_search_in . '` ' - . (isset($_GET['initial']) - ? $this->rangeOfUsers($_GET['initial']) - : ''); - } - } - $user_defaults = [ - 'User' => '', - 'Host' => '%', - 'Password' => '?', - 'Grant_priv' => 'N', - 'privs' => ['USAGE'], - ]; - - // for the rights - $db_rights = []; - - $db_rights_sql = '(' . implode(') UNION (', $db_rights_sqls) . ')' - . ' ORDER BY `User` ASC, `Host` ASC'; - - $db_rights_result = $this->dbi->query($db_rights_sql); - - while ($db_rights_row = $this->dbi->fetchAssoc($db_rights_result)) { - $db_rights_row = array_merge($user_defaults, $db_rights_row); - $db_rights[$db_rights_row['User']][$db_rights_row['Host']] - = $db_rights_row; - } - $this->dbi->freeResult($db_rights_result); - ksort($db_rights); - - return $db_rights; - } - - /** - * Delete user and get message and sql query for delete user in privileges - * - * @param array $queries queries - * - * @return array Message - */ - public function deleteUser(array $queries) - { - $sql_query = ''; - if (empty($queries)) { - $message = Message::error(__('No users selected for deleting!')); - } else { - if ($_POST['mode'] == 3) { - $queries[] = '# ' . __('Reloading the privileges') . ' …'; - $queries[] = 'FLUSH PRIVILEGES;'; - } - $drop_user_error = ''; - foreach ($queries as $sql_query) { - if ($sql_query[0] != '#') { - if (! $this->dbi->tryQuery($sql_query)) { - $drop_user_error .= $this->dbi->getError() . "\n"; - } - } - } - // tracking sets this, causing the deleted db to be shown in navi - unset($GLOBALS['db']); - - $sql_query = implode("\n", $queries); - if (! empty($drop_user_error)) { - $message = Message::rawError($drop_user_error); - } else { - $message = Message::success( - __('The selected users have been deleted successfully.') - ); - } - } - return [ - $sql_query, - $message, - ]; - } - - /** - * Update the privileges and return the success or error message - * - * @param string $username username - * @param string $hostname host name - * @param string $tablename table name - * @param string $dbname database name - * @param string $itemType item type - * - * @return array success message or error message for update - */ - public function updatePrivileges($username, $hostname, $tablename, $dbname, $itemType) - { - $db_and_table = $this->wildcardEscapeForGrant($dbname, $tablename); - - $sql_query0 = 'REVOKE ALL PRIVILEGES ON ' . $itemType . ' ' . $db_and_table - . ' FROM \'' . $this->dbi->escapeString($username) - . '\'@\'' . $this->dbi->escapeString($hostname) . '\';'; - - if (! isset($_POST['Grant_priv']) || $_POST['Grant_priv'] != 'Y') { - $sql_query1 = 'REVOKE GRANT OPTION ON ' . $itemType . ' ' . $db_and_table - . ' FROM \'' . $this->dbi->escapeString($username) . '\'@\'' - . $this->dbi->escapeString($hostname) . '\';'; - } else { - $sql_query1 = ''; - } - - // Should not do a GRANT USAGE for a table-specific privilege, it - // causes problems later (cannot revoke it) - if (! (strlen($tablename) > 0 - && 'USAGE' == implode('', $this->extractPrivInfo())) - ) { - $sql_query2 = 'GRANT ' . implode(', ', $this->extractPrivInfo()) - . ' ON ' . $itemType . ' ' . $db_and_table - . ' TO \'' . $this->dbi->escapeString($username) . '\'@\'' - . $this->dbi->escapeString($hostname) . '\''; - - if (strlen($dbname) === 0) { - // add REQUIRE clause - $sql_query2 .= $this->getRequireClause(); - } - - if ((isset($_POST['Grant_priv']) && $_POST['Grant_priv'] == 'Y') - || (strlen($dbname) === 0 - && (isset($_POST['max_questions']) || isset($_POST['max_connections']) - || isset($_POST['max_updates']) - || isset($_POST['max_user_connections']))) - ) { - $sql_query2 .= $this->getWithClauseForAddUserAndUpdatePrivs(); - } - $sql_query2 .= ';'; - } - if (! $this->dbi->tryQuery($sql_query0)) { - // This might fail when the executing user does not have - // ALL PRIVILEGES himself. - // See https://github.com/phpmyadmin/phpmyadmin/issues/9673 - $sql_query0 = ''; - } - if (! empty($sql_query1) && ! $this->dbi->tryQuery($sql_query1)) { - // this one may fail, too... - $sql_query1 = ''; - } - if (! empty($sql_query2)) { - $this->dbi->query($sql_query2); - } else { - $sql_query2 = ''; - } - $sql_query = $sql_query0 . ' ' . $sql_query1 . ' ' . $sql_query2; - $message = Message::success(__('You have updated the privileges for %s.')); - $message->addParam('\'' . $username . '\'@\'' . $hostname . '\''); - - return [ - $sql_query, - $message, - ]; - } - - /** - * Get List of information: Changes / copies a user - * - * @return array - */ - public function getDataForChangeOrCopyUser() - { - $queries = null; - $password = null; - - if (isset($_POST['change_copy'])) { - $user_host_condition = ' WHERE `User` = ' - . "'" . $this->dbi->escapeString($_POST['old_username']) . "'" - . ' AND `Host` = ' - . "'" . $this->dbi->escapeString($_POST['old_hostname']) . "';"; - $row = $this->dbi->fetchSingleRow( - 'SELECT * FROM `mysql`.`user` ' . $user_host_condition - ); - if (! $row) { - $response = Response::getInstance(); - $response->addHTML( - Message::notice(__('No user found.'))->getDisplay() - ); - unset($_POST['change_copy']); - } else { - foreach ($row as $key => $value) { - $GLOBALS[$key] = $value; - } - $serverVersion = $this->dbi->getVersion(); - // Recent MySQL versions have the field "Password" in mysql.user, - // so the previous extract creates $row['Password'] but this script - // uses $password - if (! isset($row['password']) && isset($row['Password'])) { - $row['password'] = $row['Password']; - } - if (Util::getServerType() == 'MySQL' - && $serverVersion >= 50606 - && $serverVersion < 50706 - && ((isset($row['authentication_string']) - && empty($row['password'])) - || (isset($row['plugin']) - && $row['plugin'] == 'sha256_password')) - ) { - $row['password'] = $row['authentication_string']; - } - - if (Util::getServerType() == 'MariaDB' - && $serverVersion >= 50500 - && isset($row['authentication_string']) - && empty($row['password']) - ) { - $row['password'] = $row['authentication_string']; - } - - // Always use 'authentication_string' column - // for MySQL 5.7.6+ since it does not have - // the 'password' column at all - if (in_array(Util::getServerType(), ['MySQL', 'Percona Server']) - && $serverVersion >= 50706 - && isset($row['authentication_string']) - ) { - $row['password'] = $row['authentication_string']; - } - $password = $row['password']; - $queries = []; - } - } - - return [ - $queries, - $password, - ]; - } - - /** - * Update Data for information: Deletes users - * - * @param array $queries queries array - * - * @return array - */ - public function getDataForDeleteUsers($queries) - { - if (isset($_POST['change_copy'])) { - $selected_usr = [ - $_POST['old_username'] . '&#27;' . $_POST['old_hostname'], - ]; - } else { - $selected_usr = $_POST['selected_usr']; - $queries = []; - } - - // this happens, was seen in https://reports.phpmyadmin.net/reports/view/17146 - if (! is_array($selected_usr)) { - return []; - } - - foreach ($selected_usr as $each_user) { - list($this_user, $this_host) = explode('&#27;', $each_user); - $queries[] = '# ' - . sprintf( - __('Deleting %s'), - '\'' . $this_user . '\'@\'' . $this_host . '\'' - ) - . ' ...'; - $queries[] = 'DROP USER \'' - . $this->dbi->escapeString($this_user) - . '\'@\'' . $this->dbi->escapeString($this_host) . '\';'; - $this->relationCleanup->user($this_user); - - if (isset($_POST['drop_users_db'])) { - $queries[] = 'DROP DATABASE IF EXISTS ' - . Util::backquote($this_user) . ';'; - $GLOBALS['reload'] = true; - } - } - return $queries; - } - - /** - * update Message For Reload - * - * @return Message|null - */ - public function updateMessageForReload(): ?Message - { - $message = null; - if (isset($_GET['flush_privileges'])) { - $sql_query = 'FLUSH PRIVILEGES;'; - $this->dbi->query($sql_query); - $message = Message::success( - __('The privileges were reloaded successfully.') - ); - } - - if (isset($_GET['validate_username'])) { - $message = Message::success(); - } - - return $message; - } - - /** - * update Data For Queries from queries_for_display - * - * @param array $queries queries array - * @param array|null $queries_for_display queries array for display - * - * @return array - */ - public function getDataForQueries(array $queries, $queries_for_display) - { - $tmp_count = 0; - foreach ($queries as $sql_query) { - if ($sql_query[0] != '#') { - $this->dbi->query($sql_query); - } - // when there is a query containing a hidden password, take it - // instead of the real query sent - if (isset($queries_for_display[$tmp_count])) { - $queries[$tmp_count] = $queries_for_display[$tmp_count]; - } - $tmp_count++; - } - - return $queries; - } - - /** - * update Data for information: Adds a user - * - * @param string|array|null $dbname db name - * @param string $username user name - * @param string $hostname host name - * @param string|null $password password - * @param bool $is_menuwork is_menuwork set? - * - * @return array - */ - public function addUser( - $dbname, - $username, - $hostname, - ?string $password, - $is_menuwork - ) { - $_add_user_error = false; - $message = null; - $queries = null; - $queries_for_display = null; - $sql_query = null; - - if (! isset($_POST['adduser_submit']) && ! isset($_POST['change_copy'])) { - return [ - $message, - $queries, - $queries_for_display, - $sql_query, - $_add_user_error, - ]; - } - - $sql_query = ''; - if ($_POST['pred_username'] == 'any') { - $username = ''; - } - switch ($_POST['pred_hostname']) { - case 'any': - $hostname = '%'; - break; - case 'localhost': - $hostname = 'localhost'; - break; - case 'hosttable': - $hostname = ''; - break; - case 'thishost': - $_user_name = $this->dbi->fetchValue('SELECT USER()'); - $hostname = mb_substr( - $_user_name, - mb_strrpos($_user_name, '@') + 1 - ); - unset($_user_name); - break; - } - $sql = "SELECT '1' FROM `mysql`.`user`" - . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" - . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "';"; - if ($this->dbi->fetchValue($sql) == 1) { - $message = Message::error(__('The user %s already exists!')); - $message->addParam('[em]\'' . $username . '\'@\'' . $hostname . '\'[/em]'); - $_GET['adduser'] = true; - $_add_user_error = true; - - return [ - $message, - $queries, - $queries_for_display, - $sql_query, - $_add_user_error, - ]; - } - - list( - $create_user_real, - $create_user_show, - $real_sql_query, - $sql_query, - $password_set_real, - $password_set_show, - $alter_real_sql_query, - $alter_sql_query - ) = $this->getSqlQueriesForDisplayAndAddUser( - $username, - $hostname, - (isset($password) ? $password : '') - ); - - if (empty($_POST['change_copy'])) { - $_error = false; - - if ($create_user_real !== null) { - if (! $this->dbi->tryQuery($create_user_real)) { - $_error = true; - } - if (isset($password_set_real) && ! empty($password_set_real) - && isset($_POST['authentication_plugin']) - ) { - $this->setProperPasswordHashing( - $_POST['authentication_plugin'] - ); - if ($this->dbi->tryQuery($password_set_real)) { - $sql_query .= $password_set_show; - } - } - $sql_query = $create_user_show . $sql_query; - } - - list($sql_query, $message) = $this->addUserAndCreateDatabase( - $_error, - $real_sql_query, - $sql_query, - $username, - $hostname, - $dbname, - $alter_real_sql_query, - $alter_sql_query - ); - if (! empty($_POST['userGroup']) && $is_menuwork) { - $this->setUserGroup($GLOBALS['username'], $_POST['userGroup']); - } - - return [ - $message, - $queries, - $queries_for_display, - $sql_query, - $_add_user_error, - ]; - } - - // Copy the user group while copying a user - $old_usergroup = - isset($_POST['old_usergroup']) ? $_POST['old_usergroup'] : null; - $this->setUserGroup($_POST['username'], $old_usergroup); - - if ($create_user_real === null) { - $queries[] = $create_user_real; - } - $queries[] = $real_sql_query; - - if (isset($password_set_real) && ! empty($password_set_real) - && isset($_POST['authentication_plugin']) - ) { - $this->setProperPasswordHashing( - $_POST['authentication_plugin'] - ); - - $queries[] = $password_set_real; - } - // we put the query containing the hidden password in - // $queries_for_display, at the same position occupied - // by the real query in $queries - $tmp_count = count($queries); - if (isset($create_user_real)) { - $queries_for_display[$tmp_count - 2] = $create_user_show; - } - if (isset($password_set_real) && ! empty($password_set_real)) { - $queries_for_display[$tmp_count - 3] = $create_user_show; - $queries_for_display[$tmp_count - 2] = $sql_query; - $queries_for_display[$tmp_count - 1] = $password_set_show; - } else { - $queries_for_display[$tmp_count - 1] = $sql_query; - } - - return [ - $message, - $queries, - $queries_for_display, - $sql_query, - $_add_user_error, - ]; - } - - /** - * Sets proper value of `old_passwords` according to - * the authentication plugin selected - * - * @param string $auth_plugin authentication plugin selected - * - * @return void - */ - public function setProperPasswordHashing($auth_plugin) - { - // Set the hashing method used by PASSWORD() - // to be of type depending upon $authentication_plugin - if ($auth_plugin == 'sha256_password') { - $this->dbi->tryQuery('SET `old_passwords` = 2;'); - } elseif ($auth_plugin == 'mysql_old_password') { - $this->dbi->tryQuery('SET `old_passwords` = 1;'); - } else { - $this->dbi->tryQuery('SET `old_passwords` = 0;'); - } - } - - /** - * Update DB information: DB, Table, isWildcard - * - * @return array - */ - public function getDataForDBInfo() - { - $username = null; - $hostname = null; - $dbname = null; - $tablename = null; - $routinename = null; - $dbname_is_wildcard = null; - - if (isset($_REQUEST['username'])) { - $username = $_REQUEST['username']; - } - if (isset($_REQUEST['hostname'])) { - $hostname = $_REQUEST['hostname']; - } - /** - * Checks if a dropdown box has been used for selecting a database / table - */ - if (Core::isValid($_POST['pred_tablename'])) { - $tablename = $_POST['pred_tablename']; - } elseif (Core::isValid($_REQUEST['tablename'])) { - $tablename = $_REQUEST['tablename']; - } else { - unset($tablename); - } - - if (Core::isValid($_POST['pred_routinename'])) { - $routinename = $_POST['pred_routinename']; - } elseif (Core::isValid($_REQUEST['routinename'])) { - $routinename = $_REQUEST['routinename']; - } else { - unset($routinename); - } - - if (isset($_POST['pred_dbname'])) { - $is_valid_pred_dbname = true; - foreach ($_POST['pred_dbname'] as $key => $db_name) { - if (! Core::isValid($db_name)) { - $is_valid_pred_dbname = false; - break; - } - } - } - - if (isset($_REQUEST['dbname'])) { - $is_valid_dbname = true; - if (is_array($_REQUEST['dbname'])) { - foreach ($_REQUEST['dbname'] as $key => $db_name) { - if (! Core::isValid($db_name)) { - $is_valid_dbname = false; - break; - } - } - } else { - if (! Core::isValid($_REQUEST['dbname'])) { - $is_valid_dbname = false; - } - } - } - - if (isset($is_valid_pred_dbname) && $is_valid_pred_dbname) { - $dbname = $_POST['pred_dbname']; - // If dbname contains only one database. - if (count($dbname) === 1) { - $dbname = $dbname[0]; - } - } elseif (isset($is_valid_dbname) && $is_valid_dbname) { - $dbname = $_REQUEST['dbname']; - } else { - unset($dbname); - unset($tablename); - } - - if (isset($dbname)) { - if (is_array($dbname)) { - $db_and_table = $dbname; - foreach ($db_and_table as $key => $db_name) { - $db_and_table[$key] .= '.'; - } - } else { - $unescaped_db = Util::unescapeMysqlWildcards($dbname); - $db_and_table = Util::backquote($unescaped_db) . '.'; - } - if (isset($tablename)) { - $db_and_table .= Util::backquote($tablename); - } else { - if (is_array($db_and_table)) { - foreach ($db_and_table as $key => $db_name) { - $db_and_table[$key] .= '*'; - } - } else { - $db_and_table .= '*'; - } - } - } else { - $db_and_table = '*.*'; - } - - // check if given $dbname is a wildcard or not - if (isset($dbname)) { - //if (preg_match('/\\\\(?:_|%)/i', $dbname)) { - if (! is_array($dbname) && preg_match('/(?'; - - if (isset($_POST['selected_usr'])) { - // export privileges for selected users - $title = __('Privileges'); - - //For removing duplicate entries of users - $_POST['selected_usr'] = array_unique($_POST['selected_usr']); - - foreach ($_POST['selected_usr'] as $export_user) { - $export_username = mb_substr( - $export_user, - 0, - mb_strpos($export_user, '&') - ); - $export_hostname = mb_substr( - $export_user, - mb_strrpos($export_user, ';') + 1 - ); - $export .= '# ' - . sprintf( - __('Privileges for %s'), - '`' . htmlspecialchars($export_username) - . '`@`' . htmlspecialchars($export_hostname) . '`' - ) - . "\n\n"; - $export .= $this->getGrants($export_username, $export_hostname) . "\n"; - } - } else { - // export privileges for a single user - $title = __('User') . ' `' . htmlspecialchars($username) - . '`@`' . htmlspecialchars($hostname) . '`'; - $export .= $this->getGrants($username, $hostname); - } - // remove trailing whitespace - $export = trim($export); - - $export .= ''; - - return [ - $title, - $export, - ]; - } - - /** - * Get HTML for display Add userfieldset - * - * @param string $db the database - * @param string $table the table name - * - * @return string html output - */ - public function getAddUserHtmlFieldset($db = '', $table = '') - { - if (! $GLOBALS['is_createuser']) { - return ''; - } - $rel_params = []; - $url_params = [ - 'adduser' => 1, - ]; - if (! empty($db)) { - $url_params['dbname'] - = $rel_params['checkprivsdb'] - = $db; - } - if (! empty($table)) { - $url_params['tablename'] - = $rel_params['checkprivstable'] - = $table; - } - - return $this->template->render('server/privileges/add_user_fieldset', [ - 'url_params' => $url_params, - 'rel_params' => $rel_params, - ]); - } - - /** - * Get HTML header for display User's properties - * - * @param boolean $dbname_is_wildcard whether database name is wildcard or not - * @param string $url_dbname url database name that urlencode() string - * @param string $dbname database name - * @param string $username username - * @param string $hostname host name - * @param string $entity_name entity (table or routine) name - * @param string $entity_type optional, type of entity ('table' or 'routine') - * - * @return string - */ - public function getHtmlHeaderForUserProperties( - $dbname_is_wildcard, - $url_dbname, - $dbname, - $username, - $hostname, - $entity_name, - $entity_type = 'table' - ) { - $html_output = '

    ' . "\n" - . Util::getIcon('b_usredit') - . __('Edit privileges:') . ' ' - . __('User account'); - - if (! empty($dbname)) { - $html_output .= ' \'' . htmlspecialchars($username) - . '\'@\'' . htmlspecialchars($hostname) - . '\'' . "\n"; - - $html_output .= ' - '; - $html_output .= $dbname_is_wildcard - || is_array($dbname) && count($dbname) > 1 - ? __('Databases') : __('Database'); - if (! empty($entity_name) && $entity_type === 'table') { - $html_output .= ' ' . htmlspecialchars($dbname) - . ''; - - $html_output .= ' - ' . __('Table') - . ' ' . htmlspecialchars($entity_name) . ''; - } elseif (! empty($entity_name)) { - $html_output .= ' ' . htmlspecialchars($dbname) - . ''; - - $html_output .= ' - ' . __('Routine') - . ' ' . htmlspecialchars($entity_name) . ''; - } else { - if (! is_array($dbname)) { - $dbname = [$dbname]; - } - $html_output .= ' ' - . htmlspecialchars(implode(', ', $dbname)) - . ''; - } - } else { - $html_output .= ' \'' . htmlspecialchars($username) - . '\'@\'' . htmlspecialchars($hostname) - . '\'' . "\n"; - } - $html_output .= '

    ' . "\n"; - $cur_user = $this->dbi->getCurrentUser(); - $user = $username . '@' . $hostname; - // Add a short notice for the user - // to remind him that he is editing his own privileges - if ($user === $cur_user) { - $html_output .= Message::notice( - __( - 'Note: You are attempting to edit privileges of the ' - . 'user with which you are currently logged in.' - ) - )->getDisplay(); - } - return $html_output; - } - - /** - * Get HTML snippet for display user overview page - * - * @param string $pmaThemeImage a image source link - * @param string $text_dir text directory - * - * @return string - */ - public function getHtmlForUserOverview($pmaThemeImage, $text_dir) - { - $html_output = '

    ' . "\n" - . Util::getIcon('b_usrlist') - . __('User accounts overview') . "\n" - . '

    ' . "\n"; - - $password_column = 'Password'; - $server_type = Util::getServerType(); - $serverVersion = $this->dbi->getVersion(); - if (($server_type == 'MySQL' || $server_type == 'Percona Server') - && $serverVersion >= 50706 - ) { - $password_column = 'authentication_string'; - } - // $sql_query is for the initial-filtered, - // $sql_query_all is for counting the total no. of users - - $sql_query = $sql_query_all = 'SELECT *,' . - " IF(`" . $password_column . "` = _latin1 '', 'N', 'Y') AS 'Password'" . - ' FROM `mysql`.`user`'; - - $sql_query .= (isset($_GET['initial']) - ? $this->rangeOfUsers($_GET['initial']) - : ''); - - $sql_query .= ' ORDER BY `User` ASC, `Host` ASC;'; - $sql_query_all .= ' ;'; - - $res = $this->dbi->tryQuery( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - $res_all = $this->dbi->tryQuery( - $sql_query_all, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - - if (! $res) { - // the query failed! This may have two reasons: - // - the user does not have enough privileges - // - the privilege tables use a structure of an earlier version. - // so let's try a more simple query - - $this->dbi->freeResult($res); - $this->dbi->freeResult($res_all); - $sql_query = 'SELECT * FROM `mysql`.`user`'; - $res = $this->dbi->tryQuery( - $sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - - if (! $res) { - $html_output .= $this->getHtmlForViewUsersError(); - $html_output .= $this->getAddUserHtmlFieldset(); - } else { - // This message is hardcoded because I will replace it by - // a automatic repair feature soon. - $raw = 'Your privilege table structure seems to be older than' - . ' this MySQL version!
    ' - . 'Please run the mysql_upgrade command' - . ' that should be included in your MySQL server distribution' - . ' to solve this problem!'; - $html_output .= Message::rawError($raw)->getDisplay(); - } - $this->dbi->freeResult($res); - } else { - $db_rights = $this->getDbRightsForUserOverview(); - // for all initials, even non A-Z - $array_initials = []; - - foreach ($db_rights as $right) { - foreach ($right as $account) { - if (empty($account['User']) && $account['Host'] == 'localhost') { - $html_output .= Message::notice( - __( - 'A user account allowing any user from localhost to ' - . 'connect is present. This will prevent other users ' - . 'from connecting if the host part of their account ' - . 'allows a connection from any (%) host.' - ) - . Util::showMySQLDocu('problems-connecting') - )->getDisplay(); - break 2; - } - } - } - - /** - * Displays the initials - * Also not necessary if there is less than 20 privileges - */ - if ($this->dbi->numRows($res_all) > 20) { - $html_output .= $this->getHtmlForInitials($array_initials); - } - - /** - * Display the user overview - * (if less than 50 users, display them immediately) - */ - if (isset($_GET['initial']) - || isset($_GET['showall']) - || $this->dbi->numRows($res) < 50 - ) { - $html_output .= $this->getUsersOverview( - $res, - $db_rights, - $pmaThemeImage, - $text_dir - ); - } else { - $html_output .= $this->getAddUserHtmlFieldset(); - } // end if (display overview) - - $response = Response::getInstance(); - if (! $response->isAjax() - || ! empty($_REQUEST['ajax_page_request']) - ) { - if ($GLOBALS['is_reload_priv']) { - $flushnote = new Message( - __( - 'Note: phpMyAdmin gets the users’ privileges directly ' - . 'from MySQL’s privilege tables. The content of these ' - . 'tables may differ from the privileges the server uses, ' - . 'if they have been changed manually. In this case, ' - . 'you should %sreload the privileges%s before you continue.' - ), - Message::NOTICE - ); - $flushnote->addParamHtml( - '' - ); - $flushnote->addParamHtml(''); - } else { - $flushnote = new Message( - __( - 'Note: phpMyAdmin gets the users’ privileges directly ' - . 'from MySQL’s privilege tables. The content of these ' - . 'tables may differ from the privileges the server uses, ' - . 'if they have been changed manually. In this case, ' - . 'the privileges have to be reloaded but currently, you ' - . 'don\'t have the RELOAD privilege.' - ) - . Util::showMySQLDocu( - 'privileges-provided', - false, - null, - null, - 'priv_reload' - ), - Message::NOTICE - ); - } - $html_output .= $flushnote->getDisplay(); - } - } - - return $html_output; - } - - /** - * Get HTML snippet for display user properties - * - * @param boolean $dbname_is_wildcard whether database name is wildcard or not - * @param string $url_dbname url database name that urlencode() string - * @param string $username username - * @param string $hostname host name - * @param string $dbname database name - * @param string $tablename table name - * - * @return string - */ - public function getHtmlForUserProperties( - $dbname_is_wildcard, - $url_dbname, - $username, - $hostname, - $dbname, - $tablename - ) { - $html_output = '
    '; - $html_output .= $this->getHtmlHeaderForUserProperties( - $dbname_is_wildcard, - $url_dbname, - $dbname, - $username, - $hostname, - $tablename, - 'table' - ); - - $sql = "SELECT '1' FROM `mysql`.`user`" - . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" - . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "';"; - - $user_does_not_exists = (bool) ! $this->dbi->fetchValue($sql); - - if ($user_does_not_exists) { - $html_output .= Message::error( - __('The selected user was not found in the privilege table.') - )->getDisplay(); - $html_output .= $this->getHtmlForLoginInformationFields(); - } - - $_params = [ - 'username' => $username, - 'hostname' => $hostname, - ]; - if (! is_array($dbname) && strlen($dbname) > 0) { - $_params['dbname'] = $dbname; - if (strlen($tablename) > 0) { - $_params['tablename'] = $tablename; - } - } else { - $_params['dbname'] = $dbname; - } - - $html_output .= '' . "\n"; - - if (! is_array($dbname) && strlen($tablename) === 0 - && empty($dbname_is_wildcard) - ) { - // no table name was given, display all table specific rights - // but only if $dbname contains no wildcards - if (strlen($dbname) === 0) { - $html_output .= $this->getHtmlForAllTableSpecificRights( - $username, - $hostname, - 'database' - ); - } else { - // unescape wildcards in dbname at table level - $unescaped_db = Util::unescapeMysqlWildcards($dbname); - - $html_output .= $this->getHtmlForAllTableSpecificRights( - $username, - $hostname, - 'table', - $unescaped_db - ); - $html_output .= $this->getHtmlForAllTableSpecificRights( - $username, - $hostname, - 'routine', - $unescaped_db - ); - } - } - - // Provide a line with links to the relevant database and table - if (! is_array($dbname) && strlen($dbname) > 0 && empty($dbname_is_wildcard)) { - $html_output .= $this->getLinkToDbAndTable($url_dbname, $dbname, $tablename); - } - - if (! is_array($dbname) && strlen($dbname) === 0 && ! $user_does_not_exists) { - //change login information - $html_output .= ChangePassword::getHtml( - 'edit_other', - $username, - $hostname - ); - $html_output .= $this->getChangeLoginInformationHtmlForm($username, $hostname); - } - $html_output .= '
    '; - - return $html_output; - } - - /** - * Get queries for Table privileges to change or copy user - * - * @param string $user_host_condition user host condition to - * select relevant table privileges - * @param array $queries queries array - * @param string $username username - * @param string $hostname host name - * - * @return array - */ - public function getTablePrivsQueriesForChangeOrCopyUser( - $user_host_condition, - array $queries, - $username, - $hostname - ) { - $res = $this->dbi->query( - 'SELECT `Db`, `Table_name`, `Table_priv` FROM `mysql`.`tables_priv`' - . $user_host_condition, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - while ($row = $this->dbi->fetchAssoc($res)) { - $res2 = $this->dbi->query( - 'SELECT `Column_name`, `Column_priv`' - . ' FROM `mysql`.`columns_priv`' - . ' WHERE `User`' - . ' = \'' . $this->dbi->escapeString($_POST['old_username']) . "'" - . ' AND `Host`' - . ' = \'' . $this->dbi->escapeString($_POST['old_username']) . '\'' - . ' AND `Db`' - . ' = \'' . $this->dbi->escapeString($row['Db']) . "'" - . ' AND `Table_name`' - . ' = \'' . $this->dbi->escapeString($row['Table_name']) . "'" - . ';', - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - - $tmp_privs1 = $this->extractPrivInfo($row); - $tmp_privs2 = [ - 'Select' => [], - 'Insert' => [], - 'Update' => [], - 'References' => [], - ]; - - while ($row2 = $this->dbi->fetchAssoc($res2)) { - $tmp_array = explode(',', $row2['Column_priv']); - if (in_array('Select', $tmp_array)) { - $tmp_privs2['Select'][] = $row2['Column_name']; - } - if (in_array('Insert', $tmp_array)) { - $tmp_privs2['Insert'][] = $row2['Column_name']; - } - if (in_array('Update', $tmp_array)) { - $tmp_privs2['Update'][] = $row2['Column_name']; - } - if (in_array('References', $tmp_array)) { - $tmp_privs2['References'][] = $row2['Column_name']; - } - } - if (count($tmp_privs2['Select']) > 0 && ! in_array('SELECT', $tmp_privs1)) { - $tmp_privs1[] = 'SELECT (`' . implode('`, `', $tmp_privs2['Select']) . '`)'; - } - if (count($tmp_privs2['Insert']) > 0 && ! in_array('INSERT', $tmp_privs1)) { - $tmp_privs1[] = 'INSERT (`' . implode('`, `', $tmp_privs2['Insert']) . '`)'; - } - if (count($tmp_privs2['Update']) > 0 && ! in_array('UPDATE', $tmp_privs1)) { - $tmp_privs1[] = 'UPDATE (`' . implode('`, `', $tmp_privs2['Update']) . '`)'; - } - if (count($tmp_privs2['References']) > 0 - && ! in_array('REFERENCES', $tmp_privs1) - ) { - $tmp_privs1[] - = 'REFERENCES (`' . implode('`, `', $tmp_privs2['References']) . '`)'; - } - - $queries[] = 'GRANT ' . implode(', ', $tmp_privs1) - . ' ON ' . Util::backquote($row['Db']) . '.' - . Util::backquote($row['Table_name']) - . ' TO \'' . $this->dbi->escapeString($username) - . '\'@\'' . $this->dbi->escapeString($hostname) . '\'' - . (in_array('Grant', explode(',', $row['Table_priv'])) - ? ' WITH GRANT OPTION;' - : ';'); - } - return $queries; - } - - /** - * Get queries for database specific privileges for change or copy user - * - * @param array $queries queries array with string - * @param string $username username - * @param string $hostname host name - * - * @return array - */ - public function getDbSpecificPrivsQueriesForChangeOrCopyUser( - array $queries, - $username, - $hostname - ) { - $user_host_condition = ' WHERE `User`' - . ' = \'' . $this->dbi->escapeString($_POST['old_username']) . "'" - . ' AND `Host`' - . ' = \'' . $this->dbi->escapeString($_POST['old_hostname']) . '\';'; - - $res = $this->dbi->query( - 'SELECT * FROM `mysql`.`db`' . $user_host_condition - ); - - while ($row = $this->dbi->fetchAssoc($res)) { - $queries[] = 'GRANT ' . implode(', ', $this->extractPrivInfo($row)) - . ' ON ' . Util::backquote($row['Db']) . '.*' - . ' TO \'' . $this->dbi->escapeString($username) - . '\'@\'' . $this->dbi->escapeString($hostname) . '\'' - . ($row['Grant_priv'] == 'Y' ? ' WITH GRANT OPTION;' : ';'); - } - $this->dbi->freeResult($res); - - $queries = $this->getTablePrivsQueriesForChangeOrCopyUser( - $user_host_condition, - $queries, - $username, - $hostname - ); - - return $queries; - } - - /** - * Prepares queries for adding users and - * also create database and return query and message - * - * @param boolean $_error whether user create or not - * @param string $real_sql_query SQL query for add a user - * @param string $sql_query SQL query to be displayed - * @param string $username username - * @param string $hostname host name - * @param string $dbname database name - * @param string $alter_real_sql_query SQL query for ALTER USER - * @param string $alter_sql_query SQL query for ALTER USER to be displayed - * - * @return array, $message - */ - public function addUserAndCreateDatabase( - $_error, - $real_sql_query, - $sql_query, - $username, - $hostname, - $dbname, - $alter_real_sql_query, - $alter_sql_query - ) { - if ($_error || (! empty($real_sql_query) - && ! $this->dbi->tryQuery($real_sql_query)) - ) { - $_POST['createdb-1'] = $_POST['createdb-2'] - = $_POST['createdb-3'] = null; - $message = Message::rawError($this->dbi->getError()); - } elseif ($alter_real_sql_query !== '' && ! $this->dbi->tryQuery($alter_real_sql_query)) { - $_POST['createdb-1'] = $_POST['createdb-2'] - = $_POST['createdb-3'] = null; - $message = Message::rawError($this->dbi->getError()); - } else { - $sql_query .= $alter_sql_query; - $message = Message::success(__('You have added a new user.')); - } - - if (isset($_POST['createdb-1'])) { - // Create database with same name and grant all privileges - $q = 'CREATE DATABASE IF NOT EXISTS ' - . Util::backquote( - $this->dbi->escapeString($username) - ) . ';'; - $sql_query .= $q; - if (! $this->dbi->tryQuery($q)) { - $message = Message::rawError($this->dbi->getError()); - } - - /** - * Reload the navigation - */ - $GLOBALS['reload'] = true; - $GLOBALS['db'] = $username; - - $q = 'GRANT ALL PRIVILEGES ON ' - . Util::backquote( - Util::escapeMysqlWildcards( - $this->dbi->escapeString($username) - ) - ) . '.* TO \'' - . $this->dbi->escapeString($username) - . '\'@\'' . $this->dbi->escapeString($hostname) . '\';'; - $sql_query .= $q; - if (! $this->dbi->tryQuery($q)) { - $message = Message::rawError($this->dbi->getError()); - } - } - - if (isset($_POST['createdb-2'])) { - // Grant all privileges on wildcard name (username\_%) - $q = 'GRANT ALL PRIVILEGES ON ' - . Util::backquote( - Util::escapeMysqlWildcards( - $this->dbi->escapeString($username) - ) . '\_%' - ) . '.* TO \'' - . $this->dbi->escapeString($username) - . '\'@\'' . $this->dbi->escapeString($hostname) . '\';'; - $sql_query .= $q; - if (! $this->dbi->tryQuery($q)) { - $message = Message::rawError($this->dbi->getError()); - } - } - - if (isset($_POST['createdb-3'])) { - // Grant all privileges on the specified database to the new user - $q = 'GRANT ALL PRIVILEGES ON ' - . Util::backquote( - $this->dbi->escapeString($dbname) - ) . '.* TO \'' - . $this->dbi->escapeString($username) - . '\'@\'' . $this->dbi->escapeString($hostname) . '\';'; - $sql_query .= $q; - if (! $this->dbi->tryQuery($q)) { - $message = Message::rawError($this->dbi->getError()); - } - } - return [ - $sql_query, - $message, - ]; - } - - /** - * Get the hashed string for password - * - * @param string $password password - * - * @return string - */ - public function getHashedPassword($password) - { - $password = $this->dbi->escapeString($password); - $result = $this->dbi->fetchSingleRow( - "SELECT PASSWORD('" . $password . "') AS `password`;" - ); - - return $result['password']; - } - - /** - * Check if MariaDB's 'simple_password_check' - * OR 'cracklib_password_check' is ACTIVE - * - * @return boolean if atleast one of the plugins is ACTIVE - */ - public function checkIfMariaDBPwdCheckPluginActive() - { - $serverVersion = $this->dbi->getVersion(); - if (! (Util::getServerType() == 'MariaDB' && $serverVersion >= 100002)) { - return false; - } - - $result = $this->dbi->tryQuery( - 'SHOW PLUGINS SONAME LIKE \'%_password_check%\'' - ); - - /* Plugins are not working, for example directory does not exists */ - if ($result === false) { - return false; - } - - while ($row = $this->dbi->fetchAssoc($result)) { - if ($row['Status'] === 'ACTIVE') { - return true; - } - } - - return false; - } - - - /** - * Get SQL queries for Display and Add user - * - * @param string $username username - * @param string $hostname host name - * @param string $password password - * - * @return array ($create_user_real, $create_user_show, $real_sql_query, $sql_query - * $password_set_real, $password_set_show, $alter_real_sql_query, $alter_sql_query) - */ - public function getSqlQueriesForDisplayAndAddUser($username, $hostname, $password) - { - $slashedUsername = $this->dbi->escapeString($username); - $slashedHostname = $this->dbi->escapeString($hostname); - $slashedPassword = $this->dbi->escapeString($password); - $serverType = Util::getServerType(); - $serverVersion = $this->dbi->getVersion(); - - $create_user_stmt = sprintf( - 'CREATE USER \'%s\'@\'%s\'', - $slashedUsername, - $slashedHostname - ); - $isMariaDBPwdPluginActive = $this->checkIfMariaDBPwdCheckPluginActive(); - - // See https://github.com/phpmyadmin/phpmyadmin/pull/11560#issuecomment-147158219 - // for details regarding details of syntax usage for various versions - - // 'IDENTIFIED WITH auth_plugin' - // is supported by MySQL 5.5.7+ - if (($serverType == 'MySQL' || $serverType == 'Percona Server') - && $serverVersion >= 50507 - && isset($_POST['authentication_plugin']) - ) { - $create_user_stmt .= ' IDENTIFIED WITH ' - . $_POST['authentication_plugin']; - } - - // 'IDENTIFIED VIA auth_plugin' - // is supported by MariaDB 5.2+ - if ($serverType == 'MariaDB' - && $serverVersion >= 50200 - && isset($_POST['authentication_plugin']) - && ! $isMariaDBPwdPluginActive - ) { - $create_user_stmt .= ' IDENTIFIED VIA ' - . $_POST['authentication_plugin']; - } - - $create_user_real = $create_user_stmt; - $create_user_show = $create_user_stmt; - - $password_set_stmt = 'SET PASSWORD FOR \'%s\'@\'%s\' = \'%s\''; - $password_set_show = sprintf( - $password_set_stmt, - $slashedUsername, - $slashedHostname, - '***' - ); - - $sql_query_stmt = sprintf( - 'GRANT %s ON *.* TO \'%s\'@\'%s\'', - implode(', ', $this->extractPrivInfo()), - $slashedUsername, - $slashedHostname - ); - $real_sql_query = $sql_query = $sql_query_stmt; - - // Set the proper hashing method - if (isset($_POST['authentication_plugin'])) { - $this->setProperPasswordHashing( - $_POST['authentication_plugin'] - ); - } - - // Use 'CREATE USER ... WITH ... AS ..' syntax for - // newer MySQL versions - // and 'CREATE USER ... VIA .. USING ..' syntax for - // newer MariaDB versions - if ((($serverType == 'MySQL' || $serverType == 'Percona Server') - && $serverVersion >= 50706) - || ($serverType == 'MariaDB' - && $serverVersion >= 50200) - ) { - $password_set_real = null; - - // Required for binding '%' with '%s' - $create_user_stmt = str_replace( - '%', - '%%', - $create_user_stmt - ); - - // MariaDB uses 'USING' whereas MySQL uses 'AS' - // but MariaDB with validation plugin needs cleartext password - if ($serverType == 'MariaDB' - && ! $isMariaDBPwdPluginActive - ) { - $create_user_stmt .= ' USING \'%s\''; - } elseif ($serverType == 'MariaDB') { - $create_user_stmt .= ' IDENTIFIED BY \'%s\''; - } elseif (($serverType == 'MySQL' || $serverType == 'Percona Server') && $serverVersion >= 80011) { - $create_user_stmt .= ' BY \'%s\''; - } else { - $create_user_stmt .= ' AS \'%s\''; - } - - if ($_POST['pred_password'] == 'keep') { - $create_user_real = sprintf( - $create_user_stmt, - $slashedPassword - ); - $create_user_show = sprintf( - $create_user_stmt, - '***' - ); - } elseif ($_POST['pred_password'] == 'none') { - $create_user_real = sprintf( - $create_user_stmt, - null - ); - $create_user_show = sprintf( - $create_user_stmt, - '***' - ); - } else { - if (! (($serverType == 'MariaDB' && $isMariaDBPwdPluginActive) - || ($serverType == 'MySQL' || $serverType == 'Percona Server') && $serverVersion >= 80011)) { - $hashedPassword = $this->getHashedPassword($_POST['pma_pw']); - } else { - // MariaDB with validation plugin needs cleartext password - $hashedPassword = $_POST['pma_pw']; - } - $create_user_real = sprintf( - $create_user_stmt, - $hashedPassword - ); - $create_user_show = sprintf( - $create_user_stmt, - '***' - ); - } - } else { - // Use 'SET PASSWORD' syntax for pre-5.7.6 MySQL versions - // and pre-5.2.0 MariaDB versions - if ($_POST['pred_password'] == 'keep') { - $password_set_real = sprintf( - $password_set_stmt, - $slashedUsername, - $slashedHostname, - $slashedPassword - ); - } elseif ($_POST['pred_password'] == 'none') { - $password_set_real = sprintf( - $password_set_stmt, - $slashedUsername, - $slashedHostname, - null - ); - } else { - $hashedPassword = $this->getHashedPassword($_POST['pma_pw']); - $password_set_real = sprintf( - $password_set_stmt, - $slashedUsername, - $slashedHostname, - $hashedPassword - ); - } - } - - $alter_real_sql_query = ''; - $alter_sql_query = ''; - if (($serverType == 'MySQL' || $serverType == 'Percona Server') && $serverVersion >= 80011) { - $sql_query_stmt = ''; - if ((isset($_POST['Grant_priv']) && $_POST['Grant_priv'] == 'Y') - || (isset($GLOBALS['Grant_priv']) && $GLOBALS['Grant_priv'] == 'Y') - ) { - $sql_query_stmt = ' WITH GRANT OPTION'; - } - $real_sql_query .= $sql_query_stmt; - $sql_query .= $sql_query_stmt; - - $alter_sql_query_stmt = sprintf( - 'ALTER USER \'%s\'@\'%s\'', - $slashedUsername, - $slashedHostname - ); - $alter_real_sql_query = $alter_sql_query_stmt; - $alter_sql_query = $alter_sql_query_stmt; - } - - // add REQUIRE clause - $require_clause = $this->getRequireClause(); - $with_clause = $this->getWithClauseForAddUserAndUpdatePrivs(); - - if (($serverType == 'MySQL' || $serverType == 'Percona Server') && $serverVersion >= 80011) { - $alter_real_sql_query .= $require_clause; - $alter_sql_query .= $require_clause; - $alter_real_sql_query .= $with_clause; - $alter_sql_query .= $with_clause; - } else { - $real_sql_query .= $require_clause; - $sql_query .= $require_clause; - $real_sql_query .= $with_clause; - $sql_query .= $with_clause; - } - - if ($alter_real_sql_query !== '') { - $alter_real_sql_query .= ';'; - $alter_sql_query .= ';'; - } - $create_user_real .= ';'; - $create_user_show .= ';'; - $real_sql_query .= ';'; - $sql_query .= ';'; - // No Global GRANT_OPTION privilege - if (! $GLOBALS['is_grantuser']) { - $real_sql_query = ''; - $sql_query = ''; - } - - // Use 'SET PASSWORD' for pre-5.7.6 MySQL versions - // and pre-5.2.0 MariaDB - if (($serverType == 'MySQL' - && $serverVersion >= 50706) - || ($serverType == 'MariaDB' - && $serverVersion >= 50200) - ) { - $password_set_real = null; - $password_set_show = null; - } else { - if ($password_set_real !== null) { - $password_set_real .= ";"; - } - $password_set_show .= ";"; - } - - return [ - $create_user_real, - $create_user_show, - $real_sql_query, - $sql_query, - $password_set_real, - $password_set_show, - $alter_real_sql_query, - $alter_sql_query, - ]; - } - - /** - * Returns the type ('PROCEDURE' or 'FUNCTION') of the routine - * - * @param string $dbname database - * @param string $routineName routine - * - * @return string type - */ - public function getRoutineType($dbname, $routineName) - { - $routineData = $this->dbi->getRoutines($dbname); - - foreach ($routineData as $routine) { - if ($routine['name'] === $routineName) { - return $routine['type']; - } - } - return ''; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Server/Select.php b/srcs/phpmyadmin/libraries/classes/Server/Select.php deleted file mode 100644 index bfc1f19..0000000 --- a/srcs/phpmyadmin/libraries/classes/Server/Select.php +++ /dev/null @@ -1,128 +0,0 @@ -'; - - if (! $omit_fieldset) { - $retval .= '
    '; - } - - $retval .= Url::getHiddenFields([]); - $retval .= ' '; - - $retval .= ''; - if (! $omit_fieldset) { - $retval .= '
    '; - } - $retval .= ''; - } elseif ($list) { - $retval .= ''; - } - - return $retval; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Server/Status/Data.php b/srcs/phpmyadmin/libraries/classes/Server/Status/Data.php deleted file mode 100644 index 7d352f7..0000000 --- a/srcs/phpmyadmin/libraries/classes/Server/Status/Data.php +++ /dev/null @@ -1,430 +0,0 @@ - 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', - ]; - } - - /** - * Gets the sections for constructor - * - * @return array - */ - private function _getSections() - { - return [ - // 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'), - ]; - } - - /** - * Gets the links for constructor - * - * @return array - */ - private function _getLinks() - { - $links = []; - // variable or section name => (name => url) - - $links['table'][__('Flush (close) all tables')] = [ - 'url' => $this->selfUrl, - 'params' => Url::getCommon(['flush' => 'TABLES'], ''), - ]; - $links['table'][__('Show open tables')] = [ - 'url' => 'sql.php', - 'params' => Url::getCommon([ - 'sql_query' => 'SHOW OPEN TABLES', - 'goto' => $this->selfUrl, - ], ''), - ]; - - if ($GLOBALS['replication_info']['master']['status']) { - $links['repl'][__('Show slave hosts')] = [ - 'url' => 'sql.php', - 'params' => Url::getCommon([ - 'sql_query' => 'SHOW SLAVE HOSTS', - 'goto' => $this->selfUrl, - ], ''), - ]; - $links['repl'][__('Show master status')] = [ - 'url' => '#replication_master', - 'params' => '', - ]; - } - if ($GLOBALS['replication_info']['slave']['status']) { - $links['repl'][__('Show slave status')] = [ - 'url' => '#replication_slave', - 'params' => '', - ]; - } - - $links['repl']['doc'] = 'replication'; - - $links['qcache'][__('Flush query cache')] = [ - 'url' => $this->selfUrl, - 'params' => Url::getCommon(['flush' => 'QUERY CACHE'], ''), - ]; - $links['qcache']['doc'] = 'query_cache'; - - $links['threads']['doc'] = 'mysql_threads'; - - $links['key']['doc'] = 'myisam_key_cache'; - - $links['binlog_cache']['doc'] = 'binary_log'; - - $links['Slow_queries']['doc'] = 'slow_query_log'; - - $links['innodb'][__('Variables')] = [ - 'url' => 'server_engines.php', - 'params' => Url::getCommon(['engine' => 'InnoDB'], ''), - ]; - $links['innodb'][__('InnoDB Status')] = [ - 'url' => 'server_engines.php', - 'params' => Url::getCommon([ - 'engine' => 'InnoDB', - 'page' => 'Status', - ], ''), - ]; - $links['innodb']['doc'] = 'innodb'; - - return $links; - } - - /** - * Calculate some values - * - * @param array $server_status contains results of SHOW GLOBAL STATUS - * @param array $server_variables contains results of SHOW GLOBAL VARIABLES - * - * @return array - */ - private function _calculateValues(array $server_status, array $server_variables) - { - // Key_buffer_fraction - if (isset($server_status['Key_blocks_unused']) - && isset($server_variables['key_cache_block_size']) - && isset($server_variables['key_buffer_size']) - && $server_variables['key_buffer_size'] != 0 - ) { - $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_variables['key_buffer_size'] != 0 - ) { - $server_status['Key_buffer_fraction_%'] - = $server_status['Key_blocks_used'] - * 1024 - / $server_variables['key_buffer_size']; - } - - // Ratio for key read/write - if (isset($server_status['Key_writes']) - && isset($server_status['Key_write_requests']) - && $server_status['Key_write_requests'] > 0 - ) { - $key_writes = $server_status['Key_writes']; - $key_write_requests = $server_status['Key_write_requests']; - $server_status['Key_write_ratio_%'] - = 100 * $key_writes / $key_write_requests; - } - - if (isset($server_status['Key_reads']) - && isset($server_status['Key_read_requests']) - && $server_status['Key_read_requests'] > 0 - ) { - $key_reads = $server_status['Key_reads']; - $key_read_requests = $server_status['Key_read_requests']; - $server_status['Key_read_ratio_%'] - = 100 * $key_reads / $key_read_requests; - } - - // Threads_cache_hitrate - if (isset($server_status['Threads_created']) - && isset($server_status['Connections']) - && $server_status['Connections'] > 0 - ) { - $server_status['Threads_cache_hitrate_%'] - = 100 - $server_status['Threads_created'] - / $server_status['Connections'] * 100; - } - return $server_status; - } - - /** - * Sort variables into arrays - * - * @param array $server_status contains results of SHOW GLOBAL STATUS - * @param array $allocations allocations for sections - * @param array $allocationMap map variables to their section - * @param array $sectionUsed is a section used? - * @param array $used_queries used queries - * - * @return array ($allocationMap, $sectionUsed, $used_queries) - */ - private function _sortVariables( - array $server_status, - array $allocations, - array $allocationMap, - array $sectionUsed, - array $used_queries - ) { - foreach ($server_status as $name => $value) { - $section_found = false; - foreach ($allocations as $filter => $section) { - if (mb_strpos($name, $filter) !== false) { - $allocationMap[$name] = $section; - $sectionUsed[$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'; - $sectionUsed['other'] = true; - } - } - return [ - $allocationMap, - $sectionUsed, - $used_queries, - ]; - } - - /** - * Constructor - */ - public function __construct() - { - $this->selfUrl = basename($GLOBALS['PMA_PHP_SELF']); - - // get status from server - $server_status_result = $GLOBALS['dbi']->tryQuery('SHOW GLOBAL STATUS'); - $server_status = []; - if ($server_status_result === false) { - $this->dataLoaded = false; - } else { - $this->dataLoaded = true; - while ($arr = $GLOBALS['dbi']->fetchRow($server_status_result)) { - $server_status[$arr[0]] = $arr[1]; - } - $GLOBALS['dbi']->freeResult($server_status_result); - } - - // for some calculations we require also some server settings - $server_variables = $GLOBALS['dbi']->fetchResult( - 'SHOW GLOBAL VARIABLES', - 0, - 1 - ); - - // cleanup of some deprecated values - $server_status = self::cleanDeprecated($server_status); - - // calculate some values - $server_status = $this->_calculateValues( - $server_status, - $server_variables - ); - - // split variables in sections - $allocations = $this->_getAllocations(); - - $sections = $this->_getSections(); - - // define some needful links/commands - $links = $this->_getLinks(); - - // Variable to contain all com_ variables (query statistics) - $used_queries = []; - - // Variable to map variable names to their respective section name - // (used for js category filtering) - $allocationMap = []; - - // Variable to mark used sections - $sectionUsed = []; - - // sort vars into arrays - list( - $allocationMap, $sectionUsed, $used_queries - ) = $this->_sortVariables( - $server_status, - $allocations, - $allocationMap, - $sectionUsed, - $used_queries - ); - - // 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; - $serverHostToLower = mb_strtolower( - $GLOBALS['cfg']['Server']['host'] - ); - if ($serverHostToLower === '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->sectionUsed = $sectionUsed; - } - - /** - * cleanup of some deprecated values - * - * @param array $server_status status array to process - * - * @return array - */ - public static function cleanDeprecated(array $server_status) - { - $deprecated = [ - '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; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Server/Status/Monitor.php b/srcs/phpmyadmin/libraries/classes/Server/Status/Monitor.php deleted file mode 100644 index efa9e40..0000000 --- a/srcs/phpmyadmin/libraries/classes/Server/Status/Monitor.php +++ /dev/null @@ -1,546 +0,0 @@ -dbi = $dbi; - } - - /** - * Returns JSON for real-time charting data - * - * @param string $requiredData Required data - * - * @return array JSON - */ - public function getJsonForChartingData(string $requiredData): array - { - $ret = json_decode($requiredData, true); - $statusVars = []; - $serverVars = []; - $sysinfo = $cpuload = $memory = 0; - - /* Accumulate all required variables and data */ - list($serverVars, $statusVars, $ret) = $this->getJsonForChartingDataGet( - $ret, - $serverVars, - $statusVars, - $sysinfo, - $cpuload, - $memory - ); - - // Retrieve all required status variables - $statusVarValues = []; - if (count($statusVars)) { - $statusVarValues = $this->dbi->fetchResult( - "SHOW GLOBAL STATUS WHERE Variable_name='" - . implode("' OR Variable_name='", $statusVars) . "'", - 0, - 1 - ); - } - - // Retrieve all required server variables - $serverVarValues = []; - if (count($serverVars)) { - $serverVarValues = $this->dbi->fetchResult( - "SHOW GLOBAL VARIABLES WHERE Variable_name='" - . implode("' OR Variable_name='", $serverVars) . "'", - 0, - 1 - ); - } - - // ...and now assign them - $ret = $this->getJsonForChartingDataSet($ret, $statusVarValues, $serverVarValues); - - $ret['x'] = microtime(true) * 1000; - return $ret; - } - - /** - * Assign the variables for real-time charting data - * - * @param array $ret Real-time charting data - * @param array $statusVarValues Status variable values - * @param array $serverVarValues Server variable values - * - * @return array - */ - private function getJsonForChartingDataSet( - array $ret, - array $statusVarValues, - array $serverVarValues - ): array { - foreach ($ret as $chart_id => $chartNodes) { - foreach ($chartNodes as $node_id => $nodeDataPoints) { - foreach ($nodeDataPoints as $point_id => $dataPoint) { - switch ($dataPoint['type']) { - case 'statusvar': - $ret[$chart_id][$node_id][$point_id]['value'] - = $statusVarValues[$dataPoint['name']]; - break; - case 'servervar': - $ret[$chart_id][$node_id][$point_id]['value'] - = $serverVarValues[$dataPoint['name']]; - break; - } - } - } - } - return $ret; - } - - /** - * Get called to get JSON for charting data - * - * @param array $ret Real-time charting data - * @param array $serverVars Server variable values - * @param array $statusVars Status variable values - * @param mixed $sysinfo System info - * @param mixed $cpuload CPU load - * @param mixed $memory Memory - * - * @return array - */ - private function getJsonForChartingDataGet( - array $ret, - array $serverVars, - array $statusVars, - $sysinfo, - $cpuload, - $memory - ) { - // For each chart - foreach ($ret as $chartId => $chartNodes) { - // For each data series - foreach ($chartNodes as $nodeId => $nodeDataPoints) { - // For each data point in the series (usually just 1) - foreach ($nodeDataPoints as $pointId => $dataPoint) { - list($serverVars, $statusVars, $ret[$chartId][$nodeId][$pointId]) - = $this->getJsonForChartingDataSwitch( - $dataPoint['type'], - $dataPoint['name'], - $serverVars, - $statusVars, - $ret[$chartId][$nodeId][$pointId], - $sysinfo, - $cpuload, - $memory - ); - } /* foreach */ - } /* foreach */ - } - return [ - $serverVars, - $statusVars, - $ret, - ]; - } - - /** - * Switch called to get JSON for charting data - * - * @param string $type Type - * @param string $pName Name - * @param array $serverVars Server variable values - * @param array $statusVars Status variable values - * @param array $ret Real-time charting data - * @param mixed $sysinfo System info - * @param mixed $cpuload CPU load - * @param mixed $memory Memory - * - * @return array - */ - private function getJsonForChartingDataSwitch( - $type, - $pName, - array $serverVars, - array $statusVars, - array $ret, - $sysinfo, - $cpuload, - $memory - ) { - switch ($type) { - /* We only collect the status and server variables here to - * read them all in one query, - * and only afterwards assign them. - * Also do some white list filtering on the names - */ - case 'servervar': - if (! preg_match('/[^a-zA-Z_]+/', $pName)) { - $serverVars[] = $pName; - } - break; - - case 'statusvar': - if (! preg_match('/[^a-zA-Z_]+/', $pName)) { - $statusVars[] = $pName; - } - break; - - case 'proc': - $result = $this->dbi->query('SHOW PROCESSLIST'); - $ret['value'] = $this->dbi->numRows($result); - break; - - case 'cpu': - if (! $sysinfo) { - $sysinfo = SysInfo::get(); - } - if (! $cpuload) { - $cpuload = $sysinfo->loadavg(); - } - - if (SysInfo::getOs() == 'Linux') { - $ret['idle'] = $cpuload['idle']; - $ret['busy'] = $cpuload['busy']; - } else { - $ret['value'] = $cpuload['loadavg']; - } - - break; - - case 'memory': - if (! $sysinfo) { - $sysinfo = SysInfo::get(); - } - if (! $memory) { - $memory = $sysinfo->memory(); - } - - $ret['value'] = isset($memory[$pName]) ? $memory[$pName] : 0; - break; - } - - return [ - $serverVars, - $statusVars, - $ret, - ]; - } - - /** - * Returns JSON for log data with type: slow - * - * @param int $start Unix Time: Start time for query - * @param int $end Unix Time: End time for query - * - * @return array - */ - public function getJsonForLogDataTypeSlow(int $start, int $end): array - { - $query = 'SELECT start_time, user_host, '; - $query .= 'Sec_to_Time(Sum(Time_to_Sec(query_time))) as query_time, '; - $query .= 'Sec_to_Time(Sum(Time_to_Sec(lock_time))) as lock_time, '; - $query .= 'SUM(rows_sent) AS rows_sent, '; - $query .= 'SUM(rows_examined) AS rows_examined, db, sql_text, '; - $query .= 'COUNT(sql_text) AS \'#\' '; - $query .= 'FROM `mysql`.`slow_log` '; - $query .= 'WHERE start_time > FROM_UNIXTIME(' . $start . ') '; - $query .= 'AND start_time < FROM_UNIXTIME(' . $end . ') GROUP BY sql_text'; - - $result = $this->dbi->tryQuery($query); - - $return = [ - 'rows' => [], - 'sum' => [], - ]; - - while ($row = $this->dbi->fetchAssoc($result)) { - $type = mb_strtolower( - mb_substr( - $row['sql_text'], - 0, - mb_strpos($row['sql_text'], ' ') - ) - ); - - switch ($type) { - case 'insert': - case 'update': - //Cut off big inserts and updates, but append byte count instead - if (mb_strlen($row['sql_text']) > 220) { - $implodeSqlText = implode( - ' ', - Util::formatByteDown( - mb_strlen($row['sql_text']), - 2, - 2 - ) - ); - $row['sql_text'] = mb_substr($row['sql_text'], 0, 200) - . '... [' . $implodeSqlText . ']'; - } - break; - default: - break; - } - - if (! isset($return['sum'][$type])) { - $return['sum'][$type] = 0; - } - $return['sum'][$type] += $row['#']; - $return['rows'][] = $row; - } - - $return['sum']['TOTAL'] = array_sum($return['sum']); - $return['numRows'] = count($return['rows']); - - $this->dbi->freeResult($result); - return $return; - } - - /** - * Returns JSon for log data with type: general - * - * @param int $start Unix Time: Start time for query - * @param int $end Unix Time: End time for query - * @param bool $isTypesLimited Whether to limit types or not - * @param bool $removeVariables Whether to remove variables or not - * - * @return array - */ - public function getJsonForLogDataTypeGeneral( - int $start, - int $end, - bool $isTypesLimited, - bool $removeVariables - ): array { - $limitTypes = ''; - if ($isTypesLimited) { - $limitTypes = 'AND argument REGEXP \'^(INSERT|SELECT|UPDATE|DELETE)\' '; - } - - $query = 'SELECT TIME(event_time) as event_time, user_host, thread_id, '; - $query .= 'server_id, argument, count(argument) as \'#\' '; - $query .= 'FROM `mysql`.`general_log` '; - $query .= 'WHERE command_type=\'Query\' '; - $query .= 'AND event_time > FROM_UNIXTIME(' . $start . ') '; - $query .= 'AND event_time < FROM_UNIXTIME(' . $end . ') '; - $query .= $limitTypes . 'GROUP by argument'; // HAVING count > 1'; - - $result = $this->dbi->tryQuery($query); - - $return = [ - 'rows' => [], - 'sum' => [], - ]; - $insertTables = []; - $insertTablesFirst = -1; - $i = 0; - - while ($row = $this->dbi->fetchAssoc($result)) { - preg_match('/^(\w+)\s/', $row['argument'], $match); - $type = mb_strtolower($match[1]); - - if (! isset($return['sum'][$type])) { - $return['sum'][$type] = 0; - } - $return['sum'][$type] += $row['#']; - - switch ($type) { - /** @noinspection PhpMissingBreakStatementInspection */ - case 'insert': - // Group inserts if selected - if ($removeVariables - && preg_match( - '/^INSERT INTO (`|\'|"|)([^\s\\1]+)\\1/i', - $row['argument'], - $matches - ) - ) { - $insertTables[$matches[2]]++; - if ($insertTables[$matches[2]] > 1) { - $return['rows'][$insertTablesFirst]['#'] - = $insertTables[$matches[2]]; - - // Add a ... to the end of this query to indicate that - // there's been other queries - $temp = $return['rows'][$insertTablesFirst]['argument']; - $return['rows'][$insertTablesFirst]['argument'] - .= $this->getSuspensionPoints( - $temp[strlen($temp) - 1] - ); - - // Group this value, thus do not add to the result list - continue 2; - } else { - $insertTablesFirst = $i; - $insertTables[$matches[2]] += $row['#'] - 1; - } - } - // No break here - - case 'update': - // Cut off big inserts and updates, - // but append byte count therefor - if (mb_strlen($row['argument']) > 220) { - $row['argument'] = mb_substr($row['argument'], 0, 200) - . '... [' - . implode( - ' ', - Util::formatByteDown( - mb_strlen($row['argument']), - 2, - 2 - ) - ) - . ']'; - } - break; - - default: - break; - } - - $return['rows'][] = $row; - $i++; - } - - $return['sum']['TOTAL'] = array_sum($return['sum']); - $return['numRows'] = count($return['rows']); - - $this->dbi->freeResult($result); - - return $return; - } - - /** - * Return suspension points if needed - * - * @param string $lastChar Last char - * - * @return string Return suspension points if needed - */ - private function getSuspensionPoints(string $lastChar): string - { - if ($lastChar != '.') { - return '
    ...'; - } - - return ''; - } - - /** - * Returns JSON for logging vars - * - * @param string|null $name Variable name - * @param string|null $value Variable value - * - * @return array JSON - */ - public function getJsonForLoggingVars(?string $name, ?string $value): array - { - if (isset($name) && isset($value)) { - $escapedValue = $this->dbi->escapeString($value); - if (! is_numeric($escapedValue)) { - $escapedValue = "'" . $escapedValue . "'"; - } - - if (! preg_match("/[^a-zA-Z0-9_]+/", $name)) { - $this->dbi->query( - 'SET GLOBAL ' . $name . ' = ' . $escapedValue - ); - } - } - - $loggingVars = $this->dbi->fetchResult( - 'SHOW GLOBAL VARIABLES WHERE Variable_name IN' - . ' ("general_log","slow_query_log","long_query_time","log_output")', - 0, - 1 - ); - return $loggingVars; - } - - /** - * Returns JSON for query_analyzer - * - * @param string $database Database name - * @param string $query SQL query - * - * @return array JSON - */ - public function getJsonForQueryAnalyzer( - string $database, - string $query - ): array { - global $cached_affected_rows; - - $return = []; - - if (strlen($database) > 0) { - $this->dbi->selectDb($database); - } - - if ($profiling = Util::profilingSupported()) { - $this->dbi->query('SET PROFILING=1;'); - } - - // Do not cache query - $sqlQuery = preg_replace( - '/^(\s*SELECT)/i', - '\\1 SQL_NO_CACHE', - $query - ); - - $this->dbi->tryQuery($sqlQuery); - $return['affectedRows'] = $cached_affected_rows; - - $result = $this->dbi->tryQuery('EXPLAIN ' . $sqlQuery); - while ($row = $this->dbi->fetchAssoc($result)) { - $return['explain'][] = $row; - } - - // In case an error happened - $return['error'] = $this->dbi->getError(); - - $this->dbi->freeResult($result); - - if ($profiling) { - $return['profiling'] = []; - $result = $this->dbi->tryQuery( - 'SELECT seq,state,duration FROM INFORMATION_SCHEMA.PROFILING' - . ' WHERE QUERY_ID=1 ORDER BY seq' - ); - while ($row = $this->dbi->fetchAssoc($result)) { - $return['profiling'][] = $row; - } - $this->dbi->freeResult($result); - } - return $return; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Server/UserGroups.php b/srcs/phpmyadmin/libraries/classes/Server/UserGroups.php deleted file mode 100644 index 89bc1a3..0000000 --- a/srcs/phpmyadmin/libraries/classes/Server/UserGroups.php +++ /dev/null @@ -1,390 +0,0 @@ -' - . sprintf(__('Users of \'%s\' user group'), htmlspecialchars($userGroup)) - . ''; - - $cfgRelation = $relation->getRelationsParam(); - $usersTable = Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['users']); - $sql_query = "SELECT `username` FROM " . $usersTable - . " WHERE `usergroup`='" . $GLOBALS['dbi']->escapeString($userGroup) - . "'"; - $result = $relation->queryAsControlUser($sql_query, false); - if ($result) { - if ($GLOBALS['dbi']->numRows($result) == 0) { - $html_output .= '

    ' - . __('No users were found belonging to this user group.') - . '

    '; - } else { - $html_output .= '' - . '' - . ''; - $i = 0; - while ($row = $GLOBALS['dbi']->fetchRow($result)) { - $i++; - $html_output .= '' - . '' - . '' - . ''; - } - $html_output .= '' - . '
    #' . __('User') . '
    ' . $i . ' ' . htmlspecialchars($row[0]) . '
    '; - } - } - $GLOBALS['dbi']->freeResult($result); - return $html_output; - } - - /** - * Returns HTML for the 'user groups' table - * - * @return string HTML for the 'user groups' table - */ - public static function getHtmlForUserGroupsTable() - { - $relation = new Relation($GLOBALS['dbi']); - $html_output = '

    ' . __('User groups') . '

    '; - $cfgRelation = $relation->getRelationsParam(); - $groupTable = Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['usergroups']); - $sql_query = "SELECT * FROM " . $groupTable . " ORDER BY `usergroup` ASC"; - $result = $relation->queryAsControlUser($sql_query, false); - - if ($result && $GLOBALS['dbi']->numRows($result)) { - $html_output .= '
    '; - $html_output .= Url::getHiddenInputs(); - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - - $userGroups = []; - while ($row = $GLOBALS['dbi']->fetchAssoc($result)) { - $groupName = $row['usergroup']; - if (! isset($userGroups[$groupName])) { - $userGroups[$groupName] = []; - } - $userGroups[$groupName][$row['tab']] = $row['allowed']; - } - foreach ($userGroups as $groupName => $tabs) { - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - $html_output .= ''; - - $html_output .= ''; - - $html_output .= ''; - } - - $html_output .= ''; - $html_output .= '
    ' - . __('User group') . '' . __('Server level tabs') . '' . __('Database level tabs') . '' . __('Table level tabs') . '' . __('Action') . '
    ' . htmlspecialchars($groupName) . '' . self::getAllowedTabNames($tabs, 'server') . '' . self::getAllowedTabNames($tabs, 'db') . '' . self::getAllowedTabNames($tabs, 'table') . ''; - $html_output .= '' - . Util::getIcon('b_usrlist', __('View users')) - . ''; - $html_output .= '  '; - $html_output .= '' - . Util::getIcon('b_edit', __('Edit')) . ''; - $html_output .= '  '; - $html_output .= '' - . Util::getIcon('b_drop', __('Delete')) . ''; - $html_output .= '
    '; - $html_output .= '
    '; - } - $GLOBALS['dbi']->freeResult($result); - - $html_output .= '
    '; - $html_output .= '' - . Util::getIcon('b_usradd') - . __('Add user group') . ''; - $html_output .= '
    '; - - return $html_output; - } - - /** - * Returns the list of allowed menu tab names - * based on a data row from usergroup table. - * - * @param array $row row of usergroup table - * @param string $level 'server', 'db' or 'table' - * - * @return string comma separated list of allowed menu tab names - */ - public static function getAllowedTabNames(array $row, $level) - { - $tabNames = []; - $tabs = Util::getMenuTabList($level); - foreach ($tabs as $tab => $tabName) { - if (! isset($row[$level . '_' . $tab]) - || $row[$level . '_' . $tab] == 'Y' - ) { - $tabNames[] = $tabName; - } - } - return implode(', ', $tabNames); - } - - /** - * Deletes a user group - * - * @param string $userGroup user group name - * - * @return void - */ - public static function delete($userGroup) - { - $relation = new Relation($GLOBALS['dbi']); - $cfgRelation = $relation->getRelationsParam(); - $userTable = Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['users']); - $groupTable = Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['usergroups']); - $sql_query = "DELETE FROM " . $userTable - . " WHERE `usergroup`='" . $GLOBALS['dbi']->escapeString($userGroup) - . "'"; - $relation->queryAsControlUser($sql_query, true); - $sql_query = "DELETE FROM " . $groupTable - . " WHERE `usergroup`='" . $GLOBALS['dbi']->escapeString($userGroup) - . "'"; - $relation->queryAsControlUser($sql_query, true); - } - - /** - * Returns HTML for add/edit user group dialog - * - * @param string $userGroup name of the user group in case of editing - * - * @return string HTML for add/edit user group dialog - */ - public static function getHtmlToEditUserGroup($userGroup = null) - { - $relation = new Relation($GLOBALS['dbi']); - $html_output = ''; - if ($userGroup == null) { - $html_output .= '

    ' . __('Add user group') . '

    '; - } else { - $html_output .= '

    ' - . sprintf(__('Edit user group: \'%s\''), htmlspecialchars($userGroup)) - . '

    '; - } - - $html_output .= '
    '; - $urlParams = []; - if ($userGroup != null) { - $urlParams['userGroup'] = $userGroup; - $urlParams['editUserGroupSubmit'] = '1'; - } else { - $urlParams['addUserGroupSubmit'] = '1'; - } - $html_output .= Url::getHiddenInputs($urlParams); - - $html_output .= '
    '; - $html_output .= '' . __('User group menu assignments') - . '   ' - . '' - . '' - . ''; - - if ($userGroup == null) { - $html_output .= ''; - $html_output .= ''; - $html_output .= '
    '; - } - - $allowedTabs = [ - 'server' => [], - 'db' => [], - 'table' => [], - ]; - if ($userGroup != null) { - $cfgRelation = $relation->getRelationsParam(); - $groupTable = Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['usergroups']); - $sql_query = "SELECT * FROM " . $groupTable - . " WHERE `usergroup`='" . $GLOBALS['dbi']->escapeString($userGroup) - . "'"; - $result = $relation->queryAsControlUser($sql_query, false); - if ($result) { - while ($row = $GLOBALS['dbi']->fetchAssoc($result)) { - $key = $row['tab']; - $value = $row['allowed']; - if (substr($key, 0, 7) == 'server_' && $value == 'Y') { - $allowedTabs['server'][] = mb_substr($key, 7); - } elseif (substr($key, 0, 3) == 'db_' && $value == 'Y') { - $allowedTabs['db'][] = mb_substr($key, 3); - } elseif (substr($key, 0, 6) == 'table_' - && $value == 'Y' - ) { - $allowedTabs['table'][] = mb_substr($key, 6); - } - } - } - $GLOBALS['dbi']->freeResult($result); - } - - $html_output .= self::getTabList( - __('Server-level tabs'), - 'server', - $allowedTabs['server'] - ); - $html_output .= self::getTabList( - __('Database-level tabs'), - 'db', - $allowedTabs['db'] - ); - $html_output .= self::getTabList( - __('Table-level tabs'), - 'table', - $allowedTabs['table'] - ); - - $html_output .= '
    '; - - $html_output .= ''; - - return $html_output; - } - - /** - * Returns HTML for checkbox groups to choose - * tabs of 'server', 'db' or 'table' levels. - * - * @param string $title title of the checkbox group - * @param string $level 'server', 'db' or 'table' - * @param array $selected array of selected allowed tabs - * - * @return string HTML for checkbox groups - */ - public static function getTabList($title, $level, array $selected) - { - $tabs = Util::getMenuTabList($level); - $html_output = '
    '; - $html_output .= '' . $title . ''; - foreach ($tabs as $tab => $tabName) { - $html_output .= '
    '; - $html_output .= ''; - $html_output .= ''; - $html_output .= '
    '; - } - $html_output .= '
    '; - return $html_output; - } - - /** - * Add/update a user group with allowed menu tabs. - * - * @param string $userGroup user group name - * @param boolean $new whether this is a new user group - * - * @return void - */ - public static function edit($userGroup, $new = false) - { - $relation = new Relation($GLOBALS['dbi']); - $tabs = Util::getMenuTabList(); - $cfgRelation = $relation->getRelationsParam(); - $groupTable = Util::backquote($cfgRelation['db']) - . "." . Util::backquote($cfgRelation['usergroups']); - - if (! $new) { - $sql_query = "DELETE FROM " . $groupTable - . " WHERE `usergroup`='" . $GLOBALS['dbi']->escapeString($userGroup) - . "';"; - $relation->queryAsControlUser($sql_query, true); - } - - $sql_query = "INSERT INTO " . $groupTable - . "(`usergroup`, `tab`, `allowed`)" - . " VALUES "; - $first = true; - foreach ($tabs as $tabGroupName => $tabGroup) { - foreach ($tabGroup as $tab => $tabName) { - if (! $first) { - $sql_query .= ", "; - } - $tabName = $tabGroupName . '_' . $tab; - $allowed = isset($_POST[$tabName]) && $_POST[$tabName] == 'Y'; - $sql_query .= "('" . $GLOBALS['dbi']->escapeString($userGroup) . "', '" . $tabName . "', '" - . ($allowed ? "Y" : "N") . "')"; - $first = false; - } - } - $sql_query .= ";"; - $relation->queryAsControlUser($sql_query, true); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Server/Users.php b/srcs/phpmyadmin/libraries/classes/Server/Users.php deleted file mode 100644 index a497241..0000000 --- a/srcs/phpmyadmin/libraries/classes/Server/Users.php +++ /dev/null @@ -1,64 +0,0 @@ - __('User accounts overview'), - 'url' => 'server_privileges.php', - 'params' => Url::getCommon(['viewing_mode' => 'server']), - ], - ]; - - if ($GLOBALS['dbi']->isSuperuser()) { - $items[] = [ - 'name' => __('User groups'), - 'url' => 'server_user_groups.php', - 'params' => Url::getCommon(), - ]; - } - - $retval = '
      '; - foreach ($items as $item) { - $class = ''; - if ($item['url'] === $selfUrl) { - $class = ' class="tabactive"'; - } - $retval .= '
    • '; - $retval .= ''; - $retval .= $item['name']; - $retval .= ''; - $retval .= '
    • '; - } - $retval .= '
    '; - $retval .= '
    '; - - return $retval; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Session.php b/srcs/phpmyadmin/libraries/classes/Session.php deleted file mode 100644 index 0d43a48..0000000 --- a/srcs/phpmyadmin/libraries/classes/Session.php +++ /dev/null @@ -1,234 +0,0 @@ -getMessage()) - ); - } - - /* - * Session initialization is done before selecting language, so we - * can not use translations here. - */ - Core::fatalError( - 'Error during session start; please check your PHP and/or ' - . 'webserver log file and configure your PHP ' - . 'installation properly. Also ensure that cookies are enabled ' - . 'in your browser.' - . '

    ' - . implode('

    ', $messages) - ); - } - - /** - * Set up session - * - * @param Config $config Configuration handler - * @param ErrorHandler $errorHandler Error handler - * @return void - */ - public static function setUp(Config $config, ErrorHandler $errorHandler) - { - // verify if PHP supports session, die if it does not - if (! function_exists('session_name')) { - Core::warnMissingExtension('session', true); - } elseif (! empty(ini_get('session.auto_start')) - && session_name() != 'phpMyAdmin' - && ! empty(session_id())) { - // Do not delete the existing non empty session, it might be used by - // other applications; instead just close it. - if (empty($_SESSION)) { - // Ignore errors as this might have been destroyed in other - // request meanwhile - @session_destroy(); - } elseif (function_exists('session_abort')) { - // PHP 5.6 and newer - session_abort(); - } else { - session_write_close(); - } - } - - // session cookie settings - session_set_cookie_params( - 0, - $config->getRootPath(), - '', - $config->isHttps(), - true - ); - - // cookies are safer (use ini_set() in case this function is disabled) - ini_set('session.use_cookies', 'true'); - - // optionally set session_save_path - $path = $config->get('SessionSavePath'); - if (! empty($path)) { - session_save_path($path); - // We can not do this unconditionally as this would break - // any more complex setup (eg. cluster), see - // https://github.com/phpmyadmin/phpmyadmin/issues/8346 - ini_set('session.save_handler', 'files'); - } - - // use cookies only - ini_set('session.use_only_cookies', '1'); - // strict session mode (do not accept random string as session ID) - ini_set('session.use_strict_mode', '1'); - // make the session cookie HttpOnly - ini_set('session.cookie_httponly', '1'); - // do not force transparent session ids - ini_set('session.use_trans_sid', '0'); - - // delete session/cookies when browser is closed - ini_set('session.cookie_lifetime', '0'); - - // some pages (e.g. stylesheet) may be cached on clients, but not in shared - // proxy servers - session_cache_limiter('private'); - - $httpCookieName = $config->getCookieName('phpMyAdmin'); - @session_name($httpCookieName); - - // Restore correct sesion ID (it might have been reset by auto started session - if ($config->issetCookie('phpMyAdmin')) { - session_id($config->getCookie('phpMyAdmin')); - } - - // on first start of session we check for errors - // f.e. session dir cannot be accessed - session file not created - $orig_error_count = $errorHandler->countErrors(false); - - $session_result = session_start(); - - if ($session_result !== true - || $orig_error_count != $errorHandler->countErrors(false) - ) { - setcookie($httpCookieName, '', 1); - $errors = $errorHandler->sliceErrors($orig_error_count); - self::sessionFailed($errors); - } - unset($orig_error_count, $session_result); - - /** - * Disable setting of session cookies for further session_start() calls. - */ - if (session_status() !== PHP_SESSION_ACTIVE) { - ini_set('session.use_cookies', 'true'); - } - - /** - * Token which is used for authenticating access queries. - * (we use "space PMA_token space" to prevent overwriting) - */ - if (empty($_SESSION[' PMA_token '])) { - self::generateToken(); - - /** - * Check for disk space on session storage by trying to write it. - * - * This seems to be most reliable approach to test if sessions are working, - * otherwise the check would fail with custom session backends. - */ - $orig_error_count = $errorHandler->countErrors(); - session_write_close(); - if ($errorHandler->countErrors() > $orig_error_count) { - $errors = $errorHandler->sliceErrors($orig_error_count); - self::sessionFailed($errors); - } - session_start(); - if (empty($_SESSION[' PMA_token '])) { - Core::fatalError( - 'Failed to store CSRF token in session! ' . - 'Probably sessions are not working properly.' - ); - } - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Setup/ConfigGenerator.php b/srcs/phpmyadmin/libraries/classes/Setup/ConfigGenerator.php deleted file mode 100644 index 8ba09ab..0000000 --- a/srcs/phpmyadmin/libraries/classes/Setup/ConfigGenerator.php +++ /dev/null @@ -1,184 +0,0 @@ -getConfig(); - - // header - $ret = 'get('PMA_VERSION') - . ' setup script' . $crlf - . ' * Date: ' . gmdate(DATE_RFC1123) . $crlf - . ' */' . $crlf . $crlf; - - //servers - if (! empty($conf['Servers'])) { - $ret .= self::getServerPart($cf, $crlf, $conf['Servers']); - unset($conf['Servers']); - } - - // other settings - $persistKeys = $cf->getPersistKeysMap(); - - foreach ($conf as $k => $v) { - $k = preg_replace('/[^A-Za-z0-9_]/', '_', $k); - $ret .= self::_getVarExport($k, $v, $crlf); - if (isset($persistKeys[$k])) { - unset($persistKeys[$k]); - } - } - // keep 1d array keys which are present in $persist_keys (config.values.php) - foreach (array_keys($persistKeys) as $k) { - if (mb_strpos($k, '/') === false) { - $k = preg_replace('/[^A-Za-z0-9_]/', '_', $k); - $ret .= self::_getVarExport($k, $cf->getDefault($k), $crlf); - } - } - $ret .= '?' . '>'; - - return $ret; - } - - /** - * Returns exported configuration variable - * - * @param string $var_name configuration name - * @param mixed $var_value configuration value(s) - * @param string $crlf line ending - * - * @return string - */ - private static function _getVarExport($var_name, $var_value, $crlf) - { - if (! is_array($var_value) || empty($var_value)) { - return "\$cfg['$var_name'] = " - . var_export($var_value, true) . ';' . $crlf; - } - $ret = ''; - if (self::_isZeroBasedArray($var_value)) { - $ret = "\$cfg['$var_name'] = " - . self::_exportZeroBasedArray($var_value, $crlf) - . ';' . $crlf; - } else { - // string keys: $cfg[key][subkey] = value - foreach ($var_value as $k => $v) { - $k = preg_replace('/[^A-Za-z0-9_]/', '_', $k); - $ret .= "\$cfg['$var_name']['$k'] = " - . var_export($v, true) . ';' . $crlf; - } - } - return $ret; - } - - /** - * Check whether $array is a continuous 0-based array - * - * @param array $array Array to check - * - * @return boolean - */ - private static function _isZeroBasedArray(array $array) - { - for ($i = 0, $nb = count($array); $i < $nb; $i++) { - if (! isset($array[$i])) { - return false; - } - } - return true; - } - - /** - * Exports continuous 0-based array - * - * @param array $array Array to export - * @param string $crlf Newline string - * - * @return string - */ - private static function _exportZeroBasedArray(array $array, $crlf) - { - $retv = []; - foreach ($array as $v) { - $retv[] = var_export($v, true); - } - $ret = "array("; - if (count($retv) <= 4) { - // up to 4 values - one line - $ret .= implode(', ', $retv); - } else { - // more than 4 values - value per line - $imax = count($retv); - for ($i = 0; $i < $imax; $i++) { - $ret .= ($i > 0 ? ',' : '') . $crlf . ' ' . $retv[$i]; - } - } - $ret .= ')'; - return $ret; - } - - /** - * Generate server part of config file - * - * @param ConfigFile $cf Config file - * @param string $crlf Carriage return char - * @param array $servers Servers list - * - * @return string|null - */ - protected static function getServerPart(ConfigFile $cf, $crlf, array $servers) - { - if ($cf->getServerCount() === 0) { - return null; - } - - $ret = "/* Servers configuration */$crlf\$i = 0;" . $crlf . $crlf; - foreach ($servers as $id => $server) { - $ret .= '/* Server: ' - . strtr($cf->getServerName($id) . " [$id] ", '*/', '-') - . "*/" . $crlf - . '$i++;' . $crlf; - foreach ($server as $k => $v) { - $k = preg_replace('/[^A-Za-z0-9_]/', '_', $k); - $ret .= "\$cfg['Servers'][\$i]['$k'] = " - . (is_array($v) && self::_isZeroBasedArray($v) - ? self::_exportZeroBasedArray($v, $crlf) - : var_export($v, true)) - . ';' . $crlf; - } - $ret .= $crlf; - } - $ret .= '/* End of servers configuration */' . $crlf . $crlf; - return $ret; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Setup/FormProcessing.php b/srcs/phpmyadmin/libraries/classes/Setup/FormProcessing.php deleted file mode 100644 index dce9ecc..0000000 --- a/srcs/phpmyadmin/libraries/classes/Setup/FormProcessing.php +++ /dev/null @@ -1,77 +0,0 @@ -fixErrors(); - $response = Response::getInstance(); - $response->disable(); - $response->generateHeader303('index.php' . Url::getCommonRaw()); - } - - if (! $form_display->process(false)) { - // handle form view and failed POST - echo $form_display->getDisplay(true, true); - return; - } - - // check for form errors - if (! $form_display->hasErrors()) { - $response = Response::getInstance(); - $response->disable(); - $response->generateHeader303('index.php' . Url::getCommonRaw()); - return; - } - - // form has errors, show warning - $page = isset($_GET['page']) ? $_GET['page'] : ''; - $formset = isset($_GET['formset']) ? $_GET['formset'] : ''; - $formId = Core::isValid($_GET['id'], 'numeric') ? $_GET['id'] : ''; - if ($formId === null && $page == 'servers') { - // we've just added a new server, get its id - $formId = $form_display->getConfigFile()->getServerCount(); - } - - $urlParams = [ - 'page' => $page, - 'formset' => $formset, - 'id' => $formId, - ]; - - $template = new Template(); - echo $template->render('setup/error', [ - 'url_params' => $urlParams, - 'errors' => $form_display->displayErrors(), - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Setup/Index.php b/srcs/phpmyadmin/libraries/classes/Setup/Index.php deleted file mode 100644 index 9518221..0000000 --- a/srcs/phpmyadmin/libraries/classes/Setup/Index.php +++ /dev/null @@ -1,198 +0,0 @@ - [], - 'notice' => [], - ]; - } else { - // reset message states - foreach ($_SESSION['messages'] as &$messages) { - foreach ($messages as &$msg) { - $msg['fresh'] = false; - $msg['active'] = false; - } - } - } - } - - /** - * Adds a new message to message list - * - * @param string $type one of: notice, error - * @param string $msgId unique message identifier - * @param string $title language string id (in $str array) - * @param string $message message text - * - * @return void - */ - public static function messagesSet($type, $msgId, $title, $message) - { - $fresh = ! isset($_SESSION['messages'][$type][$msgId]); - $_SESSION['messages'][$type][$msgId] = [ - 'fresh' => $fresh, - 'active' => true, - 'title' => $title, - 'message' => $message, - ]; - } - - /** - * Cleans up message list - * - * @return void - */ - public static function messagesEnd() - { - foreach ($_SESSION['messages'] as &$messages) { - $remove_ids = []; - foreach ($messages as $id => &$msg) { - if ($msg['active'] == false) { - $remove_ids[] = $id; - } - } - foreach ($remove_ids as $id) { - unset($messages[$id]); - } - } - } - - /** - * Prints message list, must be called after self::messagesEnd() - * - * @return array - */ - public static function messagesShowHtml() - { - $return = []; - foreach ($_SESSION['messages'] as $type => $messages) { - foreach ($messages as $id => $msg) { - $return[] = [ - 'id' => $id, - 'title' => $msg['title'], - 'type' => $type, - 'message' => $msg['message'], - 'is_hidden' => ! $msg['fresh'] && $type !== 'error', - ]; - } - } - return $return; - } - - /** - * Checks for newest phpMyAdmin version and sets result as a new notice - * - * @return void - */ - public static function versionCheck() - { - // version check messages should always be visible so let's make - // a unique message id each time we run it - $message_id = uniqid('version_check'); - - // Fetch data - $versionInformation = new VersionInformation(); - $version_data = $versionInformation->getLatestVersion(); - - if (empty($version_data)) { - self::messagesSet( - 'error', - $message_id, - __('Version check'), - __( - 'Reading of version failed. ' - . 'Maybe you\'re offline or the upgrade server does not respond.' - ) - ); - return; - } - - $releases = $version_data->releases; - $latestCompatible = $versionInformation->getLatestCompatibleVersion($releases); - if ($latestCompatible != null) { - $version = $latestCompatible['version']; - $date = $latestCompatible['date']; - } else { - return; - } - - $version_upstream = $versionInformation->versionToInt($version); - if ($version_upstream === false) { - self::messagesSet( - 'error', - $message_id, - __('Version check'), - __('Got invalid version string from server') - ); - return; - } - - $version_local = $versionInformation->versionToInt( - $GLOBALS['PMA_Config']->get('PMA_VERSION') - ); - if ($version_local === false) { - self::messagesSet( - 'error', - $message_id, - __('Version check'), - __('Unparsable version string') - ); - return; - } - - if ($version_upstream > $version_local) { - $version = htmlspecialchars($version); - $date = htmlspecialchars($date); - self::messagesSet( - 'notice', - $message_id, - __('Version check'), - sprintf(__('A newer version of phpMyAdmin is available and you should consider upgrading. The newest version is %s, released on %s.'), $version, $date) - ); - } else { - if ($version_local % 100 == 0) { - self::messagesSet( - 'notice', - $message_id, - __('Version check'), - Sanitize::sanitizeMessage(sprintf(__('You are using Git version, run [kbd]git pull[/kbd] :-)[br]The latest stable version is %s, released on %s.'), $version, $date)) - ); - } else { - self::messagesSet( - 'notice', - $message_id, - __('Version check'), - __('No newer stable version is available') - ); - } - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Sql.php b/srcs/phpmyadmin/libraries/classes/Sql.php deleted file mode 100644 index fb4b07f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Sql.php +++ /dev/null @@ -1,2328 +0,0 @@ -relation = new Relation($GLOBALS['dbi']); - $this->relationCleanup = new RelationCleanup($GLOBALS['dbi'], $this->relation); - $this->operations = new Operations($GLOBALS['dbi'], $this->relation); - $this->transformations = new Transformations(); - $this->template = new Template(); - } - - /** - * Parses and analyzes the given SQL query. - * - * @param string $sql_query SQL query - * @param string $db DB name - * - * @return mixed - */ - public function parseAndAnalyze($sql_query, $db = null) - { - if ($db === null && isset($GLOBALS['db']) && strlen($GLOBALS['db'])) { - $db = $GLOBALS['db']; - } - list($analyzed_sql_results,,) = ParseAnalyze::sqlQuery($sql_query, $db); - return $analyzed_sql_results; - } - - /** - * Handle remembered sorting order, only for single table query - * - * @param string $db database name - * @param string $table table name - * @param array $analyzed_sql_results the analyzed query results - * @param string $full_sql_query SQL query - * - * @return void - */ - private function handleSortOrder( - $db, - $table, - array &$analyzed_sql_results, - &$full_sql_query - ) { - $pmatable = new Table($table, $db); - - if (empty($analyzed_sql_results['order'])) { - // Retrieving the name of the column we should sort after. - $sortCol = $pmatable->getUiProp(Table::PROP_SORTED_COLUMN); - if (empty($sortCol)) { - return; - } - - // Remove the name of the table from the retrieved field name. - $sortCol = str_replace( - Util::backquote($table) . '.', - '', - $sortCol - ); - - // Create the new query. - $full_sql_query = Query::replaceClause( - $analyzed_sql_results['statement'], - $analyzed_sql_results['parser']->list, - 'ORDER BY ' . $sortCol - ); - - // TODO: Avoid reparsing the query. - $analyzed_sql_results = Query::getAll($full_sql_query); - } else { - // Store the remembered table into session. - $pmatable->setUiProp( - Table::PROP_SORTED_COLUMN, - Query::getClause( - $analyzed_sql_results['statement'], - $analyzed_sql_results['parser']->list, - 'ORDER BY' - ) - ); - } - } - - /** - * Append limit clause to SQL query - * - * @param array $analyzed_sql_results the analyzed query results - * - * @return string limit clause appended SQL query - */ - private function getSqlWithLimitClause(array &$analyzed_sql_results) - { - return Query::replaceClause( - $analyzed_sql_results['statement'], - $analyzed_sql_results['parser']->list, - 'LIMIT ' . $_SESSION['tmpval']['pos'] . ', ' - . $_SESSION['tmpval']['max_rows'] - ); - } - - /** - * Verify whether the result set has columns from just one table - * - * @param array $fields_meta meta fields - * - * @return boolean whether the result set has columns from just one table - */ - private function resultSetHasJustOneTable(array $fields_meta) - { - $just_one_table = true; - $prev_table = ''; - foreach ($fields_meta as $one_field_meta) { - if ($one_field_meta->table != '' - && $prev_table != '' - && $one_field_meta->table != $prev_table - ) { - $just_one_table = false; - } - if ($one_field_meta->table != '') { - $prev_table = $one_field_meta->table; - } - } - return $just_one_table && $prev_table != ''; - } - - /** - * Verify whether the result set contains all the columns - * of at least one unique key - * - * @param string $db database name - * @param string $table table name - * @param array $fields_meta meta fields - * - * @return boolean whether the result set contains a unique key - */ - private function resultSetContainsUniqueKey($db, $table, array $fields_meta) - { - $columns = $GLOBALS['dbi']->getColumns($db, $table); - $resultSetColumnNames = []; - foreach ($fields_meta as $oneMeta) { - $resultSetColumnNames[] = $oneMeta->name; - } - foreach (Index::getFromTable($table, $db) as $index) { - if ($index->isUnique()) { - $indexColumns = $index->getColumns(); - $numberFound = 0; - foreach ($indexColumns as $indexColumnName => $dummy) { - if (in_array($indexColumnName, $resultSetColumnNames)) { - $numberFound++; - } elseif (! in_array($indexColumnName, $columns)) { - $numberFound++; - } elseif (strpos($columns[$indexColumnName]['Extra'], 'INVISIBLE') !== false) { - $numberFound++; - } - } - if ($numberFound == count($indexColumns)) { - return true; - } - } - } - return false; - } - - /** - * Get the HTML for relational column dropdown - * During grid edit, if we have a relational field, returns the html for the - * dropdown - * - * @param string $db current database - * @param string $table current table - * @param string $column current column - * @param string $curr_value current selected value - * - * @return string html for the dropdown - */ - private function getHtmlForRelationalColumnDropdown($db, $table, $column, $curr_value) - { - $foreigners = $this->relation->getForeigners($db, $table, $column); - - $foreignData = $this->relation->getForeignData( - $foreigners, - $column, - false, - '', - '' - ); - - if ($foreignData['disp_row'] == null) { - //Handle the case when number of values - //is more than $cfg['ForeignKeyMaxLimit'] - $_url_params = [ - 'db' => $db, - 'table' => $table, - 'field' => $column, - ]; - - $dropdown = $this->template->render('sql/relational_column_dropdown', [ - 'current_value' => $_POST['curr_value'], - 'params' => $_url_params, - ]); - } else { - $dropdown = $this->relation->foreignDropdown( - $foreignData['disp_row'], - $foreignData['foreign_field'], - $foreignData['foreign_display'], - $curr_value, - $GLOBALS['cfg']['ForeignKeyMaxLimit'] - ); - $dropdown = ''; - } - - return $dropdown; - } - - /** - * Get the HTML for the profiling table and accompanying chart if profiling is set. - * Otherwise returns null - * - * @param string|null $urlQuery url query - * @param string $database current database - * @param array $profilingResults array containing the profiling info - * - * @return string html for the profiling table and chart - */ - private function getHtmlForProfilingChart($urlQuery, $database, $profilingResults): string - { - if (! empty($profilingResults)) { - $urlQuery = isset($urlQuery) ? $urlQuery : Url::getCommon(['db' => $database]); - - list( - $detailedTable, - $chartJson, - $profilingStats - ) = $this->analyzeAndGetTableHtmlForProfilingResults($profilingResults); - - return $this->template->render('sql/profiling_chart', [ - 'url_query' => $urlQuery, - 'detailed_table' => $detailedTable, - 'states' => $profilingStats['states'], - 'total_time' => $profilingStats['total_time'], - 'chart_json' => $chartJson, - ]); - } - return ''; - } - - /** - * Function to get HTML for detailed profiling results table, profiling stats, and - * $chart_json for displaying the chart. - * - * @param array $profiling_results profiling results - * - * @return mixed - */ - private function analyzeAndGetTableHtmlForProfilingResults( - $profiling_results - ) { - $profiling_stats = [ - 'total_time' => 0, - 'states' => [], - ]; - $chart_json = []; - $i = 1; - $table = ''; - foreach ($profiling_results as $one_result) { - if (! isset($profiling_stats['states'][ucwords($one_result['Status'])])) { - $profiling_stats['states'][ucwords($one_result['Status'])] = [ - 'total_time' => $one_result['Duration'], - 'calls' => 1, - ]; - } - $profiling_stats['total_time'] += $one_result['Duration']; - - $table .= $this->template->render('sql/detailed_table', [ - 'index' => $i++, - 'status' => $one_result['Status'], - 'duration' => $one_result['Duration'], - ]); - - if (isset($chart_json[ucwords($one_result['Status'])])) { - $chart_json[ucwords($one_result['Status'])] - += $one_result['Duration']; - } else { - $chart_json[ucwords($one_result['Status'])] - = $one_result['Duration']; - } - } - return [ - $table, - $chart_json, - $profiling_stats, - ]; - } - - /** - * Get the HTML for the enum column dropdown - * During grid edit, if we have a enum field, returns the html for the - * dropdown - * - * @param string $db current database - * @param string $table current table - * @param string $column current column - * @param string $curr_value currently selected value - * - * @return string html for the dropdown - */ - private function getHtmlForEnumColumnDropdown($db, $table, $column, $curr_value) - { - $values = $this->getValuesForColumn($db, $table, $column); - return $this->template->render('sql/enum_column_dropdown', [ - 'values' => $values, - 'selected_values' => [$curr_value], - ]); - } - - /** - * Get value of a column for a specific row (marked by $where_clause) - * - * @param string $db current database - * @param string $table current table - * @param string $column current column - * @param string $where_clause where clause to select a particular row - * - * @return string with value - */ - private function getFullValuesForSetColumn($db, $table, $column, $where_clause) - { - $result = $GLOBALS['dbi']->fetchSingleRow( - "SELECT `$column` FROM `$db`.`$table` WHERE $where_clause" - ); - - return $result[$column]; - } - - /** - * Get the HTML for the set column dropdown - * During grid edit, if we have a set field, returns the html for the - * dropdown - * - * @param string $db current database - * @param string $table current table - * @param string $column current column - * @param string $curr_value currently selected value - * - * @return string html for the set column - */ - private function getHtmlForSetColumn($db, $table, $column, $curr_value): string - { - $values = $this->getValuesForColumn($db, $table, $column); - - $full_values = isset($_POST['get_full_values']) ? $_POST['get_full_values'] : false; - $where_clause = isset($_POST['where_clause']) ? $_POST['where_clause'] : null; - - // If the $curr_value was truncated, we should - // fetch the correct full values from the table - if ($full_values && ! empty($where_clause)) { - $curr_value = $this->getFullValuesForSetColumn( - $db, - $table, - $column, - $where_clause - ); - } - - //converts characters of $curr_value to HTML entities - $converted_curr_value = htmlentities( - $curr_value, - ENT_COMPAT, - "UTF-8" - ); - - $selected_values = explode(',', $converted_curr_value); - $select_size = (count($values) > 10) ? 10 : count($values); - - return $this->template->render('sql/set_column', [ - 'size' => $select_size, - 'values' => $values, - 'selected_values' => $selected_values, - ]); - } - - /** - * Get all the values for a enum column or set column in a table - * - * @param string $db current database - * @param string $table current table - * @param string $column current column - * - * @return array array containing the value list for the column - */ - private function getValuesForColumn($db, $table, $column) - { - $field_info_query = $GLOBALS['dbi']->getColumnsSql($db, $table, $column); - - $field_info_result = $GLOBALS['dbi']->fetchResult( - $field_info_query, - null, - null, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - - return Util::parseEnumSetValues($field_info_result[0]['Type']); - } - - /** - * Function to get html for bookmark support if bookmarks are enabled. Else will - * return null - * - * @param array $displayParts the parts to display - * @param array $cfgBookmark configuration setting for bookmarking - * @param string $sql_query sql query - * @param string $db current database - * @param string $table current table - * @param string|null $complete_query complete query - * @param string $bkm_user bookmarking user - * - * @return string - */ - public function getHtmlForBookmark( - array $displayParts, - array $cfgBookmark, - $sql_query, - $db, - $table, - ?string $complete_query, - $bkm_user - ): string { - if ($displayParts['bkm_form'] == '1' - && (! empty($cfgBookmark) && empty($_GET['id_bookmark'])) - && ! empty($sql_query) - ) { - return $this->template->render('sql/bookmark', [ - 'db' => $db, - 'goto' => 'sql.php' . Url::getCommon([ - 'db' => $db, - 'table' => $table, - 'sql_query' => $sql_query, - 'id_bookmark' => 1, - ]), - 'user' => $bkm_user, - 'sql_query' => isset($complete_query) ? $complete_query : $sql_query, - ]); - } - return ''; - } - - /** - * Function to check whether to remember the sorting order or not - * - * @param array $analyzed_sql_results the analyzed query and other variables set - * after analyzing the query - * - * @return boolean - */ - private function isRememberSortingOrder(array $analyzed_sql_results) - { - return $GLOBALS['cfg']['RememberSorting'] - && ! ($analyzed_sql_results['is_count'] - || $analyzed_sql_results['is_export'] - || $analyzed_sql_results['is_func'] - || $analyzed_sql_results['is_analyse']) - && $analyzed_sql_results['select_from'] - && isset($analyzed_sql_results['select_expr']) - && isset($analyzed_sql_results['select_tables']) - && (empty($analyzed_sql_results['select_expr']) - || ((count($analyzed_sql_results['select_expr']) === 1) - && ($analyzed_sql_results['select_expr'][0] == '*'))) - && count($analyzed_sql_results['select_tables']) === 1; - } - - /** - * Function to check whether the LIMIT clause should be appended or not - * - * @param array $analyzed_sql_results the analyzed query and other variables set - * after analyzing the query - * - * @return boolean - */ - private function isAppendLimitClause(array $analyzed_sql_results) - { - // Assigning LIMIT clause to an syntactically-wrong query - // is not needed. Also we would want to show the true query - // and the true error message to the query executor - - return (isset($analyzed_sql_results['parser']) - && count($analyzed_sql_results['parser']->errors) === 0) - && ($_SESSION['tmpval']['max_rows'] != 'all') - && ! ($analyzed_sql_results['is_export'] - || $analyzed_sql_results['is_analyse']) - && ($analyzed_sql_results['select_from'] - || $analyzed_sql_results['is_subquery']) - && empty($analyzed_sql_results['limit']); - } - - /** - * Function to check whether this query is for just browsing - * - * @param array $analyzed_sql_results the analyzed query and other variables set - * after analyzing the query - * @param boolean|null $find_real_end whether the real end should be found - * - * @return boolean - */ - public function isJustBrowsing(array $analyzed_sql_results, ?bool $find_real_end): bool - { - return ! $analyzed_sql_results['is_group'] - && ! $analyzed_sql_results['is_func'] - && empty($analyzed_sql_results['union']) - && empty($analyzed_sql_results['distinct']) - && $analyzed_sql_results['select_from'] - && (count($analyzed_sql_results['select_tables']) === 1) - && (empty($analyzed_sql_results['statement']->where) - || (count($analyzed_sql_results['statement']->where) === 1 - && $analyzed_sql_results['statement']->where[0]->expr === '1')) - && empty($analyzed_sql_results['group']) - && ! isset($find_real_end) - && ! $analyzed_sql_results['is_subquery'] - && ! $analyzed_sql_results['join'] - && empty($analyzed_sql_results['having']); - } - - /** - * Function to check whether the related transformation information should be deleted - * - * @param array $analyzed_sql_results the analyzed query and other variables set - * after analyzing the query - * - * @return boolean - */ - private function isDeleteTransformationInfo(array $analyzed_sql_results) - { - return ! empty($analyzed_sql_results['querytype']) - && (($analyzed_sql_results['querytype'] == 'ALTER') - || ($analyzed_sql_results['querytype'] == 'DROP')); - } - - /** - * Function to check whether the user has rights to drop the database - * - * @param array $analyzed_sql_results the analyzed query and other variables set - * after analyzing the query - * @param boolean $allowUserDropDatabase whether the user is allowed to drop db - * @param boolean $is_superuser whether this user is a superuser - * - * @return boolean - */ - public function hasNoRightsToDropDatabase( - array $analyzed_sql_results, - $allowUserDropDatabase, - $is_superuser - ) { - return ! $allowUserDropDatabase - && isset($analyzed_sql_results['drop_database']) - && $analyzed_sql_results['drop_database'] - && ! $is_superuser; - } - - /** - * Function to set a column property - * - * @param Table $pmatable Table instance - * @param string $request_index col_order|col_visib - * - * @return boolean - */ - private function setColumnProperty($pmatable, $request_index) - { - $property_value = array_map('intval', explode(',', $_POST[$request_index])); - switch ($request_index) { - case 'col_order': - $property_to_set = Table::PROP_COLUMN_ORDER; - break; - case 'col_visib': - $property_to_set = Table::PROP_COLUMN_VISIB; - break; - default: - $property_to_set = ''; - } - $retval = $pmatable->setUiProp( - $property_to_set, - $property_value, - isset($_POST['table_create_time']) ? $_POST['table_create_time'] : null - ); - if (gettype($retval) != 'boolean') { - $response = Response::getInstance(); - $response->setRequestStatus(false); - $response->addJSON('message', $retval->getString()); - exit; - } - - return $retval; - } - - /** - * Function to check the request for setting the column order or visibility - * - * @param string $table the current table - * @param string $db the current database - * - * @return void - */ - public function setColumnOrderOrVisibility($table, $db) - { - $pmatable = new Table($table, $db); - $retval = false; - - // set column order - if (isset($_POST['col_order'])) { - $retval = $this->setColumnProperty($pmatable, 'col_order'); - } - - // set column visibility - if ($retval === true && isset($_POST['col_visib'])) { - $retval = $this->setColumnProperty($pmatable, 'col_visib'); - } - - $response = Response::getInstance(); - $response->setRequestStatus($retval === true); - exit; - } - - /** - * Function to add a bookmark - * - * @param string $goto goto page URL - * - * @return void - */ - public function addBookmark($goto) - { - $bookmark = Bookmark::createBookmark( - $GLOBALS['dbi'], - $GLOBALS['cfg']['Server']['user'], - $_POST['bkm_fields'], - (isset($_POST['bkm_all_users']) - && $_POST['bkm_all_users'] == 'true' ? true : false - ) - ); - $result = $bookmark->save(); - $response = Response::getInstance(); - if ($response->isAjax()) { - if ($result) { - $msg = Message::success(__('Bookmark %s has been created.')); - $msg->addParam($_POST['bkm_fields']['bkm_label']); - $response->addJSON('message', $msg); - } else { - $msg = Message::error(__('Bookmark not created!')); - $response->setRequestStatus(false); - $response->addJSON('message', $msg); - } - exit; - } else { - // go back to sql.php to redisplay query; do not use & in this case: - /** - * @todo In which scenario does this happen? - */ - Core::sendHeaderLocation( - './' . $goto - . '&label=' . $_POST['bkm_fields']['bkm_label'] - ); - } - } - - /** - * Function to find the real end of rows - * - * @param string $db the current database - * @param string $table the current table - * - * @return mixed the number of rows if "retain" param is true, otherwise true - */ - public function findRealEndOfRows($db, $table) - { - $unlim_num_rows = $GLOBALS['dbi']->getTable($db, $table)->countRecords(true); - $_SESSION['tmpval']['pos'] = $this->getStartPosToDisplayRow($unlim_num_rows); - - return $unlim_num_rows; - } - - /** - * Function to get values for the relational columns - * - * @param string $db the current database - * @param string $table the current table - * - * @return void - */ - public function getRelationalValues($db, $table) - { - $column = $_POST['column']; - if ($_SESSION['tmpval']['relational_display'] == 'D' - && isset($_POST['relation_key_or_display_column']) - && $_POST['relation_key_or_display_column'] - ) { - $curr_value = $_POST['relation_key_or_display_column']; - } else { - $curr_value = $_POST['curr_value']; - } - $dropdown = $this->getHtmlForRelationalColumnDropdown( - $db, - $table, - $column, - $curr_value - ); - $response = Response::getInstance(); - $response->addJSON('dropdown', $dropdown); - exit; - } - - /** - * Function to get values for Enum or Set Columns - * - * @param string $db the current database - * @param string $table the current table - * @param string $columnType whether enum or set - * - * @return void - */ - public function getEnumOrSetValues($db, $table, $columnType) - { - $column = $_POST['column']; - $curr_value = $_POST['curr_value']; - $response = Response::getInstance(); - if ($columnType == "enum") { - $dropdown = $this->getHtmlForEnumColumnDropdown( - $db, - $table, - $column, - $curr_value - ); - $response->addJSON('dropdown', $dropdown); - } else { - $select = $this->getHtmlForSetColumn( - $db, - $table, - $column, - $curr_value - ); - $response->addJSON('select', $select); - } - exit; - } - - /** - * Function to get the default sql query for browsing page - * - * @param string $db the current database - * @param string $table the current table - * - * @return string the default $sql_query for browse page - */ - public function getDefaultSqlQueryForBrowse($db, $table) - { - $bookmark = Bookmark::get( - $GLOBALS['dbi'], - $GLOBALS['cfg']['Server']['user'], - $db, - $table, - 'label', - false, - true - ); - - if (! empty($bookmark) && ! empty($bookmark->getQuery())) { - $GLOBALS['using_bookmark_message'] = Message::notice( - __('Using bookmark "%s" as default browse query.') - ); - $GLOBALS['using_bookmark_message']->addParam($table); - $GLOBALS['using_bookmark_message']->addHtml( - Util::showDocu('faq', 'faq6-22') - ); - $sql_query = $bookmark->getQuery(); - } else { - $defaultOrderByClause = ''; - - if (isset($GLOBALS['cfg']['TablePrimaryKeyOrder']) - && ($GLOBALS['cfg']['TablePrimaryKeyOrder'] !== 'NONE') - ) { - $primaryKey = null; - $primary = Index::getPrimary($table, $db); - - if ($primary !== false) { - $primarycols = $primary->getColumns(); - - foreach ($primarycols as $col) { - $primaryKey = $col->getName(); - break; - } - - if ($primaryKey != null) { - $defaultOrderByClause = ' ORDER BY ' - . Util::backquote($table) . '.' - . Util::backquote($primaryKey) . ' ' - . $GLOBALS['cfg']['TablePrimaryKeyOrder']; - } - } - } - - $sql_query = 'SELECT * FROM ' . Util::backquote($table) - . $defaultOrderByClause; - } - - return $sql_query; - } - - /** - * Responds an error when an error happens when executing the query - * - * @param boolean $is_gotofile whether goto file or not - * @param string $error error after executing the query - * @param string $full_sql_query full sql query - * - * @return void - */ - private function handleQueryExecuteError($is_gotofile, $error, $full_sql_query) - { - if ($is_gotofile) { - $message = Message::rawError($error); - $response = Response::getInstance(); - $response->setRequestStatus(false); - $response->addJSON('message', $message); - } else { - Util::mysqlDie($error, $full_sql_query, '', ''); - } - exit; - } - - /** - * Function to store the query as a bookmark - * - * @param string $db the current database - * @param string $bkm_user the bookmarking user - * @param string $sql_query_for_bookmark the query to be stored in bookmark - * @param string $bkm_label bookmark label - * @param boolean|null $bkm_replace whether to replace existing bookmarks - * - * @return void - */ - public function storeTheQueryAsBookmark( - $db, - $bkm_user, - $sql_query_for_bookmark, - $bkm_label, - ?bool $bkm_replace - ) { - $bfields = [ - 'bkm_database' => $db, - 'bkm_user' => $bkm_user, - 'bkm_sql_query' => $sql_query_for_bookmark, - 'bkm_label' => $bkm_label, - ]; - - // Should we replace bookmark? - if (isset($bkm_replace)) { - $bookmarks = Bookmark::getList( - $GLOBALS['dbi'], - $GLOBALS['cfg']['Server']['user'], - $db - ); - foreach ($bookmarks as $bookmark) { - if ($bookmark->getLabel() == $bkm_label) { - $bookmark->delete(); - } - } - } - - $bookmark = Bookmark::createBookmark( - $GLOBALS['dbi'], - $GLOBALS['cfg']['Server']['user'], - $bfields, - isset($_POST['bkm_all_users']) - ); - $bookmark->save(); - } - - /** - * Executes the SQL query and measures its execution time - * - * @param string $full_sql_query the full sql query - * - * @return array ($result, $querytime) - */ - private function executeQueryAndMeasureTime($full_sql_query) - { - // close session in case the query takes too long - session_write_close(); - - // Measure query time. - $querytime_before = array_sum(explode(' ', microtime())); - - $result = @$GLOBALS['dbi']->tryQuery( - $full_sql_query, - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - $querytime_after = array_sum(explode(' ', microtime())); - - // reopen session - session_start(); - - return [ - $result, - $querytime_after - $querytime_before, - ]; - } - - /** - * Function to get the affected or changed number of rows after executing a query - * - * @param boolean $is_affected whether the query affected a table - * @param mixed $result results of executing the query - * - * @return int number of rows affected or changed - */ - private function getNumberOfRowsAffectedOrChanged($is_affected, $result) - { - if (! $is_affected) { - $num_rows = $result ? @$GLOBALS['dbi']->numRows($result) : 0; - } else { - $num_rows = @$GLOBALS['dbi']->affectedRows(); - } - - return $num_rows; - } - - /** - * Checks if the current database has changed - * This could happen if the user sends a query like "USE `database`;" - * - * @param string $db the database in the query - * - * @return bool whether to reload the navigation(1) or not(0) - */ - private function hasCurrentDbChanged($db): bool - { - if (strlen($db) > 0) { - $current_db = $GLOBALS['dbi']->fetchValue('SELECT DATABASE()'); - // $current_db is false, except when a USE statement was sent - return ($current_db != false) && ($db !== $current_db); - } - - return false; - } - - /** - * If a table, database or column gets dropped, clean comments. - * - * @param string $db current database - * @param string $table current table - * @param string|null $column current column - * @param bool $purge whether purge set or not - * - * @return void - */ - private function cleanupRelations($db, $table, ?string $column, $purge) - { - if (! empty($purge) && strlen($db) > 0) { - if (strlen($table) > 0) { - if (isset($column) && strlen($column) > 0) { - $this->relationCleanup->column($db, $table, $column); - } else { - $this->relationCleanup->table($db, $table); - } - } else { - $this->relationCleanup->database($db); - } - } - } - - /** - * Function to count the total number of rows for the same 'SELECT' query without - * the 'LIMIT' clause that may have been programatically added - * - * @param int $num_rows number of rows affected/changed by the query - * @param bool $justBrowsing whether just browsing or not - * @param string $db the current database - * @param string $table the current table - * @param array $analyzed_sql_results the analyzed query and other variables set - * after analyzing the query - * - * @return int unlimited number of rows - */ - private function countQueryResults( - $num_rows, - $justBrowsing, - $db, - $table, - array $analyzed_sql_results - ) { - - /* Shortcut for not analyzed/empty query */ - if (empty($analyzed_sql_results)) { - return 0; - } - - if (! $this->isAppendLimitClause($analyzed_sql_results)) { - // if we did not append a limit, set this to get a correct - // "Showing rows..." message - // $_SESSION['tmpval']['max_rows'] = 'all'; - $unlim_num_rows = $num_rows; - } elseif ($this->isAppendLimitClause($analyzed_sql_results) && $_SESSION['tmpval']['max_rows'] > $num_rows) { - // When user has not defined a limit in query and total rows in - // result are less than max_rows to display, there is no need - // to count total rows for that query again - $unlim_num_rows = $_SESSION['tmpval']['pos'] + $num_rows; - } elseif ($analyzed_sql_results['querytype'] == 'SELECT' - || $analyzed_sql_results['is_subquery'] - ) { - // c o u n t q u e r y - - // If we are "just browsing", there is only one table (and no join), - // and no WHERE clause (or just 'WHERE 1 '), - // we do a quick count (which uses MaxExactCount) because - // SQL_CALC_FOUND_ROWS is not quick on large InnoDB tables - - // However, do not count again if we did it previously - // due to $find_real_end == true - if ($justBrowsing) { - // Get row count (is approximate for InnoDB) - $unlim_num_rows = $GLOBALS['dbi']->getTable($db, $table)->countRecords(); - /** - * @todo Can we know at this point that this is InnoDB, - * (in this case there would be no need for getting - * an exact count)? - */ - if ($unlim_num_rows < $GLOBALS['cfg']['MaxExactCount']) { - // Get the exact count if approximate count - // is less than MaxExactCount - /** - * @todo In countRecords(), MaxExactCount is also verified, - * so can we avoid checking it twice? - */ - $unlim_num_rows = $GLOBALS['dbi']->getTable($db, $table) - ->countRecords(true); - } - } else { - // The SQL_CALC_FOUND_ROWS option of the SELECT statement is used. - - // For UNION statements, only a SQL_CALC_FOUND_ROWS is required - // after the first SELECT. - - $count_query = Query::replaceClause( - $analyzed_sql_results['statement'], - $analyzed_sql_results['parser']->list, - 'SELECT SQL_CALC_FOUND_ROWS', - null, - true - ); - - // Another LIMIT clause is added to avoid long delays. - // A complete result will be returned anyway, but the LIMIT would - // stop the query as soon as the result that is required has been - // computed. - - if (empty($analyzed_sql_results['union'])) { - $count_query .= ' LIMIT 1'; - } - - // Running the count query. - $GLOBALS['dbi']->tryQuery($count_query); - - $unlim_num_rows = $GLOBALS['dbi']->fetchValue('SELECT FOUND_ROWS()'); - } // end else "just browsing" - } else {// not $is_select - $unlim_num_rows = 0; - } - - return $unlim_num_rows; - } - - /** - * Function to handle all aspects relating to executing the query - * - * @param array $analyzed_sql_results analyzed sql results - * @param string $full_sql_query full sql query - * @param boolean $is_gotofile whether to go to a file - * @param string $db current database - * @param string $table current table - * @param boolean|null $find_real_end whether to find the real end - * @param string $sql_query_for_bookmark sql query to be stored as bookmark - * @param array $extra_data extra data - * - * @return mixed - */ - private function executeTheQuery( - array $analyzed_sql_results, - $full_sql_query, - $is_gotofile, - $db, - $table, - ?bool $find_real_end, - $sql_query_for_bookmark, - $extra_data - ) { - $response = Response::getInstance(); - $response->getHeader()->getMenu()->setTable($table); - - // Only if we ask to see the php code - if (isset($GLOBALS['show_as_php'])) { - $result = null; - $num_rows = 0; - $unlim_num_rows = 0; - } else { // If we don't ask to see the php code - if (isset($_SESSION['profiling']) - && Util::profilingSupported() - ) { - $GLOBALS['dbi']->query('SET PROFILING=1;'); - } - - list( - $result, - $GLOBALS['querytime'] - ) = $this->executeQueryAndMeasureTime($full_sql_query); - - // Displays an error message if required and stop parsing the script - $error = $GLOBALS['dbi']->getError(); - if ($error && $GLOBALS['cfg']['IgnoreMultiSubmitErrors']) { - $extra_data['error'] = $error; - } elseif ($error) { - $this->handleQueryExecuteError($is_gotofile, $error, $full_sql_query); - } - - // If there are no errors and bookmarklabel was given, - // store the query as a bookmark - if (! empty($_POST['bkm_label']) && ! empty($sql_query_for_bookmark)) { - $cfgBookmark = Bookmark::getParams($GLOBALS['cfg']['Server']['user']); - $this->storeTheQueryAsBookmark( - $db, - $cfgBookmark['user'], - $sql_query_for_bookmark, - $_POST['bkm_label'], - isset($_POST['bkm_replace']) ? $_POST['bkm_replace'] : null - ); - } // end store bookmarks - - // Gets the number of rows affected/returned - // (This must be done immediately after the query because - // mysql_affected_rows() reports about the last query done) - $num_rows = $this->getNumberOfRowsAffectedOrChanged( - $analyzed_sql_results['is_affected'], - $result - ); - - // Grabs the profiling results - if (isset($_SESSION['profiling']) - && Util::profilingSupported() - ) { - $profiling_results = $GLOBALS['dbi']->fetchResult('SHOW PROFILE;'); - } - - $justBrowsing = $this->isJustBrowsing( - $analyzed_sql_results, - isset($find_real_end) ? $find_real_end : null - ); - - $unlim_num_rows = $this->countQueryResults( - $num_rows, - $justBrowsing, - $db, - $table, - $analyzed_sql_results - ); - - $this->cleanupRelations( - isset($db) ? $db : '', - isset($table) ? $table : '', - isset($_POST['dropped_column']) ? $_POST['dropped_column'] : null, - isset($_POST['purge']) ? $_POST['purge'] : null - ); - - if (isset($_POST['dropped_column']) - && strlen($db) > 0 - && strlen($table) > 0 - ) { - // to refresh the list of indexes (Ajax mode) - $extra_data['indexes_list'] = Index::getHtmlForIndexes( - $table, - $db - ); - } - } - - return [ - $result, - $num_rows, - $unlim_num_rows, - isset($profiling_results) ? $profiling_results : null, - $extra_data, - ]; - } - /** - * Delete related transformation information - * - * @param string $db current database - * @param string $table current table - * @param array $analyzed_sql_results analyzed sql results - * - * @return void - */ - private function deleteTransformationInfo($db, $table, array $analyzed_sql_results) - { - if (! isset($analyzed_sql_results['statement'])) { - return; - } - $statement = $analyzed_sql_results['statement']; - if ($statement instanceof AlterStatement) { - if (! empty($statement->altered[0]) - && $statement->altered[0]->options->has('DROP') - ) { - if (! empty($statement->altered[0]->field->column)) { - $this->transformations->clear( - $db, - $table, - $statement->altered[0]->field->column - ); - } - } - } elseif ($statement instanceof DropStatement) { - $this->transformations->clear($db, $table); - } - } - - /** - * Function to get the message for the no rows returned case - * - * @param string $message_to_show message to show - * @param array $analyzed_sql_results analyzed sql results - * @param int $num_rows number of rows - * - * @return Message - */ - private function getMessageForNoRowsReturned( - $message_to_show, - array $analyzed_sql_results, - $num_rows - ) { - if ($analyzed_sql_results['querytype'] == 'DELETE"') { - $message = Message::getMessageForDeletedRows($num_rows); - } elseif ($analyzed_sql_results['is_insert']) { - if ($analyzed_sql_results['querytype'] == 'REPLACE') { - // For REPLACE we get DELETED + INSERTED row count, - // so we have to call it affected - $message = Message::getMessageForAffectedRows($num_rows); - } else { - $message = Message::getMessageForInsertedRows($num_rows); - } - $insert_id = $GLOBALS['dbi']->insertId(); - if ($insert_id != 0) { - // insert_id is id of FIRST record inserted in one insert, - // so if we inserted multiple rows, we had to increment this - $message->addText('[br]'); - // need to use a temporary because the Message class - // currently supports adding parameters only to the first - // message - $_inserted = Message::notice(__('Inserted row id: %1$d')); - $_inserted->addParam($insert_id + $num_rows - 1); - $message->addMessage($_inserted); - } - } elseif ($analyzed_sql_results['is_affected']) { - $message = Message::getMessageForAffectedRows($num_rows); - - // Ok, here is an explanation for the !$is_select. - // The form generated by PhpMyAdmin\SqlQueryForm - // and db_sql.php has many submit buttons - // on the same form, and some confusion arises from the - // fact that $message_to_show is sent for every case. - // The $message_to_show containing a success message and sent with - // the form should not have priority over errors - } elseif (! empty($message_to_show) - && $analyzed_sql_results['querytype'] != 'SELECT' - ) { - $message = Message::rawSuccess(htmlspecialchars($message_to_show)); - } elseif (! empty($GLOBALS['show_as_php'])) { - $message = Message::success(__('Showing as PHP code')); - } elseif (isset($GLOBALS['show_as_php'])) { - /* User disable showing as PHP, query is only displayed */ - $message = Message::notice(__('Showing SQL query')); - } else { - $message = Message::success( - __('MySQL returned an empty result set (i.e. zero rows).') - ); - } - - if (isset($GLOBALS['querytime'])) { - $_querytime = Message::notice( - '(' . __('Query took %01.4f seconds.') . ')' - ); - $_querytime->addParam($GLOBALS['querytime']); - $message->addMessage($_querytime); - } - - // In case of ROLLBACK, notify the user. - if (isset($_POST['rollback_query'])) { - $message->addText(__('[ROLLBACK occurred.]')); - } - - return $message; - } - - /** - * Function to respond back when the query returns zero rows - * This method is called - * 1-> When browsing an empty table - * 2-> When executing a query on a non empty table which returns zero results - * 3-> When executing a query on an empty table - * 4-> When executing an INSERT, UPDATE, DELETE query from the SQL tab - * 5-> When deleting a row from BROWSE tab - * 6-> When searching using the SEARCH tab which returns zero results - * 7-> When changing the structure of the table except change operation - * - * @param array $analyzed_sql_results analyzed sql results - * @param string $db current database - * @param string $table current table - * @param string|null $message_to_show message to show - * @param int $num_rows number of rows - * @param DisplayResults $displayResultsObject DisplayResult instance - * @param array|null $extra_data extra data - * @param string $pmaThemeImage uri of the theme image - * @param array|null $profiling_results profiling results - * @param object $result executed query results - * @param string $sql_query sql query - * @param string|null $complete_query complete sql query - * - * @return string html - */ - private function getQueryResponseForNoResultsReturned( - array $analyzed_sql_results, - $db, - $table, - ?string $message_to_show, - $num_rows, - $displayResultsObject, - ?array $extra_data, - $pmaThemeImage, - ?array $profiling_results, - $result, - $sql_query, - ?string $complete_query - ) { - global $url_query; - if ($this->isDeleteTransformationInfo($analyzed_sql_results)) { - $this->deleteTransformationInfo($db, $table, $analyzed_sql_results); - } - - if (isset($extra_data['error'])) { - $message = Message::rawError($extra_data['error']); - } else { - $message = $this->getMessageForNoRowsReturned( - isset($message_to_show) ? $message_to_show : null, - $analyzed_sql_results, - $num_rows - ); - } - - $html_output = ''; - $html_message = Util::getMessage( - $message, - $GLOBALS['sql_query'], - 'success' - ); - $html_output .= $html_message; - if (! isset($GLOBALS['show_as_php'])) { - if (! empty($GLOBALS['reload'])) { - $extra_data['reload'] = 1; - $extra_data['db'] = $GLOBALS['db']; - } - - // For ajax requests add message and sql_query as JSON - if (empty($_REQUEST['ajax_page_request'])) { - $extra_data['message'] = $message; - if ($GLOBALS['cfg']['ShowSQL']) { - $extra_data['sql_query'] = $html_message; - } - } - - $response = Response::getInstance(); - $response->addJSON(isset($extra_data) ? $extra_data : []); - - if (! empty($analyzed_sql_results['is_select']) && - ! isset($extra_data['error'])) { - $url_query = isset($url_query) ? $url_query : null; - - $displayParts = [ - 'edit_lnk' => null, - 'del_lnk' => null, - 'sort_lnk' => '1', - 'nav_bar' => '0', - 'bkm_form' => '1', - 'text_btn' => '1', - 'pview_lnk' => '1', - ]; - - $html_output .= $this->getHtmlForSqlQueryResultsTable( - $displayResultsObject, - $pmaThemeImage, - $url_query, - $displayParts, - false, - 0, - $num_rows, - true, - $result, - $analyzed_sql_results, - true - ); - - if (is_array($profiling_results)) { - $header = $response->getHeader(); - $scripts = $header->getScripts(); - $scripts->addFile('sql.js'); - $html_output .= $this->getHtmlForProfilingChart( - $url_query, - $db, - $profiling_results - ); - } - - $html_output .= $displayResultsObject->getCreateViewQueryResultOp( - $analyzed_sql_results - ); - - $cfgBookmark = Bookmark::getParams($GLOBALS['cfg']['Server']['user']); - if ($cfgBookmark) { - $html_output .= $this->getHtmlForBookmark( - $displayParts, - $cfgBookmark, - $sql_query, - $db, - $table, - isset($complete_query) ? $complete_query : $sql_query, - $cfgBookmark['user'] - ); - } - } - } - - return $html_output; - } - - /** - * Function to send response for ajax grid edit - * - * @param object $result result of the executed query - * - * @return void - */ - private function sendResponseForGridEdit($result) - { - $row = $GLOBALS['dbi']->fetchRow($result); - $field_flags = $GLOBALS['dbi']->fieldFlags($result, 0); - if (false !== stripos($field_flags, DisplayResults::BINARY_FIELD)) { - $row[0] = bin2hex($row[0]); - } - $response = Response::getInstance(); - $response->addJSON('value', $row[0]); - exit; - } - - /** - * Returns a message for successful creation of a bookmark or null if a bookmark - * was not created - * - * @return string - */ - private function getBookmarkCreatedMessage(): string - { - $output = ''; - if (isset($_GET['label'])) { - $message = Message::success( - __('Bookmark %s has been created.') - ); - $message->addParam($_GET['label']); - $output = $message->getDisplay(); - } - - return $output; - } - - /** - * Function to get html for the sql query results table - * - * @param DisplayResults $displayResultsObject instance of DisplayResult - * @param string $pmaThemeImage theme image uri - * @param string $url_query url query - * @param array $displayParts the parts to display - * @param bool $editable whether the result table is - * editable or not - * @param int $unlim_num_rows unlimited number of rows - * @param int $num_rows number of rows - * @param bool $showtable whether to show table or not - * @param object|null $result result of the executed query - * @param array $analyzed_sql_results analyzed sql results - * @param bool $is_limited_display Show only limited operations or not - * - * @return string - */ - private function getHtmlForSqlQueryResultsTable( - $displayResultsObject, - $pmaThemeImage, - $url_query, - array $displayParts, - $editable, - $unlim_num_rows, - $num_rows, - $showtable, - $result, - array $analyzed_sql_results, - $is_limited_display = false - ) { - $printview = isset($_POST['printview']) && $_POST['printview'] == '1' ? '1' : null; - $table_html = ''; - $browse_dist = ! empty($_POST['is_browse_distinct']); - - if ($analyzed_sql_results['is_procedure']) { - do { - if (! isset($result)) { - $result = $GLOBALS['dbi']->storeResult(); - } - $num_rows = $GLOBALS['dbi']->numRows($result); - - if ($result !== false && $num_rows > 0) { - $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result); - if (! is_array($fields_meta)) { - $fields_cnt = 0; - } else { - $fields_cnt = count($fields_meta); - } - - $displayResultsObject->setProperties( - $num_rows, - $fields_meta, - $analyzed_sql_results['is_count'], - $analyzed_sql_results['is_export'], - $analyzed_sql_results['is_func'], - $analyzed_sql_results['is_analyse'], - $num_rows, - $fields_cnt, - $GLOBALS['querytime'], - $pmaThemeImage, - $GLOBALS['text_dir'], - $analyzed_sql_results['is_maint'], - $analyzed_sql_results['is_explain'], - $analyzed_sql_results['is_show'], - $showtable, - $printview, - $url_query, - $editable, - $browse_dist - ); - - $displayParts = [ - 'edit_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE, - 'del_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE, - 'sort_lnk' => '1', - 'nav_bar' => '1', - 'bkm_form' => '1', - 'text_btn' => '1', - 'pview_lnk' => '1', - ]; - - $table_html .= $displayResultsObject->getTable( - $result, - $displayParts, - $analyzed_sql_results, - $is_limited_display - ); - } - - $GLOBALS['dbi']->freeResult($result); - } while ($GLOBALS['dbi']->moreResults() && $GLOBALS['dbi']->nextResult()); - } else { - $fields_meta = []; - if (isset($result) && ! is_bool($result)) { - $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result); - } - $fields_cnt = count($fields_meta); - $_SESSION['is_multi_query'] = false; - $displayResultsObject->setProperties( - $unlim_num_rows, - $fields_meta, - $analyzed_sql_results['is_count'], - $analyzed_sql_results['is_export'], - $analyzed_sql_results['is_func'], - $analyzed_sql_results['is_analyse'], - $num_rows, - $fields_cnt, - $GLOBALS['querytime'], - $pmaThemeImage, - $GLOBALS['text_dir'], - $analyzed_sql_results['is_maint'], - $analyzed_sql_results['is_explain'], - $analyzed_sql_results['is_show'], - $showtable, - $printview, - $url_query, - $editable, - $browse_dist - ); - - if (! is_bool($result)) { - $table_html .= $displayResultsObject->getTable( - $result, - $displayParts, - $analyzed_sql_results, - $is_limited_display - ); - } - $GLOBALS['dbi']->freeResult($result); - } - - return $table_html; - } - - /** - * Function to get html for the previous query if there is such. If not will return - * null - * - * @param string|null $displayQuery display query - * @param bool $showSql whether to show sql - * @param array $sqlData sql data - * @param Message|string $displayMessage display message - * - * @return string - */ - private function getHtmlForPreviousUpdateQuery( - ?string $displayQuery, - bool $showSql, - $sqlData, - $displayMessage - ): string { - $output = ''; - if (isset($displayQuery) && ($showSql === true) && empty($sqlData)) { - $output = Util::getMessage( - $displayMessage, - $displayQuery, - 'success' - ); - } - - return $output; - } - - /** - * To get the message if a column index is missing. If not will return null - * - * @param string $table current table - * @param string $database current database - * @param boolean $editable whether the results table can be editable or not - * @param boolean $hasUniqueKey whether there is a unique key - * - * @return string - */ - private function getMessageIfMissingColumnIndex($table, $database, $editable, $hasUniqueKey): string - { - $output = ''; - if (! empty($table) && ($GLOBALS['dbi']->isSystemSchema($database) || ! $editable)) { - $output = Message::notice( - sprintf( - __( - 'Current selection does not contain a unique column.' - . ' Grid edit, checkbox, Edit, Copy and Delete features' - . ' are not available. %s' - ), - Util::showDocu( - 'config', - 'cfg_RowActionLinksWithoutUnique' - ) - ) - )->getDisplay(); - } elseif (! empty($table) && ! $hasUniqueKey) { - $output = Message::notice( - sprintf( - __( - 'Current selection does not contain a unique column.' - . ' Grid edit, Edit, Copy and Delete features may result in' - . ' undesired behavior. %s' - ), - Util::showDocu( - 'config', - 'cfg_RowActionLinksWithoutUnique' - ) - ) - )->getDisplay(); - } - - return $output; - } - - /** - * Function to get html to display problems in indexes - * - * @param string|null $queryType query type - * @param array|null $selectedTables array of table names selected from the - * database structure page, for an action - * like check table, optimize table, - * analyze table or repair table - * @param string $database current database - * - * @return string - */ - private function getHtmlForIndexesProblems(?string $queryType, ?array $selectedTables, string $database): string - { - // BEGIN INDEX CHECK See if indexes should be checked. - $output = ''; - if (isset($queryType) - && $queryType == 'check_tbl' - && isset($selectedTables) - && is_array($selectedTables) - ) { - foreach ($selectedTables as $table) { - $check = Index::findDuplicates($table, $database); - if (! empty($check)) { - $output .= sprintf( - __('Problems with indexes of table `%s`'), - $table - ); - $output .= $check; - } - } - } - - return $output; - } - - /** - * Function to display results when the executed query returns non empty results - * - * @param object|null $result executed query results - * @param array $analyzed_sql_results analysed sql results - * @param string $db current database - * @param string $table current table - * @param string|null $message message to show - * @param array|null $sql_data sql data - * @param DisplayResults $displayResultsObject Instance of DisplayResults - * @param string $pmaThemeImage uri of the theme image - * @param int $unlim_num_rows unlimited number of rows - * @param int $num_rows number of rows - * @param string|null $disp_query display query - * @param Message|string|null $disp_message display message - * @param array|null $profiling_results profiling results - * @param string|null $query_type query type - * @param array|null $selectedTables array of table names selected - * from the database structure page, for - * an action like check table, - * optimize table, analyze table or - * repair table - * @param string $sql_query sql query - * @param string|null $complete_query complete sql query - * - * @return string html - */ - private function getQueryResponseForResultsReturned( - $result, - array $analyzed_sql_results, - $db, - $table, - ?string $message, - ?array $sql_data, - $displayResultsObject, - $pmaThemeImage, - $unlim_num_rows, - $num_rows, - ?string $disp_query, - $disp_message, - ?array $profiling_results, - ?string $query_type, - $selectedTables, - $sql_query, - ?string $complete_query - ) { - global $showtable, $url_query; - // If we are retrieving the full value of a truncated field or the original - // value of a transformed field, show it here - if (isset($_POST['grid_edit']) && $_POST['grid_edit'] == true) { - $this->sendResponseForGridEdit($result); - // script has exited at this point - } - - // Gets the list of fields properties - if (isset($result) && $result) { - $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result); - } else { - $fields_meta = []; - } - - // Should be initialized these parameters before parsing - $showtable = isset($showtable) ? $showtable : null; - $url_query = isset($url_query) ? $url_query : null; - - $response = Response::getInstance(); - $header = $response->getHeader(); - $scripts = $header->getScripts(); - - $just_one_table = $this->resultSetHasJustOneTable($fields_meta); - - // hide edit and delete links: - // - for information_schema - // - if the result set does not contain all the columns of a unique key - // (unless this is an updatable view) - // - if the SELECT query contains a join or a subquery - - $updatableView = false; - - $statement = isset($analyzed_sql_results['statement']) ? $analyzed_sql_results['statement'] : null; - if ($statement instanceof SelectStatement) { - if (! empty($statement->expr)) { - if ($statement->expr[0]->expr === '*') { - $_table = new Table($table, $db); - $updatableView = $_table->isUpdatableView(); - } - } - - if ($analyzed_sql_results['join'] - || $analyzed_sql_results['is_subquery'] - || count($analyzed_sql_results['select_tables']) !== 1 - ) { - $just_one_table = false; - } - } - - $has_unique = $this->resultSetContainsUniqueKey( - $db, - $table, - $fields_meta - ); - - $editable = ($has_unique - || $GLOBALS['cfg']['RowActionLinksWithoutUnique'] - || $updatableView) - && $just_one_table; - - $_SESSION['tmpval']['possible_as_geometry'] = $editable; - - $displayParts = [ - 'edit_lnk' => $displayResultsObject::UPDATE_ROW, - 'del_lnk' => $displayResultsObject::DELETE_ROW, - 'sort_lnk' => '1', - 'nav_bar' => '1', - 'bkm_form' => '1', - 'text_btn' => '0', - 'pview_lnk' => '1', - ]; - - if ($GLOBALS['dbi']->isSystemSchema($db) || ! $editable) { - $displayParts = [ - 'edit_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE, - 'del_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE, - 'sort_lnk' => '1', - 'nav_bar' => '1', - 'bkm_form' => '1', - 'text_btn' => '1', - 'pview_lnk' => '1', - ]; - } - if (isset($_POST['printview']) && $_POST['printview'] == '1') { - $displayParts = [ - 'edit_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE, - 'del_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE, - 'sort_lnk' => '0', - 'nav_bar' => '0', - 'bkm_form' => '0', - 'text_btn' => '0', - 'pview_lnk' => '0', - ]; - } - - $tableMaintenanceHtml = ''; - if (isset($_POST['table_maintenance'])) { - $scripts->addFile('makegrid.js'); - $scripts->addFile('sql.js'); - if (isset($message)) { - $message = Message::success($message); - $tableMaintenanceHtml = Util::getMessage( - $message, - $GLOBALS['sql_query'], - 'success' - ); - } - $tableMaintenanceHtml .= $this->getHtmlForSqlQueryResultsTable( - $displayResultsObject, - $pmaThemeImage, - $url_query, - $displayParts, - false, - $unlim_num_rows, - $num_rows, - $showtable, - $result, - $analyzed_sql_results - ); - if (empty($sql_data) || ($sql_data['valid_queries'] = 1)) { - $response->addHTML($tableMaintenanceHtml); - exit; - } - } - - if (! isset($_POST['printview']) || $_POST['printview'] != '1') { - $scripts->addFile('makegrid.js'); - $scripts->addFile('sql.js'); - unset($GLOBALS['message']); - //we don't need to buffer the output in getMessage here. - //set a global variable and check against it in the function - $GLOBALS['buffer_message'] = false; - } - - $previousUpdateQueryHtml = $this->getHtmlForPreviousUpdateQuery( - isset($disp_query) ? $disp_query : null, - (bool) $GLOBALS['cfg']['ShowSQL'], - isset($sql_data) ? $sql_data : null, - isset($disp_message) ? $disp_message : null - ); - - $profilingChartHtml = $this->getHtmlForProfilingChart( - $url_query, - $db, - isset($profiling_results) ? $profiling_results : [] - ); - - $missingUniqueColumnMessage = $this->getMessageIfMissingColumnIndex( - $table, - $db, - $editable, - $has_unique - ); - - $bookmarkCreatedMessage = $this->getBookmarkCreatedMessage(); - - $tableHtml = $this->getHtmlForSqlQueryResultsTable( - $displayResultsObject, - $pmaThemeImage, - $url_query, - $displayParts, - $editable, - $unlim_num_rows, - $num_rows, - $showtable, - $result, - $analyzed_sql_results - ); - - $indexesProblemsHtml = $this->getHtmlForIndexesProblems( - isset($query_type) ? $query_type : null, - isset($selectedTables) ? $selectedTables : null, - $db - ); - - $cfgBookmark = Bookmark::getParams($GLOBALS['cfg']['Server']['user']); - $bookmarkSupportHtml = ''; - if ($cfgBookmark) { - $bookmarkSupportHtml = $this->getHtmlForBookmark( - $displayParts, - $cfgBookmark, - $sql_query, - $db, - $table, - isset($complete_query) ? $complete_query : $sql_query, - $cfgBookmark['user'] - ); - } - - return $this->template->render('sql/sql_query_results', [ - 'table_maintenance' => $tableMaintenanceHtml, - 'previous_update_query' => $previousUpdateQueryHtml, - 'profiling_chart' => $profilingChartHtml, - 'missing_unique_column_message' => $missingUniqueColumnMessage, - 'bookmark_created_message' => $bookmarkCreatedMessage, - 'table' => $tableHtml, - 'indexes_problems' => $indexesProblemsHtml, - 'bookmark_support' => $bookmarkSupportHtml, - ]); - } - - /** - * Function to execute the query and send the response - * - * @param array $analyzed_sql_results analysed sql results - * @param bool $is_gotofile whether goto file or not - * @param string $db current database - * @param string $table current table - * @param bool|null $find_real_end whether to find real end or not - * @param string $sql_query_for_bookmark the sql query to be stored as bookmark - * @param array|null $extra_data extra data - * @param string $message_to_show message to show - * @param string $message message - * @param array|null $sql_data sql data - * @param string $goto goto page url - * @param string $pmaThemeImage uri of the PMA theme image - * @param string $disp_query display query - * @param Message|string $disp_message display message - * @param string $query_type query type - * @param string $sql_query sql query - * @param array|null $selectedTables array of table names selected from the - * database structure page, for an action - * like check table, optimize table, - * analyze table or repair table - * @param string $complete_query complete query - * - * @return void - */ - public function executeQueryAndSendQueryResponse( - $analyzed_sql_results, - $is_gotofile, - $db, - $table, - $find_real_end, - $sql_query_for_bookmark, - $extra_data, - $message_to_show, - $message, - $sql_data, - $goto, - $pmaThemeImage, - $disp_query, - $disp_message, - $query_type, - $sql_query, - $selectedTables, - $complete_query - ) { - if ($analyzed_sql_results == null) { - // Parse and analyze the query - list( - $analyzed_sql_results, - $db, - $table_from_sql - ) = ParseAnalyze::sqlQuery($sql_query, $db); - // @todo: possibly refactor - extract($analyzed_sql_results); - - if ($table != $table_from_sql && ! empty($table_from_sql)) { - $table = $table_from_sql; - } - } - - $html_output = $this->executeQueryAndGetQueryResponse( - $analyzed_sql_results, // analyzed_sql_results - $is_gotofile, // is_gotofile - $db, // db - $table, // table - $find_real_end, // find_real_end - $sql_query_for_bookmark, // sql_query_for_bookmark - $extra_data, // extra_data - $message_to_show, // message_to_show - $message, // message - $sql_data, // sql_data - $goto, // goto - $pmaThemeImage, // pmaThemeImage - $disp_query, // disp_query - $disp_message, // disp_message - $query_type, // query_type - $sql_query, // sql_query - $selectedTables, // selectedTables - $complete_query // complete_query - ); - - $response = Response::getInstance(); - $response->addHTML($html_output); - } - - /** - * Function to execute the query and send the response - * - * @param array $analyzed_sql_results analysed sql results - * @param bool $is_gotofile whether goto file or not - * @param string $db current database - * @param string $table current table - * @param bool|null $find_real_end whether to find real end or not - * @param string|null $sql_query_for_bookmark the sql query to be stored as bookmark - * @param array|null $extra_data extra data - * @param string|null $message_to_show message to show - * @param Message|string|null $message message - * @param array|null $sql_data sql data - * @param string $goto goto page url - * @param string $pmaThemeImage uri of the PMA theme image - * @param string|null $disp_query display query - * @param Message|string|null $disp_message display message - * @param string|null $query_type query type - * @param string $sql_query sql query - * @param array|null $selectedTables array of table names selected from the - * database structure page, for an action - * like check table, optimize table, - * analyze table or repair table - * @param string|null $complete_query complete query - * - * @return string html - */ - public function executeQueryAndGetQueryResponse( - array $analyzed_sql_results, - $is_gotofile, - $db, - $table, - $find_real_end, - ?string $sql_query_for_bookmark, - $extra_data, - ?string $message_to_show, - $message, - $sql_data, - $goto, - $pmaThemeImage, - ?string $disp_query, - $disp_message, - ?string $query_type, - $sql_query, - $selectedTables, - ?string $complete_query - ) { - // Handle disable/enable foreign key checks - $default_fk_check = Util::handleDisableFKCheckInit(); - - // Handle remembered sorting order, only for single table query. - // Handling is not required when it's a union query - // (the parser never sets the 'union' key to 0). - // Handling is also not required if we came from the "Sort by key" - // drop-down. - if (! empty($analyzed_sql_results) - && $this->isRememberSortingOrder($analyzed_sql_results) - && empty($analyzed_sql_results['union']) - && ! isset($_POST['sort_by_key']) - ) { - if (! isset($_SESSION['sql_from_query_box'])) { - $this->handleSortOrder($db, $table, $analyzed_sql_results, $sql_query); - } else { - unset($_SESSION['sql_from_query_box']); - } - } - - $displayResultsObject = new DisplayResults( - $GLOBALS['db'], - $GLOBALS['table'], - $GLOBALS['server'], - $goto, - $sql_query - ); - $displayResultsObject->setConfigParamsForDisplayTable(); - - // assign default full_sql_query - $full_sql_query = $sql_query; - - // Do append a "LIMIT" clause? - if ($this->isAppendLimitClause($analyzed_sql_results)) { - $full_sql_query = $this->getSqlWithLimitClause($analyzed_sql_results); - } - - $GLOBALS['reload'] = $this->hasCurrentDbChanged($db); - $GLOBALS['dbi']->selectDb($db); - - list( - $result, - $num_rows, - $unlim_num_rows, - $profiling_results, - $extra_data - ) = $this->executeTheQuery( - $analyzed_sql_results, - $full_sql_query, - $is_gotofile, - $db, - $table, - isset($find_real_end) ? $find_real_end : null, - isset($sql_query_for_bookmark) ? $sql_query_for_bookmark : null, - isset($extra_data) ? $extra_data : null - ); - - if ($GLOBALS['dbi']->moreResults()) { - $GLOBALS['dbi']->nextResult(); - } - - $warning_messages = $this->operations->getWarningMessagesArray(); - - // No rows returned -> move back to the calling page - if ((0 == $num_rows && 0 == $unlim_num_rows) - || $analyzed_sql_results['is_affected'] - ) { - $html_output = $this->getQueryResponseForNoResultsReturned( - $analyzed_sql_results, - $db, - $table, - isset($message_to_show) ? $message_to_show : null, - $num_rows, - $displayResultsObject, - $extra_data, - $pmaThemeImage, - $profiling_results, - isset($result) ? $result : null, - $sql_query, - isset($complete_query) ? $complete_query : null - ); - } else { - // At least one row is returned -> displays a table with results - $html_output = $this->getQueryResponseForResultsReturned( - isset($result) ? $result : null, - $analyzed_sql_results, - $db, - $table, - isset($message) ? $message : null, - isset($sql_data) ? $sql_data : null, - $displayResultsObject, - $pmaThemeImage, - $unlim_num_rows, - $num_rows, - isset($disp_query) ? $disp_query : null, - isset($disp_message) ? $disp_message : null, - $profiling_results, - isset($query_type) ? $query_type : null, - isset($selectedTables) ? $selectedTables : null, - $sql_query, - isset($complete_query) ? $complete_query : null - ); - } - - // Handle disable/enable foreign key checks - Util::handleDisableFKCheckCleanup($default_fk_check); - - foreach ($warning_messages as $warning) { - $message = Message::notice(Message::sanitize($warning)); - $html_output .= $message->getDisplay(); - } - - return $html_output; - } - - /** - * Function to define pos to display a row - * - * @param int $number_of_line Number of the line to display - * @param int $max_rows Number of rows by page - * - * @return int Start position to display the line - */ - private function getStartPosToDisplayRow($number_of_line, $max_rows = null) - { - if (null === $max_rows) { - $max_rows = $_SESSION['tmpval']['max_rows']; - } - - return @((ceil($number_of_line / $max_rows) - 1) * $max_rows); - } - - /** - * Function to calculate new pos if pos is higher than number of rows - * of displayed table - * - * @param string $db Database name - * @param string $table Table name - * @param int|null $pos Initial position - * - * @return int Number of pos to display last page - */ - public function calculatePosForLastPage($db, $table, $pos) - { - if (null === $pos) { - $pos = $_SESSION['tmpval']['pos']; - } - - $_table = new Table($table, $db); - $unlim_num_rows = $_table->countRecords(true); - //If position is higher than number of rows - if ($unlim_num_rows <= $pos && 0 != $pos) { - $pos = $this->getStartPosToDisplayRow($unlim_num_rows); - } - - return $pos; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/SqlQueryForm.php b/srcs/phpmyadmin/libraries/classes/SqlQueryForm.php deleted file mode 100644 index 15aaaf7..0000000 --- a/srcs/phpmyadmin/libraries/classes/SqlQueryForm.php +++ /dev/null @@ -1,457 +0,0 @@ -' . "\n"; - - $html .= '' - . "\n" . Url::getHiddenInputs($db, $table) . "\n" - . '' . "\n" - . '' . "\n" - . '' - . "\n" . '' . "\n"; - - // display querybox - if ($display_tab === 'full' || $display_tab === 'sql') { - $html .= $this->getHtmlForInsert( - $query, - $delimiter - ); - } - - // Bookmark Support - if ($display_tab === 'full') { - $cfgBookmark = Bookmark::getParams($GLOBALS['cfg']['Server']['user']); - if ($cfgBookmark) { - $html .= $this->getHtmlForBookmark(); - } - } - - // Japanese encoding setting - if (Encoding::canConvertKanji()) { - $html .= Encoding::kanjiEncodingForm(); - } - - $html .= '
    ' . "\n"; - // print an empty div, which will be later filled with - // the sql query results by ajax - $html .= '
    '; - - return $html; - } - - /** - * Get initial values for Sql Query Form Insert - * - * @param string $query query to display in the textarea - * - * @return array ($legend, $query, $columns_list) - */ - public function init($query) - { - $columns_list = []; - if (strlen($GLOBALS['db']) === 0) { - // prepare for server related - $legend = sprintf( - __('Run SQL query/queries on server “%s”'), - htmlspecialchars( - ! empty($GLOBALS['cfg']['Servers'][$GLOBALS['server']]['verbose']) - ? $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['verbose'] - : $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['host'] - ) - ); - } elseif (strlen($GLOBALS['table']) === 0) { - // prepare for db related - $db = $GLOBALS['db']; - // if you want navigation: - $tmp_db_link = ''; - $legend = sprintf(__('Run SQL query/queries on database %s'), $tmp_db_link); - if (empty($query)) { - $query = Util::expandUserString( - $GLOBALS['cfg']['DefaultQueryDatabase'], - 'backquote' - ); - } - } else { - $db = $GLOBALS['db']; - $table = $GLOBALS['table']; - // Get the list and number of fields - // we do a try_query here, because we could be in the query window, - // trying to synchronize and the table has not yet been created - $columns_list = $GLOBALS['dbi']->getColumns( - $db, - $GLOBALS['table'], - null, - true - ); - - $tmp_tbl_link = ''; - $tmp_tbl_link .= htmlspecialchars($db) - . '.' . htmlspecialchars($table) . ''; - $legend = sprintf(__('Run SQL query/queries on table %s'), $tmp_tbl_link); - if (empty($query)) { - $query = Util::expandUserString( - $GLOBALS['cfg']['DefaultQueryTable'], - 'backquote' - ); - } - } - $legend .= ': ' . Util::showMySQLDocu('SELECT'); - - return [ - $legend, - $query, - $columns_list, - ]; - } - - /** - * return HTML for Sql Query Form Insert - * - * @param string $query query to display in the textarea - * @param string $delimiter default delimiter to use - * - * @return string - */ - public function getHtmlForInsert( - $query = '', - $delimiter = ';' - ) { - // enable auto select text in textarea - if ($GLOBALS['cfg']['TextareaAutoSelect']) { - $auto_sel = ' onclick="Functions.selectContent(this, sqlBoxLocked, true);"'; - } else { - $auto_sel = ''; - } - - $locking = ''; - $height = $GLOBALS['cfg']['TextareaRows'] * 2; - - list($legend, $query, $columns_list) = $this->init($query); - - if (! empty($columns_list)) { - $sqlquerycontainer_id = 'sqlquerycontainer'; - } else { - $sqlquerycontainer_id = 'sqlquerycontainerfull'; - } - - $html = '' - . '
    ' - . '
    '; - $html .= '' . $legend . ''; - $html .= '
    '; - $html .= '
    ' - . ''; - $html .= '
    '; - // Add buttons to generate query easily for - // select all, single select, insert, update and delete - if (! empty($columns_list)) { - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - } - $html .= ''; - if ($GLOBALS['cfg']['CodemirrorEnable']) { - $html .= ''; - } - $html .= ''; - - // parameter binding - $html .= '
    '; - $html .= ''; - $html .= ''; - $html .= Util::showDocu('faq', 'faq6-40'); - $html .= '
    '; - $html .= '
    '; - - $html .= '
    ' . "\n"; - - if (! empty($columns_list)) { - $html .= '
    ' - . '' - . '' - . '
    '; - if (Util::showIcons('ActionLinksMode')) { - $html .= ''; - } else { - $html .= ''; - } - $html .= '
    ' . "\n" - . '
    ' . "\n"; - } - - $html .= '
    ' . "\n"; - $html .= '
    ' . "\n"; - - $cfgBookmark = Bookmark::getParams($GLOBALS['cfg']['Server']['user']); - if ($cfgBookmark) { - $html .= '
    '; - $html .= '
    '; - $html .= ''; - $html .= ''; - $html .= '
    '; - $html .= '
    '; - $html .= ''; - $html .= ''; - $html .= '
    '; - $html .= '
    '; - $html .= ''; - $html .= ''; - $html .= '
    '; - $html .= '
    '; - } - - $html .= '
    ' . "\n"; - $html .= '
    ' . "\n" - . '
    ' . "\n"; - - $html .= '
    ' . "\n"; - $html .= '
    ' . "\n"; - $html .= '
    ' . "\n"; - - $html .= '
    '; - $html .= '' . "\n"; - $html .= ' ]'; - $html .= '
    '; - - $html .= '
    '; - $html .= '' - . ''; - $html .= '
    '; - - $html .= '
    '; - $html .= '' - . ''; - $html .= '
    '; - - $html .= '
    '; - $html .= '' - . ''; - $html .= '
    '; - - // Disable/Enable foreign key checks - $html .= '
    '; - $html .= Util::getFKCheckbox(); - $html .= '
    '; - - $html .= '' . "\n"; - $html .= '
    ' . "\n"; - $html .= '
    ' . "\n"; - - return $html; - } - - /** - * return HTML for sql Query Form Bookmark - * - * @return string|null - */ - public function getHtmlForBookmark() - { - $bookmark_list = Bookmark::getList( - $GLOBALS['dbi'], - $GLOBALS['cfg']['Server']['user'], - $GLOBALS['db'] - ); - if (empty($bookmark_list) || count($bookmark_list) < 1) { - return null; - } - - $html = '
    '; - $html .= ''; - $html .= __('Bookmarked SQL query') . '' . "\n"; - $html .= '
    '; - $html .= ' ' . "\n"; - $html .= '
    ' . "\n"; - $html .= '
    ' . "\n"; - $html .= '' - . '' . "\n"; - $html .= '' - . '' . "\n"; - $html .= '' - . '' . "\n"; - $html .= '
    ' . "\n"; - $html .= '
    ' . "\n"; - $html .= '
    ' . "\n"; - $html .= __('Variables'); - $html .= Util::showDocu('faq', 'faqbookmark'); - $html .= '
    '; - $html .= '
    ' . "\n"; - $html .= '
    ' . "\n"; - - $html .= '
    '; - $html .= ''; - $html .= '
    ' . "\n"; - $html .= '
    ' . "\n"; - - return $html; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/StorageEngine.php b/srcs/phpmyadmin/libraries/classes/StorageEngine.php deleted file mode 100644 index cbb3172..0000000 --- a/srcs/phpmyadmin/libraries/classes/StorageEngine.php +++ /dev/null @@ -1,465 +0,0 @@ -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; - } - } - } - - /** - * Returns array of storage engines - * - * @static - * @staticvar array $storage_engines storage engines - * @access public - * @return array[] array of storage engines - */ - public static function getStorageEngines() - { - static $storage_engines = null; - - if (null == $storage_engines) { - $storage_engines - = $GLOBALS['dbi']->fetchResult('SHOW STORAGE ENGINES', 'Engine'); - if ($GLOBALS['dbi']->getVersion() >= 50708) { - $disabled = (string) Util::cacheGet( - 'disabled_storage_engines', - function () { - return $GLOBALS['dbi']->fetchValue( - 'SELECT @@disabled_storage_engines' - ); - } - ); - foreach (explode(",", $disabled) as $engine) { - if (isset($storage_engines[$engine])) { - $storage_engines[$engine]['Support'] = 'DISABLED'; - } - } - } - } - - return $storage_engines; - } - - /** - * Returns HTML code for storage engine select box - * - * @param string $name The name of the select form element - * @param string $id The ID of the form field - * @param string $selected The selected engine - * @param boolean $offerUnavailableEngines Should unavailable storage - * engines be offered? - * @param boolean $addEmpty Whether to provide empty option - * - * @static - * @return string html selectbox - */ - public static function getHtmlSelect( - $name = 'engine', - $id = null, - $selected = null, - $offerUnavailableEngines = false, - $addEmpty = false - ) { - $selected = mb_strtolower((string) $selected); - $output = '' . "\n"; - return $output; - } - - /** - * Loads the corresponding engine plugin, if available. - * - * @param string $engine The engine ID - * - * @return StorageEngine The engine plugin - * @static - */ - public static function getEngine($engine) - { - switch (mb_strtolower($engine)) { - case 'bdb': - return new Bdb($engine); - case 'berkeleydb': - return new Berkeleydb($engine); - case 'binlog': - return new Binlog($engine); - case 'innobase': - return new Innobase($engine); - case 'innodb': - return new Innodb($engine); - case 'memory': - return new Memory($engine); - case 'merge': - return new Merge($engine); - case 'mrg_myisam': - return new MrgMyisam($engine); - case 'myisam': - return new Myisam($engine); - case 'ndbcluster': - return new Ndbcluster($engine); - case 'pbxt': - return new Pbxt($engine); - case 'performance_schema': - return new PerformanceSchema($engine); - default: - return new StorageEngine($engine); - } - } - - /** - * Returns 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 - */ - public static function isValid($engine) - { - if ($engine == "PBMS") { - return true; - } - $storage_engines = self::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 - */ - public function getHtmlVariables() - { - $ret = ''; - - foreach ($this->getVariablesStatus() as $details) { - $ret .= '' . "\n" - . ' ' . "\n"; - if (! empty($details['desc'])) { - $ret .= ' ' - . 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 .= Util::formatNumber($details['value']) . ' '; - break; - default: - $ret .= htmlspecialchars($details['value']) . ' '; - } - $ret .= '' . "\n" - . '' . "\n"; - } - - 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 array the formatted value and its unit - */ - public function resolveTypeSize($value) - { - return Util::formatByteDown($value); - } - - /** - * Returns array with detailed info about engine specific server variables - * - * @return array array with detailed info about specific engine server variables - */ - public function getVariablesStatus() - { - $variables = $this->getVariables(); - $like = $this->getVariablesLikePattern(); - - if ($like) { - $like = " LIKE '" . $like . "' "; - } else { - $like = ''; - } - - $mysql_vars = []; - - $sql_query = 'SHOW GLOBAL VARIABLES ' . $like . ';'; - $res = $GLOBALS['dbi']->query($sql_query); - while ($row = $GLOBALS['dbi']->fetchAssoc($res)) { - if (isset($variables[$row['Variable_name']])) { - $mysql_vars[$row['Variable_name']] - = $variables[$row['Variable_name']]; - } elseif (! $like - && mb_strpos(mb_strtolower($row['Variable_name']), mb_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; - } - } - $GLOBALS['dbi']->freeResult($res); - - return $mysql_vars; - } - - /** - * Reveals the engine's title - * - * @return string The title - */ - public function getTitle() - { - return $this->title; - } - - /** - * Fetches the server's comment about this engine - * - * @return string The comment - */ - public function getComment() - { - return $this->comment; - } - - /** - * Information message on whether this storage engine is supported - * - * @return string The localized message. - */ - public 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)); - } - - /** - * 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. - * - * @return array The list of variables. - */ - public function getVariables() - { - return []; - } - - /** - * Returns string with filename for the MySQL helppage - * about this storage engine - * - * @return string MySQL help page filename - */ - public function getMysqlHelpPage() - { - return $this->engine . '-storage-engine'; - } - - /** - * Returns the pattern to be used in the query for SQL variables - * related to the storage engine - * - * @return string SQL query LIKE pattern - */ - public function getVariablesLikePattern() - { - return ''; - } - - /** - * Returns a list of available information pages with labels - * - * @return string[] The list - */ - public function getInfoPages() - { - return []; - } - - /** - * Generates the requested information page - * - * @param string $id page id - * - * @return string html output - */ - public function getPage($id) - { - if (! array_key_exists($id, $this->getInfoPages())) { - return ''; - } - - $id = 'getPage' . $id; - - return $this->$id(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/SubPartition.php b/srcs/phpmyadmin/libraries/classes/SubPartition.php deleted file mode 100644 index a5eac8b..0000000 --- a/srcs/phpmyadmin/libraries/classes/SubPartition.php +++ /dev/null @@ -1,182 +0,0 @@ -db = $row['TABLE_SCHEMA']; - $this->table = $row['TABLE_NAME']; - $this->loadData($row); - } - - /** - * Loads data from the fetched row from information_schema.PARTITIONS - * - * @param array $row fetched row - * - * @return void - */ - protected function loadData(array $row) - { - $this->name = $row['SUBPARTITION_NAME']; - $this->ordinal = $row['SUBPARTITION_ORDINAL_POSITION']; - $this->method = $row['SUBPARTITION_METHOD']; - $this->expression = $row['SUBPARTITION_EXPRESSION']; - $this->loadCommonData($row); - } - - /** - * Loads some data that is common to both partitions and sub partitions - * - * @param array $row fetched row - * - * @return void - */ - protected function loadCommonData(array $row) - { - $this->rows = $row['TABLE_ROWS']; - $this->dataLength = $row['DATA_LENGTH']; - $this->indexLength = $row['INDEX_LENGTH']; - $this->comment = $row['PARTITION_COMMENT']; - } - - /** - * Return the partition name - * - * @return string partition name - */ - public function getName() - { - return $this->name; - } - - /** - * Return the ordinal of the partition - * - * @return int the ordinal - */ - public function getOrdinal() - { - return $this->ordinal; - } - - /** - * Returns the partition method - * - * @return string partition method - */ - public function getMethod() - { - return $this->method; - } - - /** - * Returns the partition expression - * - * @return string partition expression - */ - public function getExpression() - { - return $this->expression; - } - - /** - * Returns the number of data rows - * - * @return integer number of rows - */ - public function getRows() - { - return $this->rows; - } - - /** - * Returns the data length - * - * @return integer data length - */ - public function getDataLength() - { - return $this->dataLength; - } - - /** - * Returns the index length - * - * @return integer index length - */ - public function getIndexLength() - { - return $this->indexLength; - } - - /** - * Returns the partition comment - * - * @return string partition comment - */ - public function getComment() - { - return $this->comment; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/SysInfo.php b/srcs/phpmyadmin/libraries/classes/SysInfo.php deleted file mode 100644 index 8fae3a8..0000000 --- a/srcs/phpmyadmin/libraries/classes/SysInfo.php +++ /dev/null @@ -1,73 +0,0 @@ -supported()) { - return $ret; - } - } - - return new SysInfoBase(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/SysInfoBase.php b/srcs/phpmyadmin/libraries/classes/SysInfoBase.php deleted file mode 100644 index 147c49a..0000000 --- a/srcs/phpmyadmin/libraries/classes/SysInfoBase.php +++ /dev/null @@ -1,50 +0,0 @@ - 0]; - } - - /** - * Gets information about memory usage - * - * @return array with memory usage data - */ - public function memory() - { - return []; - } - - /** - * Checks whether class is supported in this environment - * - * @return bool true on success - */ - public function supported() - { - return true; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/SysInfoLinux.php b/srcs/phpmyadmin/libraries/classes/SysInfoLinux.php deleted file mode 100644 index 21ac9cd..0000000 --- a/srcs/phpmyadmin/libraries/classes/SysInfoLinux.php +++ /dev/null @@ -1,103 +0,0 @@ - (int) $nums[1] + (int) $nums[2] + (int) $nums[3], - 'idle' => (int) $nums[4], - ]; - } - - /** - * Checks whether class is supported in this environment - * - * @return bool true on success - */ - public function supported() - { - return @is_readable('/proc/meminfo') && @is_readable('/proc/stat'); - } - - /** - * Gets information about memory usage - * - * @return array with memory usage data - */ - public function memory() - { - preg_match_all( - SysInfo::MEMORY_REGEXP, - file_get_contents('/proc/meminfo'), - $matches - ); - - $mem = array_combine($matches[1], $matches[2]); - - $defaults = [ - 'MemTotal' => 0, - 'MemFree' => 0, - 'Cached' => 0, - 'Buffers' => 0, - 'SwapTotal' => 0, - 'SwapFree' => 0, - 'SwapCached' => 0, - ]; - - $mem = array_merge($defaults, $mem); - - foreach ($mem as $idx => $value) { - $mem[$idx] = intval($value); - } - - $mem['MemUsed'] = $mem['MemTotal'] - - $mem['MemFree'] - $mem['Cached'] - $mem['Buffers']; - - $mem['SwapUsed'] = $mem['SwapTotal'] - - $mem['SwapFree'] - $mem['SwapCached']; - - return $mem; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/SysInfoSunOS.php b/srcs/phpmyadmin/libraries/classes/SysInfoSunOS.php deleted file mode 100644 index 6158b62..0000000 --- a/srcs/phpmyadmin/libraries/classes/SysInfoSunOS.php +++ /dev/null @@ -1,81 +0,0 @@ -_kstat('unix:0:system_misc:avenrun_1min'); - - return ['loadavg' => $load1]; - } - - /** - * Checks whether class is supported in this environment - * - * @return bool true on success - */ - public function supported() - { - return @is_readable('/proc/meminfo'); - } - - /** - * Gets information about memory usage - * - * @return array with memory usage data - */ - public function memory() - { - $pagesize = (int) $this->_kstat('unix:0:seg_cache:slab_size'); - $mem = []; - $mem['MemTotal'] = (int) $this->_kstat('unix:0:system_pages:pagestotal') * $pagesize; - $mem['MemUsed'] = (int) $this->_kstat('unix:0:system_pages:pageslocked') * $pagesize; - $mem['MemFree'] = (int) $this->_kstat('unix:0:system_pages:pagesfree') * $pagesize; - $mem['SwapTotal'] = (int) $this->_kstat('unix:0:vminfo:swap_avail') / 1024; - $mem['SwapUsed'] = (int) $this->_kstat('unix:0:vminfo:swap_alloc') / 1024; - $mem['SwapFree'] = (int) $this->_kstat('unix:0:vminfo:swap_free') / 1024; - - return $mem; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/SysInfoWINNT.php b/srcs/phpmyadmin/libraries/classes/SysInfoWINNT.php deleted file mode 100644 index 063c7e4..0000000 --- a/srcs/phpmyadmin/libraries/classes/SysInfoWINNT.php +++ /dev/null @@ -1,135 +0,0 @@ -_wmi = null; - } else { - // initialize the wmi object - $objLocator = new COM('WbemScripting.SWbemLocator'); - $this->_wmi = $objLocator->ConnectServer(); - } - } - - /** - * Gets load information - * - * @return array with load data - */ - public function loadavg() - { - $sum = 0; - $buffer = $this->_getWMI('Win32_Processor', ['LoadPercentage']); - - foreach ($buffer as $load) { - $value = $load['LoadPercentage']; - $sum += $value; - } - - return ['loadavg' => $sum / count($buffer)]; - } - - /** - * Checks whether class is supported in this environment - * - * @return bool true on success - */ - public function supported() - { - return $this->_wmi !== null; - } - - /** - * Reads data from WMI - * - * @param string $strClass Class to read - * @param array $strValue Values to read - * - * @return array with results - */ - private function _getWMI($strClass, array $strValue = []) - { - $arrData = []; - - $objWEBM = $this->_wmi->Get($strClass); - $arrProp = $objWEBM->Properties_; - $arrWEBMCol = $objWEBM->Instances_(); - foreach ($arrWEBMCol as $objItem) { - $arrInstance = []; - foreach ($arrProp as $propItem) { - $name = $propItem->Name; - if (empty($strValue) || in_array($name, $strValue)) { - $value = $objItem->$name; - if (is_string($value)) { - $arrInstance[$name] = trim($value); - } else { - $arrInstance[$name] = $value; - } - } - } - $arrData[] = $arrInstance; - } - - return $arrData; - } - - /** - * Gets information about memory usage - * - * @return array with memory usage data - */ - public function memory() - { - $buffer = $this->_getWMI( - "Win32_OperatingSystem", - [ - 'TotalVisibleMemorySize', - 'FreePhysicalMemory', - ] - ); - $mem = []; - $mem['MemTotal'] = $buffer[0]['TotalVisibleMemorySize']; - $mem['MemFree'] = $buffer[0]['FreePhysicalMemory']; - $mem['MemUsed'] = $mem['MemTotal'] - $mem['MemFree']; - - $buffer = $this->_getWMI('Win32_PageFileUsage'); - - $mem['SwapTotal'] = 0; - $mem['SwapUsed'] = 0; - $mem['SwapPeak'] = 0; - - foreach ($buffer as $swapdevice) { - $mem['SwapTotal'] += $swapdevice['AllocatedBaseSize'] * 1024; - $mem['SwapUsed'] += $swapdevice['CurrentUsage'] * 1024; - $mem['SwapPeak'] += $swapdevice['PeakUsage'] * 1024; - } - - return $mem; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/SystemDatabase.php b/srcs/phpmyadmin/libraries/classes/SystemDatabase.php deleted file mode 100644 index 8dc5174..0000000 --- a/srcs/phpmyadmin/libraries/classes/SystemDatabase.php +++ /dev/null @@ -1,137 +0,0 @@ -dbi = $dbi; - $this->relation = new Relation($this->dbi); - } - - /** - * Get existing data on transformations applied for - * columns in a particular table - * - * @param string $db Database name looking for - * - * @return mysqli_result Result of executed SQL query - */ - public function getExistingTransformationData($db) - { - $cfgRelation = $this->relation->getRelationsParam(); - - // Get the existing transformation details of the same database - // from pma__column_info table - $pma_transformation_sql = sprintf( - "SELECT * FROM %s.%s WHERE `db_name` = '%s'", - Util::backquote($cfgRelation['db']), - Util::backquote($cfgRelation['column_info']), - $GLOBALS['dbi']->escapeString($db) - ); - - return $this->dbi->tryQuery($pma_transformation_sql); - } - - /** - * Get SQL query for store new transformation details of a VIEW - * - * @param object $pma_transformation_data Result set of SQL execution - * @param array $column_map Details of VIEW columns - * @param string $view_name Name of the VIEW - * @param string $db Database name of the VIEW - * - * @return string SQL query for new transformations - */ - public function getNewTransformationDataSql( - $pma_transformation_data, - array $column_map, - $view_name, - $db - ) { - $cfgRelation = $this->relation->getRelationsParam(); - - // Need to store new transformation details for VIEW - $new_transformations_sql = sprintf( - "INSERT INTO %s.%s (" - . "`db_name`, `table_name`, `column_name`, " - . "`comment`, `mimetype`, `transformation`, " - . "`transformation_options`) VALUES", - Util::backquote($cfgRelation['db']), - Util::backquote($cfgRelation['column_info']) - ); - - $column_count = 0; - $add_comma = false; - - while ($data_row = $this->dbi->fetchAssoc($pma_transformation_data)) { - foreach ($column_map as $column) { - if ($data_row['table_name'] != $column['table_name'] - || $data_row['column_name'] != $column['refering_column'] - ) { - continue; - } - - $new_transformations_sql .= sprintf( - "%s ('%s', '%s', '%s', '%s', '%s', '%s', '%s')", - $add_comma ? ', ' : '', - $db, - $view_name, - isset($column['real_column']) - ? $column['real_column'] - : $column['refering_column'], - $data_row['comment'], - $data_row['mimetype'], - $data_row['transformation'], - $GLOBALS['dbi']->escapeString( - $data_row['transformation_options'] - ) - ); - - $add_comma = true; - $column_count++; - break; - } - - if ($column_count == count($column_map)) { - break; - } - } - - return ($column_count > 0) ? $new_transformations_sql : ''; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Table.php b/srcs/phpmyadmin/libraries/classes/Table.php deleted file mode 100644 index df1fd12..0000000 --- a/srcs/phpmyadmin/libraries/classes/Table.php +++ /dev/null @@ -1,2771 +0,0 @@ -_dbi = $dbi; - $this->_name = $table_name; - $this->_db_name = $db_name; - $this->relation = new Relation($this->_dbi); - } - - /** - * returns table name - * - * @see Table::getName() - * @return string table name - */ - public function __toString() - { - return $this->getName(); - } - - /** - * Table getter - * - * @param string $table_name table name - * @param string $db_name database name - * @param DatabaseInterface|null $dbi database interface for the table - * - * @return Table - */ - public static function get($table_name, $db_name, ?DatabaseInterface $dbi = null) - { - return new Table($table_name, $db_name, $dbi); - } - - /** - * return the last error - * - * @return string the last error - */ - public function getLastError() - { - return end($this->errors); - } - - /** - * return the last message - * - * @return string the last message - */ - public function getLastMessage() - { - return end($this->messages); - } - - /** - * returns table name - * - * @param boolean $backquoted whether to quote name with backticks `` - * - * @return string table name - */ - public function getName($backquoted = false) - { - if ($backquoted) { - return Util::backquote($this->_name); - } - return $this->_name; - } - - /** - * returns database name for this table - * - * @param boolean $backquoted whether to quote name with backticks `` - * - * @return string database name for this table - */ - public function getDbName($backquoted = false) - { - if ($backquoted) { - return 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 - */ - public function getFullName($backquoted = false) - { - return $this->getDbName($backquoted) . '.' - . $this->getName($backquoted); - } - - - /** - * Checks the storage engine used to create table - * - * @param array|string $engine Checks the table engine against an - * array of engine strings or a single string, should be uppercase - * - * @return bool True, if $engine matches the storage engine for the table, - * False otherwise. - */ - public function isEngine($engine) - { - $tbl_storage_engine = $this->getStorageEngine(); - - if (is_array($engine)) { - foreach ($engine as $e) { - if ($e == $tbl_storage_engine) { - return true; - } - } - return false; - } else { - return $tbl_storage_engine == $engine; - } - } - - /** - * returns whether the table is actually a view - * - * @return boolean whether the given is a view - */ - public function isView() - { - $db = $this->_db_name; - $table = $this->_name; - if (empty($db) || empty($table)) { - return false; - } - - // use cached data or load information with SHOW command - if ($this->_dbi->getCachedTableContent([$db, $table]) != null - || $GLOBALS['cfg']['Server']['DisableIS'] - ) { - $type = $this->getStatusInfo('TABLE_TYPE'); - return $type == 'VIEW' || $type == 'SYSTEM VIEW'; - } - - // information_schema tables are 'SYSTEM VIEW's - if ($db == 'information_schema') { - return true; - } - - // query information_schema - $result = $this->_dbi->fetchResult( - "SELECT TABLE_NAME - FROM information_schema.VIEWS - WHERE TABLE_SCHEMA = '" . $this->_dbi->escapeString((string) $db) . "' - AND TABLE_NAME = '" . $this->_dbi->escapeString((string) $table) . "'" - ); - return $result ? true : false; - } - - /** - * Returns whether the table is actually an updatable view - * - * @return boolean whether the given is an updatable view - */ - public function isUpdatableView() - { - if (empty($this->_db_name) || empty($this->_name)) { - return false; - } - - $result = $this->_dbi->fetchResult( - "SELECT TABLE_NAME - FROM information_schema.VIEWS - WHERE TABLE_SCHEMA = '" . $this->_dbi->escapeString($this->_db_name) . "' - AND TABLE_NAME = '" . $this->_dbi->escapeString($this->_name) . "' - AND IS_UPDATABLE = 'YES'" - ); - return $result ? true : false; - } - - /** - * Checks if this is a merge table - * - * If the ENGINE of the table is MERGE or MRG_MYISAM (alias), - * this is a merge table. - * - * @return boolean true if it is a merge table - */ - public function isMerge() - { - return $this->isEngine(['MERGE', 'MRG_MYISAM']); - } - - /** - * Returns full table status info, or specific if $info provided - * this info is collected from information_schema - * - * @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 DatabaseInterface::getTablesFull needs to be merged - * somehow into this class or at least better documented - * - * @return mixed - */ - public function getStatusInfo( - $info = null, - $force_read = false, - $disable_error = false - ) { - $db = $this->_db_name; - $table = $this->_name; - - if (! empty($_SESSION['is_multi_query'])) { - $disable_error = true; - } - - // sometimes there is only one entry (ExactRows) so - // we have to get the table's details - if ($this->_dbi->getCachedTableContent([$db, $table]) == null - || $force_read - || count($this->_dbi->getCachedTableContent([$db, $table])) === 1 - ) { - $this->_dbi->getTablesFull($db, $table); - } - - if ($this->_dbi->getCachedTableContent([$db, $table]) == null) { - // 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 $this->_dbi->getCachedTableContent([$db, $table]); - } - - // array_key_exists allows for null values - if (! array_key_exists( - $info, - $this->_dbi->getCachedTableContent([$db, $table]) - ) - ) { - if (! $disable_error) { - trigger_error( - __('Unknown table status:') . ' ' . $info, - E_USER_WARNING - ); - } - return false; - } - - return $this->_dbi->getCachedTableContent([$db, $table, $info]); - } - - /** - * Returns the Table storage Engine for current table. - * - * @return string Return storage engine info if it is set for - * the selected table else return blank. - */ - public function getStorageEngine() - { - $table_storage_engine = $this->getStatusInfo('ENGINE', false, true); - if ($table_storage_engine === false) { - return ''; - } - return strtoupper((string) $table_storage_engine); - } - - /** - * Returns the comments for current table. - * - * @return string Return comment info if it is set for the selected table or return blank. - */ - public function getComment() - { - $table_comment = $this->getStatusInfo('TABLE_COMMENT', false, true); - if ($table_comment === false) { - return ''; - } - return $table_comment; - } - - /** - * Returns the collation for current table. - * - * @return string Return blank if collation is empty else return the collation info from table info. - */ - public function getCollation() - { - $table_collation = $this->getStatusInfo('TABLE_COLLATION', false, true); - if ($table_collation === false) { - return ''; - } - return $table_collation; - } - - /** - * Returns the info about no of rows for current table. - * - * @return integer Return no of rows info if it is not null for the selected table or return 0. - */ - public function getNumRows() - { - $table_num_row_info = $this->getStatusInfo('TABLE_ROWS', false, true); - if (false === $table_num_row_info) { - $table_num_row_info = $this->_dbi->getTable($this->_db_name, $GLOBALS['showtable']['Name']) - ->countRecords(true); - } - return $table_num_row_info ?: 0 ; - } - - /** - * Returns the Row format for current table. - * - * @return string Return table row format info if it is set for the selected table or return blank. - */ - public function getRowFormat() - { - $table_row_format = $this->getStatusInfo('ROW_FORMAT', false, true); - if ($table_row_format === false) { - return ''; - } - return $table_row_format; - } - - /** - * Returns the auto increment option for current table. - * - * @return integer Return auto increment info if it is set for the selected table or return blank. - */ - public function getAutoIncrement() - { - $table_auto_increment = $this->getStatusInfo('AUTO_INCREMENT', false, true); - return isset($table_auto_increment) ? $table_auto_increment : ''; - } - - /** - * Returns the array for CREATE statement for current table. - * @return array Return options array info if it is set for the selected table or return blank. - */ - public function getCreateOptions() - { - $table_options = $this->getStatusInfo('CREATE_OPTIONS', false, true); - $create_options_tmp = empty($table_options) ? [] : explode(' ', $table_options); - $create_options = []; - // export create options by its name as variables into global namespace - // f.e. pack_keys=1 becomes available as $pack_keys with value of '1' - // unset($pack_keys); - foreach ($create_options_tmp as $each_create_option) { - $each_create_option = explode('=', $each_create_option); - if (isset($each_create_option[1])) { - // ensure there is no ambiguity for PHP 5 and 7 - $create_options[$each_create_option[0]] = $each_create_option[1]; - } - } - // we need explicit DEFAULT value here (different from '0') - $create_options['pack_keys'] = (! isset($create_options['pack_keys']) || strlen($create_options['pack_keys']) == 0) - ? 'DEFAULT' - : $create_options['pack_keys']; - return $create_options; - } - - /** - * generates column specification for ALTER or CREATE TABLE syntax - * - * @param string $name 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 string $virtuality virtuality of the column - * @param string $expression expression for the virtual column - * @param string $move_to new position for column - * @param array $columns_with_index Fields having PRIMARY or UNIQUE KEY indexes - * @param string $oldColumnName Old column name - * - * @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 - */ - public static function generateFieldSpec( - $name, - $type, - $length = '', - $attribute = '', - $collation = '', - $null = false, - $default_type = 'USER_DEFINED', - $default_value = '', - $extra = '', - $comment = '', - $virtuality = '', - $expression = '', - $move_to = '', - $columns_with_index = null, - $oldColumnName = null - ) { - /** @var DatabaseInterface $dbi */ - $dbi = $GLOBALS['dbi']; - $is_timestamp = mb_strpos( - mb_strtoupper($type), - 'TIMESTAMP' - ) !== false; - - $query = Util::backquote($name) . ' ' . $type; - - // allow the possibility of a length for TIME, DATETIME and TIMESTAMP - // (will work on MySQL >= 5.6.4) - // - // MySQL permits a non-standard syntax for FLOAT and DOUBLE, - // see https://dev.mysql.com/doc/refman/5.5/en/floating-point-types.html - // - $pattern = '@^(DATE|TINYBLOB|TINYTEXT|BLOB|TEXT|' - . 'MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|SERIAL|BOOLEAN|UUID)$@i'; - if (strlen($length) !== 0 && ! preg_match($pattern, $type)) { - // Note: The variable $length here can contain several other things - // besides length - ENUM/SET value or length of DECIMAL (eg. 12,3) - // so we can't just convert it to integer - $query .= '(' . $length . ')'; - } - if ($attribute != '') { - $query .= ' ' . $attribute; - - if ($is_timestamp - && false !== stripos($attribute, "TIMESTAMP") - && strlen($length) !== 0 - && $length !== 0 - ) { - $query .= '(' . $length . ')'; - } - } - - // if column is virtual, check if server type is Mysql as only Mysql server - // supports extra column properties - $isVirtualColMysql = $virtuality && in_array(Util::getServerType(), ['MySQL', 'Percona Server']); - // if column is virtual, check if server type is MariaDB as MariaDB server - // supports no extra virtual column properties except CHARACTER SET for text column types - $isVirtualColMariaDB = $virtuality && Util::getServerType() === 'MariaDB'; - - $matches = preg_match( - '@^(TINYTEXT|TEXT|MEDIUMTEXT|LONGTEXT|VARCHAR|CHAR|ENUM|SET)$@i', - $type - ); - if (! empty($collation) && $collation != 'NULL' && $matches) { - $query .= Util::getCharsetQueryPart( - $isVirtualColMariaDB ? preg_replace('~_.+~s', '', $collation) : $collation, - true - ); - } - - if ($virtuality) { - $query .= ' AS (' . $expression . ') ' . $virtuality; - } - - if (! $virtuality || $isVirtualColMysql) { - if ($null !== false) { - if ($null == 'YES') { - $query .= ' NULL'; - } else { - $query .= ' NOT NULL'; - } - } - - if (! $virtuality) { - 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', (string) $default_value)) { - $query .= ' DEFAULT TRUE'; - } elseif (preg_match('/^0|F|FALSE|NO$/i', $default_value)) { - $query .= ' DEFAULT FALSE'; - } else { - // Invalid BOOLEAN value - $query .= ' DEFAULT \'' - . $dbi->escapeString($default_value) . '\''; - } - } elseif ($type == 'BINARY' || $type == 'VARBINARY') { - $query .= ' DEFAULT 0x' . $default_value; - } else { - $query .= ' DEFAULT \'' - . $dbi->escapeString((string) $default_value) . '\''; - } - break; - /** @noinspection PhpMissingBreakStatementInspection */ - case 'NULL': - // If user uncheck null checkbox and not change default value null, - // default value will be ignored. - if ($null !== false && $null !== 'YES') { - break; - } - // else fall-through intended, no break here - case 'CURRENT_TIMESTAMP': - case 'current_timestamp()': - $query .= ' DEFAULT ' . $default_type; - - if (strlen($length) !== 0 - && $length !== 0 - && $is_timestamp - && $default_type !== 'NULL' // Not to be added in case of NULL - ) { - $query .= '(' . $length . ')'; - } - break; - case 'NONE': - default: - break; - } - } - - if (! empty($extra)) { - if ($virtuality) { - $extra = trim(preg_replace('~^\s*AUTO_INCREMENT\s*~is', ' ', $extra)); - } - - $query .= ' ' . $extra; - } - } - - if (! empty($comment)) { - $query .= " COMMENT '" . $dbi->escapeString($comment) . "'"; - } - - // move column - if ($move_to == '-first') { // dash can't appear as part of column name - $query .= ' FIRST'; - } elseif ($move_to != '') { - $query .= ' AFTER ' . Util::backquote($move_to); - } - if (! $virtuality && ! empty($extra)) { - if ($oldColumnName === null) { - if (is_array($columns_with_index) && ! in_array($name, $columns_with_index)) { - $query .= ', add PRIMARY KEY (' . Util::backquote($name) . ')'; - } - } else { - if (is_array($columns_with_index) && ! in_array($oldColumnName, $columns_with_index)) { - $query .= ', add PRIMARY KEY (' . Util::backquote($name) . ')'; - } - } - } - - return $query; - } // end function - - /** - * Checks if the number of records in a table is at least equal to - * $min_records - * - * @param int $min_records Number of records to check for in a table - * - * @return bool True, if at least $min_records exist, False otherwise. - */ - public function checkIfMinRecordsExist($min_records = 0) - { - $check_query = 'SELECT '; - $fieldsToSelect = ''; - - $uniqueFields = $this->getUniqueColumns(true, false); - if (count($uniqueFields) > 0) { - $fieldsToSelect = implode(', ', $uniqueFields); - } else { - $indexedCols = $this->getIndexedColumns(true, false); - if (count($indexedCols) > 0) { - $fieldsToSelect = implode(', ', $indexedCols); - } else { - $fieldsToSelect = '*'; - } - } - - $check_query .= $fieldsToSelect - . ' FROM ' . $this->getFullName(true) - . ' LIMIT ' . $min_records; - - $res = $this->_dbi->tryQuery( - $check_query - ); - - if ($res !== false) { - $num_records = $this->_dbi->numRows($res); - if ($num_records >= $min_records) { - return true; - } - } - - return false; - } - - /** - * Counts and returns (or displays) the number of records in a table - * - * @param bool $force_exact whether to force an exact count - * - * @return mixed the number of records if "retain" param is true, - * otherwise true - */ - public function countRecords($force_exact = false) - { - $is_view = $this->isView(); - $db = $this->_db_name; - $table = $this->_name; - - if ($this->_dbi->getCachedTableContent([$db, $table, 'ExactRows']) != null) { - $row_count = $this->_dbi->getCachedTableContent( - [ - $db, - $table, - 'ExactRows', - ] - ); - return $row_count; - } - $row_count = false; - - if (! $force_exact) { - if (($this->_dbi->getCachedTableContent([$db, $table, 'Rows']) == null) - && ! $is_view - ) { - $tmp_tables = $this->_dbi->getTablesFull($db, $table); - if (isset($tmp_tables[$table])) { - $this->_dbi->cacheTableContent( - [ - $db, - $table, - ], - $tmp_tables[$table] - ); - } - } - if ($this->_dbi->getCachedTableContent([$db, $table, 'Rows']) != null) { - $row_count = $this->_dbi->getCachedTableContent( - [ - $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'] - ) { - return $row_count; - } - - if (! $is_view) { - $row_count = $this->_dbi->fetchValue( - 'SELECT COUNT(*) FROM ' . Util::backquote($db) . '.' - . 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 = false; - } 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 = $this->_dbi->tryQuery( - 'SELECT 1 FROM ' . Util::backquote($db) . '.' - . Util::backquote($table) . ' LIMIT ' - . $GLOBALS['cfg']['MaxExactCountViews'], - DatabaseInterface::CONNECT_USER, - DatabaseInterface::QUERY_STORE - ); - if (! $this->_dbi->getError()) { - $row_count = $this->_dbi->numRows($result); - $this->_dbi->freeResult($result); - } - } - } - if ($row_count) { - $this->_dbi->cacheTableContent([$db, $table, 'ExactRows'], $row_count); - } - - return $row_count; - } // end of the '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 string $virtuality virtuality of the column - * @param string $expression expression for the virtual column - * @param string $move_to new position for column - * @param array $columns_with_index Fields having PRIMARY or UNIQUE KEY indexes - * - * @see Table::generateFieldSpec() - * - * @return string field specification - */ - public static function generateAlter( - $oldcol, - $newcol, - $type, - $length, - $attribute, - $collation, - $null, - $default_type, - $default_value, - $extra, - $comment, - $virtuality, - $expression, - $move_to, - $columns_with_index = null - ) { - return Util::backquote($oldcol) . ' ' - . self::generateFieldSpec( - $newcol, - $type, - $length, - $attribute, - $collation, - $null, - $default_type, - $default_value, - $extra, - $comment, - $virtuality, - $expression, - $move_to, - $columns_with_index, - $oldcol - ); - } // 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|boolean - */ - public static function duplicateInfo( - $work, - $pma_table, - array $get_fields, - array $where_fields, - array $new_fields - ) { - /** @var DatabaseInterface $dbi */ - $dbi = $GLOBALS['dbi']; - $relation = new Relation($dbi); - $last_id = -1; - - if (! isset($GLOBALS['cfgRelation']) || ! $GLOBALS['cfgRelation'][$work]) { - return true; - } - - $select_parts = []; - $row_fields = []; - foreach ($get_fields as $get_field) { - $select_parts[] = Util::backquote($get_field); - $row_fields[$get_field] = 'cc'; - } - - $where_parts = []; - foreach ($where_fields as $_where => $_value) { - $where_parts[] = Util::backquote($_where) . ' = \'' - . $dbi->escapeString((string) $_value) . '\''; - } - - $new_parts = []; - $new_value_parts = []; - foreach ($new_fields as $_where => $_value) { - $new_parts[] = Util::backquote($_where); - $new_value_parts[] = $dbi->escapeString((string) $_value); - } - - $table_copy_query = ' - SELECT ' . implode(', ', $select_parts) . ' - FROM ' . Util::backquote($GLOBALS['cfgRelation']['db']) . '.' - . Util::backquote($GLOBALS['cfgRelation'][$pma_table]) . ' - WHERE ' . implode(' AND ', $where_parts); - - // must use DatabaseInterface::QUERY_STORE here, since we execute - // another query inside the loop - $table_copy_rs = $relation->queryAsControlUser( - $table_copy_query, - true, - DatabaseInterface::QUERY_STORE - ); - - while ($table_copy_row = @$dbi->fetchAssoc($table_copy_rs)) { - $value_parts = []; - foreach ($table_copy_row as $_key => $_val) { - if (isset($row_fields[$_key]) && $row_fields[$_key] == 'cc') { - $value_parts[] = $dbi->escapeString($_val); - } - } - - $new_table_query = 'INSERT IGNORE INTO ' - . Util::backquote($GLOBALS['cfgRelation']['db']) - . '.' . Util::backquote($GLOBALS['cfgRelation'][$pma_table]) - . ' (' . implode(', ', $select_parts) . ', ' - . implode(', ', $new_parts) . ') VALUES (\'' - . implode('\', \'', $value_parts) . '\', \'' - . implode('\', \'', $new_value_parts) . '\')'; - - $relation->queryAsControlUser($new_table_query); - $last_id = $dbi->insertId(); - } // end while - - $dbi->freeResult($table_copy_rs); - - return $last_id; - } // end of 'Table::duplicateInfo()' function - - /** - * Copies or renames table - * - * @param string $source_db source database - * @param string $source_table source table - * @param string|null $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 - */ - public static function moveCopy( - $source_db, - $source_table, - ?string $target_db, - $target_table, - $what, - $move, - $mode - ) { - global $err_url; - /** @var DatabaseInterface $dbi */ - $dbi = $GLOBALS['dbi']; - - $relation = new Relation($dbi); - - // Try moving the tables directly, using native `RENAME` statement. - if ($move && $what == 'data') { - $tbl = new Table($source_table, $source_db); - if ($tbl->rename($target_table, $target_db)) { - $GLOBALS['message'] = $tbl->getLastMessage(); - return true; - } - } - - // Setting required export settings. - $GLOBALS['sql_backquotes'] = 1; - $GLOBALS['asfile'] = 1; - - // Ensuring the target database is valid. - if (! $GLOBALS['dblist']->databases->exists($source_db, $target_db)) { - if (! $GLOBALS['dblist']->databases->exists($source_db)) { - $GLOBALS['message'] = Message::rawError( - sprintf( - __('Source database `%s` was not found!'), - htmlspecialchars($source_db) - ) - ); - } - if (! $GLOBALS['dblist']->databases->exists($target_db)) { - $GLOBALS['message'] = Message::rawError( - sprintf( - __('Target database `%s` was not found!'), - htmlspecialchars($target_db) - ) - ); - } - return false; - } - - /** - * The full name of source table, quoted. - * @var string $source - */ - $source = Util::backquote($source_db) - . '.' . Util::backquote($source_table); - - // If the target database is not specified, the operation is taking - // place in the same database. - if (! isset($target_db) || strlen($target_db) === 0) { - $target_db = $source_db; - } - - // Selecting the database could avoid some problems with replicated - // databases, when moving table from replicated one to not replicated one. - $dbi->selectDb($target_db); - - /** - * The full name of target table, quoted. - * @var string $target - */ - $target = Util::backquote($target_db) - . '.' . Util::backquote($target_table); - - // No table is created when this is a data-only operation. - if ($what != 'dataonly') { - /** - * Instance used for exporting the current structure of the table. - * - * @var ExportSql $export_sql_plugin - */ - $export_sql_plugin = Plugins::getPlugin( - "export", - "sql", - 'libraries/classes/Plugins/Export/', - [ - 'export_type' => 'table', - 'single_table' => false, - ] - ); - - $no_constraints_comments = true; - $GLOBALS['sql_constraints_query'] = ''; - // set the value of global sql_auto_increment variable - if (isset($_POST['sql_auto_increment'])) { - $GLOBALS['sql_auto_increment'] = $_POST['sql_auto_increment']; - } - - /** - * The old structure of the table.. - * @var string $sql_structure - */ - $sql_structure = $export_sql_plugin->getTableDef( - $source_db, - $source_table, - "\n", - $err_url, - false, - false - ); - - unset($no_constraints_comments); - - // ----------------------------------------------------------------- - // Phase 0: Preparing structures used. - - /** - * The destination where the table is moved or copied to. - * @var Expression - */ - $destination = new Expression( - $target_db, - $target_table, - '' - ); - - // Find server's SQL mode so the builder can generate correct - // queries. - // One of the options that alters the behaviour is `ANSI_QUOTES`. - Context::setMode( - $dbi->fetchValue("SELECT @@sql_mode") - ); - - // ----------------------------------------------------------------- - // Phase 1: Dropping existent element of the same name (if exists - // and required). - - if (isset($_POST['drop_if_exists']) - && $_POST['drop_if_exists'] == 'true' - ) { - - /** - * Drop statement used for building the query. - * @var DropStatement $statement - */ - $statement = new DropStatement(); - - $tbl = new Table($target_db, $target_table); - - $statement->options = new OptionsArray( - [ - $tbl->isView() ? 'VIEW' : 'TABLE', - 'IF EXISTS', - ] - ); - - $statement->fields = [$destination]; - - // Building the query. - $drop_query = $statement->build() . ';'; - - // Executing it. - $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; - } - - // ----------------------------------------------------------------- - // Phase 2: Generating the new query of this structure. - - /** - * The parser responsible for parsing the old queries. - * @var Parser $parser - */ - $parser = new Parser($sql_structure); - - if (! empty($parser->statements[0])) { - - /** - * The CREATE statement of this structure. - * @var CreateStatement $statement - */ - $statement = $parser->statements[0]; - - // Changing the destination. - $statement->name = $destination; - - // Building back the query. - $sql_structure = $statement->build() . ';'; - - // Executing it. - $dbi->query($sql_structure); - $GLOBALS['sql_query'] .= "\n" . $sql_structure; - } - - // ----------------------------------------------------------------- - // Phase 3: Adding constraints. - // All constraint names are removed because they must be unique. - - if (($move || isset($GLOBALS['add_constraints'])) - && ! empty($GLOBALS['sql_constraints_query']) - ) { - $parser = new Parser($GLOBALS['sql_constraints_query']); - - /** - * The ALTER statement that generates the constraints. - * @var AlterStatement $statement - */ - $statement = $parser->statements[0]; - - // Changing the altered table to the destination. - $statement->table = $destination; - - // Removing the name of the constraints. - foreach ($statement->altered as $idx => $altered) { - // All constraint names are removed because they must be unique. - if ($altered->options->has('CONSTRAINT')) { - $altered->field = null; - } - } - - // Building back the query. - $GLOBALS['sql_constraints_query'] = $statement->build() . ';'; - - // Executing it. - if ($mode == 'one_table') { - $dbi->query($GLOBALS['sql_constraints_query']); - } - $GLOBALS['sql_query'] .= "\n" . $GLOBALS['sql_constraints_query']; - if ($mode == 'one_table') { - unset($GLOBALS['sql_constraints_query']); - } - } - - // ----------------------------------------------------------------- - // Phase 4: Adding indexes. - // View phase 3. - - if (! empty($GLOBALS['sql_indexes'])) { - $parser = new Parser($GLOBALS['sql_indexes']); - - $GLOBALS['sql_indexes'] = ''; - /** - * The ALTER statement that generates the indexes. - * @var AlterStatement $statement - */ - foreach ($parser->statements as $statement) { - // Changing the altered table to the destination. - $statement->table = $destination; - - // Removing the name of the constraints. - foreach ($statement->altered as $idx => $altered) { - // All constraint names are removed because they must be unique. - if ($altered->options->has('CONSTRAINT')) { - $altered->field = null; - } - } - - // Building back the query. - $sql_index = $statement->build() . ';'; - - // Executing it. - if ($mode == 'one_table' || $mode == 'db_copy') { - $dbi->query($sql_index); - } - - $GLOBALS['sql_indexes'] .= $sql_index; - } - - $GLOBALS['sql_query'] .= "\n" . $GLOBALS['sql_indexes']; - if ($mode == 'one_table' || $mode == 'db_copy') { - unset($GLOBALS['sql_indexes']); - } - } - - // ----------------------------------------------------------------- - // Phase 5: Adding AUTO_INCREMENT. - - if (! empty($GLOBALS['sql_auto_increments'])) { - if ($mode == 'one_table' || $mode == 'db_copy') { - $parser = new Parser($GLOBALS['sql_auto_increments']); - - /** - * The ALTER statement that alters the AUTO_INCREMENT value. - * @var AlterStatement $statement - */ - $statement = $parser->statements[0]; - - // Changing the altered table to the destination. - $statement->table = $destination; - - // Building back the query. - $GLOBALS['sql_auto_increments'] = $statement->build() . ';'; - - // Executing it. - $dbi->query($GLOBALS['sql_auto_increments']); - $GLOBALS['sql_query'] .= "\n" . $GLOBALS['sql_auto_increments']; - unset($GLOBALS['sql_auto_increments']); - } - } - } else { - $GLOBALS['sql_query'] = ''; - } - - $_table = new Table($target_table, $target_db); - // Copy the data unless this is a VIEW - if (($what == 'data' || $what == 'dataonly') - && ! $_table->isView() - ) { - $sql_set_mode = "SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO'"; - $dbi->query($sql_set_mode); - $GLOBALS['sql_query'] .= "\n\n" . $sql_set_mode . ';'; - - $_old_table = new Table($source_table, $source_db); - $nonGeneratedCols = $_old_table->getNonGeneratedColumns(true); - if (count($nonGeneratedCols) > 0) { - $sql_insert_data = 'INSERT INTO ' . $target . '(' - . implode(', ', $nonGeneratedCols) - . ') SELECT ' . implode(', ', $nonGeneratedCols) - . ' FROM ' . $source; - - $dbi->query($sql_insert_data); - $GLOBALS['sql_query'] .= "\n\n" . $sql_insert_data . ';'; - } - } - - $relation->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 - $dbi->selectDb($source_db); - - $_source_table = new Table($source_table, $source_db); - if ($_source_table->isView()) { - $sql_drop_query = 'DROP VIEW'; - } else { - $sql_drop_query = 'DROP TABLE'; - } - $sql_drop_query .= ' ' . $source; - $dbi->query($sql_drop_query); - - // Renable table in configuration storage - $relation->renameTable( - $source_db, - $target_db, - $source_table, - $target_table - ); - - $GLOBALS['sql_query'] .= "\n\n" . $sql_drop_query . ';'; - // end if ($move) - return true; - } - - // we are copying - // Create new entries as duplicates from old PMA DBs - if ($what == 'dataonly' || isset($maintain_relations)) { - return true; - } - - if ($GLOBALS['cfgRelation']['commwork']) { - // Get all comments and MIME-Types for current table - $comments_copy_rs = $relation->queryAsControlUser( - 'SELECT column_name, comment' - . ($GLOBALS['cfgRelation']['mimework'] - ? ', mimetype, transformation, transformation_options' - : '') - . ' FROM ' - . Util::backquote($GLOBALS['cfgRelation']['db']) - . '.' - . Util::backquote($GLOBALS['cfgRelation']['column_info']) - . ' WHERE ' - . ' db_name = \'' - . $dbi->escapeString($source_db) . '\'' - . ' AND ' - . ' table_name = \'' - . $dbi->escapeString((string) $source_table) . '\'' - ); - - // Write every comment as new copied entry. [MIME] - while ($comments_copy_row - = $dbi->fetchAssoc($comments_copy_rs)) { - $new_comment_query = 'REPLACE INTO ' - . Util::backquote($GLOBALS['cfgRelation']['db']) - . '.' . Util::backquote( - $GLOBALS['cfgRelation']['column_info'] - ) - . ' (db_name, table_name, column_name, comment' - . ($GLOBALS['cfgRelation']['mimework'] - ? ', mimetype, transformation, transformation_options' - : '') - . ') VALUES(\'' . $dbi->escapeString($target_db) - . '\',\'' . $dbi->escapeString($target_table) . '\',\'' - . $dbi->escapeString($comments_copy_row['column_name']) - . '\',\'' - . $dbi->escapeString($comments_copy_row['comment']) - . '\'' - . ($GLOBALS['cfgRelation']['mimework'] - ? ',\'' . $dbi->escapeString( - $comments_copy_row['mimetype'] - ) - . '\',\'' . $dbi->escapeString( - $comments_copy_row['transformation'] - ) - . '\',\'' . $dbi->escapeString( - $comments_copy_row['transformation_options'] - ) - . '\'' - : '') - . ')'; - $relation->queryAsControlUser($new_comment_query); - } // end while - $dbi->freeResult($comments_copy_rs); - unset($comments_copy_rs); - } - - // duplicating the bookmarks must not be done here, but - // just once per db - - $get_fields = ['display_field']; - $where_fields = [ - 'db_name' => $source_db, - 'table_name' => $source_table, - ]; - $new_fields = [ - 'db_name' => $target_db, - 'table_name' => $target_table, - ]; - self::duplicateInfo( - 'displaywork', - 'table_info', - $get_fields, - $where_fields, - $new_fields - ); - - /** - * @todo revise this code when we support cross-db relations - */ - $get_fields = [ - 'master_field', - 'foreign_table', - 'foreign_field', - ]; - $where_fields = [ - 'master_db' => $source_db, - 'master_table' => $source_table, - ]; - $new_fields = [ - 'master_db' => $target_db, - 'foreign_db' => $target_db, - 'master_table' => $target_table, - ]; - self::duplicateInfo( - 'relwork', - 'relation', - $get_fields, - $where_fields, - $new_fields - ); - - $get_fields = [ - 'foreign_field', - 'master_table', - 'master_field', - ]; - $where_fields = [ - 'foreign_db' => $source_db, - 'foreign_table' => $source_table, - ]; - $new_fields = [ - 'master_db' => $target_db, - 'foreign_db' => $target_db, - 'foreign_table' => $target_table, - ]; - self::duplicateInfo( - 'relwork', - 'relation', - $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 = self::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 - ); - self::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 - * @param boolean $is_backquoted whether this name is used inside backquotes or not - * - * @todo add check for valid chars in filename on current system/os - * @see https://dev.mysql.com/doc/refman/5.0/en/legal-names.html - * - * @return boolean whether the string is valid or not - */ - public static function isValidName($table_name, $is_backquoted = false) - { - if ($table_name !== rtrim((string) $table_name)) { - // trailing spaces not allowed even in backquotes - return false; - } - - if (strlen($table_name) === 0) { - // zero length - return false; - } - - if (! $is_backquoted && $table_name !== trim($table_name)) { - // spaces at the start or in between only allowed inside backquotes - return false; - } - - if (! $is_backquoted && preg_match('/^[a-zA-Z0-9_$]+$/', $table_name)) { - // only allow the above regex in unquoted identifiers - // see : https://dev.mysql.com/doc/refman/5.7/en/identifiers.html - return true; - } elseif ($is_backquoted) { - // If backquoted, all characters should be allowed (except w/ trailing spaces) - return true; - } - - // If not backquoted and doesn't follow the above regex - return false; - } - - /** - * renames table - * - * @param string $new_name new table name - * @param string $new_db new database name - * - * @return bool success - */ - public function rename($new_name, $new_db = null) - { - if ($this->_dbi->getLowerCaseNames() === '1') { - $new_name = strtolower($new_name); - } - - if (null !== $new_db && $new_db !== $this->getDbName()) { - // Ensure the target is valid - if (! $GLOBALS['dblist']->databases->exists($new_db)) { - $this->errors[] = __('Invalid database:') . ' ' . $new_db; - return false; - } - } else { - $new_db = $this->getDbName(); - } - - $new_table = new Table($new_name, $new_db); - - if ($this->getFullName() === $new_table->getFullName()) { - return true; - } - - // Allow whitespaces (not trailing) in $new_name, - // since we are using $backquoted in getting the fullName of table - // below to be used in the query - if (! self::isValidName($new_name, true)) { - $this->errors[] = __('Invalid table name:') . ' ' - . $new_table->getFullName(); - return false; - } - - // If the table is moved to a different database drop its triggers first - $triggers = $this->_dbi->getTriggers( - $this->getDbName(), - $this->getName(), - '' - ); - $handle_triggers = $this->getDbName() != $new_db && $triggers; - if ($handle_triggers) { - foreach ($triggers as $trigger) { - $sql = 'DROP TRIGGER IF EXISTS ' - . Util::backquote($this->getDbName()) - . '.' . Util::backquote($trigger['name']) . ';'; - $this->_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 (! $this->_dbi->query($GLOBALS['sql_query'])) { - // Restore triggers in the old database - if ($handle_triggers) { - $this->_dbi->selectDb($this->getDbName()); - foreach ($triggers as $trigger) { - $this->_dbi->query($trigger['create']); - } - } - $this->errors[] = sprintf( - __('Failed to rename table %1$s to %2$s!'), - $this->getFullName(), - $new_table->getFullName() - ); - return false; - } - - $old_name = $this->getName(); - $old_db = $this->getDbName(); - $this->_name = $new_name; - $this->_db_name = $new_db; - - // Renable table in configuration storage - $this->relation->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 unique 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 `` - * @param bool $fullName whether to include full name of the table as a prefix - * - * @return array - */ - public function getUniqueColumns($backquoted = true, $fullName = true) - { - $sql = $this->_dbi->getTableIndexesSql( - $this->getDbName(), - $this->getName(), - 'Non_unique = 0' - ); - $uniques = $this->_dbi->fetchResult( - $sql, - [ - 'Key_name', - null, - ], - 'Column_name' - ); - - $return = []; - foreach ($uniques as $index) { - if (count($index) > 1) { - continue; - } - if ($fullName) { - $possible_column = $this->getFullName($backquoted) . '.'; - } else { - $possible_column = ''; - } - if ($backquoted) { - $possible_column .= Util::backquote($index[0]); - } else { - $possible_column .= $index[0]; - } - // a column might have a primary and an unique index on it - if (! in_array($possible_column, $return)) { - $return[] = $possible_column; - } - } - - return $return; - } - - /** - * Formats lists of columns - * - * returns an array with all columns that make use of an index - * - * e.g. index(col1, col2) would return col1, col2 - * - * @param array $indexed column data - * @param bool $backquoted whether to quote name with backticks `` - * @param bool $fullName whether to include full name of the table as a prefix - * - * @return array - */ - private function _formatColumns(array $indexed, $backquoted, $fullName) - { - $return = []; - foreach ($indexed as $column) { - $return[] = ($fullName ? $this->getFullName($backquoted) . '.' : '') - . ($backquoted ? Util::backquote($column) : $column); - } - - return $return; - } - - /** - * Get all indexed columns - * - * returns an array with all columns that make use of an index - * - * e.g. index(col1, col2) would return col1, col2 - * - * @param bool $backquoted whether to quote name with backticks `` - * @param bool $fullName whether to include full name of the table as a prefix - * - * @return array - */ - public function getIndexedColumns($backquoted = true, $fullName = true) - { - $sql = $this->_dbi->getTableIndexesSql( - $this->getDbName(), - $this->getName(), - '' - ); - $indexed = $this->_dbi->fetchResult($sql, 'Column_name', 'Column_name'); - - return $this->_formatColumns($indexed, $backquoted, $fullName); - } - - /** - * Get all columns - * - * returns an array with all columns - * - * @param bool $backquoted whether to quote name with backticks `` - * @param bool $fullName whether to include full name of the table as a prefix - * - * @return array - */ - public function getColumns($backquoted = true, $fullName = true) - { - $sql = 'SHOW COLUMNS FROM ' . $this->getFullName(true); - $indexed = $this->_dbi->fetchResult($sql, 'Field', 'Field'); - - return $this->_formatColumns($indexed, $backquoted, $fullName); - } - - /** - * Get meta info for fields in table - * - * @return mixed - */ - public function getColumnsMeta() - { - $move_columns_sql_query = sprintf( - 'SELECT * FROM %s.%s LIMIT 1', - Util::backquote($this->_db_name), - Util::backquote($this->_name) - ); - $move_columns_sql_result = $this->_dbi->tryQuery($move_columns_sql_query); - if ($move_columns_sql_result !== false) { - return $this->_dbi->getFieldsMeta($move_columns_sql_result); - } else { - // unsure how to reproduce but it was seen on the reporting server - return []; - } - } - - /** - * Get non-generated columns in table - * - * @param bool $backquoted whether to quote name with backticks `` - * - * @return array - */ - public function getNonGeneratedColumns($backquoted = true) - { - $columns_meta_query = 'SHOW COLUMNS FROM ' . $this->getFullName(true); - $ret = []; - - $columns_meta_query_result = $this->_dbi->fetchResult( - $columns_meta_query - ); - - if ($columns_meta_query_result - && $columns_meta_query_result !== false - ) { - foreach ($columns_meta_query_result as $column) { - $value = $column['Field']; - if ($backquoted === true) { - $value = Util::backquote($value); - } - - if (( - strpos($column['Extra'], 'GENERATED') === false - && strpos($column['Extra'], 'VIRTUAL') === false - ) || $column['Extra'] === 'DEFAULT_GENERATED') { - $ret[] = $value; - } - } - } - - return $ret; - } - - /** - * Return UI preferences for this table from phpMyAdmin database. - * - * @return array - */ - protected function getUiPrefsFromDb() - { - $cfgRelation = $this->relation->getRelationsParam(); - $pma_table = Util::backquote($cfgRelation['db']) . "." - . Util::backquote($cfgRelation['table_uiprefs']); - - // Read from phpMyAdmin database - $sql_query = " SELECT `prefs` FROM " . $pma_table - . " WHERE `username` = '" . $this->_dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "'" - . " AND `db_name` = '" . $this->_dbi->escapeString($this->_db_name) . "'" - . " AND `table_name` = '" . $this->_dbi->escapeString($this->_name) . "'"; - - $row = $this->_dbi->fetchArray($this->relation->queryAsControlUser($sql_query)); - if (isset($row[0])) { - return json_decode($row[0], true); - } - - return []; - } - - /** - * Save this table's UI preferences into phpMyAdmin database. - * - * @return true|Message - */ - protected function saveUiPrefsToDb() - { - $cfgRelation = $this->relation->getRelationsParam(); - $pma_table = Util::backquote($cfgRelation['db']) . "." - . Util::backquote($cfgRelation['table_uiprefs']); - - $secureDbName = $this->_dbi->escapeString($this->_db_name); - - $username = $GLOBALS['cfg']['Server']['user']; - $sql_query = " REPLACE INTO " . $pma_table - . " (username, db_name, table_name, prefs) VALUES ('" - . $this->_dbi->escapeString($username) . "', '" . $secureDbName - . "', '" . $this->_dbi->escapeString($this->_name) . "', '" - . $this->_dbi->escapeString(json_encode($this->uiprefs)) . "')"; - - $success = $this->_dbi->tryQuery($sql_query, DatabaseInterface::CONNECT_CONTROL); - - if (! $success) { - $message = Message::error( - __('Could not save table UI preferences!') - ); - $message->addMessage( - Message::rawError( - $this->_dbi->getError(DatabaseInterface::CONNECT_CONTROL) - ), - '

    ' - ); - 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 = $this->_dbi->fetchValue($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 = $this->_dbi->tryQuery( - $sql_query, - DatabaseInterface::CONNECT_CONTROL - ); - - if (! $success) { - $message = Message::error( - sprintf( - __( - 'Failed to cleanup table UI preferences (see ' . - '$cfg[\'Servers\'][$i][\'MaxTableUiprefs\'] %s)' - ), - Util::showDocu('config', 'cfg_Servers_MaxTableUiprefs') - ) - ); - $message->addMessage( - Message::rawError( - $this->_dbi->getError(DatabaseInterface::CONNECT_CONTROL) - ), - '

    ' - ); - 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() - { - $cfgRelation = $this->relation->getRelationsParam(); - $server_id = $GLOBALS['server']; - - // set session variable if it's still undefined - if (! isset($_SESSION['tmpval']['table_uiprefs'][$server_id][$this->_db_name][$this->_name])) { - // check whether we can get from pmadb - $_SESSION['tmpval']['table_uiprefs'][$server_id][$this->_db_name][$this->_name] = $cfgRelation['uiprefswork'] - ? $this->getUiPrefsFromDb() - : []; - } - $this->uiprefs =& $_SESSION['tmpval']['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])) { - return false; - } - - if (! isset($_POST['discard_remembered_sort'])) { - // check if the column name exists in this table - $tmp = explode(' ', $this->uiprefs[$property]); - $colname = $tmp[0]; - //remove backquoting from colname - $colname = str_replace('`', '', $colname); - //get the available column name without backquoting - $avail_columns = $this->getColumns(false); - - foreach ($avail_columns as $each_col) { - // check if $each_col ends with $colname - if (substr_compare( - $each_col, - $colname, - mb_strlen($each_col) - mb_strlen($colname) - ) === 0 - ) { - return $this->uiprefs[$property]; - } - } - } - // remove the property, since it no longer exists in database - $this->removeUiProp($property); - return false; - } - - if ($property == self::PROP_COLUMN_ORDER - || $property == self::PROP_COLUMN_VISIB - ) { - if ($this->isView() || ! isset($this->uiprefs[$property])) { - return false; - } - - // check if the table has not been modified - if ($this->getStatusInfo('Create_time') == $this->uiprefs['CREATE_TIME'] - ) { - return array_map('intval', $this->uiprefs[$property]); - } - - // remove the property, since the table has been modified - $this->removeUiProp($property); - 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|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 (! $this->isView() - && ($property == self::PROP_COLUMN_ORDER - || $property == self::PROP_COLUMN_VISIB) - ) { - $curr_create_time = $this->getStatusInfo('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 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 - $cfgRelation = $this->relation->getRelationsParam(); - if ($cfgRelation['uiprefswork']) { - return $this->saveUiPrefsToDb(); - } - return true; - } - - /** - * Remove a property from UI preferences. - * - * @param string $property the property - * - * @return true|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 - $cfgRelation = $this->relation->getRelationsParam(); - if ($cfgRelation['uiprefswork']) { - return $this->saveUiPrefsToDb(); - } - } - return true; - } - - /** - * Get all column names which are MySQL reserved words - * - * @return array - * @access public - */ - public function getReservedColumnNames() - { - $columns = $this->getColumns(false); - $return = []; - foreach ($columns as $column) { - $temp = explode('.', $column); - $column_name = $temp[2]; - if (Context::isKeyword($column_name, true)) { - $return[] = $column_name; - } - } - return $return; - } - - /** - * Function to get the name and type of the columns of a table - * - * @return array - */ - public function getNameAndTypeOfTheColumns() - { - $columns = []; - foreach ($this->_dbi->getColumnsFull( - $this->_db_name, - $this->_name - ) as $row) { - if (preg_match('@^(set|enum)\((.+)\)$@i', $row['Type'], $tmp)) { - $tmp[2] = mb_substr( - preg_replace('@([^,])\'\'@', '\\1\\\'', ',' . $tmp[2]), - 1 - ); - $columns[$row['Field']] = $tmp[1] . '(' - . str_replace(',', ', ', $tmp[2]) . ')'; - } else { - $columns[$row['Field']] = $row['Type']; - } - } - return $columns; - } - - /** - * Get index with index name - * - * @param string $index Index name - * - * @return Index - */ - public function getIndex($index) - { - return Index::singleton($this->_db_name, $this->_name, $index); - } - - /** - * Function to get the sql query for index creation or edit - * - * @param Index $index current index - * @param bool $error whether error occurred or not - * - * @return string - */ - public function getSqlQueryForIndexCreateOrEdit($index, &$error) - { - // $sql_query is the one displayed in the query box - $sql_query = sprintf( - 'ALTER TABLE %s.%s', - Util::backquote($this->_db_name), - Util::backquote($this->_name) - ); - - // Drops the old index - if (! empty($_POST['old_index'])) { - if ($_POST['old_index'] == 'PRIMARY') { - $sql_query .= ' DROP PRIMARY KEY,'; - } else { - $sql_query .= sprintf( - ' DROP INDEX %s,', - Util::backquote($_POST['old_index']) - ); - } - } // end if - - // Builds the new one - switch ($index->getChoice()) { - case 'PRIMARY': - if ($index->getName() == '') { - $index->setName('PRIMARY'); - } elseif ($index->getName() != 'PRIMARY') { - $error = Message::error( - __('The name of the primary key must be "PRIMARY"!') - ); - } - $sql_query .= ' ADD PRIMARY KEY'; - break; - case 'FULLTEXT': - case 'UNIQUE': - case 'INDEX': - case 'SPATIAL': - if ($index->getName() == 'PRIMARY') { - $error = Message::error( - __('Can\'t rename index to PRIMARY!') - ); - } - $sql_query .= sprintf( - ' ADD %s ', - $index->getChoice() - ); - if ($index->getName()) { - $sql_query .= Util::backquote($index->getName()); - } - break; - } // end switch - - $index_fields = []; - foreach ($index->getColumns() as $key => $column) { - $index_fields[$key] = Util::backquote($column->getName()); - if ($column->getSubPart()) { - $index_fields[$key] .= '(' . $column->getSubPart() . ')'; - } - } // end while - - if (empty($index_fields)) { - $error = Message::error(__('No index parts defined!')); - } else { - $sql_query .= ' (' . implode(', ', $index_fields) . ')'; - } - - $keyBlockSizes = $index->getKeyBlockSize(); - if (! empty($keyBlockSizes)) { - $sql_query .= sprintf( - ' KEY_BLOCK_SIZE = %s', - $this->_dbi->escapeString($keyBlockSizes) - ); - } - - // specifying index type is allowed only for primary, unique and index only - // TokuDB is using Fractal Tree, Using Type is not useless - // Ref: https://mariadb.com/kb/en/mariadb/storage-engine-index-types/ - $type = $index->getType(); - if ($index->getChoice() != 'SPATIAL' - && $index->getChoice() != 'FULLTEXT' - && in_array($type, Index::getIndexTypes()) - && ! $this->isEngine(['TOKUDB']) - ) { - $sql_query .= ' USING ' . $type; - } - - $parser = $index->getParser(); - if ($index->getChoice() == 'FULLTEXT' && ! empty($parser)) { - $sql_query .= ' WITH PARSER ' . $this->_dbi->escapeString($parser); - } - - $comment = $index->getComment(); - if (! empty($comment)) { - $sql_query .= sprintf( - " COMMENT '%s'", - $this->_dbi->escapeString($comment) - ); - } - - $sql_query .= ';'; - - return $sql_query; - } - - /** - * Function to handle update for display field - * - * @param string $display_field display field - * @param array $cfgRelation configuration relation - * - * @return boolean True on update succeed or False on failure - */ - public function updateDisplayField($display_field, array $cfgRelation) - { - $upd_query = false; - if ($display_field == '') { - $upd_query = 'DELETE FROM ' - . Util::backquote($GLOBALS['cfgRelation']['db']) - . '.' . Util::backquote($cfgRelation['table_info']) - . ' WHERE db_name = \'' - . $this->_dbi->escapeString($this->_db_name) . '\'' - . ' AND table_name = \'' - . $this->_dbi->escapeString($this->_name) . '\''; - } else { - $upd_query = 'REPLACE INTO ' - . Util::backquote($GLOBALS['cfgRelation']['db']) - . '.' . Util::backquote($cfgRelation['table_info']) - . '(db_name, table_name, display_field) VALUES(' - . '\'' . $this->_dbi->escapeString($this->_db_name) . '\',' - . '\'' . $this->_dbi->escapeString($this->_name) . '\',' - . '\'' . $this->_dbi->escapeString($display_field) . '\')'; - } - - if ($upd_query) { - $this->_dbi->query( - $upd_query, - DatabaseInterface::CONNECT_CONTROL, - 0, - false - ); - return true; - } - return false; - } - - /** - * Function to get update query for updating internal relations - * - * @param array $multi_edit_columns_name multi edit column names - * @param array $destination_db destination tables - * @param array $destination_table destination tables - * @param array $destination_column destination columns - * @param array $cfgRelation configuration relation - * @param array|null $existrel db, table, column - * - * @return boolean - */ - public function updateInternalRelations( - array $multi_edit_columns_name, - array $destination_db, - array $destination_table, - array $destination_column, - array $cfgRelation, - $existrel - ) { - $updated = false; - foreach ($destination_db as $master_field_md5 => $foreign_db) { - $upd_query = null; - // Map the fieldname's md5 back to its real name - $master_field = $multi_edit_columns_name[$master_field_md5]; - $foreign_table = $destination_table[$master_field_md5]; - $foreign_field = $destination_column[$master_field_md5]; - if (! empty($foreign_db) - && ! empty($foreign_table) - && ! empty($foreign_field) - ) { - if (! isset($existrel[$master_field])) { - $upd_query = 'INSERT INTO ' - . Util::backquote($GLOBALS['cfgRelation']['db']) - . '.' . Util::backquote($cfgRelation['relation']) - . '(master_db, master_table, master_field, foreign_db,' - . ' foreign_table, foreign_field)' - . ' values(' - . '\'' . $this->_dbi->escapeString($this->_db_name) . '\', ' - . '\'' . $this->_dbi->escapeString($this->_name) . '\', ' - . '\'' . $this->_dbi->escapeString($master_field) . '\', ' - . '\'' . $this->_dbi->escapeString($foreign_db) . '\', ' - . '\'' . $this->_dbi->escapeString($foreign_table) . '\',' - . '\'' . $this->_dbi->escapeString($foreign_field) . '\')'; - } elseif ($existrel[$master_field]['foreign_db'] != $foreign_db - || $existrel[$master_field]['foreign_table'] != $foreign_table - || $existrel[$master_field]['foreign_field'] != $foreign_field - ) { - $upd_query = 'UPDATE ' - . Util::backquote($GLOBALS['cfgRelation']['db']) - . '.' . Util::backquote($cfgRelation['relation']) - . ' SET foreign_db = \'' - . $this->_dbi->escapeString($foreign_db) . '\', ' - . ' foreign_table = \'' - . $this->_dbi->escapeString($foreign_table) . '\', ' - . ' foreign_field = \'' - . $this->_dbi->escapeString($foreign_field) . '\' ' - . ' WHERE master_db = \'' - . $this->_dbi->escapeString($this->_db_name) . '\'' - . ' AND master_table = \'' - . $this->_dbi->escapeString($this->_name) . '\'' - . ' AND master_field = \'' - . $this->_dbi->escapeString($master_field) . '\''; - } // end if... else.... - } elseif (isset($existrel[$master_field])) { - $upd_query = 'DELETE FROM ' - . Util::backquote($GLOBALS['cfgRelation']['db']) - . '.' . Util::backquote($cfgRelation['relation']) - . ' WHERE master_db = \'' - . $this->_dbi->escapeString($this->_db_name) . '\'' - . ' AND master_table = \'' - . $this->_dbi->escapeString($this->_name) . '\'' - . ' AND master_field = \'' - . $this->_dbi->escapeString($master_field) . '\''; - } // end if... else.... - - if (isset($upd_query)) { - $this->_dbi->query( - $upd_query, - DatabaseInterface::CONNECT_CONTROL, - 0, - false - ); - $updated = true; - } - } - return $updated; - } - - /** - * Function to handle foreign key updates - * - * @param array $destination_foreign_db destination foreign database - * @param array $multi_edit_columns_name multi edit column names - * @param array $destination_foreign_table destination foreign table - * @param array $destination_foreign_column destination foreign column - * @param array $options_array options array - * @param string $table current table - * @param array $existrel_foreign db, table, column - * - * @return array - */ - public function updateForeignKeys( - array $destination_foreign_db, - array $multi_edit_columns_name, - array $destination_foreign_table, - array $destination_foreign_column, - array $options_array, - $table, - array $existrel_foreign - ) { - $html_output = ''; - $preview_sql_data = ''; - $display_query = ''; - $seen_error = false; - - foreach ($destination_foreign_db as $master_field_md5 => $foreign_db) { - $create = false; - $drop = false; - - // Map the fieldname's md5 back to its real name - $master_field = $multi_edit_columns_name[$master_field_md5]; - - $foreign_table = $destination_foreign_table[$master_field_md5]; - $foreign_field = $destination_foreign_column[$master_field_md5]; - - if (isset($existrel_foreign[$master_field_md5]['ref_db_name'])) { - $ref_db_name = $existrel_foreign[$master_field_md5]['ref_db_name']; - } else { - $ref_db_name = $GLOBALS['db']; - } - - $empty_fields = false; - foreach ($master_field as $key => $one_field) { - if ((! empty($one_field) && empty($foreign_field[$key])) - || (empty($one_field) && ! empty($foreign_field[$key])) - ) { - $empty_fields = true; - } - - if (empty($one_field) && empty($foreign_field[$key])) { - unset($master_field[$key]); - unset($foreign_field[$key]); - } - } - - if (! empty($foreign_db) - && ! empty($foreign_table) - && ! $empty_fields - ) { - if (isset($existrel_foreign[$master_field_md5])) { - $constraint_name - = $existrel_foreign[$master_field_md5]['constraint']; - $on_delete = ! empty( - $existrel_foreign[$master_field_md5]['on_delete'] - ) - ? $existrel_foreign[$master_field_md5]['on_delete'] - : 'RESTRICT'; - $on_update = ! empty( - $existrel_foreign[$master_field_md5]['on_update'] - ) - ? $existrel_foreign[$master_field_md5]['on_update'] - : 'RESTRICT'; - - if ($ref_db_name != $foreign_db - || $existrel_foreign[$master_field_md5]['ref_table_name'] != $foreign_table - || $existrel_foreign[$master_field_md5]['ref_index_list'] != $foreign_field - || $existrel_foreign[$master_field_md5]['index_list'] != $master_field - || $_POST['constraint_name'][$master_field_md5] != $constraint_name - || ($_POST['on_delete'][$master_field_md5] != $on_delete) - || ($_POST['on_update'][$master_field_md5] != $on_update) - ) { - // another foreign key is already defined for this field - // or an option has been changed for ON DELETE or ON UPDATE - $drop = true; - $create = true; - } // end if... else.... - } else { - // no key defined for this field(s) - $create = true; - } - } elseif (isset($existrel_foreign[$master_field_md5])) { - $drop = true; - } // end if... else.... - - $tmp_error_drop = false; - if ($drop) { - $drop_query = 'ALTER TABLE ' . Util::backquote($table) - . ' DROP FOREIGN KEY ' - . Util::backquote( - $existrel_foreign[$master_field_md5]['constraint'] - ) - . ';'; - - if (! isset($_POST['preview_sql'])) { - $display_query .= $drop_query . "\n"; - $this->_dbi->tryQuery($drop_query); - $tmp_error_drop = $this->_dbi->getError(); - - if (! empty($tmp_error_drop)) { - $seen_error = true; - $html_output .= Util::mysqlDie( - $tmp_error_drop, - $drop_query, - false, - '', - false - ); - continue; - } - } else { - $preview_sql_data .= $drop_query . "\n"; - } - } - $tmp_error_create = false; - if (! $create) { - continue; - } - - $create_query = $this->_getSQLToCreateForeignKey( - $table, - $master_field, - $foreign_db, - $foreign_table, - $foreign_field, - $_POST['constraint_name'][$master_field_md5], - $options_array[$_POST['on_delete'][$master_field_md5]], - $options_array[$_POST['on_update'][$master_field_md5]] - ); - - if (! isset($_POST['preview_sql'])) { - $display_query .= $create_query . "\n"; - $this->_dbi->tryQuery($create_query); - $tmp_error_create = $this->_dbi->getError(); - if (! empty($tmp_error_create)) { - $seen_error = true; - - if (substr($tmp_error_create, 1, 4) == '1005') { - $message = Message::error( - __( - 'Error creating foreign key on %1$s (check data ' . - 'types)' - ) - ); - $message->addParam(implode(', ', $master_field)); - $html_output .= $message->getDisplay(); - } else { - $html_output .= Util::mysqlDie( - $tmp_error_create, - $create_query, - false, - '', - false - ); - } - $html_output .= Util::showMySQLDocu( - 'InnoDB_foreign_key_constraints' - ) . "\n"; - } - } else { - $preview_sql_data .= $create_query . "\n"; - } - - // this is an alteration and the old constraint has been dropped - // without creation of a new one - if ($drop && $create && empty($tmp_error_drop) - && ! empty($tmp_error_create) - ) { - // a rollback may be better here - $sql_query_recreate = '# Restoring the dropped constraint...' . "\n"; - $sql_query_recreate .= $this->_getSQLToCreateForeignKey( - $table, - $master_field, - $existrel_foreign[$master_field_md5]['ref_db_name'], - $existrel_foreign[$master_field_md5]['ref_table_name'], - $existrel_foreign[$master_field_md5]['ref_index_list'], - $existrel_foreign[$master_field_md5]['constraint'], - $options_array[$existrel_foreign[$master_field_md5]['on_delete']], - $options_array[$existrel_foreign[$master_field_md5]['on_update']] - ); - if (! isset($_POST['preview_sql'])) { - $display_query .= $sql_query_recreate . "\n"; - $this->_dbi->tryQuery($sql_query_recreate); - } else { - $preview_sql_data .= $sql_query_recreate; - } - } - } // end foreach - - return [ - $html_output, - $preview_sql_data, - $display_query, - $seen_error, - ]; - } - - /** - * Returns the SQL query for foreign key constraint creation - * - * @param string $table table name - * @param array $field field names - * @param string $foreignDb foreign database name - * @param string $foreignTable foreign table name - * @param array $foreignField foreign field names - * @param string $name name of the constraint - * @param string $onDelete on delete action - * @param string $onUpdate on update action - * - * @return string SQL query for foreign key constraint creation - */ - private function _getSQLToCreateForeignKey( - $table, - array $field, - $foreignDb, - $foreignTable, - array $foreignField, - $name = null, - $onDelete = null, - $onUpdate = null - ) { - $sql_query = 'ALTER TABLE ' . Util::backquote($table) . ' ADD '; - // if user entered a constraint name - if (! empty($name)) { - $sql_query .= ' CONSTRAINT ' . Util::backquote($name); - } - - foreach ($field as $key => $one_field) { - $field[$key] = Util::backquote($one_field); - } - foreach ($foreignField as $key => $one_field) { - $foreignField[$key] = Util::backquote($one_field); - } - $sql_query .= ' FOREIGN KEY (' . implode(', ', $field) . ') REFERENCES ' - . ($this->_db_name != $foreignDb - ? Util::backquote($foreignDb) . '.' : '') - . Util::backquote($foreignTable) - . '(' . implode(', ', $foreignField) . ')'; - - if (! empty($onDelete)) { - $sql_query .= ' ON DELETE ' . $onDelete; - } - if (! empty($onUpdate)) { - $sql_query .= ' ON UPDATE ' . $onUpdate; - } - $sql_query .= ';'; - - return $sql_query; - } - - /** - * Returns the generation expression for virtual columns - * - * @param string $column name of the column - * - * @return array|boolean associative array of column name and their expressions - * or false on failure - */ - public function getColumnGenerationExpression($column = null) - { - $serverType = Util::getServerType(); - if ($serverType == 'MySQL' - && $this->_dbi->getVersion() > 50705 - && ! $GLOBALS['cfg']['Server']['DisableIS'] - ) { - $sql - = "SELECT - `COLUMN_NAME` AS `Field`, - `GENERATION_EXPRESSION` AS `Expression` - FROM - `information_schema`.`COLUMNS` - WHERE - `TABLE_SCHEMA` = '" . $this->_dbi->escapeString($this->_db_name) . "' - AND `TABLE_NAME` = '" . $this->_dbi->escapeString($this->_name) . "'"; - if ($column != null) { - $sql .= " AND `COLUMN_NAME` = '" . $this->_dbi->escapeString($column) - . "'"; - } - return $this->_dbi->fetchResult($sql, 'Field', 'Expression'); - } - - $createTable = $this->showCreate(); - if (! $createTable) { - return false; - } - - $parser = new Parser($createTable); - /** - * @var CreateStatement $stmt - */ - $stmt = $parser->statements[0]; - $fields = TableUtils::getFields($stmt); - if ($column != null) { - $expression = isset($fields[$column]['expr']) ? - substr($fields[$column]['expr'], 1, -1) : ''; - return [$column => $expression]; - } - - $ret = []; - foreach ($fields as $field => $options) { - if (isset($options['expr'])) { - $ret[$field] = substr($options['expr'], 1, -1); - } - } - return $ret; - } - - /** - * Returns the CREATE statement for this table - * - * @return mixed - */ - public function showCreate() - { - return $this->_dbi->fetchValue( - 'SHOW CREATE TABLE ' . Util::backquote($this->_db_name) . '.' - . Util::backquote($this->_name), - 0, - 1 - ); - } - - /** - * Returns the real row count for a table - * - * @return int - */ - public function getRealRowCountTable() - { - // SQL query to get row count for a table. - $result = $this->_dbi->fetchSingleRow( - sprintf( - 'SELECT COUNT(*) AS %s FROM %s.%s', - Util::backquote('row_count'), - Util::backquote($this->_db_name), - Util::backquote($this->_name) - ) - ); - return $result['row_count']; - } - - /** - * Get columns with indexes - * - * @param int $types types bitmask - * - * @return array an array of columns - */ - public function getColumnsWithIndex($types) - { - $columns_with_index = []; - foreach (Index::getFromTableByChoice( - $this->_name, - $this->_db_name, - $types - ) as $index) { - $columns = $index->getColumns(); - foreach ($columns as $column_name => $dummy) { - $columns_with_index[] = $column_name; - } - } - return $columns_with_index; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/TablePartitionDefinition.php b/srcs/phpmyadmin/libraries/classes/TablePartitionDefinition.php deleted file mode 100644 index 89ece4b..0000000 --- a/srcs/phpmyadmin/libraries/classes/TablePartitionDefinition.php +++ /dev/null @@ -1,200 +0,0 @@ - 1 - && isset($partitionDetails['partition_by']) - && ($partitionDetails['partition_by'] === 'RANGE' - || $partitionDetails['partition_by'] === 'RANGE COLUMNS' - || $partitionDetails['partition_by'] === 'LIST' - || $partitionDetails['partition_by'] === 'LIST COLUMNS'); - - // Values are specified only for LIST and RANGE type partitions - $partitionDetails['value_enabled'] = isset($partitionDetails['partition_by']) - && ($partitionDetails['partition_by'] === 'RANGE' - || $partitionDetails['partition_by'] === 'RANGE COLUMNS' - || $partitionDetails['partition_by'] === 'LIST' - || $partitionDetails['partition_by'] === 'LIST COLUMNS'); - - return self::extractPartitions($partitionDetails); - } - - /** - * Extract some partitioning and subpartitioning parameters from the request - * - * @return array - */ - protected static function extractDetailsFromRequest(): array - { - $partitionParams = [ - 'partition_by' => null, - 'partition_expr' => null, - 'subpartition_by' => null, - 'subpartition_expr' => null, - ]; - //Initialize details with values to "null" if not in request - $details = array_merge( - $partitionParams, - //Keep $_POST values, but only for keys that are in $partitionParams - array_intersect_key($_POST, $partitionParams) - ); - - $details['partition_count'] = self::extractPartitionCount('partition_count') ?: ''; - $details['subpartition_count'] = self::extractPartitionCount('subpartition_count') ?: ''; - - return $details; - } - - /** - * @param string $paramLabel Label searched in request - * - * @return int - */ - protected static function extractPartitionCount(string $paramLabel): int - { - if (Core::isValid($_POST[$paramLabel], 'numeric')) { - // MySQL's limit is 8192, so do not allow more - $count = min((int) $_POST[$paramLabel], 8192); - } else { - $count = 0; - } - return $count; - } - - /** - * @param array $partitionDetails Details of partitions - * - * @return array - */ - protected static function extractPartitions(array $partitionDetails): array - { - $partitionCount = $partitionDetails['partition_count']; - $subpartitionCount = $partitionDetails['subpartition_count']; - - // No partitions - if ($partitionCount <= 1) { - return $partitionDetails; - } - - // Has partitions - $partitions = $_POST['partitions'] ?? []; - - // Remove details of the additional partitions - // when number of partitions have been reduced - array_splice($partitions, $partitionCount); - - for ($i = 0; $i < $partitionCount; $i++) { - if (! isset($partitions[$i])) { // Newly added partition - $partitions[$i] = [ - 'name' => 'p' . $i, - 'value_type' => '', - 'value' => '', - 'engine' => '', - 'comment' => '', - 'data_directory' => '', - 'index_directory' => '', - 'max_rows' => '', - 'min_rows' => '', - 'tablespace' => '', - 'node_group' => '', - ]; - } - - $partition =& $partitions[$i]; - $partition['prefix'] = 'partitions[' . $i . ']'; - - // Changing from HASH/KEY to RANGE/LIST - if (! isset($partition['value_type'])) { - $partition['value_type'] = ''; - $partition['value'] = ''; - } - if (! isset($partition['engine'])) { // When removing subpartitioning - $partition['engine'] = ''; - $partition['comment'] = ''; - $partition['data_directory'] = ''; - $partition['index_directory'] = ''; - $partition['max_rows'] = ''; - $partition['min_rows'] = ''; - $partition['tablespace'] = ''; - $partition['node_group'] = ''; - } - - // No subpartitions - if ($subpartitionCount <= 1 || $partitionDetails['can_have_subpartitions'] !== true) { - unset($partition['subpartitions'], $partition['subpartition_count']); - continue; - } - - // Has subpartitions - $partition['subpartition_count'] = $subpartitionCount; - - if (! isset($partition['subpartitions'])) { - $partition['subpartitions'] = []; - } - $subpartitions =& $partition['subpartitions']; - - // Remove details of the additional subpartitions - // when number of subpartitions have been reduced - array_splice($subpartitions, $subpartitionCount); - - for ($j = 0; $j < $subpartitionCount; $j++) { - if (! isset($subpartitions[$j])) { // Newly added subpartition - $subpartitions[$j] = [ - 'name' => $partition['name'] . '_s' . $j, - 'engine' => '', - 'comment' => '', - 'data_directory' => '', - 'index_directory' => '', - 'max_rows' => '', - 'min_rows' => '', - 'tablespace' => '', - 'node_group' => '', - ]; - } - - $subpartitions[$j]['prefix'] = 'partitions[' . $i . ']' - . '[subpartitions][' . $j . ']'; - } - } - $partitionDetails['partitions'] = $partitions; - return $partitionDetails; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Template.php b/srcs/phpmyadmin/libraries/classes/Template.php deleted file mode 100644 index 3866fd2..0000000 --- a/srcs/phpmyadmin/libraries/classes/Template.php +++ /dev/null @@ -1,142 +0,0 @@ -getTempDir('twig'); - /* Twig expects false when cache is not configured */ - if ($cache_dir === null) { - $cache_dir = false; - } - $twig = new Environment($loader, [ - 'auto_reload' => true, - 'cache' => $cache_dir, - 'debug' => false, - ]); - $twig->addExtension(new CoreExtension()); - $twig->addExtension(new I18nExtension()); - $twig->addExtension(new MessageExtension()); - $twig->addExtension(new PluginsExtension()); - $twig->addExtension(new RelationExtension()); - $twig->addExtension(new SanitizeExtension()); - $twig->addExtension(new ServerPrivilegesExtension()); - $twig->addExtension(new StorageEngineExtension()); - $twig->addExtension(new TableExtension()); - $twig->addExtension(new TrackerExtension()); - $twig->addExtension(new TransformationsExtension()); - $twig->addExtension(new UrlExtension()); - $twig->addExtension(new UtilExtension()); - static::$twig = $twig; - } - } - - /** - * Loads a template. - * - * @param string $templateName Template path name - * - * @return Twig_TemplateWrapper - * @throws LoaderError - * @throws RuntimeError - * @throws SyntaxError - */ - public function load(string $templateName): Twig_TemplateWrapper - { - try { - $template = static::$twig->load($templateName . '.twig'); - } catch (RuntimeException $e) { - /* Retry with disabled cache */ - static::$twig->setCache(false); - $template = static::$twig->load($templateName . '.twig'); - /* - * The trigger error is intentionally after second load - * to avoid triggering error when disabling cache does not - * solve it. - */ - trigger_error( - sprintf( - __('Error while working with template cache: %s'), - $e->getMessage() - ), - E_USER_WARNING - ); - } - - return $template; - } - - /** - * @param string $template Template path name - * @param array $data Associative array of template variables - * - * @return string - * @throws Throwable - * @throws Twig_Error_Loader - * @throws Twig_Error_Runtime - * @throws Twig_Error_Syntax - */ - public function render(string $template, array $data = []): string - { - return $this->load($template)->render($data); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Theme.php b/srcs/phpmyadmin/libraries/classes/Theme.php deleted file mode 100644 index ece3a27..0000000 --- a/srcs/phpmyadmin/libraries/classes/Theme.php +++ /dev/null @@ -1,387 +0,0 @@ -template = new Template(); - } - - /** - * Loads theme information - * - * @return boolean whether loading them info was successful or not - * @access public - */ - public function loadInfo() - { - $infofile = $this->getPath() . '/theme.json'; - if (! @file_exists($infofile)) { - return false; - } - - if ($this->mtime_info === filemtime($infofile)) { - return true; - } - $content = @file_get_contents($infofile); - if ($content === false) { - return false; - } - $data = json_decode($content, true); - - // Did we get expected data? - if (! is_array($data)) { - return false; - } - // Check that all required data are there - $members = [ - 'name', - 'version', - 'supports', - ]; - foreach ($members as $member) { - if (! isset($data[$member])) { - return false; - } - } - - // Version check - if (! is_array($data['supports'])) { - return false; - } - if (! in_array(PMA_MAJOR_VERSION, $data['supports'])) { - return false; - } - - $this->mtime_info = filemtime($infofile); - $this->filesize_info = filesize($infofile); - - $this->setVersion($data['version']); - $this->setName($data['name']); - - return true; - } - - /** - * returns theme object loaded from given folder - * or false if theme is invalid - * - * @param string $folder path to theme - * - * @return Theme|false - * @static - * @access public - */ - public static function load($folder) - { - $theme = new Theme(); - - $theme->setPath($folder); - - if (! $theme->loadInfo()) { - return false; - } - - $theme->checkImgPath(); - - return $theme; - } - - /** - * checks image path for existence - 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 = './themes/' . ThemeManager::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; - } - - /** - * 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 against $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 - * @param string $fallback fallback image - * - * @access public - * @return string image path for this theme - */ - public function getImgPath($file = null, $fallback = null) - { - if ($file === null) { - return $this->img_path; - } - - if (is_readable($this->img_path . $file)) { - return $this->img_path . $file; - } - - if ($fallback !== null) { - return $this->getImgPath($fallback); - } - - return './themes/' . ThemeManager::FALLBACK_THEME . '/img/' . $file; - } - - /** - * Renders the preview for this theme - * - * @return string - * @access public - */ - public function getPrintPreview() - { - $url_params = ['set_theme' => $this->getId()]; - $screen = null; - $path = $this->getPath() . '/screen.png'; - if (@file_exists($path)) { - $screen = $path; - } - - return $this->template->render('theme_preview', [ - 'url_params' => $url_params, - 'name' => $this->getName(), - 'version' => $this->getVersion(), - 'id' => $this->getId(), - 'screen' => $screen, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/ThemeManager.php b/srcs/phpmyadmin/libraries/classes/ThemeManager.php deleted file mode 100644 index 8bba657..0000000 --- a/srcs/phpmyadmin/libraries/classes/ThemeManager.php +++ /dev/null @@ -1,417 +0,0 @@ -themes = []; - $this->theme_default = self::FALLBACK_THEME; - $this->active_theme = ''; - - if (! $this->setThemesPath('./themes/')) { - return; - } - - $this->setThemePerServer($GLOBALS['cfg']['ThemePerServer']); - - $this->loadThemes(); - - $this->theme = new Theme(); - - $config_theme_exists = true; - - if (! $this->checkTheme($GLOBALS['cfg']['ThemeDefault'])) { - trigger_error( - sprintf( - __('Default theme %s not found!'), - htmlspecialchars($GLOBALS['cfg']['ThemeDefault']) - ), - E_USER_ERROR - ); - $config_theme_exists = false; - } else { - $this->theme_default = $GLOBALS['cfg']['ThemeDefault']; - } - - // check if user have a theme cookie - $cookie_theme = $this->getThemeCookie(); - if (! $cookie_theme || ! $this->setActiveTheme($cookie_theme)) { - if ($config_theme_exists) { - // otherwise use default theme - $this->setActiveTheme($this->theme_default); - } else { - // or fallback theme - $this->setActiveTheme(self::FALLBACK_THEME); - } - } - } - - /** - * Returns the singleton ThemeManager object - * - * @return ThemeManager The instance - */ - public static function getInstance(): ThemeManager - { - if (empty(self::$_instance)) { - self::$_instance = new ThemeManager(); - } - return self::$_instance; - } - - /** - * 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; - } - - /** - * sets if there are different themes per server - * - * @param boolean $per_server Whether to enable per server flag - * - * @access public - * @return void - */ - public function setThemePerServer($per_server) - { - $this->per_server = (bool) $per_server; - } - - /** - * 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; - } - - /** - * Returns name for storing theme - * - * @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']; - } - - return $this->cookie_name; - } - - /** - * returns name of theme stored in the cookie - * - * @return string|bool theme name from cookie or false - * @access public - */ - public function getThemeCookie() - { - /** @var Config $PMA_Config */ - global $PMA_Config; - - $name = $this->getThemeCookieName(); - if ($PMA_Config->issetCookie($name)) { - return $PMA_Config->getCookie($name); - } - - 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; - } - - /** - * Checks whether folder is valid for storing themes - * - * @param string $folder Folder name to test - * - * @return boolean - * @access private - */ - private function _checkThemeFolder($folder) - { - if (! is_dir($folder)) { - trigger_error( - sprintf( - __('Theme path not found for theme %s!'), - htmlspecialchars($folder) - ), - E_USER_ERROR - ); - return false; - } - - return true; - } - - /** - * read all themes - * - * @return bool true - * @access public - */ - public function loadThemes() - { - $this->themes = []; - - if (false === ($handleThemes = opendir($this->_themes_path))) { - trigger_error( - 'phpMyAdmin-ERROR: cannot open themes folder: ' - . $this->_themes_path, - E_USER_WARNING - ); - return false; - } - - // check for themes directory - while (false !== ($PMA_Theme = readdir($handleThemes))) { - // Skip non dirs, . and .. - if ($PMA_Theme == '.' - || $PMA_Theme == '..' - || ! @is_dir(ROOT_PATH . $this->_themes_path . $PMA_Theme) - ) { - continue; - } - if (array_key_exists($PMA_Theme, $this->themes)) { - continue; - } - $new_theme = Theme::load( - $this->_themes_path . $PMA_Theme - ); - if ($new_theme) { - $new_theme->setId($PMA_Theme); - $this->themes[$PMA_Theme] = $new_theme; - } - } // end get themes - closedir($handleThemes); - - 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) - { - return array_key_exists($theme, $this->themes); - } - - /** - * 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; - } - - /** - * 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; - } - - /** - * Theme initialization - * - * @return void - * @access public - */ - public static function initializeTheme() - { - $tmanager = self::getInstance(); - - /** - * the theme object - * - * @global Theme $GLOBALS['PMA_Theme'] - */ - $GLOBALS['PMA_Theme'] = $tmanager->theme; - - // BC - /** - * the theme path - * @global string $GLOBALS['pmaThemePath'] - */ - $GLOBALS['pmaThemePath'] = $GLOBALS['PMA_Theme']->getPath(); - /** - * the theme image path - * @global string $GLOBALS['pmaThemeImage'] - */ - $GLOBALS['pmaThemeImage'] = $GLOBALS['PMA_Theme']->getImgPath(); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Tracker.php b/srcs/phpmyadmin/libraries/classes/Tracker.php deleted file mode 100644 index 882c09d..0000000 --- a/srcs/phpmyadmin/libraries/classes/Tracker.php +++ /dev/null @@ -1,942 +0,0 @@ -getRelationsParam(); - /* Restore original state */ - self::$enabled = true; - if (! $cfgRelation['trackingwork']) { - return false; - } - - $pma_table = self::_getTrackingTable(); - - return $pma_table !== null; - } - - /** - * Parses the name of a table from a SQL statement substring. - * - * @param string $string part of SQL statement - * - * @static - * - * @return string the name of table - */ - protected static function getTableName($string) - { - if (mb_strstr($string, '.')) { - $temp = explode('.', $string); - $tablename = $temp[1]; - } else { - $tablename = $string; - } - - $str = explode("\n", $tablename); - $tablename = $str[0]; - - $tablename = str_replace([';', '`'], '', $tablename); - $tablename = trim($tablename); - - return $tablename; - } - - - /** - * Gets the tracking status of a table, is it active or deactive ? - * - * @param string $dbname name of database - * @param string $tablename name of table - * - * @static - * - * @return boolean true or false - */ - public static function isTracked($dbname, $tablename) - { - if (! self::$enabled) { - return false; - } - - if (isset(self::$_tracking_cache[$dbname][$tablename])) { - return self::$_tracking_cache[$dbname][$tablename]; - } - /* We need to avoid attempt to track any queries - * from Relation::getRelationsParam - */ - self::$enabled = false; - $relation = new Relation($GLOBALS['dbi']); - $cfgRelation = $relation->getRelationsParam(); - /* Restore original state */ - self::$enabled = true; - if (! $cfgRelation['trackingwork']) { - return false; - } - - $sql_query = " SELECT tracking_active FROM " . self::_getTrackingTable() . - " WHERE db_name = '" . $GLOBALS['dbi']->escapeString($dbname) . "' " . - " AND table_name = '" . $GLOBALS['dbi']->escapeString($tablename) . "' " . - " ORDER BY version DESC LIMIT 1"; - - $result = $GLOBALS['dbi']->fetchValue($sql_query, 0, 0, DatabaseInterface::CONNECT_CONTROL) == 1; - - self::$_tracking_cache[$dbname][$tablename] = $result; - - return $result; - } - - /** - * Returns the comment line for the log. - * - * @return string Comment, contains date and username - */ - public static function getLogComment() - { - $date = Util::date('Y-m-d H:i:s'); - $user = preg_replace('/\s+/', ' ', $GLOBALS['cfg']['Server']['user']); - - return "# log " . $date . " " . $user . "\n"; - } - - /** - * Creates tracking version of a table / view - * (in other words: create a job to track future changes on the table). - * - * @param string $dbname name of database - * @param string $tablename name of table - * @param string $version version - * @param string $tracking_set set of tracking statements - * @param bool $is_view if table is a view - * - * @static - * - * @return int result of version insertion - */ - public static function createVersion( - $dbname, - $tablename, - $version, - $tracking_set = '', - bool $is_view = false - ) { - global $sql_backquotes, $export_type; - - $relation = new Relation($GLOBALS['dbi']); - - if ($tracking_set == '') { - $tracking_set - = $GLOBALS['cfg']['Server']['tracking_default_statements']; - } - - /** - * get Export SQL instance - * @var ExportSql $export_sql_plugin - */ - $export_sql_plugin = Plugins::getPlugin( - "export", - "sql", - 'libraries/classes/Plugins/Export/', - [ - 'export_type' => $export_type, - 'single_table' => false, - ] - ); - - $sql_backquotes = true; - - $date = Util::date('Y-m-d H:i:s'); - - // Get data definition snapshot of table - - $columns = $GLOBALS['dbi']->getColumns($dbname, $tablename, null, true); - // int indices to reduce size - $columns = array_values($columns); - // remove Privileges to reduce size - for ($i = 0, $nb = count($columns); $i < $nb; $i++) { - unset($columns[$i]['Privileges']); - } - - $indexes = $GLOBALS['dbi']->getTableIndexes($dbname, $tablename); - - $snapshot = [ - 'COLUMNS' => $columns, - 'INDEXES' => $indexes, - ]; - $snapshot = serialize($snapshot); - - // Get DROP TABLE / DROP VIEW and CREATE TABLE SQL statements - $sql_backquotes = true; - - $create_sql = ""; - - if ($GLOBALS['cfg']['Server']['tracking_add_drop_table'] == true - && $is_view === false - ) { - $create_sql .= self::getLogComment() - . 'DROP TABLE IF EXISTS ' . Util::backquote($tablename) . ";\n"; - } - - if ($GLOBALS['cfg']['Server']['tracking_add_drop_view'] == true - && $is_view === true - ) { - $create_sql .= self::getLogComment() - . 'DROP VIEW IF EXISTS ' . Util::backquote($tablename) . ";\n"; - } - - $create_sql .= self::getLogComment() . - $export_sql_plugin->getTableDef($dbname, $tablename, "\n", ""); - - // Save version - - $sql_query = "/*NOTRACK*/\n" . - "INSERT INTO " . self::_getTrackingTable() . " (" . - "db_name, " . - "table_name, " . - "version, " . - "date_created, " . - "date_updated, " . - "schema_snapshot, " . - "schema_sql, " . - "data_sql, " . - "tracking " . - ") " . - "values ( - '" . $GLOBALS['dbi']->escapeString($dbname) . "', - '" . $GLOBALS['dbi']->escapeString($tablename) . "', - '" . $GLOBALS['dbi']->escapeString($version) . "', - '" . $GLOBALS['dbi']->escapeString($date) . "', - '" . $GLOBALS['dbi']->escapeString($date) . "', - '" . $GLOBALS['dbi']->escapeString($snapshot) . "', - '" . $GLOBALS['dbi']->escapeString($create_sql) . "', - '" . $GLOBALS['dbi']->escapeString("\n") . "', - '" . $GLOBALS['dbi']->escapeString($tracking_set) - . "' )"; - - $result = $relation->queryAsControlUser($sql_query); - - if ($result) { - // Deactivate previous version - self::deactivateTracking($dbname, $tablename, (int) $version - 1); - } - - return $result; - } - - - /** - * Removes all tracking data for a table or a version of a table - * - * @param string $dbname name of database - * @param string $tablename name of table - * @param string $version version - * - * @static - * - * @return int result of version insertion - */ - public static function deleteTracking($dbname, $tablename, $version = '') - { - $relation = new Relation($GLOBALS['dbi']); - - $sql_query = "/*NOTRACK*/\n" - . "DELETE FROM " . self::_getTrackingTable() - . " WHERE `db_name` = '" - . $GLOBALS['dbi']->escapeString($dbname) . "'" - . " AND `table_name` = '" - . $GLOBALS['dbi']->escapeString($tablename) . "'"; - if ($version) { - $sql_query .= " AND `version` = '" - . $GLOBALS['dbi']->escapeString($version) . "'"; - } - return $relation->queryAsControlUser($sql_query); - } - - /** - * 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 - */ - public static function createDatabaseVersion( - $dbname, - $version, - $query, - $tracking_set = 'CREATE DATABASE,ALTER DATABASE,DROP DATABASE' - ) { - $relation = new Relation($GLOBALS['dbi']); - - $date = Util::date('Y-m-d H:i:s'); - - if ($tracking_set == '') { - $tracking_set - = $GLOBALS['cfg']['Server']['tracking_default_statements']; - } - - $create_sql = ""; - - if ($GLOBALS['cfg']['Server']['tracking_add_drop_database'] == true) { - $create_sql .= self::getLogComment() - . 'DROP DATABASE IF EXISTS ' . Util::backquote($dbname) . ";\n"; - } - - $create_sql .= self::getLogComment() . $query; - - // Save version - $sql_query = "/*NOTRACK*/\n" . - "INSERT INTO " . self::_getTrackingTable() . " (" . - "db_name, " . - "table_name, " . - "version, " . - "date_created, " . - "date_updated, " . - "schema_snapshot, " . - "schema_sql, " . - "data_sql, " . - "tracking " . - ") " . - "values ( - '" . $GLOBALS['dbi']->escapeString($dbname) . "', - '" . $GLOBALS['dbi']->escapeString('') . "', - '" . $GLOBALS['dbi']->escapeString($version) . "', - '" . $GLOBALS['dbi']->escapeString($date) . "', - '" . $GLOBALS['dbi']->escapeString($date) . "', - '" . $GLOBALS['dbi']->escapeString('') . "', - '" . $GLOBALS['dbi']->escapeString($create_sql) . "', - '" . $GLOBALS['dbi']->escapeString("\n") . "', - '" . $GLOBALS['dbi']->escapeString($tracking_set) - . "' )"; - - return $relation->queryAsControlUser($sql_query); - } - - - - /** - * 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 - */ - private static function _changeTracking( - $dbname, - $tablename, - $version, - $new_state - ) { - $relation = new Relation($GLOBALS['dbi']); - - $sql_query = " UPDATE " . self::_getTrackingTable() . - " SET `tracking_active` = '" . $new_state . "' " . - " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($dbname) . "' " . - " AND `table_name` = '" . $GLOBALS['dbi']->escapeString($tablename) . "' " . - " AND `version` = '" . $GLOBALS['dbi']->escapeString((string) $version) . "' "; - - return $relation->queryAsControlUser($sql_query); - } - - /** - * 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 - */ - public static function changeTrackingData( - $dbname, - $tablename, - $version, - $type, - $new_data - ) { - $relation = new Relation($GLOBALS['dbi']); - - if ($type == 'DDL') { - $save_to = 'schema_sql'; - } elseif ($type == 'DML') { - $save_to = 'data_sql'; - } else { - return false; - } - $date = Util::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'] - . $GLOBALS['dbi']->escapeString($data['statement']) . "\n"; - } - } else { - $new_data_processed = $new_data; - } - - $sql_query = " UPDATE " . self::_getTrackingTable() . - " SET `" . $save_to . "` = '" . $new_data_processed . "' " . - " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($dbname) . "' " . - " AND `table_name` = '" . $GLOBALS['dbi']->escapeString($tablename) . "' " . - " AND `version` = '" . $GLOBALS['dbi']->escapeString($version) . "' "; - - $result = $relation->queryAsControlUser($sql_query); - - return (bool) $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 - */ - public static 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 - */ - public static 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) - */ - public static function getVersion($dbname, $tablename, $statement = null) - { - $relation = new Relation($GLOBALS['dbi']); - - $sql_query = " SELECT MAX(version) FROM " . self::_getTrackingTable() . - " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($dbname) . "' " . - " AND `table_name` = '" . $GLOBALS['dbi']->escapeString($tablename) . "' "; - - if ($statement != "") { - $sql_query .= " AND FIND_IN_SET('" - . $statement . "',tracking) > 0" ; - } - $row = $GLOBALS['dbi']->fetchArray($relation->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. - */ - public static function getTrackedData($dbname, $tablename, $version) - { - $relation = new Relation($GLOBALS['dbi']); - - $sql_query = " SELECT * FROM " . self::_getTrackingTable() . - " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($dbname) . "' "; - if (! empty($tablename)) { - $sql_query .= " AND `table_name` = '" - . $GLOBALS['dbi']->escapeString($tablename) . "' "; - } - $sql_query .= " AND `version` = '" . $GLOBALS['dbi']->escapeString($version) - . "' ORDER BY `version` DESC LIMIT 1"; - - $mixed = $GLOBALS['dbi']->fetchAssoc($relation->queryAsControlUser($sql_query)); - - // PHP 7.4 fix for accessing array offset on null - if (! is_array($mixed)) { - $mixed = [ - 'schema_sql' => null, - 'data_sql' => null, - 'tracking' => null, - 'schema_snapshot' => null, - ]; - } - - // Parse log - $log_schema_entries = explode('# log ', (string) $mixed['schema_sql']); - $log_data_entries = explode('# log ', (string) $mixed['data_sql']); - - $ddl_date_from = $date = Util::date('Y-m-d H:i:s'); - - $ddlog = []; - $first_iteration = true; - - // 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 = mb_substr($log_entry, 0, 19); - $username = mb_substr( - $log_entry, - 20, - mb_strpos($log_entry, "\n") - 20 - ); - if ($first_iteration) { - $ddl_date_from = $date; - $first_iteration = false; - } - $statement = rtrim(mb_strstr($log_entry, "\n")); - - $ddlog[] = [ - 'date' => $date, - 'username' => $username, - 'statement' => $statement, - ]; - } - } - - $date_from = $ddl_date_from; - $ddl_date_to = $date; - - $dml_date_from = $date_from; - - $dmlog = []; - $first_iteration = true; - - // 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 = mb_substr($log_entry, 0, 19); - $username = mb_substr( - $log_entry, - 20, - mb_strpos($log_entry, "\n") - 20 - ); - if ($first_iteration) { - $dml_date_from = $date; - $first_iteration = false; - } - $statement = rtrim(mb_strstr($log_entry, "\n")); - - $dmlog[] = [ - 'date' => $date, - 'username' => $username, - 'statement' => $statement, - ]; - } - } - - $dml_date_to = $date; - - // Define begin and end of date range for both logs - $data = []; - 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'] = $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. - * - */ - public static 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); - - $parser = new Parser($query); - - $tokens = $parser->list->tokens; - - // Parse USE statement, need it for SQL dump imports - if ($tokens[0]->value == 'USE') { - $GLOBALS['db'] = $tokens[2]->value; - } - - $result = []; - - if (! empty($parser->statements)) { - $statement = $parser->statements[0]; - $options = isset($statement->options) ? $statement->options->options : null; - - /* - * DDL statements - */ - $result['type'] = 'DDL'; - - // Parse CREATE statement - if ($statement instanceof CreateStatement) { - if (empty($options) || ! isset($options[6])) { - return $result; - } - - if ($options[6] == 'VIEW' || $options[6] == 'TABLE') { - $result['identifier'] = 'CREATE ' . $options[6]; - $result['tablename'] = $statement->name->table ; - } elseif ($options[6] == 'DATABASE') { - $result['identifier'] = 'CREATE DATABASE' ; - $result['tablename'] = '' ; - - // In case of CREATE DATABASE, table field of the CreateStatement is actually name of the database - $GLOBALS['db'] = $statement->name->table; - } elseif ($options[6] == 'INDEX' - || $options[6] == 'UNIQUE INDEX' - || $options[6] == 'FULLTEXT INDEX' - || $options[6] == 'SPATIAL INDEX' - ) { - $result['identifier'] = 'CREATE INDEX'; - - // In case of CREATE INDEX, we have to get the table name from body of the statement - $result['tablename'] = $statement->body[3]->value == '.' ? $statement->body[4]->value - : $statement->body[2]->value ; - } - } elseif ($statement instanceof AlterStatement) { // Parse ALTER statement - if (empty($options) || ! isset($options[3])) { - return $result; - } - - if ($options[3] == 'VIEW' || $options[3] == 'TABLE') { - $result['identifier'] = 'ALTER ' . $options[3] ; - $result['tablename'] = $statement->table->table ; - } elseif ($options[3] == 'DATABASE') { - $result['identifier'] = 'ALTER DATABASE' ; - $result['tablename'] = '' ; - - $GLOBALS['db'] = $statement->table->table ; - } - } elseif ($statement instanceof DropStatement) { // Parse DROP statement - if (empty($options) || ! isset($options[1])) { - return $result; - } - - if ($options[1] == 'VIEW' || $options[1] == 'TABLE') { - $result['identifier'] = 'DROP ' . $options[1] ; - $result['tablename'] = $statement->fields[0]->table; - } elseif ($options[1] == 'DATABASE') { - $result['identifier'] = 'DROP DATABASE' ; - $result['tablename'] = ''; - - $GLOBALS['db'] = $statement->fields[0]->table; - } elseif ($options[1] == 'INDEX') { - $result['identifier'] = 'DROP INDEX' ; - $result['tablename'] = $statement->table->table; - } - } elseif ($statement instanceof RenameStatement) { // Parse RENAME statement - $result['identifier'] = 'RENAME TABLE'; - $result['tablename'] = $statement->renames[0]->old->table; - $result['tablename_after_rename'] = $statement->renames[0]->new->table; - } - - if (isset($result['identifier'])) { - return $result ; - } - - /* - * DML statements - */ - $result['type'] = 'DML'; - - // Parse UPDATE statement - if ($statement instanceof UpdateStatement) { - $result['identifier'] = 'UPDATE'; - $result['tablename'] = $statement->tables[0]->table; - } - - // Parse INSERT INTO statement - if ($statement instanceof InsertStatement) { - $result['identifier'] = 'INSERT'; - $result['tablename'] = $statement->into->dest->table; - } - - // Parse DELETE statement - if ($statement instanceof DeleteStatement) { - $result['identifier'] = 'DELETE'; - $result['tablename'] = $statement->from[0]->table; - } - - // Parse TRUNCATE statement - if ($statement instanceof TruncateStatement) { - $result['identifier'] = 'TRUNCATE' ; - $result['tablename'] = $statement->table->table; - } - } - - return $result; - } - - - /** - * Analyzes a given SQL statement and saves tracking data. - * - * @param string $query a SQL query - * - * @static - * - * @return void - */ - public static function handleQuery($query) - { - $relation = new Relation($GLOBALS['dbi']); - - // If query is marked as untouchable, leave - if (mb_strstr($query, "/*NOTRACK*/")) { - return; - } - - if (! (substr($query, -1) == ';')) { - $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; - } - - // If we found a valid statement - if (isset($result['identifier'])) { - if (! self::isTracked($dbname, $result['tablename'])) { - return; - } - - $version = self::getVersion( - $dbname, - $result['tablename'], - $result['identifier'] - ); - - // If version not exists and auto-creation is enabled - if ($GLOBALS['cfg']['Server']['tracking_version_auto_create'] == true - && $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 ($version != -1) { - if ($result['type'] == 'DDL') { - $save_to = 'schema_sql'; - } elseif ($result['type'] == 'DML') { - $save_to = 'data_sql'; - } else { - $save_to = ''; - } - $date = Util::date('Y-m-d H:i:s'); - - // Cut off `dbname`. from query - $query = preg_replace( - '/`' . preg_quote($dbname, '/') . '`\s?\./', - '', - $query - ); - - // Add log information - $query = self::getLogComment() . $query ; - - // Mark it as untouchable - $sql_query = " /*NOTRACK*/\n" - . " UPDATE " . self::_getTrackingTable() - . " SET " . Util::backquote($save_to) - . " = CONCAT( " . Util::backquote($save_to) . ",'\n" - . $GLOBALS['dbi']->escapeString($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` = \'' - . $GLOBALS['dbi']->escapeString($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` = '" . $GLOBALS['dbi']->escapeString($dbname) . "' " . - " AND `table_name` = '" - . $GLOBALS['dbi']->escapeString($result['tablename']) . "' " . - " AND `version` = '" . $GLOBALS['dbi']->escapeString($version) . "' "; - - $relation->queryAsControlUser($sql_query); - } - } - } - - /** - * Returns the tracking table - * - * @return string tracking table - */ - private static function _getTrackingTable() - { - $relation = new Relation($GLOBALS['dbi']); - $cfgRelation = $relation->getRelationsParam(); - return Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['tracking']); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Tracking.php b/srcs/phpmyadmin/libraries/classes/Tracking.php deleted file mode 100644 index a0a7c1d..0000000 --- a/srcs/phpmyadmin/libraries/classes/Tracking.php +++ /dev/null @@ -1,1320 +0,0 @@ -sqlQueryForm = $sqlQueryForm; - $this->template = $template; - $this->relation = $relation; - } - - /** - * Filters tracking entries - * - * @param array $data the entries to filter - * @param string $filter_ts_from "from" date - * @param string $filter_ts_to "to" date - * @param array $filter_users users - * - * @return array filtered entries - */ - public function filter( - array $data, - $filter_ts_from, - $filter_ts_to, - array $filter_users - ): array { - $tmp_entries = []; - $id = 0; - foreach ($data as $entry) { - $timestamp = strtotime($entry['date']); - $filtered_user = in_array($entry['username'], $filter_users); - if ($timestamp >= $filter_ts_from - && $timestamp <= $filter_ts_to - && (in_array('*', $filter_users) || $filtered_user) - ) { - $tmp_entries[] = [ - 'id' => $id, - 'timestamp' => $timestamp, - 'username' => $entry['username'], - 'statement' => $entry['statement'], - ]; - } - $id++; - } - return $tmp_entries; - } - - /** - * Function to get html for data definition and data manipulation statements - * - * @param string $urlQuery url query - * @param int $lastVersion last version - * @param string $db database - * @param array $selected selected tables - * @param string $type type of the table; table, view or both - * - * @return string HTML - */ - public function getHtmlForDataDefinitionAndManipulationStatements( - $urlQuery, - $lastVersion, - $db, - array $selected, - $type = 'both' - ) { - return $this->template->render('create_tracking_version', [ - 'url_query' => $urlQuery, - 'last_version' => $lastVersion, - 'db' => $db, - 'selected' => $selected, - 'type' => $type, - 'default_statements' => $GLOBALS['cfg']['Server']['tracking_default_statements'], - ]); - } - - /** - * Function to get html for activate/deactivate tracking - * - * @param string $action activate|deactivate - * @param string $urlQuery url query - * @param int $lastVersion last version - * - * @return string HTML - */ - public function getHtmlForActivateDeactivateTracking( - $action, - $urlQuery, - $lastVersion - ) { - return $this->template->render('table/tracking/activate_deactivate', [ - 'action' => $action, - 'url_query' => $urlQuery, - 'last_version' => $lastVersion, - 'db' => $GLOBALS['db'], - 'table' => $GLOBALS['table'], - ]); - } - - /** - * Function to get the list versions of the table - * - * @return array - */ - public function getListOfVersionsOfTable() - { - $relation = $this->relation; - $cfgRelation = $relation->getRelationsParam(); - $sql_query = " SELECT * FROM " . - Util::backquote($cfgRelation['db']) . "." . - Util::backquote($cfgRelation['tracking']) . - " WHERE db_name = '" . $GLOBALS['dbi']->escapeString($GLOBALS['db']) . - "' " . - " AND table_name = '" . - $GLOBALS['dbi']->escapeString($GLOBALS['table']) . "' " . - " ORDER BY version DESC "; - - return $relation->queryAsControlUser($sql_query); - } - - /** - * Function to get html for main page parts that do not use $_REQUEST - * - * @param string $urlQuery url query - * @param array $urlParams url parameters - * @param string $pmaThemeImage path to theme's image folder - * @param string $textDir text direction - * @param int $lastVersion last tracking version - * - * @return string - */ - public function getHtmlForMainPage( - $urlQuery, - $urlParams, - $pmaThemeImage, - $textDir, - $lastVersion = null - ) { - $selectableTablesSqlResult = $this->getSqlResultForSelectableTables(); - $selectableTablesEntries = []; - while ($entry = $GLOBALS['dbi']->fetchArray($selectableTablesSqlResult)) { - $entry['is_tracked'] = Tracker::isTracked( - $entry['db_name'], - $entry['table_name'] - ); - $selectableTablesEntries[] = $entry; - } - $selectableTablesNumRows = $GLOBALS['dbi']->numRows($selectableTablesSqlResult); - - $versionSqlResult = $this->getListOfVersionsOfTable(); - if ($lastVersion === null) { - $lastVersion = $this->getTableLastVersionNumber($versionSqlResult); - } - $GLOBALS['dbi']->dataSeek($versionSqlResult, 0); - $versions = []; - while ($version = $GLOBALS['dbi']->fetchArray($versionSqlResult)) { - $versions[] = $version; - } - - $type = $GLOBALS['dbi']->getTable($GLOBALS['db'], $GLOBALS['table']) - ->isView() ? 'view' : 'table'; - - return $this->template->render('table/tracking/main', [ - 'url_query' => $urlQuery, - 'url_params' => $urlParams, - 'db' => $GLOBALS['db'], - 'table' => $GLOBALS['table'], - 'selectable_tables_num_rows' => $selectableTablesNumRows, - 'selectable_tables_entries' => $selectableTablesEntries, - 'selected_table' => isset($_POST['table']) ? $_POST['table'] : null, - 'last_version' => $lastVersion, - 'versions' => $versions, - 'type' => $type, - 'default_statements' => $GLOBALS['cfg']['Server']['tracking_default_statements'], - 'pmaThemeImage' => $pmaThemeImage, - 'text_dir' => $textDir, - ]); - } - - /** - * Function to get the last version number of a table - * - * @param array $sql_result sql result - * - * @return int - */ - public function getTableLastVersionNumber($sql_result) - { - $maxversion = $GLOBALS['dbi']->fetchArray($sql_result); - return intval(is_array($maxversion) ? $maxversion['version'] : null); - } - - /** - * Function to get sql results for selectable tables - * - * @return array - */ - public function getSqlResultForSelectableTables() - { - $relation = $this->relation; - $cfgRelation = $relation->getRelationsParam(); - - $sql_query = " SELECT DISTINCT db_name, table_name FROM " . - Util::backquote($cfgRelation['db']) . "." . - Util::backquote($cfgRelation['tracking']) . - " WHERE db_name = '" . $GLOBALS['dbi']->escapeString($GLOBALS['db']) . - "' " . - " ORDER BY db_name, table_name"; - - return $relation->queryAsControlUser($sql_query); - } - - /** - * Function to get html for tracking report and tracking report export - * - * @param string $url_query url query - * @param array $data data - * @param array $url_params url params - * @param boolean $selection_schema selection schema - * @param boolean $selection_data selection data - * @param boolean $selection_both selection both - * @param int $filter_ts_to filter time stamp from - * @param int $filter_ts_from filter time stamp tp - * @param array $filter_users filter users - * - * @return string - */ - public function getHtmlForTrackingReport( - $url_query, - array $data, - array $url_params, - $selection_schema, - $selection_data, - $selection_both, - $filter_ts_to, - $filter_ts_from, - array $filter_users - ) { - $html = '

    ' . __('Tracking report') - . ' [' . __('Close') - . ']

    '; - - $html .= '' . __('Tracking statements') . ' ' - . htmlspecialchars($data['tracking']) . '
    '; - $html .= '
    '; - - list($str1, $str2, $str3, $str4, $str5) = $this->getHtmlForElementsOfTrackingReport( - $selection_schema, - $selection_data, - $selection_both - ); - - // Prepare delete link content here - $drop_image_or_text = ''; - if (Util::showIcons('ActionLinksMode')) { - $drop_image_or_text .= Util::getImage( - 'b_drop', - __('Delete tracking data row from report') - ); - } - if (Util::showText('ActionLinksMode')) { - $drop_image_or_text .= __('Delete'); - } - - /* - * First, list tracked data definition statements - */ - if (count($data['ddlog']) == 0 && count($data['dmlog']) === 0) { - $msg = Message::notice(__('No data')); - $msg->display(); - } - - $html .= $this->getHtmlForTrackingReportExportForm1( - $data, - $url_params, - $selection_schema, - $selection_data, - $selection_both, - $filter_ts_to, - $filter_ts_from, - $filter_users, - $str1, - $str2, - $str3, - $str4, - $str5, - $drop_image_or_text - ); - - $html .= $this->getHtmlForTrackingReportExportForm2( - $url_params, - $str1, - $str2, - $str3, - $str4, - $str5 - ); - - $html .= "



    \n"; - - return $html; - } - - /** - * Generate HTML element for report form - * - * @param boolean $selection_schema selection schema - * @param boolean $selection_data selection data - * @param boolean $selection_both selection both - * - * @return array - */ - public function getHtmlForElementsOfTrackingReport( - $selection_schema, - $selection_data, - $selection_both - ) { - $str1 = ''; - $str2 = ''; - $str3 = ''; - $str4 = ''; - $str5 = '' - . ''; - return [ - $str1, - $str2, - $str3, - $str4, - $str5, - ]; - } - - /** - * Generate HTML for export form - * - * @param array $data data - * @param array $url_params url params - * @param boolean $selection_schema selection schema - * @param boolean $selection_data selection data - * @param boolean $selection_both selection both - * @param int $filter_ts_to filter time stamp from - * @param int $filter_ts_from filter time stamp tp - * @param array $filter_users filter users - * @param string $str1 HTML for logtype select - * @param string $str2 HTML for "from date" - * @param string $str3 HTML for "to date" - * @param string $str4 HTML for user - * @param string $str5 HTML for "list report" - * @param string $drop_image_or_text HTML for image or text - * - * @return string HTML for form - */ - public function getHtmlForTrackingReportExportForm1( - array $data, - array $url_params, - $selection_schema, - $selection_data, - $selection_both, - $filter_ts_to, - $filter_ts_from, - array $filter_users, - $str1, - $str2, - $str3, - $str4, - $str5, - $drop_image_or_text - ) { - $ddlog_count = 0; - - $html = '
    '; - $html .= Url::getHiddenInputs($url_params + [ - 'report' => 'true', - 'version' => $_POST['version'], - ]); - - $html .= sprintf( - __('Show %1$s with dates from %2$s to %3$s by user %4$s %5$s'), - $str1, - $str2, - $str3, - $str4, - $str5 - ); - - if ($selection_schema || $selection_both && count($data['ddlog']) > 0) { - list($temp, $ddlog_count) = $this->getHtmlForDataDefinitionStatements( - $data, - $filter_users, - $filter_ts_from, - $filter_ts_to, - $url_params, - $drop_image_or_text - ); - $html .= $temp; - unset($temp); - } //endif - - /* - * Secondly, list tracked data manipulation statements - */ - if (($selection_data || $selection_both) && count($data['dmlog']) > 0) { - $html .= $this->getHtmlForDataManipulationStatements( - $data, - $filter_users, - $filter_ts_from, - $filter_ts_to, - $url_params, - $ddlog_count, - $drop_image_or_text - ); - } - $html .= '
    '; - return $html; - } - - /** - * Generate HTML for export form - * - * @param array $url_params Parameters - * @param string $str1 HTML for logtype select - * @param string $str2 HTML for "from date" - * @param string $str3 HTML for "to date" - * @param string $str4 HTML for user - * @param string $str5 HTML for "list report" - * - * @return string HTML for form - */ - public function getHtmlForTrackingReportExportForm2( - array $url_params, - $str1, - $str2, - $str3, - $str4, - $str5 - ) { - $html = '
    '; - $html .= Url::getHiddenInputs($url_params + [ - 'report' => 'true', - 'version' => $_POST['version'], - ]); - - $html .= sprintf( - __('Show %1$s with dates from %2$s to %3$s by user %4$s %5$s'), - $str1, - $str2, - $str3, - $str4, - $str5 - ); - $html .= '
    '; - - $html .= '
    '; - $html .= Url::getHiddenInputs($url_params + [ - 'report' => 'true', - 'version' => $_POST['version'], - 'logtype' => $_POST['logtype'], - 'date_from' => $_POST['date_from'], - 'date_to' => $_POST['date_to'], - 'users' => $_POST['users'], - 'report_export' => 'true', - ]); - - $str_export1 = ''; - - $str_export2 = ''; - - $html .= "
    " . sprintf(__('Export as %s'), $str_export1) - . $str_export2 . "
    "; - $html .= '
    '; - return $html; - } - - /** - * Function to get html for data manipulation statements - * - * @param array $data data - * @param array $filter_users filter users - * @param int $filter_ts_from filter time staml from - * @param int $filter_ts_to filter time stamp to - * @param array $url_params url parameters - * @param int $ddlog_count data definition log count - * @param string $drop_image_or_text drop image or text - * - * @return string - */ - public function getHtmlForDataManipulationStatements( - array $data, - array $filter_users, - $filter_ts_from, - $filter_ts_to, - array $url_params, - $ddlog_count, - $drop_image_or_text - ) { - // no need for the secondth returned parameter - list($html,) = $this->getHtmlForDataStatements( - $data, - $filter_users, - $filter_ts_from, - $filter_ts_to, - $url_params, - $drop_image_or_text, - 'dmlog', - __('Data manipulation statement'), - $ddlog_count, - 'dml_versions' - ); - - return $html; - } - - /** - * Function to get html for data definition statements in schema snapshot - * - * @param array $data data - * @param array $filter_users filter users - * @param int $filter_ts_from filter time stamp from - * @param int $filter_ts_to filter time stamp to - * @param array $url_params url parameters - * @param string $drop_image_or_text drop image or text - * - * @return array - */ - public function getHtmlForDataDefinitionStatements( - array $data, - array $filter_users, - $filter_ts_from, - $filter_ts_to, - array $url_params, - $drop_image_or_text - ) { - list($html, $line_number) = $this->getHtmlForDataStatements( - $data, - $filter_users, - $filter_ts_from, - $filter_ts_to, - $url_params, - $drop_image_or_text, - 'ddlog', - __('Data definition statement'), - 1, - 'ddl_versions' - ); - - return [ - $html, - $line_number, - ]; - } - - /** - * Function to get html for data statements in schema snapshot - * - * @param array $data data - * @param array $filterUsers filter users - * @param int $filterTsFrom filter time stamp from - * @param int $filterTsTo filter time stamp to - * @param array $urlParams url parameters - * @param string $dropImageOrText drop image or text - * @param string $whichLog dmlog|ddlog - * @param string $headerMessage message for this section - * @param int $lineNumber line number - * @param string $tableId id for the table element - * - * @return array [$html, $lineNumber] - */ - private function getHtmlForDataStatements( - array $data, - array $filterUsers, - $filterTsFrom, - $filterTsTo, - array $urlParams, - $dropImageOrText, - $whichLog, - $headerMessage, - $lineNumber, - $tableId - ) { - $offset = $lineNumber; - $entries = []; - foreach ($data[$whichLog] as $entry) { - $timestamp = strtotime($entry['date']); - if ($timestamp >= $filterTsFrom - && $timestamp <= $filterTsTo - && (in_array('*', $filterUsers) - || in_array($entry['username'], $filterUsers)) - ) { - $entry['formated_statement'] = Util::formatSql($entry['statement'], true); - $deleteParam = 'delete_' . $whichLog; - $entry['url_params'] = Url::getCommon($urlParams + [ - 'report' => 'true', - 'version' => $_POST['version'], - $deleteParam => $lineNumber - $offset, - ], ''); - $entry['line_number'] = $lineNumber; - $entries[] = $entry; - } - $lineNumber++; - } - - $html = $this->template->render('table/tracking/report_table', [ - 'table_id' => $tableId, - 'header_message' => $headerMessage, - 'entries' => $entries, - 'drop_image_or_text' => $dropImageOrText, - ]); - - return [ - $html, - $lineNumber, - ]; - } - - /** - * Function to get html for schema snapshot - * - * @param string $url_query url query - * - * @return string - */ - public function getHtmlForSchemaSnapshot($url_query) - { - $html = '

    ' . __('Structure snapshot') - . ' [' . __('Close') - . ']

    '; - $data = Tracker::getTrackedData( - $_POST['db'], - $_POST['table'], - $_POST['version'] - ); - - // Get first DROP TABLE/VIEW and CREATE TABLE/VIEW statements - $drop_create_statements = $data['ddlog'][0]['statement']; - - if (mb_strstr($data['ddlog'][0]['statement'], 'DROP TABLE') - || mb_strstr($data['ddlog'][0]['statement'], 'DROP VIEW') - ) { - $drop_create_statements .= $data['ddlog'][1]['statement']; - } - // Print SQL code - $html .= Util::getMessage( - sprintf( - __('Version %s snapshot (SQL code)'), - htmlspecialchars($_POST['version']) - ), - $drop_create_statements - ); - - // Unserialize snapshot - $temp = Core::safeUnserialize($data['schema_snapshot']); - if ($temp === null) { - $temp = [ - 'COLUMNS' => [], - 'INDEXES' => [], - ]; - } - $columns = $temp['COLUMNS']; - $indexes = $temp['INDEXES']; - $html .= $this->getHtmlForColumns($columns); - - if (count($indexes) > 0) { - $html .= $this->getHtmlForIndexes($indexes); - } // endif - $html .= '


    '; - - return $html; - } - - /** - * Function to get html for displaying columns in the schema snapshot - * - * @param array $columns columns - * - * @return string - */ - public function getHtmlForColumns(array $columns) - { - return $this->template->render('table/tracking/structure_snapshot_columns', [ - 'columns' => $columns, - ]); - } - - /** - * Function to get html for the indexes in schema snapshot - * - * @param array $indexes indexes - * - * @return string - */ - public function getHtmlForIndexes(array $indexes) - { - return $this->template->render('table/tracking/structure_snapshot_indexes', [ - 'indexes' => $indexes, - ]); - } - - /** - * Function to handle the tracking report - * - * @param array $data tracked data - * - * @return string HTML for the message - */ - public function deleteTrackingReportRows(array &$data) - { - $html = ''; - if (isset($_POST['delete_ddlog'])) { - // Delete ddlog row data - $html .= $this->deleteFromTrackingReportLog( - $data, - 'ddlog', - 'DDL', - __('Tracking data definition successfully deleted') - ); - } - - if (isset($_POST['delete_dmlog'])) { - // Delete dmlog row data - $html .= $this->deleteFromTrackingReportLog( - $data, - 'dmlog', - 'DML', - __('Tracking data manipulation successfully deleted') - ); - } - return $html; - } - - /** - * Function to delete from a tracking report log - * - * @param array $data tracked data - * @param string $which_log ddlog|dmlog - * @param string $type DDL|DML - * @param string $message success message - * - * @return string HTML for the message - */ - public function deleteFromTrackingReportLog(array &$data, $which_log, $type, $message) - { - $html = ''; - $delete_id = $_POST['delete_' . $which_log]; - - // Only in case of valid id - if ($delete_id == (int) $delete_id) { - unset($data[$which_log][$delete_id]); - - $successfullyDeleted = Tracker::changeTrackingData( - $GLOBALS['db'], - $GLOBALS['table'], - $_POST['version'], - $type, - $data[$which_log] - ); - if ($successfullyDeleted) { - $msg = Message::success($message); - } else { - $msg = Message::rawError(__('Query error')); - } - $html .= $msg->getDisplay(); - } - return $html; - } - - /** - * Function to export as sql dump - * - * @param array $entries entries - * - * @return string HTML SQL query form - */ - public function exportAsSqlDump(array $entries) - { - $html = ''; - $new_query = "# " - . __( - 'You can execute the dump by creating and using a temporary database. ' - . 'Please ensure that you have the privileges to do so.' - ) - . "\n" - . "# " . __('Comment out these two lines if you do not need them.') . "\n" - . "\n" - . "CREATE database IF NOT EXISTS pma_temp_db; \n" - . "USE pma_temp_db; \n" - . "\n"; - - foreach ($entries as $entry) { - $new_query .= $entry['statement']; - } - $msg = Message::success( - __('SQL statements exported. Please copy the dump or execute it.') - ); - $html .= $msg->getDisplay(); - - $db_temp = $GLOBALS['db']; - $table_temp = $GLOBALS['table']; - - $GLOBALS['db'] = $GLOBALS['table'] = ''; - - $html .= $this->sqlQueryForm->getHtml($new_query, 'sql'); - - $GLOBALS['db'] = $db_temp; - $GLOBALS['table'] = $table_temp; - - return $html; - } - - /** - * Function to export as sql execution - * - * @param array $entries entries - * - * @return array - */ - public function exportAsSqlExecution(array $entries) - { - $sql_result = []; - foreach ($entries as $entry) { - $sql_result = $GLOBALS['dbi']->query("/*NOTRACK*/\n" . $entry['statement']); - } - - return $sql_result; - } - - /** - * Function to export as entries - * - * @param array $entries entries - * - * @return void - */ - public function exportAsFileDownload(array $entries) - { - ini_set('url_rewriter.tags', ''); - - // Replace all multiple whitespaces by a single space - $table = htmlspecialchars(preg_replace('/\s+/', ' ', $_POST['table'])); - $dump = "# " . sprintf( - __('Tracking report for table `%s`'), - $table - ) - . "\n" . '# ' . date('Y-m-d H:i:s') . "\n"; - foreach ($entries as $entry) { - $dump .= $entry['statement']; - } - $filename = 'log_' . $table . '.sql'; - Response::getInstance()->disable(); - Core::downloadHeader( - $filename, - 'text/x-sql', - strlen($dump) - ); - echo $dump; - - exit; - } - - /** - * Function to activate or deactivate tracking - * - * @param string $action activate|deactivate - * - * @return string HTML for the success message - */ - public function changeTracking($action) - { - $html = ''; - if ($action == 'activate') { - $method = 'activateTracking'; - $message = __('Tracking for %1$s was activated at version %2$s.'); - } else { - $method = 'deactivateTracking'; - $message = __('Tracking for %1$s was deactivated at version %2$s.'); - } - $status = Tracker::$method( - $GLOBALS['db'], - $GLOBALS['table'], - $_POST['version'] - ); - if ($status) { - $msg = Message::success( - sprintf( - $message, - htmlspecialchars($GLOBALS['db'] . '.' . $GLOBALS['table']), - htmlspecialchars($_POST['version']) - ) - ); - $html .= $msg->getDisplay(); - } - - return $html; - } - - /** - * Function to get tracking set - * - * @return string - */ - public function getTrackingSet() - { - $tracking_set = ''; - - // a key is absent from the request if it has been removed from - // tracking_default_statements in the config - if (isset($_POST['alter_table']) && $_POST['alter_table'] == true) { - $tracking_set .= 'ALTER TABLE,'; - } - if (isset($_POST['rename_table']) && $_POST['rename_table'] == true) { - $tracking_set .= 'RENAME TABLE,'; - } - if (isset($_POST['create_table']) && $_POST['create_table'] == true) { - $tracking_set .= 'CREATE TABLE,'; - } - if (isset($_POST['drop_table']) && $_POST['drop_table'] == true) { - $tracking_set .= 'DROP TABLE,'; - } - if (isset($_POST['alter_view']) && $_POST['alter_view'] == true) { - $tracking_set .= 'ALTER VIEW,'; - } - if (isset($_POST['create_view']) && $_POST['create_view'] == true) { - $tracking_set .= 'CREATE VIEW,'; - } - if (isset($_POST['drop_view']) && $_POST['drop_view'] == true) { - $tracking_set .= 'DROP VIEW,'; - } - if (isset($_POST['create_index']) && $_POST['create_index'] == true) { - $tracking_set .= 'CREATE INDEX,'; - } - if (isset($_POST['drop_index']) && $_POST['drop_index'] == true) { - $tracking_set .= 'DROP INDEX,'; - } - if (isset($_POST['insert']) && $_POST['insert'] == true) { - $tracking_set .= 'INSERT,'; - } - if (isset($_POST['update']) && $_POST['update'] == true) { - $tracking_set .= 'UPDATE,'; - } - if (isset($_POST['delete']) && $_POST['delete'] == true) { - $tracking_set .= 'DELETE,'; - } - if (isset($_POST['truncate']) && $_POST['truncate'] == true) { - $tracking_set .= 'TRUNCATE,'; - } - $tracking_set = rtrim($tracking_set, ','); - - return $tracking_set; - } - - /** - * Deletes a tracking version - * - * @param string $version tracking version - * - * @return string HTML of the success message - */ - public function deleteTrackingVersion($version) - { - $html = ''; - $versionDeleted = Tracker::deleteTracking( - $GLOBALS['db'], - $GLOBALS['table'], - $version - ); - if ($versionDeleted) { - $msg = Message::success( - sprintf( - __('Version %1$s of %2$s was deleted.'), - htmlspecialchars($version), - htmlspecialchars($GLOBALS['db'] . '.' . $GLOBALS['table']) - ) - ); - $html .= $msg->getDisplay(); - } - - return $html; - } - - /** - * Function to create the tracking version - * - * @return string HTML of the success message - */ - public function createTrackingVersion() - { - $html = ''; - $tracking_set = $this->getTrackingSet(); - - $versionCreated = Tracker::createVersion( - $GLOBALS['db'], - $GLOBALS['table'], - $_POST['version'], - $tracking_set, - $GLOBALS['dbi']->getTable($GLOBALS['db'], $GLOBALS['table'])->isView() - ); - if ($versionCreated) { - $msg = Message::success( - sprintf( - __('Version %1$s was created, tracking for %2$s is active.'), - htmlspecialchars($_POST['version']), - htmlspecialchars($GLOBALS['db'] . '.' . $GLOBALS['table']) - ) - ); - $html .= $msg->getDisplay(); - } - - return $html; - } - - /** - * Create tracking version for multiple tables - * - * @param array $selected list of selected tables - * - * @return void - */ - public function createTrackingForMultipleTables(array $selected) - { - $tracking_set = $this->getTrackingSet(); - - foreach ($selected as $selected_table) { - Tracker::createVersion( - $GLOBALS['db'], - $selected_table, - $_POST['version'], - $tracking_set, - $GLOBALS['dbi']->getTable($GLOBALS['db'], $selected_table)->isView() - ); - } - } - - /** - * Function to get the entries - * - * @param array $data data - * @param int $filter_ts_from filter time stamp from - * @param int $filter_ts_to filter time stamp to - * @param array $filter_users filter users - * - * @return array - */ - public function getEntries(array $data, $filter_ts_from, $filter_ts_to, array $filter_users) - { - $entries = []; - // Filtering data definition statements - if ($_POST['logtype'] == 'schema' - || $_POST['logtype'] == 'schema_and_data' - ) { - $entries = array_merge( - $entries, - $this->filter( - $data['ddlog'], - $filter_ts_from, - $filter_ts_to, - $filter_users - ) - ); - } - - // Filtering data manipulation statements - if ($_POST['logtype'] == 'data' - || $_POST['logtype'] == 'schema_and_data' - ) { - $entries = array_merge( - $entries, - $this->filter( - $data['dmlog'], - $filter_ts_from, - $filter_ts_to, - $filter_users - ) - ); - } - - // Sort it - $ids = $timestamps = $usernames = $statements = []; - foreach ($entries as $key => $row) { - $ids[$key] = $row['id']; - $timestamps[$key] = $row['timestamp']; - $usernames[$key] = $row['username']; - $statements[$key] = $row['statement']; - } - - array_multisort( - $timestamps, - SORT_ASC, - $ids, - SORT_ASC, - $usernames, - SORT_ASC, - $statements, - SORT_ASC, - $entries - ); - - return $entries; - } - - /** - * Function to get version status - * - * @param array $version version info - * - * @return string The status message - */ - public function getVersionStatus(array $version) - { - if ($version['tracking_active'] == 1) { - return __('active'); - } - - return __('not active'); - } - - /** - * Get HTML for tracked and untracked tables - * - * @param string $db current database - * @param string $urlQuery url query string - * @param string $pmaThemeImage path to theme's image folder - * @param string $textDir text direction - * - * @return string HTML - */ - public function getHtmlForDbTrackingTables( - string $db, - string $urlQuery, - string $pmaThemeImage, - string $textDir - ) { - $relation = $this->relation; - $cfgRelation = $relation->getRelationsParam(); - - // Prepare statement to get HEAD version - $allTablesQuery = ' SELECT table_name, MAX(version) as version FROM ' . - Util::backquote($cfgRelation['db']) . '.' . - Util::backquote($cfgRelation['tracking']) . - ' WHERE db_name = \'' . $GLOBALS['dbi']->escapeString($db) . - '\' ' . - ' GROUP BY table_name' . - ' ORDER BY table_name ASC'; - - $allTablesResult = $relation->queryAsControlUser($allTablesQuery); - $untrackedTables = $this->getUntrackedTables($db); - - // If a HEAD version exists - $versions = []; - $headVersionExists = is_object($allTablesResult) - && $GLOBALS['dbi']->numRows($allTablesResult) > 0; - if ($headVersionExists) { - while ($oneResult = $GLOBALS['dbi']->fetchArray($allTablesResult)) { - list($tableName, $versionNumber) = $oneResult; - $tableQuery = ' SELECT * FROM ' . - Util::backquote($cfgRelation['db']) . '.' . - Util::backquote($cfgRelation['tracking']) . - ' WHERE `db_name` = \'' - . $GLOBALS['dbi']->escapeString($db) - . '\' AND `table_name` = \'' - . $GLOBALS['dbi']->escapeString($tableName) - . '\' AND `version` = \'' . $versionNumber . '\''; - - $tableResult = $relation->queryAsControlUser($tableQuery); - $versionData = $GLOBALS['dbi']->fetchArray($tableResult); - $versionData['status_button'] = $this->getStatusButton( - $versionData, - $urlQuery - ); - $versions[] = $versionData; - } - } - - $html = $this->template->render('database/tracking/tables', [ - 'db' => $db, - 'head_version_exists' => $headVersionExists, - 'untracked_tables_exists' => count($untrackedTables) > 0, - 'versions' => $versions, - 'url_query' => $urlQuery, - 'text_dir' => $textDir, - 'untracked_tables' => $untrackedTables, - 'pma_theme_image' => $pmaThemeImage, - ]); - - return $html; - } - - /** - * Helper function: Recursive function for getting table names from $table_list - * - * @param array $table_list Table list - * @param string $db Current database - * @param boolean $testing Testing - * - * @return array - */ - public function extractTableNames(array $table_list, $db, $testing = false) - { - $untracked_tables = []; - $sep = $GLOBALS['cfg']['NavigationTreeTableSeparator']; - - foreach ($table_list as $key => $value) { - if (is_array($value) && array_key_exists('is' . $sep . 'group', $value) - && $value['is' . $sep . 'group'] - ) { - $untracked_tables = array_merge($this->extractTableNames($value, $db), $untracked_tables); //Recursion step - } else { - if (is_array($value) && ($testing || Tracker::getVersion($db, $value['Name']) == -1)) { - $untracked_tables[] = $value['Name']; - } - } - } - return $untracked_tables; - } - - - /** - * Get untracked tables - * - * @param string $db current database - * - * @return array - */ - public function getUntrackedTables($db) - { - $table_list = Util::getTableList($db); - //Use helper function to get table list recursively. - return $this->extractTableNames($table_list, $db); - } - - /** - * Get tracking status button - * - * @param array $versionData data about tracking versions - * @param string $urlQuery url query string - * - * @return string HTML - */ - private function getStatusButton(array $versionData, $urlQuery) - { - $state = $this->getVersionStatus($versionData); - $options = [ - 0 => [ - 'label' => __('not active'), - 'value' => 'deactivate_now', - 'selected' => $state != 'active', - ], - 1 => [ - 'label' => __('active'), - 'value' => 'activate_now', - 'selected' => $state == 'active', - ], - ]; - $link = 'tbl_tracking.php' . $urlQuery . '&table=' - . htmlspecialchars($versionData['table_name']) - . '&version=' . $versionData['version']; - - return Util::toggleButton( - $link, - 'toggle_activation', - $options, - null - ); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Transformations.php b/srcs/phpmyadmin/libraries/classes/Transformations.php deleted file mode 100644 index adc2265..0000000 --- a/srcs/phpmyadmin/libraries/classes/Transformations.php +++ /dev/null @@ -1,485 +0,0 @@ - - * getOptions("'option ,, quoted',abd,'2,3',"); - * // array { - * // 'option ,, quoted', - * // 'abc', - * // '2,3', - * // '', - * // } - * - * - * @param string $option_string comma separated options - * - * @return array options - */ - public function getOptions($option_string) - { - $result = []; - - if (strlen($option_string) === 0 - || ! $transform_options = explode(",", $option_string) - ) { - return $result; - } - - while (($option = array_shift($transform_options)) !== null) { - $trimmed = trim($option); - if (strlen($trimmed) > 1 - && $trimmed[0] == "'" - && $trimmed[strlen($trimmed) - 1] == "'" - ) { - // '...' - $option = mb_substr($trimmed, 1, -1); - } elseif (isset($trimmed[0]) && $trimmed[0] == "'") { - // '..., - $trimmed = ltrim($option); - $rtrimmed = null; - while (($option = array_shift($transform_options)) !== null) { - // ..., - $trimmed .= ',' . $option; - $rtrimmed = rtrim($trimmed); - if ($rtrimmed[strlen($rtrimmed) - 1] == "'") { - // ,...' - break; - } - } - $option = mb_substr($rtrimmed, 1, -1); - } - $result[] = stripslashes($option); - } - - return $result; - } - - /** - * Gets all available MIME-types - * - * @access public - * @staticvar array mimetypes - * @return array array[mimetype], array[transformation] - */ - public function getAvailableMimeTypes() - { - static $stack = null; - - if (null !== $stack) { - return $stack; - } - - $stack = []; - $sub_dirs = [ - 'Input/' => 'input_', - 'Output/' => '', - '' => '', - ]; - - foreach ($sub_dirs as $sd => $prefix) { - $handle = opendir('libraries/classes/Plugins/Transformations/' . $sd); - - if (! $handle) { - $stack[$prefix . 'transformation'] = []; - $stack[$prefix . 'transformation_file'] = []; - continue; - } - - $filestack = []; - while ($file = readdir($handle)) { - // Ignore hidden files - if ($file[0] == '.') { - continue; - } - // Ignore old plugins (.class in filename) - if (strpos($file, '.class') !== false) { - continue; - } - $filestack[] = $file; - } - - closedir($handle); - sort($filestack); - - foreach ($filestack as $file) { - if (preg_match('|^[^.].*_.*_.*\.php$|', $file)) { - // File contains transformation functions. - $parts = explode('_', str_replace('.php', '', $file)); - $mimetype = $parts[0] . "/" . $parts[1]; - $stack['mimetype'][$mimetype] = $mimetype; - - $stack[$prefix . 'transformation'][] = $mimetype . ': ' . $parts[2]; - $stack[$prefix . 'transformation_file'][] = $sd . $file; - if ($sd === '') { - $stack['input_transformation'][] = $mimetype . ': ' . $parts[2]; - $stack['input_transformation_file'][] = $sd . $file; - } - } elseif (preg_match('|^[^.].*\.php$|', $file)) { - // File is a plain mimetype, no functions. - $base = str_replace('.php', '', $file); - - if ($base != 'global') { - $mimetype = str_replace('_', '/', $base); - $stack['mimetype'][$mimetype] = $mimetype; - $stack['empty_mimetype'][$mimetype] = $mimetype; - } - } - } - } - return $stack; - } - - /** - * Returns the class name of the transformation - * - * @param string $filename transformation file name - * - * @return string the class name of transformation - */ - public function getClassName($filename) - { - // get the transformation class name - $class_name = explode(".php", $filename); - $class_name = 'PhpMyAdmin\\' . str_replace('/', '\\', mb_substr($class_name[0], 18)); - - return $class_name; - } - - /** - * Returns the description of the transformation - * - * @param string $file transformation file - * - * @return string the description of the transformation - */ - public function getDescription($file) - { - $include_file = 'libraries/classes/Plugins/Transformations/' . $file; - /** @var TransformationsInterface $class_name */ - $class_name = $this->getClassName($include_file); - if (class_exists($class_name)) { - return $class_name::getInfo(); - } - return ''; - } - - /** - * Returns the name of the transformation - * - * @param string $file transformation file - * - * @return string the name of the transformation - */ - public function getName($file) - { - $include_file = 'libraries/classes/Plugins/Transformations/' . $file; - /** @var TransformationsInterface $class_name */ - $class_name = $this->getClassName($include_file); - if (class_exists($class_name)) { - return $class_name::getName(); - } - return ''; - } - - /** - * Fixups old MIME or transformation name to new one - * - * - applies some hardcoded fixups - * - adds spaces after _ and numbers - * - capitalizes words - * - removes back spaces - * - * @param string $value Value to fixup - * - * @return string - */ - public function fixUpMime($value) - { - $value = str_replace( - [ - "jpeg", - "png", - ], - [ - "JPEG", - "PNG", - ], - $value - ); - return str_replace( - ' ', - '', - ucwords( - preg_replace('/([0-9_]+)/', '$1 ', $value) - ) - ); - } - - /** - * Gets the mimetypes for all columns 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 - * @param boolean $strict whether to include only results having a mimetype set - * @param boolean $fullName whether to use full column names as the key - * - * @access public - * - * @return array|bool [field_name][field_key] = field_value - */ - public function getMime($db, $table, $strict = false, $fullName = false) - { - $relation = new Relation($GLOBALS['dbi']); - $cfgRelation = $relation->getRelationsParam(); - - if (! $cfgRelation['mimework']) { - return false; - } - - $com_qry = ''; - if ($fullName) { - $com_qry .= "SELECT CONCAT(" - . "`db_name`, '.', `table_name`, '.', `column_name`" - . ") AS column_name, "; - } else { - $com_qry = "SELECT `column_name`, "; - } - $com_qry .= '`mimetype`, - `transformation`, - `transformation_options`, - `input_transformation`, - `input_transformation_options` - FROM ' . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['column_info']) . ' - WHERE `db_name` = \'' . $GLOBALS['dbi']->escapeString($db) . '\' - AND `table_name` = \'' . $GLOBALS['dbi']->escapeString($table) . '\' - AND ( `mimetype` != \'\'' . (! $strict ? ' - OR `transformation` != \'\' - OR `transformation_options` != \'\' - OR `input_transformation` != \'\' - OR `input_transformation_options` != \'\'' : '') . ')'; - $result = $GLOBALS['dbi']->fetchResult( - $com_qry, - 'column_name', - null, - DatabaseInterface::CONNECT_CONTROL - ); - - foreach ($result as $column => $values) { - // convert mimetype to new format (f.e. Text_Plain, etc) - $values['mimetype'] = $this->fixUpMime($values['mimetype']); - - // For transformation of form - // output/image_jpeg__inline.inc.php - // extract dir part. - $dir = explode('/', $values['transformation']); - $subdir = ''; - if (count($dir) === 2) { - $subdir = ucfirst($dir[0]) . '/'; - $values['transformation'] = $dir[1]; - } - - $values['transformation'] = $this->fixUpMime($values['transformation']); - $values['transformation'] = $subdir . $values['transformation']; - $result[$column] = $values; - } - - return $result; - } - - /** - * Set a single mimetype to a certain value. - * - * @param string $db the name of the db - * @param string $table the name of the table - * @param string $key the name of the column - * @param string $mimetype the mimetype of the column - * @param string $transformation the transformation of the column - * @param string $transformationOpts the transformation options of the column - * @param string $inputTransform the input transformation of the column - * @param string $inputTransformOpts the input transformation options of the column - * @param boolean $forcedelete force delete, will erase any existing - * comments for this column - * - * @access public - * - * @return boolean true, if comment-query was made. - */ - public function setMime( - $db, - $table, - $key, - $mimetype, - $transformation, - $transformationOpts, - $inputTransform, - $inputTransformOpts, - $forcedelete = false - ) { - $relation = new Relation($GLOBALS['dbi']); - $cfgRelation = $relation->getRelationsParam(); - - if (! $cfgRelation['mimework']) { - return false; - } - - // lowercase mimetype & transformation - $mimetype = mb_strtolower($mimetype); - $transformation = mb_strtolower($transformation); - - // Do we have any parameter to set? - $has_value = ( - strlen($mimetype) > 0 || - strlen($transformation) > 0 || - strlen($transformationOpts) > 0 || - strlen($inputTransform) > 0 || - strlen($inputTransformOpts) > 0 - ); - - $test_qry = ' - SELECT `mimetype`, - `comment` - FROM ' . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['column_info']) . ' - WHERE `db_name` = \'' . $GLOBALS['dbi']->escapeString($db) . '\' - AND `table_name` = \'' . $GLOBALS['dbi']->escapeString($table) . '\' - AND `column_name` = \'' . $GLOBALS['dbi']->escapeString($key) . '\''; - - $test_rs = $relation->queryAsControlUser( - $test_qry, - true, - DatabaseInterface::QUERY_STORE - ); - - if ($test_rs && $GLOBALS['dbi']->numRows($test_rs) > 0) { - $row = @$GLOBALS['dbi']->fetchAssoc($test_rs); - $GLOBALS['dbi']->freeResult($test_rs); - - if (! $forcedelete && ($has_value || strlen($row['comment']) > 0)) { - $upd_query = 'UPDATE ' - . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['column_info']) - . ' SET ' - . '`mimetype` = \'' - . $GLOBALS['dbi']->escapeString($mimetype) . '\', ' - . '`transformation` = \'' - . $GLOBALS['dbi']->escapeString($transformation) . '\', ' - . '`transformation_options` = \'' - . $GLOBALS['dbi']->escapeString($transformationOpts) . '\', ' - . '`input_transformation` = \'' - . $GLOBALS['dbi']->escapeString($inputTransform) . '\', ' - . '`input_transformation_options` = \'' - . $GLOBALS['dbi']->escapeString($inputTransformOpts) . '\''; - } else { - $upd_query = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['column_info']); - } - $upd_query .= ' - WHERE `db_name` = \'' . $GLOBALS['dbi']->escapeString($db) . '\' - AND `table_name` = \'' . $GLOBALS['dbi']->escapeString($table) - . '\' - AND `column_name` = \'' . $GLOBALS['dbi']->escapeString($key) - . '\''; - } elseif ($has_value) { - $upd_query = 'INSERT INTO ' - . Util::backquote($cfgRelation['db']) - . '.' . Util::backquote($cfgRelation['column_info']) - . ' (db_name, table_name, column_name, mimetype, ' - . 'transformation, transformation_options, ' - . 'input_transformation, input_transformation_options) ' - . ' VALUES(' - . '\'' . $GLOBALS['dbi']->escapeString($db) . '\',' - . '\'' . $GLOBALS['dbi']->escapeString($table) . '\',' - . '\'' . $GLOBALS['dbi']->escapeString($key) . '\',' - . '\'' . $GLOBALS['dbi']->escapeString($mimetype) . '\',' - . '\'' . $GLOBALS['dbi']->escapeString($transformation) . '\',' - . '\'' . $GLOBALS['dbi']->escapeString($transformationOpts) . '\',' - . '\'' . $GLOBALS['dbi']->escapeString($inputTransform) . '\',' - . '\'' . $GLOBALS['dbi']->escapeString($inputTransformOpts) . '\')'; - } - - if (isset($upd_query)) { - return $relation->queryAsControlUser($upd_query); - } - - return false; - } - - - /** - * GLOBAL Plugin functions - */ - - /** - * Delete related transformation details - * after deleting database. table or column - * - * @param string $db Database name - * @param string $table Table name - * @param string $column Column name - * - * @return boolean State of the query execution - */ - public function clear($db, $table = '', $column = '') - { - $relation = new Relation($GLOBALS['dbi']); - $cfgRelation = $relation->getRelationsParam(); - - if (! isset($cfgRelation['column_info'])) { - return false; - } - - $delete_sql = 'DELETE FROM ' - . Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['column_info']) - . ' WHERE '; - - if (($column != '') && ($table != '')) { - $delete_sql .= '`db_name` = \'' . $db . '\' AND ' - . '`table_name` = \'' . $table . '\' AND ' - . '`column_name` = \'' . $column . '\' '; - } elseif ($table != '') { - $delete_sql .= '`db_name` = \'' . $db . '\' AND ' - . '`table_name` = \'' . $table . '\' '; - } else { - $delete_sql .= '`db_name` = \'' . $db . '\' '; - } - - return $GLOBALS['dbi']->tryQuery($delete_sql); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Twig/CoreExtension.php b/srcs/phpmyadmin/libraries/classes/Twig/CoreExtension.php deleted file mode 100644 index e6e2142..0000000 --- a/srcs/phpmyadmin/libraries/classes/Twig/CoreExtension.php +++ /dev/null @@ -1,41 +0,0 @@ - ['html']] - ), - new TwigFilter( - 'link', - 'PhpMyAdmin\Core::linkURL' - ), - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Twig/I18n/NodeTrans.php b/srcs/phpmyadmin/libraries/classes/Twig/I18n/NodeTrans.php deleted file mode 100644 index 6fae7aa..0000000 --- a/srcs/phpmyadmin/libraries/classes/Twig/I18n/NodeTrans.php +++ /dev/null @@ -1,171 +0,0 @@ -node). - * The attributes are automatically made available as array items ($this['name']). - * - * @param Node $body Body of node trans - * @param Node $plural Node plural - * @param AbstractExpression $count Node count - * @param Node $context Node context - * @param Node $notes Node notes - * @param int $lineno The line number - * @param string $tag The tag name associated with the Node - */ - public function __construct( - Node $body, - Node $plural = null, - AbstractExpression $count = null, - Node $context = null, - Node $notes = null, - $lineno, - $tag = null - ) { - $nodes = ['body' => $body]; - if (null !== $count) { - $nodes['count'] = $count; - } - if (null !== $plural) { - $nodes['plural'] = $plural; - } - if (null !== $context) { - $nodes['context'] = $context; - } - if (null !== $notes) { - $nodes['notes'] = $notes; - } - - Node::__construct($nodes, [], $lineno, $tag); - } - - /** - * Compiles the node to PHP. - * - * @param Compiler $compiler Node compiler - * - * @return void - */ - public function compile(Compiler $compiler) - { - $compiler->addDebugInfo($this); - - list($msg, $vars) = $this->compileString($this->getNode('body')); - - if ($this->hasNode('plural')) { - list($msg1, $vars1) = $this->compileString($this->getNode('plural')); - - $vars = array_merge($vars, $vars1); - } - - $function = $this->getTransFunction( - $this->hasNode('plural'), - $this->hasNode('context') - ); - - if ($this->hasNode('notes')) { - $message = trim($this->getNode('notes')->getAttribute('data')); - - // line breaks are not allowed cause we want a single line comment - $message = str_replace(["\n", "\r"], ' ', $message); - $compiler->write("// l10n: {$message}\n"); - } - - if ($vars) { - $compiler - ->write('echo strtr(' . $function . '(') - ->subcompile($msg) - ; - - if ($this->hasNode('plural')) { - $compiler - ->raw(', ') - ->subcompile($msg1) - ->raw(', abs(') - ->subcompile($this->hasNode('count') ? $this->getNode('count') : null) - ->raw(')') - ; - } - - $compiler->raw('), array('); - - foreach ($vars as $var) { - if ('count' === $var->getAttribute('name')) { - $compiler - ->string('%count%') - ->raw(' => abs(') - ->subcompile($this->hasNode('count') ? $this->getNode('count') : null) - ->raw('), ') - ; - } else { - $compiler - ->string('%' . $var->getAttribute('name') . '%') - ->raw(' => ') - ->subcompile($var) - ->raw(', ') - ; - } - } - - $compiler->raw("));\n"); - } else { - $compiler->write('echo ' . $function . '('); - - if ($this->hasNode('context')) { - $context = trim($this->getNode('context')->getAttribute('data')); - $compiler->write('"' . $context . '", '); - } - - $compiler->subcompile($msg); - - if ($this->hasNode('plural')) { - $compiler - ->raw(', ') - ->subcompile($msg1) - ->raw(', abs(') - ->subcompile($this->hasNode('count') ? $this->getNode('count') : null) - ->raw(')') - ; - } - - $compiler->raw(");\n"); - } - } - - /** - * @param bool $plural Return plural or singular function to use - * @param bool $hasMsgContext It has message context? - * - * @return string - */ - protected function getTransFunction($plural, $hasMsgContext = false) - { - if ($hasMsgContext) { - return $plural ? '_ngettext' : '_pgettext'; - } - - return $plural ? '_ngettext' : '_gettext'; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Twig/I18n/TokenParserTrans.php b/srcs/phpmyadmin/libraries/classes/Twig/I18n/TokenParserTrans.php deleted file mode 100644 index 25aade0..0000000 --- a/srcs/phpmyadmin/libraries/classes/Twig/I18n/TokenParserTrans.php +++ /dev/null @@ -1,85 +0,0 @@ -getLine(); - $stream = $this->parser->getStream(); - $count = null; - $plural = null; - $notes = null; - $context = null; - - if (! $stream->test(Token::BLOCK_END_TYPE)) { - $body = $this->parser->getExpressionParser()->parseExpression(); - } else { - $stream->expect(Token::BLOCK_END_TYPE); - $body = $this->parser->subparse([$this, 'decideForFork']); - $next = $stream->next()->getValue(); - - if ('plural' === $next) { - $count = $this->parser->getExpressionParser()->parseExpression(); - $stream->expect(Token::BLOCK_END_TYPE); - $plural = $this->parser->subparse([$this, 'decideForFork']); - - if ('notes' === $stream->next()->getValue()) { - $stream->expect(Token::BLOCK_END_TYPE); - $notes = $this->parser->subparse([$this, 'decideForEnd'], true); - } - } elseif ('context' === $next) { - $stream->expect(Token::BLOCK_END_TYPE); - $context = $this->parser->subparse([$this, 'decideForEnd'], true); - } elseif ('notes' === $next) { - $stream->expect(Token::BLOCK_END_TYPE); - $notes = $this->parser->subparse([$this, 'decideForEnd'], true); - } - } - - $stream->expect(Token::BLOCK_END_TYPE); - - $this->checkTransString($body, $lineno); - - return new NodeTrans($body, $plural, $count, $context, $notes, $lineno, $this->getTag()); - } - - /** - * Tests the current token for a type. - * - * @param Token $token Twig token to test - * - * @return bool - */ - public function decideForFork(Token $token) - { - return $token->test(['plural', 'context', 'notes', 'endtrans']); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Twig/I18nExtension.php b/srcs/phpmyadmin/libraries/classes/Twig/I18nExtension.php deleted file mode 100644 index 4d0c14f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Twig/I18nExtension.php +++ /dev/null @@ -1,45 +0,0 @@ -getDisplay(); - }, - ['is_safe' => ['html']] - ), - new TwigFilter( - 'error', - function (string $string) { - return Message::error($string)->getDisplay(); - }, - ['is_safe' => ['html']] - ), - new TwigFilter( - 'raw_success', - function (string $string) { - return Message::rawSuccess($string)->getDisplay(); - }, - ['is_safe' => ['html']] - ), - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Twig/PluginsExtension.php b/srcs/phpmyadmin/libraries/classes/Twig/PluginsExtension.php deleted file mode 100644 index 1706a62..0000000 --- a/srcs/phpmyadmin/libraries/classes/Twig/PluginsExtension.php +++ /dev/null @@ -1,52 +0,0 @@ - ['html']] - ), - new TwigFunction( - 'get_choice', - 'PhpMyAdmin\Plugins::getChoice', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_default_plugin', - 'PhpMyAdmin\Plugins::getDefault', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_options', - 'PhpMyAdmin\Plugins::getOptions', - ['is_safe' => ['html']] - ), - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Twig/RelationExtension.php b/srcs/phpmyadmin/libraries/classes/Twig/RelationExtension.php deleted file mode 100644 index 6aca5d3..0000000 --- a/srcs/phpmyadmin/libraries/classes/Twig/RelationExtension.php +++ /dev/null @@ -1,71 +0,0 @@ - ['html']] - ), - new TwigFunction( - 'get_display_field', - [ - $relation, - 'getDisplayField', - ], - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_foreign_data', - [ - $relation, - 'getForeignData', - ] - ), - new TwigFunction( - 'get_tables', - [ - $relation, - 'getTables', - ] - ), - new TwigFunction( - 'search_column_in_foreigners', - [ - $relation, - 'searchColumnInForeigners', - ] - ), - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Twig/SanitizeExtension.php b/srcs/phpmyadmin/libraries/classes/Twig/SanitizeExtension.php deleted file mode 100644 index 0256109..0000000 --- a/srcs/phpmyadmin/libraries/classes/Twig/SanitizeExtension.php +++ /dev/null @@ -1,64 +0,0 @@ - ['html']] - ), - new TwigFilter( - 'js_format', - 'PhpMyAdmin\Sanitize::jsFormat', - ['is_safe' => ['html']] - ), - new TwigFilter( - 'sanitize', - 'PhpMyAdmin\Sanitize::sanitizeMessage', - ['is_safe' => ['html']] - ), - ]; - } - - /** - * Returns a list of functions to add to the existing list. - * - * @return TwigFunction[] - */ - public function getFunctions() - { - return [ - new TwigFunction( - 'get_js_value', - 'PhpMyAdmin\Sanitize::getJsValue', - ['is_safe' => ['html']] - ), - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Twig/ServerPrivilegesExtension.php b/srcs/phpmyadmin/libraries/classes/Twig/ServerPrivilegesExtension.php deleted file mode 100644 index 0a1363c..0000000 --- a/srcs/phpmyadmin/libraries/classes/Twig/ServerPrivilegesExtension.php +++ /dev/null @@ -1,51 +0,0 @@ - ['html']] - ), - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Twig/StorageEngineExtension.php b/srcs/phpmyadmin/libraries/classes/Twig/StorageEngineExtension.php deleted file mode 100644 index 34b87c1..0000000 --- a/srcs/phpmyadmin/libraries/classes/Twig/StorageEngineExtension.php +++ /dev/null @@ -1,37 +0,0 @@ - ['html']] - ), - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Twig/TableExtension.php b/srcs/phpmyadmin/libraries/classes/Twig/TableExtension.php deleted file mode 100644 index 1dc4ef1..0000000 --- a/srcs/phpmyadmin/libraries/classes/Twig/TableExtension.php +++ /dev/null @@ -1,36 +0,0 @@ - ['html']] - ), - new TwigFunction( - 'get_hidden_fields', - 'PhpMyAdmin\Url::getHiddenFields', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_common', - 'PhpMyAdmin\Url::getCommon', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_common_raw', - 'PhpMyAdmin\Url::getCommonRaw', - ['is_safe' => ['html']] - ), - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Twig/UtilExtension.php b/srcs/phpmyadmin/libraries/classes/Twig/UtilExtension.php deleted file mode 100644 index 809b07e..0000000 --- a/srcs/phpmyadmin/libraries/classes/Twig/UtilExtension.php +++ /dev/null @@ -1,212 +0,0 @@ - ['html']] - ), - new TwigFunction( - 'extract_column_spec', - 'PhpMyAdmin\Util::extractColumnSpec' - ), - new TwigFunction( - 'format_byte_down', - 'PhpMyAdmin\Util::formatByteDown' - ), - new TwigFunction( - 'format_number', - 'PhpMyAdmin\Util::formatNumber' - ), - new TwigFunction( - 'format_sql', - 'PhpMyAdmin\Util::formatSql', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_button_or_image', - 'PhpMyAdmin\Util::getButtonOrImage', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_docu_link', - 'PhpMyAdmin\Util::getDocuLink', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_list_navigator', - 'PhpMyAdmin\Util::getListNavigator', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'show_docu', - 'PhpMyAdmin\Util::showDocu', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_dropdown', - 'PhpMyAdmin\Util::getDropdown', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_fk_checkbox', - 'PhpMyAdmin\Util::getFKCheckbox', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_gis_datatypes', - 'PhpMyAdmin\Util::getGISDatatypes' - ), - new TwigFunction( - 'get_gis_functions', - 'PhpMyAdmin\Util::getGISFunctions' - ), - new TwigFunction( - 'get_html_tab', - 'PhpMyAdmin\Util::getHtmlTab', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_icon', - 'PhpMyAdmin\Util::getIcon', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_image', - 'PhpMyAdmin\Util::getImage', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_radio_fields', - 'PhpMyAdmin\Util::getRadioFields', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_select_upload_file_block', - 'PhpMyAdmin\Util::getSelectUploadFileBlock', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_script_name_for_option', - 'PhpMyAdmin\Util::getScriptNameForOption', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_start_and_number_of_rows_panel', - 'PhpMyAdmin\Util::getStartAndNumberOfRowsPanel', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_supported_datatypes', - 'PhpMyAdmin\Util::getSupportedDatatypes', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'is_foreign_key_supported', - 'PhpMyAdmin\Util::isForeignKeySupported' - ), - new TwigFunction( - 'link_or_button', - 'PhpMyAdmin\Util::linkOrButton', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'link_to_var_documentation', - 'PhpMyAdmin\Util::linkToVarDocumentation', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'localised_date', - 'PhpMyAdmin\Util::localisedDate' - ), - new TwigFunction( - 'show_hint', - 'PhpMyAdmin\Util::showHint', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'show_icons', - 'PhpMyAdmin\Util::showIcons' - ), - new TwigFunction( - 'show_mysql_docu', - 'PhpMyAdmin\Util::showMySQLDocu', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_mysql_docu_url', - 'PhpMyAdmin\Util::getMySQLDocuURL', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'show_php_docu', - 'PhpMyAdmin\Util::showPHPDocu', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'sortable_table_header', - 'PhpMyAdmin\Util::sortableTableHeader', - ['is_safe' => ['html']] - ), - new TwigFunction( - 'timespan_format', - 'PhpMyAdmin\Util::timespanFormat' - ), - new TwigFunction( - 'generate_hidden_max_file_size', - 'PhpMyAdmin\Util::generateHiddenMaxFileSize', - ['is_safe' => ['html']] - ), - ]; - } - - /** - * Returns a list of filters to add to the existing list. - * - * @return TwigFilter[] - */ - public function getFilters() - { - return [ - new TwigFilter( - 'convert_bit_default_value', - 'PhpMyAdmin\Util::convertBitDefaultValue' - ), - new TwigFilter( - 'escape_mysql_wildcards', - 'PhpMyAdmin\Util::convertBitDefaultValue' - ), - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/TwoFactor.php b/srcs/phpmyadmin/libraries/classes/TwoFactor.php deleted file mode 100644 index cc26528..0000000 --- a/srcs/phpmyadmin/libraries/classes/TwoFactor.php +++ /dev/null @@ -1,303 +0,0 @@ -initRelationParamsCache(); - - $this->userPreferences = new UserPreferences(); - $this->user = $user; - $this->_available = $this->getAvailable(); - $this->config = $this->readConfig(); - $this->_writable = ($this->config['type'] == 'db'); - $this->_backend = $this->getBackend(); - } - - /** - * Reads the configuration - * - * @return array - */ - public function readConfig() - { - $result = []; - $config = $this->userPreferences->load(); - if (isset($config['config_data']['2fa'])) { - $result = $config['config_data']['2fa']; - } - $result['type'] = $config['type']; - if (! isset($result['backend'])) { - $result['backend'] = ''; - } - if (! isset($result['settings'])) { - $result['settings'] = []; - } - return $result; - } - - /** - * Get any property of this class - * - * @param string $property name of the property - * - * @return mixed|void if property exist, value of the relevant property - */ - public function __get($property) - { - switch ($property) { - case 'backend': - return $this->_backend; - case 'available': - return $this->_available; - case 'writable': - return $this->_writable; - case 'showSubmit': - $backend = $this->_backend; - return $backend::$showSubmit; - } - } - - /** - * Returns list of available backends - * - * @return array - */ - public function getAvailable() - { - $result = []; - if ($GLOBALS['cfg']['DBG']['simple2fa']) { - $result[] = 'simple'; - } - if (class_exists(Google2FA::class)) { - $result[] = 'application'; - } - if (class_exists(U2FServer::class)) { - $result[] = 'key'; - } - return $result; - } - - /** - * Returns list of missing dependencies - * - * @return array - */ - public function getMissingDeps() - { - $result = []; - if (! class_exists(Google2FA::class)) { - $result[] = [ - 'class' => Application::getName(), - 'dep' => 'pragmarx/google2fa-qrcode', - ]; - } - if (! class_exists('BaconQrCode\Renderer\Image\Png')) { - $result[] = [ - 'class' => Application::getName(), - 'dep' => 'bacon/bacon-qr-code', - ]; - } - if (! class_exists(U2FServer::class)) { - $result[] = [ - 'class' => Key::getName(), - 'dep' => 'samyoul/u2f-php-server', - ]; - } - return $result; - } - - /** - * Returns class name for given name - * - * @param string $name Backend name - * - * @return string - */ - public function getBackendClass($name) - { - $result = TwoFactorPlugin::class; - if (in_array($name, $this->_available)) { - $result = 'PhpMyAdmin\\Plugins\\TwoFactor\\' . ucfirst($name); - } elseif (! empty($name)) { - $result = Invalid::class; - } - return $result; - } - - /** - * Returns backend for current user - * - * @return TwoFactorPlugin - */ - public function getBackend() - { - $name = $this->getBackendClass($this->config['backend']); - return new $name($this); - } - - /** - * Checks authentication, returns true on success - * - * @param boolean $skip_session Skip session cache - * - * @return boolean - */ - public function check($skip_session = false) - { - if ($skip_session) { - return $this->_backend->check(); - } - if (empty($_SESSION['two_factor_check'])) { - $_SESSION['two_factor_check'] = $this->_backend->check(); - } - return $_SESSION['two_factor_check']; - } - - /** - * Renders user interface to enter two-factor authentication - * - * @return string HTML code - */ - public function render() - { - return $this->_backend->getError() . $this->_backend->render(); - } - - /** - * Renders user interface to configure two-factor authentication - * - * @return string HTML code - */ - public function setup() - { - return $this->_backend->getError() . $this->_backend->setup(); - } - - /** - * Saves current configuration. - * - * @return true|Message - */ - public function save() - { - return $this->userPreferences->persistOption('2fa', $this->config, null); - } - - /** - * Changes two-factor authentication settings - * - * The object might stay in partialy changed setup - * if configuration fails. - * - * @param string $name Backend name - * - * @return boolean - */ - public function configure($name) - { - $this->config = [ - 'backend' => $name, - ]; - if ($name === '') { - $cls = $this->getBackendClass($name); - $this->config['settings'] = []; - $this->_backend = new $cls($this); - } else { - if (! in_array($name, $this->_available)) { - return false; - } - $cls = $this->getBackendClass($name); - $this->config['settings'] = []; - $this->_backend = new $cls($this); - if (! $this->_backend->configure()) { - return false; - } - } - $result = $this->save(); - if ($result !== true) { - $result->display(); - } - return true; - } - - /** - * Returns array with all available backends - * - * @return array - */ - public function getAllBackends() - { - $all = array_merge([''], $this->available); - $backends = []; - foreach ($all as $name) { - $cls = $this->getBackendClass($name); - $backends[] = [ - 'id' => $cls::$id, - 'name' => $cls::getName(), - 'description' => $cls::getDescription(), - ]; - } - return $backends; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Types.php b/srcs/phpmyadmin/libraries/classes/Types.php deleted file mode 100644 index 40bc15f..0000000 --- a/srcs/phpmyadmin/libraries/classes/Types.php +++ /dev/null @@ -1,875 +0,0 @@ -_dbi = $dbi; - } - - /** - * Returns list of unary operators. - * - * @return string[] - */ - public function getUnaryOperators() - { - return [ - 'IS NULL', - 'IS NOT NULL', - "= ''", - "!= ''", - ]; - } - - /** - * Check whether operator is unary. - * - * @param string $op operator name - * - * @return boolean - */ - public function isUnaryOperator($op) - { - return in_array($op, $this->getUnaryOperators()); - } - - /** - * Returns list of operators checking for NULL. - * - * @return string[] - */ - public function getNullOperators() - { - return [ - 'IS NULL', - 'IS NOT NULL', - ]; - } - - /** - * ENUM search operators - * - * @return string[] - */ - public function getEnumOperators() - { - return [ - '=', - '!=', - ]; - } - - /** - * TEXT search operators - * - * @return string[] - */ - public function getTextOperators() - { - return [ - 'LIKE', - 'LIKE %...%', - 'NOT LIKE', - '=', - '!=', - 'REGEXP', - 'REGEXP ^...$', - 'NOT REGEXP', - "= ''", - "!= ''", - 'IN (...)', - 'NOT IN (...)', - 'BETWEEN', - 'NOT BETWEEN', - ]; - } - - /** - * Number search operators - * - * @return string[] - */ - public function getNumberOperators() - { - return [ - '=', - '>', - '>=', - '<', - '<=', - '!=', - '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 string[] - */ - public function getTypeOperators($type, $null) - { - $ret = []; - $class = $this->getTypeClass($type); - - if (strncasecmp($type, 'enum', 4) == 0) { - $ret = array_merge($ret, $this->getEnumOperators()); - } elseif ($class == 'CHAR') { - $ret = array_merge($ret, $this->getTextOperators()); - } else { - $ret = array_merge($ret, $this->getNumberOperators()); - } - - if ($null) { - $ret = array_merge($ret, $this->getNullOperators()); - } - - return $ret; - } - - /** - * Returns operators for given type as html options - * - * @param string $type Type of field - * @param boolean $null Whether field can be NULL - * @param string $selectedOperator Option to be selected - * - * @return string Generated Html - */ - public function getTypeOperatorsHtml($type, $null, $selectedOperator = null) - { - $html = ''; - - foreach ($this->getTypeOperators($type, $null) as $fc) { - if (isset($selectedOperator) && $selectedOperator == $fc) { - $selected = ' selected="selected"'; - } else { - $selected = ''; - } - $html .= ''; - } - - return $html; - } - - /** - * Returns the data type description. - * - * @param string $type The data type to get a description. - * - * @return string - * - */ - public function getTypeDescription($type) - { - $type = mb_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'); - case 'JSON': - return __( - 'Stores and enables efficient access to data in JSON' - . ' (JavaScript Object Notation) documents' - ); - } - 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 = mb_strtoupper((string) $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'; - - case 'JSON': - return 'JSON'; - } - - return ''; - } - - /** - * Returns array of functions available for a class. - * - * @param string $class The class to get function list. - * - * @return string[] - * - */ - public function getFunctionsClass($class) - { - $isMariaDB = $this->_dbi->isMariaDB(); - $serverVersion = $this->_dbi->getVersion(); - - switch ($class) { - case 'CHAR': - $ret = [ - 'AES_DECRYPT', - 'AES_ENCRYPT', - 'BIN', - 'CHAR', - 'COMPRESS', - 'CURRENT_USER', - 'DATABASE', - 'DAYNAME', - 'DES_DECRYPT', - 'DES_ENCRYPT', - 'ENCRYPT', - 'HEX', - 'INET6_NTOA', - 'INET_NTOA', - 'LOAD_FILE', - 'LOWER', - 'LTRIM', - 'MD5', - 'MONTHNAME', - 'OLD_PASSWORD', - 'PASSWORD', - 'QUOTE', - 'REVERSE', - 'RTRIM', - 'SHA1', - 'SOUNDEX', - 'SPACE', - 'TRIM', - 'UNCOMPRESS', - 'UNHEX', - 'UPPER', - 'USER', - 'UUID', - 'VERSION', - ]; - - if (($isMariaDB && $serverVersion < 100012) - || $serverVersion < 50603 - ) { - $ret = array_diff($ret, ['INET6_NTOA']); - } - return $ret; - - case 'DATE': - return [ - '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 = [ - 'ABS', - 'ACOS', - 'ASCII', - 'ASIN', - 'ATAN', - 'BIT_LENGTH', - 'BIT_COUNT', - 'CEILING', - 'CHAR_LENGTH', - 'CONNECTION_ID', - 'COS', - 'COT', - 'CRC32', - 'DAYOFMONTH', - 'DAYOFWEEK', - 'DAYOFYEAR', - 'DEGREES', - 'EXP', - 'FLOOR', - 'HOUR', - 'INET6_ATON', - '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', - ]; - if (($isMariaDB && $serverVersion < 100012) - || $serverVersion < 50603 - ) { - $ret = array_diff($ret, ['INET6_ATON']); - } - return $ret; - - case 'SPATIAL': - if ($serverVersion >= 50600) { - return [ - 'ST_GeomFromText', - 'ST_GeomFromWKB', - - 'ST_GeomCollFromText', - 'ST_LineFromText', - 'ST_MLineFromText', - 'ST_PointFromText', - 'ST_MPointFromText', - 'ST_PolyFromText', - 'ST_MPolyFromText', - - 'ST_GeomCollFromWKB', - 'ST_LineFromWKB', - 'ST_MLineFromWKB', - 'ST_PointFromWKB', - 'ST_MPointFromWKB', - 'ST_PolyFromWKB', - 'ST_MPolyFromWKB', - ]; - } else { - return [ - 'GeomFromText', - 'GeomFromWKB', - - 'GeomCollFromText', - 'LineFromText', - 'MLineFromText', - 'PointFromText', - 'MPointFromText', - 'PolyFromText', - 'MPolyFromText', - - 'GeomCollFromWKB', - 'LineFromWKB', - 'MLineFromWKB', - 'PointFromWKB', - 'MPointFromWKB', - 'PolyFromWKB', - 'MPolyFromWKB', - ]; - } - } - return []; - } - - /** - * Returns array of functions available for a type. - * - * @param string $type The data type to get function list. - * - * @return string[] - * - */ - public function getFunctions($type) - { - $class = $this->getTypeClass($type); - return $this->getFunctionsClass($class); - } - - /** - * Returns array of all functions available. - * - * @return string[] - * - */ - 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 string[] - * - */ - public function getAttributes() - { - return [ - '', - '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 string[] - * - */ - public function getColumns() - { - $isMariaDB = $this->_dbi->isMariaDB(); - $serverVersion = $this->_dbi->getVersion(); - - // most used types - $ret = [ - 'INT', - 'VARCHAR', - 'TEXT', - 'DATE', - ]; - // numeric - $ret[_pgettext('numeric types', 'Numeric')] = [ - 'TINYINT', - 'SMALLINT', - 'MEDIUMINT', - 'INT', - 'BIGINT', - '-', - 'DECIMAL', - 'FLOAT', - 'DOUBLE', - 'REAL', - '-', - 'BIT', - 'BOOLEAN', - 'SERIAL', - ]; - - // Date/Time - $ret[_pgettext('date and time types', 'Date and time')] = [ - 'DATE', - 'DATETIME', - 'TIMESTAMP', - 'TIME', - 'YEAR', - ]; - - // Text - $ret[_pgettext('string types', 'String')] = [ - 'CHAR', - 'VARCHAR', - '-', - 'TINYTEXT', - 'TEXT', - 'MEDIUMTEXT', - 'LONGTEXT', - '-', - 'BINARY', - 'VARBINARY', - '-', - 'TINYBLOB', - 'BLOB', - 'MEDIUMBLOB', - 'LONGBLOB', - '-', - 'ENUM', - 'SET', - ]; - - $ret[_pgettext('spatial types', 'Spatial')] = [ - 'GEOMETRY', - 'POINT', - 'LINESTRING', - 'POLYGON', - 'MULTIPOINT', - 'MULTILINESTRING', - 'MULTIPOLYGON', - 'GEOMETRYCOLLECTION', - ]; - - if (($isMariaDB && $serverVersion > 100207) - || (! $isMariaDB && $serverVersion >= 50708)) { - $ret['JSON'] = [ - 'JSON', - ]; - } - - return $ret; - } - - /** - * Returns an array of integer types - * - * @return string[] integer types - */ - public function getIntegerTypes() - { - return [ - 'tinyint', - 'smallint', - 'mediumint', - 'int', - 'bigint', - ]; - } - - /** - * Returns the min and max values of a given integer type - * - * @param string $type integer type - * @param boolean $signed whether signed - * - * @return string[] min and max values - */ - public function getIntegerRange($type, $signed = true) - { - static $min_max_data = [ - 'unsigned' => [ - 'tinyint' => [ - '0', - '255', - ], - 'smallint' => [ - '0', - '65535', - ], - 'mediumint' => [ - '0', - '16777215', - ], - 'int' => [ - '0', - '4294967295', - ], - 'bigint' => [ - '0', - '18446744073709551615', - ], - ], - 'signed' => [ - 'tinyint' => [ - '-128', - '127', - ], - 'smallint' => [ - '-32768', - '32767', - ], - 'mediumint' => [ - '-8388608', - '8388607', - ], - 'int' => [ - '-2147483648', - '2147483647', - ], - 'bigint' => [ - '-9223372036854775808', - '9223372036854775807', - ], - ], - ]; - $relevantArray = $signed - ? $min_max_data['signed'] - : $min_max_data['unsigned']; - return isset($relevantArray[$type]) ? $relevantArray[$type] : [ - '', - '', - ]; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Url.php b/srcs/phpmyadmin/libraries/classes/Url.php deleted file mode 100644 index aeae50a..0000000 --- a/srcs/phpmyadmin/libraries/classes/Url.php +++ /dev/null @@ -1,274 +0,0 @@ - 0) { - $params['db'] = $db; - } - if (strlen((string) $table) > 0) { - $params['table'] = $table; - } - } - - if (! empty($GLOBALS['server']) - && $GLOBALS['server'] != $GLOBALS['cfg']['ServerDefault'] - ) { - $params['server'] = $GLOBALS['server']; - } - if (empty($PMA_Config->getCookie('pma_lang')) && ! empty($GLOBALS['lang'])) { - $params['lang'] = $GLOBALS['lang']; - } - - if (! is_array($skip)) { - if (isset($params[$skip])) { - unset($params[$skip]); - } - } else { - foreach ($skip as $skipping) { - if (isset($params[$skipping])) { - unset($params[$skipping]); - } - } - } - - return Url::getHiddenFields($params); - } - - /** - * create hidden form fields from array with name => value - * - * - * $values = array( - * 'aaa' => aaa, - * 'bbb' => array( - * 'bbb_0', - * 'bbb_1', - * ), - * 'ccc' => array( - * 'a' => 'ccc_a', - * 'b' => 'ccc_b', - * ), - * ); - * echo Url::getHiddenFields($values); - * - * // produces: - * - * - * - * - * - * - * - * @param array $values hidden values - * @param string $pre prefix - * @param bool $is_token if token already added in hidden input field - * - * @return string form fields of type hidden - */ - public static function getHiddenFields(array $values, $pre = '', $is_token = false) - { - $fields = ''; - - /* Always include token in plain forms */ - if ($is_token === false) { - $values['token'] = $_SESSION[' PMA_token ']; - } - - foreach ($values as $name => $value) { - if (! empty($pre)) { - $name = $pre . '[' . $name . ']'; - } - - if (is_array($value)) { - $fields .= Url::getHiddenFields($value, $name, true); - } else { - // do not generate an ending "\n" because - // Url::getHiddenInputs() is sometimes called - // from a JS document.write() - $fields .= ''; - } - } - - return $fields; - } - - /** - * Generates text with URL parameters. - * - * - * $params['myparam'] = 'myvalue'; - * $params['db'] = 'mysql'; - * $params['table'] = 'rights'; - * // note the missing ? - * echo 'script.php' . Url::getCommon($params); - * // produces with cookies enabled: - * // script.php?myparam=myvalue&db=mysql&table=rights - * // with cookies disabled: - * // script.php?server=1&lang=en&myparam=myvalue&db=mysql - * // &table=rights - * - * // note the missing ? - * echo 'script.php' . Url::getCommon(); - * // produces with cookies enabled: - * // script.php - * // with cookies disabled: - * // script.php?server=1&lang=en - * - * - * @param mixed $params optional, Contains an associative array with url params - * @param string $divider optional character to use instead of '?' - * - * @return string string with URL parameters - * @access public - */ - public static function getCommon($params = [], $divider = '?') - { - return htmlspecialchars( - Url::getCommonRaw($params, $divider) - ); - } - - /** - * Generates text with URL parameters. - * - * - * $params['myparam'] = 'myvalue'; - * $params['db'] = 'mysql'; - * $params['table'] = 'rights'; - * // note the missing ? - * echo 'script.php' . Url::getCommon($params); - * // produces with cookies enabled: - * // script.php?myparam=myvalue&db=mysql&table=rights - * // with cookies disabled: - * // script.php?server=1&lang=en&myparam=myvalue&db=mysql - * // &table=rights - * - * // note the missing ? - * echo 'script.php' . Url::getCommon(); - * // produces with cookies enabled: - * // script.php - * // with cookies disabled: - * // script.php?server=1&lang=en - * - * - * @param mixed $params optional, Contains an associative array with url params - * @param string $divider optional character to use instead of '?' - * - * @return string string with URL parameters - * @access public - */ - public static function getCommonRaw($params = [], $divider = '?') - { - /** @var Config $PMA_Config */ - global $PMA_Config; - $separator = Url::getArgSeparator(); - - // avoid overwriting when creating navi panel links to servers - if (isset($GLOBALS['server']) - && $GLOBALS['server'] != $GLOBALS['cfg']['ServerDefault'] - && ! isset($params['server']) - && ! $PMA_Config->get('is_setup') - ) { - $params['server'] = $GLOBALS['server']; - } - - if (empty($PMA_Config->getCookie('pma_lang')) && ! empty($GLOBALS['lang'])) { - $params['lang'] = $GLOBALS['lang']; - } - - $query = http_build_query($params, '', $separator); - - if ($divider != '?' || strlen($query) > 0) { - return $divider . $query; - } - - return ''; - } - - /** - * Returns url separator - * - * extracted from arg_separator.input as set in php.ini - * we do not use arg_separator.output to avoid problems with & and & - * - * @param string $encode whether to encode separator or not, - * currently 'none' or 'html' - * - * @return string character used for separating url parts usually ; or & - * @access public - */ - public static function getArgSeparator($encode = 'none') - { - static $separator = null; - static $html_separator = null; - - if (null === $separator) { - // use separators defined by php, but prefer ';' - // as recommended by W3C - // (see https://www.w3.org/TR/1999/REC-html401-19991224/appendix - // /notes.html#h-B.2.2) - $arg_separator = ini_get('arg_separator.input'); - if (mb_strpos($arg_separator, ';') !== false) { - $separator = ';'; - } elseif (strlen($arg_separator) > 0) { - $separator = $arg_separator[0]; - } else { - $separator = '&'; - } - $html_separator = htmlentities($separator); - } - - switch ($encode) { - case 'html': - return $html_separator; - case 'text': - case 'none': - default: - return $separator; - } - } -} diff --git a/srcs/phpmyadmin/libraries/classes/UserPassword.php b/srcs/phpmyadmin/libraries/classes/UserPassword.php deleted file mode 100644 index f9ee4fb..0000000 --- a/srcs/phpmyadmin/libraries/classes/UserPassword.php +++ /dev/null @@ -1,286 +0,0 @@ -serverPrivileges = $serverPrivileges; - } - - /** - * Send the message as an ajax request - * - * @param array $change_password_message Message to display - * @param string $sql_query SQL query executed - * - * @return void - */ - public function getChangePassMessage(array $change_password_message, $sql_query = '') - { - $response = Response::getInstance(); - if ($response->isAjax()) { - /** - * If in an Ajax request, we don't need to show the rest of the page - */ - if ($change_password_message['error']) { - $response->addJSON('message', $change_password_message['msg']); - $response->setRequestStatus(false); - } else { - $sql_query = Util::getMessage( - $change_password_message['msg'], - $sql_query, - 'success' - ); - $response->addJSON('message', $sql_query); - } - exit; - } - } - - /** - * Generate the message - * - * @return array error value and message - */ - public function setChangePasswordMsg() - { - $error = false; - $message = Message::success(__('The profile has been updated.')); - - if ($_POST['nopass'] != '1') { - if (strlen($_POST['pma_pw']) === 0 || strlen($_POST['pma_pw2']) === 0) { - $message = Message::error(__('The password is empty!')); - $error = true; - } elseif ($_POST['pma_pw'] !== $_POST['pma_pw2']) { - $message = Message::error( - __('The passwords aren\'t the same!') - ); - $error = true; - } elseif (strlen($_POST['pma_pw']) > 256) { - $message = Message::error(__('Password is too long!')); - $error = true; - } - } - return [ - 'error' => $error, - 'msg' => $message, - ]; - } - - /** - * Change the password - * - * @param string $password New password - * @param string $message Message - * @param array $change_password_message Message to show - * - * @return void - */ - public function changePassword($password, $message, array $change_password_message) - { - global $auth_plugin; - - $hashing_function = $this->changePassHashingFunction(); - - list($username, $hostname) = $GLOBALS['dbi']->getCurrentUserAndHost(); - - $serverType = Util::getServerType(); - $serverVersion = $GLOBALS['dbi']->getVersion(); - - if (isset($_POST['authentication_plugin']) - && ! empty($_POST['authentication_plugin']) - ) { - $orig_auth_plugin = $_POST['authentication_plugin']; - } else { - $orig_auth_plugin = $this->serverPrivileges->getCurrentAuthenticationPlugin( - 'change', - $username, - $hostname - ); - } - - $sql_query = 'SET password = ' - . (($password == '') ? '\'\'' : $hashing_function . '(\'***\')'); - - if ($serverType == 'MySQL' - && $serverVersion >= 50706 - ) { - $sql_query = 'ALTER USER \'' . $username . '\'@\'' . $hostname - . '\' IDENTIFIED WITH ' . $orig_auth_plugin . ' BY ' - . (($password == '') ? '\'\'' : '\'***\''); - } elseif (($serverType == 'MySQL' - && $serverVersion >= 50507) - || ($serverType == 'MariaDB' - && $serverVersion >= 50200) - ) { - // For MySQL versions 5.5.7+ and MariaDB versions 5.2+, - // explicitly set value of `old_passwords` so that - // it does not give an error while using - // the PASSWORD() function - if ($orig_auth_plugin == 'sha256_password') { - $value = 2; - } else { - $value = 0; - } - $GLOBALS['dbi']->tryQuery('SET `old_passwords` = ' . $value . ';'); - } - - $this->changePassUrlParamsAndSubmitQuery( - $username, - $hostname, - $password, - $sql_query, - $hashing_function, - $orig_auth_plugin - ); - - $auth_plugin->handlePasswordChange($password); - $this->getChangePassMessage($change_password_message, $sql_query); - $this->changePassDisplayPage($message, $sql_query); - } - - /** - * Generate the hashing function - * - * @return string - */ - private function changePassHashingFunction() - { - if (Core::isValid( - $_POST['authentication_plugin'], - 'identical', - 'mysql_old_password' - )) { - $hashing_function = 'OLD_PASSWORD'; - } else { - $hashing_function = 'PASSWORD'; - } - return $hashing_function; - } - - /** - * Changes password for a user - * - * @param string $username Username - * @param string $hostname Hostname - * @param string $password Password - * @param string $sql_query SQL query - * @param string $hashing_function Hashing function - * @param string $orig_auth_plugin Original Authentication Plugin - * - * @return void - */ - private function changePassUrlParamsAndSubmitQuery( - $username, - $hostname, - $password, - $sql_query, - $hashing_function, - $orig_auth_plugin - ) { - $err_url = 'user_password.php' . Url::getCommon(); - - $serverType = Util::getServerType(); - $serverVersion = $GLOBALS['dbi']->getVersion(); - - if ($serverType == 'MySQL' && $serverVersion >= 50706) { - $local_query = 'ALTER USER \'' . $username . '\'@\'' . $hostname . '\'' - . ' IDENTIFIED with ' . $orig_auth_plugin . ' BY ' - . (($password == '') - ? '\'\'' - : '\'' . $GLOBALS['dbi']->escapeString($password) . '\''); - } elseif ($serverType == 'MariaDB' - && $serverVersion >= 50200 - && $serverVersion < 100100 - && $orig_auth_plugin !== '' - ) { - if ($orig_auth_plugin == 'mysql_native_password') { - // Set the hashing method used by PASSWORD() - // to be 'mysql_native_password' type - $GLOBALS['dbi']->tryQuery('SET old_passwords = 0;'); - } elseif ($orig_auth_plugin == 'sha256_password') { - // Set the hashing method used by PASSWORD() - // to be 'sha256_password' type - $GLOBALS['dbi']->tryQuery('SET `old_passwords` = 2;'); - } - - $hashedPassword = $this->serverPrivileges->getHashedPassword($_POST['pma_pw']); - - $local_query = "UPDATE `mysql`.`user` SET" - . " `authentication_string` = '" . $hashedPassword - . "', `Password` = '', " - . " `plugin` = '" . $orig_auth_plugin . "'" - . " WHERE `User` = '" . $username . "' AND Host = '" - . $hostname . "';"; - } else { - $local_query = 'SET password = ' . (($password == '') - ? '\'\'' - : $hashing_function . '(\'' - . $GLOBALS['dbi']->escapeString($password) . '\')'); - } - if (! @$GLOBALS['dbi']->tryQuery($local_query)) { - Util::mysqlDie( - $GLOBALS['dbi']->getError(), - $sql_query, - false, - $err_url - ); - } - - // Flush privileges after successful password change - $GLOBALS['dbi']->tryQuery("FLUSH PRIVILEGES;"); - } - - /** - * Display the page - * - * @param string $message Message - * @param string $sql_query SQL query - * - * @return void - */ - private function changePassDisplayPage($message, $sql_query) - { - echo '

    ' , __('Change password') , '

    ' , "\n\n"; - echo Util::getMessage( - $message, - $sql_query, - 'success' - ); - echo '' , "\n" - , '' , __('Back') , ''; - exit; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/UserPreferences.php b/srcs/phpmyadmin/libraries/classes/UserPreferences.php deleted file mode 100644 index 3f737ac..0000000 --- a/srcs/phpmyadmin/libraries/classes/UserPreferences.php +++ /dev/null @@ -1,287 +0,0 @@ -relation = new Relation($GLOBALS['dbi']); - $this->template = new Template(); - } - - /** - * Common initialization for user preferences modification pages - * - * @param ConfigFile $cf Config file instance - * - * @return void - */ - public function pageInit(ConfigFile $cf) - { - $forms_all_keys = UserFormList::getFields(); - $cf->resetConfigData(); // start with a clean instance - $cf->setAllowedKeys($forms_all_keys); - $cf->setCfgUpdateReadMapping( - [ - 'Server/hide_db' => 'Servers/1/hide_db', - 'Server/only_db' => 'Servers/1/only_db', - ] - ); - $cf->updateWithGlobalConfig($GLOBALS['cfg']); - } - - /** - * Loads user preferences - * - * Returns an array: - * * config_data - path => value pairs - * * mtime - last modification time - * * type - 'db' (config read from pmadb) or 'session' (read from user session) - * - * @return array - */ - public function load() - { - $cfgRelation = $this->relation->getRelationsParam(); - if (! $cfgRelation['userconfigwork']) { - // no pmadb table, use session storage - if (! isset($_SESSION['userconfig'])) { - $_SESSION['userconfig'] = [ - 'db' => [], - 'ts' => time(), - ]; - } - return [ - 'config_data' => $_SESSION['userconfig']['db'], - 'mtime' => $_SESSION['userconfig']['ts'], - 'type' => 'session', - ]; - } - // load configuration from pmadb - $query_table = Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['userconfig']); - $query = 'SELECT `config_data`, UNIX_TIMESTAMP(`timevalue`) ts' - . ' FROM ' . $query_table - . ' WHERE `username` = \'' - . $GLOBALS['dbi']->escapeString($cfgRelation['user']) - . '\''; - $row = $GLOBALS['dbi']->fetchSingleRow($query, 'ASSOC', DatabaseInterface::CONNECT_CONTROL); - - return [ - 'config_data' => $row ? json_decode($row['config_data'], true) : [], - 'mtime' => $row ? $row['ts'] : time(), - 'type' => 'db', - ]; - } - - /** - * Saves user preferences - * - * @param array $config_array configuration array - * - * @return true|Message - */ - public function save(array $config_array) - { - $cfgRelation = $this->relation->getRelationsParam(); - $server = isset($GLOBALS['server']) - ? $GLOBALS['server'] - : $GLOBALS['cfg']['ServerDefault']; - $cache_key = 'server_' . $server; - if (! $cfgRelation['userconfigwork']) { - // no pmadb table, use session storage - $_SESSION['userconfig'] = [ - 'db' => $config_array, - 'ts' => time(), - ]; - if (isset($_SESSION['cache'][$cache_key]['userprefs'])) { - unset($_SESSION['cache'][$cache_key]['userprefs']); - } - return true; - } - - // save configuration to pmadb - $query_table = Util::backquote($cfgRelation['db']) . '.' - . Util::backquote($cfgRelation['userconfig']); - $query = 'SELECT `username` FROM ' . $query_table - . ' WHERE `username` = \'' - . $GLOBALS['dbi']->escapeString($cfgRelation['user']) - . '\''; - - $has_config = $GLOBALS['dbi']->fetchValue( - $query, - 0, - 0, - DatabaseInterface::CONNECT_CONTROL - ); - $config_data = json_encode($config_array); - if ($has_config) { - $query = 'UPDATE ' . $query_table - . ' SET `timevalue` = NOW(), `config_data` = \'' - . $GLOBALS['dbi']->escapeString($config_data) - . '\'' - . ' WHERE `username` = \'' - . $GLOBALS['dbi']->escapeString($cfgRelation['user']) - . '\''; - } else { - $query = 'INSERT INTO ' . $query_table - . ' (`username`, `timevalue`,`config_data`) ' - . 'VALUES (\'' - . $GLOBALS['dbi']->escapeString($cfgRelation['user']) . '\', NOW(), ' - . '\'' . $GLOBALS['dbi']->escapeString($config_data) . '\')'; - } - if (isset($_SESSION['cache'][$cache_key]['userprefs'])) { - unset($_SESSION['cache'][$cache_key]['userprefs']); - } - if (! $GLOBALS['dbi']->tryQuery($query, DatabaseInterface::CONNECT_CONTROL)) { - $message = Message::error(__('Could not save configuration')); - $message->addMessage( - Message::rawError( - $GLOBALS['dbi']->getError(DatabaseInterface::CONNECT_CONTROL) - ), - '

    ' - ); - return $message; - } - return true; - } - - /** - * Returns a user preferences array filtered by $cfg['UserprefsDisallow'] - * (blacklist) and keys from user preferences form (whitelist) - * - * @param array $config_data path => value pairs - * - * @return array - */ - public function apply(array $config_data) - { - $cfg = []; - $blacklist = array_flip($GLOBALS['cfg']['UserprefsDisallow']); - $whitelist = array_flip(UserFormList::getFields()); - // whitelist some additional fields which are custom handled - $whitelist['ThemeDefault'] = true; - $whitelist['lang'] = true; - $whitelist['Server/hide_db'] = true; - $whitelist['Server/only_db'] = true; - $whitelist['2fa'] = true; - foreach ($config_data as $path => $value) { - if (! isset($whitelist[$path]) || isset($blacklist[$path])) { - continue; - } - Core::arrayWrite($path, $cfg, $value); - } - return $cfg; - } - - /** - * Updates one user preferences option (loads and saves to database). - * - * No validation is done! - * - * @param string $path configuration - * @param mixed $value value - * @param mixed $default_value default value - * - * @return true|Message - */ - public function persistOption($path, $value, $default_value) - { - $prefs = $this->load(); - if ($value === $default_value) { - if (isset($prefs['config_data'][$path])) { - unset($prefs['config_data'][$path]); - } else { - return true; - } - } else { - $prefs['config_data'][$path] = $value; - } - return $this->save($prefs['config_data']); - } - - /** - * Redirects after saving new user preferences - * - * @param string $file_name Filename - * @param array|null $params URL parameters - * @param string $hash Hash value - * - * @return void - */ - public function redirect( - $file_name, - $params = null, - $hash = null - ) { - // redirect - $url_params = ['saved' => 1]; - if (is_array($params)) { - $url_params = array_merge($params, $url_params); - } - if ($hash) { - $hash = '#' . urlencode($hash); - } - Core::sendHeaderLocation('./' . $file_name - . Url::getCommonRaw($url_params) . $hash); - } - - /** - * Shows form which allows to quickly load - * settings stored in browser's local storage - * - * @return string - */ - public function autoloadGetHeader() - { - if (isset($_REQUEST['prefs_autoload']) - && $_REQUEST['prefs_autoload'] == 'hide' - ) { - $_SESSION['userprefs_autoload'] = true; - return ''; - } - - $script_name = basename(basename($GLOBALS['PMA_PHP_SELF'])); - $return_url = $script_name . '?' . http_build_query($_GET, '', '&'); - - return $this->template->render('preferences/autoload', [ - 'hidden_inputs' => Url::getHiddenInputs(), - 'return_url' => $return_url, - ]); - } -} diff --git a/srcs/phpmyadmin/libraries/classes/UserPreferencesHeader.php b/srcs/phpmyadmin/libraries/classes/UserPreferencesHeader.php deleted file mode 100644 index cecbb05..0000000 --- a/srcs/phpmyadmin/libraries/classes/UserPreferencesHeader.php +++ /dev/null @@ -1,148 +0,0 @@ - 'prefs_manage.php', - 'text' => __('Manage your settings'), - ] - ) . "\n"; - /* Second authentication factor */ - $content .= Util::getHtmlTab( - [ - 'link' => 'prefs_twofactor.php', - 'text' => __('Two-factor authentication'), - ] - ) . "\n"; - - $content .= self::displayTabsWithIcon(); - - return $template->render( - 'list/unordered', - [ - 'id' => 'topmenu2', - 'class' => 'user_prefs_tabs', - 'content' => $content, - ] - ) . '
    '; - } - - /** - * @return string - */ - protected static function displayTabsWithIcon(): string - { - $form_param = $_GET['form'] ?? null; - $tabs_icons = [ - 'Features' => 'b_tblops', - 'Sql' => 'b_sql', - 'Navi' => 'b_select', - 'Main' => 'b_props', - 'Import' => 'b_import', - 'Export' => 'b_export', - ]; - $script_name = basename($GLOBALS['PMA_PHP_SELF']); - $content = null; - foreach (UserFormList::getAll() as $formset) { - $formset_class = UserFormList::get($formset); - $tab = [ - 'link' => 'prefs_forms.php', - 'text' => $formset_class::getName(), - 'icon' => $tabs_icons[$formset], - 'active' => 'prefs_forms.php' === $script_name && $formset === $form_param, - ]; - $content .= Util::getHtmlTab($tab, ['form' => $formset]) . "\n"; - } - return $content; - } - - /** - * @return string|null - */ - protected static function displayConfigurationSavedMessage(): ?string - { - // show "configuration saved" message and reload navigation panel if needed - if (! empty($_GET['saved'])) { - return Message::rawSuccess(__('Configuration has been saved.')) - ->getDisplay(); - } - - return null; - } - - /** - * @param Relation $relation Relation instance - * - * @return string|null - */ - protected static function sessionStorageWarning(Relation $relation): ?string - { - // warn about using session storage for settings - $cfgRelation = $relation->getRelationsParam(); - if (! $cfgRelation['userconfigwork']) { - $msg = __( - 'Your preferences will be saved for current session only. Storing them ' - . 'permanently requires %sphpMyAdmin configuration storage%s.' - ); - $msg = Sanitize::sanitizeMessage( - sprintf($msg, '[doc@linked-tables]', '[/doc]') - ); - return Message::notice($msg) - ->getDisplay(); - } - - return null; - } -} diff --git a/srcs/phpmyadmin/libraries/classes/Util.php b/srcs/phpmyadmin/libraries/classes/Util.php deleted file mode 100644 index ad7bcdf..0000000 --- a/srcs/phpmyadmin/libraries/classes/Util.php +++ /dev/null @@ -1,4975 +0,0 @@ -'; - 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 - * - * The image name should match CSS class defined in icons.css.php - * - * @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 = '', array $attributes = []) - { - $alternate = htmlspecialchars($alternate); - - if (isset($attributes['class'])) { - $attributes['class'] = "icon ic_$image " . $attributes['class']; - } else { - $attributes['class'] = "icon ic_$image"; - } - - // set all other attributes - $attr_str = ''; - foreach ($attributes as $key => $value) { - if (! in_array($key, ['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'; - return sprintf($template, $title, $alt, $attr_str); - } - - /** - * 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 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, ['_' => '\\_', '%' => '\\%']); - } // 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, ['\\_' => '_', '\\%' => '%']); - } // 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 = []; - - if ($quote === null) { - $quotes[] = '`'; - $quotes[] = '"'; - $quotes[] = "'"; - } else { - $quotes[] = $quote; - } - - foreach ($quotes as $quote) { - if (mb_substr($quoted_string, 0, 1) === $quote - && mb_substr($quoted_string, -1, 1) === $quote - ) { - $unquoted_string = mb_substr($quoted_string, 1, -1); - // replace escaped quotes - $unquoted_string = str_replace( - $quote . $quote, - $quote, - $unquoted_string - ); - return $unquoted_string; - } - } - - return $quoted_string; - } - - /** - * format sql strings - * - * @param string $sqlQuery raw SQL string - * @param boolean $truncate truncate the query if it is too long - * - * @return string the formatted sql - * - * @global array $cfg the configuration array - * - * @access public - * @todo move into PMA_Sql - */ - public static function formatSql($sqlQuery, $truncate = false) - { - global $cfg; - - if ($truncate - && mb_strlen($sqlQuery) > $cfg['MaxCharactersInDisplayedSQL'] - ) { - $sqlQuery = mb_substr( - $sqlQuery, - 0, - $cfg['MaxCharactersInDisplayedSQL'] - ) . '[...]'; - } - return '
    ' . "\n"
    -            . htmlspecialchars($sqlQuery) . "\n"
    -            . '
    '; - } // end of the "formatSql()" function - - /** - * Displays a button to copy content to clipboard - * - * @param string $text Text to copy to clipboard - * - * @return string the html link - * - * @access public - */ - public static function showCopyToClipboard($text) - { - $open_link = ' ' . __('Copy') . ''; - return $open_link; - } // end of the 'showCopyToClipboard()' function - - /** - * Displays a link to the documentation as an icon - * - * @param string $link documentation link - * @param string $target optional link target - * @param boolean $bbcode optional flag indicating whether to output bbcode - * - * @return string the html link - * - * @access public - */ - public static function showDocLink($link, $target = 'documentation', $bbcode = false) - { - if ($bbcode) { - return "[a@$link@$target][dochelpicon][/a]"; - } - - return '' - . self::getImage('b_help', __('Documentation')) - . ''; - } // end of the 'showDocLink()' function - - /** - * Get a URL link to the official MySQL documentation - * - * @param string $link contains name of page/anchor that is being linked - * @param string $anchor anchor to page part - * - * @return string the URL link - * - * @access public - */ - public static function getMySQLDocuURL($link, $anchor = '') - { - // Fixup for newly used names: - $link = str_replace('_', '-', mb_strtolower($link)); - - if (empty($link)) { - $link = 'index'; - } - $mysql = '5.5'; - $lang = 'en'; - if (isset($GLOBALS['dbi'])) { - $serverVersion = $GLOBALS['dbi']->getVersion(); - if ($serverVersion >= 50700) { - $mysql = '5.7'; - } elseif ($serverVersion >= 50600) { - $mysql = '5.6'; - } elseif ($serverVersion >= 50500) { - $mysql = '5.5'; - } - } - $url = 'https://dev.mysql.com/doc/refman/' - . $mysql . '/' . $lang . '/' . $link . '.html'; - if (! empty($anchor)) { - $url .= '#' . $anchor; - } - - return Core::linkURL($url); - } - - /** - * Get a link to variable documentation - * - * @param string $name The variable name - * @param boolean $useMariaDB Use only MariaDB documentation - * @param string $text (optional) The text for the link - * @return string link or empty string - */ - public static function linkToVarDocumentation( - string $name, - bool $useMariaDB = false, - string $text = null - ): string { - $html = ''; - try { - $type = KBSearch::MYSQL; - if ($useMariaDB) { - $type = KBSearch::MARIADB; - } - $docLink = KBSearch::getByName($name, $type); - $html = Util::showMySQLDocu( - $name, - false, - $docLink, - $text - ); - } catch (KBException $e) { - unset($e);// phpstan workaround - } - return $html; - } - - /** - * Displays a link to the official MySQL documentation - * - * @param string $link contains name of page/anchor that is being linked - * @param bool $bigIcon whether to use big icon (like in left frame) - * @param string|null $url href attribute - * @param string|null $text text of link - * @param string $anchor anchor to page part - * - * @return string the html link - * - * @access public - */ - public static function showMySQLDocu( - $link, - bool $bigIcon = false, - $url = null, - $text = null, - $anchor = '' - ): string { - if ($url === null) { - $url = self::getMySQLDocuURL($link, $anchor); - } - $openLink = ''; - $closeLink = ''; - $html = ''; - - if ($bigIcon) { - $html = $openLink . - self::getImage('b_sqlhelp', __('Documentation')) - . $closeLink; - } elseif ($text !== null) { - $html = $openLink . $text . $closeLink; - } else { - $html = self::showDocLink($url, 'mysql_doc'); - } - - return $html; - } // 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, however - * provide consistent URL for testsuite - */ - if (! defined('TESTSUITE') && @file_exists(ROOT_PATH . 'doc/html/index.html')) { - return 'doc/html/' . $url; - } - - return Core::linkURL('https://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 - * @param boolean $bbcode Optional flag indicating whether to output bbcode - * - * @return string the html link - * - * @access public - */ - public static function showDocu($page, $anchor = '', $bbcode = false) - { - return self::showDocLink(self::getDocuLink($page, $anchor), 'documentation', $bbcode); - } // 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 = Core::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') - . '' . $message . '' - . ''; - } - - /** - * Displays a MySQL error message in the main panel when $exit is true. - * Returns the error message otherwise. - * - * @param string|bool $server_msg Server's error message. - * @param string $sql_query The SQL query that failed. - * @param bool $is_modify_link Whether to show a "modify" link or not. - * @param string $back_url URL for the "back" link (full path is - * not required). - * @param bool $exit Whether execution should be stopped or - * the error message should be returned. - * - * @return string - * - * @global string $table The current table. - * @global string $db The current database. - * - * @access public - */ - public static function mysqlDie( - $server_msg = '', - $sql_query = '', - $is_modify_link = true, - $back_url = '', - $exit = true - ) { - global $table, $db; - - /** - * Error message to be built. - * @var string $error_msg - */ - $error_msg = ''; - - // Checking for any server errors. - if (empty($server_msg)) { - $server_msg = $GLOBALS['dbi']->getError(); - } - - // Finding the query that failed, if not specified. - if (empty($sql_query) && ! empty($GLOBALS['sql_query'])) { - $sql_query = $GLOBALS['sql_query']; - } - $sql_query = trim($sql_query); - - /** - * The lexer used for analysis. - * @var Lexer $lexer - */ - $lexer = new Lexer($sql_query); - - /** - * The parser used for analysis. - * @var Parser $parser - */ - $parser = new Parser($lexer->list); - - /** - * The errors found by the lexer and the parser. - * @var array $errors - */ - $errors = ParserError::get([$lexer, $parser]); - - if (empty($sql_query)) { - $formatted_sql = ''; - } elseif (count($errors)) { - $formatted_sql = htmlspecialchars($sql_query); - } else { - $formatted_sql = self::formatSql($sql_query, true); - } - - $error_msg .= '

    ' . __('Error') . '

    '; - - // For security reasons, if the MySQL refuses the connection, the query - // is hidden so no details are revealed. - if (! empty($sql_query) && ! mb_strstr($sql_query, 'connect')) { - // Static analysis errors. - if (! empty($errors)) { - $error_msg .= '

    ' . __('Static analysis:') - . '

    '; - $error_msg .= '

    ' . sprintf( - __('%d errors were found during analysis.'), - count($errors) - ) . '

    '; - $error_msg .= '

      '; - $error_msg .= implode( - ParserError::format( - $errors, - '
    1. %2$s (near "%4$s" at position %5$d)
    2. ' - ) - ); - $error_msg .= '

    '; - } - - // Display the SQL query and link to MySQL documentation. - $error_msg .= '

    ' . __('SQL query:') . '' . self::showCopyToClipboard($sql_query) . "\n"; - $formattedSqlToLower = mb_strtolower($formatted_sql); - - // TODO: Show documentation for all statement types. - if (mb_strstr($formattedSqlToLower, 'select')) { - // please show me help to the error on select - $error_msg .= self::showMySQLDocu('SELECT'); - } - - if ($is_modify_link) { - $_url_params = [ - 'sql_query' => $sql_query, - 'show_query' => 1, - ]; - if (strlen($table) > 0) { - $_url_params['db'] = $db; - $_url_params['table'] = $table; - $doedit_goto = ''; - } elseif (strlen($db) > 0) { - $_url_params['db'] = $db; - $doedit_goto = ''; - } else { - $doedit_goto = ''; - } - - $error_msg .= $doedit_goto - . self::getIcon('b_edit', __('Edit')) - . ''; - } - - $error_msg .= '

    ' . "\n" - . '

    ' . "\n" - . $formatted_sql . "\n" - . '

    ' . "\n"; - } - - // Display server's error. - if (! empty($server_msg)) { - $server_msg = preg_replace( - "@((\015\012)|(\015)|(\012)){3,}@", - "\n\n", - $server_msg - ); - - // Adds a link to MySQL documentation. - $error_msg .= '

    ' . "\n" - . ' ' . __('MySQL said: ') . '' - . self::showMySQLDocu('Error-messages-server') - . "\n" - . '

    ' . "\n"; - - // The error message will be displayed within a CODE segment. - // To preserve original formatting, but allow word-wrapping, - // a couple of replacements are done. - // All non-single blanks and TAB-characters are replaced with their - // HTML-counterpart - $server_msg = str_replace( - [ - ' ', - "\t", - ], - [ - '  ', - '    ', - ], - $server_msg - ); - - // Replace line breaks - $server_msg = nl2br($server_msg); - - $error_msg .= '' . $server_msg . '
    '; - } - - $error_msg .= '
    '; - $_SESSION['Import_message']['message'] = $error_msg; - - if (! $exit) { - return $error_msg; - } - - /** - * If this is an AJAX request, there is no "Back" link and - * `Response()` is used to send the response. - */ - $response = Response::getInstance(); - if ($response->isAjax()) { - $response->setRequestStatus(false); - $response->addJSON('message', $error_msg); - exit; - } - - if (! empty($back_url)) { - if (mb_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"; - } - - exit($error_msg); - } - - /** - * Check the correct row count - * - * @param string $db the db name - * @param array $table the table infos - * - * @return int the possibly modified row count - * - */ - private static function _checkRowCount($db, array $table) - { - $rowCount = 0; - - 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 the navigation panel; - // but we can check row count if this is a view or the - // information_schema database - // since Table::countRecords() returns a limited row count - // in this case. - - // set this because Table::countRecords() can use it - $tbl_is_view = $table['TABLE_TYPE'] == 'VIEW'; - - if ($tbl_is_view || $GLOBALS['dbi']->isSystemSchema($db)) { - $rowCount = $GLOBALS['dbi'] - ->getTable($db, $table['Name']) - ->countRecords(); - } - } - return $rowCount; - } - - /** - * returns array with tables of given db with extended information and grouped - * - * @param string $db name of db - * @param string $tables name of tables - * @param integer $limit_offset list offset - * @param int|bool $limit_count max tables to return - * - * @return array (recursive) grouped table list - */ - public static function getTableList( - $db, - $tables = null, - $limit_offset = 0, - $limit_count = false - ) { - $sep = $GLOBALS['cfg']['NavigationTreeTableSeparator']; - - if ($tables === null) { - $tables = $GLOBALS['dbi']->getTablesFull( - $db, - '', - false, - $limit_offset, - $limit_count - ); - if ($GLOBALS['cfg']['NaturalOrder']) { - uksort($tables, 'strnatcasecmp'); - } - } - - if (count($tables) < 1) { - return $tables; - } - - $default = [ - 'Name' => '', - 'Rows' => 0, - 'Comment' => '', - 'disp_name' => '', - ]; - - $table_groups = []; - - foreach ($tables as $table_name => $table) { - $table['Rows'] = self::_checkRowCount($db, $table); - - // in $group we save the reference to the place in $table_groups - // where to store the table info - if ($GLOBALS['cfg']['NavigationTreeEnableGrouping'] - && $sep && mb_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] = []; - $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] = []; - $group[$group_name][$group_name] = $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] = []; - } - $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) { - if (! (Context::isKeyword($a_name) & Token::FLAG_KEYWORD_RESERVED) - ) { - return $a_name; - } - } - - // '0' is also empty for php :-( - if (strlen((string) $a_name) > 0 && $a_name !== '*') { - return '`' . str_replace('`', '``', (string) $a_name) . '`'; - } - - return $a_name; - } // end of the 'backquote()' function - - /** - * Adds backquotes on both sides of a database, table or field name. - * in compatibility mode - * - * example: - * - * echo backquoteCompat('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) { - if (! Context::isKeyword($a_name)) { - return $a_name; - } - } - - // @todo add more compatibility cases (ORACLE for example) - switch ($compatibility) { - case 'MSSQL': - $quote = '"'; - break; - default: - $quote = "`"; - break; - } - - // '0' is also empty for php :-( - if (strlen((string) $a_name) > 0 && $a_name !== '*') { - return $quote . $a_name . $quote; - } - - return $a_name; - } // end of the 'backquoteCompat()' function - - /** - * Prepare the message and the query - * usually the message is the result of the query executed - * - * @param Message|string $message the message to display - * @param string $sql_query the query to display - * @param string $type the type (level) of the message - * - * @return string - * - * @access public - */ - public static function getMessage( - $message, - $sql_query = null, - $type = 'notice' - ) { - global $cfg; - $template = new Template(); - $retval = ''; - - if (null === $sql_query) { - if (! empty($GLOBALS['display_query'])) { - $sql_query = $GLOBALS['display_query']; - } elseif (! empty($GLOBALS['unparsed_sql'])) { - $sql_query = $GLOBALS['unparsed_sql']; - } elseif (! empty($GLOBALS['sql_query'])) { - $sql_query = $GLOBALS['sql_query']; - } else { - $sql_query = ''; - } - } - - $render_sql = $cfg['ShowSQL'] == true && ! empty($sql_query) && $sql_query !== ';'; - - if (isset($GLOBALS['using_bookmark_message'])) { - $retval .= $GLOBALS['using_bookmark_message']->getDisplay(); - unset($GLOBALS['using_bookmark_message']); - } - - if ($render_sql) { - $retval .= '
    ' . "\n"; - } - - if ($message instanceof Message) { - if (isset($GLOBALS['special_message'])) { - $message->addText($GLOBALS['special_message']); - unset($GLOBALS['special_message']); - } - $retval .= $message->getDisplay(); - } else { - $retval .= '
    '; - $retval .= Sanitize::sanitizeMessage($message); - if (isset($GLOBALS['special_message'])) { - $retval .= Sanitize::sanitizeMessage($GLOBALS['special_message']); - unset($GLOBALS['special_message']); - } - $retval .= '
    '; - } - - if ($render_sql) { - $query_too_big = false; - - $queryLength = mb_strlen($sql_query); - if ($queryLength > $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; - $query_base = mb_substr( - $sql_query, - 0, - $cfg['MaxCharactersInDisplayedSQL'] - ) . '[...]'; - } else { - $query_base = $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($query_base)); - $query_base = preg_replace( - '/((\015\012)|(\015)|(\012))/', - $new_line, - $query_base - ); - $query_base = '
    ' . "\n"
    -                    . '$sql = "' . $query_base . '";' . "\n"
    -                    . '
    '; - } elseif ($query_too_big) { - $query_base = '
    ' . "\n" .
    -                    htmlspecialchars($query_base) .
    -                    '
    '; - } else { - $query_base = self::formatSql($query_base); - } - - // Prepares links that may be displayed to edit/explain the query - // (don't go to default pages, we must go to the page - // where the query box is available) - - // Basic url query part - $url_params = []; - if (! isset($GLOBALS['db'])) { - $GLOBALS['db'] = ''; - } - if (strlen($GLOBALS['db']) > 0) { - $url_params['db'] = $GLOBALS['db']; - if (strlen($GLOBALS['table']) > 0) { - $url_params['table'] = $GLOBALS['table']; - $edit_link = 'tbl_sql.php'; - } else { - $edit_link = 'db_sql.php'; - } - } else { - $edit_link = 'server_sql.php'; - } - - // Want to have the query explained - // but only explain a SELECT (that has not been explained) - /* SQL-Parser-Analyzer */ - $explain_link = ''; - $is_select = preg_match('@^SELECT[[:space:]]+@i', $sql_query); - if (! empty($cfg['SQLQuery']['Explain']) && ! $query_too_big) { - $explain_params = $url_params; - if ($is_select) { - $explain_params['sql_query'] = 'EXPLAIN ' . $sql_query; - $explain_link = ' [ ' - . self::linkOrButton( - 'import.php' . Url::getCommon($explain_params), - __('Explain SQL') - ) . ' ]'; - } elseif (preg_match( - '@^EXPLAIN[[:space:]]+SELECT[[:space:]]+@i', - $sql_query - )) { - $explain_params['sql_query'] - = mb_substr($sql_query, 8); - $explain_link = ' [ ' - . self::linkOrButton( - 'import.php' . Url::getCommon($explain_params), - __('Skip Explain SQL') - ) . ']'; - $url = 'https://mariadb.org/explain_analyzer/analyze/' - . '?client=phpMyAdmin&raw_explain=' - . urlencode(self::_generateRowQueryOutput($sql_query)); - $explain_link .= ' [' - . self::linkOrButton( - htmlspecialchars('url.php?url=' . urlencode($url)), - sprintf(__('Analyze Explain at %s'), 'mariadb.org'), - [], - '_blank' - ) . ' ]'; - } - } //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']) - && empty($GLOBALS['show_as_php']) - ) { - $edit_link .= Url::getCommon($url_params); - $edit_link = ' [ ' - . self::linkOrButton($edit_link, __('Edit')) - . ' ]'; - } 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) { - if (! empty($GLOBALS['show_as_php'])) { - $php_link = ' [ ' - . self::linkOrButton( - 'import.php' . Url::getCommon($url_params), - __('Without PHP code') - ) - . ' ]'; - - $php_link .= ' [ ' - . self::linkOrButton( - 'import.php' . Url::getCommon($url_params), - __('Submit query') - ) - . ' ]'; - } else { - $php_params = $url_params; - $php_params['show_as_php'] = 1; - $php_link = ' [ ' - . self::linkOrButton( - 'import.php' . Url::getCommon($php_params), - __('Create PHP code') - ) - . ' ]'; - } - } 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 = 'sql.php' . Url::getCommon($url_params); - $refresh_link = ' [ ' - . self::linkOrButton($refresh_link, __('Refresh')) . ']'; - } else { - $refresh_link = ''; - } //refresh - - $retval .= '
    '; - $retval .= $query_base; - $retval .= '
    '; - - $retval .= ''; - - $retval .= '
    '; - } - - return $retval; - } // end of the 'getMessage()' function - - /** - * Execute an EXPLAIN query and formats results similar to MySQL command line - * utility. - * - * @param string $sqlQuery EXPLAIN query - * - * @return string query resuls - */ - private static function _generateRowQueryOutput($sqlQuery) - { - $ret = ''; - $result = $GLOBALS['dbi']->query($sqlQuery); - if ($result) { - $devider = '+'; - $columnNames = '|'; - $fieldsMeta = $GLOBALS['dbi']->getFieldsMeta($result); - foreach ($fieldsMeta as $meta) { - $devider .= '---+'; - $columnNames .= ' ' . $meta->name . ' |'; - } - $devider .= "\n"; - - $ret .= $devider . $columnNames . "\n" . $devider; - while ($row = $GLOBALS['dbi']->fetchRow($result)) { - $values = '|'; - foreach ($row as $value) { - if ($value === null) { - $value = 'NULL'; - } - $values .= ' ' . $value . ' |'; - } - $ret .= $values . "\n"; - } - $ret .= $devider; - } - return $ret; - } - - /** - * Verifies if current MySQL server supports profiling - * - * @access public - * - * @return boolean whether profiling is supported - */ - public static function profilingSupported() - { - if (! self::cacheExists('profiling_supported')) { - // 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 ($GLOBALS['dbi']->fetchValue("SELECT @@have_profiling") - ) { - self::cacheSet('profiling_supported', true); - } else { - self::cacheSet('profiling_supported', false); - } - } - - return self::cacheGet('profiling_supported'); - } - - /** - * Formats $value to byte view - * - * @param double|int $value the value to format - * @param int $limes the sensitiveness - * @param int $comma the number of decimals to retain - * - * @return array|null the formatted value and its unit - * - * @access public - */ - public static function formatByteDown($value, $limes = 6, $comma = 0) - { - if ($value === null) { - return null; - } - - $byteUnits = [ - /* 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 = pow(10, $comma); - $li = pow(10, $limes); - $unit = $byteUnits[0]; - - for ($d = 6, $ex = 15; $d >= 1; $d--, $ex -= 3) { - $unitSize = $li * pow(10, $ex); - if (isset($byteUnits[$d]) && $value >= $unitSize) { - // use 1024.0 to avoid integer overflow on 64-bit machines - $value = round($value / (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, false); - } else { - // do not reformat, just handle the locale - $return_value = self::formatNumber($value, 0); - } - - return [ - trim($return_value), - $unit, - ]; - } // end of the 'formatByteDown' function - - - /** - * Formats $value to the given length and appends SI prefixes - * with a $length of 0 no truncation occurs, number is only formatted - * 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( - (float) $value, - $digits_right, - /* l10n: Decimal separator */ - __('.'), - /* l10n: Thousands separator */ - __(',') - ); - if (($originalValue != 0) && (floatval($value) == 0)) { - $value = ' <' . (1 / pow(10, $digits_right)); - } - return $value; - } - - // this units needs no translation, ISO - $units = [ - -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', - ]; - /* l10n: Decimal separator */ - $decimal_sep = __('.'); - /* l10n: Thousands separator */ - $thousands_sep = __(','); - - // check for negative value to retain sign - if ($value < 0) { - $sign = '-'; - $value = abs($value); - } else { - $sign = ''; - } - - $dh = pow(10, $digits_right); - - /* - * This gives us the right SI prefix already, - * but $digits_left parameter not incorporated - */ - $d = floor(log10((float) $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 / pow(1000, $d)) + 1); - if ($digits_left > $cur_digits) { - $d -= floor(($digits_left - $cur_digits) / 3); - } - - if ($d < 0 && $only_down) { - $d = 0; - } - - $value = round($value / (pow(1000, $d) / $dh)) / $dh; - $unit = $units[$d]; - - // number_format is not multibyte safe, str_replace is safe - $formattedValue = number_format( - $value, - $digits_right, - $decimal_sep, - $thousands_sep - ); - // If we don't want any zeros, remove them now - if ($noTrailingZero && strpos($formattedValue, $decimal_sep) !== false) { - $formattedValue = preg_replace('/' . preg_quote($decimal_sep, '/') . '?0+$/', '', $formattedValue); - } - - if ($originalValue != 0 && floatval($value) == 0) { - return ' <' . number_format( - 1 / pow(10, $digits_right), - $digits_right, - $decimal_sep, - $thousands_sep - ) - . ' ' . $unit; - } - - return $sign . $formattedValue . ' ' . $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; - - $formatted_size = (string) $formatted_size; - - if (preg_match('/^[0-9]+GB$/', $formatted_size)) { - $return_value = (int) mb_substr( - $formatted_size, - 0, - -2 - ) * pow(1024, 3); - } elseif (preg_match('/^[0-9]+MB$/', $formatted_size)) { - $return_value = (int) mb_substr( - $formatted_size, - 0, - -2 - ) * pow(1024, 2); - } elseif (preg_match('/^[0-9]+K$/', $formatted_size)) { - $return_value = (int) mb_substr( - $formatted_size, - 0, - -1 - ) * pow(1024, 1); - } - return $return_value; - } - - /** - * Writes localised date - * - * @param integer $timestamp the current timestamp - * @param string $format format - * - * @return string the formatted date - * - * @access public - */ - public static function localisedDate($timestamp = -1, $format = '') - { - $month = [ - /* 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 = [ - /* l10n: Short week day name for Sunday */ - _pgettext('Short week day name', 'Sun'), - /* l10n: Short week day name for Monday */ - __('Mon'), - /* l10n: Short week day name for Tuesday */ - __('Tue'), - /* l10n: Short week day name for Wednesday */ - __('Wed'), - /* l10n: Short week day name for Thursday */ - __('Thu'), - /* l10n: Short week day name for Friday */ - __('Fri'), - /* l10n: Short week day name for Saturday */ - __('Sat'), - ]; - - if ($format == '') { - /* l10n: See https://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', (int) $timestamp)], - $format - ); - $date = preg_replace( - '@%[bB]@', - $month[(int) strftime('%m', (int) $timestamp) - 1], - $date - ); - - /* Fill in AM/PM */ - $hours = (int) date('H', (int) $timestamp); - if ($hours >= 12) { - $am_pm = _pgettext('AM/PM indication in time', 'PM'); - } else { - $am_pm = _pgettext('AM/PM indication in time', 'AM'); - } - $date = preg_replace('@%[pP]@', $am_pm, $date); - - $ret = strftime($date, (int) $timestamp); - // Some OSes such as Win8.1 Traditional Chinese version did not produce UTF-8 - // output here. See https://github.com/phpmyadmin/phpmyadmin/issues/10598 - if (mb_detect_encoding($ret, 'UTF-8', true) != 'UTF-8') { - $ret = date('Y-m-d H:i:s', (int) $timestamp); - } - - return $ret; - } // 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(array $tab, array $url_params = []) - { - $template = new Template(); - // default values - $defaults = [ - 'text' => '', - 'class' => '', - 'active' => null, - 'link' => '', - 'sep' => '?', - 'attr' => '', - 'args' => '', - 'warning' => '', - 'fragment' => '', - 'id' => '', - ]; - - $tab = array_merge($defaults, $tab); - - // determine additional style-class - if (empty($tab['class'])) { - if (! empty($tab['active']) - || Core::isValid($GLOBALS['active_page'], 'identical', $tab['link']) - ) { - $tab['class'] = 'active'; - } elseif ($tab['active'] === null && empty($GLOBALS['active_page']) - && (basename($GLOBALS['PMA_PHP_SELF']) == $tab['link']) - ) { - $tab['class'] = 'active'; - } - } - - // build the link - if (! empty($tab['link'])) { - // If there are any tab specific URL parameters, merge those with - // the general URL parameters - if (! empty($tab['args']) && is_array($tab['args'])) { - $url_params = array_merge($url_params, $tab['args']); - } - $tab['link'] = htmlentities($tab['link']) . Url::getCommon($url_params); - } - - if (! empty($tab['fragment'])) { - $tab['link'] .= $tab['fragment']; - } - - // display icon - if (isset($tab['icon'])) { - // avoid generating an alt tag, because it only illustrates - // the text that follows and if browser does not display - // images, the text is duplicated - $tab['text'] = self::getIcon( - $tab['icon'], - $tab['text'], - false, - true, - 'TabsMode' - ); - } elseif (empty($tab['text'])) { - // check to not display an empty link-text - $tab['text'] = '?'; - trigger_error( - 'empty linktext in function ' . __FUNCTION__ . '()', - E_USER_NOTICE - ); - } - - //Set the id for the tab, if set in the params - $tabId = (empty($tab['id']) ? null : $tab['id']); - - $item = []; - if (! empty($tab['link'])) { - $item = [ - 'content' => $tab['text'], - 'url' => [ - 'href' => empty($tab['link']) ? null : $tab['link'], - 'id' => $tabId, - 'class' => 'tab' . htmlentities($tab['class']), - ], - ]; - } else { - $item['content'] = '' . $tab['text'] . ''; - } - - $item['class'] = $tab['class'] == 'active' ? 'active' : ''; - - return $template->render('list/item', $item); - } - - /** - * returns html-code for a tab navigation - * - * @param array $tabs one element per tab - * @param array $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( - array $tabs, - array $url_params, - $menu_id, - $resizable = false - ) { - $class = ''; - if ($resizable) { - $class = ' class="resizable-menu"'; - } - - $tab_navigation = '' . "\n"; - - return $tab_navigation; - } - - /** - * Displays a link, or a link with code to trigger POST request. - * - * POST is used in following cases: - * - * - URL is too long - * - URL components are over Suhosin limits - * - There is SQL query in the parameters - * - * @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 string $target target - * - * @return string the results to be echoed or saved in an array - */ - public static function linkOrButton( - $url, - $message, - $tag_params = [], - $target = '' - ) { - $url_length = strlen($url); - - if (! is_array($tag_params)) { - $tmp = $tag_params; - $tag_params = []; - if (! empty($tmp)) { - $tag_params['onclick'] = 'return Functions.confirmLink(this, \'' - . Sanitize::escapeJsString($tmp) . '\')'; - } - unset($tmp); - } - if (! empty($target)) { - $tag_params['target'] = $target; - if ($target === '_blank' && strncmp($url, 'url.php?', 8) == 0) { - $tag_params['rel'] = 'noopener noreferrer'; - } - } - - // Suhosin: Check that each query parameter is not above maximum - $in_suhosin_limits = true; - if ($url_length <= $GLOBALS['cfg']['LinkLengthLimit']) { - $suhosin_get_MaxValueLength = ini_get('suhosin.get.max_value_length'); - if ($suhosin_get_MaxValueLength) { - $query_parts = self::splitURLQuery($url); - foreach ($query_parts as $query_pair) { - if (strpos($query_pair, '=') === false) { - continue; - } - - list(, $eachval) = explode('=', $query_pair); - if (strlen($eachval) > $suhosin_get_MaxValueLength - ) { - $in_suhosin_limits = false; - break; - } - } - } - } - - $tag_params_strings = []; - if (($url_length > $GLOBALS['cfg']['LinkLengthLimit']) - || ! $in_suhosin_limits - // Has as sql_query without a signature - || ( strpos($url, 'sql_query=') !== false && strpos($url, 'sql_signature=') === false) - || strpos($url, 'view[as]=') !== false - ) { - $parts = explode('?', $url, 2); - /* - * The data-post indicates that client should do POST - * this is handled in js/ajax.js - */ - $tag_params_strings[] = 'data-post="' . (isset($parts[1]) ? $parts[1] : '') . '"'; - $url = $parts[0]; - if (array_key_exists('class', $tag_params) - && strpos($tag_params['class'], 'create_view') !== false - ) { - $url .= '?' . explode('&', $parts[1], 2)[0]; - } - } - - foreach ($tag_params as $par_name => $par_value) { - $tag_params_strings[] = $par_name . '="' . htmlspecialchars($par_value) . '"'; - } - - // no whitespace within an else Safari will make it part of the link - return '' - . $message . ''; - } // 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 = Url::getArgSeparator(); - // on most places separator is still hard coded ... - if ($separator !== '&') { - // ... so always replace & with $separator - $url = str_replace([htmlentities('&'), '&'], [$separator, $separator], $url); - } - - $url = str_replace(htmlentities($separator), $separator, $url); - // end decode - - $url_parts = parse_url($url); - - if (! empty($url_parts['query'])) { - return explode($separator, $url_parts['query']); - } - - return []; - } - - /** - * 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 - ); - } - - /** - * Function added to avoid path disclosures. - * Called by each script that needs parameters, it displays - * an error message and, by default, stops the execution. - * - * @param string[] $params The names of the parameters needed by the calling - * script - * @param boolean $request Check parameters in request - * - * @return void - * - * @access public - */ - public static function checkParameters($params, $request = false) - { - $reported_script_name = basename($GLOBALS['PMA_PHP_SELF']); - $found_error = false; - $error_message = ''; - if ($request) { - $array = $_REQUEST; - } else { - $array = $GLOBALS; - } - - foreach ($params as $param) { - if (! isset($array[$param])) { - $error_message .= $reported_script_name - . ': ' . __('Missing parameter:') . ' ' - . $param - . self::showDocu('faq', 'faqmissingparameters', true) - . '[br]'; - $found_error = true; - } - } - if ($found_error) { - Core::fatalError($error_message); - } - } // end function - - /** - * Function to generate unique condition for specified row. - * - * @param resource $handle current query result - * @param integer $fields_cnt number of fields - * @param stdClass[] $fields_meta meta information about fields - * @param array $row current row - * @param boolean $force_unique generate condition only on pk - * or unique - * @param string|boolean $restrict_to_table restrict the unique condition - * to this table or false if - * none - * @param array|null $analyzed_sql_results the analyzed query - * - * @access public - * - * @return array the calculated condition and whether condition is unique - */ - public static function getUniqueCondition( - $handle, - $fields_cnt, - array $fields_meta, - array $row, - $force_unique = false, - $restrict_to_table = false, - $analyzed_sql_results = null - ) { - $primary_key = ''; - $unique_key = ''; - $nonprimary_condition = ''; - $preferred_condition = ''; - $primary_key_array = []; - $unique_key_array = []; - $nonprimary_condition_array = []; - $condition_array = []; - - for ($i = 0; $i < $fields_cnt; ++$i) { - $con_val = ''; - $field_flags = $GLOBALS['dbi']->fieldFlags($handle, $i); - $meta = $fields_meta[$i]; - - // do not use a column alias in a condition - if (! isset($meta->orgname) || strlen($meta->orgname) === 0) { - $meta->orgname = $meta->name; - - if (! empty($analyzed_sql_results['statement']->expr)) { - foreach ($analyzed_sql_results['statement']->expr as $expr) { - if (empty($expr->alias) || empty($expr->column)) { - continue; - } - if (strcasecmp($meta->name, $expr->alias) == 0) { - $meta->orgname = $expr->column; - break; - } - } - } - } - - // 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) - && ! $GLOBALS['dbi']->getTable($GLOBALS['db'], $meta->table)->isView() - ) { - $meta->table = $meta->orgtable; - } - - // If this field is not from the table which the unique clause needs - // to be restricted to. - if ($restrict_to_table && $restrict_to_table != $meta->table) { - continue; - } - - // 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]) || $row[$i] === null) { - $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')) - && false !== stripos($field_flags, 'BINARY') - && ! empty($row[$i]) - ) { - // hexify only if this is a true not empty BLOB or a BINARY - - // do not waste memory building a too big condition - if (mb_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)'; - } elseif ($fields_cnt == 1) { - // when this blob is the only field present - // try settling with length comparison - $condition = ' CHAR_LENGTH(' . $con_key . ') '; - $con_val = ' = ' . mb_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 (mb_strlen($row[$i]) < 5000) { - $condition .= '=0x' . bin2hex($row[$i]) . ' AND'; - } else { - $condition = ''; - } - } elseif ($meta->type == 'bit') { - $con_val = "= b'" - . self::printableBitValue((int) $row[$i], (int) $meta->length) . "'"; - } else { - $con_val = '= \'' - . $GLOBALS['dbi']->escapeString($row[$i]) . '\''; - } - } - - 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 [ - $where_clause, - $clause_is_unique, - $condition_array, - ]; - } // end function - - /** - * Generate the charset query part - * - * @param string $collation Collation - * @param boolean $override (optional) force 'CHARACTER SET' keyword - * - * @return string - */ - public static function getCharsetQueryPart($collation, $override = false) - { - list($charset) = explode('_', $collation); - $keyword = ' CHARSET='; - - if ($override) { - $keyword = ' CHARACTER SET '; - } - return $keyword . $charset - . ($charset == $collation ? '' : ' COLLATE ' . $collation); - } - - /** - * 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 $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, - $text, - $image, - $value = '' - ) { - if ($value == '') { - $value = $text; - } - if ($GLOBALS['cfg']['ActionLinksMode'] == 'text') { - return ' ' . "\n"; - } - return '' . "\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 - - - /** - * Calculate page number through position - * @param int $pos position of first item - * @param int $max_count number of items per page - * @return int $page_num - * @access public - */ - public static function getPageFromPosition($pos, $max_count) - { - return (int) floor($pos / $max_count) + 1; - } - - /** - * 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 string[] $classes additional classes for the container - * - * @return string the html content - * - * @access public - * - * @todo use $pos from $_url_params - */ - public static function getListNavigator( - $count, - $pos, - array $_url_params, - $script, - $frame, - $max_count, - $name = 'pos', - $classes = [] - ) { - - // This is often coming from $cfg['MaxTableList'] and - // people sometimes set it to empty string - $max_count = intval($max_count); - if ($max_count <= 0) { - $max_count = 250; - } - - $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) { - $caption1 = ''; - $caption2 = ''; - if (self::showIcons('TableNavigationLinksMode')) { - $caption1 .= '<< '; - $caption2 .= '< '; - } - if (self::showText('TableNavigationLinksMode')) { - $caption1 .= _pgettext('First page', 'Begin'); - $caption2 .= _pgettext('Previous page', 'Previous'); - } - $title1 = ' title="' . _pgettext('First page', 'Begin') . '"'; - $title2 = ' title="' . _pgettext('Previous page', 'Previous') . '"'; - - $_url_params[$name] = 0; - $list_navigator_html .= '' . $caption1 - . ''; - - $_url_params[$name] = $pos - $max_count; - $list_navigator_html .= ' ' - . $caption2 . ''; - } - - $list_navigator_html .= '
    '; - - $list_navigator_html .= Url::getHiddenInputs($_url_params); - $list_navigator_html .= self::pageselector( - $name, - $max_count, - self::getPageFromPosition($pos, $max_count), - ceil($count / $max_count) - ); - $list_navigator_html .= '
    '; - - if ($pos + $max_count < $count) { - $caption3 = ''; - $caption4 = ''; - if (self::showText('TableNavigationLinksMode')) { - $caption3 .= _pgettext('Next page', 'Next'); - $caption4 .= _pgettext('Last page', 'End'); - } - if (self::showIcons('TableNavigationLinksMode')) { - $caption3 .= ' >'; - $caption4 .= ' >>'; - } - $title3 = ' title="' . _pgettext('Next page', 'Next') . '"'; - $title4 = ' title="' . _pgettext('Last page', 'End') . '"'; - - $_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 (mb_substr($dir, -1) != '/') { - $dir .= '/'; - } - - return str_replace('%u', Core::securePath($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 = '') - { - if (strlen((string) $database) === 0) { - if (strlen((string) $GLOBALS['db']) === 0) { - return ''; - } - $database = $GLOBALS['db']; - } else { - $database = self::unescapeMysqlWildcards($database); - } - - return '' . htmlspecialchars($database) . ''; - } - - /** - * Prepare a lightbulb hint explaining a known external bug - * that affects a functionality - * - * @param string $functionality localized message explaining the func. - * @param string $component 'mysql' (eventually, 'php') - * @param string $minimum_version of this component - * @param string $bugref bug reference for this component - * - * @return String - */ - public static function getExternalBug( - $functionality, - $component, - $minimum_version, - $bugref - ) { - $ext_but_html = ''; - if (($component == 'mysql') && ($GLOBALS['dbi']->getVersion() < $minimum_version)) { - $ext_but_html .= self::showHint( - sprintf( - __('The %s functionality is affected by a known bug, see %s'), - $functionality, - Core::linkURL('https://bugs.mysql.com/') . $bugref - ) - ); - } - return $ext_but_html; - } - - /** - * 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 - * @param string $id_prefix prefix for the id attribute, name will be - * used if this is not supplied - * - * @return string set of html radio fiels - */ - public static function getRadioFields( - $html_field_name, - array $choices, - $checked_choice = '', - $line_break = true, - $escape_label = true, - $class = '', - $id_prefix = '' - ) { - $template = new Template(); - $radio_html = ''; - - foreach ($choices as $choice_value => $choice_label) { - if (! $id_prefix) { - $id_prefix = $html_field_name; - } - $html_field_id = $id_prefix . '_' . $choice_value; - - if ($choice_value == $checked_choice) { - $checked = 1; - } else { - $checked = 0; - } - $radio_html .= $template->render('radio_fields', [ - 'class' => $class, - 'html_field_name' => $html_field_name, - 'html_field_id' => $html_field_id, - 'choice_value' => $choice_value, - 'is_line_break' => $line_break, - 'choice_label' => $choice_label, - 'escape_label' => $escape_label, - 'checked' => $checked, - ]); - } - - return $radio_html; - } - - /** - * Generates and returns an HTML dropdown - * - * @param string $select_name name for the select element - * @param array $choices choices values - * @param string $active_choice the choice to select by default - * @param string $id id of the select element; can be different in - * case the dropdown is present more than once - * on the page - * @param string $class class for the select element - * @param string $placeholder Placeholder for dropdown if nothing else - * is selected - * - * @return string html content - * - * @todo support titles - */ - public static function getDropdown( - $select_name, - array $choices, - $active_choice, - $id, - $class = '', - $placeholder = null - ) { - $template = new Template(); - $resultOptions = []; - $selected = false; - - foreach ($choices as $one_choice_value => $one_choice_label) { - $resultOptions[$one_choice_value]['value'] = $one_choice_value; - $resultOptions[$one_choice_value]['selected'] = false; - - if ($one_choice_value == $active_choice) { - $resultOptions[$one_choice_value]['selected'] = true; - $selected = true; - } - $resultOptions[$one_choice_value]['label'] = $one_choice_label; - } - return $template->render('dropdown', [ - 'select_name' => $select_name, - 'id' => $id, - 'class' => $class, - 'placeholder' => $placeholder, - 'selected' => $selected, - 'result_options' => $resultOptions, - ]); - } - - /** - * 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 - * @param string|null $overrideDefault override InitialSlidersState config - * - * @return string html div element - * - */ - public static function getDivForSliderEffect($id = '', $message = '', $overrideDefault = null) - { - $template = new Template(); - return $template->render('div_for_slider_effect', [ - 'id' => $id, - 'initial_sliders_state' => ($overrideDefault != null) ? $overrideDefault : $GLOBALS['cfg']['InitialSlidersState'], - 'message' => $message, - ]); - } - - /** - * Creates an AJAX sliding toggle button - * (or and equivalent form when AJAX is disabled) - * - * @param string $action The URL for the request to be executed - * @param string $select_name The name for the dropdown box - * @param array $options An array of options (see PhpMyAdmin\Rte\Footer) - * @param string $callback A JS snippet to execute when the request is - * successfully processed - * - * @return string HTML code for the toggle button - */ - public static function toggleButton($action, $select_name, array $options, $callback) - { - $template = new Template(); - // Do the logic first - $link = "$action&" . urlencode($select_name) . "="; - $link_on = $link . urlencode($options[1]['value']); - $link_off = $link . urlencode($options[0]['value']); - - if ($options[1]['selected'] == true) { - $state = 'on'; - } elseif ($options[0]['selected'] == true) { - $state = 'off'; - } else { - $state = 'on'; - } - - return $template->render('toggle_button', [ - 'pma_theme_image' => $GLOBALS['pmaThemeImage'], - 'text_dir' => $GLOBALS['text_dir'], - 'link_on' => $link_on, - 'link_off' => $link_off, - 'toggle_on' => $options[1]['label'], - 'toggle_off' => $options[0]['label'], - 'callback' => $callback, - 'state' => $state, - ]); - } - - /** - * Clears cache content which needs to be refreshed on user change. - * - * @return void - */ - public static function clearUserCache() - { - self::cacheUnset('is_superuser'); - self::cacheUnset('is_createuser'); - self::cacheUnset('is_grantuser'); - } - - /** - * Calculates session cache key - * - * @return string - */ - public static function cacheKey() - { - if (isset($GLOBALS['cfg']['Server']['user'])) { - return 'server_' . $GLOBALS['server'] . '_' . $GLOBALS['cfg']['Server']['user']; - } - - return 'server_' . $GLOBALS['server']; - } - - /** - * Verifies if something is cached in the session - * - * @param string $var variable name - * - * @return boolean - */ - public static function cacheExists($var) - { - return isset($_SESSION['cache'][self::cacheKey()][$var]); - } - - /** - * Gets cached information from the session - * - * @param string $var variable name - * @param Closure $callback callback to fetch the value - * - * @return mixed - */ - public static function cacheGet($var, $callback = null) - { - if (self::cacheExists($var)) { - return $_SESSION['cache'][self::cacheKey()][$var]; - } - - if ($callback) { - $val = $callback(); - self::cacheSet($var, $val); - return $val; - } - return null; - } - - /** - * Caches information in the session - * - * @param string $var variable name - * @param mixed $val value - * - * @return void - */ - public static function cacheSet($var, $val = null) - { - $_SESSION['cache'][self::cacheKey()][$var] = $val; - } - - /** - * Removes cached information from the session - * - * @param string $var variable name - * - * @return void - */ - public static function cacheUnset($var) - { - unset($_SESSION['cache'][self::cacheKey()][$var]); - } - - /** - * Converts a bit value to printable format; - * in MySQL a BIT field can be from 1 to 64 bits so we need this - * function because in PHP, decbin() supports only 32 bits - * on 32-bit servers - * - * @param int $value coming from a BIT field - * @param int $length length - * - * @return string the printable value - */ - public static function printableBitValue(int $value, int $length): string - { - // if running on a 64-bit server or the length is safe for decbin() - if (PHP_INT_SIZE == 8 || $length < 33) { - $printable = decbin($value); - } else { - // FIXME: does not work for the leftmost bit of a 64-bit value - $i = 0; - $printable = ''; - while ($value >= pow(2, $i)) { - ++$i; - } - if ($i != 0) { - --$i; - } - - while ($i >= 0) { - if ($value - pow(2, $i) < 0) { - $printable = '0' . $printable; - } else { - $printable = '1' . $printable; - $value -= pow(2, $i); - } - --$i; - } - $printable = strrev($printable); - } - $printable = str_pad($printable, $length, '0', STR_PAD_LEFT); - return $printable; - } - - /** - * Converts a BIT type default value - * for example, b'010' becomes 010 - * - * @param string $bit_default_value value - * - * @return string the converted value - */ - public static function convertBitDefaultValue($bit_default_value) - { - return rtrim(ltrim(htmlspecialchars_decode($bit_default_value, ENT_QUOTES), "b'"), "'"); - } - - /** - * Extracts the various parts from a column spec - * - * @param string $columnspec Column specification - * - * @return array associative array containing type, spec_in_brackets - * and possibly enum_set_values (another array) - */ - public static function extractColumnSpec($columnspec) - { - $first_bracket_pos = mb_strpos($columnspec, '('); - if ($first_bracket_pos) { - $spec_in_brackets = rtrim( - mb_substr( - $columnspec, - $first_bracket_pos + 1, - mb_strrpos($columnspec, ')') - $first_bracket_pos - 1 - ) - ); - // convert to lowercase just to be sure - $type = mb_strtolower( - rtrim(mb_substr($columnspec, 0, $first_bracket_pos)) - ); - } else { - // Split trailing attributes such as unsigned, - // binary, zerofill and get data type name - $type_parts = explode(' ', $columnspec); - $type = mb_strtolower($type_parts[0]); - $spec_in_brackets = ''; - } - - if ('enum' == $type || 'set' == $type) { - // Define our working vars - $enum_set_values = self::parseEnumSetValues($columnspec, false); - $printtype = $type - . '(' . str_replace("','", "', '", $spec_in_brackets) . ')'; - $binary = false; - $unsigned = false; - $zerofill = false; - } else { - $enum_set_values = []; - - /* Create printable type name */ - $printtype = mb_strtolower($columnspec); - - // Strip the "BINARY" attribute, except if we find "BINARY(" because - // this would be a BINARY or VARBINARY column type; - // by the way, a BLOB should not show the BINARY attribute - // because this is not accepted in MySQL syntax. - if (false !== strpos($printtype, "binary") - && ! preg_match('@binary[\(]@', $printtype) - ) { - $printtype = str_replace("binary", '', $printtype); - $binary = true; - } else { - $binary = false; - } - - $printtype = preg_replace( - '@zerofill@', - '', - $printtype, - -1, - $zerofill_cnt - ); - $zerofill = ($zerofill_cnt > 0); - $printtype = preg_replace( - '@unsigned@', - '', - $printtype, - -1, - $unsigned_cnt - ); - $unsigned = ($unsigned_cnt > 0); - $printtype = trim($printtype); - } - - $attribute = ' '; - if ($binary) { - $attribute = 'BINARY'; - } - if ($unsigned) { - $attribute = 'UNSIGNED'; - } - if ($zerofill) { - $attribute = 'UNSIGNED ZEROFILL'; - } - - $can_contain_collation = false; - if (! $binary - && preg_match( - "@^(char|varchar|text|tinytext|mediumtext|longtext|set|enum)@", - $type - ) - ) { - $can_contain_collation = true; - } - - // for the case ENUM('–','“') - $displayed_type = htmlspecialchars($printtype); - if (mb_strlen($printtype) > $GLOBALS['cfg']['LimitChars']) { - $displayed_type = ''; - $displayed_type .= htmlspecialchars( - mb_substr( - $printtype, - 0, - (int) $GLOBALS['cfg']['LimitChars'] - ) . '...' - ); - $displayed_type .= ''; - } - - return [ - 'type' => $type, - 'spec_in_brackets' => $spec_in_brackets, - 'enum_set_values' => $enum_set_values, - 'print_type' => $printtype, - 'binary' => $binary, - 'unsigned' => $unsigned, - 'zerofill' => $zerofill, - 'attribute' => $attribute, - 'can_contain_collation' => $can_contain_collation, - 'displayed_type' => $displayed_type, - ]; - } - - /** - * Verifies if this table's engine supports foreign keys - * - * @param string $engine engine - * - * @return boolean - */ - public static function isForeignKeySupported($engine) - { - $engine = strtoupper((string) $engine); - if (($engine == 'INNODB') || ($engine == 'PBXT')) { - return true; - } elseif ($engine == 'NDBCLUSTER' || $engine == 'NDB') { - $ndbver = strtolower( - $GLOBALS['dbi']->fetchValue("SELECT @@ndb_version_string") - ); - if (substr($ndbver, 0, 4) == 'ndb-') { - $ndbver = substr($ndbver, 4); - } - return version_compare($ndbver, '7.3', '>='); - } - - return false; - } - - /** - * Is Foreign key check enabled? - * - * @return bool - */ - public static function isForeignKeyCheck() - { - if ($GLOBALS['cfg']['DefaultForeignKeyChecks'] === 'enable') { - return true; - } elseif ($GLOBALS['cfg']['DefaultForeignKeyChecks'] === 'disable') { - return false; - } - return ($GLOBALS['dbi']->getVariable('FOREIGN_KEY_CHECKS') == 'ON'); - } - - /** - * Get HTML for Foreign key check checkbox - * - * @return string HTML for checkbox - */ - public static function getFKCheckbox() - { - $template = new Template(); - return $template->render('fk_checkbox', [ - 'checked' => self::isForeignKeyCheck(), - ]); - } - - /** - * Handle foreign key check request - * - * @return bool Default foreign key checks value - */ - public static function handleDisableFKCheckInit() - { - $default_fk_check_value - = $GLOBALS['dbi']->getVariable('FOREIGN_KEY_CHECKS') == 'ON'; - if (isset($_REQUEST['fk_checks'])) { - if (empty($_REQUEST['fk_checks'])) { - // Disable foreign key checks - $GLOBALS['dbi']->setVariable('FOREIGN_KEY_CHECKS', 'OFF'); - } else { - // Enable foreign key checks - $GLOBALS['dbi']->setVariable('FOREIGN_KEY_CHECKS', 'ON'); - } - } // else do nothing, go with default - return $default_fk_check_value; - } - - /** - * Cleanup changes done for foreign key check - * - * @param bool $default_fk_check_value original value for 'FOREIGN_KEY_CHECKS' - * - * @return void - */ - public static function handleDisableFKCheckCleanup($default_fk_check_value) - { - $GLOBALS['dbi']->setVariable( - 'FOREIGN_KEY_CHECKS', - $default_fk_check_value ? 'ON' : 'OFF' - ); - } - - /** - * Converts GIS data to Well Known Text format - * - * @param string $data GIS data - * @param bool $includeSRID Add SRID to the WKT - * - * @return string GIS data in Well Know Text format - */ - public static function asWKT($data, $includeSRID = false) - { - // Convert to WKT format - $hex = bin2hex($data); - $spatialAsText = 'ASTEXT'; - $spatialSrid = 'SRID'; - if ($GLOBALS['dbi']->getVersion() >= 50600) { - $spatialAsText = 'ST_ASTEXT'; - $spatialSrid = 'ST_SRID'; - } - $wktsql = "SELECT $spatialAsText(x'" . $hex . "')"; - if ($includeSRID) { - $wktsql .= ", $spatialSrid(x'" . $hex . "')"; - } - - $wktresult = $GLOBALS['dbi']->tryQuery( - $wktsql - ); - $wktarr = $GLOBALS['dbi']->fetchRow($wktresult, 0); - $wktval = $wktarr[0] ?? null; - - if ($includeSRID) { - $srid = $wktarr[1] ?? null; - $wktval = "'" . $wktval . "'," . $srid; - } - @$GLOBALS['dbi']->freeResult($wktresult); - - return $wktval; - } - - /** - * If the string starts with a \r\n pair (0x0d0a) add an extra \n - * - * @param string $string string - * - * @return string with the chars replaced - */ - public static function duplicateFirstNewline($string) - { - $first_occurence = mb_strpos($string, "\r\n"); - if ($first_occurence === 0) { - $string = "\n" . $string; - } - return $string; - } - - /** - * Get the action word corresponding to a script name - * in order to display it as a title in navigation panel - * - * @param string $target a valid value for $cfg['NavigationTreeDefaultTabTable'], - * $cfg['NavigationTreeDefaultTabTable2'], - * $cfg['DefaultTabTable'] or $cfg['DefaultTabDatabase'] - * - * @return string Title for the $cfg value - */ - public static function getTitleForTarget($target) - { - $mapping = [ - 'structure' => __('Structure'), - 'sql' => __('SQL'), - 'search' => __('Search'), - 'insert' => __('Insert'), - 'browse' => __('Browse'), - 'operations' => __('Operations'), - - // For backward compatiblity - - // Values for $cfg['DefaultTabTable'] - 'tbl_structure.php' => __('Structure'), - 'tbl_sql.php' => __('SQL'), - 'tbl_select.php' => __('Search'), - 'tbl_change.php' => __('Insert'), - 'sql.php' => __('Browse'), - // Values for $cfg['DefaultTabDatabase'] - 'db_structure.php' => __('Structure'), - 'db_sql.php' => __('SQL'), - 'db_search.php' => __('Search'), - 'db_operations.php' => __('Operations'), - ]; - return isset($mapping[$target]) ? $mapping[$target] : false; - } - - /** - * Get the script name corresponding to a plain English config word - * in order to append in links on navigation and main panel - * - * @param string $target a valid value for - * $cfg['NavigationTreeDefaultTabTable'], - * $cfg['NavigationTreeDefaultTabTable2'], - * $cfg['DefaultTabTable'], $cfg['DefaultTabDatabase'] or - * $cfg['DefaultTabServer'] - * @param string $location one out of 'server', 'table', 'database' - * - * @return string script name corresponding to the config word - */ - public static function getScriptNameForOption($target, $location) - { - if ($location == 'server') { - // Values for $cfg['DefaultTabServer'] - switch ($target) { - case 'welcome': - return 'index.php'; - case 'databases': - return 'server_databases.php'; - case 'status': - return 'server_status.php'; - case 'variables': - return 'server_variables.php'; - case 'privileges': - return 'server_privileges.php'; - } - } elseif ($location == 'database') { - // Values for $cfg['DefaultTabDatabase'] - switch ($target) { - case 'structure': - return 'db_structure.php'; - case 'sql': - return 'db_sql.php'; - case 'search': - return 'db_search.php'; - case 'operations': - return 'db_operations.php'; - } - } elseif ($location == 'table') { - // Values for $cfg['DefaultTabTable'], - // $cfg['NavigationTreeDefaultTabTable'] and - // $cfg['NavigationTreeDefaultTabTable2'] - switch ($target) { - case 'structure': - return 'tbl_structure.php'; - case 'sql': - return 'tbl_sql.php'; - case 'search': - return 'tbl_select.php'; - case 'insert': - return 'tbl_change.php'; - case 'browse': - return 'sql.php'; - } - } - - return $target; - } - - /** - * Formats user string, expanding @VARIABLES@, accepting strftime format - * string. - * - * @param string $string Text where to do expansion. - * @param array|string $escape Function to call for escaping variable values. - * Can also be an array of: - * - the escape method name - * - the class that contains the method - * - location of the class (for inclusion) - * @param array $updates Array with overrides for default parameters - * (obtained from GLOBALS). - * - * @return string - */ - public static function expandUserString( - $string, - $escape = null, - array $updates = [] - ) { - /* Content */ - $vars = []; - $vars['http_host'] = Core::getenv('HTTP_HOST'); - $vars['server_name'] = $GLOBALS['cfg']['Server']['host']; - $vars['server_verbose'] = $GLOBALS['cfg']['Server']['verbose']; - - if (empty($GLOBALS['cfg']['Server']['verbose'])) { - $vars['server_verbose_or_name'] = $GLOBALS['cfg']['Server']['host']; - } else { - $vars['server_verbose_or_name'] = $GLOBALS['cfg']['Server']['verbose']; - } - - $vars['database'] = $GLOBALS['db']; - $vars['table'] = $GLOBALS['table']; - $vars['phpmyadmin_version'] = 'phpMyAdmin ' . PMA_VERSION; - - /* Update forced variables */ - foreach ($updates as $key => $val) { - $vars[$key] = $val; - } - - /* Replacement mapping */ - /* - * The __VAR__ ones are for backward compatibility, because user - * might still have it in cookies. - */ - $replace = [ - '@HTTP_HOST@' => $vars['http_host'], - '@SERVER@' => $vars['server_name'], - '__SERVER__' => $vars['server_name'], - '@VERBOSE@' => $vars['server_verbose'], - '@VSERVER@' => $vars['server_verbose_or_name'], - '@DATABASE@' => $vars['database'], - '__DB__' => $vars['database'], - '@TABLE@' => $vars['table'], - '__TABLE__' => $vars['table'], - '@PHPMYADMIN@' => $vars['phpmyadmin_version'], - ]; - - /* Optional escaping */ - if ($escape !== null) { - if (is_array($escape)) { - $escape_class = new $escape[1]; - $escape_method = $escape[0]; - } - foreach ($replace as $key => $val) { - if (is_array($escape)) { - $replace[$key] = $escape_class->$escape_method($val); - } else { - $replace[$key] = ($escape == 'backquote') - ? self::$escape($val) - : $escape($val); - } - } - } - - /* Backward compatibility in 3.5.x */ - if (mb_strpos($string, '@FIELDS@') !== false) { - $string = strtr($string, ['@FIELDS@' => '@COLUMNS@']); - } - - /* Fetch columns list if required */ - if (mb_strpos($string, '@COLUMNS@') !== false) { - $columns_list = $GLOBALS['dbi']->getColumns( - $GLOBALS['db'], - $GLOBALS['table'] - ); - - // sometimes the table no longer exists at this point - if ($columns_list !== null) { - $column_names = []; - foreach ($columns_list as $column) { - if ($escape !== null) { - $column_names[] = self::$escape($column['Field']); - } else { - $column_names[] = $column['Field']; - } - } - $replace['@COLUMNS@'] = implode(',', $column_names); - } else { - $replace['@COLUMNS@'] = '*'; - } - } - - /* Do the replacement */ - return strtr((string) strftime($string), $replace); - } - - /** - * Prepare the form used to browse anywhere on the local server for a file to - * import - * - * @param string $max_upload_size maximum upload size - * - * @return String - */ - public static function getBrowseUploadFileBlock($max_upload_size) - { - $block_html = ''; - - if ($GLOBALS['is_upload'] && ! empty($GLOBALS['cfg']['UploadDir'])) { - $block_html .= '