Config.php 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536
  1. <?php
  2. /**
  3. * Configuration handling.
  4. */
  5. declare(strict_types=1);
  6. namespace PhpMyAdmin;
  7. use const DIRECTORY_SEPARATOR;
  8. use const E_USER_ERROR;
  9. use const PHP_OS;
  10. use const PHP_URL_PATH;
  11. use const PHP_URL_SCHEME;
  12. use const PHP_VERSION_ID;
  13. use function array_filter;
  14. use function array_flip;
  15. use function array_intersect_key;
  16. use function array_keys;
  17. use function array_merge;
  18. use function array_replace_recursive;
  19. use function array_slice;
  20. use function count;
  21. use function define;
  22. use function defined;
  23. use function error_get_last;
  24. use function error_reporting;
  25. use function explode;
  26. use function fclose;
  27. use function file_exists;
  28. use function filemtime;
  29. use function fileperms;
  30. use function fopen;
  31. use function fread;
  32. use function function_exists;
  33. use function gd_info;
  34. use function implode;
  35. use function ini_get;
  36. use function intval;
  37. use function is_dir;
  38. use function is_int;
  39. use function is_numeric;
  40. use function is_readable;
  41. use function is_string;
  42. use function is_writable;
  43. use function max;
  44. use function mb_strstr;
  45. use function mb_strtolower;
  46. use function md5;
  47. use function min;
  48. use function mkdir;
  49. use function ob_end_clean;
  50. use function ob_get_clean;
  51. use function ob_start;
  52. use function parse_url;
  53. use function preg_match;
  54. use function realpath;
  55. use function rtrim;
  56. use function setcookie;
  57. use function sprintf;
  58. use function str_replace;
  59. use function stripos;
  60. use function strlen;
  61. use function strpos;
  62. use function strtolower;
  63. use function substr;
  64. use function sys_get_temp_dir;
  65. use function time;
  66. use function trigger_error;
  67. use function trim;
  68. use function crc32;
  69. /**
  70. * Configuration class
  71. */
  72. class Config
  73. {
  74. /** @var string default config source */
  75. public $defaultSource = ROOT_PATH . 'libraries/config.default.php';
  76. /** @var array default configuration settings */
  77. public $default = [];
  78. /** @var array configuration settings, without user preferences applied */
  79. public $baseSettings = [];
  80. /** @var array configuration settings */
  81. public $settings = [];
  82. /** @var string config source */
  83. public $source = '';
  84. /** @var int source modification time */
  85. public $sourceMtime = 0;
  86. /** @var int */
  87. public $defaultSourceMtime = 0;
  88. /** @var int */
  89. public $setMtime = 0;
  90. /** @var bool */
  91. public $errorConfigFile = false;
  92. /** @var bool */
  93. public $errorConfigDefaultFile = false;
  94. /** @var array */
  95. public $defaultServer = [];
  96. /**
  97. * @var bool whether init is done or not
  98. * set this to false to force some initial checks
  99. * like checking for required functions
  100. */
  101. public $done = false;
  102. /**
  103. * @param string $source source to read config from
  104. */
  105. public function __construct(?string $source = null)
  106. {
  107. $this->settings = ['is_setup' => false];
  108. // functions need to refresh in case of config file changed goes in
  109. // PhpMyAdmin\Config::load()
  110. $this->load($source);
  111. // other settings, independent from config file, comes in
  112. $this->checkSystem();
  113. $this->baseSettings = $this->settings;
  114. }
  115. /**
  116. * sets system and application settings
  117. */
  118. public function checkSystem(): void
  119. {
  120. // All the version handling is now done in the Version class
  121. $this->set('PMA_VERSION', Version::VERSION);
  122. $this->set('PMA_MAJOR_VERSION', Version::SERIES);
  123. $this->checkWebServerOs();
  124. $this->checkWebServer();
  125. $this->checkGd2();
  126. $this->checkClient();
  127. $this->checkUpload();
  128. $this->checkUploadSize();
  129. $this->checkOutputCompression();
  130. }
  131. /**
  132. * whether to use gzip output compression or not
  133. */
  134. public function checkOutputCompression(): void
  135. {
  136. // If zlib output compression is set in the php configuration file, no
  137. // output buffering should be run
  138. if (ini_get('zlib.output_compression')) {
  139. $this->set('OBGzip', false);
  140. }
  141. // enable output-buffering (if set to 'auto')
  142. if (strtolower((string) $this->get('OBGzip')) !== 'auto') {
  143. return;
  144. }
  145. $this->set('OBGzip', true);
  146. }
  147. /**
  148. * Sets the client platform based on user agent
  149. *
  150. * @param string $user_agent the user agent
  151. */
  152. private function setClientPlatform(string $user_agent): void
  153. {
  154. if (mb_strstr($user_agent, 'Win')) {
  155. $this->set('PMA_USR_OS', 'Win');
  156. } elseif (mb_strstr($user_agent, 'Mac')) {
  157. $this->set('PMA_USR_OS', 'Mac');
  158. } elseif (mb_strstr($user_agent, 'Linux')) {
  159. $this->set('PMA_USR_OS', 'Linux');
  160. } elseif (mb_strstr($user_agent, 'Unix')) {
  161. $this->set('PMA_USR_OS', 'Unix');
  162. } elseif (mb_strstr($user_agent, 'OS/2')) {
  163. $this->set('PMA_USR_OS', 'OS/2');
  164. } else {
  165. $this->set('PMA_USR_OS', 'Other');
  166. }
  167. }
  168. /**
  169. * Determines platform (OS), browser and version of the user
  170. * Based on a phpBuilder article:
  171. *
  172. * @see http://www.phpbuilder.net/columns/tim20000821.php
  173. */
  174. public function checkClient(): void
  175. {
  176. if (Core::getenv('HTTP_USER_AGENT')) {
  177. $HTTP_USER_AGENT = Core::getenv('HTTP_USER_AGENT');
  178. } else {
  179. $HTTP_USER_AGENT = '';
  180. }
  181. // 1. Platform
  182. $this->setClientPlatform($HTTP_USER_AGENT);
  183. // 2. browser and version
  184. // (must check everything else before Mozilla)
  185. $is_mozilla = preg_match(
  186. '@Mozilla/([0-9]\.[0-9]{1,2})@',
  187. $HTTP_USER_AGENT,
  188. $mozilla_version
  189. );
  190. if (preg_match(
  191. '@Opera(/| )([0-9]\.[0-9]{1,2})@',
  192. $HTTP_USER_AGENT,
  193. $log_version
  194. )) {
  195. $this->set('PMA_USR_BROWSER_VER', $log_version[2]);
  196. $this->set('PMA_USR_BROWSER_AGENT', 'OPERA');
  197. } elseif (preg_match(
  198. '@(MS)?IE ([0-9]{1,2}\.[0-9]{1,2})@',
  199. $HTTP_USER_AGENT,
  200. $log_version
  201. )) {
  202. $this->set('PMA_USR_BROWSER_VER', $log_version[2]);
  203. $this->set('PMA_USR_BROWSER_AGENT', 'IE');
  204. } elseif (preg_match(
  205. '@Trident/(7)\.0@',
  206. $HTTP_USER_AGENT,
  207. $log_version
  208. )) {
  209. $this->set('PMA_USR_BROWSER_VER', intval($log_version[1]) + 4);
  210. $this->set('PMA_USR_BROWSER_AGENT', 'IE');
  211. } elseif (preg_match(
  212. '@OmniWeb/([0-9]{1,3})@',
  213. $HTTP_USER_AGENT,
  214. $log_version
  215. )) {
  216. $this->set('PMA_USR_BROWSER_VER', $log_version[1]);
  217. $this->set('PMA_USR_BROWSER_AGENT', 'OMNIWEB');
  218. // Konqueror 2.2.2 says Konqueror/2.2.2
  219. // Konqueror 3.0.3 says Konqueror/3
  220. } elseif (preg_match(
  221. '@(Konqueror/)(.*)(;)@',
  222. $HTTP_USER_AGENT,
  223. $log_version
  224. )) {
  225. $this->set('PMA_USR_BROWSER_VER', $log_version[2]);
  226. $this->set('PMA_USR_BROWSER_AGENT', 'KONQUEROR');
  227. // must check Chrome before Safari
  228. } elseif ($is_mozilla
  229. && preg_match('@Chrome/([0-9.]*)@', $HTTP_USER_AGENT, $log_version)
  230. ) {
  231. $this->set('PMA_USR_BROWSER_VER', $log_version[1]);
  232. $this->set('PMA_USR_BROWSER_AGENT', 'CHROME');
  233. // newer Safari
  234. } elseif ($is_mozilla
  235. && preg_match('@Version/(.*) Safari@', $HTTP_USER_AGENT, $log_version)
  236. ) {
  237. $this->set(
  238. 'PMA_USR_BROWSER_VER',
  239. $log_version[1]
  240. );
  241. $this->set('PMA_USR_BROWSER_AGENT', 'SAFARI');
  242. // older Safari
  243. } elseif ($is_mozilla
  244. && preg_match('@Safari/([0-9]*)@', $HTTP_USER_AGENT, $log_version)
  245. ) {
  246. $this->set(
  247. 'PMA_USR_BROWSER_VER',
  248. $mozilla_version[1] . '.' . $log_version[1]
  249. );
  250. $this->set('PMA_USR_BROWSER_AGENT', 'SAFARI');
  251. // Firefox
  252. } elseif (! mb_strstr($HTTP_USER_AGENT, 'compatible')
  253. && preg_match('@Firefox/([\w.]+)@', $HTTP_USER_AGENT, $log_version)
  254. ) {
  255. $this->set(
  256. 'PMA_USR_BROWSER_VER',
  257. $log_version[1]
  258. );
  259. $this->set('PMA_USR_BROWSER_AGENT', 'FIREFOX');
  260. } elseif (preg_match('@rv:1\.9(.*)Gecko@', $HTTP_USER_AGENT)) {
  261. $this->set('PMA_USR_BROWSER_VER', '1.9');
  262. $this->set('PMA_USR_BROWSER_AGENT', 'GECKO');
  263. } elseif ($is_mozilla) {
  264. $this->set('PMA_USR_BROWSER_VER', $mozilla_version[1]);
  265. $this->set('PMA_USR_BROWSER_AGENT', 'MOZILLA');
  266. } else {
  267. $this->set('PMA_USR_BROWSER_VER', 0);
  268. $this->set('PMA_USR_BROWSER_AGENT', 'OTHER');
  269. }
  270. }
  271. /**
  272. * Whether GD2 is present
  273. */
  274. public function checkGd2(): void
  275. {
  276. if ($this->get('GD2Available') === 'yes') {
  277. $this->set('PMA_IS_GD2', 1);
  278. return;
  279. }
  280. if ($this->get('GD2Available') === 'no') {
  281. $this->set('PMA_IS_GD2', 0);
  282. return;
  283. }
  284. if (! function_exists('imagecreatetruecolor')) {
  285. $this->set('PMA_IS_GD2', 0);
  286. return;
  287. }
  288. if (function_exists('gd_info')) {
  289. $gd_nfo = gd_info();
  290. if (mb_strstr($gd_nfo['GD Version'], '2.')) {
  291. $this->set('PMA_IS_GD2', 1);
  292. } else {
  293. $this->set('PMA_IS_GD2', 0);
  294. }
  295. } else {
  296. $this->set('PMA_IS_GD2', 0);
  297. }
  298. }
  299. /**
  300. * Whether the Web server php is running on is IIS
  301. */
  302. public function checkWebServer(): void
  303. {
  304. // some versions return Microsoft-IIS, some Microsoft/IIS
  305. // we could use a preg_match() but it's slower
  306. if (Core::getenv('SERVER_SOFTWARE')
  307. && stripos(Core::getenv('SERVER_SOFTWARE'), 'Microsoft') !== false
  308. && stripos(Core::getenv('SERVER_SOFTWARE'), 'IIS') !== false
  309. ) {
  310. $this->set('PMA_IS_IIS', 1);
  311. } else {
  312. $this->set('PMA_IS_IIS', 0);
  313. }
  314. }
  315. /**
  316. * Whether the os php is running on is windows or not
  317. */
  318. public function checkWebServerOs(): void
  319. {
  320. // Default to Unix or Equiv
  321. $this->set('PMA_IS_WINDOWS', false);
  322. // If PHP_OS is defined then continue
  323. if (! defined('PHP_OS')) {
  324. return;
  325. }
  326. if (stripos(PHP_OS, 'win') !== false && stripos(PHP_OS, 'darwin') === false) {
  327. // Is it some version of Windows
  328. $this->set('PMA_IS_WINDOWS', true);
  329. } elseif (stripos(PHP_OS, 'OS/2') !== false) {
  330. // Is it OS/2 (No file permissions like Windows)
  331. $this->set('PMA_IS_WINDOWS', true);
  332. }
  333. }
  334. /**
  335. * loads default values from default source
  336. *
  337. * @return bool success
  338. */
  339. public function loadDefaults(): bool
  340. {
  341. global $isConfigLoading;
  342. /** @var array<string,mixed> $cfg */
  343. $cfg = [];
  344. if (! @file_exists($this->defaultSource)) {
  345. $this->errorConfigDefaultFile = true;
  346. return false;
  347. }
  348. $canUseErrorReporting = Util::isErrorReportingAvailable();
  349. $oldErrorReporting = null;
  350. if ($canUseErrorReporting) {
  351. $oldErrorReporting = error_reporting(0);
  352. }
  353. ob_start();
  354. $isConfigLoading = true;
  355. $eval_result = include $this->defaultSource;
  356. $isConfigLoading = false;
  357. ob_end_clean();
  358. if ($canUseErrorReporting) {
  359. error_reporting($oldErrorReporting);
  360. }
  361. if ($eval_result === false) {
  362. $this->errorConfigDefaultFile = true;
  363. return false;
  364. }
  365. $this->defaultSourceMtime = filemtime($this->defaultSource);
  366. $this->defaultServer = $cfg['Servers'][1];
  367. unset($cfg['Servers']);
  368. $this->default = $cfg;
  369. $this->settings = array_replace_recursive($this->settings, $cfg);
  370. $this->errorConfigDefaultFile = false;
  371. return true;
  372. }
  373. /**
  374. * loads configuration from $source, usually the config file
  375. * should be called on object creation
  376. *
  377. * @param string $source config file
  378. */
  379. public function load(?string $source = null): bool
  380. {
  381. global $isConfigLoading;
  382. $this->loadDefaults();
  383. if ($source !== null) {
  384. $this->setSource($source);
  385. }
  386. if (! $this->checkConfigSource()) {
  387. return false;
  388. }
  389. $cfg = [];
  390. /**
  391. * Parses the configuration file, we throw away any errors or
  392. * output.
  393. */
  394. $canUseErrorReporting = Util::isErrorReportingAvailable();
  395. $oldErrorReporting = null;
  396. if ($canUseErrorReporting) {
  397. $oldErrorReporting = error_reporting(0);
  398. }
  399. ob_start();
  400. $isConfigLoading = true;
  401. $eval_result = include $this->getSource();
  402. $isConfigLoading = false;
  403. ob_end_clean();
  404. if ($canUseErrorReporting) {
  405. error_reporting($oldErrorReporting);
  406. }
  407. if ($eval_result === false) {
  408. $this->errorConfigFile = true;
  409. } else {
  410. $this->errorConfigFile = false;
  411. $this->sourceMtime = filemtime($this->getSource());
  412. }
  413. /**
  414. * Ignore keys with / as we do not use these
  415. *
  416. * These can be confusing for user configuration layer as it
  417. * flatten array using / and thus don't see difference between
  418. * $cfg['Export/method'] and $cfg['Export']['method'], while rest
  419. * of the code uses the setting only in latter form.
  420. *
  421. * This could be removed once we consistently handle both values
  422. * in the functional code as well.
  423. *
  424. * It could use array_filter(...ARRAY_FILTER_USE_KEY), but it's not
  425. * supported on PHP 5.5 and HHVM.
  426. */
  427. $matched_keys = array_filter(
  428. array_keys($cfg),
  429. static function ($key) {
  430. return strpos($key, '/') === false;
  431. }
  432. );
  433. $cfg = array_intersect_key($cfg, array_flip($matched_keys));
  434. $this->settings = array_replace_recursive($this->settings, $cfg);
  435. return true;
  436. }
  437. /**
  438. * Sets the connection collation
  439. */
  440. private function setConnectionCollation(): void
  441. {
  442. global $dbi;
  443. $collation_connection = $this->get('DefaultConnectionCollation');
  444. if (empty($collation_connection)
  445. || $collation_connection == $GLOBALS['collation_connection']
  446. ) {
  447. return;
  448. }
  449. $dbi->setCollation($collation_connection);
  450. }
  451. /**
  452. * Loads user preferences and merges them with current config
  453. * must be called after control connection has been established
  454. */
  455. public function loadUserPreferences(): void
  456. {
  457. $userPreferences = new UserPreferences();
  458. // index.php should load these settings, so that phpmyadmin.css.php
  459. // will have everything available in session cache
  460. $server = $GLOBALS['server'] ?? (! empty($GLOBALS['cfg']['ServerDefault'])
  461. ? $GLOBALS['cfg']['ServerDefault']
  462. : 0);
  463. $cache_key = 'server_' . $server;
  464. if ($server > 0 && ! defined('PMA_MINIMUM_COMMON')) {
  465. $config_mtime = max($this->defaultSourceMtime, $this->sourceMtime);
  466. // cache user preferences, use database only when needed
  467. if (! isset($_SESSION['cache'][$cache_key]['userprefs'])
  468. || $_SESSION['cache'][$cache_key]['config_mtime'] < $config_mtime
  469. ) {
  470. $prefs = $userPreferences->load();
  471. $_SESSION['cache'][$cache_key]['userprefs']
  472. = $userPreferences->apply($prefs['config_data']);
  473. $_SESSION['cache'][$cache_key]['userprefs_mtime'] = $prefs['mtime'];
  474. $_SESSION['cache'][$cache_key]['userprefs_type'] = $prefs['type'];
  475. $_SESSION['cache'][$cache_key]['config_mtime'] = $config_mtime;
  476. }
  477. } elseif ($server == 0
  478. || ! isset($_SESSION['cache'][$cache_key]['userprefs'])
  479. ) {
  480. $this->set('user_preferences', false);
  481. return;
  482. }
  483. $config_data = $_SESSION['cache'][$cache_key]['userprefs'];
  484. // type is 'db' or 'session'
  485. $this->set(
  486. 'user_preferences',
  487. $_SESSION['cache'][$cache_key]['userprefs_type']
  488. );
  489. $this->set(
  490. 'user_preferences_mtime',
  491. $_SESSION['cache'][$cache_key]['userprefs_mtime']
  492. );
  493. // load config array
  494. $this->settings = array_replace_recursive($this->settings, $config_data);
  495. $GLOBALS['cfg'] = array_replace_recursive($GLOBALS['cfg'], $config_data);
  496. if (defined('PMA_MINIMUM_COMMON')) {
  497. return;
  498. }
  499. // settings below start really working on next page load, but
  500. // changes are made only in index.php so everything is set when
  501. // in frames
  502. // save theme
  503. /** @var ThemeManager $tmanager */
  504. $tmanager = ThemeManager::getInstance();
  505. if ($tmanager->getThemeCookie() || isset($_REQUEST['set_theme'])) {
  506. if ((! isset($config_data['ThemeDefault'])
  507. && $tmanager->theme->getId() !== 'original')
  508. || isset($config_data['ThemeDefault'])
  509. && $config_data['ThemeDefault'] != $tmanager->theme->getId()
  510. ) {
  511. // new theme was set in common.inc.php
  512. $this->setUserValue(
  513. null,
  514. 'ThemeDefault',
  515. $tmanager->theme->getId(),
  516. 'original'
  517. );
  518. }
  519. } else {
  520. // no cookie - read default from settings
  521. if ($tmanager->theme !== null
  522. && $this->settings['ThemeDefault'] != $tmanager->theme->getId()
  523. && $tmanager->checkTheme($this->settings['ThemeDefault'])
  524. ) {
  525. $tmanager->setActiveTheme($this->settings['ThemeDefault']);
  526. $tmanager->setThemeCookie();
  527. }
  528. }
  529. // save language
  530. if ($this->issetCookie('pma_lang') || isset($_POST['lang'])) {
  531. if ((! isset($config_data['lang'])
  532. && $GLOBALS['lang'] !== 'en')
  533. || isset($config_data['lang'])
  534. && $GLOBALS['lang'] != $config_data['lang']
  535. ) {
  536. $this->setUserValue(null, 'lang', $GLOBALS['lang'], 'en');
  537. }
  538. } else {
  539. // read language from settings
  540. if (isset($config_data['lang'])) {
  541. $language = LanguageManager::getInstance()->getLanguage(
  542. $config_data['lang']
  543. );
  544. if ($language !== false) {
  545. $language->activate();
  546. $this->setCookie('pma_lang', $language->getCode());
  547. }
  548. }
  549. }
  550. // set connection collation
  551. $this->setConnectionCollation();
  552. }
  553. /**
  554. * Sets config value which is stored in user preferences (if available)
  555. * or in a cookie.
  556. *
  557. * If user preferences are not yet initialized, option is applied to
  558. * global config and added to a update queue, which is processed
  559. * by {@link loadUserPreferences()}
  560. *
  561. * @param string|null $cookie_name can be null
  562. * @param string $cfg_path configuration path
  563. * @param string $new_cfg_value new value
  564. * @param string|null $default_value default value
  565. *
  566. * @return true|Message
  567. */
  568. public function setUserValue(
  569. ?string $cookie_name,
  570. string $cfg_path,
  571. $new_cfg_value,
  572. $default_value = null
  573. ) {
  574. $userPreferences = new UserPreferences();
  575. $result = true;
  576. // use permanent user preferences if possible
  577. $prefs_type = $this->get('user_preferences');
  578. if ($prefs_type) {
  579. if ($default_value === null) {
  580. $default_value = Core::arrayRead($cfg_path, $this->default);
  581. }
  582. $result = $userPreferences->persistOption($cfg_path, $new_cfg_value, $default_value);
  583. }
  584. if ($prefs_type !== 'db' && $cookie_name) {
  585. // fall back to cookies
  586. if ($default_value === null) {
  587. $default_value = Core::arrayRead($cfg_path, $this->settings);
  588. }
  589. $this->setCookie($cookie_name, $new_cfg_value, $default_value);
  590. }
  591. Core::arrayWrite($cfg_path, $GLOBALS['cfg'], $new_cfg_value);
  592. Core::arrayWrite($cfg_path, $this->settings, $new_cfg_value);
  593. return $result;
  594. }
  595. /**
  596. * Reads value stored by {@link setUserValue()}
  597. *
  598. * @param string $cookie_name cookie name
  599. * @param mixed $cfg_value config value
  600. *
  601. * @return mixed
  602. */
  603. public function getUserValue(string $cookie_name, $cfg_value)
  604. {
  605. $cookie_exists = ! empty($this->getCookie($cookie_name));
  606. $prefs_type = $this->get('user_preferences');
  607. if ($prefs_type === 'db') {
  608. // permanent user preferences value exists, remove cookie
  609. if ($cookie_exists) {
  610. $this->removeCookie($cookie_name);
  611. }
  612. } elseif ($cookie_exists) {
  613. return $this->getCookie($cookie_name);
  614. }
  615. // return value from $cfg array
  616. return $cfg_value;
  617. }
  618. /**
  619. * set source
  620. *
  621. * @param string $source source
  622. */
  623. public function setSource(string $source): void
  624. {
  625. $this->source = trim($source);
  626. }
  627. /**
  628. * check config source
  629. *
  630. * @return bool whether source is valid or not
  631. */
  632. public function checkConfigSource(): bool
  633. {
  634. if (! $this->getSource()) {
  635. // no configuration file set at all
  636. return false;
  637. }
  638. if (! @file_exists($this->getSource())) {
  639. $this->sourceMtime = 0;
  640. return false;
  641. }
  642. if (! @is_readable($this->getSource())) {
  643. // manually check if file is readable
  644. // might be bug #3059806 Supporting running from CIFS/Samba shares
  645. $contents = false;
  646. $handle = @fopen($this->getSource(), 'r');
  647. if ($handle !== false) {
  648. $contents = @fread($handle, 1); // reading 1 byte is enough to test
  649. fclose($handle);
  650. }
  651. if ($contents === false) {
  652. $this->sourceMtime = 0;
  653. Core::fatalError(
  654. sprintf(
  655. function_exists('__')
  656. ? __('Existing configuration file (%s) is not readable.')
  657. : 'Existing configuration file (%s) is not readable.',
  658. $this->getSource()
  659. )
  660. );
  661. return false;
  662. }
  663. }
  664. return true;
  665. }
  666. /**
  667. * verifies the permissions on config file (if asked by configuration)
  668. * (must be called after config.inc.php has been merged)
  669. */
  670. public function checkPermissions(): void
  671. {
  672. // Check for permissions (on platforms that support it):
  673. if (! $this->get('CheckConfigurationPermissions') || ! @file_exists($this->getSource())) {
  674. return;
  675. }
  676. $perms = @fileperms($this->getSource());
  677. if ($perms === false || (! ($perms & 2))) {
  678. return;
  679. }
  680. // This check is normally done after loading configuration
  681. $this->checkWebServerOs();
  682. if ($this->get('PMA_IS_WINDOWS') === true) {
  683. return;
  684. }
  685. $this->sourceMtime = 0;
  686. Core::fatalError(
  687. __(
  688. 'Wrong permissions on configuration file, '
  689. . 'should not be world writable!'
  690. )
  691. );
  692. }
  693. /**
  694. * Checks for errors
  695. * (must be called after config.inc.php has been merged)
  696. */
  697. public function checkErrors(): void
  698. {
  699. if ($this->errorConfigDefaultFile) {
  700. Core::fatalError(
  701. sprintf(
  702. __('Could not load default configuration from: %1$s'),
  703. $this->defaultSource
  704. )
  705. );
  706. }
  707. if (! $this->errorConfigFile) {
  708. return;
  709. }
  710. $error = '[strong]' . __('Failed to read configuration file!') . '[/strong]'
  711. . '[br][br]'
  712. . __(
  713. 'This usually means there is a syntax error in it, '
  714. . 'please check any errors shown below.'
  715. )
  716. . '[br][br]'
  717. . '[conferr]';
  718. trigger_error($error, E_USER_ERROR);
  719. }
  720. /**
  721. * returns specific config setting
  722. *
  723. * @param string $setting config setting
  724. *
  725. * @return mixed|null value
  726. */
  727. public function get(string $setting)
  728. {
  729. if (isset($this->settings[$setting])) {
  730. return $this->settings[$setting];
  731. }
  732. return null;
  733. }
  734. /**
  735. * sets configuration variable
  736. *
  737. * @param string $setting configuration option
  738. * @param mixed $value new value for configuration option
  739. */
  740. public function set(string $setting, $value): void
  741. {
  742. if (isset($this->settings[$setting])
  743. && $this->settings[$setting] === $value
  744. ) {
  745. return;
  746. }
  747. $this->settings[$setting] = $value;
  748. $this->setMtime = time();
  749. }
  750. /**
  751. * returns source for current config
  752. *
  753. * @return string config source
  754. */
  755. public function getSource(): string
  756. {
  757. return $this->source;
  758. }
  759. /**
  760. * returns a unique value to force a CSS reload if either the config
  761. * or the theme changes
  762. *
  763. * @return int Summary of unix timestamps, to be unique on theme parameters
  764. * change
  765. */
  766. public function getThemeUniqueValue(): int
  767. {
  768. global $PMA_Theme;
  769. return crc32(
  770. $this->sourceMtime .
  771. $this->defaultSourceMtime .
  772. $this->get('user_preferences_mtime') .
  773. ($PMA_Theme->mtimeInfo ?? 0) .
  774. ($PMA_Theme->filesizeInfo ?? 0)
  775. );
  776. }
  777. /**
  778. * checks if upload is enabled
  779. */
  780. public function checkUpload(): void
  781. {
  782. if (! ini_get('file_uploads')) {
  783. $this->set('enable_upload', false);
  784. return;
  785. }
  786. $this->set('enable_upload', true);
  787. // if set "php_admin_value file_uploads Off" in httpd.conf
  788. // ini_get() also returns the string "Off" in this case:
  789. if (strtolower((string) ini_get('file_uploads')) !== 'off') {
  790. return;
  791. }
  792. $this->set('enable_upload', false);
  793. }
  794. /**
  795. * Maximum upload size as limited by PHP
  796. * Used with permission from Moodle (https://moodle.org/) by Martin Dougiamas
  797. *
  798. * this section generates $max_upload_size in bytes
  799. */
  800. public function checkUploadSize(): void
  801. {
  802. $fileSize = ini_get('upload_max_filesize');
  803. if (! $fileSize) {
  804. $fileSize = '5M';
  805. }
  806. $size = Core::getRealSize($fileSize);
  807. $postSize = ini_get('post_max_size');
  808. if ($postSize) {
  809. $size = min($size, Core::getRealSize($postSize));
  810. }
  811. $this->set('max_upload_size', $size);
  812. }
  813. /**
  814. * Checks if protocol is https
  815. *
  816. * This function checks if the https protocol on the active connection.
  817. */
  818. public function isHttps(): bool
  819. {
  820. if ($this->get('is_https') !== null) {
  821. return $this->get('is_https');
  822. }
  823. $url = $this->get('PmaAbsoluteUri');
  824. $is_https = false;
  825. if (! empty($url) && parse_url($url, PHP_URL_SCHEME) === 'https') {
  826. $is_https = true;
  827. } elseif (strtolower(Core::getenv('HTTP_SCHEME')) === 'https') {
  828. $is_https = true;
  829. } elseif (strtolower(Core::getenv('HTTPS')) === 'on') {
  830. $is_https = true;
  831. } elseif (strtolower(substr(Core::getenv('REQUEST_URI'), 0, 6)) === 'https:') {
  832. $is_https = true;
  833. } elseif (strtolower(Core::getenv('HTTP_HTTPS_FROM_LB')) === 'on') {
  834. // A10 Networks load balancer
  835. $is_https = true;
  836. } elseif (strtolower(Core::getenv('HTTP_FRONT_END_HTTPS')) === 'on') {
  837. $is_https = true;
  838. } elseif (strtolower(Core::getenv('HTTP_X_FORWARDED_PROTO')) === 'https') {
  839. $is_https = true;
  840. } elseif (strtolower(Core::getenv('HTTP_CLOUDFRONT_FORWARDED_PROTO')) === 'https') {
  841. // Amazon CloudFront, issue #15621
  842. $is_https = true;
  843. } elseif (Util::getProtoFromForwardedHeader(Core::getenv('HTTP_FORWARDED')) === 'https') {
  844. // RFC 7239 Forwarded header
  845. $is_https = true;
  846. } elseif (Core::getenv('SERVER_PORT') == 443) {
  847. $is_https = true;
  848. }
  849. $this->set('is_https', $is_https);
  850. return $is_https;
  851. }
  852. /**
  853. * Get phpMyAdmin root path
  854. */
  855. public function getRootPath(): string
  856. {
  857. static $cookie_path = null;
  858. if ($cookie_path !== null && ! defined('TESTSUITE')) {
  859. return $cookie_path;
  860. }
  861. $url = $this->get('PmaAbsoluteUri');
  862. if (! empty($url)) {
  863. $path = parse_url($url, PHP_URL_PATH);
  864. if (! empty($path)) {
  865. if (substr($path, -1) !== '/') {
  866. return $path . '/';
  867. }
  868. return $path;
  869. }
  870. }
  871. $parsedUrlPath = parse_url($GLOBALS['PMA_PHP_SELF'], PHP_URL_PATH);
  872. $parts = explode(
  873. '/',
  874. rtrim(str_replace('\\', '/', $parsedUrlPath), '/')
  875. );
  876. /* Remove filename */
  877. if (substr($parts[count($parts) - 1], -4) === '.php') {
  878. $parts = array_slice($parts, 0, count($parts) - 1);
  879. }
  880. /* Remove extra path from javascript calls */
  881. if (defined('PMA_PATH_TO_BASEDIR')) {
  882. $parts = array_slice($parts, 0, count($parts) - 1);
  883. }
  884. $parts[] = '';
  885. return implode('/', $parts);
  886. }
  887. /**
  888. * enables backward compatibility
  889. */
  890. public function enableBc(): void
  891. {
  892. $GLOBALS['cfg'] = $this->settings;
  893. $GLOBALS['default_server'] = $this->defaultServer;
  894. unset($this->defaultServer);
  895. $GLOBALS['is_upload'] = $this->get('enable_upload');
  896. $GLOBALS['max_upload_size'] = $this->get('max_upload_size');
  897. $GLOBALS['is_https'] = $this->get('is_https');
  898. $defines = [
  899. 'PMA_VERSION',
  900. 'PMA_MAJOR_VERSION',
  901. 'PMA_THEME_VERSION',
  902. 'PMA_THEME_GENERATION',
  903. 'PMA_IS_WINDOWS',
  904. 'PMA_IS_GD2',
  905. 'PMA_USR_OS',
  906. 'PMA_USR_BROWSER_VER',
  907. 'PMA_USR_BROWSER_AGENT',
  908. ];
  909. foreach ($defines as $define) {
  910. if (defined($define)) {
  911. continue;
  912. }
  913. define($define, $this->get($define));
  914. }
  915. }
  916. /**
  917. * removes cookie
  918. *
  919. * @param string $cookieName name of cookie to remove
  920. *
  921. * @return bool result of setcookie()
  922. */
  923. public function removeCookie(string $cookieName): bool
  924. {
  925. $httpCookieName = $this->getCookieName($cookieName);
  926. if ($this->issetCookie($cookieName)) {
  927. unset($_COOKIE[$httpCookieName]);
  928. }
  929. if (defined('TESTSUITE')) {
  930. return true;
  931. }
  932. return setcookie(
  933. $httpCookieName,
  934. '',
  935. time() - 3600,
  936. $this->getRootPath(),
  937. '',
  938. $this->isHttps()
  939. );
  940. }
  941. /**
  942. * sets cookie if value is different from current cookie value,
  943. * or removes if value is equal to default
  944. *
  945. * @param string $cookie name of cookie to remove
  946. * @param string $value new cookie value
  947. * @param string $default default value
  948. * @param int $validity validity of cookie in seconds (default is one month)
  949. * @param bool $httponly whether cookie is only for HTTP (and not for scripts)
  950. *
  951. * @return bool result of setcookie()
  952. */
  953. public function setCookie(
  954. string $cookie,
  955. string $value,
  956. ?string $default = null,
  957. ?int $validity = null,
  958. bool $httponly = true
  959. ): bool {
  960. global $cfg;
  961. if (strlen($value) > 0 && $default !== null && $value === $default
  962. ) {
  963. // default value is used
  964. if ($this->issetCookie($cookie)) {
  965. // remove cookie
  966. return $this->removeCookie($cookie);
  967. }
  968. return false;
  969. }
  970. if (strlen($value) === 0 && $this->issetCookie($cookie)) {
  971. // remove cookie, value is empty
  972. return $this->removeCookie($cookie);
  973. }
  974. $httpCookieName = $this->getCookieName($cookie);
  975. if (! $this->issetCookie($cookie) || $this->getCookie($cookie) !== $value) {
  976. // set cookie with new value
  977. /* Calculate cookie validity */
  978. if ($validity === null) {
  979. /* Valid for one month */
  980. $validity = time() + 2592000;
  981. } elseif ($validity == 0) {
  982. /* Valid for session */
  983. $validity = 0;
  984. } else {
  985. $validity = time() + $validity;
  986. }
  987. if (defined('TESTSUITE')) {
  988. $_COOKIE[$httpCookieName] = $value;
  989. return true;
  990. }
  991. if (PHP_VERSION_ID < 70300) {
  992. return setcookie(
  993. $httpCookieName,
  994. $value,
  995. $validity,
  996. $this->getRootPath() . '; samesite=' . $cfg['CookieSameSite'],
  997. '',
  998. $this->isHttps(),
  999. $httponly
  1000. );
  1001. }
  1002. $optionalParams = [
  1003. 'expires' => $validity,
  1004. 'path' => $this->getRootPath(),
  1005. 'domain' => '',
  1006. 'secure' => $this->isHttps(),
  1007. 'httponly' => $httponly,
  1008. 'samesite' => $cfg['CookieSameSite'],
  1009. ];
  1010. return setcookie(
  1011. $httpCookieName,
  1012. $value,
  1013. $optionalParams
  1014. );
  1015. }
  1016. // cookie has already $value as value
  1017. return true;
  1018. }
  1019. /**
  1020. * get cookie
  1021. *
  1022. * @param string $cookieName The name of the cookie to get
  1023. *
  1024. * @return mixed|null result of getCookie()
  1025. */
  1026. public function getCookie(string $cookieName)
  1027. {
  1028. if (isset($_COOKIE[$this->getCookieName($cookieName)])) {
  1029. return $_COOKIE[$this->getCookieName($cookieName)];
  1030. }
  1031. return null;
  1032. }
  1033. /**
  1034. * Get the real cookie name
  1035. *
  1036. * @param string $cookieName The name of the cookie
  1037. */
  1038. public function getCookieName(string $cookieName): string
  1039. {
  1040. return $cookieName . ( $this->isHttps() ? '_https' : '' );
  1041. }
  1042. /**
  1043. * isset cookie
  1044. *
  1045. * @param string $cookieName The name of the cookie to check
  1046. *
  1047. * @return bool result of issetCookie()
  1048. */
  1049. public function issetCookie(string $cookieName): bool
  1050. {
  1051. return isset($_COOKIE[$this->getCookieName($cookieName)]);
  1052. }
  1053. /**
  1054. * Error handler to catch fatal errors when loading configuration
  1055. * file
  1056. */
  1057. public static function fatalErrorHandler(): void
  1058. {
  1059. global $isConfigLoading;
  1060. if (! isset($isConfigLoading) || ! $isConfigLoading) {
  1061. return;
  1062. }
  1063. $error = error_get_last();
  1064. if ($error === null) {
  1065. return;
  1066. }
  1067. Core::fatalError(
  1068. sprintf(
  1069. 'Failed to load phpMyAdmin configuration (%s:%s): %s',
  1070. Error::relPath($error['file']),
  1071. $error['line'],
  1072. $error['message']
  1073. )
  1074. );
  1075. }
  1076. /**
  1077. * Wrapper for footer/header rendering
  1078. *
  1079. * @param string $filename File to check and render
  1080. * @param string $id Div ID
  1081. */
  1082. private static function renderCustom(string $filename, string $id): string
  1083. {
  1084. $retval = '';
  1085. if (@file_exists($filename)) {
  1086. $retval .= '<div id="' . $id . '">';
  1087. ob_start();
  1088. include $filename;
  1089. $retval .= ob_get_clean();
  1090. $retval .= '</div>';
  1091. }
  1092. return $retval;
  1093. }
  1094. /**
  1095. * Renders user configured footer
  1096. */
  1097. public static function renderFooter(): string
  1098. {
  1099. return self::renderCustom(CUSTOM_FOOTER_FILE, 'pma_footer');
  1100. }
  1101. /**
  1102. * Renders user configured footer
  1103. */
  1104. public static function renderHeader(): string
  1105. {
  1106. return self::renderCustom(CUSTOM_HEADER_FILE, 'pma_header');
  1107. }
  1108. /**
  1109. * Returns temporary dir path
  1110. *
  1111. * @param string $name Directory name
  1112. */
  1113. public function getTempDir(string $name): ?string
  1114. {
  1115. static $temp_dir = [];
  1116. if (isset($temp_dir[$name]) && ! defined('TESTSUITE')) {
  1117. return $temp_dir[$name];
  1118. }
  1119. $path = $this->get('TempDir');
  1120. if (empty($path)) {
  1121. $path = null;
  1122. } else {
  1123. $path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $name;
  1124. if (! @is_dir($path)) {
  1125. @mkdir($path, 0770, true);
  1126. }
  1127. if (! @is_dir($path) || ! @is_writable($path)) {
  1128. $path = null;
  1129. }
  1130. }
  1131. $temp_dir[$name] = $path;
  1132. return $path;
  1133. }
  1134. /**
  1135. * Returns temporary directory
  1136. */
  1137. public function getUploadTempDir(): ?string
  1138. {
  1139. // First try configured temp dir
  1140. // Fallback to PHP upload_tmp_dir
  1141. $dirs = [
  1142. $this->getTempDir('upload'),
  1143. ini_get('upload_tmp_dir'),
  1144. sys_get_temp_dir(),
  1145. ];
  1146. foreach ($dirs as $dir) {
  1147. if (! empty($dir) && @is_writable($dir)) {
  1148. return realpath($dir);
  1149. }
  1150. }
  1151. return null;
  1152. }
  1153. /**
  1154. * Selects server based on request parameters.
  1155. */
  1156. public function selectServer(): int
  1157. {
  1158. $request = empty($_REQUEST['server']) ? 0 : $_REQUEST['server'];
  1159. /**
  1160. * Lookup server by name
  1161. * (see FAQ 4.8)
  1162. */
  1163. if (! is_numeric($request)) {
  1164. foreach ($this->settings['Servers'] as $i => $server) {
  1165. $verboseToLower = mb_strtolower($server['verbose']);
  1166. $serverToLower = mb_strtolower($request);
  1167. if ($server['host'] == $request
  1168. || $server['verbose'] == $request
  1169. || $verboseToLower == $serverToLower
  1170. || md5($verboseToLower) === $serverToLower
  1171. ) {
  1172. $request = $i;
  1173. break;
  1174. }
  1175. }
  1176. if (is_string($request)) {
  1177. $request = 0;
  1178. }
  1179. }
  1180. /**
  1181. * If no server is selected, make sure that $this->settings['Server'] is empty (so
  1182. * that nothing will work), and skip server authentication.
  1183. * We do NOT exit here, but continue on without logging into any server.
  1184. * This way, the welcome page will still come up (with no server info) and
  1185. * present a choice of servers in the case that there are multiple servers
  1186. * and '$this->settings['ServerDefault'] = 0' is set.
  1187. */
  1188. if (is_numeric($request) && ! empty($request) && ! empty($this->settings['Servers'][$request])) {
  1189. $server = $request;
  1190. $this->settings['Server'] = $this->settings['Servers'][$server];
  1191. } else {
  1192. if (! empty($this->settings['Servers'][$this->settings['ServerDefault']])) {
  1193. $server = $this->settings['ServerDefault'];
  1194. $this->settings['Server'] = $this->settings['Servers'][$server];
  1195. } else {
  1196. $server = 0;
  1197. $this->settings['Server'] = [];
  1198. }
  1199. }
  1200. return (int) $server;
  1201. }
  1202. /**
  1203. * Checks whether Servers configuration is valid and possibly apply fixups.
  1204. */
  1205. public function checkServers(): void
  1206. {
  1207. // Do we have some server?
  1208. if (! isset($this->settings['Servers']) || count($this->settings['Servers']) === 0) {
  1209. // No server => create one with defaults
  1210. $this->settings['Servers'] = [1 => $this->defaultServer];
  1211. } else {
  1212. // We have server(s) => apply default configuration
  1213. $new_servers = [];
  1214. foreach ($this->settings['Servers'] as $server_index => $each_server) {
  1215. // Detect wrong configuration
  1216. if (! is_int($server_index) || $server_index < 1) {
  1217. trigger_error(
  1218. sprintf(__('Invalid server index: %s'), $server_index),
  1219. E_USER_ERROR
  1220. );
  1221. }
  1222. $each_server = array_merge($this->defaultServer, $each_server);
  1223. // Final solution to bug #582890
  1224. // If we are using a socket connection
  1225. // and there is nothing in the verbose server name
  1226. // or the host field, then generate a name for the server
  1227. // in the form of "Server 2", localized of course!
  1228. if (empty($each_server['host']) && empty($each_server['verbose'])) {
  1229. $each_server['verbose'] = sprintf(__('Server %d'), $server_index);
  1230. }
  1231. $new_servers[$server_index] = $each_server;
  1232. }
  1233. $this->settings['Servers'] = $new_servers;
  1234. }
  1235. }
  1236. /**
  1237. * Return connection parameters for the database server
  1238. *
  1239. * @param int $mode Connection mode on of CONNECT_USER, CONNECT_CONTROL
  1240. * or CONNECT_AUXILIARY.
  1241. * @param array|null $server Server information like host/port/socket/persistent
  1242. *
  1243. * @return array user, host and server settings array
  1244. */
  1245. public static function getConnectionParams(int $mode, ?array $server = null): array
  1246. {
  1247. global $cfg;
  1248. $user = null;
  1249. $password = null;
  1250. if ($mode == DatabaseInterface::CONNECT_USER) {
  1251. $user = $cfg['Server']['user'];
  1252. $password = $cfg['Server']['password'];
  1253. $server = $cfg['Server'];
  1254. } elseif ($mode == DatabaseInterface::CONNECT_CONTROL) {
  1255. $user = $cfg['Server']['controluser'];
  1256. $password = $cfg['Server']['controlpass'];
  1257. $server = [];
  1258. if (! empty($cfg['Server']['controlhost'])) {
  1259. $server['host'] = $cfg['Server']['controlhost'];
  1260. } else {
  1261. $server['host'] = $cfg['Server']['host'];
  1262. }
  1263. // Share the settings if the host is same
  1264. if ($server['host'] == $cfg['Server']['host']) {
  1265. $shared = [
  1266. 'port',
  1267. 'socket',
  1268. 'compress',
  1269. 'ssl',
  1270. 'ssl_key',
  1271. 'ssl_cert',
  1272. 'ssl_ca',
  1273. 'ssl_ca_path',
  1274. 'ssl_ciphers',
  1275. 'ssl_verify',
  1276. ];
  1277. foreach ($shared as $item) {
  1278. if (! isset($cfg['Server'][$item])) {
  1279. continue;
  1280. }
  1281. $server[$item] = $cfg['Server'][$item];
  1282. }
  1283. }
  1284. // Set configured port
  1285. if (! empty($cfg['Server']['controlport'])) {
  1286. $server['port'] = $cfg['Server']['controlport'];
  1287. }
  1288. // Set any configuration with control_ prefix
  1289. foreach ($cfg['Server'] as $key => $val) {
  1290. if (substr($key, 0, 8) !== 'control_') {
  1291. continue;
  1292. }
  1293. $server[substr($key, 8)] = $val;
  1294. }
  1295. } else {
  1296. if ($server === null) {
  1297. return [
  1298. null,
  1299. null,
  1300. null,
  1301. ];
  1302. }
  1303. if (isset($server['user'])) {
  1304. $user = $server['user'];
  1305. }
  1306. if (isset($server['password'])) {
  1307. $password = $server['password'];
  1308. }
  1309. }
  1310. // Perform sanity checks on some variables
  1311. $server['port'] = empty($server['port']) ? 0 : (int) $server['port'];
  1312. if (empty($server['socket'])) {
  1313. $server['socket'] = null;
  1314. }
  1315. if (empty($server['host'])) {
  1316. $server['host'] = 'localhost';
  1317. }
  1318. if (! isset($server['ssl'])) {
  1319. $server['ssl'] = false;
  1320. }
  1321. if (! isset($server['compress'])) {
  1322. $server['compress'] = false;
  1323. }
  1324. return [
  1325. $user,
  1326. $password,
  1327. $server,
  1328. ];
  1329. }
  1330. /**
  1331. * Get LoginCookieValidity from preferences cache.
  1332. *
  1333. * No generic solution for loading preferences from cache as some settings
  1334. * need to be kept for processing in loadUserPreferences().
  1335. *
  1336. * @see loadUserPreferences()
  1337. */
  1338. public function getLoginCookieValidityFromCache(int $server): void
  1339. {
  1340. global $cfg;
  1341. $cacheKey = 'server_' . $server;
  1342. if (! isset($_SESSION['cache'][$cacheKey]['userprefs']['LoginCookieValidity'])) {
  1343. return;
  1344. }
  1345. $value = $_SESSION['cache'][$cacheKey]['userprefs']['LoginCookieValidity'];
  1346. $this->set('LoginCookieValidity', $value);
  1347. $cfg['LoginCookieValidity'] = $value;
  1348. }
  1349. }