1<?php
2/**
3 * Coppermine Photo Gallery
4 *
5 * v1.0 originally written by Gregory Demar
6 *
7 * @copyright  Copyright (c) 2003-2021 Coppermine Dev Team
8 * @license    GNU General Public License version 3 or later; see LICENSE
9 *
10 * include/init.inc.php
11 * @since  1.6.12
12 */
13
14define('COPPERMINE_VERSION', '1.6.12');
15define('COPPERMINE_VERSION_STATUS', 'stable');
16// Define path to jQuery for this version of Coppermine
17define('CPG_JQUERY_VERSION', 'js/jquery-1.12.4.js');
18define('CPG_JQUERY_MIGRATE', 'js/jquery-migrate-1.4.1.js');
19
20if (!defined('IN_COPPERMINE')) die('Not in Coppermine...');
21
22function cpgGetMicroTime()
23{
24    list($usec, $sec) = explode(' ', microtime());
25    return ((float)$usec + (float)$sec);
26}
27$cpg_time_start = cpgGetMicroTime();
28
29// Set a flag if register globals is on to show a warning to admin
30if (ini_get('register_globals') == '1' || strtolower(ini_get('register_globals')) == 'on') {
31    $register_globals_flag = true;
32} else {
33    $register_globals_flag = false;
34}
35
36require_once('include/inspekt.php');
37
38// Set $strict to false to make the superglobals available
39$strict = TRUE;
40
41$superCage = Inspekt::makeSuperCage($strict);
42// Remove any variables introduced by register_globals, if enabled
43$keysToSkip = array('keysToSkip', 'register_globals_flag', 'superCage', 'cpg_time_start', 'key');
44
45if ($register_globals_flag && is_array($GLOBALS)) {
46    foreach ($GLOBALS as $key => $value) {
47        if (!in_array($key, $keysToSkip) && isset($$key)) {
48            unset($$key);
49        }
50    }
51}
52
53// List of valid meta albums - needed for displaying 'no image to display' message
54$valid_meta_albums = array('lastcom', 'lastcomby', 'lastup', 'lastupby', 'topn', 'toprated', 'lasthits', 'random', 'search', 'lastalb', 'favpics', 'datebrowse');
55
56// HTML tags replace pairs (used at some places for input validation)
57$HTML_SUBST = array('&' => '&amp;', '"' => '&quot;', '<' => '&lt;', '>' => '&gt;', '%26' => '&amp;', '%22' => '&quot;', '%3C' => '&lt;', '%3E' => '&gt;','%27' => '&#39;', "'" => '&#39;');
58
59// Store all reported errors in the $cpgdebugger
60require_once('include/debugger.inc.php');
61
62// used for timing purposes
63$query_stats = array();
64$queries     = array();
65
66// Initialise the $CONFIG array and some other variables
67$CONFIG = array();
68
69$PHP_SELF = '';
70
71$possibilities = array(
72    'REDIRECT_URL',
73    'PHP_SELF',
74    'SCRIPT_URL',
75    'SCRIPT_NAME',
76    'SCRIPT_FILENAME'
77);
78
79foreach ($possibilities as $test) {
80    if ( ($matches = $superCage->server->getMatched($test, '/([^\/]+\.php)$/')) ) {
81        $CPG_PHP_SELF = $matches[1];
82        break;
83    }
84}
85/**
86 * TODO: $REFERER has a potential for exploitation as the QUERY_STRING is being fetched with getRaw()
87 * A probable solution is to parse the query string into its individual key and values and check
88 * them against a regex, recombine and use only if all the values are safe else set referer to index.php
89 */
90$REFERER            = urlencode($CPG_PHP_SELF . (($superCage->server->keyExists('QUERY_STRING') && $superCage->server->getRaw('QUERY_STRING')) ? '?' . $superCage->server->getRaw('QUERY_STRING') : ''));
91$ALBUM_SET          = '';
92$META_ALBUM_SET     = '';
93$FORBIDDEN_SET      = '';
94$FORBIDDEN_SET_DATA = array();
95$CURRENT_CAT_NAME   = '';
96$CAT_LIST           = '';
97$LINEBREAK          = "\r\n"; // For compatibility both on Windows as well as *nix
98
99// Define some constants
100define('USER_GAL_CAT', 1);
101define('FIRST_USER_CAT', 10000);
102define('TEMPLATE_FILE', 'template.html');
103// Constants used by the cpg_die function
104define('INFORMATION', 1);
105define('ERROR', 2);
106define('CRITICAL_ERROR', 3);
107
108// Include config and functions files
109if (file_exists('include/config.inc.php')) {
110    ob_start();
111    require_once 'include/config.inc.php';
112    ob_clean();
113} else {
114    // error handling: if the config file doesn't exist go to install
115    die('<html>
116    <head>
117      <title>Coppermine not installed yet</title>
118      <meta http-equiv="refresh" content="10;url=install.php" />
119      <style type="text/css">
120      <!--
121      body { font-size: 12px; background: #FFFFFF; margin: 20%; color: black; font-family: verdana, arial, helvetica, sans-serif;}
122      -->
123      </style>
124    </head>
125    <body>
126      <img src="images/coppermine-logo.png" alt="Coppermine Photo Gallery - Your Online Photo Gallery" /><br />
127      Coppermine Photo Gallery seems not to be installed correctly, or you are running coppermine for the first time. You\'ll be redirected to the installer. If your browser doesn\'t support redirect, click <a href="install.php">here</a>.
128    </body>
129</html>');
130}
131
132$mb_utf8_regex = '[\xE1-\xEF][\x80-\xBF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xC2-\xDF][\x80-\xBF]';
133
134require 'include/functions.inc.php';
135
136// Include logger functions
137include_once('include/logger.inc.php');
138
139// see http://php.net/mbstring for details
140if (function_exists('mb_internal_encoding')) {
141    mb_internal_encoding('UTF-8');
142}
143
144$CONFIG['TABLE_PICTURES']      = $CONFIG['TABLE_PREFIX'].'pictures';
145$CONFIG['TABLE_ALBUMS']        = $CONFIG['TABLE_PREFIX'].'albums';
146$CONFIG['TABLE_COMMENTS']      = $CONFIG['TABLE_PREFIX'].'comments';
147$CONFIG['TABLE_CATEGORIES']    = $CONFIG['TABLE_PREFIX'].'categories';
148$CONFIG['TABLE_CONFIG']        = $CONFIG['TABLE_PREFIX'].'config';
149$CONFIG['TABLE_USERGROUPS']    = $CONFIG['TABLE_PREFIX'].'usergroups';
150$CONFIG['TABLE_VOTES']         = $CONFIG['TABLE_PREFIX'].'votes';
151$CONFIG['TABLE_USERS']         = $CONFIG['TABLE_PREFIX'].'users';
152$CONFIG['TABLE_BANNED']        = $CONFIG['TABLE_PREFIX'].'banned';
153$CONFIG['TABLE_EXIF']          = $CONFIG['TABLE_PREFIX'].'exif';
154$CONFIG['TABLE_FILETYPES']     = $CONFIG['TABLE_PREFIX'].'filetypes';
155$CONFIG['TABLE_ECARDS']        = $CONFIG['TABLE_PREFIX'].'ecards';
156$CONFIG['TABLE_FAVPICS']       = $CONFIG['TABLE_PREFIX'].'favpics';
157$CONFIG['TABLE_BRIDGE']        = $CONFIG['TABLE_PREFIX'].'bridge';
158$CONFIG['TABLE_VOTE_STATS']    = $CONFIG['TABLE_PREFIX'].'vote_stats';
159$CONFIG['TABLE_HIT_STATS']     = $CONFIG['TABLE_PREFIX'].'hit_stats';
160$CONFIG['TABLE_TEMP_MESSAGES'] = $CONFIG['TABLE_PREFIX'].'temp_messages';
161$CONFIG['TABLE_CATMAP']        = $CONFIG['TABLE_PREFIX'].'categorymap';
162$CONFIG['TABLE_LANGUAGE']      = $CONFIG['TABLE_PREFIX'].'languages';
163$CONFIG['TABLE_DICT']          = $CONFIG['TABLE_PREFIX'].'dict';
164
165// Connect to database
166list($db_ext, $db_sub) = explode(':', $CONFIG['dbtype'].':');
167$db_ext = $db_ext ?: 'mysqli';
168require 'include/database/'.$db_ext.'/dbase.inc.php';
169$CPGDB = new CPG_Dbase($CONFIG);
170
171if (!$CPGDB->isConnected()) {
172    log_write("Unable to connect to database: " . $CPGDB->getError(), CPG_DATABASE_LOG);
173    die('<strong>Coppermine critical error</strong>:<br />Unable to connect to database !<br /><br />'.$CPGDB->db_type.' said: <strong>' . $CPGDB->getError() . '</strong>');
174}
175
176// Retrieve DB stored configuration
177$result = cpg_db_query("SELECT name, value FROM {$CONFIG['TABLE_CONFIG']}");
178if (!$result) cpg_db_error('When read CONFIG from database ');
179while ( ($row = $result->fetchAssoc()) ) {
180    $CONFIG[$row['name']] = $row['value'];
181} // while
182$result->free();
183
184// Check if Coppermine is allowed to store cookies (cookie consent is required and user has agreed to store cookies)
185define('CPG_COOKIES_ALLOWED', ($CONFIG['cookies_need_consent'] && !$superCage->cookie->keyExists($CONFIG['cookie_name'].'_cookies_allowed') ? false : true));
186
187// A space cannot be stored in the config table since the value field is VARCHAR, so %20 is used instead.
188if ($CONFIG['keyword_separator'] == '%20') {
189    $CONFIG['keyword_separator'] = ' ';
190}
191
192if ($CONFIG['log_mode']) {
193    spring_cleaning('logs', (!empty($CONFIG['log_retention']) ? $CONFIG['log_retention'] : CPG_DAY * 2));
194}
195
196// Record User's IP address
197$raw_ip = $superCage->server->testIp('REMOTE_ADDR') ? $superCage->server->getEscaped('REMOTE_ADDR') : '0.0.0.0';
198
199if ($superCage->server->testIp('HTTP_CLIENT_IP')) {
200    $hdr_ip = $superCage->server->getEscaped('HTTP_CLIENT_IP');
201} else {
202    if ($superCage->server->testIp('HTTP_X_FORWARDED_FOR')) {
203        $hdr_ip = $superCage->server->getEscaped('X_FORWARDED_FOR');
204    } else {
205        $hdr_ip = $raw_ip;
206    }
207}
208
209// Reference 'site_url' to 'ecards_more_pic_target'
210$CONFIG['site_url'] =& $CONFIG['ecards_more_pic_target'];
211
212// Set the site_url in js_vars so that it can be used in js
213set_js_var('site_url', rtrim($CONFIG['site_url'], '/'));
214
215// Set a constant for the default language and theme (in the gallery config), since it might get replaced during runtime
216define('DEFAULT_LANGUAGE', $CONFIG['lang']);
217define('DEFAULT_THEME', $CONFIG['theme']);
218
219// Check for GD GIF Create support
220if ($CONFIG['thumb_method'] == 'im' || $CONFIG['thumb_method'] == 'imx' || function_exists('imagecreatefromgif')) {
221    $CONFIG['GIF_support'] = 1;
222} else {
223    $CONFIG['GIF_support'] = 0;
224}
225
226// Include plugin API
227require('include/plugin_api.inc.php');
228if ($CONFIG['enable_plugins'] == 1) {
229    CPGPluginAPI::load();
230}
231
232// Set UDB_INTEGRATION if enabled in admin
233if ($CONFIG['bridge_enable'] == 1 && !defined('BRIDGEMGR_PHP')) {
234    $BRIDGE = cpg_get_bridge_db_values();
235} else {
236    $BRIDGE['short_name']              = 'coppermine';
237    $BRIDGE['recovery_logon_failures'] = 0;
238    $BRIDGE['use_post_based_groups']   = false;
239}
240
241define('UDB_INTEGRATION', $BRIDGE['short_name']);
242
243require_once 'bridge/' . UDB_INTEGRATION . '.inc.php';
244
245// Start output buffering
246ob_start('cpg_filter_page_html');
247
248// Parse cookie stored user profile
249user_get_profile();
250
251// Authenticate
252$cpg_udb->authenticate();
253
254// Test if admin mode
255$USER['am'] = isset($USER['am']) ? (int)$USER['am'] : 0;
256define('GALLERY_ADMIN_MODE', USER_IS_ADMIN && $USER['am']);
257define('USER_ADMIN_MODE', USER_ID && USER_CAN_CREATE_ALBUMS && !GALLERY_ADMIN_MODE);
258
259// Set error logging level
260// Maze's new error report system
261if (!USER_IS_ADMIN) {
262    if (!$CONFIG['debug_mode']) {
263        $cpgdebugger->stop(); // useless to run debugger because there's no output
264    }
265    error_reporting(0); // hide all errors for visitors
266}
267
268$USER_DATA['allowed_albums'] = array();
269
270if (!GALLERY_ADMIN_MODE) {
271    $result = cpg_db_query("SELECT aid FROM {$CONFIG['TABLE_ALBUMS']} WHERE moderator_group IN ".USER_GROUP_SET);
272    if ($result->numRows()) {
273        while ( ($row = $result->fetchAssoc()) ) {
274            $USER_DATA['allowed_albums'][] = $row['aid'];
275        }
276    }
277    $result->free();
278}
279
280// Set the debug flag to be used in js var
281if ($CONFIG['debug_mode'] == 1 || ($CONFIG['debug_mode'] == 2 && GALLERY_ADMIN_MODE)) {
282    set_js_var('debug', true);
283} else {
284    set_js_var('debug', false);
285}
286
287// ********************************************************
288// * Theme processing - start
289// ********************************************************
290
291$CONFIG['theme_config'] = DEFAULT_THEME;        // Save the gallery-configured setting
292
293if ($matches = $superCage->get->getMatched('theme', '/^[A-Za-z0-9_-]+$/')) {
294    $USER['theme'] = $matches[0];
295    $hasURLtheme = true;
296}
297if (isset($USER['theme']) && !strstr($USER['theme'], '/') && is_dir('themes/' . $USER['theme'])) {
298    $CONFIG['theme'] = strtr($USER['theme'], '$/\\:*?"\'<>|`', '____________');
299} else {
300    unset($USER['theme']);
301}
302// If no URL override, give plugins the chance to specify a theme
303if (empty($hasURLtheme))
304	$CONFIG['theme'] = CPGPluginAPI::filter('theme_name', $CONFIG['theme']);
305if (!file_exists('themes/'.$CONFIG['theme'].'/theme.php')) {
306    $CONFIG['theme'] = 'curve';
307}
308$THEME_DIR = 'themes/'.$CONFIG['theme'].'/';
309require('themes/'.$CONFIG['theme'].'/theme.php');   // Load configured theme first
310require('include/themes.inc.php');                  // All Fallback Theme Templates and Functions
311
312// ********************************************************
313// * Theme processing - end
314// ********************************************************
315
316if (defined('THEME_HAS_MENU_ICONS')) {
317    $ICON_DIR = $THEME_DIR . 'images/icons/';
318} else {
319    $ICON_DIR = 'images/icons/';
320}
321
322set_js_var('icon_dir', $ICON_DIR);
323
324// ********************************************************
325// * Language processing --- start
326// ********************************************************
327
328require('lang/english.php');                    // Load the default language file: 'english.php'
329$CONFIG['lang_config'] = DEFAULT_LANGUAGE;      // Save the gallery-configured setting
330$CONFIG['default_lang'] = $CONFIG['lang'];      // Save default language
331
332$enabled_languages_array = array();
333
334$result = cpg_db_query("SELECT lang_id FROM {$CONFIG['TABLE_LANGUAGE']} WHERE enabled='YES'");
335while ($row = $result->fetchAssoc()) {
336    $enabled_languages_array[] = $row['lang_id'];
337}
338$result->free();
339
340// Process language selection if present in URI or in user profile or try
341// autodetection if default charset is utf-8
342if ($matches = $superCage->get->getMatched('lang', '/^[a-z0-9_-]+$/')) {
343    $USER['lang'] = $matches[0];
344}
345
346// Set the user preference to the language submit by URL parameter or by auto-detection
347// Only set the preference if a corresponding file language file exists.
348if (isset($USER['lang']) && !strstr($USER['lang'], '/') && file_exists('lang/' . $USER['lang'] . '.php')) {
349    $CONFIG['lang'] = strtr($USER['lang'], '$/\\:*?"\'<>|`', '____________');
350} elseif ($CONFIG['charset'] == 'utf-8' && $CONFIG['language_autodetect'] != 0) {
351    include('include/select_lang.inc.php');
352    if (file_exists('lang/' . $USER['lang'] . '.php') == TRUE) {
353        if (in_array($USER['lang'], $enabled_languages_array)) {
354            $CONFIG['lang'] = $USER['lang'];
355        }
356    }
357} else {
358    unset($USER['lang']);
359}
360
361if (!file_exists("lang/{$CONFIG['lang']}.php")) {
362    $CONFIG['lang'] = 'english';
363}
364
365// We finally load the chosen language file if it differs from English
366if ($CONFIG['lang'] != 'english') {
367    require('lang/' . $CONFIG['lang'] . '.php');
368}
369set_js_var('lang_close', $lang_common['close']);
370if (defined('THEME_HAS_MENU_ICONS')) {
371    set_js_var('icon_close_path', $THEME_DIR . 'images/icons/close.png');
372} else {
373    set_js_var('icon_close_path', 'images/icons/close.png');
374}
375
376// ********************************************************
377// * Language processing --- end
378// ********************************************************
379
380// See if the fav cookie is set; else set it
381if ($superCage->cookie->keyExists($CONFIG['cookie_name'] . '_fav')) {
382    $FAVPICS = @unserialize(@base64_decode($superCage->cookie->getRaw($CONFIG['cookie_name'] . '_fav')));
383    foreach ($FAVPICS as $key => $id ) {
384        $FAVPICS[$key] = (int)$id; //protect against sql injection attacks
385    }
386} else {
387    $FAVPICS = array();
388}
389
390// If the person is logged in get favs from DB those in the DB have precedence
391if (USER_ID > 0) {
392    $result = cpg_db_query("SELECT user_favpics FROM {$CONFIG['TABLE_FAVPICS']} WHERE user_id = ".USER_ID);
393
394    $row = $result->fetchAssoc(true);
395    if (!empty($row['user_favpics'])) {
396        $FAVPICS = @unserialize(@base64_decode($row['user_favpics']));
397    } else {
398        $FAVPICS = array();
399    }
400}
401
402// Include the jquery javascript library. Jquery will be included on all pages.
403js_include(CPG_JQUERY_VERSION);
404js_include(CPG_JQUERY_MIGRATE);
405
406// Include the scripts.js javascript library that contains coppermine-specific
407// JavaScript that is being used on all pages.
408// Do not remove this line unless you really know what you're doing
409js_include('js/scripts.js');
410
411// Include the JavaScript library that takes care of the help system.
412js_include('js/jquery.greybox.js');
413
414// Include the elastic plugin for auto-expanding textareas if debug_mode is on
415js_include('js/jquery.elastic.js');
416
417// If referer is set in URL and it contains 'http' or 'script' texts then set it to 'index.php' script
418/**
419 * Use $CPG_REFERER wherever $_GET['referer'] is used
420 */
421if ( ($matches = $superCage->get->getMatched('referer', '/((\%3C)|<)[^\n]+((\%3E)|>)|(.*http.*)|(.*script.*)|(^[\W].*)/i')) ) {
422    $CPG_REFERER = 'index.php';
423} else {
424    /**
425     * Using getRaw() since we are checking the referer in the above if condition.
426     */
427    $CPG_REFERER = $superCage->get->getRaw('referer');
428}
429
430/**
431 * CPGPluginAPI::action('page_start',null)
432 *
433 * Executes page_start action on all plugins
434 *
435 * @param null
436 * @return N/A
437 **/
438
439CPGPluginAPI::action('page_start', null);
440
441// load the main template
442load_template();
443$CONFIG['template_loaded'] = true;
444
445// Remove expired bans
446$now = date('Y-m-d H:i:s');
447if ($CONFIG['purge_expired_bans'] == 1) {
448    cpg_db_query("DELETE FROM {$CONFIG['TABLE_BANNED']} WHERE expiry < '$now'");
449}
450// Check if the user is banned
451$user_id = USER_ID;
452// Compose the query
453$query_string = "SELECT null FROM {$CONFIG['TABLE_BANNED']} WHERE (";
454if (USER_ID) {
455    $query_string .= "user_id=$user_id OR ";
456}
457if ($raw_ip != $hdr_ip) {
458    $query_string .= "'$raw_ip' LIKE ip_addr OR '$hdr_ip' LIKE ip_addr ";
459} elseif ($raw_ip != '') {
460    $query_string .= "'$raw_ip' LIKE ip_addr ";
461}
462$query_string .= ") AND brute_force=0 LIMIT 1";
463
464$result = cpg_db_query($query_string);
465unset($query_string);
466if ($result->numRows()) {
467    pageheader($lang_common['error']);
468    msg_box($lang_common['information'], $lang_errors['banned']);
469    pagefooter();
470    exit;
471}
472$result->free();
473
474// Retrieve the "private" album set
475if (!GALLERY_ADMIN_MODE && $CONFIG['allow_private_albums']) {
476    get_private_album_set();
477}
478
479if (!USER_IS_ADMIN && $CONFIG['offline'] && $CPG_PHP_SELF != 'login.php' && $CPG_PHP_SELF != 'update.php') {
480    pageheader($lang_errors['offline_title']);
481    msg_box($lang_errors['offline_title'], $lang_errors['offline_text']);
482    pagefooter();
483    exit;
484}
485//EOF