OSDN Git Service

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