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/functions.inc.php
11 * @since  1.6.10
12 */
13
14if (!function_exists('stripos')) {
15    function stripos($str, $needle, $offset = 0)
16    {
17        return strpos(strtolower($str), strtolower($needle), $offset);
18    }
19}
20
21/**
22* get_meta_album_set()
23*
24* Generates a WHERE statement that reflects the meta album
25* Incorporates restrictions based on visibility and album passwords
26*
27* @param integer $cat Category
28* @return void
29**/
30// TODO: add in INNER JOIN {$CONFIG['TABLE_CATEGORIES']} ON cid = category
31// only add when we are at the top level, cat == 0
32function get_meta_album_set($cat)
33{
34    global $CONFIG, $lft, $rgt, $RESTRICTEDWHERE, $FORBIDDEN_SET_DATA, $CURRENT_ALBUM_KEYWORD, $CURRENT_CAT_DEPTH;
35    if ($cat == USER_GAL_CAT) {
36        $RESTRICTEDWHERE   = "WHERE (category > " . FIRST_USER_CAT;
37        $CURRENT_CAT_DEPTH = -1;
38
39    } elseif ($cat > FIRST_USER_CAT) {
40        $RESTRICTEDWHERE   = "WHERE (category = $cat";
41        $CURRENT_CAT_DEPTH = -1;
42
43    } elseif ($cat > 0) {
44        $result = cpg_db_query("SELECT rgt, lft, depth FROM {$CONFIG['TABLE_CATEGORIES']} WHERE cid = $cat LIMIT 1");
45        list($rgt, $lft, $CURRENT_CAT_DEPTH) = $result->fetchRow(true);
46        $RESTRICTEDWHERE = "INNER JOIN {$CONFIG['TABLE_CATEGORIES']} AS c2 ON c2.cid = category WHERE (c2.lft BETWEEN $lft AND $rgt";
47
48        if (empty($CURRENT_ALBUM_KEYWORD)) {
49            $result = cpg_db_query("SELECT cid FROM {$CONFIG['TABLE_CATEGORIES']} WHERE lft BETWEEN $lft AND $rgt");
50            $categories = array();
51            while($row = $result->fetchAssoc()) {
52                $categories[] = $row['cid'];
53            }
54            $result->free();
55            $categories = implode(', ', $categories);
56
57            $result = cpg_db_query("SELECT keyword FROM {$CONFIG['TABLE_ALBUMS']} WHERE category IN ($categories)");
58            if ($result->numRows() > 0) {
59                $CURRENT_ALBUM_KEYWORD = array();
60                while($row = $result->fetchAssoc()) {
61                    if(!empty($row['keyword'])) {
62                        $CURRENT_ALBUM_KEYWORD[] = $row['keyword'];
63                    }
64                }
65            }
66            $result->free();
67        }
68
69    } elseif ($cat < 0) {
70        $RESTRICTEDWHERE = "WHERE (r.aid = " . -$cat;
71
72    } else {
73        $RESTRICTEDWHERE   = "WHERE (1";
74        $CURRENT_CAT_DEPTH = 0;
75    }
76
77    if (!empty($CURRENT_ALBUM_KEYWORD)) {
78        $RESTRICTEDWHERE .= ") AND (1";
79        if(is_array($CURRENT_ALBUM_KEYWORD)) {
80            foreach($CURRENT_ALBUM_KEYWORD as $keyword) {
81                $RESTRICTEDWHERE .= " OR keywords like '%$keyword%'";
82            }
83        } else {
84            $RESTRICTEDWHERE .= " OR keywords like '%$CURRENT_ALBUM_KEYWORD%'";
85        }
86    }
87    $RESTRICTEDWHERE .= ')';
88    if ($FORBIDDEN_SET_DATA) {
89        $RESTRICTEDWHERE .= " AND r.aid NOT IN (" . implode(', ', $FORBIDDEN_SET_DATA) . ")";
90    }
91}
92
93
94/**
95 * user_get_profile()
96 *
97 * Decode the user profile contained in a cookie
98 *
99 **/
100
101function user_get_profile()
102{
103    global $CONFIG, $USER;
104
105    $superCage = Inspekt::makeSuperCage();
106
107    /**
108     * TODO: Use the md5 # to verify integrity of cookie string
109     * At the time of installation we write a randomly generated secret salt in config.inc
110     * This secret salt will be appended to the encoded string and the resulting md5 # of this string will
111     * be appended to the encoded string with @ separator
112     * e.g. $encoded_string_with_md5 = "asdfkhasdf987we89rfadfjhasdfklj@^@".md5("asdfkhasdf987we89rfadfjhasdfklj".$secret_salt)
113     */
114    if ($superCage->cookie->keyExists($CONFIG['cookie_name'].'_data')) {
115        $USER = @unserialize(@base64_decode($superCage->cookie->getRaw($CONFIG['cookie_name'].'_data')));
116        if (isset($USER['lang'])) {
117            $USER['lang'] = strtr($USER['lang'], '$/\\:*?"\'<>|`', '____________');
118        }
119    }
120
121    if (!isset($USER['ID']) || strlen($USER['ID']) != 32) {
122        list($usec, $sec) = explode(' ', microtime());
123        $seed             = (float) $sec + ((float) $usec * 100000);
124        srand($seed);
125        $USER = array('ID' => md5(uniqid(rand(), 1)));
126    } else {
127        $USER['ID'] = addslashes($USER['ID']);
128    }
129
130    if (!isset($USER['am'])) {
131        $USER['am'] = 1;
132    }
133}
134
135// Save the user profile in a cookie
136
137
138/**
139 * user_save_profile()
140 *
141 * Save the user profile in a cookie
142 *
143 **/
144
145function user_save_profile()
146{
147    global $CONFIG, $USER;
148
149    /**
150     * TODO: Use the md5 # to verify integrity of cookie string
151     * At the time of installation we write a randomly generated secret salt in config.inc
152     * This secret salt will be appended to the encoded string and the resulting md5 # of this string will
153     * be appended to the encoded string with @ separator
154     * e.g. $encoded_string_with_md5 = "asdfkhasdf987we89rfadfjhasdfklj@^@".md5("asdfkhasdf987we89rfadfjhasdfklj".$secret_salt)
155     */
156    $data = base64_encode(serialize($USER));
157    if (CPG_COOKIES_ALLOWED) {
158        setcookie($CONFIG['cookie_name'].'_data', $data, time() + (CPG_DAY*30), $CONFIG['cookie_path']);
159    }
160}
161
162/**************************************************************************
163   Database functions
164 **************************************************************************/
165
166/**
167 * cpg_db_get_connection()
168 *
169 * Get the global database object
170 *  or return a new database object
171 *
172 * @return
173 **/
174
175function cpg_db_get_connection($cfg=null)
176{
177    global $CPGDB;
178
179	if ($cfg && isset($cfg['dbserver']) && isset($cfg['dbuser']) && isset($cfg['dbpass']) && isset($cfg['dbname'])) {
180		return new CPG_Dbase($cfg);
181	} else {
182    	return $CPGDB;
183    }
184}
185
186
187/**
188 * cpg_db_query()
189 *
190 * Perform a database query
191 *
192 * @param $query
193 * @return
194 **/
195
196function cpg_db_query($query, $dbobj=null)
197{
198    global $CONFIG, $CPGDB, $query_stats, $queries;
199
200    $query_start = cpgGetMicroTime();
201
202    $result = $dbobj ? $dbobj->query($query) : $CPGDB->query($query);
203
204    $query_end = cpgGetMicroTime();
205
206    if (!isset($CONFIG['debug_mode']) || $CONFIG['debug_mode'] == 1 || $CONFIG['debug_mode'] == 2) {
207        $trace = debug_backtrace();
208        $last = $trace[0];
209        $localfile = str_replace(realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..') . DIRECTORY_SEPARATOR , '', $last['file']);
210
211        $duration      = ($query_end - $query_start) * 1000;
212        $query_stats[] = $duration;
213        $queries[]     = "$query [$localfile:{$last['line']}] (".round($duration, 2)." ms)";
214    }
215
216    if (!$result && !defined('UPDATE_PHP')) {
217        $trace = debug_backtrace();
218        $last = $trace[0];
219        $localfile = str_replace(realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..') . DIRECTORY_SEPARATOR , '', $last['file']);
220        cpg_db_error("While executing query '$query' in $localfile on line {$last['line']}");
221    }
222
223    return $result;
224}
225
226
227/**
228 * cpg_db_error()
229 *
230 * Error message if a query failed
231 *
232 * @param $the_error
233 * @return
234 **/
235
236function cpg_db_error($the_error, $dbobj=null)
237{
238    global $CONFIG, $CPGDB, $lang_errors, $LINEBREAK;
239
240	$dbo = $dbobj ?: $CPGDB;
241
242    log_write("$the_error the following error was encountered: $LINEBREAK" . $dbo->getError(), CPG_DATABASE_LOG);
243
244    if ($CONFIG['debug_mode'] === '0' || ($CONFIG['debug_mode'] === '2' && !GALLERY_ADMIN_MODE)) {
245        cpg_die(CRITICAL_ERROR, $lang_errors['database_query'], __FILE__, __LINE__);
246    } else {
247        $the_error .= $LINEBREAK . $LINEBREAK . 'database error: ' . $dbo->getError() . $LINEBREAK;
248        $out        = "<br />" . $lang_errors['database_query'] . ".<br /><br/>
249                <form name=\"dbsql\" id=\"dbsql\"><textarea rows=\"8\" cols=\"60\">" . htmlspecialchars($the_error) . "</textarea></form>";
250        cpg_die(CRITICAL_ERROR, $out, __FILE__, __LINE__);
251    }
252}
253
254
255/**
256 * cpg_db_num_rows()
257 *
258 * Get then numbers of rows in a result
259 *
260 * @param $result
261 * @return
262 **/
263
264function cpg_db_num_rows($result, $free=false)
265{
266    return $result->numRows($free);
267}
268
269
270/**
271 * cpg_db_fetch_rowset()
272 *
273 * Fetch all rows in an array
274 *
275 * @param $result
276 * @return
277 **/
278
279function cpg_db_fetch_rowset($result, $free=false)
280{
281    $rowset = array();
282
283    while ( ($row = $result->fetchAssoc()) ) {
284        $rowset[] = $row;
285    }
286	if ($free) $result->free();
287
288    return $rowset;
289}
290
291
292/**
293 * cpg_db_fetch_row()
294 *
295 * Fetch row as a simple numeric array
296 *
297 * @param $result
298 * @return
299 **/
300
301function cpg_db_fetch_row($result, $free=false)
302{
303    return $result->fetchRow($free);
304}
305
306
307/**
308 * cpg_db_fetch_assoc()
309 *
310 * Fetch row as an associative array
311 *
312 * @param $result
313 * @return
314 **/
315
316function cpg_db_fetch_assoc($result, $free=false)
317{
318    return $result->fetchAssoc($free);
319}
320
321
322/**
323 * cpg_db_fetch_array()
324 *
325 * Fetch row as both a simple and associative array
326 *
327 * @param $result
328 * @return
329 **/
330
331function cpg_db_fetch_array($result, $free=false)
332{
333    return $result->fetchArray($free);
334}
335
336
337/**
338 * cpg_db_result()
339 *
340 * Fetch data from a certain row and field
341 *
342 * @param $result
343 **/
344
345function cpg_db_result($result, $row=0, $field=0, $free=false)
346{
347    return $result->result($row, $field, $free);
348}
349
350
351/**
352 * cpg_db_free_result()
353 *
354 * Free query result storage
355 *
356 * @param $result
357 **/
358
359function cpg_db_free_result($result)
360{
361	if (is_object($result))
362    	$result->free();
363}
364
365
366/**
367 * cpg_db_last_insert_id()
368 *
369 * Get the last inserted id of a query
370 *
371 * @return integer $id
372 **/
373
374function cpg_db_last_insert_id($dbobj=null)
375{
376    global $CPGDB;
377
378    return $dbobj ? $dbobj->insertId() : $CPGDB->insertId();
379}
380
381function cpg_db_insert_id($dbobj=null)
382{
383	return cpg_db_last_insert_id($dbobj);
384}
385
386/**
387 * cpg_db_affected_rows()
388 *
389 * Get the count of rows affected by last query
390 *
391 * @return integer $id
392 **/
393
394function cpg_db_affected_rows($dbobj=null)
395{
396    global $CPGDB;
397
398    return $dbobj ? $dbobj->affectedRows() : $CPGDB->affectedRows();
399}
400
401
402/**
403 * cpg_db_escape_string()
404 *
405 * Escape a string for database purposes
406 *
407 * @param $str
408 * @return
409 **/
410
411function cpg_db_escape_string($str)
412{
413    global $CPGDB;
414
415    return $CPGDB->escapeStr($str);
416}
417
418function cpg_db_real_escape_string($str, $dbobj=null)
419{
420    global $CPGDB;
421
422    return $dbobj ? $dbobj->escapeStr($str) : $CPGDB->escapeStr($str);
423}
424
425
426
427/**************************************************************************
428   Sanitization functions
429 **************************************************************************/
430
431/**
432 * cpgSanitizeUserTextInput()
433 *
434 * Function to sanitize the data which cannot be directly sanitized with Inspekt
435 *
436 * @param string $string
437 * @return string Return sanitized data
438 */
439function cpgSanitizeUserTextInput($string)
440{
441    //TODO: Add some sanitization code
442    return $string;
443}
444
445/**************************************************************************
446   Utilities functions
447 **************************************************************************/
448
449// Replacement for the die function
450
451/**
452 * cpg_die()
453 *
454 * Replacement for the die function
455 *
456 * @param $msg_code
457 * @param $msg_text
458 * @param $error_file
459 * @param $error_line
460 * @param boolean $output_buffer
461 * @return
462 **/
463
464function cpg_die($msg_code, $msg_text,  $error_file = '?file?', $error_line = '?line?', $output_buffer = false)
465{
466    global $lang_common, $lang_errors, $CONFIG, $USER_DATA, $hdr_ip;
467
468    // Three types of error levels: INFORMATION, ERROR, CRITICAL_ERROR.
469    // There used to be a clumsy method for error mesages that didn't work well with i18n.
470    // Let's add some more logic to this: try to get the translation
471    // for the error type from the language file. If that fails, use the hard-coded
472    // English string.
473
474    // Record access denied messages to the log
475    if ($msg_text == $lang_errors['access_denied'] && $CONFIG['log_mode'] != 0) {
476        log_write("Denied privileged access to " . basename($error_file) . " by user {$USER_DATA['user_name']} at IP $hdr_ip", CPG_SECURITY_LOG);
477    }
478
479    // Record invalid form token messages to the log
480    if ($msg_text == $lang_errors['invalid_form_token'] && $CONFIG['log_mode'] != 0) {
481        log_write("Invalid form token encountered for " . basename($error_file) . " by user {$USER_DATA['user_name']} at IP $hdr_ip", CPG_SECURITY_LOG);
482    }
483
484    if ($msg_code == INFORMATION) {
485        //$msg_icon = 'info'; not used anymore?
486        $css_class = 'cpg_message_info';
487        if ($lang_common['information'] != '') {
488            $msg_string = $lang_common['information'];
489        } else {
490            $msg_string = 'Information';
491        }
492    } elseif ($msg_code == ERROR) {
493        //$msg_icon = 'warning'; not used anymore?
494        $css_class = 'cpg_message_warning';
495        if ($lang_errors['error'] != '') {
496            $msg_string = $lang_errors['error'];
497        } else {
498            $msg_string = 'Error';
499        }
500    } elseif ($msg_code == CRITICAL_ERROR) {
501        //$msg_icon = 'stop'; not used anymore?
502        $css_class = 'cpg_message_error';
503        if ($lang_errors['critical_error'] != '') {
504            $msg_string = $lang_errors['critical_error'];
505        } else {
506            $msg_string = 'Critical error';
507        }
508    }
509
510    // Simple output if theme file is not loaded
511    if (!function_exists('pageheader')) {
512        echo 'Fatal error :<br />'.$msg_text;
513        exit;
514    }
515
516    $ob = ob_get_contents();
517
518    if ($ob) {
519        ob_end_clean();
520    }
521
522    theme_cpg_die($msg_code, $msg_text, $msg_string, $css_class, $error_file, $error_line, $output_buffer, $ob);
523    exit;
524}
525
526
527// Display a localised date
528
529/**
530 * localised_date()
531 *
532 * Display a localised date
533 *
534 * @param integer $timestamp
535 * @param $datefmt
536 * @return
537 **/
538
539function localised_date($timestamp, $datefmt)
540{
541    global $lang_month, $lang_day_of_week;
542
543    $timestamp = localised_timestamp($timestamp);
544
545    $date = str_replace(array('%a', '%A'), $lang_day_of_week[(int)strftime('%w', $timestamp)], $datefmt);
546    $date = str_replace(array('%b', '%B'), $lang_month[(int)strftime('%m', $timestamp)-1], $date);
547
548    return strftime($date, $timestamp);
549}
550
551/**
552 * localised_timestamp()
553 *
554 * Display a localised timestamp
555 *
556 * @return
557 **/
558function localised_timestamp($timestamp = -1)
559{
560    global $CONFIG;
561
562    if ($timestamp == -1) {
563        $timestamp = time();
564    }
565
566    $diff_to_GMT = date("O") / 100;
567
568    $timestamp += ($CONFIG['time_offset'] - $diff_to_GMT) * 3600;
569
570    return $timestamp;
571}
572
573// Function to create correct URLs for image name with space or exotic characters
574
575/**
576 * path2url()
577 *
578 * Function to create correct URLs for image name with space or exotic characters
579 *
580 * @param $path
581 * @return
582 **/
583
584function path2url($path)
585{
586    return str_replace("%2F", "/", rawurlencode($path));
587}
588
589// Display a 'message box like' table
590
591/**
592 * msg_box()
593 *
594 * Display a 'message box like' table
595 *
596 * @param $title
597 * @param $msg_text
598 * @param string $button_text
599 * @param string $button_link
600 * @param string $width
601 * @return
602 **/
603
604function msg_box($title, $msg_text, $button_text='', $button_link='', $type = 'info')
605{
606    if ($type == 'error') {
607        $css_class = 'cpg_message_error';
608    } elseif ($type == 'warning') {
609        $css_class = 'cpg_message_warning';
610    } elseif ($type == 'validation') {
611        $css_class = 'cpg_message_validation';
612    } elseif ($type == 'success') {
613        $css_class = 'cpg_message_success';
614    } else {
615        $css_class = 'cpg_message_info';
616    }
617    // Call theme function to display message box
618    theme_msg_box($title, $msg_text, $css_class, $button_text, $button_link);
619}
620
621
622/**
623 * create_tabs()
624 *
625 * @param $items
626 * @param $curr_page
627 * @param $total_pages
628 * @param $template
629 * @return
630 **/
631
632function create_tabs($items, $curr_page, $total_pages, $template)
633{
634    return theme_create_tabs($items, $curr_page, $total_pages, $template);
635}
636
637/**
638 * Rewritten by Nathan Codding - Feb 6, 2001. Taken from phpBB code
639 * - Goes through the given string, and replaces xxxx://yyyy with an HTML <a> tag linking
640 *         to that URL
641 * - Goes through the given string, and replaces www.xxxx.yyyy[zzzz] with an HTML <a> tag linking
642 *         to http://www.xxxx.yyyy[/zzzz]
643 * - Goes through the given string, and replaces xxxx@yyyy with an HTML mailto: tag linking
644 *                to that email address
645 * - Only matches these 2 patterns either after a space, or at the beginning of a line
646 *
647 * Notes: the email one might get annoying - it's easy to make it more restrictive, though.. maybe
648 * have it require something like xxxx@yyyy.zzzz or such. We'll see.
649 */
650
651/**
652 * make_clickable()
653 *
654 * @param $text
655 * @return
656 **/
657
658function make_clickable($text)
659{
660    $ret = ' '.$text;
661
662    $ret = preg_replace("#([\n ])([a-z]+?)://([a-z0-9\-\.,\?!%\*_\#:;~\\&$@\/=\+]+)#i", "\\1<a href=\"\\2://\\3\" rel=\"external\">\\2://\\3</a>", $ret);
663    $ret = preg_replace("#([\n ])www\.([a-z0-9\-]+)\.([a-z0-9\-.\~]+)((?:/[a-z0-9\-\.,\?!%\*_\#:;~\\&$@\/=\+]*)?)#i", "\\1<a href=\"http://www.\\2.\\3\\4\" rel=\"external\">www.\\2.\\3\\4</a>", $ret);
664    $ret = preg_replace("#([\n ])([a-z0-9\-_.]+?)@([\w\-]+\.([\w\-\.]+\.)?[\w]+)#i", "\\1<a href=\"mailto:\\2@\\3\">\\2@\\3</a>", $ret);
665
666    return substr($ret, 1);
667}
668
669// Allow the use of a limited set of phpBB bb codes in albums and image descriptions
670// Taken from phpBB code
671
672/**
673 * bb_decode()
674 *
675 * @param $text
676 * @return
677 **/
678
679function bb_decode($text)
680{
681    $text = nl2br($text);
682
683    static $bbcode_tpl   = array();
684    static $patterns     = array();
685    static $replacements = array();
686
687    // First: If there isn't a "[" and a "]" in the message, don't bother.
688    if ((strpos($text, "[") === false || strpos($text, "]") === false)) {
689        return $text;
690    }
691
692    $text = CPGPluginAPI::filter('bbcode', $text);
693
694    // [b] and [/b] for bolding text.
695    $text = str_replace("[b]", '<strong>', $text);
696    $text = str_replace("[/b]", '</strong>', $text);
697
698    // [u] and [/u] for underlining text.
699    $text = str_replace("[u]", '<u>', $text);
700    $text = str_replace("[/u]", '</u>', $text);
701
702    // [i] and [/i] for italicizing text.
703    $text = str_replace("[i]", '<em>', $text);
704    $text = str_replace("[/i]", '</em>', $text);
705
706    // [s] and [/s] for striking through
707    $text = str_replace("[s]", '<del>', $text);
708    $text = str_replace("[/s]", '</del>', $text);
709
710    // colours
711    $text = preg_replace('/\[color=(\#[0-9A-F]{6}|[a-z]+)\]/', '<span style="color:$1">', $text);
712    $text = str_replace("[/color]", '</span>', $text);
713
714    if (!count($bbcode_tpl)) {
715
716        // We do URLs in several different ways..
717        $bbcode_tpl['url'] = '<span class="bblink"><a href="{URL}" %s>{DESCRIPTION}</a></span>';
718
719        $bbcode_tpl['url1'] = str_replace('{URL}', '\\1\\2', $bbcode_tpl['url']);
720        $bbcode_tpl['url1'] = str_replace('{DESCRIPTION}', '\\1\\2', $bbcode_tpl['url1']);
721
722        // [url]xxxx://www.phpbb.com[/url] code..
723        $patterns['link'][1]     = '#\[url\]([a-z]+?://){1}([a-z0-9\-\.,\?!%\*_\#:;~\\&$@\/=\+\(\)]+)\[/url\]#si';
724        $replacements['link'][1] = $bbcode_tpl['url1'];
725
726        $bbcode_tpl['url2'] = str_replace('{URL}', 'http://\\1', $bbcode_tpl['url']);
727        $bbcode_tpl['url2'] = str_replace('{DESCRIPTION}', '\\1', $bbcode_tpl['url2']);
728
729        // [url]www.phpbb.com[/url] code.. (no xxxx:// prefix).
730        $patterns['link'][2]     = '#\[url\]([a-z0-9\-\.,\?!%\*_\#:;~\\&$@\/=\+\(\)]+)\[/url\]#si';
731        $replacements['link'][2] = $bbcode_tpl['url2'];
732
733        $bbcode_tpl['url3'] = str_replace('{URL}', '\\1\\2', $bbcode_tpl['url']);
734        $bbcode_tpl['url3'] = str_replace('{DESCRIPTION}', '\\3', $bbcode_tpl['url3']);
735
736        // [url=xxxx://www.phpbb.com]phpBB[/url] code..
737        $patterns['link'][3]     = '#\[url=([a-z]+?://){1}([a-z0-9\-\.,\?!%\*_\#:;~\\&$@\/=\+\(\)]+)\](.*?)\[/url\]#si';
738        $replacements['link'][3] = $bbcode_tpl['url3'];
739
740        $bbcode_tpl['url4'] = str_replace('{URL}', 'http://\\1', $bbcode_tpl['url']);
741        $bbcode_tpl['url4'] = str_replace('{DESCRIPTION}', '\\2', $bbcode_tpl['url4']);
742
743        // [url=www.phpbb.com]phpBB[/url] code.. (no xxxx:// prefix).
744        $patterns['link'][4]     = '#\[url=([a-z0-9\-\.,\?!%\*_\#:;~\\&$@\/=\+\(\)]+)\](.*?)\[/url\]#si';
745        $replacements['link'][4] = $bbcode_tpl['url4'];
746
747        $bbcode_tpl['email'] = '<span class="bblink"><a href="mailto:{EMAIL}">{EMAIL}</a></span>';
748        $bbcode_tpl['email'] = str_replace('{EMAIL}', '\\1', $bbcode_tpl['email']);
749
750        // [email]user@domain.tld[/email] code..
751        $patterns['other'][1]     = '#\[email\]([a-z0-9\-_.]+?@[\w\-]+\.([\w\-\.]+\.)?[\w]+)\[/email\]#si';
752        $replacements['other'][1] = $bbcode_tpl['email'];
753
754        // [img]xxxx://www.phpbb.com[/img] code..
755        $bbcode_tpl['img'] = '<img src="{URL}" alt="" />';
756        $bbcode_tpl['img'] = str_replace('{URL}', '\\1\\2', $bbcode_tpl['img']);
757
758        $patterns['other'][2]     = '#\[img\]([a-z]+?://){1}([a-z0-9\-\.,\?!%\*_\#:;~\\&$@\/=\+\(\)]+)\[/img\]#si';
759        $replacements['other'][2] = $bbcode_tpl['img'];
760    }
761
762    $text = check_link_type_and_replace($patterns['link'][1], $replacements['link'][1], $text, 1);
763    $text = check_link_type_and_replace($patterns['link'][2], $replacements['link'][2], $text, 2);
764    $text = check_link_type_and_replace($patterns['link'][3], $replacements['link'][3], $text, 3);
765    $text = check_link_type_and_replace($patterns['link'][4], $replacements['link'][4], $text, 4);
766
767    $text = preg_replace($patterns['other'], $replacements['other'], $text);
768
769    return $text;
770}
771
772/**
773* check_link_type_and_replace()
774*
775* Checks if the text contains this pattern and replace it accordingly
776*
777* @param string $pattern
778* @param string $replacement
779* @param string $text
780* @param integer $stage
781*
782* @return string $text
783*/
784function check_link_type_and_replace ($pattern, $replacement, $text, $stage)
785{
786    $ext_rel = 'rel="external nofollow" class="external"';
787    $int_rel = '';
788
789    if (preg_match($pattern, $text, $url) != 0) {
790
791        switch ($stage) {
792
793        case 1:
794        case 3:
795            $url = $url[1] . $url[2];
796            break;
797
798        case 2:
799            $url = $url[1];
800            break;
801
802        case 4:
803            $url = 'http://' . $url[1];
804        }
805
806        if (is_link_local($url)) {
807            //apply regular formatting
808            $replacement_sprintfed = sprintf($replacement, $int_rel);
809        } else {
810            //add rel attribute to link
811            $replacement_sprintfed = sprintf($replacement, $ext_rel);
812        }
813
814        $text = preg_replace($pattern, $replacement_sprintfed, $text, 1);
815        $text = check_link_type_and_replace($pattern, $replacement, $text, $stage);
816    }
817
818    return $text;
819}
820
821/**
822* is_link_local()
823*
824* Determines if a URL is local or external. FROM phpBB MOD: prime links (by Ken F. Innes IV)
825*
826* @param string $url
827*
828* @return boolean $is_local
829*/
830function is_link_local($url)
831{
832    global $CONFIG;
833
834    $subdomain_remove_regex = '#^(http|https)://[^/]+?\.((?:[a-z0-9-]+\.[a-z]+)|localhost/)#i';
835
836    $cpg_url = preg_replace($subdomain_remove_regex, '$1://$2', $CONFIG['site_url']);
837    $url     = preg_replace($subdomain_remove_regex, '$1://$2', $url);
838
839    $is_local = (strpos($url, $cpg_url) === 0);
840
841    if (!$is_local) {
842        $protocol = substr($url, 0, strpos($url, ':'));
843        $is_local = !$protocol || ($protocol && !in_array($protocol, array('http', 'https', 'mailto', 'ftp', 'gopher')));
844    }
845
846    return($is_local);
847}
848
849/**
850* is_url()
851*
852* Determines if a string is in the form of a URL
853*
854* @param string $url
855*
856* @return boolean $is_url
857*/
858function is_url($url)
859{
860	$regx = '|^(http(s)?:)?//[-a-z0-9_.]+/|i';
861	$is_url = preg_match($regx, $url);
862	return $is_url;
863}
864
865
866/**************************************************************************
867   Template functions
868 **************************************************************************/
869
870// Load and parse the template.html file
871
872/**
873 * load_template()
874 *
875 * Load and parse the template.html file
876 *
877 * @return
878 **/
879
880function load_template()
881{
882    global $THEME_DIR, $CONFIG, $template_header, $template_footer, $theme_lang, $LINEBREAK;
883
884    $template = file_get_contents($THEME_DIR . TEMPLATE_FILE);
885
886    if ($template === FALSE) {
887        die("Coppermine critical error:<br />Unable to load template file " . $THEME_DIR . TEMPLATE_FILE . "!");
888    }
889
890    $template = CPGPluginAPI::filter('template_html', $template);
891
892    if (strpos($template, '{LANGUAGE_SELECT_FLAGS}')) {
893        $template = str_replace('{LANGUAGE_SELECT_FLAGS}', languageSelect('flags'), $template);
894    }
895
896    if (strpos($template, '{LANGUAGE_SELECT_LIST}')) {
897        $template = str_replace('{LANGUAGE_SELECT_LIST}', languageSelect('list'), $template);
898    }
899
900    if (strpos($template, '{THEME_DIR}')) {
901    	$template = str_replace('{THEME_DIR}', $THEME_DIR, $template);
902    }
903
904    if (strpos($template, '{THEME_SELECT_LIST}')) {
905        $template = str_replace('{THEME_SELECT_LIST}', themeSelect('list'), $template);
906    }
907
908	// apply any language files
909	$theme_lang_path = $THEME_DIR . 'lang';
910	if (is_dir($theme_lang_path)) {
911		include $theme_lang_path . '/english.php';
912		if ($CONFIG['lang'] != 'english' && file_exists($theme_lang_path."/{$CONFIG['lang']}.php")) {
913			include $theme_lang_path."/{$CONFIG['lang']}.php";
914		}
915		while (preg_match('#\{THEME_LANG_([^}]+)\}#', $template, $match)) {
916			if (isset($theme_lang[$match[1]])) {
917				$template = str_replace('{THEME_LANG_'.$match[1].'}', $theme_lang[$match[1]], $template);
918			} else {
919				$template = str_replace('{THEME_LANG_'.$match[1].'}', $match[1], $template);
920			}
921		}
922	}
923
924    // Failsafe-option if JAVASCRIPT-token is missing from custom theme
925    if (strpos($template, '{JAVASCRIPT}') === FALSE) {
926        if (stripos($template, '</head>') !== FALSE) {
927            $template = str_ireplace('</head>', '{JAVASCRIPT}' . $LINEBREAK . '</head>', $template);
928        } elseif (stripos($template, '<head>') !== FALSE) {
929            $template = str_ireplace('<head>',  '<head>' . $LINEBREAK .'{JAVASCRIPT}', $template);
930        } elseif (stripos($template, '</title>') !== FALSE) {
931            $template = str_ireplace('</title>', '</title>' . $LINEBREAK . '{JAVASCRIPT}', $template);
932        }
933    }
934
935    $gallery_pos = strpos($template, '{GALLERY}');
936
937    if (!strstr($template, '{CREDITS}')) {
938        $template = str_replace('{GALLERY}', '{CREDITS}', $template);
939    } else {
940        $template = str_replace('{GALLERY}', '', $template);
941    }
942
943    $template_header = substr($template, 0, $gallery_pos);
944    $template_header = str_replace('{META}', '{META}' . CPGPluginAPI::filter('page_meta', ''), $template_header);
945
946    $template_footer = substr($template, $gallery_pos);
947
948    // Filter gallery header and footer
949    $template_header = CPGPluginAPI::filter('gallery_header', $template_header);
950    $template_footer = CPGPluginAPI::filter('gallery_footer', $template_footer);
951
952    $add_version_info = '<!--Coppermine Photo Gallery ' . COPPERMINE_VERSION . ' (' . COPPERMINE_VERSION_STATUS . ')-->' . $LINEBREAK . '</body>';
953    $template_footer  = preg_replace("#</body[^>]*>#", $add_version_info, $template_footer);
954}
955
956// Eval a template (substitute vars with values)
957
958/**
959 * template_eval()
960 *
961 * @param $template
962 * @param $vars
963 * @return
964 **/
965
966function template_eval($template, $vars)
967{
968	if (!is_array($vars)) return $template;
969    return str_replace(array_keys($vars), array_values($vars), $template);
970}
971
972
973// Extract and return block '$block_name' from the template, the block is replaced by $subst
974
975/**
976 * template_extract_block()
977 *
978 * @param $template
979 * @param $block_name
980 * @param string $subst
981 * @return
982 **/
983
984function template_extract_block(&$template, $block_name, $subst='')
985{
986    $pattern = "#<!-- BEGIN $block_name -->(.*?)<!-- END $block_name -->#s";
987
988    if (!preg_match($pattern, $template, $matches)) {
989        die('<strong>Template error<strong><br />Failed to find block \'' . $block_name . '\' (' . htmlspecialchars($pattern) . ') in :<br /><pre>' . htmlspecialchars($template) . '</pre>');
990    }
991
992    $template = str_replace($matches[0], $subst, $template);
993
994    return $matches[1];
995}
996
997/**************************************************************************
998   Functions for album/picture management
999 **************************************************************************/
1000
1001// Get the list of albums that the current user can't see
1002
1003/**
1004 * get_private_album_set()
1005 *
1006 * @param string $aid_str
1007 * @return
1008 **/
1009
1010//TODO: only load restricted albums in the currently viewed category filtering
1011
1012function get_private_album_set($aid_str="")
1013{
1014    if (GALLERY_ADMIN_MODE) {
1015        return;
1016    }
1017
1018    global $CONFIG, $USER_DATA, $FORBIDDEN_SET, $FORBIDDEN_SET_DATA, $lang_errors;;
1019
1020    $superCage = Inspekt::makeSuperCage();
1021
1022    $FORBIDDEN_SET_DATA = array();
1023
1024    if ($USER_DATA['can_see_all_albums']) {
1025        return;
1026    }
1027
1028    //Stuff for Album level passwords
1029    if ($superCage->cookie->keyExists($CONFIG['cookie_name'] . "_albpw") && empty($aid_str)) {
1030
1031        //Using getRaw(). The data is sanitized in the foreach running just below
1032        $tmpStr = $superCage->cookie->getRaw($CONFIG['cookie_name'] . "_albpw");
1033        $alb_pw = unserialize(stripslashes($tmpStr));
1034
1035        foreach ($alb_pw as $aid => $value) {
1036            $aid_str .= (int)$aid . ",";
1037        }
1038
1039        $aid_str = substr($aid_str, 0, -1);
1040
1041        $sql = "SELECT aid, alb_password FROM {$CONFIG['TABLE_ALBUMS']} WHERE aid IN ($aid_str)";
1042
1043        $albpw_db = array();
1044
1045        $result = cpg_db_query($sql);
1046
1047        if ($result->numRows()) {
1048            while ( ($data = $result->fetchAssoc()) ) {
1049                $albpw_db[$data['aid']] = $data['alb_password'];
1050            }
1051        }
1052        $result->free();
1053
1054        $valid = array_intersect($albpw_db, $alb_pw);
1055
1056        if (is_array($valid)) {
1057            $aid_str = implode(",", array_keys($valid));
1058        } else {
1059            $aid_str = "";
1060        }
1061    }
1062
1063    // restrict the private album set to only those in current cat tree branch
1064
1065    $RESTRICTEDWHERE = "WHERE (1";
1066
1067    if (defined('RESTRICTED_PRIV')) {
1068
1069        if ($superCage->get->keyExists('cat')) {
1070            $cat = $superCage->get->getInt('cat');
1071        } else {
1072            $cat = 0;
1073        }
1074
1075        if ($cat == USER_GAL_CAT) {
1076
1077            $RESTRICTEDWHERE = "WHERE (category > " . FIRST_USER_CAT;
1078
1079        } elseif ($cat > FIRST_USER_CAT) {
1080
1081            $RESTRICTEDWHERE = "WHERE (category = $cat";
1082
1083        } elseif ($cat > 0) {
1084            //$CURRENT_CAT_DEPTH isn't used
1085            //$result = cpg_db_query("SELECT rgt, lft, depth FROM {$CONFIG['TABLE_CATEGORIES']} WHERE cid = $cat LIMIT 1");
1086            //list($rgt, $lft, $CURRENT_CAT_DEPTH) = mysql_fetch_row($result);
1087
1088            $result = cpg_db_query("SELECT rgt, lft FROM {$CONFIG['TABLE_CATEGORIES']} WHERE cid = $cat LIMIT 1");
1089            if ($result->numRows() == 0) {
1090                cpg_die(CRITICAL_ERROR, $lang_errors['non_exist_cat'], __FILE__, __LINE__);
1091            }
1092            list($rgt, $lft) = $result->fetchRow(true);
1093
1094            $RESTRICTEDWHERE = "INNER JOIN {$CONFIG['TABLE_CATEGORIES']} AS c2 ON c2.cid = category
1095                                    WHERE (c2.lft BETWEEN $lft AND $rgt";
1096        }
1097    }
1098
1099    $sql = "SELECT aid FROM {$CONFIG['TABLE_ALBUMS']} $RESTRICTEDWHERE "
1100            . " AND visibility != 0 AND visibility != " . (FIRST_USER_CAT + USER_ID)
1101            . " AND visibility NOT IN " . USER_GROUP_SET . ')';
1102
1103    if (!empty($aid_str)) {
1104        $sql .= " AND aid NOT IN ($aid_str)";
1105    }
1106
1107    $result = cpg_db_query($sql);
1108
1109    if ($result->numRows()) {
1110
1111        while ( ($album = $result->fetchAssoc()) ) {
1112            $FORBIDDEN_SET_DATA[] = $album['aid'];
1113        } // while
1114
1115        $FORBIDDEN_SET = "AND p.aid NOT IN (" . implode(', ', $FORBIDDEN_SET_DATA) . ') ';
1116
1117    } else {
1118        $FORBIDDEN_SET_DATA = array();
1119        $FORBIDDEN_SET      = "";
1120    }
1121
1122    $result->free();
1123}
1124
1125// Generate the thumbnail caption based on admin preference and thumbnail page requirements
1126
1127/**
1128 * build_caption()
1129 *
1130 * @param array $rowset by reference
1131 * @param array $must_have
1132 **/
1133function build_caption(&$rowset, $must_have = array(), $mode = 'files')
1134{
1135    global $CONFIG, $THEME_DIR, $lang_date, $lang_get_pic_data, $cpg_udb;
1136
1137    foreach ($rowset as $key => $row) {
1138
1139        $caption = '';
1140
1141        if ($CONFIG['display_filename']) {
1142            $caption .= '<span class="thumb_filename">' . $row['filename'] . '</span>';
1143        }
1144
1145        if (!empty($row['title'])) {
1146            $caption .= '<span class="thumb_title thumb_title_title">' . $row['title'] . '</span>';
1147        }
1148
1149        if ($CONFIG['views_in_thumbview'] || in_array('hits', $must_have)) {
1150            $views = ($mode == 'albums') ? $row['alb_hits'] : $row['hits'];
1151            $caption .= '<span class="thumb_title thumb_title_views">' . sprintf($lang_get_pic_data['n_views'], $views) . '</span>';
1152        }
1153
1154        if ($CONFIG['caption_in_thumbview'] && !empty($row['caption'])) {
1155            $caption .= '<span class="thumb_caption thumb_caption_caption">' . strip_tags(bb_decode($row['caption'])) . '</span>';
1156        }
1157
1158        if ($CONFIG['display_comment_count'] && $row['pid']) {
1159            $comments_nr = count_pic_comments($row['pid']);
1160            if ($comments_nr > 0) {
1161                $caption .= '<span class="thumb_num_comments">' . sprintf($lang_get_pic_data['n_comments'], $comments_nr) . '</span>';
1162            }
1163        }
1164
1165        if ($CONFIG['display_uploader']) {
1166            if ($row['owner_id']) {
1167                $caption .= '<span class="thumb_title thumb_title_owner"><a href="profile.php?uid=' . $row['owner_id'] . '">' . $cpg_udb->get_user_name($row['owner_id']) . '</a></span>';
1168            }
1169        }
1170
1171        if (in_array('msg_date', $must_have)) {
1172            $caption .= '<span class="thumb_caption thumb_caption_msg_date">' . localised_date($row['msg_date'], $lang_date['lastcom']) . '</span>';
1173        }
1174
1175        if (in_array('msg_body', $must_have)) {
1176
1177            $msg_body = strip_tags(bb_decode($row['msg_body'])); // I didn't want to fully bb_decode the message where report to admin isn't available. -donnoman
1178            $msg_body = utf_strlen($msg_body) > 50 ? utf_substr($msg_body, 0, 50) . '...' : $msg_body;
1179
1180            if ($CONFIG['enable_smilies']) {
1181                $msg_body = process_smilies($msg_body);
1182            }
1183
1184            if ($row['author_id']) {
1185                $caption .= '<span class="thumb_caption thumb_caption_author"><a href="profile.php?uid=' . $row['author_id'] . '">' . $row['msg_author'] . '</a>: ' . $msg_body . '</span>';
1186            } else {
1187                $caption .= '<span class="thumb_caption thumb_caption_author">' . $row['msg_author'] . ': ' . $msg_body . '</span>';
1188            }
1189        }
1190
1191        if (in_array('ctime', $must_have)) {
1192            $caption .= '<span class="thumb_caption thumb_caption_ctime">' . localised_date($row['ctime'], $lang_date['lastup']) . '</span>';
1193        }
1194
1195        if (in_array('pic_rating', $must_have)) {
1196
1197            if (defined('THEME_HAS_RATING_GRAPHICS')) {
1198                $prefix = $THEME_DIR;
1199            } else {
1200                $prefix = '';
1201            }
1202
1203            //calculate required amount of stars in picinfo
1204            $rating        = round(($row['pic_rating'] / 2000) / (5 / $CONFIG['rating_stars_amount']));
1205            $rating_images = '';
1206
1207            for ($i = 1; $i <= $CONFIG['rating_stars_amount']; $i++) {
1208
1209                if ($i <= $rating) {
1210                    $rating_images .= '<img src="' . $prefix . 'images/rate_full.png" alt="' . $rating . '"/>';
1211                } else {
1212                    $rating_images .= '<img src="' . $prefix . 'images/rate_empty.png" alt="' . $rating . '"/>';
1213                }
1214            }
1215
1216            $caption .= '<span class="thumb_caption thumb_caption_rating">' . $rating_images . '<br />' . sprintf($lang_get_pic_data['n_votes'], $row['votes']) . '</span>';
1217        }
1218
1219        if (in_array('mtime', $must_have)) {
1220
1221            $caption .= '<span class="thumb_caption thumb_caption_mtime">' . localised_date($row['mtime'], $lang_date['lasthit']);
1222
1223            if (GALLERY_ADMIN_MODE) {
1224                $caption .= '<br />' . $row['lasthit_ip'];
1225            }
1226
1227            $caption .= '</span>';
1228        }
1229
1230        $rowset[$key]['caption_text'] = $caption;
1231    }
1232
1233    $rowset = CPGPluginAPI::filter('thumb_caption', $rowset);
1234}
1235
1236/*
1237    To retrieve pictures from the end of an album or meta album, it is more
1238    efficient to sort from the end of the album and then reverse the result.
1239    $total is the total number of files in the [meta]album
1240    $offset is the position we are browsing from
1241    $row_count is the desired number of pics per page
1242*/
1243function get_pic_data_ordering($total, $offset, $row_count)
1244{
1245    // Determine if we are over halfway through the album
1246    if ($offset > $total / 2) {
1247
1248        // If so, switch the sort direction
1249        $ASC = 'DESC';
1250        $DESC = 'ASC';
1251
1252        // If we are on the last page, we need a partial result
1253        if ($offset + $row_count > $total) {
1254            $row_count = $total - $offset;
1255            $offset = 0;
1256        } else {
1257            $offset = $total - $offset - $row_count;
1258        }
1259
1260        // Flag so that we know to reverse the results later
1261        $flipped = true;
1262
1263    } else {
1264
1265        // Else, carry on as usual
1266        $ASC = 'ASC';
1267        $DESC = 'DESC';
1268        $flipped = false;
1269    }
1270
1271    // Generate the new LIMIT clause
1272    $limit = ($offset != -1) ? ' LIMIT ' . $offset : '';
1273    $limit .= ($row_count != -1) ? ' ,' . $row_count : '';
1274
1275    return array($ASC, $DESC, $limit, $flipped);
1276}
1277
1278// Retrieve the data for a picture or a set of picture
1279
1280/**
1281 * get_pic_data()
1282 *
1283 * @param $album
1284 * @param $count
1285 * @param $album_name
1286 * @param integer $limit1
1287 * @param integer $limit2
1288 * @param boolean $set_caption
1289 * @return
1290 **/
1291
1292function get_pic_data($album, &$count, &$album_name, $limit1=-1, $limit2=-1, $set_caption = true, $mode = '')
1293{
1294    global $USER, $CONFIG, $CURRENT_CAT_NAME, $CURRENT_ALBUM_KEYWORD, $FAVPICS, $FORBIDDEN_SET_DATA, $FORBIDDEN_SET, $USER_DATA;
1295    global $cat;
1296    global $lang_common, $lang_meta_album_names, $lang_errors;
1297    global $RESTRICTEDWHERE;
1298
1299    static $album_name_keyword = '', $pic_count = null;
1300
1301    $superCage = Inspekt::makeSuperCage();
1302
1303    $limit = ($limit1 != -1) ? ' LIMIT ' . $limit1 : '';
1304    $limit .= ($limit2 != -1) ? ' ,' . $limit2 : '';
1305
1306    if ($mode == 'pidonly') {
1307        $select_column_list = array('r.pid');
1308
1309    } elseif ($mode == 'filmstrip') {
1310        $select_column_list = array(
1311            'r.pid',
1312            'r.aid',
1313            'filepath',
1314            'filename',
1315            'url_prefix',
1316            'pwidth',
1317            'pheight',
1318            'filesize',
1319            'ctime',
1320            'r.title',
1321        );
1322
1323    } else {
1324        $select_column_list = array(
1325            'r.pid',
1326            'r.aid',
1327            'filepath',
1328            'filename',
1329            'url_prefix',
1330            'pwidth',
1331            'pheight',
1332            'filesize',
1333            'ctime',
1334            'r.title',
1335            'r.keywords',
1336            'r.votes',
1337            'pic_rating'
1338        );
1339
1340        //if ($CONFIG['views_in_thumbview']) {
1341            $select_column_list[] = 'hits';
1342        //}
1343
1344        //if ($CONFIG['caption_in_thumbview']) {
1345            $select_column_list[] = 'caption';
1346        //}
1347
1348        //if ($CONFIG['display_uploader']) {
1349            $select_column_list[] = 'r.owner_id';
1350        //}
1351
1352        if (GALLERY_ADMIN_MODE) {
1353            $select_column_list[] = 'pic_raw_ip';
1354            $select_column_list[] = 'pic_hdr_ip';
1355        }
1356
1357        for ($i = 1; $i <= 4; $i++) {
1358            if ($CONFIG['user_field' . $i . '_name']) {
1359                $select_column_list[] = 'user' . $i;
1360            }
1361        }
1362    }
1363
1364    if (count($FORBIDDEN_SET_DATA) > 0) {
1365        $forbidden_set_string = ' AND aid NOT IN (' . implode(', ', $FORBIDDEN_SET_DATA) . ')';
1366    } else {
1367        $forbidden_set_string = '';
1368    }
1369
1370    // Keyword
1371    if (!empty($CURRENT_ALBUM_KEYWORD)) {
1372        $keyword = "OR (keywords like '%$CURRENT_ALBUM_KEYWORD%' $forbidden_set_string )";
1373    } else {
1374        $keyword = '';
1375    }
1376
1377    // Regular albums
1378    if (is_numeric($album)) {
1379
1380        if (!$album_name_keyword) {
1381            $album_name_keyword = get_album_name($album);
1382        }
1383
1384        $album_name    = $album_name_keyword['title'];
1385        $album_keyword = addslashes($album_name_keyword['keyword']);
1386
1387        if (!empty($album_keyword)) {
1388            $keyword = "OR (keywords like '%$album_keyword%' $forbidden_set_string )";
1389        } else {
1390            $keyword = '';
1391        }
1392
1393        if (array_key_exists('allowed_albums', $USER_DATA) && is_array($USER_DATA['allowed_albums'])
1394                && in_array($album, $USER_DATA['allowed_albums'])) {
1395            $approved = '';
1396        } else {
1397            $approved = GALLERY_ADMIN_MODE ? '' : 'AND approved=\'YES\'';
1398        }
1399
1400        $approved = GALLERY_ADMIN_MODE ? '' : 'AND approved=\'YES\'';
1401
1402        // Note: Use a second variable, $pic_count, since $count is passed by reference
1403        // and having it defined as static in the function may be problematic
1404        if (is_null($pic_count)) {
1405            $result = cpg_db_query("SELECT COUNT(*) FROM {$CONFIG['TABLE_PICTURES']} WHERE ((aid='$album' $forbidden_set_string ) $keyword) $approved");
1406            list($count) = $result->fetchRow(true);
1407            $pic_count = $count;
1408        } else {
1409            $count = $pic_count;
1410        }
1411
1412        list($ASC, $DESC, $limit, $flipped) = get_pic_data_ordering($count, $limit1, $limit2);
1413
1414        $sort_array = array(
1415            'na' => "filename $ASC, pid $ASC",
1416            'nd' => "filename $DESC, pid $DESC",
1417            'ta' => "title $ASC, pid $ASC",
1418            'td' => "title $DESC, pid $DESC",
1419            'da' => "ctime $ASC, pid $ASC",
1420            'dd' => "ctime $DESC, pid $DESC",
1421            'pa' => "position $ASC, pid $ASC",
1422            'pd' => "position $DESC, pid $DESC",
1423        );
1424        $sort_array = CPGPluginAPI::filter('pic_data_sort_array', $sort_array);
1425
1426        $sort_code  = isset($USER['sort']) && $CONFIG['custom_sortorder_thumbs'] ? $USER['sort'] : $CONFIG['default_sort_order'];
1427        $sort_order = isset($sort_array[$sort_code]) ? $sort_array[$sort_code] : $sort_array[$CONFIG['default_sort_order']];
1428
1429        $select_columns = implode(', ', $select_column_list);
1430
1431        $query = "SELECT $select_columns FROM {$CONFIG['TABLE_PICTURES']} AS r
1432                    WHERE ((aid = $album $forbidden_set_string ) $keyword)$approved
1433                    ORDER BY $sort_order
1434                    $limit";
1435
1436        $result = cpg_db_query($query);
1437        $rowset = cpg_db_fetch_rowset($result, true);
1438
1439        if ($flipped) {
1440            $rowset = array_reverse($rowset);
1441        }
1442
1443        // Set picture caption
1444        if ($set_caption) {
1445            if ($CONFIG['display_thumbnail_rating'] == 1) {
1446                build_caption($rowset, array('pic_rating'));
1447            } else {
1448                build_caption($rowset);
1449            }
1450        }
1451        $rowset = CPGPluginAPI::filter('thumb_caption_regular', $rowset);
1452        return $rowset;
1453    }
1454
1455    $meta_album_passto = array (
1456        'album' => $album,
1457        'limit' => $limit,
1458        'set_caption' => $set_caption,
1459    );
1460
1461    $meta_album_params = CPGPluginAPI::filter('meta_album', $meta_album_passto);
1462
1463    if (array_key_exists('album_name', $meta_album_params) && $meta_album_params['album_name']) {
1464
1465        $album_name = $meta_album_params['album_name'];
1466        $count      = $meta_album_params['count'];
1467        $rowset     = $meta_album_params['rowset'];
1468
1469        return $rowset;
1470    }
1471
1472    // Meta albums
1473    switch($album) {
1474
1475    case 'lastcom': // Latest comments
1476
1477        if ($cat && $CURRENT_CAT_NAME) {
1478            $album_name = cpg_fetch_icon('comment', 2) . $album_name = $lang_meta_album_names['lastcom'] . ' - ' . $CURRENT_CAT_NAME;
1479        } else {
1480            $album_name = cpg_fetch_icon('comment', 2) . $lang_meta_album_names['lastcom'];
1481        }
1482
1483        $query = "SELECT COUNT(*)
1484                FROM {$CONFIG['TABLE_COMMENTS']} AS c
1485                INNER JOIN {$CONFIG['TABLE_PICTURES']} AS r ON r.pid = c.pid
1486                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1487                $RESTRICTEDWHERE
1488                AND r.approved = 'YES'
1489                AND c.approval = 'YES'";
1490
1491        $result = cpg_db_query($query);
1492
1493        list($count) = $result->fetchRow(true);
1494
1495        list($ASC, $DESC, $limit, $flipped) = get_pic_data_ordering($count, $limit1, $limit2);
1496
1497        $select_column_list[] = 'UNIX_TIMESTAMP(msg_date) AS msg_date';
1498        $select_column_list[] = 'msg_body';
1499        $select_column_list[] = 'author_id';
1500        $select_column_list[] = 'msg_author';
1501        $select_column_list[] = 'msg_id'; // needed for get_pic_pos()
1502
1503        $select_columns = implode(', ', $select_column_list);
1504
1505        $query = "SELECT $select_columns
1506                FROM {$CONFIG['TABLE_COMMENTS']} AS c
1507                INNER JOIN {$CONFIG['TABLE_PICTURES']} AS r ON r.pid = c.pid
1508                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1509                $RESTRICTEDWHERE
1510                AND r.approved = 'YES'
1511                AND c.approval = 'YES'
1512                ORDER BY msg_id $DESC
1513                $limit";
1514
1515        $result = cpg_db_query($query);
1516        $rowset = cpg_db_fetch_rowset($result, true);
1517
1518        if ($flipped) {
1519            $rowset = array_reverse($rowset);
1520        }
1521
1522        if ($set_caption) {
1523            build_caption($rowset, array('msg_body', 'msg_date'));
1524        }
1525
1526        $rowset = CPGPluginAPI::filter('thumb_caption_lastcom', $rowset);
1527
1528        return $rowset;
1529        break;
1530
1531    case 'lastcomby': // Latest comments by a specific user
1532
1533        if (isset($USER['uid'])) {
1534            $uid = (int) $USER['uid'];
1535        } else {
1536            $uid = -1;
1537        }
1538
1539        $user_name = get_username($uid);
1540
1541        if ($cat && $CURRENT_CAT_NAME) {
1542            $album_name = cpg_fetch_icon('comment', 2) . $album_name = $lang_meta_album_names['lastcom'] . ' - ' . $CURRENT_CAT_NAME . ' - ' . $user_name;
1543        } else {
1544            $album_name = cpg_fetch_icon('comment', 2) . $lang_meta_album_names['lastcom'] . ' - ' . $user_name;
1545        }
1546
1547        $query = "SELECT COUNT(*)
1548                FROM {$CONFIG['TABLE_COMMENTS']} AS c
1549                INNER JOIN {$CONFIG['TABLE_PICTURES']} AS r ON r.pid = c.pid
1550                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1551                $RESTRICTEDWHERE
1552                AND author_id = '$uid'
1553                AND r.approved = 'YES'
1554                AND c.approval = 'YES'";
1555
1556        $result = cpg_db_query($query);
1557
1558        list($count) = $result->fetchRow(true);
1559
1560        list($ASC, $DESC, $limit, $flipped) = get_pic_data_ordering($count, $limit1, $limit2);
1561
1562        $select_column_list[] = 'UNIX_TIMESTAMP(msg_date) AS msg_date';
1563        $select_column_list[] = 'msg_body';
1564        $select_column_list[] = 'author_id';
1565        $select_column_list[] = 'msg_author';
1566        $select_column_list[] = 'msg_id'; // needed for get_pic_pos()
1567
1568        $select_columns = implode(', ', $select_column_list);
1569
1570        $query = "SELECT $select_columns
1571                FROM {$CONFIG['TABLE_COMMENTS']} AS c
1572                INNER JOIN {$CONFIG['TABLE_PICTURES']} AS r ON r.pid = c.pid
1573                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1574                $RESTRICTEDWHERE
1575                AND author_id = '$uid'
1576                AND r.approved = 'YES'
1577                AND c.approval = 'YES'
1578                ORDER BY msg_id $DESC
1579                $limit";
1580
1581        $result = cpg_db_query($query);
1582        $rowset = cpg_db_fetch_rowset($result, true);
1583
1584        if ($set_caption) {
1585            build_caption($rowset, array('msg_body', 'msg_date'));
1586        }
1587
1588        if ($flipped) {
1589            $rowset = array_reverse($rowset);
1590        }
1591
1592        $rowset = CPGPluginAPI::filter('thumb_caption_lastcomby', $rowset);
1593
1594        return $rowset;
1595        break;
1596
1597    case 'lastup': // Latest (most recent) uploads
1598
1599        if ($cat && $CURRENT_CAT_NAME) {
1600            $album_name = cpg_fetch_icon('last_uploads', 2) . $lang_meta_album_names['lastup'] . ' - ' . $CURRENT_CAT_NAME;
1601        } else {
1602            $album_name = cpg_fetch_icon('last_uploads', 2) . $lang_meta_album_names['lastup'];
1603        }
1604
1605        $query = "SELECT COUNT(*)
1606                FROM {$CONFIG['TABLE_PICTURES']} AS r
1607                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1608                $RESTRICTEDWHERE
1609                AND approved = 'YES'";
1610
1611        $result = cpg_db_query($query);
1612
1613        list($count) = $result->fetchRow(true);
1614
1615        list($ASC, $DESC, $limit, $flipped) = get_pic_data_ordering($count, $limit1, $limit2);
1616
1617        $select_columns = implode(', ', $select_column_list);
1618
1619        $query = "SELECT $select_columns
1620                FROM {$CONFIG['TABLE_PICTURES']} AS r
1621                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1622                $RESTRICTEDWHERE
1623                AND approved = 'YES'
1624                ORDER BY ctime $DESC, pid $DESC
1625                $limit";
1626
1627        $result = cpg_db_query($query);
1628        $rowset = cpg_db_fetch_rowset($result, true);
1629
1630        if ($flipped) {
1631            $rowset = array_reverse($rowset);
1632        }
1633
1634        if ($set_caption) {
1635            build_caption($rowset, array('ctime'));
1636        }
1637
1638        $rowset = CPGPluginAPI::filter('thumb_caption_lastup', $rowset);
1639
1640        return $rowset;
1641        break;
1642
1643    case 'lastupby': // Latest (most recent) uploads by a specific user
1644
1645        if (isset($USER['uid'])) {
1646            $uid = (int) $USER['uid'];
1647        } else {
1648            $uid = -1;
1649        }
1650
1651        $user_name = get_username($uid);
1652
1653        if ($cat && $CURRENT_CAT_NAME) {
1654            $album_name = cpg_fetch_icon('last_uploads', 2) . $lang_meta_album_names['lastup'] . ' - ' . $CURRENT_CAT_NAME . ' - ' . $user_name;
1655        } else {
1656            $album_name = cpg_fetch_icon('last_uploads', 2) . $lang_meta_album_names['lastup'] . ' - ' . $user_name;
1657        }
1658
1659        $query = "SELECT COUNT(*)
1660                FROM {$CONFIG['TABLE_PICTURES']} AS r
1661                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1662                $RESTRICTEDWHERE
1663                AND r.owner_id = '$uid'
1664                AND approved = 'YES'";
1665
1666        $result = cpg_db_query($query);
1667
1668        list($count) = $result->fetchRow(true);
1669
1670        list($ASC, $DESC, $limit, $flipped) = get_pic_data_ordering($count, $limit1, $limit2);
1671
1672        $select_columns = implode(', ', $select_column_list);
1673
1674        $query = "SELECT $select_columns
1675                FROM {$CONFIG['TABLE_PICTURES']} AS r
1676                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1677                $RESTRICTEDWHERE
1678                AND r.owner_id = '$uid'
1679                AND approved = 'YES'
1680                ORDER BY ctime $DESC, pid $DESC
1681                $limit";
1682
1683        $result = cpg_db_query($query);
1684        $rowset = cpg_db_fetch_rowset($result, true);
1685
1686        if ($flipped) {
1687            $rowset = array_reverse($rowset);
1688        }
1689
1690        if ($set_caption) {
1691            build_caption($rowset, array('ctime'));
1692        }
1693
1694        $rowset = CPGPluginAPI::filter('thumb_caption_lastupby', $rowset);
1695
1696        return $rowset;
1697        break;
1698
1699    case 'topn': // Most viewed files
1700
1701        if ($cat && $CURRENT_CAT_NAME) {
1702            $album_name = cpg_fetch_icon('most_viewed', 2) . $lang_meta_album_names['topn'] . ' - ' . $CURRENT_CAT_NAME;
1703        } else {
1704            $album_name = cpg_fetch_icon('most_viewed', 2) . $lang_meta_album_names['topn'];
1705        }
1706
1707        $query = "SELECT COUNT(*)
1708                FROM {$CONFIG['TABLE_PICTURES']} AS r
1709                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1710                $RESTRICTEDWHERE
1711                AND approved = 'YES'
1712                AND hits > 0";
1713
1714        $result = cpg_db_query($query);
1715
1716        list($count) = $result->fetchRow(true);
1717
1718        list($ASC, $DESC, $limit, $flipped) = get_pic_data_ordering($count, $limit1, $limit2);
1719
1720        $select_columns = implode(', ', $select_column_list);
1721
1722        $query = "SELECT $select_columns
1723                FROM {$CONFIG['TABLE_PICTURES']} AS r
1724                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1725                $RESTRICTEDWHERE
1726                AND approved = 'YES'
1727                AND hits > 0
1728                ORDER BY hits $DESC, pid $ASC
1729                $limit";
1730
1731        $result = cpg_db_query($query);
1732        $rowset = cpg_db_fetch_rowset($result, true);
1733
1734        if ($flipped) {
1735            $rowset = array_reverse($rowset);
1736        }
1737
1738        if ($set_caption) {
1739            build_caption($rowset, array('hits'));
1740        }
1741
1742        $rowset = CPGPluginAPI::filter('thumb_caption_topn', $rowset);
1743
1744        return $rowset;
1745        break;
1746
1747    case 'toprated': // Top rated pictures
1748
1749        if ($cat && $CURRENT_CAT_NAME) {
1750            $album_name = cpg_fetch_icon('top_rated', 2) . $lang_meta_album_names['toprated'] . ' - ' . $CURRENT_CAT_NAME;
1751        } else {
1752            $album_name = cpg_fetch_icon('top_rated', 2) . $lang_meta_album_names['toprated'];
1753        }
1754
1755        $query = "SELECT COUNT(*)
1756                FROM {$CONFIG['TABLE_PICTURES']} AS r
1757                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1758                $RESTRICTEDWHERE
1759                AND approved = 'YES'
1760                AND r.votes >= '{$CONFIG['min_votes_for_rating']}'";
1761
1762        $result = cpg_db_query($query);
1763
1764        list($count) = $result->fetchRow(true);
1765
1766        list($ASC, $DESC, $limit, $flipped) = get_pic_data_ordering($count, $limit1, $limit2);
1767
1768        $select_columns = implode(', ', $select_column_list);
1769
1770        $query = "SELECT $select_columns
1771                FROM {$CONFIG['TABLE_PICTURES']} AS r
1772                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1773                $RESTRICTEDWHERE
1774                AND approved = 'YES'
1775                AND r.votes >= '{$CONFIG['min_votes_for_rating']}'
1776                ORDER BY pic_rating $DESC, r.votes $DESC, pid $DESC
1777                $limit";
1778
1779        $result = cpg_db_query($query);
1780        $rowset = cpg_db_fetch_rowset($result, true);
1781
1782        if ($flipped) {
1783            $rowset = array_reverse($rowset);
1784        }
1785
1786        if ($set_caption) {
1787            build_caption($rowset, array('pic_rating'));
1788        }
1789
1790        $rowset = CPGPluginAPI::filter('thumb_caption_toprated', $rowset);
1791
1792        return $rowset;
1793        break;
1794
1795    case 'lasthits': // Last viewed files (most recently-viewed files)
1796
1797        if ($cat && $CURRENT_CAT_NAME) {
1798            $album_name = cpg_fetch_icon('last_viewed', 2) . $lang_meta_album_names['lasthits'] . ' - ' . $CURRENT_CAT_NAME;
1799        } else {
1800            $album_name = cpg_fetch_icon('last_viewed', 2) . $lang_meta_album_names['lasthits'];
1801        }
1802
1803        $query = "SELECT COUNT(*)
1804                FROM {$CONFIG['TABLE_PICTURES']} AS r
1805                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1806                $RESTRICTEDWHERE
1807                AND approved = 'YES'
1808                AND hits > 0";
1809
1810        $result = cpg_db_query($query);
1811
1812        list($count) = $result->fetchRow(true);
1813
1814        list($ASC, $DESC, $limit, $flipped) = get_pic_data_ordering($count, $limit1, $limit2);
1815
1816        $select_column_list[] = 'UNIX_TIMESTAMP(mtime) AS mtime';
1817
1818        if (GALLERY_ADMIN_MODE) {
1819            $select_column_list[] = 'lasthit_ip';
1820        }
1821
1822        $select_columns = implode(', ', $select_column_list);
1823
1824        $query = "SELECT $select_columns
1825                FROM {$CONFIG['TABLE_PICTURES']} AS r
1826                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1827                $RESTRICTEDWHERE
1828                AND approved = 'YES'
1829                AND hits > 0
1830                ORDER BY mtime $DESC, pid $ASC
1831                $limit";
1832
1833        $result = cpg_db_query($query);
1834        $rowset = cpg_db_fetch_rowset($result, true);
1835
1836        if ($flipped) {
1837            $rowset = array_reverse($rowset);
1838        }
1839
1840        if ($set_caption) {
1841            build_caption($rowset, array('mtime', 'hits'));
1842        }
1843
1844        $rowset = CPGPluginAPI::filter('thumb_caption_lasthits', $rowset);
1845
1846        return $rowset;
1847        break;
1848
1849    case 'random': // Random files
1850
1851        if ($cat && $CURRENT_CAT_NAME) {
1852            $album_name = cpg_fetch_icon('random', 2) . $lang_meta_album_names['random'] . ' - ' . $CURRENT_CAT_NAME;
1853        } else {
1854            $album_name = cpg_fetch_icon('random', 2) . $lang_meta_album_names['random'];
1855        }
1856
1857        $query = "SELECT COUNT(*)
1858                FROM {$CONFIG['TABLE_PICTURES']} AS r
1859                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1860                $RESTRICTEDWHERE
1861                AND approved = 'YES'";
1862
1863        $result = cpg_db_query($query);
1864
1865        list($count) = $result->fetchRow(true);
1866
1867        $query = "SELECT pid
1868                FROM {$CONFIG['TABLE_PICTURES']} AS r
1869                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1870                $RESTRICTEDWHERE
1871                AND approved = 'YES'
1872                ORDER BY RAND()
1873                $limit";
1874
1875        $result = cpg_db_query($query);
1876
1877        $pidlist = array();
1878        while ($row = $result->fetchAssoc()) {
1879            $pidlist[] = $row['pid'];
1880        }
1881        $result->free();
1882
1883        if (count($pidlist)) {
1884            $select_columns = implode(', ', $select_column_list);
1885
1886            $query = "SELECT $select_columns
1887                    FROM {$CONFIG['TABLE_PICTURES']} AS r
1888                    INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1889                    WHERE pid IN (" . implode(', ', $pidlist) . ")";
1890
1891            $result = cpg_db_query($query);
1892            $rowset = cpg_db_fetch_rowset($result, true);
1893
1894            shuffle($rowset);
1895        } else {
1896            $rowset = array();
1897        }
1898
1899        if ($set_caption) {
1900            build_caption($rowset);
1901        }
1902
1903        $rowset = CPGPluginAPI::filter('thumb_caption_random', $rowset);
1904
1905        return $rowset;
1906        break;
1907
1908    case 'search': // Search results
1909
1910        if (isset($USER['search']['search'])) {
1911            $search_string = $USER['search']['search'];
1912        } else {
1913            $search_string = '';
1914        }
1915
1916        if ($cat && $CURRENT_CAT_NAME) {
1917            $album_name = cpg_fetch_icon('search', 2) . $lang_meta_album_names['search'] . ' - ' . $CURRENT_CAT_NAME;
1918        } else {
1919            $album_name = cpg_fetch_icon('search', 2) . $lang_meta_album_names['search'] . ' - "' . strip_tags($search_string) . '"';
1920        }
1921
1922        include 'include/search.inc.php';
1923
1924        $rowset = CPGPluginAPI::filter('thumb_caption_search', $rowset);
1925
1926        return $rowset;
1927        break;
1928
1929    case 'lastalb': // Last albums to which files have been uploaded
1930
1931        if ($cat && $CURRENT_CAT_NAME) {
1932            $album_name = cpg_fetch_icon('last_created', 2) . $lang_meta_album_names['lastalb'] . ' - ' . $CURRENT_CAT_NAME;
1933        } else {
1934            $album_name = cpg_fetch_icon('last_created', 2) . $lang_meta_album_names['lastalb'];
1935        }
1936
1937        // If $select_column_list includes an 'a.' field, split off into album query and remove from file query
1938        $select_column_list_files = $select_column_list;
1939        $select_column_list_albums = array('r.aid', 'a.thumb', 'a.keyword', 'a.alb_hits', 'a.title', 'ctime');
1940        foreach ($select_column_list_files as $key => $value) {
1941            if (strpos($value,'a.') === 0) {
1942                $select_column_list_albums[] = $value;
1943                unset($select_column_list_files[$key]);
1944            }
1945        }
1946        $select_columns_files = implode(', ', $select_column_list_files);
1947        $select_columns_albums = str_replace('ctime', 'MAX(ctime) AS ctime', implode(', ', $select_column_list_albums));
1948
1949        // Keyword-linked files are not included; only native files are checked for last-updated albums
1950        $query = "SELECT COUNT(*)
1951                FROM {$CONFIG['TABLE_PICTURES']} AS r
1952                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1953                $RESTRICTEDWHERE
1954                AND approved = 'YES'
1955                GROUP BY r.aid";
1956        $result = cpg_db_query($query);
1957        $count = $result->numRows();
1958        $result->free();
1959
1960        $query = "SELECT $select_columns_albums
1961                FROM {$CONFIG['TABLE_PICTURES']} AS r
1962                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
1963                $RESTRICTEDWHERE
1964                AND approved = 'YES'
1965                GROUP BY r.aid
1966                ORDER BY ctime DESC
1967                $limit";
1968        $result = cpg_db_query($query);
1969        $rowset_aid = cpg_db_fetch_rowset($result, true);
1970
1971        // For 'lastalb' album, only use approved photos for album thumbnails
1972        $approved = 'AND approved=\'YES\'';
1973
1974        // Preparation for check if album thumbnail exists
1975        $album_thumbs = array();
1976        foreach ($rowset_aid as $index => $row) {
1977            if ($row['thumb'] > 0) {
1978                $album_thumbs[] = $row['thumb'];
1979            }
1980        }
1981        if (count($album_thumbs)) {
1982            $query = "SELECT pid FROM {$CONFIG['TABLE_PICTURES']} WHERE pid IN (".implode(',', $album_thumbs).")";
1983            $result = cpg_db_query($query);
1984            while ($row = $result->fetchAssoc()) {
1985                $rowset_available_pids[] = $row['pid'];
1986            }
1987            $result->free();
1988        }
1989
1990        $album_thumbs = array();
1991        foreach ($rowset_aid as $index => $row) {
1992
1993            // Check if album thumbnail exists, if not, set to last uploaded
1994            if ($row['thumb'] > 0 && !in_array($row['thumb'], $rowset_available_pids)) {
1995                $row['thumb'] = 0;
1996            }
1997
1998            if ($row['thumb'] > 0) {
1999                $album_thumbs[] = $row['thumb'];
2000            } elseif ($row['thumb'] < 0) {
2001                // random file from album
2002                $keyword = ($row['keyword'] ? "OR (keywords like '%".addslashes($row['keyword'])."%' $forbidden_set_string )" : '');
2003                $query = "SELECT pid FROM {$CONFIG['TABLE_PICTURES']} WHERE ((aid = '{$row['aid']}' $forbidden_set_string) $keyword) $approved ORDER BY RAND() LIMIT 0,1";
2004                $result = cpg_db_query($query);
2005                list($pid_random) = $result->fetchRow(true);
2006                $album_thumbs[] = $pid_random;
2007                $rowset_aid[$index]['thumb'] = $pid_random;
2008            } else {  // thumb = 0
2009                // last uploaded file from album
2010                $keyword = ($row['keyword'] ? "OR (keywords like '%".addslashes($row['keyword'])."%' $forbidden_set_string )" : '');
2011                $query = "SELECT pid FROM {$CONFIG['TABLE_PICTURES']} WHERE ((aid = '{$row['aid']}' $forbidden_set_string) $keyword) $approved ORDER BY ctime DESC LIMIT 0,1";
2012                $result = cpg_db_query($query);
2013                list($pid_lastup) = $result->fetchRow(true);
2014                $album_thumbs[] = $pid_lastup;
2015                $rowset_aid[$index]['thumb'] = $pid_lastup;
2016            }
2017        }
2018
2019        if (!$album_thumbs) {
2020            $rowset = array();
2021        } else {
2022            $album_thumbs_set = implode(',', array_unique($album_thumbs));
2023            $query = "SELECT $select_columns_files
2024                    FROM {$CONFIG['TABLE_PICTURES']} AS r
2025                    WHERE approved = 'YES'
2026                    AND r.pid IN ($album_thumbs_set)";
2027            $result = cpg_db_query($query);
2028            $rowset_pid = cpg_db_fetch_rowset($result, true);
2029
2030            $rowset_pid_indexed = array();
2031            foreach ($rowset_pid as $row) {
2032                $rowset_pid_indexed[$row['pid']] = $row;
2033            }
2034            $rowset = array();
2035            foreach ($rowset_aid as $row) {
2036                $rowset[] = is_array($rowset_pid_indexed[$row['thumb']]) ? array_merge($rowset_pid_indexed[$row['thumb']], $row) : $row;
2037            }
2038
2039            if ($set_caption) {
2040                build_caption($rowset, array('ctime'), 'albums');
2041            }
2042        }
2043
2044        $rowset = CPGPluginAPI::filter('thumb_caption_lastalb', $rowset);
2045
2046        return $rowset;
2047        break;
2048
2049    case 'favpics': // Favorite Files
2050
2051        $album_name = cpg_fetch_icon('favorites', 2) . $lang_meta_album_names['favpics'];
2052
2053        $rowset = array();
2054
2055        if (count($FAVPICS) > 0) {
2056
2057            $favs = implode(', ', $FAVPICS);
2058
2059            $query = "SELECT COUNT(*)
2060                            FROM {$CONFIG['TABLE_PICTURES']} AS r
2061                            INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
2062                            $RESTRICTEDWHERE
2063                            AND approved = 'YES'
2064                            AND pid IN ($favs)";
2065
2066            $result = cpg_db_query($query);
2067
2068            list($count) = $result->fetchRow(true);
2069
2070            $select_columns = implode(', ', $select_column_list);
2071
2072            $query = "SELECT $select_columns
2073                            FROM {$CONFIG['TABLE_PICTURES']} AS r
2074                            INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
2075                            $RESTRICTEDWHERE
2076                            AND approved = 'YES'
2077                            AND pid IN ($favs)
2078                            ORDER BY pid ASC
2079                            $limit";
2080
2081            $result = cpg_db_query($query);
2082            $rowset = cpg_db_fetch_rowset($result, true);
2083
2084            if ($set_caption) {
2085                build_caption($rowset, array('ctime'));
2086            }
2087        }
2088
2089        $rowset = CPGPluginAPI::filter('thumb_caption_favpics', $rowset);
2090
2091        return $rowset;
2092        break;
2093
2094    case 'datebrowse': // Browsing by uploading date
2095
2096        // Using getRaw():  The date is sanitized in the called function
2097        $date = $superCage->get->keyExists('date') ? cpgValidateDate($superCage->get->getRaw('date')) : null;
2098
2099        $album_name = cpg_fetch_icon('calendar', 2) . $lang_common['date'] . ': ' . $date;
2100
2101        $rowset = array();
2102
2103        $query = "SELECT COUNT(*)
2104                FROM {$CONFIG['TABLE_PICTURES']} AS r
2105                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
2106                $RESTRICTEDWHERE
2107                AND approved = 'YES'
2108                AND substring(from_unixtime(ctime),1,10) = '" . substr($date, 0, 10) . "'";
2109
2110        $result = cpg_db_query($query);
2111
2112        list($count) = $result->fetchRow(true);
2113
2114        list($ASC, $DESC, $limit, $flipped) = get_pic_data_ordering($count, $limit1, $limit2);
2115
2116        $select_columns = implode(', ', $select_column_list);
2117
2118        $query = "SELECT $select_columns
2119                FROM {$CONFIG['TABLE_PICTURES']} AS r
2120                INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS a ON a.aid = r.aid
2121                $RESTRICTEDWHERE
2122                AND approved = 'YES'
2123                AND substring(from_unixtime(ctime),1,10) = '" . substr($date, 0, 10) . "'
2124                ORDER BY ctime $ASC, pid $ASC
2125                $limit";
2126
2127        $result = cpg_db_query($query);
2128        $rowset = cpg_db_fetch_rowset($result, true);
2129
2130        if ($flipped) {
2131            $rowset = array_reverse($rowset);
2132        }
2133
2134        if ($set_caption) {
2135            build_caption($rowset, array('ctime'));
2136        }
2137
2138        return $rowset;
2139        break;
2140    } // switch
2141} // function get_pic_data
2142
2143// Copy of get_pic_data, created to obtain position for the given pid in the given album
2144function get_pic_pos($album, $pid)
2145{
2146    global $USER, $CONFIG, $CURRENT_ALBUM_KEYWORD, $FORBIDDEN_SET_DATA, $USER_DATA;
2147    global $RESTRICTEDWHERE, $FORBIDDEN_SET;
2148    global $lang_errors;
2149
2150    // Regular albums
2151    if (is_numeric($album)) {
2152
2153        if (count($FORBIDDEN_SET_DATA) > 0) {
2154            $forbidden_set_string = ' AND aid NOT IN (' . implode(', ', $FORBIDDEN_SET_DATA) . ')';
2155        } else {
2156            $forbidden_set_string = '';
2157        }
2158
2159        $album_name_keyword = get_album_name($album);
2160        //$album_name         = $album_name_keyword['title'];
2161        $album_keyword      = addslashes($album_name_keyword['keyword']);
2162
2163        if (!empty($album_keyword)) {
2164            $keyword = "OR (keywords like '%$album_keyword%' $forbidden_set_string )";
2165        } else {
2166            $keyword = '';
2167        }
2168
2169        $approved = GALLERY_ADMIN_MODE ? '' : 'AND approved=\'YES\'';
2170
2171        $result = cpg_db_query("SELECT filename, title, pid, position, ctime FROM {$CONFIG['TABLE_PICTURES']} WHERE pid = $pid");
2172        if (!$result->numRows()) cpg_die(ERROR, $lang_errors['non_exist_ap'], __FILE__, __LINE__);
2173        $pic = $result->fetchAssoc(true);
2174        $pic['title'] = cpg_db_escape_string($pic['title']);
2175
2176        $sort_array = array(
2177            'na' => "(filename < '{$pic['filename']}' OR filename = '{$pic['filename']}' AND pid < {$pic['pid']})",
2178            'nd' => "(filename > '{$pic['filename']}' OR filename = '{$pic['filename']}' AND pid > {$pic['pid']})",
2179            'ta' => "(title < '{$pic['title']}' OR title = '{$pic['title']}' AND pid < {$pic['pid']})",
2180            'td' => "(title > '{$pic['title']}' OR title = '{$pic['title']}' AND pid > {$pic['pid']})",
2181            'da' => "(ctime < '{$pic['ctime']}' OR ctime = '{$pic['ctime']}' AND pid < {$pic['pid']})",
2182            'dd' => "(ctime > '{$pic['ctime']}' OR ctime = '{$pic['ctime']}' AND pid > {$pic['pid']})",
2183            'pa' => "(position < {$pic['position']} OR position = {$pic['position']} AND pid < {$pic['pid']})",
2184            'pd' => "(position > {$pic['position']} OR position = {$pic['position']} AND pid > {$pic['pid']})",
2185        );
2186        list($sort_array) = CPGPluginAPI::filter('pic_pos_sort_array', array($sort_array, $pid));
2187
2188        $sort_code  = isset($USER['sort']) && $CONFIG['custom_sortorder_thumbs'] ? $USER['sort'] : $CONFIG['default_sort_order'];
2189        $sort_order = isset($sort_array[$sort_code]) ? $sort_array[$sort_code] : $sort_array[$CONFIG['default_sort_order']];
2190
2191        $query = "SELECT COUNT(*) FROM {$CONFIG['TABLE_PICTURES']}
2192                    WHERE ((aid='$album' $forbidden_set_string) $keyword) $approved
2193                    AND $sort_order";
2194
2195        $result = cpg_db_query($query);
2196
2197        list($pos) = $result->fetchRow(true);
2198
2199        return $pos;
2200    }
2201
2202    // Meta albums
2203    switch($album) {
2204
2205    case 'lastcom': // Latest comments
2206
2207        $superCage = Inspekt::makeSuperCage();
2208
2209        if (!$superCage->get->getInt('msg_id')) {
2210            cpg_die(ERROR, $lang_errors['param_missing'], __FILE__, __LINE__);
2211        }
2212
2213        $query = "SELECT COUNT(*) FROM {$CONFIG['TABLE_PICTURES']} AS p
2214            INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS r ON r.aid = p.aid
2215            INNER JOIN {$CONFIG['TABLE_COMMENTS']} AS c ON c.pid = p.pid
2216            $RESTRICTEDWHERE
2217            AND approved = 'YES'
2218            AND approval = 'YES'
2219            AND msg_id > ".$superCage->get->getInt('msg_id');
2220
2221            $result = cpg_db_query($query);
2222
2223            list($pos) = $result->fetchRow(true);
2224
2225        return $pos;
2226        break;
2227
2228    case 'lastcomby': // Latest comments by a specific user
2229
2230        if (isset($USER['uid'])) {
2231            $uid = (int) $USER['uid'];
2232        } else {
2233            $uid = -1;
2234        }
2235
2236        $superCage = Inspekt::makeSuperCage();
2237
2238        if (!$superCage->get->getInt('msg_id')) {
2239            cpg_die(ERROR, $lang_errors['param_missing'], __FILE__, __LINE__);
2240        }
2241
2242        $query = "SELECT COUNT(*) FROM {$CONFIG['TABLE_PICTURES']} AS p
2243            INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS r ON r.aid = p.aid
2244            INNER JOIN {$CONFIG['TABLE_COMMENTS']} AS c ON c.pid = p.pid
2245            $RESTRICTEDWHERE
2246            AND author_id = $uid
2247            AND approved = 'YES'
2248            AND approval = 'YES'
2249            AND msg_id > ".$superCage->get->getInt('msg_id');
2250
2251            $result = cpg_db_query($query);
2252
2253            list($pos) = $result->fetchRow(true);
2254
2255        return $pos;
2256        break;
2257
2258    case 'lastup': // Latest (most recent) uploads
2259
2260        $query = "SELECT ctime FROM {$CONFIG['TABLE_PICTURES']} WHERE pid = $pid";
2261        $result = cpg_db_query($query);
2262        if (!$result->numRows()) cpg_die(ERROR, $lang_errors['non_exist_ap'], __FILE__, __LINE__);
2263        $ctime = $result->result(0, 0, true);
2264
2265        $query = "SELECT COUNT(*) FROM {$CONFIG['TABLE_PICTURES']} AS p
2266            INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS r ON r.aid = p.aid
2267            $RESTRICTEDWHERE
2268            AND approved = 'YES'
2269            AND (ctime > $ctime
2270            OR ctime = $ctime AND pid > $pid)";
2271
2272            $result = cpg_db_query($query);
2273
2274            list($pos) = $result->fetchRow(true);
2275
2276        return $pos;
2277        break;
2278
2279    case 'lastupby': // Latest (most recent) uploads by a specific user
2280
2281        if (isset($USER['uid'])) {
2282            $uid = (int) $USER['uid'];
2283        } else {
2284            $uid = -1;
2285        }
2286
2287        $query = "SELECT ctime FROM {$CONFIG['TABLE_PICTURES']} WHERE pid = $pid";
2288        $result = cpg_db_query($query);
2289        if (!$result->numRows()) cpg_die(ERROR, $lang_errors['non_exist_ap'], __FILE__, __LINE__);
2290        $ctime = $result->result(0, 0, true);
2291
2292        $query = "SELECT COUNT(*) FROM {$CONFIG['TABLE_PICTURES']} AS p
2293            INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS r ON r.aid = p.aid
2294            $RESTRICTEDWHERE
2295            AND p.owner_id = $uid
2296            AND approved = 'YES'
2297            AND (ctime > $ctime
2298            OR ctime = $ctime AND pid > $pid)";
2299
2300            $result = cpg_db_query($query);
2301
2302            list($pos) = $result->fetchRow(true);
2303
2304        return $pos;
2305        break;
2306
2307    case 'topn': // Most viewed files
2308
2309        $query = "SELECT hits FROM {$CONFIG['TABLE_PICTURES']} WHERE pid = $pid";
2310        $result = cpg_db_query($query);
2311        if (!$result->numRows()) cpg_die(ERROR, $lang_errors['non_exist_ap'], __FILE__, __LINE__);
2312        $hits = $result->result(0, 0, true);
2313
2314        $query = "SELECT COUNT(*) FROM {$CONFIG['TABLE_PICTURES']} AS p
2315            INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS r ON r.aid = p.aid
2316            $RESTRICTEDWHERE
2317            AND approved = 'YES'
2318            AND (hits > $hits
2319            OR hits = $hits AND pid < $pid)";
2320
2321            $result = cpg_db_query($query);
2322
2323            list($pos) = $result->fetchRow(true);
2324
2325        return $pos;
2326        break;
2327
2328    case 'toprated': // Top rated pictures
2329
2330        $query = "SELECT pic_rating, votes FROM {$CONFIG['TABLE_PICTURES']} WHERE pid = $pid";
2331        $result = cpg_db_query($query);
2332        if (!$result->numRows()) cpg_die(ERROR, $lang_errors['non_exist_ap'], __FILE__, __LINE__);
2333        list($pic_rating, $votes) = $result->fetchRow(true);
2334
2335        $query = "SELECT COUNT(*) FROM {$CONFIG['TABLE_PICTURES']} AS p
2336            INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS r ON r.aid = p.aid
2337            $RESTRICTEDWHERE
2338            AND approved = 'YES'
2339            AND p.votes >= '{$CONFIG['min_votes_for_rating']}'
2340            AND (pic_rating > $pic_rating
2341            OR (pic_rating = $pic_rating AND p.votes > $votes)
2342            OR (pic_rating = $pic_rating AND p.votes = $votes AND pid > $pid))";
2343
2344            $result = cpg_db_query($query);
2345
2346            list($pos) = $result->fetchRow(true);
2347
2348        return $pos;
2349        break;
2350
2351    case 'lasthits': // Last viewed files (most recently-viewed files)
2352
2353        $query = "SELECT mtime FROM {$CONFIG['TABLE_PICTURES']} WHERE pid = $pid";
2354        $result = cpg_db_query($query);
2355        if (!$result->numRows()) cpg_die(ERROR, $lang_errors['non_exist_ap'], __FILE__, __LINE__);
2356        $mtime = $result->result(0, 0, true);
2357
2358        $query = "SELECT COUNT(*) FROM {$CONFIG['TABLE_PICTURES']} AS p
2359            INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS r ON r.aid = p.aid
2360            $RESTRICTEDWHERE
2361            AND approved = 'YES'
2362            AND hits > 0
2363            AND (mtime > '$mtime'
2364            OR mtime = '$mtime' AND pid < $pid)";
2365
2366            $result = cpg_db_query($query);
2367
2368            list($pos) = $result->fetchRow(true);
2369
2370        return $pos;
2371        break;
2372
2373    case 'search': // Search results
2374        $superCage = Inspekt::makeSuperCage();
2375
2376        if (isset($USER['search']['search'])) {
2377            $search_string = $USER['search']['search'];
2378        } else {
2379            $search_string = '';
2380        }
2381
2382        $get_pic_pos = true;
2383        include 'include/search.inc.php';
2384
2385        return $pos;
2386        break;
2387
2388    case 'favpics': // Favorite Files
2389
2390        global $FAVPICS;
2391
2392        if (empty($FAVPICS)) {
2393            return 0;
2394        }
2395
2396        $favs = implode(', ', $FAVPICS);
2397
2398        $query = "SELECT COUNT(*) FROM {$CONFIG['TABLE_PICTURES']} AS p
2399            INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS r ON r.aid = p.aid
2400            $RESTRICTEDWHERE
2401            AND approved = 'YES'
2402            AND pid IN ($favs)
2403            AND pid < $pid";
2404
2405            $result = cpg_db_query($query);
2406
2407            list($pos) = $result->fetchRow(true);
2408
2409        return $pos;
2410        break;
2411
2412    case 'datebrowse': // Browsing by uploading date
2413
2414        $superCage = Inspekt::makeSuperCage();
2415        // Using getRaw():  The date is sanitized in the called function
2416        $date = $superCage->get->keyExists('date') ? cpgValidateDate($superCage->get->getRaw('date')) : null;
2417
2418        $query = "SELECT COUNT(*) FROM {$CONFIG['TABLE_PICTURES']} AS p
2419            INNER JOIN {$CONFIG['TABLE_ALBUMS']} AS r ON r.aid = p.aid
2420            $RESTRICTEDWHERE
2421            AND approved = 'YES'
2422            AND substring(from_unixtime(ctime),1,10) = '" . substr($date, 0, 10) . "'
2423            AND pid < $pid";
2424
2425            $result = cpg_db_query($query);
2426
2427            list($pos) = $result->fetchRow(true);
2428
2429        return $pos;
2430        break;
2431
2432
2433    default : // Invalid/custom meta album
2434        $pos = CPGPluginAPI::filter('meta_album_get_pic_pos', $album);
2435        if (is_numeric($pos)) {
2436            return $pos; // Custom meta album
2437        } else {
2438            return FALSE; // Invalid meta album
2439        }
2440
2441    } // switch
2442} // function get_pic_pos
2443
2444// Get the name of an album
2445
2446/**
2447 * get_album_name()
2448 *
2449 * @param $aid
2450 * @return
2451 **/
2452
2453function get_album_name($aid)
2454{
2455    global $CONFIG;
2456    global $lang_errors;
2457
2458    $result = cpg_db_query("SELECT title, keyword FROM {$CONFIG['TABLE_ALBUMS']} WHERE aid = $aid");
2459
2460    $count = $result->numRows();
2461
2462    if ($count > 0) {
2463        $row = $result->fetchAssoc(true);
2464        return $row;
2465    } else {
2466        cpg_die(ERROR, $lang_errors['non_exist_ap'], __FILE__, __LINE__);
2467    }
2468} // function get_album_name
2469
2470
2471// Return the name of a user
2472
2473/**
2474 * get_username()
2475 *
2476 * @param $uid
2477 * @return
2478 **/
2479function get_username($uid)
2480{
2481    global $cpg_udb;
2482
2483    $uid = (int) $uid;
2484
2485    if (!$uid) {
2486        return 'Anonymous';
2487    } elseif (defined('UDB_INTEGRATION')) {
2488        return $cpg_udb->get_user_name($uid);
2489    }
2490} // function get_username
2491
2492
2493// Return the ID of a user
2494
2495/**
2496 * get_userid()
2497 *
2498 * @param $username
2499 * @return
2500 **/
2501function get_userid($username)
2502{
2503    global $cpg_udb;
2504
2505    $username = addslashes($username);
2506
2507    if (!$username) {
2508        return 0;
2509    } elseif (defined('UDB_INTEGRATION')) {
2510        return $cpg_udb->get_user_id($username);
2511    }
2512}
2513
2514// get number of pending approvals
2515
2516/**
2517 * cpg_get_pending_approvals()
2518 *
2519 * @return
2520 **/
2521function cpg_get_pending_approvals()
2522{
2523    global $CONFIG;
2524
2525    $result = cpg_db_query("SELECT COUNT(*) FROM {$CONFIG['TABLE_PICTURES']} WHERE approved = 'NO'");
2526
2527    list($count) = $result->fetchRow(true);
2528
2529    return $count;
2530}
2531
2532// Return the total number of comments for a certain picture
2533
2534/**
2535 * count_pic_comments()
2536 *
2537 * @param $pid
2538 * @param integer $skip
2539 * @return
2540 **/
2541function count_pic_comments($pid, $skip = 0)
2542{
2543    global $CONFIG;
2544
2545    $sql = "SELECT COUNT(*) FROM {$CONFIG['TABLE_COMMENTS']} WHERE pid = $pid";
2546
2547    if ($skip) {
2548        $sql .= " AND msg_id != $skip";
2549    }
2550
2551    $result = cpg_db_query($sql);
2552
2553    list($count) = $result->fetchRow(true);
2554
2555    return $count;
2556}
2557
2558/******************
2559/**
2560 * cpg_determine_client()
2561 *
2562 * @param
2563 * @return $return_array
2564 **/
2565function cpg_determine_client()
2566{
2567    //Making Cage
2568    $superCage = Inspekt::makeSuperCage();
2569
2570    /**
2571     * Populate the client stats
2572     */
2573
2574    // Get the details of user browser, IP, OS, etc
2575    $server_agent = $superCage->server->getRaw('HTTP_USER_AGENT');
2576
2577    $os = 'Unknown';
2578    if (preg_match('#Ubuntu#i', $server_agent)) {
2579        $os = 'Linux Ubuntu';
2580    } elseif (preg_match('#Debian#i', $server_agent)) {
2581        $os = 'Linux Debian';
2582    } elseif (preg_match('#CentOS#i', $server_agent)) {
2583        $os = 'Linux CentOS';
2584    } elseif (preg_match('#Fedora#i', $server_agent)) {
2585        $os = 'Linux Fedora';
2586    } elseif (preg_match('#Mandrake#i', $server_agent)) {
2587        $os = 'Linux Mandrake';
2588    } elseif (preg_match('#RedHat#i', $server_agent)) {
2589        $os = 'Linux RedHat';
2590    } elseif (preg_match('#Suse#i', $server_agent)) {
2591        $os = 'Linux Suse';
2592    } elseif (preg_match('#Linux#i', $server_agent)) {
2593        $os = 'Linux';
2594    } elseif (preg_match('#Windows NT 5.0#i', $server_agent)) {
2595        $os = 'Windows 2000';
2596    } elseif (preg_match('#win98|Windows 98#i', $server_agent)) {
2597        $os = 'Windows 98';
2598    } elseif (preg_match('#Windows NT 5\.1#i', $server_agent)) {
2599        $os = 'Windows XP';
2600    } elseif (preg_match('#Windows NT 5\.2#i', $server_agent)) {
2601        $os = 'Windows 2003 Server';
2602    } elseif (preg_match('#Windows NT 6\.0#i', $server_agent)) {
2603        $os = 'Windows Vista';
2604    } elseif (preg_match('#Windows NT 6\.1#i', $server_agent)) {
2605        $os = 'Windows 7';
2606    } elseif (preg_match('#Windows NT 6\.2#i', $server_agent)) {
2607        $os = 'Windows 8';
2608    } elseif (preg_match('#Windows CE#i', $server_agent)) {
2609        $os = 'Windows CE';
2610    } elseif (preg_match('#Windows#i', $server_agent)) {
2611        $os = 'Windows';
2612    } elseif (preg_match('#SunOS#i', $server_agent)) {
2613        $os = 'Sun OS';
2614    } elseif (preg_match('#Macintosh#i', $server_agent)) {
2615        $os = 'Macintosh';
2616    } elseif (preg_match('#Mac_PowerPC#i', $server_agent)) {
2617        $os = 'Mac OS';
2618    } elseif (preg_match('#Mac_PPC#i', $server_agent)) {
2619        $os = 'Macintosh';
2620    } elseif (preg_match('#OS/2#i', $server_agent)) {
2621        $os = 'OS/2';
2622    } elseif (preg_match('#aix#i', $server_agent)) {
2623        $os = 'aix';
2624    } elseif (preg_match('#FreeBSD#i', $server_agent)) {
2625        $os = 'BSD FreeBSD';
2626    } elseif (preg_match('#Unix#i', $server_agent)) {
2627        $os = 'Unix';
2628    } elseif (preg_match('#iphone#i', $server_agent)) {
2629        $os = 'iPhone';
2630    } elseif (preg_match('#Nintendo Wii#i', $server_agent)) {
2631        $os = 'Nintendo Wii';
2632    } elseif (preg_match('#PalmOS#i', $server_agent)) {
2633        $os = 'PalmOS';
2634    } elseif (preg_match('#Symbian#i', $server_agent)) {
2635        $os = 'Symbian';
2636    } elseif (preg_match('#PLAYSTATION 3#i', $server_agent)) {
2637        $os = 'Playstation 3';
2638    } elseif (preg_match('#PlayStation Portable#i', $server_agent)) {
2639        $os = 'Playstation Portable';
2640    } elseif (preg_match('#Playstation#i', $server_agent)) {
2641        $os = 'Playstation';
2642    } elseif (preg_match('#Inferno#i', $server_agent)) {
2643        $os = 'Inferno';
2644    } elseif (preg_match('#BeOS#i', $server_agent)) {
2645        $os = 'beOS';
2646    }
2647
2648
2649
2650    $browser = 'Unknown';
2651    if (preg_match('#MSIE#i', $server_agent)) {
2652        if (preg_match('#MSIE 10\.0#i', $server_agent)) {
2653            $browser = 'IE10';
2654        } elseif (preg_match('#MSIE 9\.0#i', $server_agent)) {
2655            $browser = 'IE9';
2656        } elseif (preg_match('#MSIE 8\.0#i', $server_agent)) {
2657            $browser = 'IE8';
2658        } elseif (preg_match('#MSIE 7\.0#i', $server_agent)) {
2659            $browser = 'IE7';
2660        } elseif (preg_match('#MSIE 6\.0#i', $server_agent)) {
2661            $browser = 'IE6';
2662        } elseif (preg_match('#MSIE 5\.5#i', $server_agent)) {
2663            $browser = 'IE5.5';
2664        } elseif (preg_match('#MSIE 5\.0#i', $server_agent)) {
2665            $browser = 'IE5.0';
2666        } elseif (preg_match('#MSIE 4\.0#i', $server_agent)) {
2667            $browser = 'IE4';
2668        } elseif (preg_match('#MSIE 3\.0#i', $server_agent)) {
2669            $browser = 'IE3';
2670        } else {
2671            $browser = 'IE';
2672        }
2673    } elseif (preg_match('#Nitro#i', $server_agent)) {
2674        $browser = 'Nintendo DS';
2675    } elseif (preg_match('#Nokia#i', $server_agent)) {
2676        $browser = 'Nokia';
2677    } elseif (preg_match('#iPhone#i', $server_agent)) {
2678        $browser = 'iPhone';
2679    } elseif (preg_match('#Epiphany#i', $server_agent)) {
2680        $browser = 'Epiphany';
2681    } elseif (preg_match('#Flock#i', $server_agent)) {
2682        $browser = 'Flock';
2683    } elseif (preg_match('#SeaMonkey#i', $server_agent)) {
2684        $browser = 'SeaMonkey';
2685    } elseif (preg_match('#Phoenix#i', $server_agent)) {
2686        $browser = 'Phoenix';
2687    } elseif (preg_match('#Firebird#i', $server_agent)) {
2688        $browser = 'Mozilla Firebird';
2689    } elseif (preg_match('#NetSurf#i', $server_agent)) {
2690        $browser = 'NetSurf';
2691    } elseif (preg_match('#netscape#i', $server_agent)) {
2692        $browser = 'Netscape';
2693    } elseif (preg_match('#Chrome#i', $server_agent)) {
2694        $browser = 'Chrome';
2695    } elseif (preg_match('#Firefox#i', $server_agent)) {
2696        $browser = 'Firefox';
2697    } elseif (preg_match('#Galeon#i', $server_agent)) {
2698        $browser = 'Galeon';
2699    } elseif (preg_match('#Camino#i', $server_agent)) {
2700        $browser = 'Camino';
2701    } elseif (preg_match('#Konqueror#i', $server_agent)) {
2702        $browser = 'Konqueror';
2703    } elseif (preg_match('#Cheshire#i', $server_agent)) {
2704        $browser = 'AOL';
2705    } elseif (preg_match('#Safari#i', $server_agent)) {
2706        $browser = 'Safari';
2707    } elseif (preg_match('#OmniWeb#i', $server_agent)) {
2708        $browser = 'OmniWeb';
2709    } elseif (preg_match('#Opera#i', $server_agent)) {
2710        $browser = 'Opera';
2711    } elseif (preg_match('#HTTrack#i', $server_agent)) {
2712        $browser = 'HTTrack';
2713    } elseif (preg_match('#OffByOne#i', $server_agent)) {
2714        $browser = 'Off By One';
2715    } elseif (preg_match('#amaya#i', $server_agent)) {
2716        $browser = 'Amaya';
2717    } elseif (preg_match('#iCab#i', $server_agent)) {
2718        $browser = 'iCab';
2719    } elseif (preg_match('#Lynx#i', $server_agent)) {
2720        $browser = 'Lynx';
2721    } elseif (preg_match('#Googlebot#i', $server_agent)) {
2722        $browser = 'Googlebot';
2723    } elseif (preg_match('#Lycos_Spider#i', $server_agent)) {
2724        $browser = 'Lycos Spider';
2725    } elseif (preg_match('#Firefly#i', $server_agent)) {
2726        $browser = 'Fireball Spider';
2727    } elseif (preg_match('#Amiga-AWeb#i', $server_agent)) {
2728        $browser = 'AWeb';
2729    } elseif (preg_match('#Cyberdog#i', $server_agent)) {
2730        $browser = 'Cyberdog';
2731    } elseif (preg_match('#Dillo#i', $server_agent)) {
2732        $browser = 'Dillo';
2733    } elseif (preg_match('#DreamPassport#i', $server_agent)) {
2734        $browser = 'DreamCast';
2735    } elseif (preg_match('#eCatch#i', $server_agent)) {
2736        $browser = 'eCatch';
2737    } elseif (preg_match('#ANTFresco#i', $server_agent)) {
2738        $browser = 'Fresco';
2739    } elseif (preg_match('#RSS#i', $server_agent)) {
2740        $browser = 'RSS';
2741    } elseif (preg_match('#Avant#i', $server_agent)) {
2742        $browser = 'Avant';
2743    } elseif (preg_match('#HotJava#i', $server_agent)) {
2744        $browser = 'HotJava';
2745    } elseif (preg_match('#W3C-checklink|W3C_Validator|Jigsaw#i', $server_agent)) {
2746        $browser = 'W3C';
2747    } elseif (preg_match('#K-Meleon#i', $server_agent)) {
2748        $browser = 'K-Meleon';
2749    } elseif (preg_match('#Iceape#i', $server_agent)) {
2750        $browser = 'Iceape';
2751    } elseif (preg_match('#Iceweasel#i', $server_agent)) {
2752        $browser = 'Iceweasel';
2753    } elseif (preg_match('#Kazehakase#i', $server_agent)) {
2754        $browser = 'Kazehakase';
2755    } elseif (preg_match('#Minefield#i', $server_agent)) {
2756        $browser = 'Firefox';
2757    } elseif (preg_match('#Namoroka#i', $server_agent)) {
2758        $browser = 'Firefox';
2759    } elseif (preg_match('#MC680x0#i', $server_agent)) {
2760        $browser = 'Amiga Voyager';
2761    } elseif (preg_match('#AOL #i', $server_agent)) {
2762        $browser = 'AOL';
2763    } elseif (preg_match('#Beonex#i', $server_agent)) {
2764        $browser = 'Beonex';
2765    } elseif (preg_match('#BonEcho#i', $server_agent)) {
2766        $browser = 'Mozilla';
2767    } elseif (preg_match('#Charon#i', $server_agent)) {
2768        $browser = 'Charon';
2769    } elseif (preg_match('#Chimera#i', $server_agent)) {
2770        $browser = 'Chimera';
2771    } elseif (preg_match('#Crazy Browser#i', $server_agent)) {
2772        $browser = 'Crazy Browser';
2773    } elseif (preg_match('#Fennec#i', $server_agent)) {
2774        $browser = 'Firefox';
2775    } elseif (preg_match('#iNet Browser#i', $server_agent)) {
2776        $browser = 'iNet';
2777    } elseif (preg_match('#iSonyEricsson#i', $server_agent)) {
2778        $browser = 'Sony Ericsson';
2779    } elseif (preg_match('#MAXTHON#i', $server_agent)) {
2780        $browser = 'Maxthon';
2781    } elseif (preg_match('#NCSA Mosaic#i', $server_agent)) {
2782        $browser = 'Mosaic';
2783    } elseif (preg_match('#NetNewsWire#i', $server_agent)) {
2784        $browser = 'NetNewsWire';
2785    } elseif (preg_match('#NetPositive#i', $server_agent)) {
2786        $browser = 'NetPositive';
2787    } elseif (preg_match('#Shiira#i', $server_agent)) {
2788        $browser = 'Shiira';
2789    } elseif (preg_match('#Shiretoko#i', $server_agent)) {
2790        $browser = 'Firefox';
2791    } elseif (preg_match('#Sleipnir#i', $server_agent)) {
2792        $browser = 'Sleipnir';
2793    } elseif (preg_match('#Stainless#i', $server_agent)) {
2794        $browser = 'Stainless';
2795    } elseif (preg_match('#Sunrise#i', $server_agent)) {
2796        $browser = 'Sunrise';
2797    }
2798    // Information partially taken from http://www.useragentstring.com/
2799
2800    //Code to get the search string if the referrer is any of the following
2801    $search_engines = array(
2802        'google',
2803        'lycos',
2804        'yahoo'
2805    );
2806
2807    $query_array = array();
2808    foreach ($search_engines as $engine) {
2809        if (is_referer_search_engine($engine)) {
2810            $query_array = get_search_query_terms($engine);
2811            break;
2812        }
2813    }
2814    $query_terms = is_array($query_array) ? implode(',', $query_array) : '';
2815
2816    $return_array = array(
2817        'os' => $os,
2818        'browser' => $browser,
2819        'query_terms' => $query_terms
2820    );
2821
2822    return $return_array;
2823}
2824
2825
2826// Add 1 everytime a picture is viewed.
2827
2828/**
2829 * add_hit()
2830 *
2831 * @param $pid
2832 * @return
2833 **/
2834function add_hit($pid)
2835{
2836    global $CONFIG, $raw_ip;
2837
2838    if ($CONFIG['count_file_hits']) {
2839        cpg_db_query("UPDATE {$CONFIG['TABLE_PICTURES']} SET hits = hits + 1, lasthit_ip = '$raw_ip', mtime = CURRENT_TIMESTAMP WHERE pid = $pid");
2840    }
2841
2842    /**
2843     * Code to record the details of hits for the picture, if the option is set in CONFIG
2844     */
2845
2846    if ($CONFIG['hit_details']) {
2847
2848        // Get the details of user browser, IP, OS, etc
2849        $client_details = cpg_determine_client();
2850        $search_phrase = addslashes($client_details['query_terms']);
2851
2852        //Making Cage
2853        $superCage = Inspekt::makeSuperCage();
2854
2855        $time = time();
2856
2857        //Sanitize the referer
2858        if ($superCage->server->keyExists('HTTP_REFERER')) {
2859            $referer = $superCage->server->getEscaped('HTTP_REFERER');
2860        } else {
2861            $referer = '';
2862        }
2863
2864        $hitUserId = USER_ID;
2865
2866        // Insert the record in database
2867        $query = "INSERT INTO {$CONFIG['TABLE_HIT_STATS']} SET"
2868            ." pid = $pid,"
2869            ." search_phrase = '$search_phrase',"
2870            ." Ip   = '$raw_ip',"
2871            ." sdate = '$time',"
2872            ." referer='$referer',"
2873            ." browser = '{$client_details['browser']}',"
2874            ." os = '{$client_details['os']}',"
2875            ." uid ='$hitUserId'";
2876        cpg_db_query($query);
2877    }
2878}
2879
2880/**
2881 * add_album_hit()
2882 * Add a hit to the album.
2883 * @param $pid
2884 * @return
2885 **/
2886function add_album_hit($aid)
2887{
2888    global $CONFIG;
2889
2890    if ($CONFIG['count_album_hits']) {
2891        $aid = (int) $aid;
2892        cpg_db_query("UPDATE {$CONFIG['TABLE_ALBUMS']} SET alb_hits = alb_hits + 1 WHERE aid = $aid");
2893    }
2894}
2895/**
2896 * breadcrumb()
2897 *
2898 * Build the breadcrumb navigation
2899 *
2900 * @param integer $cat
2901 * @param string $breadcrumb
2902 * @param string $BREADCRUMB_TEXT
2903 * @return
2904 **/
2905
2906function breadcrumb($cat, &$breadcrumb, &$BREADCRUMB_TEXT)
2907{
2908    global $lang_list_categories, $lang_common;
2909    global $CONFIG,$CURRENT_ALBUM_DATA, $CURRENT_CAT_NAME;
2910
2911    $category_array = array();
2912
2913    // first we build the category path: names and id
2914    if ($cat != 0) { //Categories other than 0 need to be selected
2915
2916        if ($cat >= FIRST_USER_CAT) {
2917
2918            $result = cpg_db_query("SELECT name FROM {$CONFIG['TABLE_CATEGORIES']} WHERE cid = " . USER_GAL_CAT);
2919
2920            $row = $result->fetchAssoc(true);
2921
2922            $category_array[] = array(USER_GAL_CAT, $row['name']);
2923
2924            $user_name = get_username($cat - FIRST_USER_CAT);
2925
2926            if (!$user_name) {
2927                $user_name = $lang_common['username_if_blank'];
2928            }
2929
2930            $category_array[] = array($cat, $user_name);
2931            $CURRENT_CAT_NAME = sprintf($lang_list_categories['xx_s_gallery'], $user_name);
2932
2933            $row['parent'] = 1;
2934
2935        } else {
2936
2937            $result = cpg_db_query("SELECT p.cid, p.name FROM {$CONFIG['TABLE_CATEGORIES']} AS c,
2938                {$CONFIG['TABLE_CATEGORIES']} AS p
2939                WHERE c.lft BETWEEN p.lft AND p.rgt
2940                AND c.cid = $cat
2941                ORDER BY p.lft");
2942
2943            while ( ($row = $result->fetchAssoc()) ) {
2944                $category_array[] = array($row['cid'], $row['name']);
2945                $CURRENT_CAT_NAME = $row['name'];
2946            }
2947
2948            $result->free();
2949        }
2950    }
2951
2952    $breadcrumb_links = array();
2953    $BREADCRUMB_TEXTS = array();
2954
2955    // Add the Home link  to breadcrumb
2956    $breadcrumb_links[0] = '<a href="index.php">'.$lang_list_categories['home'].'</a>';
2957    $BREADCRUMB_TEXTS[0] = $lang_list_categories['home'];
2958
2959    $cat_order = 1;
2960
2961    foreach ($category_array as $category) {
2962
2963        $breadcrumb_links[$cat_order] = "<a href=\"index.php?cat={$category[0]}\">{$category[1]}</a>";
2964        $BREADCRUMB_TEXTS[$cat_order] = $category[1];
2965
2966        $cat_order += 1;
2967    }
2968
2969    //Add Link for album if aid is set
2970    if (isset($CURRENT_ALBUM_DATA['aid'])) {
2971        $breadcrumb_links[$cat_order] = "<a href=\"thumbnails.php?album=".$CURRENT_ALBUM_DATA['aid']."\">".$CURRENT_ALBUM_DATA['title']."</a>";
2972        $BREADCRUMB_TEXTS[$cat_order] = $CURRENT_ALBUM_DATA['title'];
2973    }
2974
2975    // Build $breadcrumb,$BREADCRUMB_TEXT from _links and _TEXTS
2976    theme_breadcrumb($breadcrumb_links, $BREADCRUMB_TEXTS, $breadcrumb, $BREADCRUMB_TEXT);
2977}  // function breadcrumb
2978
2979
2980/**************************************************************************
2981
2982 **************************************************************************/
2983
2984// Get the configured/available image tool class
2985function getImageTool ()
2986{
2987	global $CONFIG;
2988
2989	if ($CONFIG['thumb_method'] == 'imx') {
2990		require_once 'include/imageobject_imx.class.php';
2991	} elseif ($CONFIG['thumb_method'] == 'im') {
2992		require_once 'include/imageobject_im.class.php';
2993	} else {
2994		require_once 'include/imageobject_gd.class.php';
2995	}
2996}
2997
2998
2999// Compute image geometry based on max width / height
3000
3001/**
3002 * compute_img_size()
3003 *
3004 * Compute image geometry based on max, width / height
3005 *
3006 * @param integer $width
3007 * @param integer $height
3008 * @param integer $max
3009 * @return array
3010 **/
3011function compute_img_size($width, $height, $max, $system_icon = false, $normal = false)
3012{
3013    global $CONFIG;
3014
3015    $thumb_use = $CONFIG['thumb_use'];
3016
3017    if ($thumb_use == 'ht') {
3018        $ratio = $height / $max;
3019    } elseif ($thumb_use == 'wd') {
3020        $ratio = $width / $max;
3021    } else {
3022        $ratio = max($width, $height) / $max;
3023    }
3024
3025    if ($ratio > 1) {
3026        $image_size['reduced'] = true;
3027    }
3028
3029    $ratio = max($ratio, 1);
3030
3031    $image_size['width']  =  (int) ($width / $ratio);
3032    $image_size['height'] = (int) ($height / $ratio);
3033    $image_size['whole']  = 'width="' . $image_size['width'] . '" height="' . $image_size['height'] . '"';
3034
3035    if ($thumb_use == 'ht') {
3036        $image_size['geom'] = ' height="' . $image_size['height'] . '"';
3037    } elseif ($thumb_use == 'wd') {
3038        $image_size['geom'] = 'width="' . $image_size['width'] . '"';
3039
3040        //thumb cropping
3041    } elseif ($thumb_use == 'ex') {
3042
3043        if ($normal == 'normal') {
3044            $image_size['geom'] = 'width="' . $image_size['width'] . '" height="' . $image_size['height'] . '"';
3045        } elseif ($normal == 'cat_thumb') {
3046            $image_size['geom'] = 'width="' . $max . '" height="' . ($CONFIG['thumb_height'] * $max / $CONFIG['thumb_width']) . '"';
3047        } else {
3048            $image_size['geom'] = 'width="' . $CONFIG['thumb_width'] . '" height="' . $CONFIG['thumb_height'] . '"';
3049        }
3050        //if we have a system icon we override the previous calculation and take 'any' as base for the calc
3051        if ($system_icon) {
3052            $image_size['geom'] = 'width="' . $image_size['width'] . '" height="' . $image_size['height'] . '"';
3053        }
3054
3055    } else {
3056        $image_size['geom'] = 'width="' . $image_size['width'] . '" height="' . $image_size['height'] . '"';
3057    }
3058
3059    return $image_size;
3060} // function compute_img_size
3061
3062// Prints thumbnails of pictures in an album
3063
3064/**
3065 * display_thumbnails()
3066 *
3067 * Generates data to display thumbnails of pictures in an album
3068 *
3069 * @param mixed $album Either the album ID or the meta album name
3070 * @param integer $cat Either the category ID or album ID if negative
3071 * @param integer $page Page number to display
3072 * @param integer $thumbcols
3073 * @param integer $thumbrows
3074 * @param boolean $display_tabs
3075 **/
3076
3077function display_thumbnails($album, $cat, $page, $thumbcols, $thumbrows, $display_tabs)
3078{
3079    global $CONFIG, $USER, $LINEBREAK;
3080    global $lang_date, $lang_display_thumbnails, $lang_byte_units, $lang_common, $valid_meta_albums;
3081
3082    $superCage = Inspekt::makeSuperCage();
3083
3084    $thumb_per_page = $thumbcols * $thumbrows;
3085    $lower_limit    = ($page - 1) * $thumb_per_page;
3086
3087    $pic_data = get_pic_data($album, $thumb_count, $album_name, $lower_limit, $thumb_per_page);
3088
3089    $total_pages = ceil($thumb_count / $thumb_per_page);
3090
3091    $i = 0;
3092
3093    if (is_array($pic_data) && $pic_data) {
3094
3095        foreach ($pic_data as $key => $row) {
3096
3097            $i++;
3098
3099            $pic_title = $lang_common['filename'] . '=' . $row['filename'] . $LINEBREAK .
3100                $lang_common['filesize'] . '=' . ($row['filesize'] >> 10) . $lang_byte_units[1] . $LINEBREAK .
3101                $lang_display_thumbnails['dimensions'] . $row['pwidth'] . "x" . $row['pheight'] . $LINEBREAK .
3102                $lang_display_thumbnails['date_added'] . localised_date($row['ctime'], $lang_date['album']);
3103
3104            list($pic_title) = CPGPluginAPI::filter('thumb_html_title', array($pic_title, $row));
3105
3106            $pic_url = get_pic_url($row, 'thumb');
3107
3108            if (!is_image($row['filename'])) {
3109                $image_info     = cpg_getimagesize(urldecode($pic_url));
3110                $row['pwidth']  = $image_info[0];
3111                $row['pheight'] = $image_info[1];
3112            }
3113
3114            // thumb cropping - if we display a system thumb we calculate the dimension by any and not ex
3115            if (array_key_exists('system_icon', $row) && ($row['system_icon'] == true)) {
3116                $image_size = compute_img_size($row['pwidth'], $row['pheight'], $CONFIG['thumb_width'], true);
3117            } else {
3118                $image_size = compute_img_size($row['pwidth'], $row['pheight'], $CONFIG['thumb_width']);
3119            }
3120
3121            $thumb_list[$i]['pos']          = $key < 0 ? $key : $i - 1 + $lower_limit;
3122            $thumb_list[$i]['pid']          = $row['pid'];
3123            $thumb_list[$i]['image']        = '<img src="' . $pic_url . '" class="image thumbnail" ' . $image_size['geom'] . ' border="0" alt="' . $row['filename'] . '" title="' . $pic_title . '" />';
3124            $thumb_list[$i]['caption']      = bb_decode($row['caption_text']);
3125            $thumb_list[$i]['admin_menu']   = '';
3126            $thumb_list[$i]['aid']          = $row['aid'];
3127            $thumb_list[$i]['pwidth']       = $row['pwidth'];
3128            $thumb_list[$i]['pheight']      = $row['pheight'];
3129            // cpg1.5: new thumb fields below
3130            $thumb_list[$i]['title']        = $row['title'];
3131            $thumb_list[$i]['description']  = $row['caption'];
3132            $thumb_list[$i]['filepath']     = $row['filepath'];
3133            $thumb_list[$i]['filename']     = $row['filename'];
3134            $thumb_list[$i]['filesize']     = $row['filesize'];
3135            $thumb_list[$i]['msg_id']       = isset($row['msg_id']) ? $row['msg_id'] : '';   // needed for get_pic_pos()
3136        }
3137
3138        // Add a hit to album counter if it is a numeric album
3139        if (is_numeric($album)) {
3140
3141            // Create an array to hold the album id for hits (if not created)
3142            if (!isset($USER['liv_a']) || !is_array($USER['liv_a'])) {
3143                $USER['liv_a'] = array();
3144            }
3145
3146            // Add 1 to album hit counter
3147            if ((!USER_IS_ADMIN && $CONFIG['count_admin_hits'] == 0 || $CONFIG['count_admin_hits'] == 1) && !in_array($album, $USER['liv_a']) && $superCage->cookie->keyExists($CONFIG['cookie_name'] . '_data')) {
3148
3149                add_album_hit($album);
3150
3151                if (count($USER['liv_a']) > 4) {
3152                    array_shift($USER['liv_a']);
3153                }
3154
3155                array_push($USER['liv_a'], $album);
3156                user_save_profile();
3157            }
3158        }
3159
3160        //Using getRaw(). The date is sanitized in the called function.
3161        $date = $superCage->get->keyExists('date') ? cpgValidateDate($superCage->get->getRaw('date')) : null;
3162
3163        theme_display_thumbnails($thumb_list, $thumb_count, $album_name, $album, $cat, $page, $total_pages, is_numeric($album), $display_tabs, 'thumb', $date);
3164
3165    } elseif (is_numeric($album) || in_array($album, $valid_meta_albums)) {
3166        theme_no_img_to_display($album_name);
3167    }
3168}
3169
3170 /**
3171 * cpg_get_system_thumb_list()
3172 *
3173 * Return an array containing the system thumbs in a directory
3174
3175 * @param string $search_folder
3176 * @return array
3177 **/
3178function cpg_get_system_thumb_list($search_folder = 'images/')
3179{
3180    global $CONFIG;
3181    static $thumbs = array();
3182
3183    $folder = 'images/thumbs/';
3184
3185    $thumb_pfx =& $CONFIG['thumb_pfx'];
3186
3187    // If thumb array is empty get list from coppermine 'images' folder
3188    if ((count($thumbs) == 0) && ($folder == $search_folder)) {
3189
3190        $dir = opendir($folder);
3191
3192        while (($file = readdir($dir)) !== false) {
3193
3194            if (is_file($folder . $file) && strpos($file, $thumb_pfx) === 0) {
3195                // Store filenames in an array
3196                $thumbs[] = array('filename' => $file);
3197            }
3198        }
3199
3200        closedir($dir);
3201
3202        return $thumbs;
3203
3204    } elseif ($folder == $search_folder) {
3205
3206        // Search folder is the same as coppermine images folder; just return the array
3207        return $thumbs;
3208
3209    } else {
3210
3211        // Search folder is different; check for files in the given folder
3212        $results = array();
3213
3214        foreach ($thumbs as $thumb) {
3215            if (is_file($search_folder . $thumb['filename'])) {
3216                $results[] = array('filename' => $thumb['filename']);
3217            }
3218        }
3219
3220        return $results;
3221    }
3222}
3223
3224
3225/**
3226 * cpg_get_system_thumb()
3227 *
3228 * Gets data for system thumbs
3229 *
3230 * @param string $filename
3231 * @param integer $user
3232 * @return array
3233 **/
3234
3235function& cpg_get_system_thumb($filename, $user = FIRST_USER_CAT)
3236{
3237    global $CONFIG;
3238
3239    // Correct user_id
3240    if ($user < FIRST_USER_CAT) {
3241        $user += FIRST_USER_CAT;
3242    }
3243
3244    if ($user == FIRST_USER_CAT) {
3245        $user = FIRST_USER_CAT + 1;
3246    }
3247
3248    // Get image data for thumb
3249    $picdata = array(
3250        'filename'   => $filename,
3251        'filepath'   => $CONFIG['userpics'] . $user . '/',
3252        'url_prefix' => 0,
3253    );
3254
3255    $pic_url = get_pic_url($picdata, 'thumb', true);
3256
3257    $picdata['thumb'] = $pic_url;
3258
3259    $image_info = cpg_getimagesize(urldecode($pic_url));
3260
3261    $picdata['pwidth']  = $image_info[0];
3262    $picdata['pheight'] = $image_info[1];
3263
3264    $image_size = compute_img_size($picdata['pwidth'], $picdata['pheight'], $CONFIG['alb_list_thumb_size']);
3265
3266    $picdata['whole']   = $image_size['whole'];
3267    $picdata['reduced'] = (isset($image_size['reduced']) && $image_size['reduced']);
3268
3269    return $picdata;
3270} // function cpg_get_system_thumb
3271
3272
3273/**
3274 * display_film_strip()
3275 *
3276 * gets data for thumbnails in an album for the film strip
3277 *
3278 * @param integer $album
3279 * @param integer $cat
3280 * @param integer $pos
3281 **/
3282
3283function display_film_strip($album, $cat, $pos,$ajax_call)
3284{
3285    global $CONFIG, $LINEBREAK;
3286    global $lang_date, $lang_display_thumbnails, $lang_byte_units, $lang_common, $pic_count,$ajax_call,$pos;
3287
3288    $superCage = Inspekt::makeSuperCage();
3289
3290    $max_item    = $CONFIG['max_film_strip_items'];
3291    $thumb_width = $CONFIG['thumb_width'];
3292
3293    /** set to variable with to javascript*/
3294    set_js_var('thumb_width', $thumb_width);
3295    set_js_var('thumb_use', $CONFIG['thumb_use']);
3296
3297    if ($CONFIG['max_film_strip_items'] % 2 == 0) {
3298        $max_item  = $CONFIG['max_film_strip_items'] + 1;
3299        $pic_count = $pic_count + 1;
3300    }
3301
3302    $max_item_real = $max_item;
3303
3304    /** check the thumb_per_page variable valid to query database*/
3305    if ($pic_count < $max_item_real) {
3306        $max_item_real = $pic_count;
3307    }
3308
3309    /** pass the max_items to the dispalyimage.js file */
3310    set_js_var('max_item', $max_item_real);
3311
3312    $max_block_items = $CONFIG['max_film_strip_items'];
3313
3314    $thumb_per_page = $max_item_real;
3315
3316    /** assign the varible $l_limit diffen */
3317    $l_limit = (int) ($max_item_real / 2);
3318    $l_limit = max(0, $pos - $l_limit);
3319
3320    /** set $l_limit to last images */
3321    if ($l_limit > ($pic_count - $max_item_real)) {
3322        $l_limit = $pic_count - $max_item_real;
3323    }
3324
3325    $pic_data = get_pic_data($album, $thumb_count, $album_name, $l_limit, $thumb_per_page, false, 'filmstrip');
3326
3327    if (count($pic_data) < $max_item) {
3328        $max_item = count($pic_data);
3329    }
3330
3331    $lower_limit = 0;
3332
3333    if ($ajax_call == 2) {
3334        $lower_limit = $max_item_real -1;
3335        $max_item    = 1;
3336    } elseif ($ajax_call == 1) {
3337        $lower_limit = 0;
3338        $max_item    = 1;
3339    }
3340
3341    $pic_data = array_slice($pic_data, $lower_limit, $max_item);
3342
3343    $i = $l_limit;
3344
3345    set_js_var('count', $pic_count);
3346
3347    $cat_link  = is_numeric($album) ? '' : '&amp;cat=' . $cat;
3348    //FIXME: Where does this '$date' come from?
3349    if (isset($date) && $date != '') {
3350        $date_link = '&amp;date=' . $date;
3351    } else {
3352        $date_link = '';
3353    }
3354
3355    if ($superCage->get->getInt('uid')) {
3356        $uid_link = '&amp;uid=' . $superCage->get->getInt('uid');
3357    } else {
3358        $uid_link = '';
3359    }
3360
3361    if (count($pic_data) > 0) {
3362
3363        foreach ($pic_data as $key => $row) {
3364            //$hi is never used
3365            //$hi = (($pos == ($i + $lower_limit))  ? '1': '');
3366
3367            $i++;
3368
3369            $pic_alt = $row['filename'];
3370
3371            $pic_title = $lang_common['filename'] . '=' . $row['filename'] . $LINEBREAK .
3372                $lang_common['filesize'] . '=' . ($row['filesize'] >> 10) . $lang_byte_units[1] . $LINEBREAK .
3373                $lang_display_thumbnails['dimensions'] . $row['pwidth'] . "x" . $row['pheight'] . $LINEBREAK .
3374                $lang_display_thumbnails['date_added'] . localised_date($row['ctime'], $lang_date['album']);
3375
3376            list($pic_title) = CPGPluginAPI::filter('thumb_strip_html_title', array($pic_title, $row));
3377
3378            $pic_url = get_pic_url($row, 'thumb');
3379
3380            /*if (!is_image($row['filename'])) {
3381
3382                $image_info = cpg_getimagesize(urldecode($pic_url));
3383
3384                $row['pwidth']  = $image_info[0];
3385                $row['pheight'] = $image_info[1];
3386            }
3387
3388            //thumb cropping
3389            /*if (array_key_exists('system_icon', $row) && ($row['system_icon'] == true)) {
3390                $image_size = compute_img_size($row['pwidth'], $row['pheight'], $CONFIG['thumb_width'], true);
3391            } else {
3392                $image_size = compute_img_size($row['pwidth'], $row['pheight'], $CONFIG['thumb_width']);
3393            }*/ // values never used
3394
3395            $p = $i - 1 + $lower_limit;
3396            $p = ($p < 0 ? 0 : $p);
3397
3398            $thumb_list[$i]['pos']        = $key < 0 ? $key : $p;
3399            $thumb_list[$i]['image']      = '<img src="' . $pic_url . '" class="strip_image" border="0" alt="' . $row['filename'] . '" title="' . $pic_title . '" />';
3400            $thumb_list[$i]['admin_menu'] = '';
3401            $thumb_list[$i]['pid']        = $row['pid'];
3402            $thumb_list[$i]['msg_id']     = isset($row['msg_id']) ? $row['msg_id'] : ''; // needed for get_pic_pos()
3403
3404            $msg_id = isset($row['msg_id']) ? '&amp;msg_id='.$row['msg_id'] : '';
3405            $page = isset($row['msg_id']) ? '&amp;page='.cpg_get_comment_page_number($row['msg_id']) : '';
3406            $hash = isset($row['msg_id']) ? '#comment'.$row['msg_id'] : '#top_display_media';
3407
3408            $target = "displayimage.php?album=$album$cat_link$date_link&amp;pid={$row['pid']}$msg_id$page$uid_link$hash";
3409        }
3410
3411        // Get the pos for next and prev links in filmstrip navigation
3412        $filmstrip_next_pos = $pos + 1;
3413        $filmstrip_prev_pos = $pos - 1;
3414
3415        // If next pos is greater then total pics then make it pic_count - 1
3416        $filmstrip_next_pos = $filmstrip_next_pos >= $pic_count ? $pic_count - 1 : $filmstrip_next_pos;
3417
3418        // If prev pos is less than 0 then make it 0
3419        $filmstrip_prev_pos = $filmstrip_prev_pos < 0 ? 0 : $filmstrip_prev_pos;
3420
3421        //Using getRaw(). The date is sanitized in the called function.
3422        $date = $superCage->get->keyExists('date') ? cpgValidateDate($superCage->get->getRaw('date')) : null;
3423
3424        if ($ajax_call == 2 || $ajax_call == 1) {
3425
3426            $setArray = array(
3427                'url'        => $pic_url,
3428                'target'     => $target,
3429                'alt'        => $pic_alt,
3430                'title'      => $pic_title,
3431             );
3432
3433             header("Content-Type: text/plain");
3434             echo json_encode($setArray);
3435
3436        } else {
3437            return theme_display_film_strip($thumb_list, $thumb_count, $album_name, $album, $cat, $pos, is_numeric($album), 'thumb', $date, $filmstrip_prev_pos, $filmstrip_next_pos, $max_block_items, $thumb_width);
3438        }
3439
3440    } else {
3441
3442        if ($ajax_call == 2 || $ajax_call == 1) {
3443
3444            $setArray = array(
3445                'url'        => 'images/stamp.png',
3446                'target'     => 'images/stamp.png',
3447                'alt'        => 'stamp.png',
3448                'title'      => '',
3449             );
3450
3451             header("Content-Type: text/plain");
3452             echo json_encode($setArray);
3453
3454        } else {
3455            theme_no_img_to_display($album_name);
3456        }
3457    }
3458}
3459
3460
3461/**
3462 * display_slideshow()
3463 *
3464 * gets data for thumbnails in an album for the film stript using Ajax call
3465 *
3466 * this added by Nuwan Sameera Hettiarachchi
3467 *
3468 * @param integer $album
3469 * @param integer $cat
3470 * @param integer $pos
3471 **/
3472function display_slideshow($pos, $ajax_show = 0)
3473{
3474    global $CONFIG, $album, $pid, $slideshow, $USER;
3475
3476    $superCage = Inspekt::makeSuperCage();
3477
3478    $Pic   = array();
3479    $Pid   = array();
3480    $Title = array();
3481
3482    $i = 0;
3483    $j = 0;
3484
3485    /** get the pic details by querying database*/
3486    $pic_data = get_pic_data($album, $pic_count, $album_name, $pos, 1, false);
3487
3488    /** calculate total amount of pic a perticular album */
3489    if ($ajax_show == 0) {
3490        set_js_var('Pic_count', $pic_count);
3491    }
3492
3493    foreach ($pic_data as $picture) {
3494
3495        if (is_image($picture['filename'])) {
3496
3497            if ($CONFIG['make_intermediate'] && cpg_picture_dimension_exceeds_intermediate_limit($picture['pwidth'], $picture['pheight'])) {
3498                $picture_url = get_pic_url($picture, 'normal');
3499            } else {
3500                $picture_url = get_pic_url($picture, 'fullsize');
3501            }
3502
3503            $Pic[$i] = htmlspecialchars($picture_url, ENT_QUOTES);
3504
3505            /*if ($picture['pid'] == $pid) {
3506                $j         = $i;
3507                $start_img = $picture_url;
3508            }*/ //$j and $start_img are never used
3509        } else {
3510            $pic_url = get_pic_url($picture, 'thumb');
3511            $Pic[$i] = htmlspecialchars($pic_url);
3512        }
3513
3514        $Pid[$i]   = $picture['pid'];
3515        $Title[$i] = $picture['title'] ? $picture['title'] : $picture['filename'];
3516
3517        $i++;
3518    }
3519
3520    /** set variables to jquery.slideshow.js */
3521    set_js_var('Time', $slideshow);
3522    set_js_var('Pid', $pid);
3523
3524    /*if (!$i) {
3525        $Pic[0] = 'images/thumb_document.jpg';
3526    }*/
3527
3528    // Add the hit if slideshow hits are enabled in config
3529    if ((!USER_IS_ADMIN && $CONFIG['count_admin_hits'] == 0 || $CONFIG['count_admin_hits'] == 1) && $CONFIG['slideshow_hits'] != 0) {
3530        // Add 1 to hit counter
3531        if (!in_array($Pid['0'], $USER['liv']) && $superCage->cookie->keyExists($CONFIG['cookie_name'] . '_data')) {
3532
3533            add_hit($Pid['0']);
3534
3535            if (count($USER['liv']) > 4) {
3536                array_shift($USER['liv']);
3537            }
3538
3539            array_push($USER['liv'], $Pid['0']);
3540            user_save_profile();
3541        }
3542    }
3543
3544    /** show slide show on first time*/
3545    if ($ajax_show == 0) {
3546        theme_slideshow($Pic['0'], $Title['0']);
3547    }
3548
3549    /** now we make a array to encode*/
3550    $dataArray = array(
3551        'url' => $Pic['0'],
3552        'title' => $Title['0'],
3553        'pid' => $Pid['0'],
3554    );
3555
3556    $dataJson = json_encode($dataArray);
3557
3558    /** send variable to javascript script*/
3559    if ($ajax_show == 1) {
3560        header("Content-Type: text/plain");
3561        echo $dataJson;
3562    }
3563}
3564
3565// Return the url for a picture, allows to have pictures spreaded over multiple servers
3566/**
3567 * get_pic_url()
3568 *
3569 * Return the url for a picture
3570 *
3571 * @param array $pic_row
3572 * @param string $mode
3573 * @param boolean $system_pic
3574 * @return string
3575 **/
3576
3577function& get_pic_url(&$pic_row, $mode, $system_pic = false)
3578{
3579    global $CONFIG, $THEME_DIR;
3580
3581    static $pic_prefix = array();
3582    static $url_prefix = array();
3583
3584    if (!count($pic_prefix)) {
3585        $pic_prefix = array(
3586            'thumb'    => $CONFIG['thumb_pfx'],
3587            'normal'   => $CONFIG['normal_pfx'],
3588            'orig'     => $CONFIG['orig_pfx'],
3589            'fullsize' => '',
3590        );
3591
3592        $url_prefix = array(
3593            0 => $CONFIG['fullpath'],
3594        );
3595    }
3596
3597    $mime_content = cpg_get_type($pic_row['filename']);
3598
3599    // If $mime_content is empty there will be errors, so only perform the array_merge if $mime_content is actually an array
3600    if (is_array($mime_content)) {
3601        $pic_row = array_merge($pic_row, $mime_content);
3602    }
3603
3604    $filepathname = null;
3605
3606    // Code to handle custom thumbnails
3607    // If fullsize or normal mode use regular file
3608    if ($mime_content['content'] != 'image' && $mode == 'normal') {
3609        $mode = 'fullsize';
3610    } elseif (($mime_content['content'] != 'image' && $mode == 'thumb') || $system_pic) {
3611
3612        $thumb_extensions = array(
3613            '.gif',
3614            '.png',
3615            '.jpg'
3616        );
3617
3618        // Check for user-level custom thumbnails
3619        // Create custom thumb path and erase extension using filename; Erase filename's extension
3620
3621        if (array_key_exists('url_prefix', $pic_row)) {
3622            $custom_thumb_path = $url_prefix[$pic_row['url_prefix']];
3623        } else {
3624            $custom_thumb_path = '';
3625        }
3626
3627        $custom_thumb_path .= $pic_row['filepath'] . (array_key_exists($mode, $pic_prefix) ? $pic_prefix[$mode] : '');
3628
3629        $file_base_name = str_ireplace('.' . $mime_content['extension'], '', basename($pic_row['filename']));
3630
3631        // Check for file-specific thumbs
3632        foreach ($thumb_extensions as $extension) {
3633            if (file_exists($custom_thumb_path . $file_base_name . $extension)) {
3634                $filepathname = $custom_thumb_path . $file_base_name . $extension;
3635                break;
3636            }
3637        }
3638
3639        if (!$system_pic) {
3640
3641            // Check for extension-specific thumbs
3642            if (is_null($filepathname)) {
3643                foreach ($thumb_extensions as $extension) {
3644                    if (file_exists($custom_thumb_path . $mime_content['extension'] . $extension)) {
3645                        $filepathname = $custom_thumb_path . $mime_content['extension'] . $extension;
3646                        break;
3647                    }
3648                }
3649            }
3650
3651            // Check for content-specific thumbs
3652            if (is_null($filepathname)) {
3653                foreach ($thumb_extensions as $extension) {
3654                    if (file_exists($custom_thumb_path . $mime_content['content'] . $extension)) {
3655                        $filepathname = $custom_thumb_path . $mime_content['content'] . $extension;
3656                        break;
3657                    }
3658                }
3659            }
3660        }
3661
3662        // Use default thumbs
3663        if (is_null($filepathname)) {
3664
3665            // Check for default theme- and global-level thumbs
3666            $thumb_paths[] = $THEME_DIR.'images/';                 // Used for custom theme thumbs
3667            $thumb_paths[] = 'images/thumbs/';                     // Default Coppermine thumbs
3668
3669            foreach ($thumb_paths as $default_thumb_path) {
3670                if (is_dir($default_thumb_path)) {
3671                    if (!$system_pic) {
3672                        foreach ($thumb_extensions as $extension) {
3673                            // Check for extension-specific thumbs
3674                            if (file_exists($default_thumb_path . $CONFIG['thumb_pfx'] . $mime_content['extension'] . $extension)) {
3675                                $filepathname = $default_thumb_path . $CONFIG['thumb_pfx'] . $mime_content['extension'] . $extension;
3676                                //thumb cropping - if we display a system thumb we calculate the dimension by any and not ex
3677                                $pic_row['system_icon'] = true;
3678                                break 2;
3679                            }
3680                        }
3681                        foreach ($thumb_extensions as $extension) {
3682                            // Check for media-specific thumbs (movie,document,audio)
3683                            if (file_exists($default_thumb_path . $CONFIG['thumb_pfx'] . $mime_content['content'] . $extension)) {
3684                                $filepathname = $default_thumb_path . $CONFIG['thumb_pfx'] . $mime_content['content'] . $extension;
3685                                //thumb cropping
3686                                $pic_row['system_icon'] = true;
3687                                break 2;
3688                            }
3689                        }
3690                    } else {
3691                        // Check for file-specific thumbs for system files
3692                        foreach ($thumb_extensions as $extension) {
3693                            if (file_exists($default_thumb_path . $CONFIG['thumb_pfx'] . $file_base_name . $extension)) {
3694                                $filepathname = $default_thumb_path . $CONFIG['thumb_pfx'] . $file_base_name . $extension;
3695                                //thumb cropping
3696                                $pic_row['system_icon'] = true;
3697                                break 2;
3698                            }
3699                        } // foreach $thumb_extensions
3700                    } // else $system_pic
3701                } // if is_dir($default_thumb_path)
3702            } // foreach $thumbpaths
3703        } // if is_null($filepathname)
3704
3705        if ($filepathname) {
3706            $filepathname = path2url($filepathname);
3707        }
3708    }
3709
3710    if (is_null($filepathname)) {
3711
3712        $localpath = $pic_row['filepath'] . $pic_prefix[$mode] . $pic_row['filename'];
3713
3714        // Check here that the filename we are going to return exists
3715        // If it doesn't exist we return a placeholder image
3716        // We then log the missing file for the admin's attention
3717        if (file_exists($url_prefix[$pic_row['url_prefix']] . $localpath)) {
3718            $filepathname = $url_prefix[$pic_row['url_prefix']] . path2url($localpath);
3719        } else {
3720            $filepathname = 'images/thumbs/thumb_nopic.png';
3721            $pic_row['system_icon'] = true;
3722            if ($CONFIG['log_mode'] != 0) {
3723                log_write("File {$url_prefix[$pic_row['url_prefix']]}$localpath is missing.");
3724            }
3725        }
3726    }
3727
3728    // Added hack:  "&& !isset($pic_row['mode'])" thumb_data filter isn't executed for the fullsize image
3729    if ($mode == 'thumb' && !isset($pic_row['mode'])) {
3730        $pic_row['url']  = $filepathname;
3731        $pic_row['mode'] = $mode;
3732
3733        $pic_row = CPGPluginAPI::filter('thumb_data', $pic_row);
3734    } elseif ($mode != 'thumb') {
3735        $pic_row['url']  = $filepathname;
3736        $pic_row['mode'] = $mode;
3737    } else {
3738        $pic_row['url'] = $filepathname;
3739    }
3740
3741    $pic_row = CPGPluginAPI::filter('picture_url', $pic_row);
3742
3743    return $pic_row['url'];
3744} // function get_pic_url
3745
3746
3747/**
3748 * cpg_get_default_lang_var()
3749 *
3750 * Return a variable from the default language file
3751 *
3752 * @param $language_var_name
3753 * @param unknown $override_language
3754 * @return
3755 **/
3756function& cpg_get_default_lang_var($language_var_name, $override_language = null)
3757{
3758    global $CONFIG;
3759
3760    if (is_null($override_language)) {
3761        if (isset($CONFIG['default_lang'])) {
3762            $language = $CONFIG['default_lang'];
3763        } else {
3764            global $$language_var_name;
3765            return $$language_var_name;
3766        }
3767    } else {
3768        $language = $override_language;
3769    }
3770
3771    include 'lang/english.php';
3772    include 'lang/'.$language.'.php';
3773
3774    return $$language_var_name;
3775} // function cpg_get_default_lang_var
3776
3777// Returns a variable from the current language file
3778// If variable doesn't exists gets value from english_us lang file
3779
3780/**
3781 * cpg_lang_var()
3782 *
3783 * @param $varname
3784 * @param unknown $index
3785 * @return
3786 **/
3787
3788function& cpg_lang_var($varname, $index = null)
3789{
3790    global $$varname;
3791
3792    $lang_var =& $$varname;
3793
3794    if (isset($lang_var)) {
3795        if (!is_null($index) && !isset($lang_var[$index])) {
3796            include 'lang/english.php';
3797            return $lang_var[$index];
3798        } elseif (is_null($index)) {
3799            return $lang_var;
3800        } else {
3801            return $lang_var[$index];
3802        }
3803    } else {
3804        include 'lang/english.php';
3805        return $lang_var;
3806    }
3807} // function cpg_lang_var
3808
3809
3810/**
3811 * cpg_debug_output()
3812 *
3813 * defined new debug_output function here in functions.inc.php instead of theme.php with different function names to avoid incompatibilities with users not updating their themes as required. Advanced info is only output if (GALLERY_ADMIN_MODE == TRUE)
3814 *
3815 **/
3816
3817function cpg_debug_output()
3818{
3819    global $USER, $USER_DATA, $CONFIG, $cpg_time_start, $query_stats, $queries, $lang_cpg_debug_output, $CPG_PHP_SELF, $superCage, $CPG_PLUGINS, $LINEBREAK;
3820    if ($CONFIG['performance_timestamp'] == 0 || (date('Y-m-d', $CONFIG['performance_timestamp']) < date('Y-m-d'))) {
3821        // The metering data in the config table are outdated, let's write fresh values.
3822        // Currently happens each day. To extend the metering period to a whole week,
3823        // use 'Y-m-W' for both date functions above. Use 'Y-m' to extend the period over
3824        // one month and subsequently 'Y' for an entire year.
3825        $CONFIG['performance_timestamp'] = time();
3826        cpg_config_set('performance_timestamp', $CONFIG['performance_timestamp']);
3827        $CONFIG['performance_page_generation_time'] = 0;
3828        $CONFIG['performance_page_query_time'] = 0;
3829        $CONFIG['performance_page_query_count'] = 0;
3830    }
3831    $time_end         = cpgGetMicroTime();
3832    $time             = round(($time_end - $cpg_time_start) * 1000, 2);
3833    if ($CONFIG['performance_page_generation_time'] < $time) {
3834        $CONFIG['performance_page_generation_time'] = $time;
3835        cpg_config_set('performance_page_generation_time', $CONFIG['performance_page_generation_time']);
3836    }
3837    $query_count      = count($query_stats);
3838    $total_query_time = round(array_sum($query_stats), 2);
3839    if ($CONFIG['performance_page_query_time'] < $total_query_time) {
3840        $CONFIG['performance_page_query_time'] = $total_query_time;
3841        cpg_config_set('performance_page_query_time', $CONFIG['performance_page_query_time']);
3842    }
3843    if ($CONFIG['performance_page_query_count'] < $query_count) {
3844        $CONFIG['performance_page_query_count'] = $query_count;
3845        cpg_config_set('performance_page_query_count', $CONFIG['performance_page_query_count']);
3846    }
3847
3848    $debug_underline   = '&#0010;------------------&#0010;';
3849    $debug_separate    = '&#0010;==========================&#0010;';
3850    $debug_toggle_link = $lang_cpg_debug_output['debug_output'] . ': <span class="detail_head_collapsed">'. $lang_cpg_debug_output['show_hide'].'</span>';
3851    $debug_help = '&nbsp;'. cpg_display_help('f=empty.htm&amp;h=lang_cpg_debug_output%5Bdebug_output_explain%5D&amp;t=lang_cpg_debug_output%5Bcopy_and_paste_instructions%5D', 470, 245);
3852    $debug_phpinfo_link = GALLERY_ADMIN_MODE ? '<a href="phpinfo.php" class="admin_menu">' . cpg_fetch_icon('phpinfo', 1) . $lang_cpg_debug_output['phpinfo'] . '</a> ' : '';
3853
3854    echo <<< EOT
3855    <script language="javascript" type="text/javascript">
3856<!--
3857        addonload("document.getElementById('debug_output_select_all').style.display = 'inline'");
3858//-->
3859        </script>
3860    <form name="debug" action="{$CPG_PHP_SELF}" id="debug">
3861EOT;
3862    starttable('100%', cpg_fetch_icon('bug', 2) . $lang_cpg_debug_output['debug_info'] . $debug_help, 2);
3863    echo <<< EOT
3864    <tr>
3865        <td>
3866
3867        </td>
3868    </tr>
3869    <tr>
3870        <td valign="top" align="left" class="tableb">
3871            {$debug_phpinfo_link}{$debug_toggle_link}
3872            <span class="detail_body">
3873                <button type="button" class="button" name="debug_output_select_all" style="display:none" id="debug_output_select_all" value="{$lang_cpg_debug_output['select_all']}" onclick="HighlightAll('debug.debugtext');">{$lang_cpg_debug_output['select_all']}</button><br />
3874                <textarea  rows="30" cols="60" class="debug_text" name="debugtext">
3875EOT;
3876    echo "USER: ";
3877    echo $debug_underline;
3878    echo htmlentities(print_r($USER, true));
3879    echo $debug_separate;
3880    echo "USER DATA:";
3881    echo $debug_underline;
3882    echo htmlentities(print_r($USER_DATA, true));
3883    echo $debug_separate;
3884    echo "Queries:";
3885    echo $debug_underline;
3886    echo htmlentities(print_r($queries, true));
3887    echo $debug_separate;
3888    echo "GET :";
3889    echo $debug_underline;
3890    echo htmlentities(print_r($superCage->get->_source, true));
3891    echo $debug_separate;
3892    echo "POST :";
3893    echo $debug_underline;
3894    echo htmlentities(print_r($superCage->post->_source, true));
3895    echo $debug_separate;
3896    echo "COOKIE :";
3897    echo $debug_underline;
3898    echo htmlentities(print_r($superCage->cookie->_source, true));
3899    echo $debug_separate;
3900
3901    if ($superCage->cookie->keyExists('PHPSESSID')) {
3902        echo "SESSION :";
3903        echo $debug_underline;
3904        if(!isset($_SESSION)){
3905            session_id($superCage->cookie->getAlnum('PHPSESSID'));
3906            session_start();
3907        }
3908        echo htmlentities(print_r($_SESSION, true));
3909        echo $debug_separate;
3910    }
3911
3912    if (GALLERY_ADMIN_MODE) {
3913
3914        $table = array();
3915        echo "VERSION INFO :";
3916        echo $debug_underline;
3917        $my_php_version = phpversion();
3918        if ($my_php_version == '') {
3919            $my_php_version = PHP_VERSION;
3920        }
3921        if (version_compare($my_php_version, '4.3.0', '>=')) {
3922            $version_comment = 'OK';
3923        } else {
3924            $version_comment = 'Your PHP version isn\'t good enough! Minimum requirements: 4.3.0';
3925        }
3926        $table[] = array('PHP version', $my_php_version, $version_comment);
3927
3928        $mySqlVersion = cpg_phpinfo_mysql_version();
3929
3930        if (version_compare($mySqlVersion, '3.23.23', '>=')) {
3931            $version_comment = 'OK';
3932        } else {
3933            $version_comment = 'Your MySQL version isn\'t good enough! Minimum requirements: 3.23.23';
3934        }
3935        $table[] =  array('MySQL version', $mySqlVersion, $version_comment);
3936
3937        $table[] =  array('Coppermine version', COPPERMINE_VERSION, COPPERMINE_VERSION_STATUS);
3938        echo cpg_fill_string_array_with_spaces($table, ' ', 'left', 'string');
3939        unset ($table);
3940        echo $debug_separate;
3941
3942        if (function_exists('gd_info') == true) {
3943            echo 'Module: GD';
3944            echo $debug_underline;
3945            $gd_array = gd_info();
3946            $table = array();
3947            if (array_key_exists('GD Version' , $gd_array) == TRUE) {
3948                $table[] = array('Exact version', preg_replace('/[[:alpha:][:space:]()]+/', '', $gd_array['GD Version']));
3949            }
3950            foreach ($gd_array as $key => $value) {
3951                $table[] = array($key,$value);
3952            }
3953            echo cpg_fill_string_array_with_spaces($table, ' ', 'left', 'string');
3954            unset($gd_array);
3955            unset($table);
3956            echo $debug_separate;
3957        } else {
3958            echo cpg_phpinfo_mod_output('gd', 'text', '|');
3959        }
3960
3961        echo 'Key config settings';
3962        echo $debug_underline;
3963        $table = array();
3964        $table[] = array('site_url', $CONFIG['site_url']);
3965        $table[] = array('charset', $CONFIG['charset']);
3966        $table[] = array('allow_private_albums', $CONFIG['allow_private_albums']);
3967        $table[] = array('cookie_name', $CONFIG['cookie_name']);
3968        $table[] = array('cookie_path', $CONFIG['cookie_path']);
3969        $table[] = array('impath', $CONFIG['impath']);
3970        $table[] = array('lang', $CONFIG['lang']);
3971        $table[] = array('main_page_layout', $CONFIG['main_page_layout']);
3972        $table[] = array('silly_safe_mode', $CONFIG['silly_safe_mode']);
3973        $table[] = array('smtp_host', $CONFIG['smtp_host']);
3974        $table[] = array('theme', $CONFIG['theme']);
3975        $table[] = array('thumb_method', $CONFIG['thumb_method']);
3976        echo cpg_fill_string_array_with_spaces($table, ' ', 'left', 'string');
3977        unset ($table);
3978        echo $debug_separate;
3979
3980        echo 'Plugins';
3981        echo $debug_underline;
3982        $table = array();
3983        foreach ($CPG_PLUGINS as $plugin) {
3984            $table[] = array('Name', $plugin->name);
3985            $table[] = array('Enabled', $plugin->enabled);
3986            $table[] = array('Actions', implode(', ', array_keys($plugin->actions)));
3987            $table[] = array('Filters', implode(', ', array_keys($plugin->filters)));
3988            $table[] = array('--------------');
3989        }
3990        echo cpg_fill_string_array_with_spaces($table, ' ', 'left', 'string');
3991        unset ($table);
3992
3993        echo $debug_separate;
3994        echo 'Server restrictions';
3995        echo $debug_underline;
3996        $table = array();
3997        $table[] = array('safe_mode', ini_get('safe_mode'));
3998        $table[] = array('safe_mode_exec_dir', ini_get('safe_mode_exec_dir'));
3999        $table[] = array('safe_mode_gid', ini_get('safe_mode_gid'));
4000        $table[] = array('safe_mode_include_dir', ini_get('safe_mode_include_dir'));
4001        $table[] = array('sql.safe_mode', ini_get('sql.safe_mode'));
4002        $table[] = array('disable_functions', ini_get('disable_functions'));
4003        $table[] = array('file_uploads', ini_get('file_uploads'));
4004        $table[] = array('include_path', ini_get('include_path'));
4005        $table[] = array('open_basedir', ini_get('open_basedir'));
4006        $table[] = array('allow_url_fopen', ini_get('allow_url_fopen'));
4007        $table[] = array('max_execution_time', ini_get('max_execution_time'));
4008        $table[] = array('max_input_time', ini_get('max_input_time'));
4009        $table[] = array('upload_max_filesize', ini_get('upload_max_filesize'));
4010        $table[] = array('post_max_size', ini_get('post_max_size'));
4011        $table[] = array('memory_limit', ini_get('memory_limit'));
4012        $table[] = array('suhosin.post.max_vars', ini_get('suhosin.post.max_vars'));
4013        $table[] = array('suhosin.request.max_vars', ini_get('suhosin.request.max_vars'));
4014        echo cpg_fill_string_array_with_spaces($table, ' ', 'left', 'string');
4015        unset ($table);
4016        echo $LINEBREAK . $debug_separate;
4017
4018        echo 'Page (performance)';
4019        echo $debug_underline;
4020        $table = array();
4021        $table[] = array('Parameter', 'Current', 'Peak');
4022        if (function_exists('memory_get_peak_usage')) {
4023            $peak_memory_usage = cpg_format_bytes(memory_get_peak_usage());
4024        } else {
4025            $peak_memory_usage = 'n/a';
4026        }
4027        $table[] = array('Memory usage', cpg_format_bytes(memory_get_usage()), $peak_memory_usage);
4028        $table[] = array('Page generation', $time . ' ms', $CONFIG['performance_page_generation_time'] . ' ms');
4029        $table[] = array('Page query time', $total_query_time . ' ms', $CONFIG['performance_page_query_time'] . ' ms');
4030        $table[] = array('Page query count', $query_count, $CONFIG['performance_page_query_count']);
4031        echo cpg_fill_string_array_with_spaces($table, ' ', 'left', 'string');
4032        unset ($table);
4033        echo $LINEBREAK . $debug_separate;
4034
4035    }
4036
4037    echo <<<EOT
4038                </textarea>
4039            </span>
4040        </td>
4041    </tr>
4042
4043EOT;
4044
4045    if ($CONFIG['debug_notice'] != 0) {
4046        // Maze's error report system
4047        global $cpgdebugger;
4048        $report = $cpgdebugger->stop();
4049        //$debug_notices_icon = cpg_fetch_icon('text_left', 2);
4050        if (GALLERY_ADMIN_MODE) {
4051            $notices_help =  'notices_help_admin';
4052        } else {
4053            $notices_help =  'notices_help_non_admin';
4054        }
4055        $notices_help = '&nbsp;' . cpg_display_help('f=empty.htm&amp;h=lang_cpg_debug_output[notices]&amp;t=lang_cpg_debug_output['.$notices_help.']', 470, 245);
4056        if (is_array($report)) {
4057            echo <<< EOT
4058            <tr>
4059                <td class="tableh2">
4060                    {$lang_cpg_debug_output['notices']}{$notices_help}
4061                </td>
4062            </tr>
4063EOT;
4064            $noticesLoopCounter = 0;
4065            foreach ($report as $file => $errors) {
4066                if ($noticesLoopCounter/2 == floor($noticesLoopCounter/2)) {
4067                    $cellstyle = 'tableb tableb_alternate';
4068                } else {
4069                    $cellstyle = 'tableb';
4070                }
4071                echo <<< EOT
4072            <tr>
4073                <td class="{$cellstyle}">
4074EOT;
4075                //echo '<strong>' . substr($file, $strstart) . '</strong><ul>'; //$strstart does not exist
4076                echo '<strong>' . $file . '</strong><ul>';
4077                foreach ($errors as $error) {
4078                    echo "<li>$error</li>";
4079                }
4080                echo <<< EOT
4081                    </ul>
4082                </td>
4083            </tr>
4084EOT;
4085                $noticesLoopCounter++;
4086            }
4087        }
4088    }
4089    endtable();
4090    echo '</form>';
4091
4092} // function cpg_debug_output
4093
4094
4095/**
4096 * cpg_phpinfo_mod()
4097 *
4098 * phpinfo-related functions:
4099 *
4100 * @param $search
4101 * @return
4102 **/
4103
4104function cpg_phpinfo_mod($search)
4105{
4106    static $pieces = array();
4107
4108    if (!$pieces) {
4109
4110        // this could be done much better with regexpr - anyone who wants to change it: go ahead
4111        ob_start();
4112        phpinfo(INFO_MODULES);
4113        $string    = ob_get_contents();
4114        //$module    = $string;
4115        $delimiter = '#cpgdelimiter#';
4116        ob_end_clean();
4117
4118        // find out the first occurence of "<h2" and throw the superfluos stuff away
4119        $string = stristr($string, 'module_' . $search);
4120        $string = preg_replace('#</table>(.*)#s', '', $string);
4121        $string = stristr($string, '<tr');
4122        $string = str_replace('</td>', '|', $string);
4123        $string = str_replace('</tr>', $delimiter, $string);
4124        $string = chop(strip_tags($string));
4125        $pieces = explode($delimiter, $string);
4126    }
4127
4128    foreach ($pieces as $key => $val) {
4129        $bits[$key] = explode('|', $val);
4130    }
4131
4132    return $bits;
4133} // function cpg_phpinfo_mod
4134
4135
4136/**
4137 * cpg_phpinfo_mod_output()
4138 *
4139 * @param $search
4140 * @param $output_type
4141 * @param $separator
4142 * @return
4143 **/
4144
4145function cpg_phpinfo_mod_output($search, $output_type, $separator = ' ')
4146{
4147    // first parameter is the module name, second parameter is the way you want your output to look like: table or text
4148    $pieces = cpg_phpinfo_mod($search);
4149    $summ   = '';
4150    $return = '';
4151
4152    $debug_underline = '&#0010;------------------&#0010;';
4153    $debug_separate  = '&#0010;==========================&#0010;';
4154
4155    if ($output_type == 'table') {
4156        ob_start();
4157        starttable('100%', 'Module: ' . $search, 2);
4158        $return .= ob_get_contents();
4159        ob_end_clean();
4160    } else {
4161        $return .= 'Module: ' . $search . $debug_underline;
4162    }
4163
4164    foreach ($pieces as $val) {
4165        if ($output_type == 'table') {
4166            $return .= '<tr><td>';
4167        }
4168        $return .= $val[0];
4169        if ($output_type == 'table') {
4170            $return .= '</td><td>';
4171        } else {
4172            $return .= $separator;
4173        }
4174        if (isset($val[1])) {
4175            $return .= $val[1];
4176        }
4177        if ($output_type == 'table') {
4178            $return .= '</td></tr>';
4179        }
4180        $summ .= $val[0];
4181    }
4182    if (!$summ) {
4183        if ($output_type == 'table') {
4184            $return .= '<tr><td colspan="2">';
4185        }
4186        $return .= 'module doesn\'t exist';
4187        if ($output_type == 'table') {
4188            $return .= '</td></tr>';
4189        }
4190    }
4191    if ($output_type == 'table') {
4192        ob_start();
4193        endtable();
4194        $return .= ob_get_contents();
4195        ob_end_clean();
4196    } else {
4197        $return .= $debug_separate;
4198    }
4199    return $return;
4200} // function cpg_phpinfo_mod_output
4201
4202
4203/**
4204 * cpg_phpinfo_mysql_version()
4205 *
4206 * @return
4207 **/
4208
4209function cpg_phpinfo_mysql_version()
4210{
4211    $result = cpg_db_query("SELECT VERSION()");
4212
4213    list($version) = $result->fetchRow(true);
4214
4215    return $version;
4216} // function cpg_phpinfo_mysql_version
4217
4218function cpg_config_output($key)
4219{
4220    global $CONFIG, $LINEBREAK;
4221
4222    return $key . ': ' . $CONFIG[$key] . $LINEBREAK;
4223} // function cpg_config_output
4224
4225
4226// THEME AND LANGUAGE SELECTION
4227
4228/**
4229 * languageSelect()
4230 *
4231 * @param $parameter
4232 * @return
4233 **/
4234
4235function languageSelect($parameter)
4236{
4237    global $CONFIG, $lang_language_selection, $lang_common, $CPG_PHP_SELF, $LINEBREAK;
4238
4239    $return    = '';
4240
4241    // get the current language
4242    //use the default language of the gallery
4243    //$cpgCurrentLanguage = $CONFIG['lang']; //not used
4244
4245    // Forget all the nonsense sanitization code that used to reside here - redefine the variable for the base URL using the function that we already have for that purpose
4246    $cpgChangeUrl = cpgGetScriptNameParams('lang') . 'lang=';
4247
4248    // Make sure that the language table exists in the first place -
4249    // return without return value if the table doesn't exist because
4250    // the upgrade script hasn't been run
4251    $results = cpg_db_query("SHOW TABLES LIKE '{$CONFIG['TABLE_LANGUAGE']}'");
4252    if (!$results->numRows()) {
4253        return;
4254    }
4255    $results->free();
4256
4257    // get list of available languages
4258    $results = cpg_db_query("SELECT * FROM {$CONFIG['TABLE_LANGUAGE']}");
4259    while ( ($row = $results->fetchArray()) ) {
4260        if ($row['available'] == 'YES' && $row['enabled'] == 'YES' && file_exists('lang/'.$row['lang_id'].'.php')) {
4261            $lang_language_data[$row['lang_id']] = $row;
4262        }
4263    } // while
4264    $results->free();
4265
4266    // sort the array by English name
4267    ksort($lang_language_data);
4268
4269    $value = strtolower($CONFIG['lang']);
4270
4271    //start the output
4272    switch ($parameter) {
4273
4274    case 'flags':
4275        $return .= '<div id="cpgChooseFlags" class="inline">';
4276        $return .= $lang_language_selection['choose_language'] . ': ';
4277        foreach ($lang_language_data as $language) {
4278            $return .= $LINEBREAK . '<a href="' . $cpgChangeUrl . $language['lang_id'] . '" rel="nofollow"><img src="images/flags/' . $language['flag'] . '.png" border="0" width="16" height="11" alt="" title="';
4279            $return .= $language['english_name'];
4280            if ($language['english_name'] != $language['native_name'] && $language['native_name'] != '') {
4281                $return .= ' / ' . $language['native_name'] ;
4282            }
4283            $return .= '" /></a>' . $LINEBREAK;
4284        }
4285        $return .=  '<a href="' . $cpgChangeUrl. 'xxx" rel="nofollow"><img src="images/flags/reset.png" border="0" width="16" height="11" alt="" title="';
4286        $return .=  $lang_language_selection['reset_language'] . '" /></a>' . $LINEBREAK;
4287        $return .= '</div>';
4288        break;
4289
4290    case 'table':
4291        $return = 'not yet implemented';
4292        break;
4293
4294    default:
4295        $return .= $LINEBREAK . '<div id="cpgChooseLanguageWrapper">' . $LINEBREAK . '<form name="cpgChooseLanguage" id="cpgChooseLanguage" action="' . $CPG_PHP_SELF . '" method="get" class="inline">' . $LINEBREAK;
4296        $return .= '<select name="lang" class="listbox_lang" onchange="if (this.options[this.selectedIndex].value) window.location.href=\'' . $cpgChangeUrl . '\' + this.options[this.selectedIndex].value;">' . $LINEBREAK;
4297        $return .='<option>' . $lang_language_selection['choose_language'] . '</option>' . $LINEBREAK;
4298        foreach ($lang_language_data as $language) {
4299            $return .=  '<option value="' . $language['lang_id']  . '" >';
4300            $return .= $language['english_name'];
4301            if ($language['english_name'] != $language['native_name'] && $language['native_name'] != '') {
4302                $return .= ' / ' . $language['native_name'] ;
4303            }
4304            $return .= ($value == $language['lang_id'] ? '*' : '');
4305            $return .= '</option>' . $LINEBREAK;
4306        }
4307        $return .=  '<option value="xxx">' . $lang_language_selection['reset_language'] . '</option>' . $LINEBREAK;
4308        $return .=  '</select>' . $LINEBREAK;
4309        $return .=  '<noscript>' . $LINEBREAK;
4310        $return .=  '<input type="submit" name="language_submit" value="' . $lang_common['go'] . '" class="listbox_lang" />&nbsp;'. $LINEBREAK;
4311        $return .=  '</noscript>' . $LINEBREAK;
4312        $return .=  '</form>' . $LINEBREAK;
4313        $return .=  '</div>' . $LINEBREAK;
4314    } // switch $parameter
4315
4316    return $return;
4317} // function languageSelect
4318
4319
4320/**
4321 * themeSelect()
4322 *
4323 * @param $parameter
4324 * @return
4325 **/
4326
4327function themeSelect($parameter)
4328{
4329    global $CONFIG,$lang_theme_selection, $lang_common, $CPG_PHP_SELF, $LINEBREAK;
4330
4331    $return    = '';
4332    $cpgCurrentTheme = cpgGetScriptNameParams('theme') . 'theme=';
4333
4334    // get list of available themes
4335    $value     = $CONFIG['theme'];
4336    $theme_dir = 'themes/';
4337
4338    $dir = opendir($theme_dir);
4339
4340    while ( ($file = readdir($dir)) ) {
4341        if (is_dir($theme_dir . $file) && $file != "." && $file != ".." && $file != '.svn' && $file != 'sample') {
4342            $theme_array[] = $file;
4343        }
4344    }
4345    closedir($dir);
4346
4347    natcasesort($theme_array);
4348
4349    $return .= $LINEBREAK . '<div id="cpgChooseThemeWrapper">' . $LINEBREAK . '<form name="cpgChooseTheme" id="cpgChooseTheme" action="' . $CPG_PHP_SELF . '" method="get" class="inline">' . $LINEBREAK;
4350    $return .= '<select name="theme" class="listbox_lang" onchange="if (this.options[this.selectedIndex].value) window.location.href=\'' . $cpgCurrentTheme . '\' + this.options[this.selectedIndex].value;">' . $LINEBREAK;
4351    $return .= '<option selected="selected">' . $lang_theme_selection['choose_theme'] . '</option>';
4352
4353    foreach ($theme_array as $theme) {
4354        $return .= '<option value="' . $theme . '"'. ($value == $theme ? '  selected="selected"' : '') . '>' . strtr(ucfirst($theme), '_', ' ') . ($value == $theme ? '  *' : '') . '</option>' . $LINEBREAK;
4355    }
4356
4357    $return .= '<option value="xxx">' . $lang_theme_selection['reset_theme'] . '</option>' . $LINEBREAK;
4358
4359    $return .= '</select>' . $LINEBREAK;
4360    $return .= '<noscript>' . $LINEBREAK;
4361    $return .= '<input type="submit" name="theme_submit" value="' . $lang_common['go'] . '" class="listbox_lang" />&nbsp;'. $LINEBREAK;
4362    $return .= '</noscript>' . $LINEBREAK;
4363    $return .= '</form>' . $LINEBREAK;
4364    $return .= '</div>' . $LINEBREAK;
4365
4366    return $return;
4367} // function themeSelect
4368
4369
4370/**
4371 * cpg_has_updates()
4372 *
4373 * @return
4374 **/
4375
4376function cpg_has_updates()
4377{
4378    global $CONFIG;
4379
4380    if ((time() - $CONFIG['last_updates_check']) > 86400) {
4381        require_once 'include/upgrader.inc.php';
4382        $upgc = new CPG_Updater(true);
4383        $has = (bool) count($upgc->getUpdates());
4384        cpg_db_query("UPDATE {$CONFIG['TABLE_CONFIG']} SET value = '".time()."' WHERE name = 'last_updates_check'");
4385        return $has;
4386    }
4387    return false;
4388}
4389
4390
4391/**
4392 * cpg_alert_dev_version()
4393 *
4394 * @return
4395 **/
4396
4397function cpg_alert_dev_version()
4398{
4399    global $lang_version_alert, $CONFIG, $REFERER;
4400
4401    $return = '';
4402
4403    if (COPPERMINE_VERSION_STATUS != 'stable' && COPPERMINE_VERSION_STATUS != 'RC') {
4404        $return = <<< EOT
4405        <div class="cpg_message_warning">
4406        <h2>{$lang_version_alert['version_alert']}</h2>
4407EOT;
4408        $return .= sprintf($lang_version_alert['no_stable_version'], COPPERMINE_VERSION, COPPERMINE_VERSION_STATUS);
4409        $return .= '</div>';
4410    }
4411
4412    // check if gallery is offline
4413    if ($CONFIG['offline'] == 1 && GALLERY_ADMIN_MODE) {
4414        $return .= <<< EOT
4415        <div class="cpg_message_validation">
4416        {$lang_version_alert['gallery_offline']}
4417        </div>
4418EOT;
4419    }
4420
4421	// notification about any updates available
4422    if (cpg_has_updates()) {
4423        $return = <<<EOT
4424        <div class="cpg_message_info">
4425        <h4>{$lang_version_alert['updates_available']}</h4>
4426EOT;
4427        $return .= '<a href="updater.php" class="button">'.$lang_version_alert['view_updates'].'</a>';
4428        $return .= '</div>';
4429    }
4430
4431    // display news from coppermine-gallery.net
4432    if ($CONFIG['display_coppermine_news'] == 1 && GALLERY_ADMIN_MODE) {
4433        $help_news      = '&nbsp;' . cpg_display_help('f=configuration.htm&amp;as=admin_general_coppermine_news&amp;ae=admin_general_coppermine_news_end&amp;top=1', '600', '300');
4434        $news_icon      = cpg_fetch_icon('news_show', 2);
4435        $news_icon_hide = cpg_fetch_icon('news_hide', 1);
4436        ob_start();
4437        starttable('100%');
4438        print <<< EOT
4439            <tr>
4440              <td>
4441                <table border="0" cellspacing="0" cellpadding="0" width="100%">
4442                  <tr>
4443                    <td class="tableh1">
4444                      {$news_icon}{$lang_version_alert['coppermine_news']}{$help_news}
4445                    </td>
4446                    <td class="tableh1" align="right">
4447                      <a href="mode.php?what=news&amp;referer={$REFERER}" class="admin_menu">{$news_icon_hide}{$lang_version_alert['hide']}</a>
4448                    </td>
4449                  </tr>
4450                  <tr>
4451                    <td class="tableb" colspan="2">
4452EOT;
4453        // Try to retrieve the news directly
4454        //$result = cpgGetRemoteFileByURL('http://coppermine-gallery.net/cpg16x_news.htm', 'GET', '', '200'); // disabled, see http://forum.coppermine-gallery.net/index.php/topic,65424.msg325573.html#msg325573
4455        if (empty($result) || strlen($result['body']) < 200) { // retrieving the file failed - let's display it in an iframe then
4456            print <<< EOT
4457                      <iframe src="//coppermine-gallery.net/cpg16x_news.htm" align="left" frameborder="0" scrolling="auto" marginheight="0" marginwidth="0" width="100%" height="100" name="coppermine_news" id="coppermine_news" class="textinput">
4458                        {$lang_version_alert['no_iframe']}
4459                      </iframe>
4460EOT;
4461        } else { // we have been able to retrieve the remote URL, let's chop the unneeded data and then display it
4462            unset($result['headers']);
4463            unset($result['error']);
4464            // drop everything before the starting body-tag
4465            //$result['body'] = substr($result['body'], strpos($result['body'], '<body>'));
4466            $result['body'] = strstr($result['body'], '<body>');
4467            // drop the starting body tag itself
4468            $result['body'] = str_replace('<body>', '', $result['body']);
4469            // drop the ending body tag and everything after it
4470            $result['body'] = str_replace(strstr($result['body'], '</body>'), '', $result['body']);
4471            // The result should now contain everything between the body tags - let's print it
4472            print $result['body'];
4473        }
4474        print <<< EOT
4475                    </td>
4476                  </tr>
4477                </table>
4478              </td>
4479            </tr>
4480EOT;
4481        endtable();
4482        print '<br />';
4483        $return .= ob_get_contents();
4484        ob_end_clean();
4485    }
4486    return $return;
4487} // function cpg_alert_dev_version
4488
4489/**
4490 * cpg_display_help()
4491 *
4492 * @param string $reference
4493 * @param string $width
4494 * @param string $height
4495 * @return
4496 **/
4497
4498function cpg_display_help($reference = 'f=empty.htm', $width = '600', $height = '350', $icon = 'help')
4499{
4500    global $CONFIG, $USER, $lang_common;
4501
4502    if ($reference == '' || $CONFIG['enable_help'] == '0') {
4503        return;
4504    }
4505
4506    if ($CONFIG['enable_help'] == '2' && GALLERY_ADMIN_MODE == false) {
4507        return;
4508    }
4509
4510    $help_theme = $CONFIG['theme'];
4511
4512    if (isset($USER['theme'])) {
4513        $help_theme = $USER['theme'];
4514    }
4515
4516    if($icon != '*' && $icon != '?') {
4517        $icon = '<img src="images/help.gif" width="13" height="11" border="0" alt="" />';
4518    }
4519
4520    $title_help = $lang_common['help'];
4521
4522    $help_html = '<a class="greybox" href="help.php?' . $reference . '" rel="help.php?css=' . $help_theme . '&amp;' . $reference . '" title="' . $title_help . '">' . $icon . '</a>';
4523
4524    return $help_html;
4525} // function cpg_display_help
4526
4527
4528/**
4529* Multi-dim array sort, with ability to sort by two and more dimensions
4530* Coded by Ichier2003, available at php.net
4531* syntax:
4532* $array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
4533**/
4534function array_csort()
4535{
4536    $args      = func_get_args();
4537    $marray    = array_shift($args);
4538    $msortline = "return(array_multisort(";
4539    $i         = 0;
4540
4541    foreach ($args as $arg) {
4542        $i++;
4543        if (is_string($arg)) {
4544            foreach ($marray as $row) {
4545                $sortarr[$i][] = $row[$arg];
4546            }
4547        } else {
4548            $sortarr[$i] = $arg;
4549        }
4550        $msortline .= "\$sortarr[" . $i . "],";
4551    }
4552
4553    $msortline .= "\$marray));";
4554
4555    eval($msortline);
4556
4557    return $marray;
4558} // function array_csort
4559
4560
4561function cpg_get_bridge_db_values()
4562{
4563    global $CONFIG;
4564
4565    // Retrieve DB stored configuration
4566    $results = cpg_db_query("SELECT name, value FROM {$CONFIG['TABLE_BRIDGE']}");
4567
4568    while ( ($row = $results->fetchAssoc()) ) {
4569        $BRIDGE[$row['name']] = $row['value'];
4570    } // while
4571
4572    $results->free();
4573
4574    return $BRIDGE;
4575} // function cpg_get_bridge_db_values
4576
4577
4578function cpg_get_webroot_path()
4579{
4580    global $CPG_PHP_SELF;
4581
4582    $superCage = Inspekt::makeSuperCage();
4583    // get the webroot folder out of a given PHP_SELF of any coppermine page
4584
4585    // what we have: we can say for sure where we are right now: $PHP_SELF (if the server doesn't even have it, there will be problems everywhere anyway)
4586
4587    // let's make those into an array:
4588    if ( ($matches = $superCage->server->getMatched('SCRIPT_FILENAME', '/^[a-z,A-Z0-9_-\/\\:.]+$/')) ) {
4589        $path_from_serverroot[] = $matches[0];
4590    }
4591    /*
4592    $path_from_serverroot[] = $_SERVER["SCRIPT_FILENAME"];
4593    if (isset($_SERVER["PATH_TRANSLATED"])) {
4594       $path_from_serverroot[] = $_SERVER["PATH_TRANSLATED"];
4595    }
4596    */
4597    if ( ($matches = $superCage->server->getMatched('PATH_TRANSLATED', '/^[a-z,A-Z0-9_-\/\\:.]+$/')) ) {
4598        $path_from_serverroot[] = $matches[0];
4599    }
4600    //$path_from_serverroot[] = $HTTP_SERVER_VARS["SCRIPT_FILENAME"];
4601    //$path_from_serverroot[] = $HTTP_SERVER_VARS["PATH_TRANSLATED"];
4602
4603    // we should be able to tell the current script's filename by removing everything before and including the last slash in $PHP_SELF
4604    $filename = ltrim(strrchr($CPG_PHP_SELF, '/'), '/');
4605
4606    // let's eliminate all those vars that don't contain the filename (and replace the funny notation from windows machines)
4607    foreach ($path_from_serverroot as $key) {
4608        $key = str_replace('\\', '/', $key); // replace the windows notation
4609        $key = str_replace('//', '/', $key); // replace duplicate forwardslashes
4610        if (strstr($key, $filename) != FALSE) { // eliminate all that don't contain the filename
4611            $path_from_serverroot2[] = $key;
4612        }
4613    }
4614
4615    // remove double entries in the array
4616    $path_from_serverroot3 = array_unique($path_from_serverroot2);
4617
4618    // in the best of all worlds, the array is not empty
4619    if (is_array($path_from_serverroot3)) {
4620        $counter = 0;
4621        foreach ($path_from_serverroot3 as $key) {
4622            // easiest possible solution: $PHP_SELF is contained in the array - if yes, we're lucky (in fact we could have done this before, but I was going to leave room for other checks to be inserted before this one)
4623            if (strstr($key, $CPG_PHP_SELF) != FALSE) { // eliminate all that don't contain $PHP_SELF
4624                $path_from_serverroot4[] = $key;
4625                $counter++;
4626            }
4627        }
4628    } else {
4629        // we're f***ed: the array is empty, there's no server var we could actually use
4630        $return = '';
4631    }
4632
4633    if ($counter == 1) { //we have only one entry left - we're happy
4634        $return = $path_from_serverroot4[0];
4635    } elseif ($counter == 0) { // we're f***ed: the array is empty, there's no server var we could actually use
4636        $return = '';
4637    } else { // there is more than one entry, and they differ. For now, let's use the first one. Maybe we could do some advanced checking later
4638        $return = $path_from_serverroot4[0];
4639    }
4640
4641    // strip the content from $PHP_SELF from the $return var and we should (hopefully) have the absolute path to the webroot
4642    $return = str_replace($CPG_PHP_SELF, '', $return);
4643
4644    // the return var should at least contain a slash - if it doesn't, add it (although this is more or less wishfull thinking)
4645    if ($return == '') {
4646        $return = '/';
4647    }
4648
4649    return $return;
4650} // function cpg_get_webroot_path
4651
4652
4653/**
4654 * Function to get the search string if the picture is viewed from google, lycos or yahoo search engine
4655 */
4656
4657function get_search_query_terms($engine = 'google')
4658{
4659    $superCage = Inspekt::makeSuperCage();
4660
4661    //Using getRaw(). $referer is sanitized below wherever needed
4662    $referer     = urldecode($superCage->server->getRaw('HTTP_REFERER'));
4663    $query_array = array();
4664
4665    switch ($engine) {
4666
4667    case 'google':
4668        // Google query parsing code adapted from Dean Allen's
4669        // Google Hilite 0.3. http://textism.com
4670        $query_terms = preg_replace('/^.*q=([^&]+)&?.*$/i', '$1', $referer);
4671        $query_terms = preg_replace('/\'|"/', '', $query_terms);
4672        $query_array = preg_split('/[\s,\+\.]+/', $query_terms);
4673        break;
4674
4675    case 'lycos':
4676        $query_terms = preg_replace('/^.*query=([^&]+)&?.*$/i', '$1', $referer);
4677        $query_terms = preg_replace('/\'|"/', '', $query_terms);
4678        $query_array = preg_split('/[\s,\+\.]+/', $query_terms);
4679        break;
4680
4681    case 'yahoo':
4682        $query_terms = preg_replace('/^.*p=([^&]+)&?.*$/i', '$1', $referer);
4683        $query_terms = preg_replace('/\'|"/', '', $query_terms);
4684        $query_array = preg_split('/[\s,\+\.]+/', $query_terms);
4685        break;
4686    } // switch $engine
4687    return $query_array;
4688} // function get_search_query_terms
4689
4690
4691function is_referer_search_engine($engine = 'google')
4692{
4693    //$siteurl = get_settings('home');
4694    $superCage = Inspekt::makeSuperCage();
4695
4696    //Using getRaw(). $referer is sanitized below wherever needed
4697    $referer = urldecode($superCage->server->getRaw('HTTP_REFERER'));
4698
4699    if (!$engine) {
4700        return 0;
4701    }
4702
4703    switch ($engine) {
4704
4705    case 'google':
4706        if (preg_match('|^http://(www)?\.?google.*|i', $referer)) {
4707            return 1;
4708        }
4709        break;
4710
4711    case 'lycos':
4712        if (preg_match('|^http://search\.lycos.*|i', $referer)) {
4713            return 1;
4714        }
4715        break;
4716
4717    case 'yahoo':
4718        if (preg_match('|^http://search\.yahoo.*|i', $referer)) {
4719            return 1;
4720        }
4721        break;
4722    } // switch $engine
4723    return 0;
4724} // end is_referer_search_engine
4725
4726
4727/**
4728 * cpg_get_custom_include()
4729 *
4730 * @param string $path
4731 * @return
4732 **/
4733function cpg_get_custom_include($path = '')
4734{
4735    global $CONFIG, $CPG_PHP_SELF, $REFERER, $CPG_REFERER, $LINEBREAK, $BRIDGE, $USER, $USER_DATA, $THEME_DIR, $ICON_DIR, $FAVPICS, $RESTRICTEDWHERE, $FORBIDDEN_SET_DATA, $CURRENT_ALBUM_KEYWORD, $CURRENT_CAT_DEPTH, $FORBIDDEN_SET, $CURRENT_CAT_NAME, $CPG_PLUGINS, $JS;
4736    $return = '';
4737
4738    // check if path is set in config
4739    if ($path == '') {
4740        return $return;
4741    }
4742
4743    // check if the include file exists
4744    if (!file_exists($path)) {
4745        return $return;
4746    }
4747
4748    ob_start();
4749    include $path;
4750    $return = ob_get_contents();
4751    ob_end_clean();
4752
4753    // crude sub-routine to remove the most basic "no-no" stuff from possible includes
4754    // could need improvement
4755    $return = str_replace('<html>', '', $return);
4756    $return = str_replace('<head>', '', $return);
4757    $return = str_replace('<body>', '', $return);
4758    $return = str_replace('</html>', '', $return);
4759    $return = str_replace('</head>', '', $return);
4760    $return = str_replace('</body>', '', $return);
4761
4762    return $return;
4763} // function cpg_get_custom_include
4764
4765
4766/**
4767 * filter_content()
4768 *
4769 * Replace strings that match badwords with tokens indicating it has been filtered.
4770 *
4771 * @param string or array $str
4772 * @return string or array
4773 **/
4774function filter_content($str)
4775{
4776    global $lang_bad_words, $CONFIG, $ercp;
4777
4778    if ($CONFIG['filter_bad_words']) {
4779
4780        static $ercp = array();
4781
4782        if (!count($ercp)) {
4783            foreach ($lang_bad_words as $word) {
4784                $ercp[] = '/' . ($word[0] == '*' ? '': '\b') . str_replace('*', '', $word) . ($word[(strlen($word)-1)] == '*' ? '': '\b') . '/i';
4785            }
4786        }
4787
4788        if (is_array($str)) {
4789
4790            $new_str = array();
4791
4792            foreach ($str as $key => $element) {
4793                $new_str[$key] = filter_content($element);
4794            }
4795
4796            $str = $new_str;
4797
4798        } else {
4799            $stripped_str = strip_tags($str);
4800            $str          = preg_replace($ercp, '(...)', $stripped_str);
4801        }
4802    }
4803    return $str;
4804} // function filter_content
4805
4806function utf_strtolower($str)
4807{
4808    if (!function_exists('mb_strtolower')) {
4809        require 'include/mb.inc.php';
4810    }
4811    return mb_strtolower($str);
4812} // function utf_strtolower
4813
4814function utf_substr($str, $start, $end = null)
4815{
4816    if (!function_exists('mb_substr')) {
4817        require 'include/mb.inc.php';
4818    }
4819    return mb_substr($str, $start, $end);
4820} // function utf_substr
4821
4822function utf_strlen($str)
4823{
4824    if (!function_exists('mb_strlen')) {
4825        require 'include/mb.inc.php';
4826    }
4827    return mb_strlen($str);
4828} // function utf_strlen
4829
4830function utf_ucfirst($str)
4831{
4832    if (!function_exists('mb_strtoupper')) {
4833        require 'include/mb.inc.php';
4834    }
4835    return mb_strtoupper(mb_substr($str, 0, 1)) . mb_substr($str, 1);
4836} // function utf_ucfirst
4837
4838
4839/*
4840  This function replaces special UTF characters to their ANSI equivelant for
4841  correct processing by MySQL, keywords, search, etc. since a bug has been
4842  found:  http://coppermine-gallery.net/forum/index.php?topic=17366.0
4843*/
4844function utf_replace($str)
4845{
4846    return preg_replace('#[\xC2][\xA0]|[\xE3][\x80][\x80]#', ' ', $str);
4847} // function utf_replace
4848
4849function replace_forbidden($str)
4850{
4851    static $forbidden_chars;
4852    if (!is_array($forbidden_chars)) {
4853        global $CONFIG, $mb_utf8_regex;
4854        if (function_exists('html_entity_decode')) {
4855            $chars = html_entity_decode($CONFIG['forbiden_fname_char'], ENT_QUOTES, 'UTF-8');
4856        } else {
4857            $chars = str_replace(array('&amp;', '&quot;', '&lt;', '&gt;', '&nbsp;', '&#39;'), array('&', '"', '<', '>', ' ', "'"), $CONFIG['forbiden_fname_char']);
4858        }
4859        preg_match_all("#$mb_utf8_regex".'|[\x00-\x7F]#', $chars, $forbidden_chars);
4860    }
4861    /**
4862     * $str may also come from $_POST, in this case, all &, ", etc will get replaced with entities.
4863     * Replace them back to normal chars so that the str_replace below can work.
4864     */
4865    $str = str_replace(array('&amp;', '&quot;', '&lt;', '&gt;'), array('&', '"', '<', '>'), $str);
4866
4867    $return = str_replace($forbidden_chars[0], '_', $str);
4868
4869    $condition = array (
4870        'transliteration' => true,
4871        'special_chars' => true
4872    );
4873    $condition = CPGPluginAPI::filter('replace_forbidden_conditions', $condition);
4874
4875    /**
4876     * Transliteration
4877     */
4878    if ($condition['transliteration']) {
4879        require_once 'include/transliteration.inc.php';
4880        $return = transliteration_process($return, '_');
4881    }
4882
4883    /**
4884     * Replace special chars
4885     */
4886    if ($condition['special_chars']) {
4887        $return = str_replace('%', '', rawurlencode($return));
4888    }
4889
4890    /**
4891     * Fix the obscure, misdocumented "feature" in Apache that causes the server
4892     * to process the last "valid" extension in the filename (rar exploit): replace all
4893     * dots in the filename except the last one with an underscore.
4894     */
4895    // This could be concatenated into a more efficient string later, keeping it in three
4896    // lines for better readability for now.
4897    $extension = ltrim(substr($return, strrpos($return, '.')), '.');
4898
4899    $filenameWithoutExtension = str_replace('.' . $extension, '', $return);
4900
4901    $return = str_replace('.', '_', $filenameWithoutExtension) . '.' . $extension;
4902
4903    return $return;
4904} // function replace_forbidden
4905
4906
4907/**
4908 * resetDetailHits()
4909 *
4910 * Reset the detailed hits stored in hit_stats table for the given pid
4911 *
4912 * @param int or array $pid
4913 **/
4914function resetDetailHits($pid)
4915{
4916    global $CONFIG;
4917
4918    if (is_array($pid)) {
4919        if (!count($pid)) {
4920            return;
4921        } else {
4922            $clause = "pid IN (".implode(',', $pid).")";
4923        }
4924    } else {
4925        $clause = "pid = '$pid'";
4926    }
4927
4928    cpg_db_query("DELETE FROM {$CONFIG['TABLE_HIT_STATS']} WHERE $clause");
4929} // function resetDetailHits
4930
4931
4932/**
4933 * resetDetailVotes()
4934 *
4935 * Reset the detailed votes stored in vote_stats table for the given pid
4936 *
4937 * @param int or array $pid
4938 **/
4939function resetDetailVotes($pid)
4940{
4941    global $CONFIG;
4942
4943    if (is_array($pid)) {
4944        if (!count($pid)) {
4945            return;
4946        } else {
4947            $clause = " IN (".implode(',', $pid).")";
4948        }
4949    } else {
4950        $clause = " = '$pid'";
4951    }
4952
4953    cpg_db_query("DELETE FROM {$CONFIG['TABLE_VOTE_STATS']} WHERE pid $clause");
4954    cpg_db_query("DELETE FROM {$CONFIG['TABLE_VOTES']} WHERE pic_id $clause");
4955} // function resetDetailVotes
4956
4957
4958/**
4959* cpgValidateColor()
4960*
4961* Validate a string: is a color code in x11 or hex?
4962*
4963* Returns the validated color string (hex with a leading #-sign or x11 color-code, or nothing if not valid)
4964*
4965* @param string $color
4966* @return $color
4967**/
4968function cpgValidateColor($color)
4969{
4970    $x11ColorNames = array('white', 'ivory', 'lightyellow', 'yellow', 'snow', 'floralwhite', 'lemonchiffon', 'cornsilk', 'seashell', 'lavenderblush', 'papayawhip', 'blanchedalmond', 'mistyrose', 'bisque', 'moccasin', 'navajowhite', 'peachpuff', 'gold', 'pink', 'lightpink', 'orange', 'lightsalmon', 'darkorange', 'coral', 'hotpink', 'tomato', 'orangered', 'deeppink', 'fuchsia', 'magenta', 'red', 'oldlace', 'lightgoldenrodyellow', 'linen', 'antiquewhite', 'salmon', 'ghostwhite', 'mintcream', 'whitesmoke', 'beige', 'wheat', 'sandybrown', 'azure', 'honeydew', 'aliceblue', 'khaki', 'lightcoral', 'palegoldenrod', 'violet', 'darksalmon', 'lavender', 'lightcyan', 'burlywood', 'plum', 'gainsboro', 'crimson', 'palevioletred', 'goldenrod', 'orchid', 'thistle', 'lightgrey', 'tan', 'chocolate', 'peru', 'indianred', 'mediumvioletred', 'silver', 'darkkhaki', 'rosybrown', 'mediumorchid', 'darkgoldenrod', 'firebrick', 'powderblue', 'lightsteelblue', 'paleturquoise', 'greenyellow', 'lightblue', 'darkgray', 'brown', 'sienna', 'yellowgreen', 'darkorchid', 'palegreen', 'darkviolet', 'mediumpurple', 'lightgreen', 'darkseagreen', 'saddlebrown', 'darkmagenta', 'darkred', 'blueviolet', 'lightskyblue', 'skyblue', 'gray', 'olive', 'purple', 'maroon', 'aquamarine', 'chartreuse', 'lawngreen', 'mediumslateblue', 'lightslategray', 'slategray', 'olivedrab', 'slateblue', 'dimgray', 'mediumaquamarine', 'cornflowerblue', 'cadetblue', 'darkolivegreen', 'indigo', 'mediumturquoise', 'darkslateblue', 'steelblue', 'royalblue', 'turquoise', 'mediumseagreen', 'limegreen', 'darkslategray', 'seagreen', 'forestgreen', 'lightseagreen', 'dodgerblue', 'midnightblue', 'aqua', 'cyan', 'springgreen', 'lime', 'mediumspringgreen', 'darkturquoise', 'deepskyblue', 'darkcyan', 'teal', 'green', 'darkgreen', 'blue', 'mediumblue', 'darkblue', 'navy', 'black');
4971
4972    if (in_array(strtolower($color), $x11ColorNames) == TRUE) {
4973        return $color;
4974    } else {
4975        $color = ltrim($color, '#'); // strip a leading #-sign if there is one
4976        if (preg_match('/^[a-f\d]+$/i', strtolower($color)) == TRUE && strlen($color) <= 6) {
4977            $color = '#' . strtoupper($color);
4978            return $color;
4979        }
4980    }
4981} // function cpgValidateColor
4982
4983
4984/**
4985* cpgStoreTempMessage()
4986*
4987* Store a temporary message to the database to carry over from one page to the other
4988*
4989* @param string $message
4990* @return $message_id
4991**/
4992function cpgStoreTempMessage($message)
4993{
4994    global $CONFIG;
4995
4996    $message = urlencode($message);
4997
4998    // come up with a unique message id
4999    $message_id = md5(uniqid(mt_rand(), true));
5000
5001    // write the message to the database
5002    $user_id = USER_ID;
5003    $time    = time();
5004
5005    // Insert the record in database
5006    $query = "INSERT INTO {$CONFIG['TABLE_TEMP_MESSAGES']} "
5007                ." SET "
5008                    ." message_id = '$message_id', "
5009                    ." user_id = '$user_id', "
5010                    ." time   = '$time', "
5011                    ." message = '$message'";
5012    cpg_db_query($query);
5013    // return the message_id
5014    return $message_id;
5015} // function cpgStoreTempMessage
5016
5017
5018/**
5019* cpgFetchTempMessage()
5020*
5021* Fetch a temporary message from the database and then delete it.
5022*
5023*
5024*
5025* @param string $message_id
5026* @return $message
5027**/
5028function cpgFetchTempMessage($message_id)
5029{
5030    global $CONFIG;
5031
5032    //$user_id = USER_ID;
5033    //$time    = time();
5034    $message = '';
5035
5036    // Read the record in database
5037    $query = "SELECT message FROM {$CONFIG['TABLE_TEMP_MESSAGES']} "
5038            . " WHERE message_id = '$message_id' LIMIT 1";
5039
5040    $result = cpg_db_query($query);
5041
5042    if ($result->numRows() > 0) {
5043        $row     = $result->fetchRow();
5044        $message = urldecode($row[0]);
5045    }
5046    $result->free();
5047
5048    // delete the message once fetched
5049    $query = "DELETE FROM {$CONFIG['TABLE_TEMP_MESSAGES']} WHERE message_id = '$message_id'";
5050    cpg_db_query($query);
5051
5052    // return the message
5053    return $message;
5054} // function cpgFetchTempMessage
5055
5056
5057/**
5058* cpgCleanTempMessage()
5059*
5060* Clean up the temporary messages table (garbage collection).
5061*
5062* @param string $seconds
5063* @return void
5064**/
5065function cpgCleanTempMessage($seconds = 3600)
5066{
5067    global $CONFIG;
5068
5069    $time = time() - (int) $seconds;
5070    // delete the messages older than the specified amount
5071    cpg_db_query("DELETE FROM {$CONFIG['TABLE_TEMP_MESSAGES']} WHERE time < $time");
5072} // function cpgCleanTempMessage
5073
5074
5075/**
5076* cpgRedirectPage()
5077*
5078* Redirect to the target page or display an info screen first and then redirect
5079*
5080* @param string $targetAddress
5081* @param string $caption
5082* @param string $message
5083* @param string $countdown
5084* @param string $type (possible values: 'info', 'error', 'warning', 'validation', 'success' -> theme_display_message_block
5085* @return void
5086**/
5087function cpgRedirectPage($targetAddress = '', $caption = '', $message = '', $countdown = 0, $type = 'info')
5088{
5089    global $CONFIG, $USER_DATA, $lang_common;
5090
5091    $logged_in = (USER_ID || (isset($USER_DATA['user_id']) && is_numeric($USER_DATA['user_id'])));
5092    if (!$logged_in && $CONFIG['allow_unlogged_access'] == 0) {
5093        // Anonymous access to site is not allowed, so need to redirect to login page
5094        $targetAddress = 'login.php';
5095    }
5096
5097    if ($CONFIG['display_redirection_page'] == 0) {
5098        $header_location = (@preg_match('/Microsoft|WebSTAR|Xitami/', getenv('SERVER_SOFTWARE'))) ? 'Refresh: 0; URL=' : 'Location: ';
5099        if (strpos($targetAddress, '?') == FALSE) {
5100            $separator = '?';
5101        } else {
5102            $separator = '&';
5103        }
5104        header($header_location . $targetAddress . $separator . 'message_id=' . cpgStoreTempMessage($message) . '&message_icon=' . $type . '#cpgMessageBlock');
5105        pageheader($caption, "<META http-equiv=\"refresh\" content=\"1;url=$targetAddress\">");
5106        msg_box($caption, $message, $lang_common['continue'], $targetAddress, $type);
5107        pagefooter();
5108        exit;
5109    } else {
5110        pageheader($caption, "<META http-equiv=\"refresh\" content=\"1;url=$targetAddress\">");
5111        msg_box($caption, $message, $lang_common['continue'], $targetAddress, $type);
5112        pagefooter();
5113        exit;
5114    }
5115} // function cpgRedirectPage
5116
5117
5118/**
5119* cpgGetScriptNameParams()
5120*
5121* Returns the script name and all vars except the ones defined in exception (which could be an array or a var).
5122* Particularly helpful to create links
5123*
5124* @param mixed $exception
5125* @return $return
5126**/
5127function cpgGetScriptNameParams($exception = '')
5128{
5129    $superCage = Inspekt::makeSuperCage();
5130
5131    if (!is_array($exception)) {
5132        $exception = array(0 => $exception);
5133    }
5134
5135    // get the file name first
5136    $match = $superCage->server->getRaw('SCRIPT_NAME'); // We'll sanitize the script path later
5137
5138    $filename = ltrim(strrchr($match, '/'), '/'); // Drop everything untill (and including) the last slash, this results in the file name only
5139
5140    if (!preg_match('/^(([a-zA-Z0-9_\-]){1,})((\.){1,1})(([a-zA-Z]){2,6})+$/', $filename)) { // the naming pattern we check against: an infinite number of lower and upper case alphanumerals plus allowed special chars dash and underscore, then one (and only one!) dot, then between two and 6 alphanumerals in lower or upper case
5141        $filename = 'index.php'; // If this doesn't match, default to the index page
5142    }
5143
5144    $return = $filename . '?';
5145
5146    // Now get the parameters.
5147    // WARNING: as this function is meant to just return the URL parameters
5148    // (minus the one mentioned in $exception), neither the parameter names
5149    // nor the the values should be sanitized, as we simply don't know here
5150    // against what we're supposed to sanitize.
5151    // For now, I have chosen the safe method, sanitizing the parameters.
5152    // Not sure if this is a bright idea for the future.
5153    // So, use the parameters returned from this function here with the same
5154    // caution that applies to anything the user could tamper with.
5155    // The function is meant to help you generate links (in other words:
5156    // something the user could come up with by typing them just as well),
5157    // so don't abuse this function for anything else.
5158    $matches = $superCage->server->getMatched('QUERY_STRING', '/^[a-zA-Z0-9&=_\/.]+$/');
5159
5160    if ($matches) {
5161        $queryString = explode('&', $matches[0]);
5162    } else {
5163        $queryString = array();
5164    }
5165
5166    foreach ($queryString as $val) {
5167        list($key, $value) = explode('=', $val);
5168        if (!in_array($key, $exception)) {
5169            $return .= $key . "=" . $value . "&amp;";
5170        }
5171    }
5172
5173    return $return;
5174} // function cpgGetScriptNameParams
5175
5176
5177/**
5178 * cpgValidateDate()
5179 *
5180 * Returns $date if $date contains a valid date string representation (yyyy-mm-dd). Returns an empty string if not.
5181 *
5182 * @param mixed $date
5183 * @return $return
5184**/
5185function cpgValidateDate($date)
5186{
5187    if (Inspekt::isDate($date)) {
5188        return $date;
5189    } else {
5190        return '';
5191    }
5192} // function cpgValidateDate
5193
5194
5195/**
5196 * cpgGetRemoteFileByURL()
5197 *
5198 * Returns array that contains content of a file (URL) retrieved by curl, fsockopen or fopen (fallback). Array consists of:
5199 * $return['headers'] = header array,
5200 * $return['error'] = error number and messages array (if error)
5201 * $return['body'] = actual content of the fetched file as string
5202 *
5203 * @param mixed $url, $method, $data, $redirect
5204 * @return array
5205 **/
5206function cpgGetRemoteFileByURL($remoteURL, $method = "GET", $redirect = 10, $minLength = '0')
5207{
5208    global $lang_get_remote_file_by_url, $LINEBREAK;
5209    // FSOCK code snippets taken from http://jeenaparadies.net/weblog/2007/jan/get_remote_file
5210    // Initialize some variables first
5211    $url = parse_url($remoteURL); // chop the URL into protocol, domain, port, folder, file, parameter
5212    if (!isset($url['host'])) {
5213        $url['host'] = '';
5214    }
5215    if (!isset($url['scheme'])) {
5216        $url['scheme'] = '';
5217    }
5218    if (!isset($url['port'])) {
5219        $url['port'] = '';
5220    }
5221    $body      = '';
5222    $headers   = '';
5223    $error     = '';
5224    $timeout   = 3;
5225
5226    // Let's try CURL first
5227    if (function_exists('curl_init')) { // don't bother to try curl if it isn't there in the first place
5228        $curl = curl_init();
5229        curl_setopt($curl, CURLOPT_URL, $remoteURL);
5230        curl_setopt($curl, CURLOPT_HEADER, 0);
5231        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
5232        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
5233        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
5234        $body = curl_exec($curl);
5235        $headers = curl_getinfo($curl);
5236        curl_close($curl);
5237        if (strlen($body) < $minLength) {
5238            // Fetching the data by CURL obviously failed
5239            $error .= sprintf($lang_get_remote_file_by_url['no_data_returned'], $lang_get_remote_file_by_url['curl']) . '<br />'.$LINEBREAK;
5240        } else {
5241            // Fetching the data by CURL was successfull. Let's return the data
5242            return array("headers" => $headers, "body" => $body);
5243        }
5244    } else {
5245        // Curl is not available
5246        $error .= $lang_get_remote_file_by_url['curl_not_available'] . '<br />' . $LINEBREAK;
5247    }
5248    // Now let's try FSOCKOPEN
5249    if ($url['host'] != '') {
5250        $fp = @fsockopen($url['host'], (!empty($url['port']) ? (int)$url['port'] : 80), $errno, $errstr, $timeout);
5251        if ($fp) { // fsockopen file handle success - start
5252            $path   = (!empty($url['path']) ? $url['path'] : "/").(!empty($url['query']) ? "?".$url['query'] : "");
5253            $header = $LINEBREAK . 'Host: '.$url['host'];
5254            //FIXME: '$data' is not defined anywhere?
5255            fputs($fp, $method." ".$path." HTTP/1.0".$header.$LINEBREAK.$LINEBREAK.("post" == strtolower($method) ? $data : ""));
5256            if (!feof($fp)) {
5257                $scheme = fgets($fp);
5258                //list(, $code ) = explode(" ", $scheme);
5259                $headers = explode(" ", $scheme);
5260                //$headers = array("Scheme" => $scheme);
5261            }
5262            while (!feof($fp)) {
5263                $h = fgets($fp);
5264                if ($h == "\r\n" OR $h == "\n") {
5265                    break;
5266                }
5267
5268                list($key, $value) = explode(":", $h, 2);
5269
5270                $key   = strtolower($key);
5271                $value = trim($value);
5272
5273                if (isset($headers[$key])) {
5274                    $headers[$key] .= ',' . trim($value);
5275                } else {
5276                    $headers[$key] = trim($value);
5277                }
5278            }
5279            $body = '';
5280            while ( !feof($fp) ) {
5281                $body .= fgets($fp);
5282            }
5283            fclose($fp);
5284            if (strlen($body) < $minLength) {
5285                // Fetching the data by FSOCKOPEN obviously failed
5286                $error .= sprintf($lang_get_remote_file_by_url['no_data_returned'], $lang_get_remote_file_by_url['fsockopen']) . '<br />' . $LINEBREAK;
5287            } elseif (in_array('404', $headers) == TRUE) {
5288                // We got a 404 error
5289                $error .= sprintf($lang_get_remote_file_by_url['error_number'], '404') . '<br />' . $LINEBREAK;
5290            } else {
5291                // Fetching the data by FSOCKOPEN was successfull. Let's return the data
5292                return array("headers" => $headers, "body" => $body, "error" => $error);
5293            }
5294        } else {  // fsockopen file handle failure - start
5295            $error .= $lang_get_remote_file_by_url['fsockopen'] . ': ';
5296            $error .= sprintf($lang_get_remote_file_by_url['error_number'], $errno);
5297            $error .= sprintf($lang_get_remote_file_by_url['error_message'], $errstr);
5298        }
5299    } else {
5300        //$error .= 'No Hostname set. In other words: we\'re trying to retrieve a local file';
5301    }
5302    // Finally, try FOPEN
5303    @ini_set('allow_url_fopen', '1'); // Try to override the existing policy
5304    if ($url['scheme'] != '') {
5305        $protocol = $url['scheme'] . '://';
5306    } else {
5307        $protocol = '';
5308    }
5309    if ($url['port'] != '') {
5310        $port = ':' . (int) $url['port'];
5311    } elseif ($url['host'] != '') {
5312        $port = ':80';
5313    } else {
5314        $port = '';
5315    }
5316
5317    @ini_set('default_socket_timeout', $timeout);
5318    $handle = @fopen($protocol . $url['host'] . $port . $url['path'], 'r');
5319    if ($handle) {
5320        while (!feof($handle)) {
5321            $body .= fread($handle, 1024);
5322        }
5323        fclose($handle);
5324        if (strlen($body) < $minLength) {
5325            $error .= sprintf($lang_get_remote_file_by_url['no_data_returned'], $lang_get_remote_file_by_url['fopen']) . '<br />' . $LINEBREAK;
5326        } else {
5327            // Fetching the data by FOPEN was successfull. Let's return the data
5328            return array("headers" => $headers, "body" => $body, "error" => $error);
5329        }
5330    } else { // opening the fopen handle failed as well
5331        // if the script reaches this stage, all available methods failed, so let's return the error messages and give up
5332        return array("headers" => $headers, "body" => $body, "error" => $error);
5333    }
5334} // function cpgGetRemoteFileByURL
5335
5336
5337/**
5338 * user_is_allowed()
5339 *
5340 * Check if a user is allowed to edit pictures/albums
5341 *
5342 * @return boolean $check_approve
5343 */
5344function user_is_allowed($include_upload_permissions = true)
5345{
5346    if (GALLERY_ADMIN_MODE) {
5347        return true;
5348    }
5349
5350    $check_approve = false;
5351    global $USER_DATA, $CONFIG;
5352    $superCage = Inspekt::makeSuperCage();
5353
5354    //get albums this user can edit
5355    if ($superCage->get->keyExists('album')) {
5356        $album_id = $superCage->get->getInt('album');
5357    } elseif ($superCage->post->keyExists('aid')) {
5358        $album_id = $superCage->post->getInt('aid');
5359    } else {
5360        //workaround when going straight to modifyalb.php and no album is set in superglobals
5361        if (defined('MODIFYALB_PHP')) {
5362            //check if the user has any album available
5363            $result        = cpg_db_query("SELECT aid FROM {$CONFIG['TABLE_ALBUMS']} WHERE owner = " . $USER_DATA['user_id'] . " LIMIT 1");
5364            $temp_album_id = $result->fetchAssoc(true);
5365            $album_id      = $temp_album_id['aid'];
5366        } else {
5367            $album_id = 0;
5368        }
5369
5370    }
5371
5372    $result = cpg_db_query("SELECT DISTINCT category FROM {$CONFIG['TABLE_ALBUMS']} WHERE owner = '" . $USER_DATA['user_id'] . "' AND aid='$album_id'");
5373
5374    $allowed_albums = cpg_db_fetch_rowset($result, true);
5375
5376    $cat = $allowed_albums ? $allowed_albums[0]['category'] : '';
5377
5378    if ($cat != '') {
5379        $check_approve = true;
5380    }
5381
5382    // We should also whether user has upload permission to the current album. but do this only if album id is set
5383    if ($album_id && $include_upload_permissions) {
5384        $public_albums = cpg_db_query("SELECT aid FROM {$CONFIG['TABLE_ALBUMS']} WHERE category < " . FIRST_USER_CAT . " AND ((uploads='YES' AND (visibility = '0' OR visibility IN ".USER_GROUP_SET." OR alb_password != '')) OR (owner=".USER_ID.")) AND aid=$album_id");
5385
5386        if (count(cpg_db_fetch_rowset($public_albums, true))) {
5387            $check_approve = true;
5388            define('USER_UPLOAD_ALLOWED', 1);
5389        }
5390    }
5391
5392    //check if admin allows editing after closing category
5393    if ($CONFIG['allow_user_edit_after_cat_close'] == 0) {
5394        //Disallowed -> Check if album is in such a category
5395        $result = cpg_db_query("SELECT DISTINCT aid FROM {$CONFIG['TABLE_ALBUMS']} AS alb INNER JOIN {$CONFIG['TABLE_CATMAP']} AS catm ON alb.category=catm.cid WHERE alb.owner = '" . $USER_DATA['user_id'] . "' AND alb.aid='$album_id' AND catm.group_id='" . $USER_DATA['group_id'] . "'");
5396
5397        $allowed_albums = cpg_db_fetch_rowset($result, true);
5398
5399        if ($allowed_albums && $allowed_albums[0]['aid'] == '' && $cat != (FIRST_USER_CAT + USER_ID)) {
5400            $check_approve = false;
5401        } elseif ($cat == (FIRST_USER_CAT + USER_ID)) {
5402            $check_approve = true;
5403        }
5404    }
5405    return $check_approve;
5406} // function user_is_allowed
5407
5408
5409/**
5410 * Function to set/output js files to be included.
5411 *
5412 * This function sets a js file to be included in the head section of the html (in theme_javascript_head() function).
5413 * This function should be called before pageheader function since the js files are included in pageheader.
5414 * If the optional second paramter is passed as true then instead of setting it for later use the html for
5415 * js file inclusion is returned right away
5416 *
5417 * @param string $filename Relative path, from the root of cpg, to the js file
5418 * @param boolean $inline If true then the html is returned
5419 * @return mixed Returns the html for js inclusion or null if inline is false
5420 */
5421function js_include($filename, $inline = false)
5422{
5423    global $JS;
5424
5425    // Proceed with inclusion only if the local file exists or it is in the form of a URL
5426    if (!(file_exists($filename) || is_url($filename))) {
5427        return;
5428    }
5429
5430    // If we need to show the html inline then return the required html
5431    if ($inline) {
5432        return '<script type="text/javascript" src="' . $filename . '"></script>';
5433    } else {
5434        // Else add the file to js includes array which will later be used in head section
5435        $JS['includes'][] = $filename;
5436    }
5437} // function js_include
5438
5439
5440/**
5441 * Function to set a js var from php
5442 *
5443 * This function sets a js var in an array. This array is later converted to json string and outputted
5444 * in the head section of html (in theme_javascript_head function).
5445 * All variables which are set using this function can be accessed in js using the json object named js_vars.
5446 *
5447 * Ex: If you set a variable: set_js_var('myvar', 'myvalue')
5448 * then you can access it in js using : js_vars.myvar
5449 *
5450 * @param string $var Name of the variable by which the value will be accessed in js
5451 * @param mixed $val Value which can be string, int, array or boolean
5452 */
5453function set_js_var($var, $val)
5454{
5455    global $JS;
5456
5457    // Add the variable to global array which will be used in theme_javascript_head() function
5458    $JS['vars'][$var] = $val;
5459} // function set_js_var
5460
5461/**
5462 * Function to convert php array to json
5463 *
5464 * This function is equivalent to PHP 5.2 's json_encode. PHP's native function will be used if the
5465 * version is greater than equal to 5.2
5466 *
5467 * @param array $arr Array which is to be converted to json string
5468 * @return string json string
5469 */
5470if (!function_exists('json_encode')) {
5471
5472    function json_encode($arr)
5473    {
5474        // If the arr is object then gets its variables
5475        if (is_object($arr)) {
5476            $arr = get_object_vars($arr);
5477        }
5478
5479        $out  = array();
5480        $keys = array();
5481
5482        // If arr is array then get its keys
5483        if (is_array($arr)) {
5484            $keys = array_keys($arr);
5485        }
5486
5487        $numeric = true;
5488
5489        // Find whether the keys are numeric or not
5490        if (!empty($keys)) {
5491            $numeric = (array_values($keys) === array_keys(array_values($keys)));
5492        }
5493
5494        foreach ($arr as $key => $val) {
5495            // If the value is array or object then call json_encode recursively
5496            if (is_array($val) || is_object($val)) {
5497                $val = json_encode($val);
5498            } else {
5499                // If the value is not numeric and boolean then escape and quote it
5500                if ((!is_numeric($val) && !is_bool($val))) {
5501                    // Escape these characters with a backslash:
5502                    // " \ / \n \r \t \b \f
5503                    $search  = array('\\', "\n", "\t", "\r", "\b", "\f", '"', '/');
5504                    $replace = array('\\\\', '\\n', '\\t', '\\r', '\\b', '\\f', '\"', '\/');
5505                    $val     = str_replace($search, $replace, $val);
5506                    $val     = '"' . $val . '"';
5507                }
5508                if ($val === null) {
5509                    $val = 'null';
5510                }
5511                if (is_bool($val)) {
5512                    $val = $val ? 'true' : 'false';
5513                }
5514            }
5515            // If key is not numeric then quote it
5516            if (!$numeric) {
5517                $val = '"' . $key . '"' . ':' . $val;
5518            }
5519
5520            $out[] = $val;
5521        }
5522
5523        if (!$numeric) {
5524            $return = '{' . implode(', ', $out) . '}';
5525        } else {
5526            $return = '[' . implode(', ', $out) . ']';
5527        }
5528
5529        return $return;
5530    } // function json_encode
5531} // if !function_exists(json_encode)
5532
5533
5534/**
5535 * function cpg_getimagesize()
5536 *
5537 * Try to get the size of an image, this is custom built as some webhosts disable this function or do weird things with it
5538 *
5539 * @param string $image
5540 * @param boolean $force_cpg_function
5541 * @return array $size
5542 */
5543function cpg_getimagesize($image, $force_cpg_function = false)
5544{
5545    if (!function_exists('getimagesize') || $force_cpg_function) {
5546        // custom function borrowed from http://www.wischik.com/lu/programmer/get-image-size.html
5547        $f = @fopen($image, 'rb');
5548        if ($f === false) {
5549            return false;
5550        }
5551        fseek($f, 0, SEEK_END);
5552        $len = ftell($f);
5553        if ($len < 24) {
5554            fclose($f);
5555            return false;
5556        }
5557        fseek($f, 0);
5558        $buf = fread($f, 24);
5559        if ($buf === false) {
5560            fclose($f);
5561            return false;
5562        }
5563        if (ord($buf[0]) == 255 && ord($buf[1]) == 216 && ord($buf[2]) == 255 && ord($buf[3]) == 224 && $buf[6] == 'J' && $buf[7] == 'F' && $buf[8] == 'I' && $buf[9] == 'F') {
5564            $pos = 2;
5565            while (ord($buf[2]) == 255) {
5566                if (ord($buf[3]) == 192 || ord($buf[3]) == 193 || ord($buf[3]) == 194 || ord($buf[3]) == 195 || ord($buf[3]) == 201 || ord($buf[3]) == 202 || ord($buf[3]) == 203) {
5567                    break; // we've found the image frame
5568                }
5569                $pos += 2 + (ord($buf[4]) << 8) + ord($buf[5]);
5570                if ($pos + 12 > $len) {
5571                    break; // too far
5572                }
5573                fseek($f, $pos);
5574                $buf = $buf[0] . $buf[1] . fread($f, 12);
5575            }
5576        }
5577        fclose($f);
5578
5579        // GIF:
5580        if ($buf[0] == 'G' && $buf[1] == 'I' && $buf[2] == 'F') {
5581            $x    = ord($buf[6]) + (ord($buf[7])<<8);
5582            $y    = ord($buf[8]) + (ord($buf[9])<<8);
5583            $type = 1;
5584        }
5585
5586        // JPEG:
5587        if (ord($buf[0]) == 255 && ord($buf[1]) == 216 && ord($buf[2]) == 255) {
5588            $y    = (ord($buf[7])<<8) + ord($buf[8]);
5589            $x    = (ord($buf[9])<<8) + ord($buf[10]);
5590            $type = 2;
5591        }
5592
5593        // PNG:
5594        if (ord($buf[0]) == 0x89 && $buf[1] == 'P' && $buf[2] == 'N' && $buf[3] == 'G' && ord($buf[4]) == 0x0D && ord($buf[5]) == 0x0A && ord($buf[6]) == 0x1A && ord($buf[7]) == 0x0A && $buf[12] == 'I' && $buf[13] == 'H' && $buf[14] == 'D' && $buf[15] == 'R') {
5595            $x    = (ord($buf[16])<<24) + (ord($buf[17])<<16) + (ord($buf[18])<<8) + (ord($buf[19])<<0);
5596            $y    = (ord($buf[20])<<24) + (ord($buf[21])<<16) + (ord($buf[22])<<8) + (ord($buf[23])<<0);
5597            $type = 3;
5598        }
5599
5600        // added ! from source line since it doesn't work otherwise
5601        if (!isset($x, $y, $type)) {
5602            return false;
5603        }
5604        return array($x, $y, $type, 'height="' . $x . '" width="' . $y . '"');
5605    } else {
5606        $size = getimagesize($image);
5607        if (!$size) {
5608            //false was returned
5609            return cpg_getimagesize($image, true/*force the use of custom function*/);
5610        } elseif (!isset($size[0]) || !isset($size[1])) {
5611            //webhost possibly changed getimagesize functionality
5612            return cpg_getimagesize($image, true/*force the use of custom function*/);
5613        } else {
5614            //function worked as expected, return the results
5615            return $size;
5616        }
5617    }
5618} // function cpg_getimagesize
5619
5620
5621function check_rebuild_tree()
5622{
5623    global $CONFIG;
5624
5625    $result = cpg_db_query("SELECT COUNT(*) FROM {$CONFIG['TABLE_PREFIX']}categories WHERE lft = 0");
5626
5627    list($count) = $result->fetchRow(true);
5628
5629    if ($count) {
5630        return rebuild_tree();
5631    } else {
5632        return false;
5633    }
5634} // function check_rebuild_tree
5635
5636
5637function rebuild_tree($parent = 0, $left = 0, $depth = 0, $pos = 0)
5638{
5639    global $CONFIG;
5640
5641    // the right value of this node is the left value + 1
5642    $right = $left + 1;
5643
5644    if ($CONFIG['categories_alpha_sort'] == 1) {
5645        $sort_query = 'name';
5646    } else {
5647        $sort_query = 'pos';
5648    }
5649
5650    $childpos = 0;
5651
5652    // get all children of this node
5653    $result = cpg_db_query("SELECT cid FROM {$CONFIG['TABLE_PREFIX']}categories WHERE parent = $parent ORDER BY $sort_query, cid");
5654
5655    while ($row = $result->fetchAssoc()) {
5656        // recursive execution of this function for each
5657        // child of this node
5658        // $right is the current right value, which is
5659        // incremented by the rebuild_tree function
5660        if ($row['cid']) {
5661            $right = rebuild_tree($row['cid'], $right, $depth + 1, $childpos++);
5662        }
5663    }
5664    $result->free();
5665
5666    // we've got the left value, and now that we've processed
5667    // the children of this node we also know the right value
5668    cpg_db_query("UPDATE {$CONFIG['TABLE_PREFIX']}categories SET lft = $left, rgt = $right, depth = $depth, pos = $pos WHERE cid = $parent LIMIT 1");
5669
5670    // return the right value of this node + 1
5671    return $right + 1;
5672} // function rebuild_tree
5673
5674/**
5675 * Function to fetch an icon
5676 *
5677 *
5678 * @param string $icon_name: the name of the icon to fetch
5679 * @param string $title string: to populate the title attribute of the <img>-tag
5680 * @param string $config_level boolean: If populated, the config option that allows toggling icons on/off will be ignored and the icon will be displayed no matter what
5681 * @param string $check boolean: If populated, the icon will be checked first if it exists
5682 * @param string $extension: name of the extension, default being 'png'
5683 * @param string $type: what should the function return, default (0) being the entire HTML-tag <img>. Specify "1" to make the function return the actual image path only without the embedding HTML tag
5684 * @return string: the fully populated <img>-tag
5685 */
5686function cpg_fetch_icon($icon_name, $config_level = 0, $title = '', $check = '', $extension = 'png', $type = 0)
5687{
5688    global $CONFIG, $ICON_DIR;
5689    static $fonticons;
5690
5691    if ($CONFIG['enable_menu_icons'] < $config_level) {
5692        return;
5693    }
5694
5695    $return = '';
5696
5697	// provide themes with a way to use font icons
5698	if (defined('THEME_USES_ICON_FONT')) {
5699		if (empty($fonticons)) include_once $ICON_DIR . 'icons.php';
5700		if (!empty($fonticons[$icon_name])) {
5701			if (!empty($fonticons['_beg'])) $return .= $fonticons['_beg'];
5702			$return .= $fonticons[$icon_name];
5703			if (!empty($fonticons['_end'])) $return .= $fonticons['_end'];
5704			return $return;
5705		}
5706	}
5707
5708    // sanitize extension
5709    if ($extension != 'jpg' && $extension != 'gif') {
5710        $extension = 'png';
5711    }
5712
5713    $relative_path = $ICON_DIR . $icon_name . '.' . $extension;
5714    // check if file exists
5715
5716    if ($check != '') {
5717        if (file_exists($relative_path) != TRUE) {
5718            return;
5719        }
5720    }
5721
5722	// fall back to distribution icons for missing theme icons
5723	if ($ICON_DIR != 'images/icons/' && !file_exists($relative_path)) {
5724		$relative_path = 'images/icons/' . $icon_name . '.' . $extension;
5725	}
5726
5727    $return .= '<img src="';
5728    $return .= $relative_path;
5729    $return .= '" border="0" alt="" ';
5730
5731    // Add width and height attributes.
5732    // Actually reading the dimensions would be too time-consuming,
5733    // so we assume 16 x 16 pixels unless specified otherwise in
5734    // the custom theme
5735    if (defined('THEME_HAS_MENU_ICONS')) {
5736        $return .= 'width="' . THEME_HAS_MENU_ICONS . '" height="' . THEME_HAS_MENU_ICONS . '" ';
5737    } else {
5738        $return .= 'width="16" height="16" ';
5739    }
5740
5741    if ($title != '') {
5742        $return .= 'title="' . $title . '" ';
5743    }
5744
5745    $return .= 'class="icon" />';
5746    if ($type == 1) {
5747        $return = $relative_path;
5748    }
5749
5750    return $return;
5751}
5752
5753/**
5754 * Function to convert numbers (floats) into formatted strings
5755 * Example: cpg_float2decimal(100000) will return the string 100,000 for English and 100.000 for German
5756 *
5757 * @param float $float: the value that should be converted
5758 * @return string: the fully populated string
5759 */
5760function cpg_float2decimal($float)
5761{
5762    global $lang_decimal_separator;
5763
5764    $value        = floor($float);
5765    $decimal_page = ltrim(strstr($float, '.'), '.');
5766
5767    // initialize some vars start
5768    $return = '';
5769    $fit    = 3; // how many digits to use
5770    $fill   = '0'; // what to fill
5771    // initialize some vars end
5772
5773    $remainder = floor($value);
5774
5775    while ($remainder >= 1000) {
5776        $chop      = $remainder - (floor($remainder / pow(10, 3)) * pow(10, 3));
5777        $chop      = sprintf("%'{$fill}{$fit}s", $chop); // fill the chop with leading zeros if needed
5778        $remainder = floor($remainder / pow(10, 3));
5779        $return    = $lang_decimal_separator[0] . $chop . $return;
5780    }
5781
5782    $return = $remainder . $return;
5783
5784    if ($decimal_page) {
5785        $return .= $lang_decimal_separator[1] . $decimal_page;
5786    }
5787
5788    return $return;
5789}
5790
5791/**
5792 * Function get the contents of a folder
5793  *
5794 * @param string $foldername: the relative path
5795 * @param string $fileOrFolder: what should be returned: files or sub-folders. Specify 'file' or 'folder'.
5796 * @param string $validextension: What file extension should be filtered. Specify 'gif' or 'html' or similar.
5797 * @param array $exception_array: optional: specify values that should not be taken into account.
5798 * @return array: a list of file names (without extension)
5799 */
5800if (!function_exists('form_get_foldercontent')) {
5801    function form_get_foldercontent ($foldername, $fileOrFolder = 'folder', $validextension = '', $exception_array = array(''))
5802    {
5803        $dir = opendir($foldername);
5804
5805        while ( ($file = readdir($dir)) ) {
5806
5807            if ($fileOrFolder == 'file') {
5808
5809                $extension = ltrim(substr($file, strrpos($file, '.')), '.');
5810
5811                $filenameWithoutExtension = str_replace('.' . $extension, '', $file);
5812
5813                if (is_file($foldername . $file) && $extension == $validextension && in_array($filenameWithoutExtension, $exception_array) != TRUE) {
5814                    $return_array[$filenameWithoutExtension] = $filenameWithoutExtension;
5815                }
5816
5817            } elseif ($fileOrFolder == 'folder') {
5818                if ($file != '.' && $file != '..' && in_array($file, $exception_array) != TRUE && is_dir($foldername . $file)) {
5819                    $return_array[$file] = $file;
5820                }
5821            }
5822        }
5823        closedir($dir);
5824        natcasesort($return_array);
5825
5826        return $return_array;
5827    }
5828}
5829
5830/**
5831 * Function get a list of available languages
5832  *
5833  * @return array: an ascotiative array of language file names (without extension) and language names
5834 */
5835if (!function_exists('cpg_get_available_languages')) {
5836    function cpg_get_available_languages()
5837    {
5838        global $CONFIG;
5839        // Make sure that the language table exists in the first place -
5840        // return without return value if the table doesn't exist because
5841        // the upgrade script hasn't been run
5842        $results = cpg_db_query("SHOW TABLES LIKE '{$CONFIG['TABLE_LANGUAGE']}'");
5843        if (!$results->numRows()) {
5844            // The update script has not been run - use the "old school" language file lookup and return the contents
5845            $language_array = form_get_foldercontent('lang/', 'file', 'php');
5846            ksort($language_array);
5847            return $language_array;
5848        }
5849        $results->free();
5850        unset($results);
5851
5852        // get list of available languages
5853        $results = cpg_db_query("SELECT lang_id, english_name, native_name, custom_name FROM {$CONFIG['TABLE_LANGUAGE']} WHERE available='YES' AND enabled='YES' ");
5854        while ( ($row = $results->fetchArray()) ) {
5855            if (file_exists('lang/' . $row['lang_id'] . '.php')) {
5856                if ($row['custom_name'] != '') {
5857                    $language_array[$row['lang_id']] = $row['custom_name'];
5858                } elseif ($row['english_name'] != '') {
5859                    $language_array[$row['lang_id']] = $row['english_name'];
5860                } else {
5861                    $language_array[$row['lang_id']] = str_replace('_', ' ', ucfirst($row['lang_id']));
5862                }
5863                if ($row['native_name'] != '' && $row['native_name'] != $language_array[$row['lang_id']]) {
5864                    $language_array[$row['lang_id']] .= ' - ' . $row['native_name'];
5865                }
5866            }
5867        } // while
5868        $results->free();
5869
5870        unset($row);
5871        if (count($language_array) == 0) {
5872            unset($language_array);
5873            $language_array = form_get_foldercontent('lang/', 'file', 'php');
5874        }
5875        // sort the array by English name
5876        ksort($language_array);
5877        return $language_array;
5878    }
5879}
5880
5881function array_is_associative($array)
5882{
5883    if (is_array($array) && ! empty($array)) {
5884        for ($iterator = count($array) - 1; $iterator; $iterator--) {
5885            if (!array_key_exists($iterator, $array)) {
5886                return true;
5887            }
5888        }
5889        return !array_key_exists(0, $array);
5890    }
5891    return false;
5892}
5893
5894function cpg_config_set($name, $value, $insert=false)
5895{
5896    global $CONFIG;
5897
5898    if (!isset($CONFIG[$name])) {
5899    	if ($insert) {
5900    		$sql = "INSERT INTO {$CONFIG['TABLE_CONFIG']} (name, value) VALUES ('{$name}', '{$value}')";
5901    		cpg_db_query($sql);
5902			if ($CONFIG['log_mode'] != 0) {
5903				log_write("Setting for '$name' set to '$value' by user " . USER_NAME, CPG_CONFIG_LOG);
5904			}
5905    	}
5906    } else {
5907		if ($CONFIG[$name] === $value) {
5908        	return;
5909    	}
5910		$sql = "UPDATE {$CONFIG['TABLE_CONFIG']} SET value = '$value' WHERE name = '$name'";
5911		cpg_db_query($sql);
5912
5913		if ($CONFIG['log_mode'] != 0) {
5914			log_write("Setting for '$name' changed from '{$CONFIG[$name]}' to '$value' by user " . USER_NAME, CPG_CONFIG_LOG);
5915		}
5916    }
5917
5918    $CONFIG[$name] = $value;
5919}
5920
5921function cpg_format_bytes($bytes)
5922{
5923    global $lang_byte_units, $lang_decimal_separator;
5924    foreach ($lang_byte_units as $unit) {
5925        if ($bytes < 1024) {
5926            break;
5927        }
5928        $bytes /= 1024;
5929    }
5930    return number_format($bytes, 2, $lang_decimal_separator[1], $lang_decimal_separator[0]) . ' ' . $unit;
5931}
5932
5933function cpg_get_type($filename,$filter=null)
5934{
5935    global $CONFIG, $CPG_PHP_SELF;
5936
5937    static $FILE_TYPES = array();
5938
5939    if (!$FILE_TYPES) {
5940
5941        // Map content types to corresponding user parameters
5942        $content_types_to_vars = array(
5943            'image'    => 'allowed_img_types',
5944            'audio'    => 'allowed_snd_types',
5945            'movie'    => 'allowed_mov_types',
5946            'document' => 'allowed_doc_types',
5947        );
5948
5949        $result = cpg_db_query('SELECT extension, mime, content, player FROM ' . $CONFIG['TABLE_FILETYPES']);
5950
5951        $CONFIG['allowed_file_extensions'] = '';
5952
5953        while ( ($row = $result->fetchAssoc()) ) {
5954            // Only add types that are in both the database and user defined parameter
5955            if ($CONFIG[$content_types_to_vars[$row['content']]] == 'ALL' || is_int(strpos('/' . $CONFIG[$content_types_to_vars[$row['content']]] . '/', '/' . $row['extension'] . '/'))) {
5956                $FILE_TYPES[$row['extension']]      = $row;
5957                $CONFIG['allowed_file_extensions'] .= '/' . $row['extension'];
5958            } elseif ($CPG_PHP_SELF == 'displayimage.php') {
5959                $FILE_TYPES[$row['extension']] = $row;
5960            }
5961        }
5962
5963        $CONFIG['allowed_file_extensions'] = substr($CONFIG['allowed_file_extensions'], 1);
5964
5965        $result->free();
5966    }
5967
5968    if (!is_array($filename)) {
5969        $filename = explode('.', $filename);
5970    }
5971
5972    $EOA            = count($filename) - 1;
5973    $filename[$EOA] = strtolower($filename[$EOA]);
5974
5975    if (!is_null($filter) && array_key_exists($filename[$EOA], $FILE_TYPES) && ($FILE_TYPES[$filename[$EOA]]['content'] == $filter)) {
5976        return $FILE_TYPES[$filename[$EOA]];
5977    } elseif (is_null($filter) && array_key_exists($filename[$EOA], $FILE_TYPES)) {
5978        return $FILE_TYPES[$filename[$EOA]];
5979    } else {
5980        return null;
5981    }
5982}
5983
5984function is_image(&$file)
5985{
5986    return cpg_get_type($file, 'image');
5987}
5988
5989function is_movie(&$file)
5990{
5991    return cpg_get_type($file, 'movie');
5992}
5993
5994function is_audio(&$file)
5995{
5996    return cpg_get_type($file, 'audio');
5997}
5998
5999function is_document(&$file)
6000{
6001    return cpg_get_type($file, 'document');
6002}
6003
6004function is_flash(&$file)
6005{
6006    return pathinfo($file, PATHINFO_EXTENSION) == 'swf';
6007}
6008
6009function is_known_filetype($file)
6010{
6011    return is_image($file) || is_movie($file) || is_audio($file) || is_document($file);
6012}
6013
6014/**
6015* Check if a plugin is used to display captcha
6016**/
6017function captcha_plugin_enabled($section = 'contact')
6018{
6019    global $CPG_PLUGINS;
6020
6021    if (!empty($CPG_PLUGINS)) {
6022        foreach ($CPG_PLUGINS as $plugin) {
6023            if ($plugin->enabled && isset($plugin->filters['captcha_'.$section.'_print'])) {
6024                return true;
6025            }
6026        }
6027    }
6028    return false;
6029}
6030
6031
6032/**
6033 * get_cat_data()
6034 *
6035 * @param integer $parent
6036 * @param string $ident
6037 **/
6038
6039function get_cat_data()
6040{
6041    global $CONFIG, $CAT_LIST, $USER_DATA, $cpg_udb;
6042
6043    if (GALLERY_ADMIN_MODE) {
6044        $sql = "SELECT rgt, cid, name FROM {$CONFIG['TABLE_CATEGORIES']} ORDER BY lft ASC";
6045    } else {
6046        $sql = "SELECT rgt, c.cid, name FROM {$CONFIG['TABLE_CATEGORIES']} AS c NATURAL JOIN {$CONFIG['TABLE_CATMAP']} WHERE group_id IN (" . implode(', ', $USER_DATA['groups']) . ") ORDER BY lft ASC";
6047    }
6048    $result = cpg_db_query($sql);
6049    if ($result->numRows() > 0) {
6050        $rowset = cpg_db_fetch_rowset($result, true);
6051        $right = array();
6052        foreach ($rowset as $subcat) {
6053            if (count($right) > 0) {
6054                // check if we should remove a node from the stack
6055                while ($right && $right[count($right) - 1] < $subcat['rgt']) {
6056                    array_pop($right);
6057                }
6058            }
6059            $ident = str_repeat('&nbsp;&nbsp;&nbsp;', count($right));
6060            $right[] = $subcat['rgt'];
6061            $CAT_LIST[] = array($subcat['cid'], $ident . $subcat['name']);
6062            // add user categories
6063            if ($subcat['cid'] == 1 && GALLERY_ADMIN_MODE) {
6064                global $cpg_udb;
6065                // query via bridge
6066                $result2 = $cpg_udb->query("SELECT {$cpg_udb->field['user_id']} AS user_id, {$cpg_udb->field['username']} AS user_name FROM {$cpg_udb->usertable} ORDER BY user_name");
6067                $rowset2 = cpg_db_fetch_rowset($result2, true);
6068                foreach ($rowset2 as $user) {
6069                    $CAT_LIST[] = array(FIRST_USER_CAT + $user['user_id'], '&nbsp;&nbsp;&nbsp;' . $user['user_name']);
6070                }
6071            }
6072        }
6073    }
6074}
6075// end function get_cat_data
6076
6077
6078// Returns an html string containing albums for use in a <select> dropdown.
6079function album_selection_options($selected = 0)
6080{
6081    global $CONFIG, $lang_common, $cpg_udb, $LINEBREAK;
6082    $superCage = Inspekt::makeSuperCage();
6083    // html string of options to be returned
6084    $options = '';
6085    $albums = array();
6086    // load all albums
6087
6088    $uploads_yes = (defined('EDITPICS_PHP') || defined('UPLOAD_PHP')) && USER_CAN_UPLOAD_PICTURES ? 'OR uploads = "YES"' : '';
6089
6090    if ($superCage->get->keyExists('only_empty_albums')) { // don't check for permissions, as it's not security related
6091        $only_empty_albums = "AND aid NOT IN (SELECT aid FROM {$CONFIG['TABLE_PICTURES']})";
6092    } else {
6093        $only_empty_albums = '';
6094    }
6095
6096    if (GALLERY_ADMIN_MODE) {
6097        $result = cpg_db_query("SELECT aid, title, category FROM {$CONFIG['TABLE_ALBUMS']} WHERE 1 $only_empty_albums ORDER BY pos");
6098    } elseif (USER_ID) {
6099        $result = cpg_db_query("SELECT aid, title, category FROM {$CONFIG['TABLE_ALBUMS']} WHERE (category = " . (FIRST_USER_CAT + USER_ID) . " OR owner = " . USER_ID . " $uploads_yes) $only_empty_albums ORDER BY pos");
6100    } else {
6101        $result = cpg_db_query("SELECT aid, title, category FROM {$CONFIG['TABLE_ALBUMS']} WHERE (0 $uploads_yes) $only_empty_albums ORDER BY pos");
6102    }
6103
6104    while ( ($row = $result->fetchAssoc()) ) {
6105        $albums[$row['category']][$row['aid']] = $row['title'];
6106    }
6107    $result->free();
6108    if (!empty($albums[0])) {
6109        // Albums in no category
6110        $options .= '<optgroup label="' . $lang_common['albums_no_category'] . '">';
6111        foreach ($albums[0] as $aid => $title) {
6112            $options .= sprintf('<option value="%d"%s>%s</option>'.$LINEBREAK, $aid, $aid == $selected ? ' selected="selected"' : '', $title);
6113        }
6114        $options .= '</optgroup>';
6115    }
6116    // Load all categories
6117    if (GALLERY_ADMIN_MODE) {
6118        $result = cpg_db_query("SELECT cid, rgt, name FROM {$CONFIG['TABLE_CATEGORIES']} ORDER BY lft");
6119    } elseif (USER_ID) {
6120        $result = cpg_db_query("SELECT DISTINCT c.cid, c.lft, c.rgt, c.name FROM {$CONFIG['TABLE_ALBUMS']} AS a RIGHT JOIN {$CONFIG['TABLE_CATEGORIES']} AS c ON a.category = c.cid WHERE c.cid = " . USER_GAL_CAT . " OR a.owner = " . USER_ID . " $uploads_yes ORDER BY lft");
6121    } else {
6122        $result = cpg_db_query("SELECT DISTINCT c.cid, c.lft, c.rgt, c.name FROM {$CONFIG['TABLE_ALBUMS']} AS a RIGHT JOIN {$CONFIG['TABLE_CATEGORIES']} AS c ON a.category = c.cid WHERE 0 $uploads_yes ORDER BY lft");
6123    }
6124
6125    $cats = array();
6126    // Loop through all categories
6127    while ( ($row = $result->fetchAssoc())) {
6128        // Determine category hierarchy
6129        if (count($cats)) {
6130            while ($cats && $cats[count($cats)-1]['rgt'] < $row['rgt']) {
6131                array_pop($cats);
6132            }
6133        }
6134        $cats[] = $row;
6135        // Add this category to the hierarchy
6136        if ($row['cid'] == USER_GAL_CAT) {
6137            // User galleries
6138            $options .= '<optgroup label="' . $lang_common['personal_albums'] . '">' . $LINEBREAK;
6139
6140            if (GALLERY_ADMIN_MODE) {
6141            	// query via bridge
6142                $result2 = $cpg_udb->query("SELECT {$cpg_udb->field['user_id']} AS user_id, {$cpg_udb->field['username']} AS user_name "
6143                    . "FROM {$cpg_udb->usertable} ORDER BY {$cpg_udb->field['username']}");
6144                $users = cpg_db_fetch_rowset($result2, true);
6145            } else {
6146                $users = array(array('user_id' => USER_ID, 'user_name' => USER_NAME));
6147            }
6148
6149            foreach ($users as $user) {
6150                if (!empty($albums[$user['user_id'] + FIRST_USER_CAT])) {
6151                    $options .= '<optgroup label="&nbsp;&nbsp;&nbsp;&nbsp;' . $user['user_name'] . '">' . $LINEBREAK;
6152                    foreach ($albums[$user['user_id'] + FIRST_USER_CAT] as $aid => $title) {
6153                        $options .= sprintf('<option value="%d"%s>%s</option>' . $LINEBREAK, $aid, $aid == $selected ? ' selected="selected"' : '', '&nbsp;&nbsp;&nbsp;&nbsp;'.$title);
6154                    }
6155                    $options .= '</optgroup>';
6156                }
6157            }
6158            $options .= '</optgroup>';
6159            unset($users);
6160            continue;
6161        }
6162        // calculate indent for this level
6163        $indent = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', (count($cats) - 1));
6164        // albums in the category
6165        if (!empty($albums[$row['cid']])) {
6166            // category header
6167            $options .= '<optgroup label="' . $indent . $row['name'] . '">' . $LINEBREAK;
6168
6169            foreach ($albums[$row['cid']] as $aid => $title) {
6170                $options .= sprintf('<option value="%d"%s>%s</option>' . $LINEBREAK, $aid, $aid == $selected ? ' selected="selected"' : '', $indent . $title);
6171            }
6172
6173            $options .= '</optgroup>';
6174        }
6175    }
6176    $result->free();
6177
6178    return $options;
6179}
6180// end function album_selection_options
6181
6182
6183/**
6184* Function used to delete a folder and everything within it except symlinks.
6185* Does not perform any checks against the path parameter, so only perform
6186* this function against trusted, validated paths and never against un-sanitized
6187* user input!
6188* Function should be performed by admin only, but is not limited to admin. There
6189* are no particular permission-checks.
6190* Contains hard-coded English language strings that are meant for debug output only.
6191* @param $path full-path or relative path to folder
6192* @return array(success(T)/failure(F), debug output)
6193*/
6194function cpg_folder_file_delete($path)
6195{
6196    global $CONFIG;
6197
6198    if ($CONFIG['debug_notice'] == 0) {
6199        $output = '';
6200    } else {
6201        if ($CONFIG['debug_mode'] == 1) {
6202            $output = 1;
6203        } elseif ($CONFIG['debug_mode'] == 2 && defined(GALLERY_ADMIN_MODE)) {
6204            $output = 1;
6205        } else {
6206            $output = '';
6207        }
6208    }
6209    // Perform some validity checks first
6210    rtrim($path,'/'); // if the path has a trailing slash we remove it here
6211    if (is_link($path)) { // We don't want to delete symlinks, so let's just return some text
6212        if ($output != '') {
6213            return array(false,$path . ' appears to be a symlink - we won\'t delete them for security reasons');
6214        } else {
6215            return array(false,'');
6216        }
6217    }
6218    if (!file_exists($path) && !is_dir($path)) {// if the path is not valid
6219        if ($output != '') {
6220            return array(false,'Path ' . $path . ' does not exist');
6221        } else {
6222            return array(false,'');
6223        }
6224    } elseif (!is_readable($path)) {// ... if the path is not readable
6225        if ($output != '') {
6226            return array(false,'Path ' . $path . ' is not readable');
6227        } else {
6228            return array(false,'');
6229        }
6230    }
6231    if (is_dir($path)) {
6232        if (version_compare(PHP_VERSION, '5.0.0') < 0) {
6233            $entries = array();
6234            if ( ($handle = opendir($path)) ) {
6235                while (false !== ($file = readdir($handle))) {
6236                    $entries[] = $file;
6237                }
6238                closedir($handle);
6239            }
6240        } else {
6241            $entries = scandir($path);
6242            if ($entries === false) {
6243                $entries = array();
6244            }
6245        }
6246        foreach ($entries as $entry) {
6247            if ($entry != '.' && $entry != '..') {
6248                cpg_folder_file_delete($path.'/'.$entry);
6249            }
6250        }
6251        // Delete the folder
6252        if ($output != '') {
6253            $result = rmdir($path);
6254        } else {
6255            $result = @rmdir($path);
6256        }
6257        if ($result == 1) {
6258            // We have issued the command to delete the folder and everything
6259            // appears to have gone fine, but we can not be sure if we succeeded,
6260            // so we'll test if the folder still is there.
6261            clearstatcache(); // We need to clear the cache before we check if the folder is still there.
6262            if (is_dir($path)) {
6263                $debug_output = 'Couldn\'t delete folder ' . $path . '. Review permissions!';
6264                $success = false;
6265            } else {
6266                $debug_output = 'Folder deleted successfully';
6267                $success = true;
6268            }
6269        } else {
6270            $debug_output = 'Couldn\'t delete folder ' . $path . '. Review permissions!';
6271            $success = false;
6272        }
6273        if ($output != '') {
6274            return array($success,$debug_output);
6275        } else {
6276            return array($success,'');
6277        }
6278    } else {
6279        // Delete the file
6280        if ($output != '') {
6281            $result = unlink($path);
6282        } else {
6283            $result = @unlink($path);
6284        }
6285        if ($result == 1) {
6286            // We have issued the command to delete the file and everything
6287            // appears to have gone fine, but we can not be sure if we succeeded,
6288            // so we'll test if the file still is there.
6289            clearstatcache(); // We need to clear the cache first.
6290            if (file_exists($path)) {
6291                $debug_output = 'Couldn\'t delete file ' . $path . '. Review permissions!';
6292                $success = false;
6293            } else {
6294                $debug_output = 'File deleted successfully';
6295                $success = true;
6296            }
6297        } else {
6298            $debug_output = 'Couldn\'t delete file ' . $path . '. Review permissions!';
6299            $success = false;
6300        }
6301        if ($output != '') {
6302            return array($success,$debug_output);
6303        } else {
6304            return array($success,'');
6305        }
6306    }
6307}// end function cpg_folder_file_delete
6308
6309/**
6310 * Get the form token and timestamp for the current user
6311 * this is calculated
6312 *
6313 * @return array ($timestamp, $token)
6314 */
6315function getFormToken($timestamp = null)
6316{
6317    global $raw_ip, $CONFIG;
6318    $superCage = Inspekt::makeSuperCage();
6319
6320    if($timestamp == null){
6321        $timestamp = time();
6322    }
6323
6324    $token_criteria_array = array(
6325        'user_id'   => USER_ID,
6326        'site_tkn'  => $CONFIG['site_token'],
6327        'timestamp' => $timestamp
6328    );
6329
6330    $token_criteria_array = CPGPluginAPI::filter('token_criteria', $token_criteria_array);
6331
6332    $token_string = '';
6333    foreach($token_criteria_array as $value) {
6334        $token_string .= $value;
6335    }
6336
6337    $token = md5($token_string);
6338
6339    return array($timestamp, $token);
6340}
6341
6342/**
6343 * Checks if the form token of a request is valid
6344 *
6345 * @return boolean
6346 */
6347function checkFormToken()
6348{
6349    global $CONFIG;
6350    $superCage = Inspekt::makeSuperCage();
6351
6352    if ($superCage->post->keyExists('form_token') || $superCage->get->keyExists('form_token')){
6353        // check if the token is valid
6354        $received_token = ($superCage->post->keyExists('form_token')) ? $superCage->post->getAlNum('form_token') : $superCage->get->getAlNum('form_token');
6355        $received_timestamp = ($superCage->post->keyExists('timestamp')) ? $superCage->post->getInt('timestamp') : $superCage->get->getInt('timestamp');
6356
6357        //first check if the timestamp hasn't expired yet
6358        if( ($received_timestamp + (int)$CONFIG['form_token_lifetime']) < time() && !defined('LOGOUT_PHP') ){
6359            return false;
6360        }
6361
6362        $token = getFormToken($received_timestamp);
6363        if ($received_token === $token[1]) {
6364            return true;
6365        } else {
6366            return false;
6367        }
6368    }
6369    return false;
6370}
6371
6372/**
6373 * array_slice with preserve_keys for every php version
6374 * (see: http://www.php.net/manual/en/function.array-slice.php#70913)
6375 *
6376 *
6377 * @param array $array Input array
6378 * @param int $offset Start offset
6379 * @param int $length Length
6380 * @param bool $preserve_keys
6381 * @return array
6382 */
6383function array_slice_preserve_keys($array, $offset, $length = null, $preserve_keys = false)
6384{
6385    // PHP >= 5.0.2 is able to do this itself
6386    if((int)str_replace('.', '', phpversion()) >= 502){
6387        return(array_slice($array, $offset, $length, $preserve_keys));
6388    }
6389
6390    if(!$preserve_keys){
6391        return(array_slice($array, $offset, $length));
6392    }else{
6393        // prepare input variables
6394        $result = array();
6395        $i = 0;
6396        if($offset < 0){
6397            $offset = count($array) + $offset;
6398        }
6399        if($length > 0){
6400            $endOffset = $offset + $length;
6401        }else if($length < 0){
6402            $endOffset = count($array) + $length;
6403        }else{
6404            $endOffset = count($array);
6405        }
6406
6407        // collect elements
6408        foreach($array as $key=>$value){
6409            if($i >= $offset && $i < $endOffset){
6410                 $result[$key] = $value;
6411            }
6412            $i++;
6413        }
6414        // return
6415        return($result);
6416    }
6417}
6418
6419/**
6420 * memory_get_usage
6421 * (see comments on http://www.php.net/manual/en/function.memory-get-usage.php)
6422 *
6423 *
6424 * @return amount of memory allocated to PHP in bytes
6425 */
6426if (!function_exists('memory_get_usage')) {
6427    // Only define function if it doesn't exist
6428    function memory_get_usage()
6429    {
6430        // All of the replacement methods assume that we can use exec, so let's test first if it isn't disabled
6431        $disabled_function = ini_get('disable_functions');
6432        if ($disabled_function != '') { // there actually are disabled functions, so let's loop through the list
6433            $disabled_function_array = explode(',', $disabled_function);
6434            $loopCounter = 0;
6435            foreach ($disabled_function_array as $disabled_value) {
6436                if (stristr($disabled_value, 'exec') != FALSE) {
6437                    $loopCounter++;
6438                }
6439            }
6440            if ($loopCounter != 0) {
6441                // exec has been disabled, so we can't use any of the clever surrogates. Return nothing!
6442                return;
6443            }
6444        }
6445        if (substr(PHP_OS,0,3)=='WIN') { // If we are running on Windows
6446            $output = array();
6447            exec( 'tasklist /FI "PID eq ' . getmypid() . '" /FO LIST', $output );
6448            return preg_replace( '/[^0-9]/', '', $output[5] ) * 1024;
6449        } else {
6450            $pid = getmypid();
6451            $output = array();
6452            exec("ps -eo%mem,rss,pid | grep $pid", $output);
6453            $output = explode('  ', $output[0]);
6454            if ($output != '') {
6455                return $output[1] * 1024;
6456            } else {
6457                unset($output);
6458                $output = array();
6459                exec("ps -o rss -p $pid", $output);
6460                return $output[1] *1024;
6461            }
6462        }
6463    }
6464}
6465
6466function cpg_fillArrayFieldWithSpaces($text, $maxchars, $fillUpOn = 'right') {
6467  global $CONFIG;
6468  if (!function_exists('mb_strlen')) {
6469      require 'include/mb.inc.php';
6470  }
6471  $spaceCharsToAdd = $maxchars - mb_strlen($text, $CONFIG['charset']);
6472  if ($spaceCharsToAdd > 0) {
6473    for ($i = 1; $i <= $spaceCharsToAdd; $i++) {
6474      if ($fillUpOn != 'left') {
6475        $text .= ' ';
6476      } else {
6477        $text = ' '.$text;
6478      }
6479    }
6480  }
6481  return $text;
6482}
6483
6484/**
6485 * cpg_fill_string_array_with_spaces
6486 *
6487 * @param array $table (can be variable or array)
6488 * @param string $align alignment of the cells (left or right)
6489 * @param string $return_value desired return value (string or array)
6490 * @return array or string
6491 */
6492function cpg_fill_string_array_with_spaces($table, $separator = '|', $align = 'left', $return_value = 'string') {
6493    global $CONFIG, $LINEBREAK;
6494    // Populate the needed function
6495    if (!function_exists('mb_strlen')) {
6496        require 'include/mb.inc.php';
6497    }
6498    // Sanitize the parameters
6499    if ($align == 'right') {
6500        $fillUpOn = 'left';
6501    } else {
6502        $fillUpOn = 'right';
6503    }
6504    if ($return_value !=  'string' && $return_value != 'array') {
6505        $return_value = 'string';
6506    }
6507    // $table needs to be an associative array
6508    $max_string_length = array();
6509    // set default for return value
6510    if ($return_value == 'array') {
6511        $return = array();
6512    } else {
6513        $return = '';
6514    }
6515    // Find the longest string
6516    foreach ($table as $key) {
6517        if (is_array($key) != TRUE) {
6518            $key = array($key);
6519        }
6520        $loopCounter = 0;
6521        foreach ($key as $subkey) {
6522            $length = mb_strlen($subkey, $CONFIG['charset']);
6523            if (empty($max_string_length[$loopCounter]) || $length > $max_string_length[$loopCounter]) {
6524                $max_string_length[$loopCounter] = $length;
6525            }
6526            $loopCounter++;
6527        }
6528    }
6529    // Fill the $return array / var
6530    foreach ($table as $key => $value) {
6531        if (is_array($value) != TRUE) {
6532            $value = array($value);
6533        }
6534        $loopCounter = 0;
6535        $temp = '';
6536        foreach ($value as $subvalue) {
6537            if ($loopCounter != 0) {
6538                $temp .= $separator;
6539            }
6540            $temp .= cpg_fillArrayFieldWithSpaces($subvalue, $max_string_length[$loopCounter], $fillUpOn) ;
6541            $loopCounter++;
6542        }
6543        if ($return_value == 'array') {
6544            $return[$key] = $temp;
6545        } else {
6546            $return .= $temp . $LINEBREAK;
6547        }
6548    }
6549    return $return;
6550}
6551
6552
6553function cpg_get_comment_page_number($msg_id) {
6554    global $CONFIG;
6555
6556    $result = cpg_db_query("SELECT pid FROM {$CONFIG['TABLE_COMMENTS']} WHERE msg_id = '$msg_id'");
6557    list($pid) = $result->fetchRow(true);
6558
6559    if (!$pid) {
6560        return false;
6561    }
6562
6563    $result = cpg_db_query("SELECT COUNT(msg_id) FROM {$CONFIG['TABLE_COMMENTS']} WHERE pid='$pid'");
6564    list($num) = $result->fetchRow(true);
6565    $page_count = ceil($num / $CONFIG['comments_per_page']);
6566
6567    $comment_sort_order = ($CONFIG['comments_sort_descending'] == 1) ? 'ASC' : 'DESC'; // we need to count reversed
6568    $result = cpg_db_query("SELECT msg_id FROM {$CONFIG['TABLE_COMMENTS']} WHERE pid='$pid' ORDER BY msg_id $comment_sort_order");
6569    $i = 0;
6570    $page = $page_count + 1;
6571    while ($row = $result->fetchAssoc()) {
6572        if (($i++ % $CONFIG['comments_per_page']) == 0) {
6573            $page--;
6574        }
6575        if ($row['msg_id'] == $msg_id) {
6576            break;
6577        }
6578    }
6579    $result->free();
6580
6581    return $page;
6582}
6583
6584/**
6585 * cpg_lang_name2code
6586 *
6587 * @param string $lang_name the name of a language file
6588 * @return string $return language code (flag name)
6589 */
6590function cpg_lang_name2code($lang_name) {
6591    global $CONFIG;
6592    if ($lang_name != '') {
6593        $result = cpg_db_query("SELECT flag, abbr FROM {$CONFIG['TABLE_LANGUAGE']} WHERE lang_id='{$lang_name}' LIMIT 1");
6594        list($flag, $abbr) = $result->fetchRow(true);
6595        if ($abbr != '') {
6596            return $abbr;
6597        } elseif ($flag != '') {
6598            return $flag;
6599        }  else {
6600            return FALSE;
6601        }
6602    }
6603}
6604
6605
6606function cpg_get_guest_token() {
6607    global $CONFIG, $raw_ip;
6608    return md5($CONFIG['site_token'] . $raw_ip);
6609}
6610
6611/**
6612 * str_ireplace
6613 *
6614 * PHP4-replacement, taken from the user comments at http://theserverpages.com/php/manual/en/function.str-ireplace.php
6615 */
6616if (!function_exists('str_ireplace')) {
6617    function str_ireplace($search, $replace, $subject) {
6618        if (is_array($search)) {
6619            foreach ($search as $word) {
6620                $words[] = "/" . $word . "/i";
6621            }
6622        }
6623        else {
6624            $words = "/" . $search . "/i";
6625        }
6626        return preg_replace($words, $replace, $subject);
6627    }
6628}
6629
6630
6631// Check if a an album is password protected album and the user has access rights to that album
6632function cpg_pw_protected_album_access($aid) {
6633    global $CONFIG, $FORBIDDEN_SET_DATA;
6634
6635    // Check if the user has already access to the album
6636    if (!in_array($aid, $FORBIDDEN_SET_DATA)) {
6637        return 2;
6638    }
6639
6640    // Fetch all password protected albums
6641    $result = cpg_db_query("SELECT aid FROM {$CONFIG['TABLE_ALBUMS']} WHERE alb_password != ''");
6642    while($row = $result->fetchAssoc()) {
6643        $aid_w_pw[] = $row['aid'];
6644    }
6645    $result->free();
6646
6647    // Check if the user has access to the password protected album if he knows the correct password
6648    if (!in_array($aid, array_diff($FORBIDDEN_SET_DATA, $aid_w_pw))) {
6649        return 1;
6650    } else {
6651        return 0;
6652    }
6653}
6654
6655
6656/**
6657 * Get all user group IDs for a particular user
6658 *
6659 * @param integer $user_id
6660 * @return array
6661 */
6662function cpg_get_groups($user_id) {
6663    global $cpg_udb;
6664
6665    if (!$cpg_udb->can_join_tables) {
6666        return false;
6667    }
6668
6669    $f = $cpg_udb->field;
6670    if (isset($cpg_udb->usergroupstable)){
6671        $sql = "SELECT u.{$f['user_id']} AS id, ug.{$f['usertbl_group_id']} AS group_id "
6672                . "FROM {$cpg_udb->usertable} AS u, {$cpg_udb->usergroupstable} AS ug "
6673                . "WHERE u.{$f['user_id']}=ug.{$f['user_id']} AND u.{$f['user_id']}='{$user_id}'";
6674    } else {
6675        $sql = "SELECT u.{$f['user_id']} AS id, u.{$f['usertbl_group_id']} AS group_id "
6676                . "FROM {$cpg_udb->usertable} AS u "
6677                . "WHERE u.{$f['user_id']}='{$user_id}'";
6678    }
6679    return $cpg_udb->get_groups(cpg_db_query($sql)->fetchAssoc(true));
6680}
6681
6682
6683/**
6684 * Strip whitespaces from the beginning and end of each keyword
6685 *
6686 * @param string $keywords
6687  */
6688function cpg_trim_keywords(&$keywords) {
6689    global $CONFIG;
6690
6691    $keywords_new = array();
6692    $keywords = explode($CONFIG['keyword_separator'], trim(html_entity_decode($keywords)));
6693    foreach ($keywords as $word) {
6694        if (trim($word)) {
6695            $keywords_new[] = trim(Inspekt::getEscaped($word));
6696        }
6697    }
6698    $keywords = implode($CONFIG['keyword_separator'], $keywords_new);
6699}
6700
6701
6702/**
6703 * Determine if an intermediate-sized picture should be used
6704 * The weird comparision is because only 'picture_width' is stored as config value
6705 *
6706 * @param integer $pwidth
6707 * @param integer $pheight
6708 * @return bool
6709 */
6710function cpg_picture_dimension_exceeds_intermediate_limit($pwidth, $pheight) {
6711    global $CONFIG;
6712
6713    $resize_method = $CONFIG['picture_use'] == "thumb" ? ($CONFIG['thumb_use'] == "ex" ? "any" : $CONFIG['thumb_use']) : $CONFIG['picture_use'];
6714    if ($resize_method == 'ht' && $pheight > $CONFIG['picture_width']) {
6715        return true;
6716    } elseif ($resize_method == 'wd' && $pwidth > $CONFIG['picture_width']) {
6717        return true;
6718    } elseif ($resize_method == 'any' && max($pwidth, $pheight) > $CONFIG['picture_width']) {
6719        return true;
6720    } else {
6721        return false;
6722    }
6723}
6724
6725
6726/**
6727 * Dummy function to avoid error message when using the EXIF library on some systems
6728 *
6729 * @param string $str
6730 * @return string
6731 */
6732if (!function_exists('gettext')) {
6733    function gettext($str) {
6734        return $str;
6735    }
6736}
6737
6738
6739/**
6740 * Strip unneeded EXIF data
6741 *
6742 * @param array $exifRawData
6743 * @param array $exif_names
6744 * @return array
6745 */
6746function cpg_exif_strip_data($exifRawData, $exif_names) {
6747    $exif = array();
6748    if (is_array($exifRawData['IFD0'])) {
6749        $exif = array_merge($exif, $exifRawData['IFD0']);
6750    }
6751    if (is_array($exifRawData['SubIFD'])) {
6752        $exif = array_merge($exif, $exifRawData['SubIFD']);
6753    }
6754    if (is_array($exifRawData['SubIFD']['MakerNote'])) {
6755        $exif = array_merge($exif, $exifRawData['SubIFD']['MakerNote']);
6756    }
6757    if (isset($exifRawData['IFD1OffSet'])) {
6758        $exif['IFD1OffSet'] = $exifRawData['IFD1OffSet'];
6759    }
6760    foreach ($exif as $key => $value) {
6761        if (!in_array($key, $exif_names)) {
6762            unset($exif[$key]);
6763        }
6764    }
6765    return $exif;
6766}
6767
6768
6769/**
6770 * htmlspecialchars_decode
6771 *
6772 * PHP4-replacement, taken from the user comments at http://www.php.net/manual/en/function.htmlspecialchars-decode.php
6773 *
6774 * @param string $str
6775 * @return string
6776 */
6777if (!function_exists('htmlspecialchars_decode')) {
6778    function htmlspecialchars_decode($str) {
6779        return strtr($str, array_flip(get_html_translation_table(HTML_SPECIALCHARS)));
6780    }
6781}
6782
6783
6784function only_empty_albums_button() {
6785    global $CONFIG, $CPG_PHP_SELF, $lang_alb_select_box;
6786    $superCage = Inspekt::makeSuperCage();
6787
6788    if ($CONFIG['only_empty_albums'] == 1 || ($CONFIG['only_empty_albums'] == 2 && GALLERY_ADMIN_MODE)) {
6789        $sep = strpos($superCage->server->getRaw('REQUEST_URI'), '?') ? '&amp;' : '?';
6790        if ($superCage->get->keyExists('only_empty_albums')) {
6791            $only_empty_albums = '<a href="'.preg_replace('/[\?&]only_empty_albums/', '', $superCage->server->getRaw('REQUEST_URI')).'" class="button">'.$lang_alb_select_box['all_albums'].'</a>';
6792        } else {
6793            $only_empty_albums = '<a href="'.$superCage->server->getRaw('REQUEST_URI').$sep.'only_empty_albums" class="button">'.$lang_alb_select_box['only_empty_albums'].'</a>';
6794        }
6795    } else {
6796        $only_empty_albums = '';
6797    }
6798
6799    return $only_empty_albums;
6800}
6801
6802
6803/**
6804 * cpg_normalize_path
6805 *
6806 * Method to normalize a virtual path that could handle .. references that go beyond the initial folder reference
6807 * Taken from http://php.net/manual/en/function.realpath.php#112367
6808 */
6809function cpg_normalize_path($path) {
6810    $parts = array(); // Array to build a new path from the good parts
6811    $path = str_replace('\\', '/', $path); // Replace backslashes with forwardslashes
6812    $path = preg_replace('/\/+/', '/', $path); // Combine multiple slashes into a single slash
6813    $segments = explode('/', $path); // Collect path segments
6814    $test = ''; // Initialize testing variable
6815    foreach ($segments as $segment) {
6816        if ($segment != '.') {
6817            $test = array_pop($parts);
6818            if (is_null($test)) {
6819                $parts[] = $segment;
6820            } elseif ($segment == '..') {
6821                if ($test == '..') {
6822                    $parts[] = $test;
6823                }
6824                if ($test == '..' || $test == '') {
6825                    $parts[] = $segment;
6826                }
6827            } else {
6828                $parts[] = $test;
6829                $parts[] = $segment;
6830            }
6831        }
6832    }
6833    return implode(DIRECTORY_SEPARATOR, $parts);
6834}
6835
6836
6837/**
6838 * cpg_album_sort_order
6839 *
6840 * @param string $table_prefix
6841 * @return string
6842 */
6843function cpg_album_sort_order($table_alias = '') {
6844    global $CONFIG, $USER;
6845
6846    $sort_array = array(
6847        'ta' => "{$table_alias}title ASC, {$table_alias}aid ASC",
6848        'td' => "{$table_alias}title DESC, {$table_alias}aid DESC",
6849        'da' => "{$table_alias}aid ASC",
6850        'dd' => "{$table_alias}aid DESC",
6851        'pa' => "{$table_alias}pos ASC, {$table_alias}aid ASC",
6852        'pd' => "{$table_alias}pos DESC, {$table_alias}aid DESC",
6853        'va' => "{$table_alias}alb_hits ASC, {$table_alias}aid ASC",
6854        'vd' => "{$table_alias}alb_hits DESC, {$table_alias}aid DESC",
6855    );
6856
6857    // TODO: add user defined sort order for albums
6858    //$sort_code  = isset($USER['sort'])? $USER['sort'] : $CONFIG['album_sort_order'];
6859    //$sort_order = isset($sort_array[$sort_code]) ? $sort_array[$sort_code] : $sort_array[$CONFIG['album_sort_order']];
6860    $sort_order = $sort_array[$CONFIG['album_sort_order']];
6861
6862    return $sort_order;
6863}
6864
6865
6866/**
6867 * cpg_load_plugin_language_file
6868 *
6869 * @param string $path
6870 */
6871function cpg_load_plugin_language_file($path) {
6872    global $CONFIG;
6873    if (file_exists('./plugins/'.$path.'/lang/english.php')) {
6874        $lg = 'lang_plugin_'.$path;
6875        global $$lg;
6876        include './plugins/'.$path.'/lang/english.php';
6877        if ($CONFIG['lang'] != 'english' && file_exists('./plugins/'.$path.'/lang/'.$CONFIG['lang'].'.php')) {
6878            include './plugins/'.$path.'/lang/'.$CONFIG['lang'].'.php';
6879        }
6880    }
6881}
6882
6883
6884/**
6885 * cpg_get_user_data
6886 *
6887 * Check user login credentials. Returns array of user data or FALSE.
6888 */
6889function cpg_get_user_data($sql_user_email, $password) {
6890    global $cpg_udb;
6891
6892    $sql = "SELECT user_password, user_password_salt, user_password_hash_algorithm, user_password_iterations FROM {$cpg_udb->usertable} WHERE $sql_user_email AND user_active = 'YES' LIMIT 1";
6893    $result = $cpg_udb->query($sql);
6894
6895    if (!$result->numRows()) {
6896        return false;
6897    }
6898
6899    require 'include/passwordhash.inc.php';
6900    $password_params = $result->fetchAssoc(true);
6901
6902    // Check for user in users table
6903    $sql = "SELECT user_id, user_name, user_password, user_password_salt FROM {$cpg_udb->usertable} WHERE $sql_user_email ";
6904    if (!$password_params['user_password_salt']) {
6905        $sql .= "AND BINARY user_password = '".md5($password)."'";
6906    } elseif (!cpg_password_validate($password, $password_params)) {
6907        return false;
6908    }
6909    $sql .= " AND user_active = 'YES' LIMIT 1";
6910
6911    $result = $cpg_udb->query($sql);
6912
6913    if (!$result->numRows()) {
6914        return false;
6915    }
6916
6917    return $result->fetchAssoc(true);
6918}
6919
6920//EOF
6921