OSDN Git Service

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