OSDN Git Service

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