OSDN Git Service

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