OSDN Git Service

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