Merge branch 'origin/master' into Weblate.
[phpmyadmin.git] / libraries / common.inc.php
blob0ca46d099a88276490dc0d31dbded1e477f52987
1 <?php
2 /**
3 * Misc stuff and REQUIRED by ALL the scripts.
4 * MUST be included by every script
6 * Among other things, it contains the advanced authentication work.
8 * Order of sections for common.inc.php:
10 * the authentication libraries must be before the connection to db
12 * ... so the required order is:
14 * LABEL_variables_init
15 * - initialize some variables always needed
16 * LABEL_parsing_config_file
17 * - parsing of the configuration file
18 * LABEL_loading_language_file
19 * - loading language file
20 * LABEL_setup_servers
21 * - check and setup configured servers
22 * LABEL_theme_setup
23 * - setting up themes
25 * - load of MySQL extension (if necessary)
26 * - loading of an authentication library
27 * - db connection
28 * - authentication work
31 declare(strict_types=1);
33 use PhpMyAdmin\Config;
34 use PhpMyAdmin\Core;
35 use PhpMyAdmin\DatabaseInterface;
36 use PhpMyAdmin\ErrorHandler;
37 use PhpMyAdmin\LanguageManager;
38 use PhpMyAdmin\Logging;
39 use PhpMyAdmin\Message;
40 use PhpMyAdmin\MoTranslator\Loader;
41 use PhpMyAdmin\Plugins\AuthenticationPlugin;
42 use PhpMyAdmin\Response;
43 use PhpMyAdmin\Routing;
44 use PhpMyAdmin\Session;
45 use PhpMyAdmin\SqlParser\Lexer;
46 use PhpMyAdmin\ThemeManager;
47 use PhpMyAdmin\Tracker;
48 use PhpMyAdmin\Util;
49 use Symfony\Component\Config\FileLocator;
50 use Symfony\Component\DependencyInjection\ContainerBuilder;
51 use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
53 global $containerBuilder, $error_handler, $PMA_Config, $server, $dbi;
54 global $lang, $cfg, $isConfigLoading, $auth_plugin, $route;
55 global $url_params, $goto, $back, $db, $table, $sql_query, $token_mismatch;
57 /**
58 * block attempts to directly run this script
60 if (getcwd() == __DIR__) {
61 die('Attack stopped');
64 /**
65 * Minimum PHP version; can't call Core::fatalError() which uses a
66 * PHP 5 function, so cannot easily localize this message.
68 if (PHP_VERSION_ID < 70103) {
69 die(
70 '<p>PHP 7.1.3+ is required.</p>'
71 . '<p>Currently installed version is: ' . PHP_VERSION . '</p>'
75 // phpcs:disable PSR1.Files.SideEffects
76 /**
77 * for verification in all procedural scripts under libraries
79 define('PHPMYADMIN', true);
80 // phpcs:enable
82 /**
83 * Load vendor configuration.
85 require_once ROOT_PATH . 'libraries/vendor_config.php';
87 /**
88 * Activate autoloader
90 if (! @is_readable(AUTOLOAD_FILE)) {
91 die(
92 '<p>File <samp>' . AUTOLOAD_FILE . '</samp> missing or not readable.</p>'
93 . '<p>Most likely you did not run Composer to '
94 . '<a href="https://docs.phpmyadmin.net/en/latest/setup.html#installing-from-git">'
95 . 'install library files</a>.</p>'
98 require_once AUTOLOAD_FILE;
100 $route = Routing::getCurrentRoute();
102 if ($route === '/import-status') {
103 // phpcs:disable PSR1.Files.SideEffects
104 define('PMA_MINIMUM_COMMON', true);
105 // phpcs:enable
108 $containerBuilder = new ContainerBuilder();
109 $loader = new PhpFileLoader($containerBuilder, new FileLocator(__DIR__));
110 $loader->load('services_loader.php');
113 * Load gettext functions.
115 Loader::loadFunctions();
117 /** @var ErrorHandler $error_handler */
118 $error_handler = $containerBuilder->get('error_handler');
121 * Warning about missing PHP extensions.
123 Core::checkExtensions();
126 * Configure required PHP settings.
128 Core::configure();
130 /* start procedural code label_start_procedural */
132 Core::cleanupPathInfo();
134 /* parsing configuration file LABEL_parsing_config_file */
136 /** @var bool $isConfigLoading Indication for the error handler */
137 $isConfigLoading = false;
140 * Force reading of config file, because we removed sensitive values
141 * in the previous iteration.
143 * @var Config $PMA_Config
145 $PMA_Config = $containerBuilder->get('config');
147 register_shutdown_function([Config::class, 'fatalErrorHandler']);
150 * include session handling after the globals, to prevent overwriting
152 if (! defined('PMA_NO_SESSION')) {
153 Session::setUp($PMA_Config, $error_handler);
157 * init some variables LABEL_variables_init
161 * holds parameters to be passed to next page
163 * @global array $url_params
165 $url_params = [];
166 $containerBuilder->setParameter('url_params', $url_params);
168 Core::setGotoAndBackGlobals($containerBuilder, $PMA_Config);
170 Core::checkTokenRequestParam();
172 Core::setDatabaseAndTableFromRequest($containerBuilder);
175 * SQL query to be executed
177 * @global string $sql_query
179 $sql_query = '';
180 if (Core::isValid($_POST['sql_query'])) {
181 $sql_query = $_POST['sql_query'];
183 $containerBuilder->setParameter('sql_query', $sql_query);
185 //$_REQUEST['set_theme'] // checked later in this file LABEL_theme_setup
186 //$_REQUEST['server']; // checked later in this file
187 //$_REQUEST['lang']; // checked by LABEL_loading_language_file
189 /* loading language file LABEL_loading_language_file */
192 * lang detection is done here
194 $language = LanguageManager::getInstance()->selectLanguage();
195 $language->activate();
198 * check for errors occurred while loading configuration
199 * this check is done here after loading language files to present errors in locale
201 $PMA_Config->checkPermissions();
202 $PMA_Config->checkErrors();
204 /* Check server configuration */
205 Core::checkConfiguration();
207 /* Check request for possible attacks */
208 Core::checkRequest();
210 /* setup servers LABEL_setup_servers */
212 $PMA_Config->checkServers();
215 * current server
217 * @global integer $server
219 $server = $PMA_Config->selectServer();
220 $url_params['server'] = $server;
221 $containerBuilder->setParameter('server', $server);
222 $containerBuilder->setParameter('url_params', $url_params);
225 * BC - enable backward compatibility
226 * exports all configuration settings into globals ($cfg global)
228 $PMA_Config->enableBc();
230 /* setup themes LABEL_theme_setup */
232 ThemeManager::initializeTheme();
234 /** @var DatabaseInterface $dbi */
235 $dbi = null;
237 if (! defined('PMA_MINIMUM_COMMON')) {
239 * save some settings in cookies
241 * @todo should be done in PhpMyAdmin\Config
243 $PMA_Config->setCookie('pma_lang', $lang);
245 ThemeManager::getInstance()->setThemeCookie();
247 $dbi = DatabaseInterface::load();
248 $containerBuilder->set(DatabaseInterface::class, $dbi);
249 $containerBuilder->setAlias('dbi', DatabaseInterface::class);
251 if (! empty($cfg['Server'])) {
252 // get LoginCookieValidity from preferences cache
253 // no generic solution for loading preferences from cache as some settings
254 // need to be kept for processing in
255 // PhpMyAdmin\Config::loadUserPreferences()
256 $cache_key = 'server_' . $server;
257 if (isset($_SESSION['cache'][$cache_key]['userprefs']['LoginCookieValidity'])
259 $value
260 = $_SESSION['cache'][$cache_key]['userprefs']['LoginCookieValidity'];
261 $PMA_Config->set('LoginCookieValidity', $value);
262 $cfg['LoginCookieValidity'] = $value;
263 unset($value);
265 unset($cache_key);
267 // Gets the authentication library that fits the $cfg['Server'] settings
268 // and run authentication
271 * the required auth type plugin
273 $auth_class = 'PhpMyAdmin\\Plugins\\Auth\\Authentication' . ucfirst(strtolower($cfg['Server']['auth_type']));
274 if (! @class_exists($auth_class)) {
275 Core::fatalError(
276 __('Invalid authentication method set in configuration:')
277 . ' ' . $cfg['Server']['auth_type']
280 if (isset($_POST['pma_password']) && strlen($_POST['pma_password']) > 256) {
281 $_POST['pma_password'] = substr($_POST['pma_password'], 0, 256);
284 /** @var AuthenticationPlugin $auth_plugin */
285 $auth_plugin = new $auth_class();
286 $auth_plugin->authenticate();
288 // Try to connect MySQL with the control user profile (will be used to
289 // get the privileges list for the current user but the true user link
290 // must be open after this one so it would be default one for all the
291 // scripts)
292 $controllink = false;
293 if ($cfg['Server']['controluser'] != '') {
294 $controllink = $dbi->connect(
295 DatabaseInterface::CONNECT_CONTROL
299 // Connects to the server (validates user's login)
300 /** @var DatabaseInterface $userlink */
301 $userlink = $dbi->connect(DatabaseInterface::CONNECT_USER);
303 if ($userlink === false) {
304 $auth_plugin->showFailure('mysql-denied');
307 if (! $controllink) {
309 * Open separate connection for control queries, this is needed
310 * to avoid problems with table locking used in main connection
311 * and phpMyAdmin issuing queries to configuration storage, which
312 * is not locked by that time.
314 $controllink = $dbi->connect(
315 DatabaseInterface::CONNECT_USER,
316 null,
317 DatabaseInterface::CONNECT_CONTROL
321 $auth_plugin->rememberCredentials();
323 $auth_plugin->checkTwoFactor();
325 /* Log success */
326 Logging::logUser($cfg['Server']['user']);
328 if ($dbi->getVersion() < $cfg['MysqlMinVersion']['internal']) {
329 Core::fatalError(
330 __('You should upgrade to %s %s or later.'),
332 'MySQL',
333 $cfg['MysqlMinVersion']['human'],
338 // Sets the default delimiter (if specified).
339 if (! empty($_REQUEST['sql_delimiter'])) {
340 Lexer::$DEFAULT_DELIMITER = $_REQUEST['sql_delimiter'];
343 // TODO: Set SQL modes too.
344 } else { // end server connecting
345 $response = Response::getInstance();
346 $response->getHeader()->disableMenuAndConsole();
347 $response->getFooter()->setMinimal();
351 * check if profiling was requested and remember it
352 * (note: when $cfg['ServerDefault'] = 0, constant is not defined)
354 if (isset($_REQUEST['profiling'])
355 && Util::profilingSupported()
357 $_SESSION['profiling'] = true;
358 } elseif (isset($_REQUEST['profiling_form'])) {
359 // the checkbox was unchecked
360 unset($_SESSION['profiling']);
364 * Inclusion of profiling scripts is needed on various
365 * pages like sql, tbl_sql, db_sql, tbl_select
367 $response = Response::getInstance();
368 if (isset($_SESSION['profiling'])) {
369 $scripts = $response->getHeader()->getScripts();
370 $scripts->addFile('chart.js');
371 $scripts->addFile('vendor/jqplot/jquery.jqplot.js');
372 $scripts->addFile('vendor/jqplot/plugins/jqplot.pieRenderer.js');
373 $scripts->addFile('vendor/jqplot/plugins/jqplot.highlighter.js');
374 $scripts->addFile('vendor/jquery/jquery.tablesorter.js');
378 * There is no point in even attempting to process
379 * an ajax request if there is a token mismatch
381 if ($response->isAjax() && $_SERVER['REQUEST_METHOD'] === 'POST' && $token_mismatch) {
382 $response->setRequestStatus(false);
383 $response->addJSON(
384 'message',
385 Message::error(__('Error: Token mismatch'))
387 exit;
390 $containerBuilder->set('response', Response::getInstance());
393 // load user preferences
394 $PMA_Config->loadUserPreferences();
396 $containerBuilder->set('theme_manager', ThemeManager::getInstance());
398 /* Tell tracker that it can actually work */
399 Tracker::enable();
401 if (! defined('PMA_MINIMUM_COMMON')
402 && ! empty($server)
403 && isset($cfg['ZeroConf'])
404 && $cfg['ZeroConf'] == true
406 $dbi->postConnectControl();