OSDN Git Service

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