OSDN Git Service

CHANGE:: ログイン処理の見直し
[nucleus-jp/nucleus-next.git] / nucleus / libs / globalfunctions.php
1 <?php
2
3 /*
4  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
5  * Copyright (C) 2002-2009 The Nucleus Group
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * (see nucleus/documentation/index.html#license for more info)
12  */
13 /**
14  * @license http://nucleuscms.org/license.txt GNU General Public License
15  * @copyright Copyright (C) 2002-2009 The Nucleus Group
16  * @version $Id: globalfunctions.php 1639 2012-01-29 08:10:11Z sakamocchi $
17  */
18
19 /* needed if we include globalfunctions from install.php */
20 global $nucleus, $CONF, $DIR_LIBS, $DIR_LOCALE, $manager, $member;
21
22 $nucleus['version'] = 'v4.00 SVN';
23 $nucleus['codename'] = '';
24
25 /* check and die if someone is trying to override internal globals (when register_globals turn on) */
26 checkVars(array('nucleus', 'CONF', 'DIR_LIBS', 'MYSQL_HOST', 'MYSQL_USER', 'MYSQL_PASSWORD', 'MYSQL_DATABASE', '$DIR_LOCALE', 'DIR_PLUGINS', 'HTTP_GET_VARS', 'HTTP_POST_VARS', 'HTTP_COOKIE_VARS', 'HTTP_ENV_VARS', 'HTTP_SESSION_VARS', 'HTTP_POST_FILES', 'HTTP_SERVER_VARS', 'GLOBALS', 'argv', 'argc', '_GET', '_POST', '_COOKIE', '_ENV', '_SESSION', '_SERVER', '_FILES'));
27
28 $CONF['debug'] = 0;
29 if ( $CONF['debug'] )
30 {
31         /* report all errors! */
32         error_reporting(E_ALL);
33 }
34 else
35 {
36         ini_set('display_errors','0');
37         error_reporting(E_ERROR | E_WARNING | E_PARSE);
38 }
39
40 /*
41  * FIXME: This is for compatibility since 4.0, should be obsoleted at future release.
42  */
43 if ( !isset($DIR_LOCALES) )
44 {
45         $DIR_LOCALES = $DIR_NUCLEUS . 'locales/';
46 }
47 global $DIR_LANG;
48 if ( !isset($DIR_LANG) )
49 {
50         $DIR_LANG = $DIR_LOCALES;
51 }
52
53 /*
54  * load and initialize i18n class
55  */
56 if (!class_exists('i18n', FALSE))
57 {
58         include($DIR_LIBS . 'i18n.php');
59 }
60 if ( !i18n::init('UTF-8', $DIR_LOCALES) )
61 {
62         exit('Fail to initialize i18n class.');
63 }
64 /*
65  * FIXME: This is for compatibility since 4.0, should be obsoleted at future release.
66  */
67 define('_CHARSET', i18n::get_current_charset());
68
69 /*
70  * Indicates when Nucleus should display startup errors. Set to 1 if you want
71  * the error enabled (default), false otherwise
72  *
73  * alertOnHeadersSent
74  *  Displays an error when visiting a public Nucleus page and headers have
75  *  been sent out to early. This usually indicates an error in either a
76  *  configuration file or a translation file, and could cause Nucleus to
77  *  malfunction
78  * alertOnSecurityRisk
79  * Displays an error only when visiting the admin area, and when one or
80  *  more of the installation files (install.php, install.sql, upgrades/
81  *  directory) are still on the server.
82  */
83 if ( !array_key_exists('alertOnHeadersSent', $CONF) || $CONF['alertOnHeadersSent'] !== 0 )
84 {
85         $CONF['alertOnHeadersSent'] = 1;
86 }
87 $CONF['alertOnSecurityRisk'] = 1;
88 /*
89  * NOTE: this should be removed when releasing 4.0
90 $CONF['ItemURL']           = $CONF['Self'];
91 $CONF['ArchiveURL']          = $CONF['Self'];
92 $CONF['ArchiveListURL']      = $CONF['Self'];
93 $CONF['MemberURL']           = $CONF['Self'];
94 $CONF['SearchURL']           = $CONF['Self'];
95 $CONF['BlogURL']             = $CONF['Self'];
96 $CONF['CategoryURL']         = $CONF['Self'];
97 */
98
99 /*
100  * Set these to 1 to allow viewing of future items or draft items
101  * Should really never do this, but can be useful for some plugins that might need to
102  * Could cause some other issues if you use future posts otr drafts
103  * So use with care
104  */
105 $CONF['allowDrafts'] = 0;
106 $CONF['allowFuture'] = 0;
107
108 if ( getNucleusPatchLevel() > 0 )
109 {
110         $nucleus['version'] .= '/' . getNucleusPatchLevel();
111 }
112
113 /* Avoid notices */
114 if ( !isset($CONF['installscript']) )
115 {
116         $CONF['installscript'] = 0;
117 }
118
119 /* we will use postVar, getVar, ... methods instead of $_GET, $_POST ...*/
120 if ( $CONF['installscript'] != 1 )
121 {
122         /* vars were already included in install.php */
123         include_once($DIR_LIBS . 'vars4.1.0.php');
124 }
125
126 /* sanitize option */
127 $bLoggingSanitizedResult=0;
128 $bSanitizeAndContinue=0;
129
130 $orgRequestURI = serverVar('REQUEST_URI');
131 sanitizeParams();
132
133 /* get all variables that can come from the request and put them in the global scope */
134 $blogid       = requestVar('blogid');
135 $itemid       = intRequestVar('itemid');
136 $catid        = intRequestVar('catid');
137 $skinid       = requestVar('skinid');
138 $memberid     = requestVar('memberid');
139 $archivelist  = requestVar('archivelist');
140 $imagepopup   = requestVar('imagepopup');
141 $archive      = requestVar('archive');
142 $query        = requestVar('query');
143 $highlight    = requestVar('highlight');
144 $amount       = requestVar('amount');
145 $action       = requestVar('action');
146 $nextaction   = requestVar('nextaction');
147 $maxresults   = requestVar('maxresults');
148 $startpos     = intRequestVar('startpos');
149 $errormessage = '';
150 $error        = '';
151 $special      = requestVar('special');
152 $virtualpath  = ((getVar('virtualpath') != null) ? getVar('virtualpath') : serverVar('PATH_INFO'));
153
154 if ( !headers_sent() )
155 {
156         header('Generator: Nucleus CMS ' . $nucleus['version']);
157 }
158
159 /* include core classes that are needed for login & plugin handling */
160 include_once($DIR_LIBS . 'mysql.php');
161 /* added for 3.5 sql_* wrapper */
162 global $MYSQL_HANDLER;
163 if ( !isset($MYSQL_HANDLER) )
164 {
165         $MYSQL_HANDLER = array('mysql','');
166 }
167 if ( $MYSQL_HANDLER[0] == '' )
168 {
169         $MYSQL_HANDLER[0] = 'mysql';
170 }
171 include_once($DIR_LIBS . 'sql/'.$MYSQL_HANDLER[0].'.php');
172 /* end new for 3.5 sql_* wrapper */
173 include($DIR_LIBS . 'MEMBER.php');
174 include($DIR_LIBS . 'ACTIONLOG.php');
175 include($DIR_LIBS . 'MANAGER.php');
176 include($DIR_LIBS . 'PLUGIN.php');
177
178 $manager =& MANAGER::instance();
179
180 /*
181  * make sure there's no unnecessary escaping:
182  * set_magic_quotes_runtime(0);
183  */
184 if ( version_compare(PHP_VERSION, '5.3.0', '<') )
185 {
186         ini_set('magic_quotes_runtime', '0');
187 }
188
189 /* Avoid notices */
190 if ( !array_key_exists('UsingAdminArea', $CONF) )
191 {
192         $CONF['UsingAdminArea'] = 0;
193 }
194
195 /* only needed when updating logs */
196 if ( $CONF['UsingAdminArea'] )
197 {
198         /* XML-RPC client classes */
199         include($DIR_LIBS . 'xmlrpc.inc.php');
200         include_once($DIR_LIBS . 'ADMIN.php');
201 }
202
203 /* connect to database */
204 sql_connect();
205 $SQLCount = 0;
206
207 /* logs sanitized result if need */
208 if ( $orgRequestURI!==serverVar('REQUEST_URI') )
209 {
210         $msg = "Sanitized [" . serverVar('REMOTE_ADDR') . "] ";
211         $msg .= $orgRequestURI . " -> " . serverVar('REQUEST_URI');
212         if ( $bLoggingSanitizedResult )
213         {
214         addToLog(WARNING, $msg);
215         }
216         if ( !$bSanitizeAndContinue )
217         {
218                 die("");
219         }
220 }
221
222 /* makes sure database connection gets closed on script termination */
223 register_shutdown_function('sql_disconnect');
224
225 /* read config */
226 getConfig();
227
228 /*
229  * FIXME: This is for backward compatibility, should be obsoleted near future.
230  */
231 if ( !preg_match('#^(.+)_(.+)_(.+)$#', $CONF['Locale'])
232   && ($CONF['Locale'] = i18n::convert_old_language_file_name_to_locale($CONF['Locale'])) === FALSE )
233 {
234         $CONF['Locale'] = 'en_Latn_US';
235 }
236 if ( !array_key_exists('Language', $CONF) )
237 {
238         $CONF['Language'] = i18n::convert_locale_to_old_language_file_name($CONF['Locale']);
239 }
240 $locale = $CONF['Locale'];
241
242 /* Properly set $CONF['Self'] and others if it's not set...
243  * usually when we are access from admin menu
244  */
245 if ( !array_key_exists('Self', $CONF) )
246 {
247         $CONF['Self'] = $CONF['IndexURL'];
248         /* strip trailing */
249         if ( $CONF['Self'][i18n::strlen($CONF['Self']) -1] == "/" )
250         {
251                 $CONF['Self'] = i18n::substr($CONF['Self'], 0, i18n::strlen($CONF['Self']) -1);
252         }
253 }
254
255 $CONF['ItemURL'] = $CONF['Self'];
256 $CONF['ArchiveURL'] = $CONF['Self'];
257 $CONF['ArchiveListURL'] = $CONF['Self'];
258 $CONF['MemberURL'] = $CONF['Self'];
259 $CONF['SearchURL'] = $CONF['Self'];
260 $CONF['BlogURL'] = $CONF['Self'];
261 $CONF['CategoryURL'] = $CONF['Self'];
262
263 /*
264  *switch URLMode back to normal when $CONF['Self'] ends in .php
265  * this avoids urls like index.php/item/13/index.php/item/15
266  */
267 if ( !array_key_exists('URLMode', $CONF) || (($CONF['URLMode'] == 'pathinfo')
268   && (i18n::substr($CONF['Self'], i18n::strlen($CONF['Self']) - 4) == '.php')) )
269 {
270         $CONF['URLMode'] = 'normal';
271 }
272
273 /* automatically use simpler toolbar for mozilla */
274 if ( ($CONF['DisableJsTools'] == 0)
275    && strstr(serverVar('HTTP_USER_AGENT'), 'Mozilla/5.0')
276    && strstr(serverVar('HTTP_USER_AGENT'), 'Gecko') )
277 {
278         $CONF['DisableJsTools'] = 2;
279 }
280
281 $member = new MEMBER();
282
283 if ( $action == 'login' )
284 {
285         $login = postVar('login');
286         $password = postVar('password');
287         $shared = intPostVar('shared');
288         $member->login($login, $password, $shared);
289 }
290 elseif ( ($action == 'logout') )
291 {
292         $member->logout();
293 }
294 else
295 {
296         $member->cookielogin();
297 }
298
299 /* NOTE: include translation file and set locale */
300 if ( $member->isLoggedIn() && !$member->getLocale())
301 {
302         $locale = $member->getLocale();
303 }
304 include_translation($locale);
305 i18n::set_current_locale($locale);
306
307 /* login completed */
308 $manager->notify('PostAuthentication', array('loggedIn' => $member->isLoggedIn() ) );
309
310 /* next action */
311 if ( $member->isLoggedIn() && $nextaction )
312 {
313         $action = $nextaction;
314 }
315
316 /*
317  * Release ticket for plugin
318  */
319 ticketForPlugin();
320
321 /* first, let's see if the site is disabled or not. always allow admin area access. */
322 if ( $CONF['DisableSite'] && !$member->isAdmin() && !$CONF['UsingAdminArea'] )
323 {
324         redirect($CONF['DisableSiteURL']);
325         exit;
326 }
327
328 /* load other classes */
329 include($DIR_LIBS . 'PARSER.php');
330 include($DIR_LIBS . 'SKIN.php');
331 include($DIR_LIBS . 'TEMPLATE.php');
332 include($DIR_LIBS . 'BLOG.php');
333 include($DIR_LIBS . 'BODYACTIONS.php');
334 include($DIR_LIBS . 'COMMENTS.php');
335 include($DIR_LIBS . 'COMMENT.php');
336 /* include($DIR_LIBS . 'ITEM.php'); */
337 include($DIR_LIBS . 'NOTIFICATION.php');
338 include($DIR_LIBS . 'BAN.php');
339 include($DIR_LIBS . 'PAGEFACTORY.php');
340 include($DIR_LIBS . 'SEARCH.php');
341 include($DIR_LIBS . 'ENTITY.php');
342 include($DIR_LIBS . 'LINK.php');
343
344 /* set lastVisit cookie (if allowed) */
345 if ( !headers_sent() )
346 {
347         if ( $CONF['LastVisit'] )
348         {
349                 setcookie($CONF['CookiePrefix'] . 'lastVisit', time(), time() + 2592000, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
350         }
351         else
352         {
353                 setcookie($CONF['CookiePrefix'] . 'lastVisit', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
354         }
355 }
356
357 if ( !defined('_ARCHIVETYPE_MONTH') )
358 {
359         define('_ARCHIVETYPE_DAY', 'day');
360         define('_ARCHIVETYPE_MONTH', 'month');
361         define('_ARCHIVETYPE_YEAR', 'year');
362 }
363
364 /* decode path_info */
365 if ( $CONF['URLMode'] == 'pathinfo' )
366 {
367         /* initialize keywords if this hasn't been done before */
368         if ( !isset($CONF['ItemKey']) || $CONF['ItemKey'] == '' )
369         {
370                 $CONF['ItemKey'] = 'item';
371         }
372         
373         if ( !isset($CONF['ArchiveKey']) || $CONF['ArchiveKey'] == '' )
374         {
375                 $CONF['ArchiveKey'] = 'archive';
376         }
377         
378         if ( !isset($CONF['ArchivesKey']) || $CONF['ArchivesKey'] == '' )
379         {
380                 $CONF['ArchivesKey'] = 'archives';
381         }
382         
383         if ( !isset($CONF['MemberKey']) || $CONF['MemberKey'] == '' )
384         {
385                 $CONF['MemberKey'] = 'member';
386         }
387         
388         if ( !isset($CONF['BlogKey']) || $CONF['BlogKey'] == '' )
389         {
390                 $CONF['BlogKey'] = 'blog';
391         }
392         
393         if ( !isset($CONF['CategoryKey']) || $CONF['CategoryKey'] == '' )
394         {
395                 $CONF['CategoryKey'] = 'category';
396         }
397         
398         if ( !isset($CONF['SpecialskinKey']) || $CONF['SpecialskinKey'] == '' )
399         {
400                 $CONF['SpecialskinKey'] = 'special';
401         }
402         
403         $parsed = false;
404         $manager->notify(
405                 'ParseURL',
406                 array(
407                         /* e.g. item, blog, ... */
408                         'type' => basename(serverVar('SCRIPT_NAME') ),
409                         'info' => $virtualpath,
410                         'complete' => &$parsed
411                 )
412         );
413         
414         if ( !$parsed )
415         {
416                 /* default implementation */
417                 $data = i18n::explode("/", $virtualpath );
418                 for ( $i = 0; $i < sizeof($data); $i++ )
419                 {
420                         switch ( $data[$i] )
421                         {
422                                 /* item/1 (blogid) */
423                                 case $CONF['ItemKey']:
424                                         $i++;
425                                         
426                                         if ( $i < sizeof($data) )
427                                         {
428                                                 $itemid = intval($data[$i]);
429                                         }
430                                         break;
431                                 
432                                 /* archives/1 (blogid) */
433                                 case $CONF['ArchivesKey']:
434                                                 $i++;
435                                                 if ( $i < sizeof($data) )
436                                                 {
437                                                         $archivelist = intval($data[$i]);
438                                                 }
439                                                 break;
440                                         
441                                 /* two possibilities: archive/yyyy-mm or archive/1/yyyy-mm (with blogid) */
442                                 case $CONF['ArchiveKey']:
443                                         if ( (($i + 1) < sizeof($data) ) && (!strstr($data[$i + 1], '-') ) )
444                                         {
445                                                 $blogid = intval($data[++$i]);
446                                         }
447                                         $i++;
448                                         if ( $i < sizeof($data) ) 
449                                         {
450                                                 $archive = $data[$i];
451                                         }
452                                         break;
453                                         
454                                 /* blogid/1 */
455                                 case 'blogid':
456                                 /* blog/1 */
457                                 case $CONF['BlogKey']:
458                                         $i++;
459                                         if ( $i < sizeof($data) )
460                                         {
461                                                 $blogid = intval($data[$i]);
462                                         }
463                                         break;
464                                 
465                                 /* category/1 (catid) */
466                                 case $CONF['CategoryKey']:
467                                 case 'catid':
468                                         $i++;
469                                         if ( $i < sizeof($data) )
470                                         {
471                                                 $catid = intval($data[$i]);
472                                         }
473                                         break;
474                                 
475                                 case $CONF['MemberKey']:
476                                         $i++;
477                                         if ( $i < sizeof($data) )
478                                         {
479                                                 $memberid = intval($data[$i]);
480                                         }
481                                         break;
482                                 
483                                 case $CONF['SpecialskinKey']:
484                                         $i++;
485                                         if ( $i < sizeof($data) )
486                                         {
487                                                 $special = $data[$i];
488                                                 $_REQUEST['special'] = $special;
489                                         }
490                                         break;
491                                 
492                                 default:
493                                         // skip...
494                         }
495                 }
496         }
497 }
498
499 /*
500  * PostParseURL is a place to cleanup any of the path-related global variables before the selector function is run.
501  * It has 2 values in the data in case the original virtualpath is needed, but most the use will be in tweaking
502  * global variables to clean up (scrub out catid or add catid) or to set someother global variable based on
503  * the values of something like catid or itemid
504  * New in 3.60
505  */
506 $manager->notify(
507         'PostParseURL',
508         array(
509                 /* e.g. item, blog, ... */
510                 'type' => basename(serverVar('SCRIPT_NAME') ),
511                 'info' => $virtualpath
512         )
513 );
514
515 /*
516  * NOTE: Here is the end of initialization
517  */
518
519         /**
520          * This function includes or requires the specified library file
521          * @param string $file
522          * @param bool $once use the _once() version
523          * @param bool $require use require() instead of include()
524          */
525         function include_libs($file, $once = TRUE, $require = TRUE)
526         {
527                 global $DIR_LIBS;
528
529                 // begin if: $DIR_LIBS isn't a directory
530                 if ( !is_dir($DIR_LIBS) )
531                 {
532                         exit;
533                 } // end if
534
535                 $lib_path = $DIR_LIBS . $file;
536
537                 // begin if: 
538                 if ( $once && $require )
539                 {
540                         require_once($lib_path);
541                 }
542                 else if ( $once && !$require )
543                 {
544                         include_once($lib_path);
545                 }
546                 else if ( $require )
547                 {
548                         require($lib_path);
549                 }
550                 else
551                 {
552                         include($lib_path);
553                 } // end if
554
555         }
556
557
558         /**
559          * This function includes or requires the specified plugin file
560          * @param string $file
561          * @param bool $once use the _once() version
562          * @param bool $require use require() instead of include()
563          */
564         function include_plugins($file, $once = TRUE, $require = TRUE)
565         {
566                 global $DIR_PLUGINS;
567
568                 // begin if: $DIR_LIBS isn't a directory
569                 if ( !is_dir($DIR_PLUGINS) )
570                 {
571                         exit;
572                 } // end if
573
574                 $plugin_path = $DIR_PLUGINS . $file;
575
576                 // begin if: 
577                 if ( $once && $require )
578                 {
579                         require_once($plugin_path);
580                 }
581                 else if ( $once && !$require )
582                 {
583                         include_once($plugin_path);
584                 }
585                 elseif ( $require )
586                 {
587                         require($plugin_path);
588                 }
589                 else
590                 {
591                         include($plugin_path);
592                 }
593         }
594         
595         /**
596          * This function decide which locale is used and include translation
597          * @param       string  $locale locale name referring to 'language tags' defined in RFC 5646
598          * @return      Void
599          */
600         function include_translation($locale)
601         {
602                 global $DIR_LOCALES;
603                 
604                 $translation_file = $DIR_LOCALES . $locale . '.' . i18n::get_current_charset() . '.php';
605                 if ( !file_exists($translation_file) )
606                 {
607                         $locale = 'en_Latn_US';
608                         $translation_file = $DIR_LOCALES . 'en_Latn_US.ISO-8859-1.php';
609                 }
610                 include($translation_file);
611                 return;
612         }
613         
614         /**
615          * This function returns the integer value of $_POST for the variable $name
616          * @param string $name field to get the integer value of
617          * @return int
618          */
619         function intPostVar($name)
620         {
621                 return intval(postVar($name));
622         }
623
624
625         /**
626          * This function returns the integer value of $_GET for the variable $name
627          * @param string $name field to get the integer value of
628          * @return int
629          */
630         function intGetVar($name)
631         {
632                 return intval(getVar($name));
633         }
634
635
636         /**
637          * This function returns the integer value of $_REQUEST for the variable $name. Also checks $_GET and $_POST if not found in $_REQUEST
638          * @param string $name field to get the integer value of
639          * @return int
640          */
641         function intRequestVar($name)
642         {
643                 return intval(requestVar($name));
644         }
645
646
647         /**
648          * This function returns the integer value of $_COOKIE for the variable $name
649          * @param string $name field to get the integer value of
650          * @return int
651          */
652         function intCookieVar($name)
653         {
654                 return intval(cookieVar($name));
655         }
656
657
658         /**
659          * This function returns the current Nucleus version (100 = 1.00, 101 = 1.01, etc...)
660          * @return int
661          */
662         function getNucleusVersion()
663         {
664                 return 400;
665         }
666
667
668         /**
669          * TODO: Better description of this function.
670          *
671          * Power users can install patches in between nucleus releases. These patches
672          * usually add new functionality in the plugin API and allow those to
673          * be tested without having to install CVS.
674          *
675          * @return int
676          */
677         function getNucleusPatchLevel()
678         {
679                 return 0;
680         }
681
682
683         /**
684          * This function returns the latest Nucleus version available for download from nucleuscms.org or FALSE if unable to attain data
685          * Format will be major.minor/patachlevel e.g. 3.41 or 3.41/02
686          * @return string|bool
687          */
688         function getLatestVersion()
689         {
690                 // begin if: cURL is not available in this PHP installation
691                 if ( !function_exists('curl_init') )
692                 {
693                         return FALSE;
694                 } // end if
695
696                 $curl = curl_init();
697                 $timeout = 5;
698                 curl_setopt ($curl, CURLOPT_URL, 'http://nucleuscms.org/version_check.php');
699                 curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
700                 curl_setopt ($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
701                 $return = curl_exec($curl);
702                 curl_close($curl);
703                 return $return;
704         }
705
706
707         /**
708          * This function returns a Nucleus table name with the appropriate prefix
709          * @param string $name
710          * @return string
711          */
712         function sql_table($name)
713         {
714                 global $MYSQL_PREFIX;
715
716                 // begin if: no MySQL prefix
717                 if ( empty($MYSQL_PREFIX) )
718                 {
719                         return 'nucleus_' . $name;
720                 }
721                 // else: use MySQL prefix
722                 else
723                 {
724                         return $MYSQL_PREFIX . 'nucleus_' . $name;
725                 } // end if
726
727         }
728
729
730         /**
731          * TODO: This function should be changed to send_content_type() per the Coding Guidelines. Ensure this change is compatible with rest of core.
732          *
733          * This function sends the Content-Type header if headers have not already been sent
734          * It also determines if the browser can accept application/xhtml+xml and sends it only to those that can.
735          * @param string $content_type
736          * @param string $page_type
737          * @param string $charset Deprecated. This has no meaning.
738          */
739         function sendContentType($content_type, $page_type = '', $charset = _CHARSET)
740         {
741                 global $manager, $CONF;
742                 
743                 if ( !headers_sent() )
744                 {
745                         // if content type is application/xhtml+xml, only send it to browsers
746                         // that can handle it (IE6 cannot). Otherwise, send text/html
747
748                         // v2.5: For admin area pages, keep sending text/html (unless it's a debug version)
749                         //       application/xhtml+xml still causes too much problems with the javascript implementations
750
751                         // v3.3: ($CONF['UsingAdminArea'] && !$CONF['debug']) gets removed,
752                         //       application/xhtml+xml seems to be working, so we're going to use it if we can.
753
754                         if ( ($content_type == 'application/xhtml+xml')
755                                 && (!stristr(serverVar('HTTP_ACCEPT'), 'application/xhtml+xml') ) )
756                         {
757                                 $content_type = 'text/html';
758                         } // end if
759
760                         $manager->notify(
761                                 'PreSendContentType',
762                                 array(
763                                         'contentType' => &$content_type,
764                                         'charset' => i18n::get_current_charset(),
765                                         'pageType' => $page_type
766                                 )
767                         );
768
769                         // strip strange characters
770                         $content_type = preg_replace('|[^a-z0-9-+./]|i', '', $content_type);
771                         header('Content-Type: ' . $content_type . '; charset=' . i18n::get_current_charset());
772                 } // end if
773
774         }
775
776
777         /**
778          * This function parses a query into an array of expressions that can be passed on to the highlight method
779          * @param string $query
780          */
781         function parseHighlight($query)
782         {
783                 // TODO: add more intelligent splitting logic
784                 
785                 // get rid of quotes
786                 $query = preg_replace('/\'|"/', '', $query);
787                 
788                 if ( !$query )
789                 {
790                         return array();
791                 }
792                 
793                 $aHighlight = i18n::explode(' ', $query);
794                 
795                 for ( $i = 0; $i < count($aHighlight); $i++ )
796                 {
797                         $aHighlight[$i] = trim($aHighlight[$i]);
798                         
799                         if ( i18n::strlen($aHighlight[$i]) < 3 )
800                         {
801                                 unset($aHighlight[$i]);
802                         }
803                 }
804                 
805                 if ( count($aHighlight) == 1 )
806                 {
807                         return $aHighlight[0];
808                 }
809                 else
810                 {
811                         return $aHighlight;
812                 }
813         }
814
815
816         /**
817          * This function gets the blog ID from the blog name
818          * @param string $name
819          * @return
820          */
821         function getBlogIDFromName($name)
822         {
823                 return quickQuery('SELECT `bnumber` AS `result` FROM `' . sql_table('blog') . '` WHERE `bshortname` = "' . sql_real_escape_string($name) . '"');
824         }
825
826
827         /**
828          * This function gets the blog name from the blog ID
829          * @param int $id
830          * @return object
831          */
832         function getBlogNameFromID($id)
833         {
834                 return quickQuery('SELECT `bname` AS `result` FROM `' . sql_table('blog') . '` WHERE `bnumber` = ' . intval($id));
835         }
836
837
838         /**
839          * This function gets the blog ID from the item ID
840          * @param int $item_id
841          * @return object
842          */
843         function getBlogIDFromItemID($item_id)
844         {
845                 return quickQuery('SELECT `iblog` AS `result` FROM `' . sql_table('item') . '` WHERE `inumber` = ' . intval($item_id));
846         }
847
848
849         /**
850          * This function gets the blog ID from the comment ID
851          * @param int $comment_id
852          * @return object
853          */
854         function getBlogIDFromCommentID($comment_id)
855         {
856                 return quickQuery('SELECT `cblog` AS `result` FROM `' . sql_table('comment') . '` WHERE `cnumber` = ' . intval($comment_id));
857         }
858
859
860         /**
861          * This function gets the blog ID from the category ID
862          * @param int $category_id
863          * @return object
864          */
865         function getBlogIDFromCatID($category_id)
866         {
867                 return quickQuery('SELECT `cblog` AS `result` FROM `' . sql_table('category') . '` WHERE `catid` = ' . intval($category_id));
868         }
869
870
871         /**
872          * This function gets the category ID from the category name
873          * @param int $name
874          * @return object
875          */
876         function getCatIDFromName($name)
877         {
878                 return quickQuery('SELECT `catid` AS `result` FROM `' . sql_table('category') . '` WHERE `cname` = "' . sql_real_escape_string($name) . '"');
879         }
880
881
882         /**
883          * This function performs a quick SQL query
884          * @param string $query
885          * @return object
886          */
887         function quickQuery($query)
888         {
889                 $res = sql_query($query);
890                 $obj = sql_fetch_object($res);
891                 return $obj->result;
892         }
893
894 function getPluginNameFromPid($pid) {
895     $res = sql_query('SELECT pfile FROM ' . sql_table('plugin') . ' WHERE pid=' . intval($pid) );
896     $obj = sql_fetch_object($res);
897     return $obj->pfile;
898 //    return isset($obj->pfile) ? $obj->pfile : false;
899 }
900
901 function selector() {
902         global $itemid, $blogid, $memberid, $query, $amount, $archivelist, $maxresults;
903         global $archive, $skinid, $blog, $memberinfo, $CONF, $member;
904         global $imagepopup, $catid, $special;
905         global $manager;
906         
907         $actionNames = array('addcomment', 'sendmessage', 'createaccount', 'forgotpassword', 'votepositive', 'votenegative', 'plugin');
908         $action = requestVar('action');
909         
910         if ( in_array($action, $actionNames) )
911         {
912                 global $DIR_LIBS, $errormessage;
913                 include_once($DIR_LIBS . 'ACTION.php');
914                 $a = new ACTION();
915                 $errorInfo = $a->doAction($action);
916                 
917                 if ( $errorInfo )
918                 {
919                         $errormessage = $errorInfo['message'];
920                 }
921         }
922         
923         // show error when headers already sent out
924         if ( headers_sent() && $CONF['alertOnHeadersSent'] )
925         {
926                 // try to get line number/filename (extra headers_sent params only exists in PHP 4.3+)
927                 if ( function_exists('version_compare') && version_compare('4.3.0', phpversion(), '<=') )
928                 {
929                         headers_sent($hsFile, $hsLine);
930                         $extraInfo = ' in <code>' . $hsFile . '</code> line <code>' . $hsLine . '</code>';
931                 }
932                 else
933                 {
934                         $extraInfo = '';
935                 }
936                 
937                 startUpError(
938                         '<p>The page headers have already been sent out' . $extraInfo . '. This could cause Nucleus not to work in the expected way.</p><p>Usually, this is caused by spaces or newlines at the end of the <code>config.php</code> file, at the end of the translation file or at the end of a plugin file. Please check this and try again.</p><p>If you don\'t want to see this error message again, without solving the problem, set <code>$CONF[\'alertOnHeadersSent\']</code> in <code>globalfunctions.php</code> to <code>0</code></p>',
939                         'Page headers already sent'
940                 );
941                 exit;
942         }
943         
944         // make is so ?archivelist without blogname or blogid shows the archivelist
945         // for the default weblog
946         if ( serverVar('QUERY_STRING') == 'archivelist' )
947         {
948                 $archivelist = $CONF['DefaultBlog'];
949         }
950         
951         // now decide which type of skin we need
952         if ( $itemid )
953         {
954                 // itemid given -> only show that item
955                 $type = 'item';
956                 
957                 if ( !$manager->existsItem($itemid,intval($CONF['allowFuture']),intval($CONF['allowDrafts'])) )
958                 {
959                         doError(_ERROR_NOSUCHITEM);
960                 }
961                 
962                 global $itemidprev, $itemidnext, $catid, $itemtitlenext, $itemtitleprev;
963                 
964                 // 1. get timestamp, blogid and catid for item
965                 $query = 'SELECT itime, iblog, icat FROM ' . sql_table('item') . ' WHERE inumber=' . intval($itemid);
966                 $res = sql_query($query);
967                 $obj = sql_fetch_object($res);
968                 
969                 // if a different blog id has been set through the request or selectBlog(),
970                 // deny access
971                 
972                 if ( $blogid && (intval($blogid) != $obj->iblog) )
973                 {
974                         doError(_ERROR_NOSUCHITEM);
975                 }
976                 
977                 // if a category has been selected which doesn't match the item, ignore the
978                 // category. #85
979                 if ( ($catid != 0) && ($catid != $obj->icat) )
980                 {
981                         $catid = 0;
982                 }
983                 
984                 $blogid = $obj->iblog;
985                 $timestamp = strtotime($obj->itime);
986                 
987                 $b =& $manager->getBlog($blogid);
988                 
989                 if ( $b->isValidCategory($catid) )
990                 {
991                         $catextra = ' and icat=' . $catid;
992                 }
993                 else
994                 {
995                         $catextra = '';
996                 }
997                 
998                 // get previous itemid and title
999                 $query = 'SELECT inumber, ititle FROM ' . sql_table('item') . ' WHERE itime<' . mysqldate($timestamp) . ' and idraft=0 and iblog=' . $blogid . $catextra . ' ORDER BY itime DESC LIMIT 1';
1000                 $res = sql_query($query);
1001                 
1002                 $obj = sql_fetch_object($res);
1003                 
1004                 if ( $obj )
1005                 {
1006                         $itemidprev = $obj->inumber;
1007                         $itemtitleprev = $obj->ititle;
1008                 }
1009                 
1010                 // get next itemid and title
1011                 $query = 'SELECT inumber, ititle FROM ' . sql_table('item') . ' WHERE itime>' . mysqldate($timestamp) . ' and itime <= ' . mysqldate($b->getCorrectTime()) . ' and idraft=0 and iblog=' . $blogid . $catextra . ' ORDER BY itime ASC LIMIT 1';
1012                 $res = sql_query($query);
1013                 
1014                 $obj = sql_fetch_object($res);
1015                 
1016                 if ( $obj )
1017                 {
1018                         $itemidnext = $obj->inumber;
1019                         $itemtitlenext = $obj->ititle;
1020                 }
1021         }
1022         elseif ($archive)
1023         {
1024                 // show archive
1025                 $type = 'archive';
1026                 
1027                 // get next and prev month links ...
1028                 global $archivenext, $archiveprev, $archivetype, $archivenextexists, $archiveprevexists;
1029                 
1030                 // sql queries for the timestamp of the first and the last published item
1031                 $query = "SELECT UNIX_TIMESTAMP(itime) as result FROM ".sql_table('item')." WHERE idraft=0 ORDER BY itime ASC";
1032                 $first_timestamp=quickQuery ($query);
1033                 $query = "SELECT UNIX_TIMESTAMP(itime) as result FROM ".sql_table('item')." WHERE idraft=0 ORDER BY itime DESC";
1034                 $last_timestamp=quickQuery ($query);
1035                 
1036                 sscanf($archive, '%d-%d-%d', $y, $m, $d);
1037                 
1038                 if ( $d != 0 )
1039                 {
1040                         $archivetype = _ARCHIVETYPE_DAY;
1041                         $t = mktime(0, 0, 0, $m, $d, $y);
1042                         // one day has 24 * 60 * 60 = 86400 seconds
1043                         $archiveprev = i18n::strftime('%Y-%m-%d', $t - 86400 );
1044                         // check for published items
1045                         if ( $t > $first_timestamp )
1046                         {
1047                                 $archiveprevexists = true;
1048                         }
1049                         else
1050                         {
1051                                 $archiveprevexists = false;
1052                         }
1053                         
1054                         // one day later
1055                         $t += 86400;
1056                         $archivenext = i18n::strftime('%Y-%m-%d', $t);
1057                         if ( $t < $last_timestamp )
1058                         {
1059                                 $archivenextexists = true;
1060                         }
1061                         else
1062                         {
1063                                 $archivenextexists = false;
1064                         }
1065                 }
1066                 elseif ( $m == 0 )
1067                 {
1068                         $archivetype = _ARCHIVETYPE_YEAR;
1069                         $t = mktime(0, 0, 0, 12, 31, $y - 1);
1070                         // one day before is in the previous year
1071                         $archiveprev = i18n::strftime('%Y', $t);
1072                         if ( $t > $first_timestamp )
1073                         {
1074                                 $archiveprevexists = true;
1075                         }
1076                         else
1077                         {
1078                                 $archiveprevexists = false;
1079                         }
1080
1081                         // timestamp for the next year
1082                         $t = mktime(0, 0, 0, 1, 1, $y + 1);
1083                         $archivenext = i18n::strftime('%Y', $t);
1084                         if ( $t < $last_timestamp )
1085                         {
1086                                 $archivenextexists = true;
1087                         }
1088                         else
1089                         {
1090                                 $archivenextexists = false;
1091                         }
1092                 }
1093                 else
1094                 {
1095                         $archivetype = _ARCHIVETYPE_MONTH;
1096                         $t = mktime(0, 0, 0, $m, 1, $y);
1097                         // one day before is in the previous month
1098                         $archiveprev = i18n::strftime('%Y-%m', $t - 86400);
1099                         if ( $t > $first_timestamp )
1100                         {
1101                                 $archiveprevexists = true;
1102                         }
1103                         else
1104                         {
1105                                 $archiveprevexists = false;
1106                         }
1107                         
1108                         // timestamp for the next month
1109                         $t = mktime(0, 0, 0, $m+1, 1, $y);
1110                         $archivenext = i18n::strftime('%Y-%m', $t);
1111                         if ( $t < $last_timestamp )
1112                         {
1113                                 $archivenextexists = true;
1114                         }
1115                         else
1116                         {
1117                                 $archivenextexists = false;
1118                         }
1119                 }
1120         }
1121         elseif ($archivelist)
1122         {
1123                 $type = 'archivelist';
1124                 
1125                 if ( is_numeric($archivelist) )
1126                 {
1127                         $blogid = intVal($archivelist);
1128                 }
1129                 else
1130                 {
1131                         $blogid = getBlogIDFromName($archivelist);
1132                 }
1133         
1134                 if ( !$blogid )
1135                 {
1136                         doError(_ERROR_NOSUCHBLOG);
1137                 }
1138         }
1139         elseif ( $query )
1140         {
1141                 global $startpos;
1142                 $type = 'search';
1143                 $query = stripslashes($query);
1144                 
1145                 if ( is_numeric($blogid) )
1146                 {
1147                         $blogid = intVal($blogid);
1148                 }
1149                 else
1150                 {
1151                         $blogid = getBlogIDFromName($blogid);
1152                 }
1153                 
1154                 if ( !$blogid )
1155                 {
1156                         doError(_ERROR_NOSUCHBLOG);
1157                 }
1158         }
1159         elseif ( $memberid )
1160         {
1161                 $type = 'member';
1162                 
1163                 if ( !MEMBER::existsID($memberid) )
1164                 {
1165                         doError(_ERROR_NOSUCHMEMBER);
1166                 }
1167                 $memberinfo = $manager->getMember($memberid);
1168         }
1169         elseif ( $imagepopup )
1170         {
1171                 // media object (images etc.)
1172                 $type = 'imagepopup';
1173                 
1174                 // TODO: check if media-object exists
1175                 // TODO: set some vars?
1176         }
1177         else
1178         {
1179                 // show regular index page
1180                 global $startpos;
1181                 $type = 'index';
1182         }
1183         
1184         // any type of skin with catid
1185         if ( $catid && !$blogid )
1186         {
1187                 $blogid = getBlogIDFromCatID($catid);
1188         }
1189         
1190         // decide which blog should be displayed
1191         if ( !$blogid )
1192         {
1193                 $blogid = $CONF['DefaultBlog'];
1194         }
1195         
1196         $b =& $manager->getBlog($blogid);
1197         $blog = $b; // references can't be placed in global variables?
1198         
1199         if ( !$blog->isValid )
1200         {
1201                 doError(_ERROR_NOSUCHBLOG);
1202         }
1203         
1204         // set catid if necessary
1205         if ( $catid )
1206         {
1207                 // check if the category is valid
1208                 if ( !$blog->isValidCategory($catid) )
1209                 {
1210                         doError(_ERROR_NOSUCHCATEGORY);
1211                 }
1212                 else
1213                 {
1214                         $blog->setSelectedCategory($catid);
1215                 }
1216         }
1217         
1218         // decide which skin should be used
1219         if ( $skinid != '' && ($skinid == 0) )
1220         {
1221                 selectSkin($skinid);
1222         }
1223         
1224         if ( !$skinid )
1225         {
1226                 $skinid = $blog->getDefaultSkin();
1227         }
1228         
1229         //$special = requestVar('special'); //get at top of file as global
1230         if ( !empty($special) && isValidShortName($special) )
1231         {
1232                 $type = strtolower($special);
1233         }
1234         
1235         $skin = new SKIN($skinid);
1236         
1237         if ( !$skin->isValid )
1238         {
1239                 doError(_ERROR_NOSUCHSKIN);
1240         }
1241         
1242         // set global skinpart variable so can determine quickly what is being parsed from any plugin or phpinclude
1243         global $skinpart;
1244         $skinpart = $type;
1245         
1246         // parse the skin
1247         $skin->parse($type);
1248         
1249         // check to see we should throw JustPosted event
1250         $blog->checkJustPosted();
1251         return;
1252 }
1253
1254 /**
1255   * Show error skin with given message. An optional skin-object to use can be given
1256   */
1257 function doError($msg, $skin = '') {
1258     global $errormessage, $CONF, $skinid, $blogid, $manager;
1259
1260     if ($skin == '') {
1261
1262         if (SKIN::existsID($skinid) ) {
1263             $skin = new SKIN($skinid);
1264         } elseif ($manager->existsBlogID($blogid) ) {
1265             $blog =& $manager->getBlog($blogid);
1266             $skin = new SKIN($blog->getDefaultSkin() );
1267         } elseif ($CONF['DefaultBlog']) {
1268             $blog =& $manager->getBlog($CONF['DefaultBlog']);
1269             $skin = new SKIN($blog->getDefaultSkin() );
1270         } else {
1271             // this statement should actually never be executed
1272             $skin = new SKIN($CONF['BaseSkin']);
1273         }
1274
1275     }
1276
1277     $skinid = $skin->id;
1278     $errormessage = $msg;
1279     $skin->parse('error');
1280     exit;
1281 }
1282
1283 function getConfig() {
1284     global $CONF;
1285
1286     $query = 'SELECT * FROM ' . sql_table('config');
1287     $res = sql_query($query);
1288
1289     while ($obj = sql_fetch_object($res) ) {
1290         $CONF[$obj->name] = $obj->value;
1291     }
1292 }
1293
1294 // some checks for names of blogs, categories, templates, members, ...
1295 function isValidShortName($name) {
1296
1297         # replaced eregi() below with preg_match(). ereg* functions are deprecated in PHP 5.3.0
1298         # original eregi: eregi('^[a-z0-9]+$', $name)
1299
1300         return preg_match('#^[a-z0-9]+$#i', $name);
1301
1302 }
1303
1304 function isValidDisplayName($name) {
1305
1306         # replaced eregi() below with preg_match(). ereg* functions are deprecated in PHP 5.3.0
1307         # original eregi: eregi('^[a-z0-9]+[a-z0-9 ]*[a-z0-9]+$', $name)
1308
1309         return preg_match('#^[a-z0-9]+[a-z0-9 ]*[a-z0-9]+$#i', $name);
1310
1311 }
1312
1313 function isValidCategoryName($name) {
1314     return 1;
1315 }
1316
1317 function isValidTemplateName($name) {
1318
1319         # replaced eregi() below with preg_match(). ereg* functions are deprecated in PHP 5.3.0
1320         # original eregi: eregi('^[a-z0-9/]+$', $name)
1321         // added - and _ to valid characters as of 4.00
1322
1323         return preg_match('#^[a-z0-9/_\-]+$#i', $name);
1324
1325 }
1326
1327 function isValidSkinName($name) {
1328
1329         # replaced eregi() below with preg_match(). ereg* functions are deprecated in PHP 5.3.0
1330         # original eregi: eregi('^[a-z0-9/]+$', $name);
1331         // added - and _ to valid characters as of 4.00
1332
1333         return preg_match('#^[a-z0-9/_\-]+$#i', $name);
1334
1335 }
1336
1337 // add and remove linebreaks
1338 function addBreaks($var) {
1339     return nl2br($var);
1340 }
1341
1342 function removeBreaks($var) {
1343     return preg_replace("/<br \/>([\r\n])/", "$1", $var);
1344 }
1345
1346 /**
1347   * Converts a unix timestamp to a mysql DATETIME format, and places
1348   * quotes around it.
1349   */
1350 function mysqldate($timestamp) {
1351     return '"' . date('Y-m-d H:i:s', $timestamp) . '"';
1352 }
1353
1354 /**
1355   * functions for use in index.php
1356   */
1357 function selectBlog($shortname) {
1358     global $blogid, $archivelist;
1359     $blogid = getBlogIDFromName($shortname);
1360
1361     // also force archivelist variable, if it is set
1362     if ($archivelist) {
1363         $archivelist = $blogid;
1364     }
1365 }
1366
1367 function selectSkin($skinname) {
1368     global $skinid;
1369     $skinid = SKIN::getIdFromName($skinname);
1370 }
1371
1372 /**
1373  * Can take either a category ID or a category name (be aware that
1374  * multiple categories can have the same name)
1375  */
1376 function selectCategory($cat) {
1377     global $catid;
1378     if (is_numeric($cat) ) {
1379         $catid = intval($cat);
1380     } else {
1381         $catid = getCatIDFromName($cat);
1382     }
1383 }
1384
1385 function selectItem($id) {
1386     global $itemid;
1387     $itemid = intval($id);
1388 }
1389
1390 // force the use of a translation file (warning: can cause warnings)
1391 function selectLanguage($language) {
1392
1393         global $DIR_LANG;
1394
1395         # replaced ereg_replace() below with preg_replace(). ereg* functions are deprecated in PHP 5.3.0
1396         # original ereg_replace: preg_replace( '@\\|/@', '', $language) . '.php')
1397         # important note that '\' must be matched with '\\\\' in preg* expressions
1398
1399         include($DIR_LANG . preg_replace('#[\\\\|/]#', '', $language) . '.php');
1400
1401 }
1402
1403 function parseFile($filename, $includeMode = 'normal', $includePrefix = '') {
1404     $handler = new ACTIONS('fileparser');
1405     $parser = new PARSER(SKIN::getAllowedActionsForType('fileparser'), $handler);
1406     $handler->parser =& $parser;
1407
1408     // set IncludeMode properties of parser
1409     PARSER::setProperty('IncludeMode', $includeMode);
1410     PARSER::setProperty('IncludePrefix', $includePrefix);
1411
1412     if (!file_exists($filename) ) {
1413         doError('A file is missing');
1414     }
1415
1416     $fsize = filesize($filename);
1417
1418     if ($fsize <= 0) {
1419         return;
1420     }
1421
1422     // read file
1423     $fd = fopen ($filename, 'r');
1424     $contents = fread ($fd, $fsize);
1425     fclose ($fd);
1426
1427     // parse file contents
1428     $parser->parse($contents);
1429 }
1430
1431 /**
1432   * Outputs a debug message
1433   */
1434 function debug($msg) {
1435     echo '<p><b>' . $msg . "</b></p>\n";
1436 }
1437
1438 // shortcut
1439 function addToLog($level, $msg) {
1440     ACTIONLOG::add($level, $msg);
1441 }
1442
1443 // shows a link to help file
1444 function help($id) {
1445     echo helpHtml($id);
1446 }
1447
1448 function helpHtml($id) {
1449     global $CONF;
1450     return helplink($id) . '<img src="' . $CONF['AdminURL'] . 'documentation/icon-help.gif" width="15" height="15" alt="' . _HELP_TT . '" title="' . _HELP_TT . '" /></a>';
1451 }
1452
1453 function helplink($id) {
1454     global $CONF;
1455     return '<a href="' . $CONF['AdminURL'] . 'documentation/help.html#'. $id . '" onclick="if (event &amp;&amp; event.preventDefault) event.preventDefault(); return help(this.href);">';
1456 }
1457
1458 /**
1459   * Includes a PHP file. This method can be called while parsing templates and skins
1460   */
1461 function includephp($filename) {
1462     // make predefined variables global, so most simple scripts can be used here
1463
1464     // apache (names taken from PHP doc)
1465     global $GATEWAY_INTERFACE, $SERVER_NAME, $SERVER_SOFTWARE, $SERVER_PROTOCOL;
1466     global $REQUEST_METHOD, $QUERY_STRING, $DOCUMENT_ROOT, $HTTP_ACCEPT;
1467     global $HTTP_ACCEPT_CHARSET, $HTTP_ACCEPT_ENCODING, $HTTP_ACCEPT_LANGUAGE;
1468     global $HTTP_CONNECTION, $HTTP_HOST, $HTTP_REFERER, $HTTP_USER_AGENT;
1469     global $REMOTE_ADDR, $REMOTE_PORT, $SCRIPT_FILENAME, $SERVER_ADMIN;
1470     global $SERVER_PORT, $SERVER_SIGNATURE, $PATH_TRANSLATED, $SCRIPT_NAME;
1471     global $REQUEST_URI;
1472
1473     // php (taken from PHP doc)
1474     global $argv, $argc, $PHP_SELF, $HTTP_COOKIE_VARS, $HTTP_GET_VARS, $HTTP_POST_VARS;
1475     global $HTTP_POST_FILES, $HTTP_ENV_VARS, $HTTP_SERVER_VARS, $HTTP_SESSION_VARS;
1476
1477     // other
1478     global $PATH_INFO, $HTTPS, $HTTP_RAW_POST_DATA, $HTTP_X_FORWARDED_FOR;
1479
1480     if (@file_exists($filename) ) {
1481         include($filename);
1482     }
1483 }
1484
1485 /**
1486  * Checks if a certain plugin exists
1487  * @param string $plug
1488  * @return bool
1489  **/
1490 function checkPlugin($plug) {
1491
1492         global $DIR_PLUGINS;
1493
1494         # replaced ereg_replace() below with preg_replace(). ereg* functions are deprecated in PHP 5.3.0
1495         # original ereg_replace: ereg_replace( '[\\|/]', '', $plug) . '.php')
1496         # important note that '\' must be matched with '\\\\' in preg* expressions
1497
1498         return file_exists($DIR_PLUGINS . preg_replace('#[\\\\|/]#', '', $plug) . '.php');
1499
1500 }
1501
1502 /**
1503  * @param $querystr
1504  *              querystring to alter (e.g. foo=1&bar=2&x=y)
1505  * @param $param
1506  *              name of parameter to change (e.g. 'foo')
1507  * @param $value
1508  *              New value for that parameter (e.g. 3)
1509  * @result
1510  *              altered query string (for the examples above: foo=3&bar=2&x=y)
1511  */
1512 function alterQueryStr($querystr, $param, $value) {
1513     $vars = i18n::explode('&', $querystr);
1514     $set  = false;
1515
1516     for ($i = 0; $i < count($vars); $i++) {
1517         $v = i18n::explode('=', $vars[$i]);
1518
1519         if ($v[0] == $param) {
1520             $v[1] = $value;
1521             $vars[$i] = implode('=', $v);
1522             $set = true;
1523             break;
1524         }
1525     }
1526
1527     if (!$set) {
1528         $vars[] = $param . '=' . $value;
1529     }
1530
1531     return ltrim(implode('&', $vars), '&');
1532 }
1533
1534 // passes one variable as hidden input field (multiple fields for arrays)
1535 // @see passRequestVars in varsx.x.x.php
1536 function passVar($key, $value) {
1537     // array ?
1538     if (is_array($value) ) {
1539         for ($i = 0; $i < sizeof($value); $i++) {
1540             passVar($key . '[' . $i . ']', $value[$i]);
1541         }
1542
1543         return;
1544     }
1545
1546     // other values: do stripslashes if needed
1547     ?><input type="hidden" name="<?php echo ENTITY::hsc($key)?>" value="<?php echo ENTITY::hsc(undoMagic($value) )?>" /><?php
1548 }
1549
1550 function checkVars($aVars) {
1551     global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_ENV_VARS, $HTTP_POST_FILES, $HTTP_SESSION_VARS;
1552
1553     foreach ($aVars as $varName) {
1554
1555         if (phpversion() >= '4.1.0') {
1556
1557             if (   isset($_GET[$varName])
1558                 || isset($_POST[$varName])
1559                 || isset($_COOKIE[$varName])
1560                 || isset($_ENV[$varName])
1561                 || isset($_SESSION[$varName])
1562                 || isset($_FILES[$varName])
1563             ) {
1564                 die('Sorry. An error occurred.');
1565             }
1566
1567         } else {
1568
1569             if (   isset($HTTP_GET_VARS[$varName])
1570                 || isset($HTTP_POST_VARS[$varName])
1571                 || isset($HTTP_COOKIE_VARS[$varName])
1572                 || isset($HTTP_ENV_VARS[$varName])
1573                 || isset($HTTP_SESSION_VARS[$varName])
1574                 || isset($HTTP_POST_FILES[$varName])
1575             ) {
1576                 die('Sorry. An error occurred.');
1577             }
1578
1579         }
1580     }
1581 }
1582
1583
1584 /**
1585  * Sanitize parameters such as $_GET and $_SERVER['REQUEST_URI'] etc.
1586  * to avoid XSS
1587  */
1588 function sanitizeParams()
1589 {
1590     global $HTTP_SERVER_VARS;
1591
1592     $array = array();
1593     $str = '';
1594     $frontParam = '';
1595
1596     // REQUEST_URI of $HTTP_SERVER_VARS
1597     $str =& $HTTP_SERVER_VARS["REQUEST_URI"];
1598     serverStringToArray($str, $array, $frontParam);
1599     sanitizeArray($array);
1600     arrayToServerString($array, $frontParam, $str);
1601
1602     // QUERY_STRING of $HTTP_SERVER_VARS
1603     $str =& $HTTP_SERVER_VARS["QUERY_STRING"];
1604     serverStringToArray($str, $array, $frontParam);
1605     sanitizeArray($array);
1606     arrayToServerString($array, $frontParam, $str);
1607
1608     if (phpversion() >= '4.1.0') {
1609         // REQUEST_URI of $_SERVER
1610         $str =& $_SERVER["REQUEST_URI"];
1611         serverStringToArray($str, $array, $frontParam);
1612         sanitizeArray($array);
1613         arrayToServerString($array, $frontParam, $str);
1614
1615         // QUERY_STRING of $_SERVER
1616         $str =& $_SERVER["QUERY_STRING"];
1617         serverStringToArray($str, $array, $frontParam);
1618         sanitizeArray($array);
1619         arrayToServerString($array, $frontParam, $str);
1620     }
1621
1622     // $_GET
1623     convArrayForSanitizing($_GET, $array);
1624     sanitizeArray($array);
1625     revertArrayForSanitizing($array, $_GET);
1626
1627     // $_REQUEST (only GET param)
1628     convArrayForSanitizing($_REQUEST, $array);
1629     sanitizeArray($array);
1630     revertArrayForSanitizing($array, $_REQUEST);
1631 }
1632
1633 /**
1634  * Check ticket when not checked in plugin's admin page
1635  * to avoid CSRF.
1636  * Also avoid the access to plugin/index.php by guest user.
1637  */
1638 function ticketForPlugin()
1639 {
1640         global $CONF, $DIR_PLUGINS, $member, $ticketforplugin;
1641         
1642         /* initialize */
1643         $ticketforplugin = array();
1644         $ticketforplugin['ticket'] = FALSE;
1645         
1646         /* $_SERVER['PATH_TRANSLATED']
1647          * http://www.php.net/manual/en/reserved.variables.server.php
1648          * Note: As of PHP 4.3.2, PATH_TRANSLATED is no longer set implicitly
1649          * under the Apache 2 SAPI in contrast to the situation in Apache 1,
1650          * where it's set to the same value as the SCRIPT_FILENAME server variable
1651          * when it's not populated by Apache.
1652          * This change was made to comply with the CGI specification
1653          * that PATH_TRANSLATED should only exist if PATH_INFO is defined.
1654          * Apache 2 users may use AcceptPathInfo = On inside httpd.conf to define PATH_INFO. 
1655          */
1656         
1657         /* Check if using plugin's php file. */
1658         $p_translated = serverVar('SCRIPT_FILENAME');
1659         
1660         if (!file_exists($p_translated) )
1661         {
1662                 header("HTTP/1.0 404 Not Found");
1663                 exit('');
1664         }
1665         
1666         $p_translated = str_replace('\\', '/', $p_translated);
1667         $d_plugins = str_replace('\\', '/', $DIR_PLUGINS);
1668         
1669         // This isn't plugin php file.
1670         if ( i18n::strpos($p_translated, $d_plugins) !== 0 )
1671         {
1672                 return;
1673         }
1674
1675         // Solve the plugin php file or admin directory
1676         $phppath = i18n::substr($p_translated, i18n::strlen($d_plugins) );
1677         // Remove the first "/" if exists.
1678         $phppath = preg_replace('#^/#', '', $phppath);
1679         // Remove the first "NP_" and the last ".php" if exists.
1680         $path = preg_replace('#^NP_(.*)\.php$#', '$1', $phppath);
1681         // Remove the "/" and beyond.
1682         $path = preg_replace('#^([^/]*)/(.*)$#', '$1', $path);
1683         
1684         // Solve the plugin name.
1685         $plugins = array();
1686         $query = 'SELECT `pfile` FROM '.sql_table('plugin');
1687         $res = sql_query($query);
1688         
1689         while($row = sql_fetch_row($res) )
1690         {
1691                 $name = i18n::substr($row[0], 3);
1692                 $plugins[strtolower($name)] = $name;
1693         }
1694         
1695         sql_free_result($res);
1696         
1697         if (array_key_exists($path, $plugins))
1698         {
1699                 $plugin_name = $plugins[$path];
1700         }
1701         else if (in_array($path, $plugins))
1702         {
1703                 $plugin_name = $path;
1704         }
1705         else
1706         {
1707                 header("HTTP/1.0 404 Not Found");
1708                 exit('');
1709         }
1710         
1711         /* Return if not index.php */
1712         if ( ($phppath != strtolower($plugin_name) . '/') && ($phppath != strtolower($plugin_name) . '/index.php') )
1713         {
1714                 return;
1715         }
1716         
1717         /* Exit if not logged in. */
1718         if ( !$member->isLoggedIn() )
1719         {
1720                 exit('You aren\'t logged in.');
1721         }
1722         
1723         global $manager, $DIR_LIBS, $DIR_LOCALE, $HTTP_GET_VARS, $HTTP_POST_VARS;
1724         
1725         /* Check if this feature is needed (ie, if "$manager->checkTicket()" is not included in the script). */
1726         if (!($p_translated = serverVar('PATH_TRANSLATED') ) )
1727         {
1728                 $p_translated = serverVar('SCRIPT_FILENAME');
1729         }
1730         
1731         if ($file = @file($p_translated) )
1732         {
1733                 $prevline = '';
1734                 
1735                 foreach($file as $line)
1736                 {
1737                         if (preg_match('/[\$]manager([\s]*)[\-]>([\s]*)checkTicket([\s]*)[\(]/i', $prevline . $line) )
1738                         {
1739                                 return;
1740                         }
1741                         
1742                         $prevline = $line;
1743                 }
1744         }
1745         
1746         /* Show a form if not valid ticket */
1747         if ( ( strstr(serverVar('REQUEST_URI'), '?') || serverVar('QUERY_STRING')
1748          || strtoupper(serverVar('REQUEST_METHOD') ) == 'POST')
1749          && (!$manager->checkTicket() ) )
1750         {
1751                 $oPluginAdmin = new PluginAdmin($plugin_name);
1752                 $oPluginAdmin->start();
1753                 echo '<p>' . _ERROR_BADTICKET . "</p>\n";
1754                 
1755                 /* Show the form to confirm action */
1756                 // PHP 4.0.x support
1757                 $get = (isset($_GET) ) ? $_GET : $HTTP_GET_VARS;
1758                 $post = (isset($_POST) ) ? $_POST : $HTTP_POST_VARS;
1759                 
1760                 // Resolve URI and QUERY_STRING
1761                 if ($uri = serverVar('REQUEST_URI') )
1762                 {
1763                         list($uri, $qstring) = i18n::explode('?', $uri);
1764                 }
1765                 else
1766                 {
1767                         if ( !($uri = serverVar('PHP_SELF') ) )
1768                         {
1769                                 $uri = serverVar('SCRIPT_NAME');
1770                         }
1771                         $qstring = serverVar('QUERY_STRING');
1772                 }
1773                 if ($qstring)
1774                 {
1775                         $qstring = '?' . $qstring;
1776                 }
1777                 
1778                 echo '<p>' . _SETTINGS_UPDATE . ' : ' . _QMENU_PLUGINS . ' <span style="color:red;">' . ENTITY::hsc($plugin_name) . "</span> ?</p>\n";
1779                 
1780                 switch(strtoupper(serverVar('REQUEST_METHOD') ) )
1781                 {
1782                         case 'POST':
1783                                 echo '<form method="POST" action="'.ENTITY::hsc($uri.$qstring).'">';
1784                                 $manager->addTicketHidden();
1785                                 _addInputTags($post);
1786                                 break;
1787                         
1788                         case 'GET':
1789                                 echo '<form method="GET" action="'.ENTITY::hsc($uri).'">';
1790                                 $manager->addTicketHidden();
1791                                 _addInputTags($get);
1792                         
1793                         default:
1794                                 break;
1795                 }
1796                 
1797                 echo '<input type="submit" value="' . _YES . '" />&nbsp;&nbsp;&nbsp;&nbsp;';
1798                 echo '<input type="button" value="' . _NO . '" onclick="history.back(); return false;" />';
1799                 echo "</form>\n";
1800                 
1801                 $oPluginAdmin->end();
1802                 exit;
1803         }
1804         
1805         /* Create new ticket */
1806         $ticket=$manager->addTicketToUrl('');
1807         $ticketforplugin['ticket']=i18n::substr($ticket,i18n::strpos($ticket,'ticket=')+7);
1808 }
1809
1810 function _addInputTags(&$keys,$prefix=''){
1811     foreach($keys as $key=>$value){
1812         if ($prefix) $key=$prefix.'['.$key.']';
1813         if (is_array($value)) _addInputTags($value,$key);
1814         else {
1815             if (get_magic_quotes_gpc()) $value=stripslashes($value);
1816             if ($key=='ticket') continue;
1817             echo '<input type="hidden" name="'.ENTITY::hsc($key).
1818                 '" value="'.ENTITY::hsc($value).'" />'."\n";
1819         }
1820     }
1821 }
1822
1823 /**
1824  * Convert the server string such as $_SERVER['REQUEST_URI']
1825  * to arry like arry['blogid']=1 and array['page']=2 etc.
1826  */
1827 function serverStringToArray($str, &$array, &$frontParam)
1828 {
1829     // init param
1830     $array = array();
1831     $frontParam = "";
1832
1833     // split front param, e.g. /index.php, and others, e.g. blogid=1&page=2
1834     if (strstr($str, "?")){
1835         list($frontParam, $args) = preg_split("/\?/", $str, 2);
1836     }
1837     else {
1838         $args = $str;
1839         $frontParam = "";
1840     }
1841
1842     // If there is no args like blogid=1&page=2, return
1843     if (!strstr($str, "=") && !i18n::strlen($frontParam)) {
1844         $frontParam = $str;
1845         return;
1846     }
1847
1848     $array = i18n::explode("&", $args);
1849 }
1850
1851 /**
1852  * Convert array like array['blogid'] to server string
1853  * such as $_SERVER['REQUEST_URI']
1854  */
1855 function arrayToServerString($array, $frontParam, &$str)
1856 {
1857     if (strstr($str, "?")) {
1858         $str = $frontParam . "?";
1859     } else {
1860         $str = $frontParam;
1861     }
1862     if (count($array)) {
1863         $str .= implode("&", $array);
1864     }
1865 }
1866
1867 /**
1868  * Sanitize array parameters.
1869  * This function checks both key and value.
1870  * - check key if it inclues " (double quote),  remove from array
1871  * - check value if it includes \ (escape sequece), remove remaining string
1872  */
1873 function sanitizeArray(&$array)
1874 {
1875     $excludeListForSanitization = array('query');
1876 //      $excludeListForSanitization = array();
1877
1878     foreach ($array as $k => $v) {
1879
1880         // split to key and value
1881         list($key, $val) = preg_split("/=/", $v, 2);
1882         if (!isset($val)) {
1883             continue;
1884         }
1885
1886         // when magic quotes is on, need to use stripslashes,
1887         // and then addslashes
1888         if (get_magic_quotes_gpc()) {
1889             $val = stripslashes($val);
1890         }
1891                 // note that we must use addslashes here because this function is called before the db connection is made
1892                 // and sql_real_escape_string needs a db connection
1893         $val = addslashes($val);
1894
1895         // if $key is included in exclude list, skip this param
1896         if (!in_array($key, $excludeListForSanitization)) {
1897
1898             // check value
1899             if (i18n::strpos($val, '\\')) {
1900                 list($val, $tmp) = i18n::explode('\\', $val);
1901             }
1902
1903             // remove control code etc.
1904             $val = strtr($val, "\0\r\n<>'\"", "       ");
1905
1906             // check key
1907             if (preg_match('/\"/i', $key)) {
1908                 unset($array[$k]);
1909                 continue;
1910             }
1911
1912             // set sanitized info
1913             $array[$k] = sprintf("%s=%s", $key, $val);
1914         }
1915     }
1916 }
1917
1918 /**
1919  * Convert array for sanitizeArray function
1920  */
1921 function convArrayForSanitizing($src, &$array)
1922 {
1923     $array = array();
1924     foreach ($src as $key => $val) {
1925         if (key_exists($key, $_GET)) {
1926             array_push($array, sprintf("%s=%s", $key, $val));
1927         }
1928     }
1929 }
1930
1931 /**
1932  * Revert array after sanitizeArray function
1933  */
1934 function revertArrayForSanitizing($array, &$dst)
1935 {
1936     foreach ($array as $v) {
1937         list($key, $val) = preg_split("/=/", $v, 2);
1938         $dst[$key] = $val;
1939     }
1940 }
1941
1942 /**
1943  * Stops processing the request and redirects to the given URL.
1944  * - no actual contents should have been sent to the output yet
1945  * - the URL will be stripped of illegal or dangerous characters
1946  */
1947 function redirect($url) {
1948     $url = preg_replace('|[^a-z0-9-~+_.?#=&;,/:@%*]|i', '', $url);
1949     header('Location: ' . $url);
1950     exit;
1951 }
1952
1953 /*
1954  * Returns the Javascript code for a bookmarklet that works on most modern browsers
1955  * @param blogid
1956  */
1957 function getBookmarklet($blogid) {
1958     global $CONF;
1959
1960     // normal
1961     $document = 'document';
1962     $bookmarkletline = "javascript:Q='';x=".$document.";y=window;if(x.selection){Q=x.selection.createRange().text;}else if(y.getSelection){Q=y.getSelection();}else if(x.getSelection){Q=x.getSelection();}wingm=window.open('";
1963     $bookmarkletline .= $CONF['AdminURL'] . "bookmarklet.php?blogid=$blogid";
1964     $bookmarkletline .="&logtext='+escape(Q)+'&loglink='+escape(x.location.href)+'&loglinktitle='+escape(x.title),'nucleusbm','scrollbars=yes,width=600,height=550,left=10,top=10,status=yes,resizable=yes');wingm.focus();";
1965
1966     return $bookmarkletline;
1967 }
1968 // END: functions from the end of file ADMIN.php
1969
1970 /**
1971  * Returns a variable or null if not set
1972  *
1973  * @param mixed Variable
1974  * @return mixed Variable
1975  */
1976 function ifset(&$var) {
1977     if (isset($var)) {
1978         return $var;
1979     }
1980
1981     return null;
1982 }
1983
1984 /**
1985  * Returns number of subscriber to an event
1986  *
1987  * @param event
1988  * @return number of subscriber(s)
1989  */
1990 function numberOfEventSubscriber($event) {
1991     $query = 'SELECT COUNT(*) as count FROM ' . sql_table('plugin_event') . ' WHERE event=\'' . $event . '\'';
1992     $res = sql_query($query);
1993     $obj = sql_fetch_object($res);
1994     return $obj->count;
1995 }
1996
1997 /**
1998  * sets $special global variable for use in index.php before selector()
1999  *
2000  * @param String id
2001  * @return nothing
2002  */
2003 function selectSpecialSkinType($id) {
2004     global $special;
2005     $special = strtolower($id);
2006 }
2007
2008 /**
2009  * cleans filename of uploaded file for writing to file system
2010  *
2011  * @param String str
2012  * @return String cleaned filename ready for use
2013  */
2014 function cleanFileName($str) {
2015         $str = strtolower($str);
2016         $ext_point = i18n::strrpos($str,".");
2017         if ($ext_point===false) return false;
2018         $ext = i18n::substr($str,$ext_point,i18n::strlen($str));
2019         $str = i18n::substr($str,0,$ext_point);
2020
2021         return preg_replace("/[^a-z0-9-]/","_",$str).$ext;
2022 }
2023
2024 /**
2025  * Centralisation of the functions to send mail
2026  * Deprecated since 4.0:
2027  * Please use functions in NOTIFICATION class instead
2028  */
2029 function getMailFooter()
2030 {
2031         NOTIFICATION::get_mail_footer();
2032 }
2033 function isValidMailAddress($address)
2034 {
2035         return NOTIFICATION::address_validation($address);
2036 }
2037 /**
2038  * Centralisation of the functions that deals XML entities
2039  * Deprecated since 4.0:
2040  * Please use ENTITY::FunctionName(...) instead
2041  */
2042 function highlight($text, $expression, $highlight)
2043 {
2044         return ENTITY::highlight($text, $expression, $highlight);
2045 }
2046 function shorten($string, $maxlength, $suffix)
2047 {
2048         return ENTITY::shorten($string, $maxlength, $suffix);
2049 }
2050 function stringStripTags ($string)
2051 {
2052         return ENTITY::strip_tags($string);
2053 }
2054 function toAscii($string)
2055 {
2056         return ENTITY::anchor_footnoting($string);
2057 }
2058 function stringToAttribute ($string)
2059 {
2060         return ENTITY::hsc($string);
2061 }
2062 function stringToXML ($string)
2063 {
2064         return ENTITY::hen($string);
2065 }
2066 function encode_desc($data)
2067 {
2068         return ENTITY::hen($data);
2069 }
2070 /**
2071  * Centralisation of the functions that deals with locales
2072  * This functions is based on the old way to deal with languages
2073  * Deprecated since 4.0:
2074  */
2075 /* NOTE: use i18n::get_current_locale() directly instead of this */
2076 function getLanguageName()
2077 {
2078         if( ($language = i18n::convert_locale_to_old_language_file_name(i18n::get_current_locale())) === FALSE )
2079         {
2080                 $language ='english';
2081         }
2082         return $language;
2083 }
2084
2085 /* NOTE: use i18n::get_available_locales() directly instead of this */
2086 function checkLanguage($lang)
2087 {
2088         return ( preg_match('#^(.+)_(.+)_(.+)$#', $lang)
2089           || i18n::convert_old_language_file_name_to_locale($lang) );
2090 }
2091 /* NOTE: use i18n::formatted_datetime() directly instead of this */
2092 function formatDate($format, $timestamp, $default_format, &$blog)
2093 {
2094         $offset = date('Z', $timestamp);
2095         if ( $blog )
2096         {
2097                 $offset += $blog->getTimeOffset() * 3600;
2098         }
2099         return i18n::formatted_datetime($format, $timestamp, $default_format, $offset);
2100 }
2101 /**
2102  * Centralisation of the functions that generate links
2103  * Deprecated since 4.0:
2104  * Please use LINK::FunctionName(...) instead
2105  */
2106 function createItemLink($itemid, $extra = '')
2107 {
2108         return LINK::create_item_link($itemid, $extra);
2109 }
2110 function createMemberLink($memberid, $extra = '')
2111 {
2112         return LINK::create_member_link($memberid, $extra);
2113 }
2114 function createCategoryLink($catid, $extra = '')
2115 {
2116         return LINK::create_category_link($catid, $extra);
2117 }
2118 function createArchiveListLink($blogid = '', $extra = '')
2119 {
2120         return LINK::create_archivelist_link($blogid, $extra);
2121 }
2122 function createArchiveLink($blogid, $archive, $extra = '')
2123 {
2124         return LINK::create_archive_link($blogid, $archive, $extra);
2125 }
2126 function createBlogidLink($blogid, $params = '')
2127 {
2128         return LINK::create_blogid_link($blogid, $params = '');
2129 }
2130 function createLink($type, $params)
2131 {
2132         return LINK::create_link($type, $params);
2133 }
2134 function createBlogLink($url, $params)
2135 {
2136         return LINK::create_blog_link($url, $params);
2137 }