Translated using Weblate (Slovenian)
[phpmyadmin.git] / libraries / common.inc.php
blob6af5caa56f0189a47aa5b40d2ea126e8ce2872a7
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
30 declare(strict_types=1);
32 use PhpMyAdmin\Config;
33 use PhpMyAdmin\Core;
34 use PhpMyAdmin\DatabaseInterface;
35 use PhpMyAdmin\Di\Migration;
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\Sanitize;
45 use PhpMyAdmin\Session;
46 use PhpMyAdmin\SqlParser\Lexer;
47 use PhpMyAdmin\ThemeManager;
48 use PhpMyAdmin\Tracker;
49 use PhpMyAdmin\Util;
50 use Symfony\Component\Config\FileLocator;
51 use Symfony\Component\DependencyInjection\ContainerBuilder;
52 use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
54 global $containerBuilder, $error_handler, $PMA_Config, $server, $dbi, $lang, $cfg, $isConfigLoading, $auth_plugin, $route;
56 /**
57 * block attempts to directly run this script
59 if (getcwd() == __DIR__) {
60 die('Attack stopped');
63 /**
64 * Minimum PHP version; can't call Core::fatalError() which uses a
65 * PHP 5 function, so cannot easily localize this message.
67 if (PHP_VERSION_ID < 70103) {
68 die(
69 '<p>PHP 7.1.3+ is required.</p>'
70 . '<p>Currently installed version is: ' . PHP_VERSION . '</p>'
74 // phpcs:disable PSR1.Files.SideEffects
75 /**
76 * for verification in all procedural scripts under libraries
78 define('PHPMYADMIN', true);
79 // phpcs:enable
81 /**
82 * Load vendor configuration.
84 require_once ROOT_PATH . 'libraries/vendor_config.php';
86 /**
87 * Activate autoloader
89 if (! @is_readable(AUTOLOAD_FILE)) {
90 die(
91 '<p>File <samp>' . AUTOLOAD_FILE . '</samp> missing or not readable.</p>'
92 . '<p>Most likely you did not run Composer to '
93 . '<a href="https://docs.phpmyadmin.net/en/latest/setup.html#installing-from-git">'
94 . 'install library files</a>.</p>'
97 require_once AUTOLOAD_FILE;
99 $route = Routing::getCurrentRoute();
101 if ($route === '/import-status') {
102 // phpcs:disable PSR1.Files.SideEffects
103 define('PMA_MINIMUM_COMMON', true);
104 // phpcs:enable
107 $containerBuilder = new ContainerBuilder();
108 $loader = new PhpFileLoader($containerBuilder, new FileLocator(__DIR__));
109 $loader->load('services_loader.php');
110 /** @var Migration $diMigration */
111 $diMigration = $containerBuilder->get('di_migration');
114 * Load gettext functions.
116 Loader::loadFunctions();
118 /** @var ErrorHandler $error_handler */
119 $error_handler = $containerBuilder->get('error_handler');
122 * Warning about missing PHP extensions.
124 Core::checkExtensions();
127 * Configure required PHP settings.
129 Core::configure();
131 /* start procedural code label_start_procedural */
133 Core::cleanupPathInfo();
135 /* parsing configuration file LABEL_parsing_config_file */
137 /** @var bool $isConfigLoading Indication for the error handler */
138 $isConfigLoading = false;
141 * Force reading of config file, because we removed sensitive values
142 * in the previous iteration.
144 * @var Config $PMA_Config
146 $PMA_Config = $containerBuilder->get('config');
148 register_shutdown_function([Config::class, 'fatalErrorHandler']);
151 * include session handling after the globals, to prevent overwriting
153 if (! defined('PMA_NO_SESSION')) {
154 Session::setUp($PMA_Config, $error_handler);
158 * init some variables LABEL_variables_init
162 * holds parameters to be passed to next page
164 * @global array $url_params
166 $diMigration->setGlobal('url_params', []);
169 * holds page that should be displayed
171 * @global string $goto
173 $diMigration->setGlobal('goto', '');
174 // Security fix: disallow accessing serious server files via "?goto="
175 if (isset($_REQUEST['goto']) && Core::checkPageValidity($_REQUEST['goto'])) {
176 $diMigration->setGlobal('goto', $_REQUEST['goto']);
177 $diMigration->setGlobal('url_params', ['goto' => $_REQUEST['goto']]);
178 } else {
179 $PMA_Config->removeCookie('goto');
180 unset($_REQUEST['goto'], $_GET['goto'], $_POST['goto']);
184 * returning page
186 * @global string $back
188 if (isset($_REQUEST['back']) && Core::checkPageValidity($_REQUEST['back'])) {
189 $diMigration->setGlobal('back', $_REQUEST['back']);
190 } else {
191 $PMA_Config->removeCookie('back');
192 unset($_REQUEST['back'], $_GET['back'], $_POST['back']);
196 * Check whether user supplied token is valid, if not remove any possibly
197 * dangerous stuff from request.
199 * remember that some objects in the session with session_start and __wakeup()
200 * could access this variables before we reach this point
201 * f.e. PhpMyAdmin\Config: fontsize
203 * Check for token mismatch only if the Request method is POST
204 * GET Requests would never have token and therefore checking
205 * mis-match does not make sense
207 * @todo variables should be handled by their respective owners (objects)
208 * f.e. lang, server in PhpMyAdmin\Config
211 $token_mismatch = true;
212 $token_provided = false;
214 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
215 if (Core::isValid($_POST['token'])) {
216 $token_provided = true;
217 $token_mismatch = ! @hash_equals($_SESSION[' PMA_token '], $_POST['token']);
220 if ($token_mismatch) {
221 /* Warn in case the mismatch is result of failed setting of session cookie */
222 if (isset($_POST['set_session']) && $_POST['set_session'] != session_id()) {
223 trigger_error(
225 'Failed to set session cookie. Maybe you are using '
226 . 'HTTP instead of HTTPS to access phpMyAdmin.'
228 E_USER_ERROR
232 * We don't allow any POST operation parameters if the token is mismatched
233 * or is not provided
235 $whitelist = ['ajax_request'];
236 Sanitize::removeRequestVars($whitelist);
242 * current selected database
244 * @global string $db
246 Core::setGlobalDbOrTable('db');
249 * current selected table
251 * @global string $table
253 Core::setGlobalDbOrTable('table');
256 * Store currently selected recent table.
257 * Affect $db and $table globals
259 if (isset($_REQUEST['selected_recent_table']) && Core::isValid($_REQUEST['selected_recent_table'])) {
260 $recent_table = json_decode($_REQUEST['selected_recent_table'], true);
262 $diMigration->setGlobal(
263 'db',
264 array_key_exists('db', $recent_table) && is_string($recent_table['db']) ? $recent_table['db'] : ''
266 $diMigration->setGlobal(
267 'url_params',
268 ['db' => $containerBuilder->getParameter('db')] + $containerBuilder->getParameter('url_params')
271 $diMigration->setGlobal(
272 'table',
273 array_key_exists('table', $recent_table) && is_string($recent_table['table']) ? $recent_table['table'] : ''
275 $diMigration->setGlobal(
276 'url_params',
277 ['table' => $containerBuilder->getParameter('table')] + $containerBuilder->getParameter('url_params')
282 * SQL query to be executed
284 * @global string $sql_query
286 $diMigration->setGlobal('sql_query', '');
287 if (Core::isValid($_POST['sql_query'])) {
288 $diMigration->setGlobal('sql_query', $_POST['sql_query']);
291 //$_REQUEST['set_theme'] // checked later in this file LABEL_theme_setup
292 //$_REQUEST['server']; // checked later in this file
293 //$_REQUEST['lang']; // checked by LABEL_loading_language_file
295 /* loading language file LABEL_loading_language_file */
298 * lang detection is done here
300 $language = LanguageManager::getInstance()->selectLanguage();
301 $language->activate();
304 * check for errors occurred while loading configuration
305 * this check is done here after loading language files to present errors in locale
307 $PMA_Config->checkPermissions();
308 $PMA_Config->checkErrors();
310 /* Check server configuration */
311 Core::checkConfiguration();
313 /* Check request for possible attacks */
314 Core::checkRequest();
316 /* setup servers LABEL_setup_servers */
318 $PMA_Config->checkServers();
321 * current server
323 * @global integer $server
325 $diMigration->setGlobal('server', $PMA_Config->selectServer());
326 $diMigration->setGlobal('url_params', ['server' => $containerBuilder->getParameter('server')] + $containerBuilder->getParameter('url_params'));
329 * BC - enable backward compatibility
330 * exports all configuration settings into globals ($cfg global)
332 $PMA_Config->enableBc();
334 /* setup themes LABEL_theme_setup */
336 ThemeManager::initializeTheme();
338 /** @var DatabaseInterface $dbi */
339 $dbi = null;
341 if (! defined('PMA_MINIMUM_COMMON')) {
343 * save some settings in cookies
345 * @todo should be done in PhpMyAdmin\Config
347 $PMA_Config->setCookie('pma_lang', $lang);
349 ThemeManager::getInstance()->setThemeCookie();
351 $containerBuilder->set(DatabaseInterface::class, DatabaseInterface::load());
352 $containerBuilder->setAlias('dbi', DatabaseInterface::class);
354 if (! empty($cfg['Server'])) {
355 // get LoginCookieValidity from preferences cache
356 // no generic solution for loading preferences from cache as some settings
357 // need to be kept for processing in
358 // PhpMyAdmin\Config::loadUserPreferences()
359 $cache_key = 'server_' . $server;
360 if (isset($_SESSION['cache'][$cache_key]['userprefs']['LoginCookieValidity'])
362 $value
363 = $_SESSION['cache'][$cache_key]['userprefs']['LoginCookieValidity'];
364 $PMA_Config->set('LoginCookieValidity', $value);
365 $cfg['LoginCookieValidity'] = $value;
366 unset($value);
368 unset($cache_key);
370 // Gets the authentication library that fits the $cfg['Server'] settings
371 // and run authentication
374 * the required auth type plugin
376 $auth_class = 'PhpMyAdmin\\Plugins\\Auth\\Authentication' . ucfirst(strtolower($cfg['Server']['auth_type']));
377 if (! @class_exists($auth_class)) {
378 Core::fatalError(
379 __('Invalid authentication method set in configuration:')
380 . ' ' . $cfg['Server']['auth_type']
383 if (isset($_POST['pma_password']) && strlen($_POST['pma_password']) > 256) {
384 $_POST['pma_password'] = substr($_POST['pma_password'], 0, 256);
387 /** @var AuthenticationPlugin $auth_plugin */
388 $auth_plugin = new $auth_class();
389 $auth_plugin->authenticate();
391 // Try to connect MySQL with the control user profile (will be used to
392 // get the privileges list for the current user but the true user link
393 // must be open after this one so it would be default one for all the
394 // scripts)
395 $controllink = false;
396 if ($cfg['Server']['controluser'] != '') {
397 $controllink = $dbi->connect(
398 DatabaseInterface::CONNECT_CONTROL
402 // Connects to the server (validates user's login)
403 /** @var DatabaseInterface $userlink */
404 $userlink = $dbi->connect(DatabaseInterface::CONNECT_USER);
406 if ($userlink === false) {
407 $auth_plugin->showFailure('mysql-denied');
410 if (! $controllink) {
412 * Open separate connection for control queries, this is needed
413 * to avoid problems with table locking used in main connection
414 * and phpMyAdmin issuing queries to configuration storage, which
415 * is not locked by that time.
417 $controllink = $dbi->connect(
418 DatabaseInterface::CONNECT_USER,
419 null,
420 DatabaseInterface::CONNECT_CONTROL
424 $auth_plugin->rememberCredentials();
426 $auth_plugin->checkTwoFactor();
428 /* Log success */
429 Logging::logUser($cfg['Server']['user']);
431 if ($dbi->getVersion() < $cfg['MysqlMinVersion']['internal']) {
432 Core::fatalError(
433 __('You should upgrade to %s %s or later.'),
435 'MySQL',
436 $cfg['MysqlMinVersion']['human'],
441 // Sets the default delimiter (if specified).
442 if (! empty($_REQUEST['sql_delimiter'])) {
443 Lexer::$DEFAULT_DELIMITER = $_REQUEST['sql_delimiter'];
446 // TODO: Set SQL modes too.
447 } else { // end server connecting
448 $response = Response::getInstance();
449 $response->getHeader()->disableMenuAndConsole();
450 $response->getFooter()->setMinimal();
454 * check if profiling was requested and remember it
455 * (note: when $cfg['ServerDefault'] = 0, constant is not defined)
457 if (isset($_REQUEST['profiling'])
458 && Util::profilingSupported()
460 $_SESSION['profiling'] = true;
461 } elseif (isset($_REQUEST['profiling_form'])) {
462 // the checkbox was unchecked
463 unset($_SESSION['profiling']);
467 * Inclusion of profiling scripts is needed on various
468 * pages like sql, tbl_sql, db_sql, tbl_select
470 $response = Response::getInstance();
471 if (isset($_SESSION['profiling'])) {
472 $scripts = $response->getHeader()->getScripts();
473 $scripts->addFile('chart.js');
474 $scripts->addFile('vendor/jqplot/jquery.jqplot.js');
475 $scripts->addFile('vendor/jqplot/plugins/jqplot.pieRenderer.js');
476 $scripts->addFile('vendor/jqplot/plugins/jqplot.highlighter.js');
477 $scripts->addFile('vendor/jquery/jquery.tablesorter.js');
481 * There is no point in even attempting to process
482 * an ajax request if there is a token mismatch
484 if ($response->isAjax() && $_SERVER['REQUEST_METHOD'] == 'POST' && $token_mismatch) {
485 $response->setRequestStatus(false);
486 $response->addJSON(
487 'message',
488 Message::error(__('Error: Token mismatch'))
490 exit;
493 $containerBuilder->set('response', Response::getInstance());
496 // load user preferences
497 $PMA_Config->loadUserPreferences();
499 $containerBuilder->set('theme_manager', ThemeManager::getInstance());
501 /* Tell tracker that it can actually work */
502 Tracker::enable();
504 if (! defined('PMA_MINIMUM_COMMON')
505 && ! empty($GLOBALS['server'])
506 && isset($GLOBALS['cfg']['ZeroConf'])
507 && $GLOBALS['cfg']['ZeroConf'] == true
509 $GLOBALS['dbi']->postConnectControl();