OSDN Git Service

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