"%{};]+'); define('WT_REGEX_PASSWORD', '.{'.WT_MINIMUM_PASSWORD_LENGTH.',}'); // UTF8 representation of various characters define('WT_UTF8_BOM', "\xEF\xBB\xBF"); // U+FEFF // UTF8 control codes affecting the BiDirectional algorithm (see http://www.unicode.org/reports/tr9/) define('WT_UTF8_LRM', "\xE2\x80\x8E"); // U+200E (Left to Right mark: zero-width character with LTR directionality) define('WT_UTF8_RLM', "\xE2\x80\x8F"); // U+200F (Right to Left mark: zero-width character with RTL directionality) define('WT_UTF8_LRO', "\xE2\x80\xAD"); // U+202D (Left to Right override: force everything following to LTR mode) define('WT_UTF8_RLO', "\xE2\x80\xAE"); // U+202E (Right to Left override: force everything following to RTL mode) define('WT_UTF8_LRE', "\xE2\x80\xAA"); // U+202A (Left to Right embedding: treat everything following as LTR text) define('WT_UTF8_RLE', "\xE2\x80\xAB"); // U+202B (Right to Left embedding: treat everything following as RTL text) define('WT_UTF8_PDF', "\xE2\x80\xAC"); // U+202C (Pop directional formatting: restore state prior to last LRO, RLO, LRE, RLE) // Alternatives to BMD events for lists, charts, etc. define('WT_EVENTS_BIRT', 'BIRT|CHR|BAPM|_BRTM|ADOP'); define('WT_EVENTS_DEAT', 'DEAT|BURI|CREM'); define('WT_EVENTS_MARR', 'MARR|_NMR'); define('WT_EVENTS_DIV', 'DIV|ANUL|_SEPR'); // Use these line endings when writing files on the server define('WT_EOL', "\r\n"); // Gedcom specification/definitions define ('WT_GEDCOM_LINE_LENGTH', 255-strlen(WT_EOL)); // Characters, not bytes // Used in Google charts define ('WT_GOOGLE_CHART_ENCODING', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.'); // Privacy constants define('WT_PRIV_PUBLIC', 2); // Allows visitors to view the marked information define('WT_PRIV_USER', 1); // Allows members to access the marked information define('WT_PRIV_NONE', 0); // Allows managers to access the marked information define('WT_PRIV_HIDE', -1); // Hide the item to all users // For performance, it is quicker to refer to files using absolute paths define ('WT_ROOT', realpath(dirname(dirname(__FILE__))).DIRECTORY_SEPARATOR); // Keep track of time statistics, for the summary in the footer $start_time=microtime(true); // We want to know about all PHP errors error_reporting(E_ALL | E_STRICT); // Invoke the Zend Framework Autoloader, so we can use Zend_XXXXX and WT_XXXXX classes set_include_path(WT_ROOT.'library'.PATH_SEPARATOR.get_include_path()); require_once 'Zend/Loader/Autoloader.php'; Zend_Loader_Autoloader::getInstance()->registerNamespace('WT_'); // PHP requires a time zone to be set in php.ini if (!ini_get('date.timezone')) { date_default_timezone_set(@date_default_timezone_get()); } // Split the request protocol://host:port/path/to/script.php?var=value into parts // WT_SERVER_NAME = protocol://host:port // WT_SCRIPT_PATH = /path/to/ (begins and ends with /) // WT_SCRIPT_NAME = script.php (already defined in the calling script) // WT_QUERY_STRING = ?var=value (generate as needed from $_GET. lang=xx and theme=yy are removed as used.) // TODO: we ought to generate this dynamically, but lots of code currently relies on this global $QUERY_STRING=isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''; define('WT_SERVER_NAME', (empty($_SERVER['HTTPS']) || !in_array($_SERVER['HTTPS'], array('1', 'on', 'On', 'ON')) ? 'http://' : 'https://'). (empty($_SERVER['SERVER_NAME']) ? '' : $_SERVER['SERVER_NAME']). (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT']==80 ? '' : ':'.$_SERVER['SERVER_PORT']) ); // SCRIPT_NAME should always be correct, but is not always present. // PHP_SELF should always be present, but may have trailing path: /path/to/script.php/FOO/BAR if (!empty($_SERVER['SCRIPT_NAME'])) { define('WT_SCRIPT_PATH', substr($_SERVER['SCRIPT_NAME'], 0, stripos($_SERVER['SCRIPT_NAME'], WT_SCRIPT_NAME))); } elseif (!empty($_SERVER['PHP_SELF'])) { define('WT_SCRIPT_PATH', substr($_SERVER['PHP_SELF'], 0, stripos($_SERVER['PHP_SELF'], WT_SCRIPT_NAME))); } else { // No server settings - probably running as a command line script define('WT_SCRIPT_PATH', '/'); } // Microsoft IIS servers don’t set REQUEST_URI, so generate it for them. if (!isset($_SERVER['REQUEST_URI'])) { $_SERVER['REQUEST_URI']=substr($_SERVER['PHP_SELF'], 1); if (isset($_SERVER['QUERY_STRING'])) { $_SERVER['REQUEST_URI'].='?'.$_SERVER['QUERY_STRING']; } } // Common functions require WT_ROOT.'includes/functions/functions.php'; require WT_ROOT.'includes/functions/functions_db.php'; // TODO: Not all pages require all of these. Only load them in scripts that need them? require WT_ROOT.'includes/functions/functions_print.php'; require WT_ROOT.'includes/functions/functions_rtl.php'; require WT_ROOT.'includes/functions/functions_mediadb.php'; require WT_ROOT.'includes/functions/functions_date.php'; require WT_ROOT.'includes/functions/functions_charts.php'; require WT_ROOT.'includes/functions/functions_utf-8.php'; set_error_handler('wt_error_handler'); // Load our configuration file, so we can connect to the database if (file_exists(WT_ROOT.'data/config.ini.php')) { $dbconfig=parse_ini_file(WT_ROOT.'data/config.ini.php'); // Invalid/unreadable config file? if (!is_array($dbconfig)) { header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.'site-unavailable.php'); exit; } // Down for maintenance? if (file_exists(WT_ROOT.'data/offline.txt')) { header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.'site-offline.php'); exit; } } else { // No config file. Set one up. header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.'setup.php'); exit; } $WT_REQUEST=new Zend_Controller_Request_Http(); require WT_ROOT.'includes/authentication.php'; // Connect to the database try { WT_DB::createInstance($dbconfig['dbhost'], $dbconfig['dbport'], $dbconfig['dbname'], $dbconfig['dbuser'], $dbconfig['dbpass']); define('WT_TBLPREFIX', $dbconfig['tblpfx']); unset($dbconfig); // Some of the FAMILY JOIN HUSBAND JOIN WIFE queries can excede the MAX_JOIN_SIZE setting WT_DB::exec("SET NAMES 'utf8' COLLATE 'utf8_unicode_ci', SQL_BIG_SELECTS=1"); try { WT_DB::updateSchema(WT_ROOT.'includes/db_schema/', 'WT_SCHEMA_VERSION', WT_SCHEMA_VERSION); } catch (PDOException $ex) { // The schema update scripts should never fail. If they do, there is no clean recovery. die($ex); } } catch (PDOException $ex) { header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.'site-unavailable.php'); exit; } // The config.ini.php file must always be in a fixed location. // Other user files can be stored elsewhere... define('WT_DATA_DIR', realpath(WT_Site::preference('INDEX_DIRECTORY') ? WT_Site::preference('INDEX_DIRECTORY') : 'data').DIRECTORY_SEPARATOR); // If we have a preferred URL (e.g. www.example.com instead of www.isp.com/~example), then redirect to it. $SERVER_URL=WT_Site::preference('SERVER_URL'); if ($SERVER_URL && $SERVER_URL != WT_SERVER_NAME.WT_SCRIPT_PATH) { header('Location: '.$SERVER_URL.WT_SCRIPT_NAME.($QUERY_STRING ? '?'.$QUERY_STRING : ''), true, 301); exit; } // Request more resources - if we can/want to if (!ini_get('safe_mode')) { $memory_limit=WT_Site::preference('MEMORY_LIMIT'); if ($memory_limit) { ini_set('memory_limit', $memory_limit); } $max_execution_time=WT_Site::preference('MAX_EXECUTION_TIME'); if ($max_execution_time && strpos(ini_get('disable_functions'), 'set_time_limit')===false) { set_time_limit($max_execution_time); } } // Determine browser type if (!isset($_SERVER['HTTP_USER_AGENT'])) { $_SERVER['HTTP_USER_AGENT']=''; } // TODO: Browser sniffing is bad. We should use capability detection. if (stristr($_SERVER['HTTP_USER_AGENT'], 'Opera')) { $BROWSERTYPE = 'opera'; } elseif (stristr($_SERVER['HTTP_USER_AGENT'], 'KHTML')) { $BROWSERTYPE = 'chrome'; } elseif (stristr($_SERVER['HTTP_USER_AGENT'], 'Gecko')) { $BROWSERTYPE = 'mozilla'; } elseif (stristr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) { $BROWSERTYPE = 'msie'; } else { $BROWSERTYPE = 'other'; } $rule=WT_DB::prepare( "SELECT SQL_CACHE rule FROM `##site_access_rule`". " WHERE IFNULL(INET_ATON(?), 0) BETWEEN ip_address_start AND ip_address_end". " AND ? LIKE user_agent_pattern". " ORDER BY ip_address_end-ip_address_start" )->execute(array($WT_REQUEST->getClientIp(), $_SERVER['HTTP_USER_AGENT']))->fetchOne(); switch ($rule) { case 'allow': $SEARCH_SPIDER=false; break; case 'deny': header('HTTP/1.1 403 Access Denied'); exit; case 'robot': case 'unknown': // Search engines don’t send cookies, and so create a new session with every visit. // Make sure they always use the same one Zend_Session::setId('search-engine-'.str_replace('.', '-', $WT_REQUEST->getClientIp())); $SEARCH_SPIDER=true; break; case '': WT_DB::prepare( "INSERT INTO `##site_access_rule` (ip_address_start, ip_address_end, user_agent_pattern, comment) VALUES (IFNULL(INET_ATON(?), 0), IFNULL(INET_ATON(?), 4294967295), ?, '')" )->execute(array($WT_REQUEST->getClientIp(), $WT_REQUEST->getClientIp(), $_SERVER['HTTP_USER_AGENT'])); $SEARCH_SPIDER=true; break; } // Store our session data in the database. // Only update the session table once per minute, unless the session data has actually changed. session_set_save_handler( create_function('', 'return true;'), // open create_function('', 'return true;'), // close create_function('$id', 'return WT_DB::prepare("SELECT session_data FROM `##session` WHERE session_id=?")->execute(array($id))->fetchOne();'), // read create_function('$id,$data', 'global $WT_REQUEST;WT_DB::prepare("INSERT INTO `##session` (session_id, user_id, ip_address, session_data, session_time) VALUES (?,?,?,?,CURRENT_TIMESTAMP-SECOND(CURRENT_TIMESTAMP)) ON DUPLICATE KEY UPDATE user_id=VALUES(user_id), ip_address=VALUES(ip_address), session_data=VALUES(session_data), session_time=CURRENT_TIMESTAMP-SECOND(CURRENT_TIMESTAMP)")->execute(array($id, WT_USER_ID, $WT_REQUEST->getClientIp(), $data));return true;'), // write create_function('$id', 'WT_DB::prepare("DELETE FROM `##session` WHERE session_id=?")->execute(array($id));return true;'), // destroy create_function('$maxlifetime', 'WT_DB::prepare("DELETE FROM `##session` WHERE session_time < DATE_SUB(NOW(), INTERVAL ? SECOND)")->execute(array($maxlifetime));return true;') // gc ); // Use the Zend_Session object to start the session. // This allows all the other Zend Framework components to integrate with the session define('WT_SESSION_NAME', 'WT_SESSION'); $cfg=array( 'name' => WT_SESSION_NAME, 'cookie_lifetime' => 0, 'gc_maxlifetime' => WT_Site::preference('SESSION_TIME'), 'gc_probability' => 1, 'gc_divisor' => 100, 'cookie_path' => WT_SCRIPT_PATH, 'cookie_httponly' => true, ); // Search engines don’t send cookies, and so create a new session with every visit. // Make sure they always use the same one if ($SEARCH_SPIDER) { Zend_Session::setId('search-engine-'.str_replace('.', '-', $WT_REQUEST->getClientIp())); } Zend_Session::start($cfg); // Register a session “namespace” to store session data. This is better than // using $_SESSION, as we can avoid clashes with other modules or applications, // and problems with servers that have enabled “register_globals”. $WT_SESSION=new Zend_Session_Namespace('WEBTREES'); if (!$SEARCH_SPIDER && !$WT_SESSION->initiated) { // A new session, so prevent session fixation attacks by choosing a new PHPSESSID. Zend_Session::regenerateId(); $WT_SESSION->initiated=true; } else { // An existing session } // Who are we? define('WT_USER_ID', getUserId()); define('WT_USER_NAME', getUserName()); define('WT_USER_IS_ADMIN', userIsAdmin(WT_USER_ID)); // Set the active GEDCOM if (isset($_REQUEST['ged'])) { // .... from the URL or form action $GEDCOM=$_REQUEST['ged']; } elseif ($WT_SESSION->GEDCOM) { // .... the most recently used one $GEDCOM=$WT_SESSION->GEDCOM; } else { // Try the site default $GEDCOM=WT_Site::preference('DEFAULT_GEDCOM'); } // Choose the selected tree (if it exists), or any valid tree otherwise $WT_TREE=null; foreach (WT_Tree::getAll() as $tree) { $WT_TREE=$tree; if ($WT_TREE->tree_name == $GEDCOM && ($WT_TREE->imported || WT_USER_IS_ADMIN)) { break; } } // These attributes of the currently-selected tree are used frequently if ($WT_TREE) { define('WT_GEDCOM', $WT_TREE->tree_name); define('WT_GED_ID', $WT_TREE->tree_id); define('WT_GEDURL', $WT_TREE->tree_name_url); define('WT_TREE_TITLE', $WT_TREE->tree_title_html); define('WT_IMPORTED', $WT_TREE->imported); define('WT_USER_GEDCOM_ADMIN', WT_USER_IS_ADMIN || userGedcomAdmin(WT_USER_ID, WT_GED_ID)); define('WT_USER_CAN_ACCEPT', $WT_TREE->canAcceptChanges(WT_USER_ID)); define('WT_USER_CAN_EDIT', WT_USER_CAN_ACCEPT || userCanEdit (WT_USER_ID, WT_GED_ID)); define('WT_USER_CAN_ACCESS', WT_USER_CAN_EDIT || userCanAccess (WT_USER_ID, WT_GED_ID)); define('WT_USER_GEDCOM_ID', $WT_TREE->userPreference(WT_USER_ID, 'gedcomid')); define('WT_USER_ROOT_ID', $WT_TREE->userPreference(WT_USER_ID, 'rootid') ? $WT_TREE->userPreference(WT_USER_ID, 'rootid') : WT_USER_GEDCOM_ID); define('WT_USER_PATH_LENGTH', $WT_TREE->userPreference(WT_USER_ID, 'RELATIONSHIP_PATH_LENGTH')); if (WT_USER_GEDCOM_ADMIN) { define('WT_USER_ACCESS_LEVEL', WT_PRIV_NONE); } elseif (WT_USER_CAN_ACCESS) { define('WT_USER_ACCESS_LEVEL', WT_PRIV_USER); } else { define('WT_USER_ACCESS_LEVEL', WT_PRIV_PUBLIC); } load_gedcom_settings(WT_GED_ID); } else { define('WT_GEDCOM', ''); define('WT_GED_ID', null); define('WT_GEDURL', ''); define('WT_TREE_TITLE', WT_WEBTREES); define('WT_IMPORTED', false); define('WT_USER_GEDCOM_ADMIN', false); define('WT_USER_CAN_ACCEPT', false); define('WT_USER_CAN_EDIT', false); define('WT_USER_CAN_ACCESS', false); define('WT_USER_GEDCOM_ID', ''); define('WT_USER_ROOT_ID', ''); define('WT_USER_PATH_LENGTH', 0); define('WT_USER_ACCESS_LEVEL', WT_PRIV_PUBLIC); } $GEDCOM=WT_GEDCOM; // With no parameters, init() looks to the environment to choose a language define('WT_LOCALE', WT_I18N::init()); $WT_SESSION->locale=WT_I18N::$locale; // Non-latin languages may need non-latin digits define('WT_NUMBERING_SYSTEM', Zend_Locale_Data::getContent(WT_LOCALE, 'defaultnumberingsystem')); // Set our gedcom selection as a default for the next page $WT_SESSION->GEDCOM=WT_GEDCOM; if (empty($WEBTREES_EMAIL)) { $WEBTREES_EMAIL='webtrees-noreply@'.preg_replace('/^www\./i', '', $_SERVER['SERVER_NAME']); } // Note that the database/webservers may not be synchronised, so use DB time throughout. define('WT_TIMESTAMP', (int)WT_DB::prepare("SELECT UNIX_TIMESTAMP()")->fetchOne()); // Server timezone is defined in php.ini define('WT_SERVER_TIMESTAMP', WT_TIMESTAMP + (int)date('Z')); if (WT_USER_ID) { define('WT_CLIENT_TIMESTAMP', WT_TIMESTAMP - $WT_SESSION->timediff); } else { define('WT_CLIENT_TIMESTAMP', WT_SERVER_TIMESTAMP); } define('WT_CLIENT_JD', 2440588 + (int)(WT_CLIENT_TIMESTAMP/86400)); // Application configuration data - things that aren’t (yet?) user-editable require WT_ROOT.'includes/config_data.php'; // If we are logged in, and logout=1 has been added to the URL, log out // If we were logged in, but our account has been deleted, log out. if (WT_USER_ID && (WT_Filter::getBool('logout') || !WT_USER_NAME)) { userLogout(WT_USER_ID); header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH); exit; } // The login URL must be an absolute URL, and can be user-defined if (WT_Site::preference('LOGIN_URL')) { define('WT_LOGIN_URL', WT_Site::preference('LOGIN_URL')); } else { define('WT_LOGIN_URL', WT_SERVER_NAME.WT_SCRIPT_PATH.'login.php'); } // If there is no current tree and we need one, then redirect somewhere if (WT_SCRIPT_NAME!='admin_trees_manage.php' && WT_SCRIPT_NAME!='admin_pgv_to_wt.php' && WT_SCRIPT_NAME!='login.php' && WT_SCRIPT_NAME!='import.php' && WT_SCRIPT_NAME!='help_text.php' && WT_SCRIPT_NAME!='message.php') { if (!$WT_TREE || !WT_IMPORTED) { if (WT_USER_IS_ADMIN) { header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.'admin_trees_manage.php'); } else { header('Location: '.WT_LOGIN_URL.'?url='.rawurlencode(WT_SCRIPT_NAME.'?'.$QUERY_STRING)); } exit; } } if (WT_USER_ID) { //-- update the login time every 5 minutes if (WT_TIMESTAMP-$WT_SESSION->activity_time > 300) { set_user_setting(WT_USER_ID, 'sessiontime', WT_TIMESTAMP); $WT_SESSION->activity_time = WT_TIMESTAMP; } } // Set the theme if (substr(WT_SCRIPT_NAME, 0, 5)=='admin' || WT_SCRIPT_NAME=='module.php' && substr(WT_Filter::get('mod_action'), 0, 5)=='admin') { // Administration scripts begin with “admin” and use a special administration theme define('WT_THEME_DIR', WT_THEMES_DIR.'_administration/'); } else { if (WT_Site::preference('ALLOW_USER_THEMES')) { // Requested change of theme? $THEME_DIR = WT_Filter::get('theme'); unset($_GET['theme']); // Last theme used? if (!$THEME_DIR && in_array($WT_SESSION->theme_dir, get_theme_names())) { $THEME_DIR=$WT_SESSION->theme_dir; } } else { $THEME_DIR=''; } if (!$THEME_DIR) { // User cannot choose (or has not chosen) a theme. // 1) gedcom setting // 2) site setting // 3) webtrees // 4) first one found if (WT_GED_ID) { $THEME_DIR=get_gedcom_setting(WT_GED_ID, 'THEME_DIR'); } if (!in_array($THEME_DIR, get_theme_names())) { $THEME_DIR=WT_Site::preference('THEME_DIR'); } if (!in_array($THEME_DIR, get_theme_names())) { $THEME_DIR='webtrees'; } if (!in_array($THEME_DIR, get_theme_names())) { list($THEME_DIR)=get_theme_names(); } } define('WT_THEME_DIR', WT_THEMES_DIR.$THEME_DIR.'/'); // Remember this setting if (WT_THEME_DIR!=WT_THEMES_DIR.'_administration/') { $WT_SESSION->theme_dir=$THEME_DIR; } } // If we have specified a CDN, use it for static theme resources define('WT_THEME_URL', WT_STATIC_URL.WT_THEME_DIR); require WT_ROOT.WT_THEME_DIR.'theme.php'; // Page hit counter - load after theme, as we need theme formatting if ($WT_TREE && $WT_TREE->preference('SHOW_COUNTER') && !$SEARCH_SPIDER) { require WT_ROOT.'includes/hitcount.php'; } else { $hitCount=''; } // define constants to be used when setting permissions after creating files/directories if (substr(PHP_SAPI, 0, 3) == 'cgi') { // cgi-mode, should only be writable by owner define('WT_PERM_EXE', 0755); // to be used on directories, php files, etc. define('WT_PERM_FILE', 0644); // to be used on images, text files, etc. } else { // mod_php mode, should be writable by everyone define('WT_PERM_EXE', 0777); define('WT_PERM_FILE', 0666); } // Lightbox needs custom integration in many places. Only check for the module once. define('WT_USE_LIGHTBOX', !$SEARCH_SPIDER && array_key_exists('lightbox', WT_Module::getActiveModules())); // Search engines are only allowed to see certain pages. if ($SEARCH_SPIDER && !in_array(WT_SCRIPT_NAME , array( 'index.php', 'indilist.php', 'module.php', 'mediafirewall.php', 'individual.php', 'family.php', 'mediaviewer.php', 'note.php', 'repo.php', 'source.php', ))) { header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden'); $controller=new WT_Controller_Page(); $controller->setPageTitle(WT_I18N::translate('Search engine')); $controller->pageHeader(); echo '
', WT_I18N::translate('You do not have permission to view this page.'), '
'; exit; }