Recalculate URL only if needed not all times when using https.
[phpmyadmin/last10db.git] / libraries / Config.class.php
blob208a7ce5895464dc4c88952d91745afd9da0124f
1 <?php
2 /* $Id$ */
3 // vim: expandtab sw=4 ts=4 sts=4:
5 /**
6 * Configuration class
8 */
9 class PMA_Config
11 /**
12 * @var string default config source
14 var $default_source = './libraries/config.default.php';
16 /**
17 * @var array configuration settings
19 var $settings = array();
21 /**
22 * @var string config source
24 var $source = '';
26 /**
27 * @var int source modification time
29 var $source_mtime = 0;
30 var $default_source_mtime = 0;
32 /**
33 * @var boolean
35 var $error_config_file = false;
37 /**
38 * @var boolean
40 var $error_config_default_file = false;
42 /**
43 * @var boolean
45 var $error_pma_uri = false;
47 /**
48 * @var array
50 var $default_server = array();
52 /**
53 * @var boolean wether init is done or mot
54 * set this to false to force some initial checks
55 * like checking for required functions
57 var $done = false;
59 /**
60 * constructor
62 * @param string source to read config from
64 function __construct($source = null)
66 $this->settings = array();
68 // functions need to refresh in case of config file changed goes in
69 // PMA_Config::load()
70 $this->load($source);
72 // other settings, independant from config file, comes in
73 $this->checkSystem();
75 $this->checkIsHttps();
78 /**
79 * sets system and application settings
81 function checkSystem()
83 $this->set('PMA_VERSION', '2.9.0-dev');
84 /**
85 * @deprecated
87 $this->set('PMA_THEME_VERSION', 2);
88 /**
89 * @deprecated
91 $this->set('PMA_THEME_GENERATION', 2);
93 $this->checkPhpVersion();
94 $this->checkWebServerOs();
95 $this->checkWebServer();
96 $this->checkGd2();
97 $this->checkClient();
98 $this->checkUpload();
99 $this->checkUploadSize();
100 $this->checkOutputCompression();
104 * wether to use gzip output compression or not
106 function checkOutputCompression()
108 // If zlib output compression is set in the php configuration file, no
109 // output buffering should be run
110 if (@ini_get('zlib.output_compression')) {
111 $this->set('OBGzip', false);
114 // disable output-buffering (if set to 'auto') for IE6, else enable it.
115 if (strtolower($this->get('OBGzip')) == 'auto') {
116 if ($this->get('PMA_USR_BROWSER_AGENT') == 'IE'
117 && $this->get('PMA_USR_BROWSER_VER') >= 6
118 && $this->get('PMA_USR_BROWSER_VER') < 7) {
119 $this->set('OBGzip', false);
120 } else {
121 $this->set('OBGzip', true);
127 * Determines platform (OS), browser and version of the user
128 * Based on a phpBuilder article:
129 * @see http://www.phpbuilder.net/columns/tim20000821.php
131 function checkClient()
133 if (PMA_getenv('HTTP_USER_AGENT')) {
134 $HTTP_USER_AGENT = PMA_getenv('HTTP_USER_AGENT');
135 } elseif (!isset($HTTP_USER_AGENT)) {
136 $HTTP_USER_AGENT = '';
139 // 1. Platform
140 if (strstr($HTTP_USER_AGENT, 'Win')) {
141 $this->set('PMA_USR_OS', 'Win');
142 } elseif (strstr($HTTP_USER_AGENT, 'Mac')) {
143 $this->set('PMA_USR_OS', 'Mac');
144 } elseif (strstr($HTTP_USER_AGENT, 'Linux')) {
145 $this->set('PMA_USR_OS', 'Linux');
146 } elseif (strstr($HTTP_USER_AGENT, 'Unix')) {
147 $this->set('PMA_USR_OS', 'Unix');
148 } elseif (strstr($HTTP_USER_AGENT, 'OS/2')) {
149 $this->set('PMA_USR_OS', 'OS/2');
150 } else {
151 $this->set('PMA_USR_OS', 'Other');
154 // 2. browser and version
155 // (must check everything else before Mozilla)
157 if (preg_match('@Opera(/| )([0-9].[0-9]{1,2})@', $HTTP_USER_AGENT, $log_version)) {
158 $this->set('PMA_USR_BROWSER_VER', $log_version[2]);
159 $this->set('PMA_USR_BROWSER_AGENT', 'OPERA');
160 } elseif (preg_match('@MSIE ([0-9].[0-9]{1,2})@', $HTTP_USER_AGENT, $log_version)) {
161 $this->set('PMA_USR_BROWSER_VER', $log_version[1]);
162 $this->set('PMA_USR_BROWSER_AGENT', 'IE');
163 } elseif (preg_match('@OmniWeb/([0-9].[0-9]{1,2})@', $HTTP_USER_AGENT, $log_version)) {
164 $this->set('PMA_USR_BROWSER_VER', $log_version[1]);
165 $this->set('PMA_USR_BROWSER_AGENT', 'OMNIWEB');
166 //} elseif (ereg('Konqueror/([0-9].[0-9]{1,2})', $HTTP_USER_AGENT, $log_version)) {
167 // Konqueror 2.2.2 says Konqueror/2.2.2
168 // Konqueror 3.0.3 says Konqueror/3
169 } elseif (preg_match('@(Konqueror/)(.*)(;)@', $HTTP_USER_AGENT, $log_version)) {
170 $this->set('PMA_USR_BROWSER_VER', $log_version[2]);
171 $this->set('PMA_USR_BROWSER_AGENT', 'KONQUEROR');
172 } elseif (preg_match('@Mozilla/([0-9].[0-9]{1,2})@', $HTTP_USER_AGENT, $log_version)
173 && preg_match('@Safari/([0-9]*)@', $HTTP_USER_AGENT, $log_version2)) {
174 $this->set('PMA_USR_BROWSER_VER', $log_version[1] . '.' . $log_version2[1]);
175 $this->set('PMA_USR_BROWSER_AGENT', 'SAFARI');
176 } elseif (preg_match('@Mozilla/([0-9].[0-9]{1,2})@', $HTTP_USER_AGENT, $log_version)) {
177 $this->set('PMA_USR_BROWSER_VER', $log_version[1]);
178 $this->set('PMA_USR_BROWSER_AGENT', 'MOZILLA');
179 } else {
180 $this->set('PMA_USR_BROWSER_VER', 0);
181 $this->set('PMA_USR_BROWSER_AGENT', 'OTHER');
186 * Whether GD2 is present
188 function checkGd2()
190 if ($this->get('GD2Available') == 'yes') {
191 $this->set('PMA_IS_GD2', 1);
192 } elseif ($this->get('GD2Available') == 'no') {
193 $this->set('PMA_IS_GD2', 0);
194 } else {
195 if (!@extension_loaded('gd')) {
196 PMA_dl('gd');
198 if (!@function_exists('imagecreatetruecolor')) {
199 $this->set('PMA_IS_GD2', 0);
200 } else {
201 if (@function_exists('gd_info')) {
202 $gd_nfo = gd_info();
203 if (strstr($gd_nfo["GD Version"], '2.')) {
204 $this->set('PMA_IS_GD2', 1);
205 } else {
206 $this->set('PMA_IS_GD2', 0);
208 } else {
209 /* We must do hard way... */
210 ob_start();
211 phpinfo(INFO_MODULES); /* Only modules */
212 $a = strip_tags(ob_get_contents());
213 ob_end_clean();
214 /* Get GD version string from phpinfo output */
215 if (preg_match('@GD Version[[:space:]]*\(.*\)@', $a, $v)) {
216 if (strstr($v, '2.')) {
217 $this->set('PMA_IS_GD2', 1);
218 } else {
219 $this->set('PMA_IS_GD2', 0);
221 } else {
222 $this->set('PMA_IS_GD2', 0);
230 * Whether the Web server php is running on is IIS
232 function checkWebServer()
234 if (PMA_getenv('SERVER_SOFTWARE')
235 // some versions return Microsoft-IIS, some Microsoft/IIS
236 // we could use a preg_match() but it's slower
237 && stristr(PMA_getenv('SERVER_SOFTWARE'), 'Microsoft')
238 && stristr(PMA_getenv('SERVER_SOFTWARE'), 'IIS')) {
239 $this->set('PMA_IS_IIS', 1);
240 } else {
241 $this->set('PMA_IS_IIS', 0);
246 * Whether the os php is running on is windows or not
248 function checkWebServerOs()
250 // Default to Unix or Equiv
251 $this->set('PMA_IS_WINDOWS', 0);
252 // If PHP_OS is defined then continue
253 if (defined('PHP_OS')) {
254 if (stristr(PHP_OS, 'win') ) {
255 // Is it some version of Windows
256 $this->set('PMA_IS_WINDOWS', 1);
257 } elseif (stristr(PHP_OS, 'OS/2')) {
258 // Is it OS/2 (No file permissions like Windows)
259 $this->set('PMA_IS_WINDOWS', 1);
265 * detects PHP version
267 function checkPhpVersion()
269 $match = array();
270 if (! preg_match('@([0-9]{1,2}).([0-9]{1,2}).([0-9]{1,2})@',
271 phpversion(), $match)) {
272 $result = preg_match('@([0-9]{1,2}).([0-9]{1,2})@',
273 phpversion(), $match);
275 if (isset($match) && ! empty($match[1])) {
276 if (! isset($match[2])) {
277 $match[2] = 0;
279 if (! isset($match[3])) {
280 $match[3] = 0;
282 $this->set('PMA_PHP_INT_VERSION',
283 (int) sprintf('%d%02d%02d', $match[1], $match[2], $match[3]));
284 } else {
285 $this->set('PMA_PHP_INT_VERSION', 0);
287 $this->set('PMA_PHP_STR_VERSION', phpversion());
291 * re-init object after loading from session file
292 * checks config file for changes and relaods if neccessary
294 function __wakeup()
296 if (file_exists($this->getSource()) && $this->source_mtime !== filemtime($this->getSource())
297 || $this->default_source_mtime !== filemtime($this->default_source)
298 || $this->error_config_file || $this->error_config_default_file) {
299 $this->settings = array();
300 $this->load($this->getSource());
301 $this->checkSystem();
304 // check for https needs to be done everytime,
305 // as https and http uses same session so this info can not be stored
306 // in session
307 $this->checkIsHttps();
309 $this->checkCollationConnection();
313 * loads default values from default source
315 * @uses file_exists()
316 * @uses $this->default_source
317 * @uses $this->error_config_default_file
318 * @uses $this->settings
319 * @return boolean success
321 function loadDefaults()
323 $cfg = array();
324 if (! file_exists($this->default_source)) {
325 $this->error_config_default_file = true;
326 return false;
328 include $this->default_source;
330 $this->default_source_mtime = filemtime($this->default_source);
332 $this->default_server = $cfg['Servers'][1];
333 unset($cfg['Servers']);
335 $this->settings = PMA_array_merge_recursive($this->settings, $cfg);
337 $this->error_config_default_file = false;
339 return true;
343 * loads configuration from $source, usally the config file
344 * should be called on object creation and from __wakeup if config file
345 * has changed
347 * @param string $source config file
349 function load($source = null)
351 $this->loadDefaults();
353 if (null !== $source) {
354 $this->setSource($source);
357 if (! $this->checkConfigSource()) {
358 return false;
361 $cfg = array();
364 * Parses the configuration file
366 $old_error_reporting = error_reporting(0);
367 if (function_exists('file_get_contents')) {
368 $eval_result =
369 eval('?>' . trim(file_get_contents($this->getSource())));
370 } else {
371 $eval_result =
372 eval('?>' . trim(implode("\n", file($this->getSource()))));
374 error_reporting($old_error_reporting);
376 if ($eval_result === false) {
377 $this->error_config_file = true;
378 } else {
379 $this->error_config_file = false;
380 $this->source_mtime = filemtime($this->getSource());
384 * @TODO check validity of $_COOKIE['pma_collation_connection']
386 if (! empty($_COOKIE['pma_collation_connection'])) {
387 $this->set('collation_connection',
388 strip_tags($_COOKIE['pma_collation_connection']));
389 } else {
390 $this->set('collation_connection',
391 $this->get('DefaultConnectionCollation'));
394 $this->checkCollationConnection();
395 //$this->checkPmaAbsoluteUri();
396 $this->settings = PMA_array_merge_recursive($this->settings, $cfg);
397 return true;
401 * set source
402 * @param string $source
404 function setSource($source)
406 $this->source = trim($source);
410 * checks if the config folder still exists and terminates app if true
412 function checkConfigFolder()
414 // Refuse to work while there still might be some world writable dir:
415 if (is_dir('./config')) {
416 die('Remove "./config" directory before using phpMyAdmin!');
421 * check config source
423 * @return boolean wether source is valid or not
425 function checkConfigSource()
427 if (! file_exists($this->getSource())) {
428 // do not trigger error here
429 // https://sf.net/tracker/?func=detail&aid=1370269&group_id=23067&atid=377408
431 trigger_error(
432 'phpMyAdmin-ERROR: unkown configuration source: ' . $source,
433 E_USER_WARNING);
435 $this->source_mtime = 0;
436 return false;
439 if (! is_readable($this->getSource())) {
440 $this->source_mtime = 0;
441 die('Existing configuration file (' . $this->getSource() . ') is not readable.');
444 // Check for permissions (on platforms that support it):
445 $perms = @fileperms($this->getSource());
446 if (!($perms === false) && ($perms & 2)) {
447 // This check is normally done after loading configuration
448 $this->checkWebServerOs();
449 if ($this->get('PMA_IS_WINDOWS') == 0) {
450 $this->source_mtime = 0;
451 die('Wrong permissions on configuration file, should not be world writable!');
455 return true;
459 * returns specific config setting
460 * @param string $setting
461 * @return mixed value
463 function get($setting)
465 if (isset($this->settings[$setting])) {
466 return $this->settings[$setting];
468 return null;
472 * sets configuration variable
474 * @uses $this->settings
475 * @param string $setting configuration option
476 * @param string $value new value for configuration option
478 function set($setting, $value)
480 $this->settings[$setting] = $value;
484 * returns source for current config
485 * @return string config source
487 function getSource()
489 return $this->source;
493 * old PHP 4 style constructor
495 * @deprecated
497 function PMA_Config($source = null)
499 $this->__construct($source);
503 * $cfg['PmaAbsoluteUri'] is a required directive else cookies won't be
504 * set properly and, depending on browsers, inserting or updating a
505 * record might fail
507 function checkPmaAbsoluteUri()
509 // Setup a default value to let the people and lazy syadmins work anyway,
510 // they'll get an error if the autodetect code doesn't work
511 $pma_absolute_uri = $this->get('PmaAbsoluteUri');
512 $is_https = $this->get('is_https');
513 if (strlen($pma_absolute_uri) < 5
514 // needed to catch http/https switch
515 || ($is_https && substr($pma_absolute_uri, 0, 6) != 'https:')
516 || (!$is_https && substr($pma_absolute_uri, 0, 5) != 'http:')
518 echo "recheck";
519 $url = array();
521 // At first we try to parse REQUEST_URI, it might contain full URL
522 if (PMA_getenv('REQUEST_URI')) {
523 $url = @parse_url(PMA_getenv('REQUEST_URI')); // produces E_WARNING if it cannot get parsed, e.g. '/foobar:/'
524 if ($url === false) {
525 $url = array( 'path' => $_SERVER['REQUEST_URI'] );
529 // If we don't have scheme, we didn't have full URL so we need to
530 // dig deeper
531 if (empty($url['scheme'])) {
532 // Scheme
533 if (PMA_getenv('HTTP_SCHEME')) {
534 $url['scheme'] = PMA_getenv('HTTP_SCHEME');
535 } else {
536 $url['scheme'] =
537 PMA_getenv('HTTPS') && strtolower(PMA_getenv('HTTPS')) != 'off'
538 ? 'https'
539 : 'http';
542 // Host and port
543 if (PMA_getenv('HTTP_HOST')) {
544 if (strpos(PMA_getenv('HTTP_HOST'), ':') !== false) {
545 list($url['host'], $url['port']) =
546 explode(':', PMA_getenv('HTTP_HOST'));
547 } else {
548 $url['host'] = PMA_getenv('HTTP_HOST');
550 } elseif (PMA_getenv('SERVER_NAME')) {
551 $url['host'] = PMA_getenv('SERVER_NAME');
552 } else {
553 $this->error_pma_uri = true;
554 return false;
557 // If we didn't set port yet...
558 if (empty($url['port']) && PMA_getenv('SERVER_PORT')) {
559 $url['port'] = PMA_getenv('SERVER_PORT');
562 // And finally the path could be already set from REQUEST_URI
563 if (empty($url['path'])) {
564 if (PMA_getenv('PATH_INFO')) {
565 $path = parse_url(PMA_getenv('PATH_INFO'));
566 } else {
567 // PHP_SELF in CGI often points to cgi executable, so use it
568 // as last choice
569 $path = parse_url(PMA_getenv('PHP_SELF'));
571 $url['path'] = $path['path'];
575 // Make url from parts we have
576 $pma_absolute_uri = $url['scheme'] . '://';
577 // Was there user information?
578 if (!empty($url['user'])) {
579 $pma_absolute_uri .= $url['user'];
580 if (!empty($url['pass'])) {
581 $pma_absolute_uri .= ':' . $url['pass'];
583 $pma_absolute_uri .= '@';
585 // Add hostname
586 $pma_absolute_uri .= $url['host'];
587 // Add port, if it not the default one
588 if (! empty($url['port'])
589 && (($url['scheme'] == 'http' && $url['port'] != 80)
590 || ($url['scheme'] == 'https' && $url['port'] != 443))) {
591 $pma_absolute_uri .= ':' . $url['port'];
593 // And finally path, without script name, the 'a' is there not to
594 // strip our directory, when path is only /pmadir/ without filename.
595 // Backslashes returned by Windows have to be changed.
596 // Only replace backslashes by forward slashes if on Windows,
597 // as the backslash could be valid on a non-Windows system.
598 if ($this->get('PMA_IS_WINDOWS') == 1) {
599 $path = str_replace("\\", "/", dirname($url['path'] . 'a'));
600 } else {
601 $path = dirname($url['path'] . 'a');
604 // To work correctly within transformations overview:
605 if (defined('PMA_PATH_TO_BASEDIR') && PMA_PATH_TO_BASEDIR == '../../') {
606 if ($this->get('PMA_IS_WINDOWS') == 1) {
607 $path = str_replace("\\", "/", dirname(dirname($path)));
608 } else {
609 $path = dirname(dirname($path));
612 // in vhost situations, there could be already an ending slash
613 if (substr($path, -1) != '/') {
614 $path .= '/';
616 $pma_absolute_uri .= $path;
618 // We used to display a warning if PmaAbsoluteUri wasn't set, but now
619 // the autodetect code works well enough that we don't display the
620 // warning at all. The user can still set PmaAbsoluteUri manually.
621 // See
622 // http://sf.net/tracker/?func=detail&aid=1257134&group_id=23067&atid=377411
624 } else {
625 // The URI is specified, however users do often specify this
626 // wrongly, so we try to fix this.
628 // Adds a trailing slash et the end of the phpMyAdmin uri if it
629 // does not exist.
630 if (substr($pma_absolute_uri, -1) != '/') {
631 $pma_absolute_uri .= '/';
634 // If URI doesn't start with http:// or https://, we will add
635 // this.
636 if (substr($pma_absolute_uri, 0, 7) != 'http://'
637 && substr($pma_absolute_uri, 0, 8) != 'https://') {
638 $pma_absolute_uri =
639 (PMA_getenv('HTTPS') && strtolower(PMA_getenv('HTTPS')) != 'off'
640 ? 'https'
641 : 'http')
642 . ':' . (substr($pma_absolute_uri, 0, 2) == '//' ? '' : '//')
643 . $pma_absolute_uri;
647 $this->set('PmaAbsoluteUri', $pma_absolute_uri);
651 * check selected collation_connection
652 * @TODO check validity of $_REQUEST['collation_connection']
654 function checkCollationConnection()
656 // (could be improved by executing it after the MySQL connection only if
657 // PMA_MYSQL_INT_VERSION >= 40100)
658 if (! empty($_REQUEST['collation_connection'])) {
659 $this->set('collation_connection',
660 strip_tags($_REQUEST['collation_connection']));
665 * checks if upload is enabled
668 function checkUpload()
670 $this->set('enable_upload', true);
671 if (strtolower(@ini_get('file_uploads')) == 'off'
672 || @ini_get('file_uploads') == 0) {
673 $this->set('enable_upload', false);
678 * Maximum upload size as limited by PHP
679 * Used with permission from Moodle (http://moodle.org) by Martin Dougiamas
681 * this section generates $max_upload_size in bytes
683 function checkUploadSize()
685 if (! $filesize = ini_get('upload_max_filesize')) {
686 $filesize = "5M";
689 if ($postsize = ini_get('post_max_size')) {
690 $this->set('max_upload_size',
691 min(get_real_size($filesize), get_real_size($postsize)));
692 } else {
693 $this->set('max_upload_size', get_real_size($filesize));
698 * check for https
700 function checkIsHttps()
702 $this->set('is_https', PMA_Config::isHttps());
706 * @static
708 function isHttps()
710 $is_https = false;
712 $url = array();
714 // At first we try to parse REQUEST_URI, it might contain full URL,
715 if (PMA_getenv('REQUEST_URI')) {
716 $url = @parse_url(PMA_getenv('REQUEST_URI')); // produces E_WARNING if it cannot get parsed, e.g. '/foobar:/'
717 if($url === false) {
718 $url = array();
722 // If we don't have scheme, we didn't have full URL so we need to
723 // dig deeper
724 if (empty($url['scheme'])) {
725 // Scheme
726 if (PMA_getenv('HTTP_SCHEME')) {
727 $url['scheme'] = PMA_getenv('HTTP_SCHEME');
728 } else {
729 $url['scheme'] =
730 PMA_getenv('HTTPS') && strtolower(PMA_getenv('HTTPS')) != 'off'
731 ? 'https'
732 : 'http';
736 if (isset($url['scheme'])
737 && $url['scheme'] == 'https') {
738 $is_https = true;
739 } else {
740 $is_https = false;
743 return $is_https;
747 * detect correct cookie path
749 function checkCookiePath()
751 $this->set('cookie_path', PMA_Config::getCookiePath());
755 * @static
757 function getCookiePath()
759 static $cookie_path = null;
761 if (null !== $cookie_path) {
762 return $cookie_path;
765 $url = '';
767 if (PMA_getenv('REQUEST_URI')) {
768 $url = PMA_getenv('REQUEST_URI');
771 // If we don't have path
772 if (empty($url)) {
773 if (PMA_getenv('PATH_INFO')) {
774 $url = PMA_getenv('PATH_INFO');
775 } elseif (PMA_getenv('PHP_SELF')) {
776 // PHP_SELF in CGI often points to cgi executable, so use it
777 // as last choice
778 $url = PMA_getenv('PHP_SELF');
779 } elseif (PMA_getenv('SCRIPT_NAME')) {
780 $url = PMA_getenv('PHP_SELF');
784 $parsed_url = @parse_url($_SERVER['REQUEST_URI']); // produces E_WARNING if it cannot get parsed, e.g. '/foobar:/'
785 if ($parsed_url === false) {
786 $parsed_url = array('path' => $url);
789 $cookie_path = substr($parsed_url['path'], 0, strrpos($parsed_url['path'], '/')) . '/';
791 return $cookie_path;
795 * enables backward compatibility
797 function enableBc()
799 $GLOBALS['cfg'] =& $this->settings;
800 $GLOBALS['default_server'] =& $this->default_server;
801 $GLOBALS['collation_connection'] = $this->get('collation_connection');
802 $GLOBALS['is_upload'] = $this->get('enable_upload');
803 $GLOBALS['max_upload_size'] = $this->get('max_upload_size');
804 $GLOBALS['cookie_path'] = $this->get('cookie_path');
805 $GLOBALS['is_https'] = $this->get('is_https');
807 $defines = array(
808 'PMA_VERSION',
809 'PMA_THEME_VERSION',
810 'PMA_THEME_GENERATION',
811 'PMA_PHP_STR_VERSION',
812 'PMA_PHP_INT_VERSION',
813 'PMA_IS_WINDOWS',
814 'PMA_IS_IIS',
815 'PMA_IS_GD2',
816 'PMA_USR_OS',
817 'PMA_USR_BROWSER_VER',
818 'PMA_USR_BROWSER_AGENT',
821 foreach ($defines as $define) {
822 if (! defined($define)) {
823 define($define, $this->get($define));
829 * @todo finish
831 function save() {}