OSDN Git Service

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