[ Index ]

PHP Cross Reference of Textpattern 4.0.8

title

Body

[close]

/textpattern/lib/ -> txplib_misc.php (source)

   1  <?php
   2  
   3  /*
   4  $HeadURL: https://textpattern.googlecode.com/svn/releases/4.0.8/source/textpattern/lib/txplib_misc.php $
   5  $LastChangedRevision: 3074 $
   6  */
   7  
   8  // -------------------------------------------------------------
   9  	function doArray($in,$function)
  10      {
  11          return is_array($in) ? array_map($function,$in) : $function($in);
  12      }
  13  
  14  // -------------------------------------------------------------
  15  	function doStrip($in)
  16      {
  17          return doArray($in,'stripslashes');
  18      }
  19  
  20  // -------------------------------------------------------------
  21  	function doStripTags($in)
  22      {
  23          return doArray($in,'strip_tags');
  24      }
  25  
  26  // -------------------------------------------------------------
  27  	function doDeEnt($in)
  28      {
  29          return doArray($in,'deEntBrackets');
  30      }
  31  
  32  // -------------------------------------------------------------
  33  	function deEntBrackets($in)
  34      {
  35          $array = array(
  36              '&#60;'  => '<',
  37              '&lt;'   => '<',
  38              '&#x3C;' => '<',
  39              '&#62;'  => '>',
  40              '&gt;'   => '>',
  41              '&#x3E;' => '>'
  42          );
  43  
  44          foreach($array as $k=>$v){
  45              $in = preg_replace("/".preg_quote($k)."/i",$v, $in);
  46          }
  47          return $in;
  48      }
  49  
  50  // -------------------------------------------------------------
  51  	function doSlash($in)
  52      {
  53          return doArray($in,'mysql_real_escape_string');
  54      }
  55  
  56  // -------------------------------------------------------------
  57  	function doSpecial($in)
  58      {
  59          return doArray($in,'htmlspecialchars');
  60      }
  61  
  62  // -------------------------------------------------------------
  63  	function _null($a)
  64      {
  65          return NULL;
  66      }
  67  // -------------------------------------------------------------
  68  	function array_null($in)
  69      {
  70          return array_map('_null', $in);
  71      }
  72  
  73  // -------------------------------------------------------------
  74  	function escape_title($title)
  75      {
  76          return strtr($title,
  77              array(
  78                  '<' => '&#60;',
  79                  '>' => '&#62;',
  80                  "'" => '&#39;',
  81                  '"' => '&#34;',
  82              )
  83          );
  84      }
  85  
  86  // -------------------------------------------------------------
  87  // deprecated, use htmlspecialchars instead. Remove in crockery
  88  	function escape_output($str)
  89      {
  90          return htmlspecialchars($str);
  91      }
  92  
  93  // -------------------------------------------------------------
  94  // unused function => deprecate and remove in crockery?
  95  	function escape_tags($str)
  96      {
  97          return strtr($str,
  98              array(
  99                  '<' => '&#60;',
 100                  '>' => '&#62;',
 101              )
 102          );
 103      }
 104  
 105  // -------------------------------------------------------------
 106  	function escape_cdata($str)
 107      {
 108          return '<![CDATA['.str_replace(']]>', ']]]><![CDATA[]>', $str).']]>';
 109      }
 110  
 111  //-------------------------------------------------------------
 112  	function gTxt($var, $atts=array())
 113      {
 114          global $textarray;
 115          if(isset($textarray[strtolower($var)])) {
 116              $out = $textarray[strtolower($var)];
 117              return strtr($out, $atts);
 118          }
 119  
 120          if ($atts)
 121              return $var.': '.join(', ', $atts);
 122          return $var;
 123      }
 124  
 125  //-------------------------------------------------------------
 126  	function gTime($timestamp)
 127      {
 128          return safe_strftime('%d&#160;%b&#160;%Y %X', $timestamp);
 129      }
 130  
 131  // -------------------------------------------------------------
 132  	function dmp()
 133      {
 134          static $f = FALSE;
 135  
 136          if(defined('txpdmpfile'))
 137          {
 138              global $prefs;
 139  
 140              if(!$f) $f = fopen($prefs['tempdir'].'/'.txpdmpfile, 'a');
 141  
 142              fwrite($f, "\n[".safe_strftime('iso8601')."]\n");
 143          }
 144  
 145          $a = func_get_args();
 146  
 147          if(!$f) echo "<pre>".n;
 148  
 149          foreach ($a as $thing)
 150          {
 151              $out = is_scalar($thing) ? strval($thing) : var_export($thing, true);
 152  
 153              if ($f)
 154              {
 155                  fwrite($f, $out."\n");
 156              }
 157              else
 158              {
 159                  echo htmlspecialchars($out), n;
 160              }
 161          }
 162  
 163          if(!$f) echo "</pre>".n;
 164      }
 165  
 166  // -------------------------------------------------------------
 167  	function load_lang($lang)
 168      {
 169          global $txpcfg;
 170  
 171          foreach(array($lang, 'en-gb') as $lang_code)
 172          {
 173              $rs = (txpinterface == 'admin')
 174                  ? safe_rows_start('name, data','txp_lang',"lang='".doSlash($lang_code)."'")
 175                  : safe_rows_start('name, data','txp_lang',"lang='".doSlash($lang_code)."' AND ( event='public' OR event='common')");
 176  
 177              if (mysql_num_rows($rs)) break;
 178          }
 179  
 180          $out = array();
 181  
 182          if ($rs && mysql_num_rows($rs) > 0)
 183          {
 184              while ($a = nextRow($rs))
 185              {
 186                  $out[$a['name']] = $a['data'];
 187              }
 188          }else{
 189              #backward compatibility stuff. Remove when necessary.
 190              $filename = is_file(txpath.'/lang/'.$lang.'.txt')
 191              ?    txpath.'/lang/'.$lang.'.txt'
 192              :    txpath.'/lang/en-gb.txt';
 193  
 194              $file = @fopen($filename, "r");
 195              if ($file) {
 196                  while (!feof($file)) {
 197                      $line = fgets($file, 4096);
 198                  if($line[0]=='#') continue;
 199                  @list($name,$val) = explode(' => ',trim($line));
 200                  $out[$name] = $val;
 201               }
 202                  @fclose($filename);
 203              }
 204          }
 205  
 206          return $out;
 207      }
 208  
 209  // -------------------------------------------------------------
 210  	function load_lang_dates($lang)
 211      {
 212          global $txpcfg;
 213          $filename = is_file(txpath.'/lang/'.$lang.'_dates.txt')?
 214              txpath.'/lang/'.$lang.'_dates.txt':
 215              txpath.'/lang/en-gb_dates.txt';
 216          $file = @file(txpath.'/lang/'.$lang.'_dates.txt','r');
 217          if(is_array($file)) {
 218              foreach($file as $line) {
 219                  if($line[0]=='#' || strlen($line) < 2) continue;
 220                  list($name,$val) = explode('=>',$line,2);
 221                  $out[trim($name)] = trim($val);
 222              }
 223              return $out;
 224          }
 225          return false;
 226      }
 227  // -------------------------------------------------------------
 228  
 229  	function load_lang_event($event)
 230      {
 231          global $txpcfg;
 232          $lang = LANG;
 233  
 234          $installed = safe_field('name', 'txp_lang',"lang='".doSlash($lang)."' limit 1");
 235  
 236          $lang_code = ($installed)? $lang : 'en-gb';
 237  
 238          $rs = safe_rows_start('name, data','txp_lang',"lang='".doSlash($lang_code)."' AND event='".doSlash($event)."'");
 239  
 240          $out = array();
 241  
 242          if ($rs && !empty($rs))
 243          {
 244              while ($a = nextRow($rs))
 245              {
 246                  $out[$a['name']] = $a['data'];
 247              }
 248          }
 249          return ($out) ? $out : '';
 250      }
 251  
 252  // -------------------------------------------------------------
 253  	function check_privs()
 254      {
 255          global $txp_user;
 256          $privs = safe_field("privs", "txp_users", "name='".doSlash($txp_user)."'");
 257          $args = func_get_args();
 258          if(!in_array($privs,$args)) {
 259              exit(pageTop('Restricted').'<p style="margin-top:3em;text-align:center">'.
 260                  gTxt('restricted_area').'</p>');
 261          }
 262      }
 263  
 264  // -------------------------------------------------------------
 265  	function add_privs($res, $perm = '1') // perm = '1,2,3'
 266      {
 267          global $txp_permissions;
 268          // Don't let them override privs that exist
 269          if (!isset($txp_permissions[$res]))
 270              $txp_permissions[$res] = $perm;
 271      }
 272  
 273  // -------------------------------------------------------------
 274  	function has_privs($res, $user='')
 275      {
 276          global $txp_user, $txp_permissions;
 277          static $privs;
 278  
 279          // If no user name is supplied, assume the current login name
 280          if (empty($user))
 281              $user = $txp_user;
 282  
 283          if (!isset($privs[$user]))
 284          {
 285              $privs[$user] = safe_field("privs", "txp_users", "name='".doSlash($user)."'");
 286          }
 287  
 288          if (isset($txp_permissions[$res]))
 289          {
 290              return in_array($privs[$user], explode(',', $txp_permissions[$res]));
 291          }
 292  
 293          else
 294          {
 295              return false;
 296          }
 297      }
 298  
 299  // -------------------------------------------------------------
 300  	function require_privs($res, $user='')
 301      {
 302          if (!has_privs($res, $user))
 303              exit(pageTop('Restricted').'<p style="margin-top:3em;text-align:center">'.
 304                  gTxt('restricted_area').'</p>');
 305      }
 306  
 307  // -------------------------------------------------------------
 308  	function sizeImage($name)
 309      {
 310          $size = @getimagesize($name);
 311          return(is_array($size)) ? $size[3] : false;
 312      }
 313  
 314  // -------------------------------------------------------------
 315  	function gps($thing) // checks GET and POST for a named variable, or creates it blank
 316      {
 317          if (isset($_GET[$thing])) {
 318              if (MAGIC_QUOTES_GPC) {
 319                  return doStrip($_GET[$thing]);
 320              } else {
 321                  return $_GET[$thing];
 322              }
 323          } elseif (isset($_POST[$thing])) {
 324              if (MAGIC_QUOTES_GPC) {
 325                  return doStrip($_POST[$thing]);
 326              } else {
 327                  return $_POST[$thing];
 328              }
 329          }
 330          return '';
 331      }
 332  
 333  // -------------------------------------------------------------
 334  	function gpsa($array) // performs gps() on an array of variable names
 335      {
 336          if(is_array($array)) {
 337              $out = array();
 338              foreach($array as $a) {
 339                  $out[$a] = gps($a);
 340              }
 341              return $out;
 342          }
 343          return false;
 344      }
 345  
 346  // -------------------------------------------------------------
 347      function ps($thing) // checks POST for a named variable, or creates it blank
 348      {
 349          if (isset($_POST[$thing])) {
 350              if (MAGIC_QUOTES_GPC) {
 351                  return doStrip($_POST[$thing]);
 352              } else {
 353                  return $_POST[$thing];
 354              }
 355          }
 356          return '';
 357      }
 358  
 359  // -------------------------------------------------------------
 360  	function psa($array) // performs ps on an array of variable names
 361      {
 362          foreach($array as $a) {
 363              $out[$a] = ps($a);
 364          }
 365          return $out;
 366      }
 367  
 368  // -------------------------------------------------------------
 369  	function psas($array) // same as above, but does strip_tags on post values
 370      {
 371          foreach($array as $a) {
 372              $out[$a] = strip_tags(ps($a));
 373          }
 374          return $out;
 375      }
 376  
 377  // -------------------------------------------------------------
 378  	function stripPost()
 379      {
 380          if (isset($_POST)) {
 381              if (MAGIC_QUOTES_GPC) {
 382                  return doStrip($_POST);
 383              } else {
 384                  return $_POST;
 385              }
 386          }
 387          return '';
 388      }
 389  
 390  // -------------------------------------------------------------
 391  	function serverSet($thing) // Get a var from $_SERVER global array, or create it
 392      {
 393          return (isset($_SERVER[$thing])) ? $_SERVER[$thing] : '';
 394      }
 395  
 396  // -------------------------------------------------------------
 397   	function pcs($thing) //    Get a var from POST or COOKIE; if not, create it
 398      {
 399          if (isset($_COOKIE["txp_".$thing])) {
 400              if (MAGIC_QUOTES_GPC) {
 401                  return doStrip($_COOKIE["txp_".$thing]);
 402              } else return $_COOKIE["txp_".$thing];
 403          } elseif (isset($_POST[$thing])) {
 404              if (MAGIC_QUOTES_GPC) {
 405                  return doStrip($_POST[$thing]);
 406              } else return $_POST[$thing];
 407          }
 408          return '';
 409      }
 410  
 411  // -------------------------------------------------------------
 412       function cs($thing) //    Get a var from COOKIE; if not, create it
 413      {
 414          if (isset($_COOKIE[$thing])) {
 415              if (MAGIC_QUOTES_GPC) {
 416                  return doStrip($_COOKIE[$thing]);
 417              } else return $_COOKIE[$thing];
 418          }
 419          return '';
 420      }
 421  
 422  // -------------------------------------------------------------
 423  	function yes_no($status)
 424      {
 425          return ($status==0) ? (gTxt('no')) : (gTxt('yes'));
 426      }
 427  
 428  // -------------------------------------------------------------
 429  	function getmicrotime()
 430      {
 431          list($usec, $sec) = explode(" ",microtime());
 432          return ((float)$usec + (float)$sec);
 433      }
 434  
 435  // -------------------------------------------------------------
 436  	function load_plugin($name)
 437      {
 438          global $plugins, $plugins_ver, $prefs, $txp_current_plugin;
 439  
 440          if (is_array($plugins) and in_array($name,$plugins)) {
 441              return true;
 442          }
 443  
 444          if (!empty($prefs['plugin_cache_dir'])) {
 445              $dir = rtrim($prefs['plugin_cache_dir'], '/') . '/';
 446              # in case it's a relative path
 447              if (!is_dir($dir))
 448                  $dir = rtrim(realpath(txpath.'/'.$dir), '/') . '/';
 449              if (is_file($dir . $name . '.php')) {
 450                  $plugins[] = $name;
 451                  set_error_handler("pluginErrorHandler");
 452                  if (isset($txp_current_plugin)) $txp_parent_plugin = $txp_current_plugin;
 453                  $txp_current_plugin = $name;
 454                  include($dir . $name . '.php');
 455                  $txp_current_plugin = (isset($txp_parent_plugin) ? $txp_parent_plugin : NULL);
 456                  $plugins_ver[$name] = @$plugin['version'];
 457                  restore_error_handler();
 458                  return true;
 459              }
 460          }
 461  
 462          $rs = safe_row("name,code,version","txp_plugin","status = 1 AND name='".doSlash($name)."'");
 463          if ($rs) {
 464              $plugins[] = $rs['name'];
 465              $plugins_ver[$rs['name']] = $rs['version'];
 466  
 467              set_error_handler("pluginErrorHandler");
 468              if (isset($txp_current_plugin)) $txp_parent_plugin = $txp_current_plugin;
 469              $txp_current_plugin = $rs['name'];
 470              eval($rs['code']);
 471              $txp_current_plugin = (isset($txp_parent_plugin) ? $txp_parent_plugin : NULL);
 472              restore_error_handler();
 473  
 474              return true;
 475          }
 476  
 477          return false;
 478      }
 479  
 480  // -------------------------------------------------------------
 481  	function require_plugin($name)
 482      {
 483          if (!load_plugin($name))
 484              trigger_error("Unable to include required plugin \"{$name}\"",E_USER_ERROR);
 485      }
 486  
 487  // -------------------------------------------------------------
 488  	function include_plugin($name)
 489      {
 490          if (!load_plugin($name))
 491              trigger_error("Unable to include plugin \"{$name}\"",E_USER_WARNING);
 492      }
 493  
 494  // -------------------------------------------------------------
 495  	function pluginErrorHandler($errno, $errstr, $errfile, $errline)
 496      {
 497          $error = array( E_WARNING => "Warning", E_NOTICE => "Notice", E_USER_ERROR => "User_Error",
 498                          E_USER_WARNING => "User_Warning", E_USER_NOTICE => "User_Notice");
 499  
 500          if (!($errno & error_reporting())) return;
 501  
 502          global $txp_current_plugin, $production_status;
 503          printf ("<pre>".gTxt('plugin_load_error').' <b>%s</b> -> <b>%s: %s on line %s</b></pre>',
 504                  $txp_current_plugin, $error[$errno], $errstr, $errline);
 505          if ($production_status == 'debug')
 506              print "\n<pre style=\"padding-left: 2em;\" class=\"backtrace\"><code>".htmlspecialchars(join("\n", get_caller(10)))."</code></pre>";
 507      }
 508  
 509  // -------------------------------------------------------------
 510  	function tagErrorHandler($errno, $errstr, $errfile, $errline)
 511      {
 512          global $production_status;
 513  
 514          $error = array( E_WARNING => "Warning", E_NOTICE => "Notice", E_USER_ERROR => "Textpattern Error",
 515                          E_USER_WARNING => "Textpattern Warning", E_USER_NOTICE => "Textpattern Notice");
 516  
 517          if (!($errno & error_reporting())) return;
 518          if ($production_status == 'live') return;
 519  
 520          global $txp_current_tag;
 521          $errline = ($errstr === 'unknown_tag') ? '' : " on line $errline";
 522          printf ("<pre>".gTxt('tag_error').' <b>%s</b> -> <b> %s: %s %s</b></pre>',
 523                  htmlspecialchars($txp_current_tag), $error[$errno], $errstr, $errline );
 524          if ($production_status == 'debug')
 525              {
 526              print "\n<pre style=\"padding-left: 2em;\" class=\"backtrace\"><code>".htmlspecialchars(join("\n", get_caller(10)))."</code></pre>";
 527  
 528              $trace_msg = gTxt('tag_error').' '.$txp_current_tag.' -> '.$error[$errno].': '.$errstr.' '.$errline;
 529              trace_add( $trace_msg );
 530              }
 531      }
 532  
 533  // -------------------------------------------------------------
 534  	function feedErrorHandler($errno, $errstr, $errfile, $errline)
 535      {
 536          global $production_status;
 537  
 538          if ($production_status != 'debug') return;
 539  
 540          return tagErrorHandler($errno, $errstr, $errfile, $errline);
 541      }
 542  
 543  // -------------------------------------------------------------
 544  	function load_plugins($type=0)
 545      {
 546          global $prefs,$plugins, $plugins_ver;
 547  
 548          if (!is_array($plugins)) $plugins = array();
 549  
 550          if (!empty($prefs['plugin_cache_dir'])) {
 551              $dir = rtrim($prefs['plugin_cache_dir'], '/') . '/';
 552              # in case it's a relative path
 553              if (!is_dir($dir))
 554                  $dir = rtrim(realpath(txpath.'/'.$dir), '/') . '/';
 555              foreach (glob($dir.'*.php') as $f) {
 556                  load_plugin(basename($f, '.php'));
 557              }
 558          }
 559  
 560          $where = 'status = 1 AND type IN ('.($type ? '1,3' : '0,1').')';
 561  
 562          $rs = safe_rows("name, code, version", "txp_plugin", $where.' order by load_order');
 563          if ($rs) {
 564              $old_error_handler = set_error_handler("pluginErrorHandler");
 565              foreach($rs as $a) {
 566                  if (!in_array($a['name'],$plugins)) {
 567                      $plugins[] = $a['name'];
 568                      $plugins_ver[$a['name']] = $a['version'];
 569                      $GLOBALS['txp_current_plugin'] = $a['name'];
 570                      $eval_ok = eval($a['code']);
 571                      if ($eval_ok === FALSE)
 572                          echo gTxt('plugin_load_error_above').strong($a['name']).n.br;
 573                      unset($GLOBALS['txp_current_plugin']);
 574                  }
 575              }
 576              restore_error_handler();
 577          }
 578      }
 579  
 580  // -------------------------------------------------------------
 581  	function register_callback($func, $event, $step='', $pre=0)
 582      {
 583          global $plugin_callback;
 584  
 585          $plugin_callback[] = array('function'=>$func, 'event'=>$event, 'step'=>$step, 'pre'=>$pre);
 586      }
 587  
 588  // -------------------------------------------------------------
 589  	function register_page_extension($func, $event, $step='', $top=0)
 590      {
 591          # For now this just does the same as register_callback
 592          register_callback($func, $event, $step, $top);
 593      }
 594  
 595  // -------------------------------------------------------------
 596  	function callback_event($event, $step='', $pre=0)
 597      {
 598          global $plugin_callback;
 599  
 600          if (!is_array($plugin_callback))
 601              return;
 602          $return_value = '';
 603          foreach ($plugin_callback as $c) {
 604              if ($c['event'] == $event and (empty($c['step']) or $c['step'] == $step) and $c['pre'] == $pre) {
 605                  if (is_callable($c['function'])) {
 606                      $return_value .= call_user_func($c['function'], $event, $step);
 607                  }
 608              }
 609          }
 610          return $return_value;
 611      }
 612  
 613  // -------------------------------------------------------------
 614  	function register_tab($area, $event, $title)
 615      {
 616          global $plugin_areas;
 617  
 618          $plugin_areas[$area][$title] = $event;
 619      }
 620  
 621  // -------------------------------------------------------------
 622      // deprecated, use lAtts instead. Remove in crockery
 623  	function getAtt($name, $default=NULL)
 624      {
 625          global $theseatts;
 626          return isset($theseatts[$name]) ? $theseatts[$name] : $default;
 627      }
 628  
 629  // -------------------------------------------------------------
 630      // deprecated, use lAtts instead. Remove in crockery
 631  	function gAtt(&$atts, $name, $default=NULL)
 632      {
 633          return isset($atts[$name]) ? $atts[$name] : $default;
 634      }
 635  
 636  // -------------------------------------------------------------
 637  	function lAtts($pairs, $atts, $warn=1)
 638      {
 639          global $production_status;
 640  
 641          foreach($atts as $name => $value)
 642          {
 643              if (array_key_exists($name, $pairs))
 644              {
 645                  $pairs[$name] = $value;
 646              }
 647              elseif ($warn and $production_status != 'live')
 648              {
 649                  trigger_error(gTxt('unknown_attribute', array('{att}' => $name)));
 650              }
 651          }
 652  
 653          return ($pairs) ? $pairs : false;
 654      }
 655  
 656  // -------------------------------------------------------------
 657  	function select_buttons()
 658      {
 659          return
 660          gTxt('select').': '.
 661          fInput('button','selall',gTxt('all'),'smallerboxsp','select all','selectall();').
 662          fInput('button','selnone',gTxt('none'),'smallerboxsp','select none','deselectall();').
 663          fInput('button','selrange',gTxt('range'),'smallerboxsp','select range','selectrange();');
 664      }
 665  
 666  // -------------------------------------------------------------
 667  	function stripSpace($text, $force=0)
 668      {
 669          global $prefs;
 670          if ($force or !empty($prefs['attach_titles_to_permalinks']))
 671          {
 672              $text = sanitizeForUrl($text);
 673              if ($prefs['permalink_title_format']) {
 674                  return strtolower($text);
 675              } else {
 676                  return str_replace('-','',$text);
 677              }
 678          }
 679      }
 680  
 681  // -------------------------------------------------------------
 682  	function sanitizeForUrl($text)
 683      {
 684          // Remove names entities and tags
 685          $text = preg_replace("/(^|&\S+;)|(<[^>]*>)/U","",dumbDown($text));
 686          // Dashify high-order chars leftover from dumbDown()
 687          $text = preg_replace("/[\x80-\xff]/","-",$text);
 688          // Collapse spaces, minuses, (back-)slashes and non-words
 689          $text = preg_replace('/[\s\-\/\\\\]+/', '-', trim(preg_replace('/[^\w\s\-\/\\\\]/', '', $text)));
 690          // Remove all non-whitelisted characters
 691          $text = preg_replace("/[^A-Za-z0-9\-_]/","",$text);
 692          return $text;
 693      }
 694  
 695  // -------------------------------------------------------------
 696  	function dumbDown($str, $lang=LANG)
 697      {
 698          static $array;
 699          if (empty($array[$lang])) {
 700              $array[$lang] = array( // nasty, huh?.
 701                  '&#192;'=>'A','&Agrave;'=>'A','&#193;'=>'A','&Aacute;'=>'A','&#194;'=>'A','&Acirc;'=>'A',
 702                  '&#195;'=>'A','&Atilde;'=>'A','&#196;'=>'Ae','&Auml;'=>'A','&#197;'=>'A','&Aring;'=>'A',
 703                  '&#198;'=>'Ae','&AElig;'=>'AE',
 704                  '&#256;'=>'A','&#260;'=>'A','&#258;'=>'A',
 705                  '&#199;'=>'C','&Ccedil;'=>'C','&#262;'=>'C','&#268;'=>'C','&#264;'=>'C','&#266;'=>'C',
 706                  '&#270;'=>'D','&#272;'=>'D','&#208;'=>'D','&ETH;'=>'D',
 707                  '&#200;'=>'E','&Egrave;'=>'E','&#201;'=>'E','&Eacute;'=>'E','&#202;'=>'E','&Ecirc;'=>'E','&#203;'=>'E','&Euml;'=>'E',
 708                  '&#274;'=>'E','&#280;'=>'E','&#282;'=>'E','&#276;'=>'E','&#278;'=>'E',
 709                  '&#284;'=>'G','&#286;'=>'G','&#288;'=>'G','&#290;'=>'G',
 710                  '&#292;'=>'H','&#294;'=>'H',
 711                  '&#204;'=>'I','&Igrave;'=>'I','&#205;'=>'I','&Iacute;'=>'I','&#206;'=>'I','&Icirc;'=>'I','&#207;'=>'I','&Iuml;'=>'I',
 712                  '&#298;'=>'I','&#296;'=>'I','&#300;'=>'I','&#302;'=>'I','&#304;'=>'I',
 713                  '&#306;'=>'IJ',
 714                  '&#308;'=>'J',
 715                  '&#310;'=>'K',
 716                  '&#321;'=>'K','&#317;'=>'K','&#313;'=>'K','&#315;'=>'K','&#319;'=>'K',
 717                  '&#209;'=>'N','&Ntilde;'=>'N','&#323;'=>'N','&#327;'=>'N','&#325;'=>'N','&#330;'=>'N',
 718                  '&#210;'=>'O','&Ograve;'=>'O','&#211;'=>'O','&Oacute;'=>'O','&#212;'=>'O','&Ocirc;'=>'O','&#213;'=>'O','&Otilde;'=>'O',
 719                  '&#214;'=>'Oe','&Ouml;'=>'Oe',
 720                  '&#216;'=>'O','&Oslash;'=>'O','&#332;'=>'O','&#336;'=>'O','&#334;'=>'O',
 721                  '&#338;'=>'OE',
 722                  '&#340;'=>'R','&#344;'=>'R','&#342;'=>'R',
 723                  '&#346;'=>'S','&#352;'=>'S','&#350;'=>'S','&#348;'=>'S','&#536;'=>'S',
 724                  '&#356;'=>'T','&#354;'=>'T','&#358;'=>'T','&#538;'=>'T',
 725                  '&#217;'=>'U','&Ugrave;'=>'U','&#218;'=>'U','&Uacute;'=>'U','&#219;'=>'U','&Ucirc;'=>'U',
 726                  '&#220;'=>'Ue','&#362;'=>'U','&Uuml;'=>'Ue',
 727                  '&#366;'=>'U','&#368;'=>'U','&#364;'=>'U','&#360;'=>'U','&#370;'=>'U',
 728                  '&#372;'=>'W',
 729                  '&#221;'=>'Y','&Yacute;'=>'Y','&#374;'=>'Y','&#376;'=>'Y',
 730                  '&#377;'=>'Z','&#381;'=>'Z','&#379;'=>'Z',
 731                  '&#222;'=>'T','&THORN;'=>'T',
 732                  '&#224;'=>'a','&#225;'=>'a','&#226;'=>'a','&#227;'=>'a','&#228;'=>'ae',
 733                  '&auml;'=>'ae',
 734                  '&#229;'=>'a','&#257;'=>'a','&#261;'=>'a','&#259;'=>'a','&aring;'=>'a',
 735                  '&#230;'=>'ae',
 736                  '&#231;'=>'c','&#263;'=>'c','&#269;'=>'c','&#265;'=>'c','&#267;'=>'c',
 737                  '&#271;'=>'d','&#273;'=>'d','&#240;'=>'d',
 738                  '&#232;'=>'e','&#233;'=>'e','&#234;'=>'e','&#235;'=>'e','&#275;'=>'e',
 739                  '&#281;'=>'e','&#283;'=>'e','&#277;'=>'e','&#279;'=>'e',
 740                  '&#402;'=>'f',
 741                  '&#285;'=>'g','&#287;'=>'g','&#289;'=>'g','&#291;'=>'g',
 742                  '&#293;'=>'h','&#295;'=>'h',
 743                  '&#236;'=>'i','&#237;'=>'i','&#238;'=>'i','&#239;'=>'i','&#299;'=>'i',
 744                  '&#297;'=>'i','&#301;'=>'i','&#303;'=>'i','&#305;'=>'i',
 745                  '&#307;'=>'ij',
 746                  '&#309;'=>'j',
 747                  '&#311;'=>'k','&#312;'=>'k',
 748                  '&#322;'=>'l','&#318;'=>'l','&#314;'=>'l','&#316;'=>'l','&#320;'=>'l',
 749                  '&#241;'=>'n','&#324;'=>'n','&#328;'=>'n','&#326;'=>'n','&#329;'=>'n',
 750                  '&#331;'=>'n',
 751                  '&#242;'=>'o','&#243;'=>'o','&#244;'=>'o','&#245;'=>'o','&#246;'=>'oe',
 752                  '&ouml;'=>'oe',
 753                  '&#248;'=>'o','&#333;'=>'o','&#337;'=>'o','&#335;'=>'o',
 754                  '&#339;'=>'oe',
 755                  '&#341;'=>'r','&#345;'=>'r','&#343;'=>'r',
 756                  '&#353;'=>'s',
 757                  '&#249;'=>'u','&#250;'=>'u','&#251;'=>'u','&#252;'=>'ue','&#363;'=>'u',
 758                  '&uuml;'=>'ue',
 759                  '&#367;'=>'u','&#369;'=>'u','&#365;'=>'u','&#361;'=>'u','&#371;'=>'u',
 760                  '&#373;'=>'w',
 761                  '&#253;'=>'y','&#255;'=>'y','&#375;'=>'y',
 762                  '&#382;'=>'z','&#380;'=>'z','&#378;'=>'z',
 763                  '&#254;'=>'t',
 764                  '&#223;'=>'ss',
 765                  '&#383;'=>'ss',
 766                  '&agrave;'=>'a','&aacute;'=>'a','&acirc;'=>'a','&atilde;'=>'a','&auml;'=>'ae',
 767                  '&aring;'=>'a','&aelig;'=>'ae','&ccedil;'=>'c','&eth;'=>'d',
 768                  '&egrave;'=>'e','&eacute;'=>'e','&ecirc;'=>'e','&euml;'=>'e',
 769                  '&igrave;'=>'i','&iacute;'=>'i','&icirc;'=>'i','&iuml;'=>'i',
 770                  '&ntilde;'=>'n',
 771                  '&ograve;'=>'o','&oacute;'=>'o','&ocirc;'=>'o','&otilde;'=>'o','&ouml;'=>'oe',
 772                  '&oslash;'=>'o',
 773                  '&ugrave;'=>'u','&uacute;'=>'u','&ucirc;'=>'u','&uuml;'=>'ue',
 774                  '&yacute;'=>'y','&yuml;'=>'y',
 775                  '&thorn;'=>'t',
 776                  '&szlig;'=>'ss'
 777              );
 778  
 779  
 780              if (is_file(txpath.'/lib/i18n-ascii.txt')) {
 781                  $i18n = parse_ini_file(txpath.'/lib/i18n-ascii.txt', true);
 782                  # load the global map
 783                  if (@is_array($i18n['default'])) {
 784                      $array[$lang] = array_merge($array[$lang], $i18n['default']);
 785                      # base language overrides: 'de-AT' applies the 'de' section
 786                      if (preg_match('/([a-zA-Z]+)-.+/', $lang, $m)) {
 787                          if (@is_array($i18n[$m[1]]))
 788                              $array[$lang] = array_merge($array[$lang], $i18n[$m[1]]);
 789                      };
 790                      # regional language overrides: 'de-AT' applies the 'de-AT' section
 791                      if (@is_array($i18n[$lang]))
 792                          $array[$lang] = array_merge($array[$lang], $i18n[$lang]);
 793                  }
 794                  # load an old file (no sections) just in case
 795                  else
 796                      $array[$lang] = array_merge($array[$lang], $i18n);
 797              }
 798          }
 799  
 800          return strtr($str, $array[$lang]);
 801      }
 802  
 803  // -------------------------------------------------------------
 804  	function clean_url($url)
 805      {
 806          return preg_replace("/\"|'|(?:\s.*$)/",'',$url);
 807      }
 808  
 809  // -------------------------------------------------------------
 810  	function noWidow($str)
 811      {
 812          // replace the last space with a nbsp
 813          if (REGEXP_UTF8 == 1)
 814              return preg_replace('@[ ]+([[:punct:]]?\pL+[[:punct:]]?)$@u', '&#160;$1', rtrim($str));
 815          return preg_replace('@[ ]+([[:punct:]]?\w+[[:punct:]]?)$@', '&#160;$1', rtrim($str));
 816      }
 817  
 818  // -------------------------------------------------------------
 819  	function is_blacklisted($ip, $checks = '')
 820      {
 821          global $prefs;
 822  
 823          if (!$checks)
 824          {
 825              $checks = do_list($prefs['spam_blacklists']);
 826          }
 827  
 828          $rip = join('.', array_reverse(explode('.', $ip)));
 829  
 830          foreach ($checks as $a)
 831          {
 832              $parts = explode(':', $a, 2);
 833              $rbl   = $parts[0];
 834  
 835              if (isset($parts[1]))
 836              {
 837                  foreach (explode(':', $parts[1]) as $code)
 838                  {
 839                      $codes[] = strpos($code, '.') ? $code : '127.0.0.'.$code;
 840                  }
 841              }
 842  
 843              $hosts = $rbl ? @gethostbynamel($rip.'.'.trim($rbl, '. ').'.') : FALSE;
 844  
 845              if ($hosts and (!isset($codes) or array_intersect($hosts, $codes)))
 846              {
 847                  $listed[] = $rbl;
 848              }
 849          }
 850  
 851          return (!empty($listed)) ? join(', ', $listed) : false;
 852      }
 853  
 854  // -------------------------------------------------------------
 855  	function is_logged_in($user = '')
 856      {
 857          $name = substr(cs('txp_login_public'), 10);
 858  
 859          if (!strlen($name) or strlen($user) and $user !== $name)
 860          {
 861              return FALSE;
 862          }
 863  
 864          $rs = safe_row('nonce, name, RealName, email, privs', 'txp_users', "name = '".doSlash($name)."'");
 865  
 866          if ($rs and substr(md5($rs['nonce']), -10) === substr(cs('txp_login_public'), 0, 10))
 867          {
 868              unset($rs['nonce']);
 869              return $rs;
 870          }
 871          else
 872          {
 873              return FALSE;
 874          }
 875      }
 876  
 877  // -------------------------------------------------------------
 878  	function updateSitePath($here)
 879      {
 880          $here = doSlash($here);
 881          $rs = safe_field ("name",'txp_prefs',"name = 'path_to_site'");
 882          if (!$rs) {
 883              safe_insert("txp_prefs","prefs_id=1,name='path_to_site',val='$here'");
 884          } else {
 885              safe_update('txp_prefs',"val='$here'","name='path_to_site'");
 886          }
 887      }
 888  
 889  // -------------------------------------------------------------
 890  	function splat($text)
 891      {
 892          $atts  = array();
 893  
 894          if (preg_match_all('@(\w+)\s*=\s*(?:"((?:[^"]|"")*)"|\'((?:[^\']|\'\')*)\'|([^\s\'"/>]+))@s', $text, $match, PREG_SET_ORDER))
 895          {
 896              foreach ($match as $m)
 897              {
 898                  switch (count($m))
 899                  {
 900                      case 3:
 901                          $val = str_replace('""', '"', $m[2]);
 902                          break;
 903                      case 4:
 904                          $val = str_replace("''", "'", $m[3]);
 905  
 906                          if (strpos($m[3], '<txp:') !== FALSE)
 907                          {
 908                              trace_add("[attribute '".$m[1]."']");
 909                              $val = parse($val);
 910                              trace_add("[/attribute]");
 911                          }
 912  
 913                          break;
 914                      case 5:
 915                          $val = $m[4];
 916                          trigger_error(gTxt('attribute_values_must_be_quoted'), E_USER_WARNING);
 917                          break;
 918                  }
 919  
 920                  $atts[strtolower($m[1])] = $val;
 921              }
 922  
 923          }
 924  
 925          return $atts;
 926      }
 927  
 928  // -------------------------------------------------------------
 929  	function maxMemUsage($message = 'none', $returnit = 0)
 930      {
 931          static $memory_top = 0;
 932          static $memory_message;
 933  
 934          if (is_callable('memory_get_usage'))
 935          {
 936              $memory_now = memory_get_usage();
 937              if ($memory_now > $memory_top)
 938              {
 939                  $memory_top = $memory_now;
 940                  $memory_message = $message;
 941              }
 942          }
 943  
 944          if ($returnit != 0)
 945          {
 946              if (is_callable('memory_get_usage'))
 947                  return n.comment(sprintf('Memory: %sKb, %s',
 948                      ceil($memory_top/1024),$memory_message));
 949              else
 950                  return n.comment('Memory: no info available');
 951          }
 952      }
 953  
 954  // -------------------------------------------------------------
 955  	function strip_rn($str)
 956      {
 957          return strtr($str, "\r\n", '  ');
 958      }
 959  
 960  // -------------------------------------------------------------
 961  
 962  	function is_valid_email($address)
 963      {
 964          return preg_match('/^[a-z0-9](\.?[a-z0-9_+%-])*@([a-z0-9](-*[a-z0-9])*\.)+[a-z]{2,6}$/i', $address);
 965      }
 966  
 967  // -------------------------------------------------------------
 968  
 969  	function txpMail($to_address, $subject, $body, $reply_to = null)
 970      {
 971          global $txp_user, $prefs;
 972  
 973          // if mailing isn't possible, don't even try
 974          if (is_disabled('mail'))
 975          {
 976              return false;
 977          }
 978  
 979          // Likely sending passwords
 980          if (isset($txp_user))
 981          {
 982              extract(safe_row('RealName, email', 'txp_users', "name = '".doSlash($txp_user)."'"));
 983          }
 984  
 985          // Likely sending comments -> "to" equals "from"
 986          else
 987          {
 988              extract(safe_row('RealName, email', 'txp_users', "email = '".doSlash($to_address)."'"));
 989          }
 990  
 991          if ($prefs['override_emailcharset'] and is_callable('utf8_decode'))
 992          {
 993              $charset = 'ISO-8859-1';
 994  
 995              $RealName = utf8_decode($RealName);
 996              $subject = utf8_decode($subject);
 997              $body = utf8_decode($body);
 998          }
 999  
1000          else
1001          {
1002              $charset = 'UTF-8';
1003          }
1004  
1005          $RealName = encode_mailheader(strip_rn($RealName), 'phrase');
1006          $subject = encode_mailheader(strip_rn($subject), 'text');
1007          $email = strip_rn($email);
1008  
1009          if (!is_null($reply_to))
1010          {
1011              $reply_to = strip_rn($reply_to);
1012          }
1013  
1014          $sep = !is_windows() ? "\n" : "\r\n";
1015  
1016          $body = str_replace("\r\n", "\n", $body);
1017          $body = str_replace("\r", "\n", $body);
1018          $body = str_replace("\n", $sep, $body);
1019  
1020          $headers = "From: $RealName <$email>".
1021              $sep.'Reply-To: '.( isset($reply_to) ? $reply_to : "$RealName <$email>" ).
1022              $sep.'X-Mailer: Textpattern'.
1023              $sep.'Content-Transfer-Encoding: 8bit'.
1024              $sep.'Content-Type: text/plain; charset="'.$charset.'"'.
1025              $sep;
1026  
1027          if (is_valid_email($prefs['smtp_from']))
1028          {
1029              if (is_windows())
1030              {
1031                  ini_set('sendmail_from', $prefs['smtp_from']);
1032              }
1033              elseif (!ini_get('safe_mode'))
1034              {
1035                  return mail($to_address, $subject, $body, $headers, '-f'.$prefs['smtp_from']);
1036              }
1037          }
1038  
1039          return mail($to_address, $subject, $body, $headers);
1040      }
1041  
1042  // -------------------------------------------------------------
1043  	function encode_mailheader($string, $type)
1044      {
1045          global $prefs;
1046          if (!strstr($string,'=?') and !preg_match('/[\x00-\x1F\x7F-\xFF]/', $string)) {
1047              if ("phrase" == $type) {
1048                  if (preg_match('/[][()<>@,;:".\x5C]/', $string)) {
1049                      $string = '"'. strtr($string, array("\\" => "\\\\", '"' => '\"')) . '"';
1050                  }
1051              }
1052              elseif ( "text" != $type) {
1053                  trigger_error( 'Unknown encode_mailheader type', E_USER_WARNING);
1054              }
1055              return $string;
1056          }
1057          if ($prefs['override_emailcharset'] and is_callable('utf8_decode')) {
1058              $start = '=?ISO-8859-1?B?';
1059              $pcre  = '/.{1,42}/s';
1060          }
1061          else {
1062              $start = '=?UTF-8?B?';
1063              $pcre  = '/.{1,45}(?=[\x00-\x7F\xC0-\xFF]|$)/s';
1064          }
1065          $end = '?=';
1066          $sep = is_windows() ? "\r\n" : "\n";
1067          preg_match_all($pcre, $string, $matches);
1068          return $start . join($end.$sep.' '.$start, array_map('base64_encode',$matches[0])) . $end;
1069      }
1070  
1071  // -------------------------------------------------------------
1072  	function stripPHP($in)
1073      {
1074          return preg_replace("/".chr(60)."\?(?:php)?|\?".chr(62)."/i",'',$in);
1075      }
1076  
1077  // -------------------------------------------------------------
1078  
1079  /**
1080   * PEDRO:
1081   * Helper functions for common textpattern event files actions.
1082   * Code refactoring from original files. Intended to do easy and less error
1083   * prone the future build of new textpattern extensions, and to add new
1084   * events to multiedit forms.
1085   */
1086  
1087   	function event_category_popup($name, $cat = '', $id = '')
1088      {
1089          $arr = array('');
1090          $rs = getTree('root', $name);
1091  
1092          if ($rs)
1093          {
1094              return treeSelectInput('category', $rs, $cat, $id);
1095          }
1096  
1097          return false;
1098      }
1099  
1100  // -------------------------------------------------------------
1101   	function event_change_pageby($name)
1102      {
1103          $qty = gps('qty');
1104          $pageby = $name.'_list_pageby';
1105          $GLOBALS[$pageby] = $qty;
1106  
1107          safe_update('txp_prefs', "val='".doSlash($qty)."'", "name='".doSlash($pageby)."'");
1108  
1109          return;
1110      }
1111  
1112  // -------------------------------------------------------------
1113  
1114  	function event_multiedit_form($name, $methods = null, $page, $sort, $dir, $crit, $search_method)
1115      {
1116          $method = ps('edit_method');
1117  
1118          if ($methods === NULL)
1119          {
1120              $methods = array(
1121                  'delete' => gTxt('delete')
1122              );
1123          }
1124  
1125          return '<label for="withselected">'.gTxt('with_selected').'</label>'.sp.
1126              selectInput('edit_method', $methods, $method, 1, ' id="withselected" onchange="poweredit(this); return false;"').
1127              n.eInput($name).
1128              n.sInput($name.'_multi_edit').
1129              n.hInput('page', $page).
1130              ( $sort ? n.hInput('sort', $sort).n.hInput('dir', $dir) : '' ).
1131              ( $crit ? n.hInput('crit', $crit).n.hInput('search_method', $search_method) : '' ).
1132              n.fInput('submit', '', gTxt('go'), 'smallerbox');
1133      }
1134  
1135  // -------------------------------------------------------------
1136  
1137  	function event_multi_edit($table, $id_key)
1138      {
1139          $method = ps('edit_method');
1140          $selected = ps('selected');
1141  
1142          if ($selected)
1143          {
1144              if ($method == 'delete')
1145              {
1146                  foreach ($selected as $id)
1147                  {
1148                      $id = assert_int($id);
1149  
1150                      if (safe_delete($table, "$id_key = $id"))
1151                      {
1152                          $ids[] = $id;
1153                      }
1154                  }
1155  
1156                  return join(', ', $ids);
1157              }
1158          }
1159  
1160          return '';
1161      }
1162  
1163  // -------------------------------------------------------------
1164  	function since($stamp)
1165      {
1166          $diff = (time() - $stamp);
1167          if ($diff <= 3600) {
1168              $mins = round($diff / 60);
1169              $since = ($mins <= 1)
1170              ?    ($mins==1)
1171                  ?    '1 '.gTxt('minute')
1172                  :    gTxt('a_few_seconds')
1173              :    "$mins ".gTxt('minutes');
1174          } else if (($diff <= 86400) && ($diff > 3600)) {
1175              $hours = round($diff / 3600);
1176              $since = ($hours <= 1) ? '1 '.gTxt('hour') : "$hours ".gTxt('hours');
1177          } else if ($diff >= 86400) {
1178              $days = round($diff / 86400);
1179              $since = ($days <= 1) ? "1 ".gTxt('day') : "$days ".gTxt('days');
1180          }
1181          return $since.' '.gTxt('ago'); // sorry, this needs to be hacked until a truly multilingual version is done
1182      }
1183  
1184  // -------------------------------------------------------------
1185  // Calculate the offset between the server local time and the
1186  // user's selected time zone
1187  	function tz_offset()
1188      {
1189          global $gmtoffset, $is_dst;
1190  
1191          extract(getdate());
1192          $serveroffset = gmmktime(0,0,0,$mon,$mday,$year) - mktime(0,0,0,$mon,$mday,$year);
1193          $offset = $gmtoffset - $serveroffset;
1194  
1195          return $offset + ($is_dst ? 3600 : 0);
1196      }
1197  
1198  // -------------------------------------------------------------
1199  // Format a time, respecting the locale and local time zone,
1200  // and make sure the output string is safe for UTF-8
1201  	function safe_strftime($format, $time='', $gmt=0, $override_locale='')
1202      {
1203          global $locale;
1204          $old_locale = $locale;
1205  
1206          if (!$time)
1207              $time = time();
1208  
1209          # we could add some other formats here
1210          if ($format == 'iso8601' or $format == 'w3cdtf') {
1211              $format = '%Y-%m-%dT%H:%M:%SZ';
1212              $gmt = 1;
1213          }
1214          elseif ($format == 'rfc822') {
1215              $format = '%a, %d %b %Y %H:%M:%S GMT';
1216              $gmt = 1;
1217              $override_locale = 'en-gb';
1218          }
1219  
1220          if ($override_locale)
1221              getlocale($override_locale);
1222  
1223          if ($format == 'since')
1224              $str = since($time);
1225          elseif ($gmt)
1226              $str = gmstrftime($format, $time);
1227          else
1228              $str = strftime($format, $time + tz_offset());
1229  
1230          @list($lang, $charset) = explode('.', $locale);
1231          if (empty($charset))
1232              $charset = 'ISO-8859-1';
1233          elseif (is_windows() and is_numeric($charset))
1234              // Score -1 for consistent naming conventions
1235              $charset = 'Windows-'.$charset;
1236  
1237          if ($charset != 'UTF-8' and $format != 'since') {
1238              $new = '';
1239              if (is_callable('iconv'))
1240                  $new = @iconv($charset, 'UTF-8', $str);
1241  
1242              if ($new)
1243                  $str = $new;
1244              elseif (is_callable('utf8_encode'))
1245                  $str = utf8_encode($str);
1246          }
1247  
1248          # revert to the old locale
1249          if ($override_locale)
1250              $locale = setlocale(LC_ALL, $old_locale);
1251  
1252          return $str;
1253      }
1254  
1255  // -------------------------------------------------------------
1256  // Convert a time string from the Textpattern time zone to GMT
1257  	function safe_strtotime($time_str)
1258      {
1259          return strtotime($time_str, time()+tz_offset()) - tz_offset();
1260      }
1261  
1262  // -------------------------------------------------------------
1263  	function myErrorHandler($errno, $errstr, $errfile, $errline)
1264      {
1265          # error_reporting() returns 0 when the '@' suppression
1266          # operator is used
1267          if (!error_reporting())
1268              return;
1269  
1270          echo '<pre>'.n.n."$errno: $errstr in $errfile at line $errline\n";
1271          # Requires PHP 4.3
1272          if (is_callable('debug_backtrace')) {
1273              echo "Backtrace:\n";
1274              $trace = debug_backtrace();
1275              foreach($trace as $ent) {
1276                  if(isset($ent['file'])) echo $ent['file'].':';
1277                  if(isset($ent['function'])) {
1278                      echo $ent['function'].'(';
1279                      if(isset($ent['args'])) {
1280                          $args='';
1281                          foreach($ent['args'] as $arg) { $args.=$arg.','; }
1282                          echo rtrim($args,',');
1283                      }
1284                      echo ') ';
1285                  }
1286                  if(isset($ent['line'])) echo 'at line '.$ent['line'].' ';
1287                  if(isset($ent['file'])) echo 'in '.$ent['file'];
1288                  echo "\n";
1289              }
1290          }
1291          echo "</pre>";
1292      }
1293  
1294  // -------------------------------------------------------------
1295  	function find_temp_dir()
1296      {
1297          global $path_to_site, $img_dir;
1298  
1299          if (is_windows()) {
1300              $guess = array(txpath.DS.'tmp', getenv('TMP'), getenv('TEMP'), getenv('SystemRoot').DS.'Temp', 'C:'.DS.'Temp', $path_to_site.DS.$img_dir);
1301              foreach ($guess as $k=>$v)
1302                  if (empty($v)) unset($guess[$k]);
1303          }
1304          else
1305              $guess = array(txpath.DS.'tmp', '', DS.'tmp', $path_to_site.DS.$img_dir);
1306  
1307          foreach ($guess as $dir) {
1308              $tf = @tempnam($dir, 'txp_');
1309              if ($tf) $tf = realpath($tf);
1310              if ($tf and file_exists($tf)) {
1311                  unlink($tf);
1312                  return dirname($tf);
1313              }
1314          }
1315  
1316          return false;
1317      }
1318  
1319  // -------------------------------------------------------------
1320  	function get_uploaded_file($f, $dest='')
1321      {
1322          global $tempdir;
1323  
1324          if (!is_uploaded_file($f))
1325              return false;
1326  
1327          if ($dest) {
1328              $newfile = $dest;
1329          }
1330          else {
1331              $newfile = tempnam($tempdir, 'txp_');
1332              if (!$newfile)
1333                  return false;
1334          }
1335  
1336          # $newfile is created by tempnam(), but move_uploaded_file
1337          # will overwrite it
1338          if (move_uploaded_file($f, $newfile))
1339              return $newfile;
1340      }
1341  
1342  // --------------------------------------------------------------
1343  	function set_error_level($level)
1344      {
1345  
1346          if ($level == 'debug') {
1347              error_reporting(E_ALL);
1348          }
1349          elseif ($level == 'live') {
1350              // don't show errors on screen
1351              error_reporting(E_ALL ^ (E_WARNING | E_NOTICE));
1352              @ini_set("display_errors","1");
1353          }
1354          else {
1355              // default is 'testing': display everything except notices
1356              error_reporting(E_ALL ^ (E_NOTICE));
1357          }
1358      }
1359  
1360  
1361  // -------------------------------------------------------------
1362  	function shift_uploaded_file($f, $dest)
1363      {
1364          // Rename might not work, but it's worth a try
1365          if (@rename($f, $dest))
1366              return true;
1367  
1368          if (@copy($f, $dest)) {
1369              unlink($f);
1370              return true;
1371          }
1372      }
1373  // -------------------------------------------------------------
1374  	function upload_get_errormsg($err_code)
1375      {
1376          $msg = '';
1377          switch ($err_code)
1378          {
1379                  // Value: 0; There is no error, the file uploaded with success.
1380              case UPLOAD_ERR_OK         : $msg = '';break;
1381                  // Value: 1; The uploaded file exceeds the upload_max_filesize directive in php.ini.
1382              case UPLOAD_ERR_INI_SIZE   : $msg = gTxt('upload_err_ini_size');break;
1383                  // Value: 2; The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.
1384              case UPLOAD_ERR_FORM_SIZE  : $msg = gTxt('upload_err_form_size');break;
1385                  // Value: 3; The uploaded file was only partially uploaded.
1386              case UPLOAD_ERR_PARTIAL    : $msg = gTxt('upload_err_partial');break;
1387                  // Value: 4; No file was uploaded.
1388              case UPLOAD_ERR_NO_FILE    : $msg = gTxt('upload_err_no_file');break;
1389                  // Value: 6; Missing a temporary folder. Introduced in PHP 4.3.10 and PHP 5.0.3.
1390              case UPLOAD_ERR_NO_TMP_DIR : $msg = gTxt('upload_err_tmp_dir');break;
1391                  // Value: 7; Failed to write file to disk. Introduced in PHP 5.1.0.
1392              case UPLOAD_ERR_CANT_WRITE : $msg = gTxt('upload_err_cant_write');break;
1393                  // Value: 8; File upload stopped by extension. Introduced in PHP 5.2.0.
1394              case UPLOAD_ERR_EXTENSION  : $msg = gTxt('upload_err_extension');break;
1395          }
1396          return $msg;
1397      }
1398  
1399  // -------------------------------------------------------------
1400  	function is_windows()
1401      {
1402          return (PHP_OS == 'WINNT' or PHP_OS == 'WIN32' or PHP_OS == 'Windows');
1403      }
1404  
1405  // -------------------------------------------------------------
1406  	function is_cgi()
1407      {
1408          return IS_CGI;
1409      }
1410  
1411  // -------------------------------------------------------------
1412  	function is_mod_php()
1413      {
1414          return IS_APACHE;
1415      }
1416  
1417  // -------------------------------------------------------------
1418  
1419  	function is_disabled($function)
1420      {
1421          static $disabled;
1422  
1423          if (!isset($disabled))
1424          {
1425              $disabled = explode(',', ini_get('disable_functions'));
1426          }
1427  
1428          return in_array($function, $disabled);
1429      }
1430  
1431  // --------------------------------------------------------------
1432  	function build_file_path($base,$path)
1433      {
1434          $base = rtrim($base,'/\\');
1435          $path = ltrim($path,'/\\');
1436  
1437          return $base.DIRECTORY_SEPARATOR.$path;
1438      }
1439  
1440  // --------------------------------------------------------------
1441  	function get_author_name($name)
1442      {
1443          static $authors = array();
1444  
1445          if (isset($authors[$name]))
1446              return $authors[$name];
1447  
1448          $realname = fetch('RealName','txp_users','name',doSlash($name));
1449          $authors[$name] = $realname;
1450          return ($realname) ? $realname : $name;
1451      }
1452  
1453  
1454  // --------------------------------------------------------------
1455  	function EvalElse($thing, $condition)
1456      {
1457          global $txp_current_tag;
1458  
1459          trace_add("[$txp_current_tag: ".($condition ? gTxt('true') : gTxt('false'))."]");
1460  
1461          $els = strpos($thing, '<txp:else');
1462  
1463          if ($els === FALSE)
1464          {
1465              return $condition ? $thing : '';
1466          }
1467          elseif ($els === strpos($thing, '<txp:'))
1468          {
1469              return $condition
1470                  ? substr($thing, 0, $els)
1471                  : substr($thing, strpos($thing, '>', $els) + 1);
1472          }
1473  
1474          $tag    = FALSE;
1475          $level  = 0;
1476          $str    = '';
1477          $regex  = '@(</?txp:\w+(?:\s+\w+\s*=\s*(?:"(?:[^"]|"")*"|\'(?:[^\']|\'\')*\'|[^\s\'"/>]+))*\s*/?'.chr(62).')@s';
1478          $parsed = preg_split($regex, $thing, -1, PREG_SPLIT_DELIM_CAPTURE);
1479  
1480          foreach ($parsed as $chunk)
1481          {
1482              if ($tag)
1483              {
1484                  if ($level === 0 and strpos($chunk, 'else') === 5 and substr($chunk, -2, 1) === '/')
1485                  {
1486                      return $condition
1487                          ? $str
1488                          : substr($thing, strlen($str)+strlen($chunk));
1489                  }
1490                  elseif (substr($chunk, 1, 1) === '/')
1491                  {
1492                      $level--;
1493                  }
1494                  elseif (substr($chunk, -2, 1) !== '/')
1495                  {
1496                      $level++;
1497                  }
1498              }
1499  
1500              $tag = !$tag;
1501              $str .= $chunk;
1502          }
1503  
1504          return $condition ? $thing : '';
1505      }
1506  
1507  // --------------------------------------------------------------
1508  	function fetch_form($name)
1509      {
1510          static $forms = array();
1511  
1512          if (isset($forms[$name]))
1513              $f = $forms[$name];
1514          else {
1515              $row = safe_row('Form', 'txp_form',"name='".doSlash($name)."'");
1516              if (!$row) {
1517                  trigger_error(gTxt('form_not_found').': '.$name);
1518                  return;
1519              }
1520              $f = $row['Form'];
1521              $forms[$name] = $f;
1522          }
1523  
1524          trace_add('['.gTxt('form').': '.$name.']');
1525          return $f;
1526      }
1527  
1528  // --------------------------------------------------------------
1529  	function parse_form($name)
1530      {
1531          static $stack = array();
1532  
1533          $f = fetch_form($name);
1534          if ($f) {
1535              if (in_array($name, $stack)) {
1536                  trigger_error(gTxt('form_circular_reference', array('{name}' => $name)));
1537                  return;
1538              }
1539              array_push($stack, $name);
1540              $out = parse($f);
1541              array_pop($stack);
1542              return $out;
1543          }
1544      }
1545  
1546  // --------------------------------------------------------------
1547  	function fetch_category_title($name, $type='article')
1548      {
1549          static $cattitles = array();
1550          global $thiscategory;
1551  
1552          if (isset($cattitles[$type][$name]))
1553              return $cattitles[$type][$name];
1554  
1555          if(!empty($thiscategory['title']) && $thiscategory['name'] == $name && $thiscategory['type'] == $type)
1556          {
1557              $cattitles[$type][$name] = $thiscategory['title'];
1558              return $thiscategory['title'];
1559          }
1560  
1561          $f = safe_field('title','txp_category',"name='".doSlash($name)."' and type='".doSlash($type)."'");
1562          $cattitles[$type][$name] = $f;
1563          return $f;
1564      }
1565  
1566  // -------------------------------------------------------------
1567  	function fetch_section_title($name)
1568      {
1569          static $sectitles = array();
1570          global $thissection;
1571  
1572          // try cache
1573          if (isset($sectitles[$name]))
1574              return $sectitles[$name];
1575  
1576          // try global set by section_list()
1577          if(!empty($thissection['title']) && $thissection['name'] == $name)
1578          {
1579              $sectitles[$name] = $thissection['title'];
1580              return $thissection['title'];
1581          }
1582  
1583          if($name == 'default' or empty($name))
1584              return '';
1585  
1586          $f = safe_field('title','txp_section',"name='".doSlash($name)."'");
1587          $sectitles[$name] = $f;
1588          return $f;
1589      }
1590  
1591  // -------------------------------------------------------------
1592  	function update_comments_count($id)
1593      {
1594          $id = assert_int($id);
1595          $thecount = safe_field('count(*)','txp_discuss','parentid='.$id.' and visible='.VISIBLE);
1596          $thecount = assert_int($thecount);
1597          $updated = safe_update('textpattern','comments_count='.$thecount,'ID='.$id);
1598          return ($updated) ? true : false;
1599      }
1600  
1601  // -------------------------------------------------------------
1602  	function clean_comment_counts($parentids)
1603      {
1604          $parentids = array_map('assert_int',$parentids);
1605          $rs = safe_rows_start('parentid, count(*) as thecount','txp_discuss','parentid IN ('.implode(',',$parentids).') AND visible='.VISIBLE.' group by parentid');
1606          if (!$rs) return;
1607  
1608          $updated = array();
1609          while($a = nextRow($rs)) {
1610              safe_update('textpattern',"comments_count=".$a['thecount'],"ID=".$a['parentid']);
1611              $updated[] = $a['parentid'];
1612          }
1613          // We still need to update all those, that have zero comments left.
1614          $leftover = array_diff($parentids, $updated);
1615          if ($leftover)
1616              safe_update('textpattern',"comments_count=0","ID IN (".implode(',',$leftover).")");
1617      }
1618  
1619  // -------------------------------------------------------------
1620  
1621  	function markup_comment($msg)
1622      {
1623          global $prefs;
1624  
1625          $disallow_images = !empty($prefs['comments_disallow_images']);
1626          $lite = empty($prefs['comments_use_fat_textile']);
1627  
1628          $rel = !empty($prefs['comment_nofollow']) ? 'nofollow' : '';
1629  
1630          include_once txpath.'/lib/classTextile.php';
1631  
1632          $textile = new Textile();
1633  
1634          return $textile->TextileRestricted($msg, $lite, $disallow_images, $rel);
1635      }
1636  
1637  //-------------------------------------------------------------
1638  	function update_lastmod() {
1639          safe_upsert("txp_prefs", "val = now()", "name = 'lastmod'");
1640      }
1641  
1642  //-------------------------------------------------------------
1643  	function get_lastmod($unix_ts=NULL) {
1644          global $prefs;
1645  
1646          if ($unix_ts === NULL)
1647              $unix_ts = @strtotime($prefs['lastmod']);
1648  
1649          # check for future articles that are now visible
1650          if ($max_article = safe_field('unix_timestamp(Posted)', 'textpattern', "Posted <= now() and Status >= 4 order by Posted desc limit 1")) {
1651              $unix_ts = max($unix_ts, $max_article);
1652          }
1653  
1654          return $unix_ts;
1655      }
1656  
1657  //-------------------------------------------------------------
1658  	function handle_lastmod($unix_ts=NULL, $exit=1) {
1659          global $prefs;
1660          extract($prefs);
1661  
1662          if($send_lastmod and $production_status == 'live') {
1663              $unix_ts = get_lastmod($unix_ts);
1664  
1665              # make sure lastmod isn't in the future
1666              $unix_ts = min($unix_ts, time());
1667              # or too far in the past (7 days)
1668              $unix_ts = max($unix_ts, time() - 3600*24*7);
1669  
1670              $last = safe_strftime('rfc822', $unix_ts, 1);
1671              header("Last-Modified: $last");
1672              header('Cache-Control: no-cache');
1673  
1674              $hims = serverset('HTTP_IF_MODIFIED_SINCE');
1675              if ($hims and @strtotime($hims) >= $unix_ts) {
1676                  log_hit('304');
1677                  if (!$exit)
1678                      return array('304', $last);
1679                  txp_status_header('304 Not Modified');
1680                  # some mod_deflate versions have a bug that breaks subsequent
1681                  # requests when keepalive is used.  dropping the connection
1682                  # is the only reliable way to fix this.
1683                  if (empty($lastmod_keepalive))
1684                      header('Connection: close');
1685                  header('Content-Length: 0');
1686                  # discard all output
1687                  while (@ob_end_clean());
1688                  exit;
1689              }
1690  
1691              if (!$exit)
1692                  return array('200', $last);
1693          }
1694      }
1695  
1696  //-------------------------------------------------------------
1697  	function set_pref($name, $val, $event='publish',  $type=0, $html='text_input', $position=0)
1698      {
1699          extract(doSlash(func_get_args()));
1700  
1701          if (!safe_row("*", 'txp_prefs', "name = '$name'") ) {
1702              return safe_insert('txp_prefs', "
1703                  name  = '$name',
1704                  val   = '$val',
1705                  event = '$event',
1706                  html  = '$html',
1707                  type  = '$type',
1708                  position = '$position',
1709                  prefs_id = 1"
1710              );
1711          } else {
1712              return safe_update('txp_prefs', "val = '$val'","name like '$name'");
1713          }
1714              return false;
1715      }
1716  
1717  // -------------------------------------------------------------
1718  	function txp_status_header($status='200 OK')
1719      {
1720          if (IS_FASTCGI)
1721              header("Status: $status");
1722          elseif ($_SERVER['SERVER_PROTOCOL'] == 'HTTP/1.0')
1723              header("HTTP/1.0 $status");
1724          else
1725              header("HTTP/1.1 $status");
1726      }
1727  
1728  // -------------------------------------------------------------
1729  	function txp_die($msg, $status='503')
1730      {
1731          // 503 status might discourage search engines from indexing or caching the error message
1732  
1733          //Make it possible to call this function as a tag, e.g. in an article <txp:txp_die status="410" />
1734          if (is_array($msg))
1735              extract(lAtts(array('msg' => '', 'status' => '503'),$msg));
1736  
1737          // Intentionally incomplete - just the ones we're likely to use
1738          $codes = array(
1739              '200' => 'OK',
1740              '301' => 'Moved Permanently',
1741              '302' => 'Found',
1742              '304' => 'Not Modified',
1743              '307' => 'Temporary Redirect',
1744              '401' => 'Unauthorized',
1745              '403' => 'Forbidden',
1746              '404' => 'Not Found',
1747              '410' => 'Gone',
1748              '414' => 'Request-URI Too Long',
1749              '500' => 'Internal Server Error',
1750              '501' => 'Not Implemented',
1751              '503' => 'Service Unavailable',
1752          );
1753  
1754          if ($status) {
1755              if (isset($codes[strval($status)]))
1756                  $status = strval($status) . ' ' . $codes[$status];
1757  
1758              txp_status_header($status);
1759          }
1760  
1761          $code = '';
1762          if ($status and $parts = @explode(' ', $status, 2)) {
1763              $code = @$parts[0];
1764          }
1765  
1766          if (@$GLOBALS['connected']) {
1767              $out = safe_field('user_html','txp_page',"name='error_".doSlash($code)."'");
1768              if (empty($out))
1769                  $out = safe_field('user_html','txp_page',"name='error_default'");
1770          }
1771  
1772          if (empty($out))
1773              $out = <<<eod
1774  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
1775          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1776  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
1777  <head>
1778     <meta http-equiv="content-type" content="text/html; charset=utf-8" />
1779     <title>Textpattern Error: <txp:error_status /></title>
1780  </head>
1781  <body>
1782  <p align="center" style="margin-top:4em"><txp:error_message /></p>
1783  </body>
1784  </html>
1785  eod;
1786  
1787          header("Content-type: text/html; charset=utf-8");
1788  
1789          if (is_callable('parse')) {
1790  
1791              $GLOBALS['txp_error_message'] = $msg;
1792              $GLOBALS['txp_error_status'] = $status;
1793              $GLOBALS['txp_error_code'] = $code;
1794  
1795              set_error_handler("tagErrorHandler");
1796              die(parse($out));
1797          }
1798          else {
1799              $out = preg_replace(array('@<txp:error_status[^>]*/>@', '@<txp:error_message[^>]*/>@'),
1800                  array($status, $msg),
1801                  $out);
1802              die($out);
1803          }
1804      }
1805  
1806  // -------------------------------------------------------------
1807  	function join_qs($q)
1808      {
1809          $qs = array();
1810          foreach ($q as $k=>$v)
1811              if ($v)
1812                  $qs[] = urlencode($k) . '=' . urlencode($v);
1813  
1814          $str = join('&amp;', $qs);
1815          return ($str ? '?'.$str : '');
1816      }
1817  
1818  // -------------------------------------------------------------
1819  
1820  	function pagelinkurl($parts, $inherit = array())
1821      {
1822          global $permlink_mode, $prefs;
1823  
1824          // $inherit can be used to add parameters to an existing url, e.g:
1825          // $url = pagelinkurl(array('pg'=>2), $pretext);
1826          $keys = array_merge($inherit, $parts);
1827  
1828          if (isset($prefs['custom_url_func'])
1829              and is_callable($prefs['custom_url_func'])
1830              and ($url = call_user_func($prefs['custom_url_func'], $keys, PAGELINKURL)) !== FALSE)
1831          {
1832              return $url;
1833          }
1834  
1835          // can't use this to link to an article
1836          if (isset($keys['id']))
1837          {
1838              unset($keys['id']);
1839          }
1840  
1841          if (@$keys['s'] == 'default')
1842          {
1843              unset($keys['s']);
1844          }
1845  
1846          if ($permlink_mode == 'messy')
1847          {
1848              return hu.'index.php'.join_qs($keys);
1849          }
1850  
1851          else
1852          {
1853              // all clean URL modes use the same schemes for list pages
1854              $url = '';
1855  
1856              if (!empty($keys['rss']))
1857              {
1858                  $url = hu.'rss/';
1859                  unset($keys['rss']);
1860                  return $url.join_qs($keys);
1861              }
1862  
1863              elseif (!empty($keys['atom']))
1864              {
1865                  $url = hu.'atom/';
1866                  unset($keys['atom']);
1867                  return $url.join_qs($keys);
1868              }
1869  
1870              elseif (!empty($keys['s']))
1871              {
1872                  $url = hu.urlencode($keys['s']).'/';
1873                  unset($keys['s']);
1874                  return $url.join_qs($keys);
1875              }
1876  
1877              elseif (!empty($keys['author']))
1878              {
1879                  $url = hu.strtolower(urlencode(gTxt('author'))).'/'.urlencode($keys['author']).'/';
1880                  unset($keys['author']);
1881                  return $url.join_qs($keys);
1882              }
1883  
1884              elseif (!empty($keys['c']))
1885              {
1886                  $url = hu.strtolower(urlencode(gTxt('category'))).'/'.urlencode($keys['c']).'/';
1887                  unset($keys['c']);
1888                  return $url.join_qs($keys);
1889              }
1890  
1891              return hu.join_qs($keys);
1892          }
1893      }
1894  
1895  // -------------------------------------------------------------
1896  	function filedownloadurl($id, $filename='')
1897      {
1898          global $permlink_mode;
1899  
1900          $filename = urlencode($filename);
1901          #FIXME: work around yet another mod_deflate problem (double compression)
1902          # http://blogs.msdn.com/wndp/archive/2006/08/21/Content-Encoding-not-equal-Content-Type.aspx
1903          if (preg_match('/gz$/i', $filename))
1904              $filename .= a;
1905          return ($permlink_mode == 'messy') ?
1906              hu.'index.php?s=file_download'.a.'id='.$id :
1907              hu.gTxt('file_download').'/'.$id.($filename ? '/'.$filename : '');
1908      }
1909  
1910  // -------------------------------------------------------------
1911  
1912  	function in_list($val, $list, $delim = ',')
1913      {
1914          $args = do_list($list, $delim);
1915  
1916          return in_array($val, $args);
1917      }
1918  
1919  // -------------------------------------------------------------
1920  
1921  	function do_list($list, $delim = ',')
1922      {
1923          return array_map('trim', explode($delim, $list));
1924      }
1925  
1926  // -------------------------------------------------------------
1927  	function doQuote($val)
1928      {
1929          return "'$val'";
1930      }
1931  
1932  // -------------------------------------------------------------
1933  	function quote_list($in)
1934      {
1935          $out = doSlash($in);
1936          return doArray($out, 'doQuote');
1937      }
1938  
1939  // -------------------------------------------------------------
1940  	function trace_add($msg)
1941      {
1942          global $production_status;
1943  
1944          if ($production_status === 'debug')
1945          {
1946              global $txptrace,$txptracelevel;
1947  
1948              $txptrace[] = str_repeat("\t", $txptracelevel).$msg;
1949          }
1950      }
1951  
1952  //-------------------------------------------------------------
1953  	function article_push() {
1954          global $thisarticle, $stack_article;
1955          $stack_article[] = @$thisarticle;
1956      }
1957  
1958  //-------------------------------------------------------------
1959  	function article_pop() {
1960          global $thisarticle, $stack_article;
1961          $thisarticle = array_pop($stack_article);
1962      }
1963  // -------------------------------------------------------------
1964  
1965  	function relative_path($path, $pfx=NULL)
1966      {
1967          if ($pfx === NULL)
1968              $pfx = dirname(txpath);
1969          return preg_replace('@^/'.preg_quote(ltrim($pfx, '/'), '@').'/?@', '', $path);
1970      }
1971  
1972  // -------------------------------------------------------------
1973  	function get_caller($num=1,$start=2)
1974      {
1975          $out = array();
1976          if (!is_callable('debug_backtrace'))
1977              return $out;
1978  
1979          $bt = debug_backtrace();
1980          for ($i=$start; $i< $num+$start; $i++) {
1981              if (!empty($bt[$i])) {
1982                  $t = '';
1983                  if (!empty($bt[$i]['file']))
1984                      $t .= relative_path($bt[$i]['file']);
1985                  if (!empty($bt[$i]['line']))
1986                      $t .= ':'.$bt[$i]['line'];
1987                  if ($t)
1988                      $t .= ' ';
1989                  if (!empty($bt[$i]['class']))
1990                      $t .= $bt[$i]['class'];
1991                  if (!empty($bt[$i]['type']))
1992                      $t .= $bt[$i]['type'];
1993                  if (!empty($bt[$i]['function'])) {
1994                      $t .= $bt[$i]['function'];
1995  
1996                  $t .= '()';
1997                  }
1998  
1999  
2000                  $out[] = $t;
2001              }
2002          }
2003          return $out;
2004      }
2005  
2006  //-------------------------------------------------------------
2007  // function name is misleading but remains for legacy reasons
2008  // this actually sets the locale
2009  	function getlocale($lang) {
2010          global $locale;
2011  
2012          if (empty($locale))
2013              $locale = @setlocale(LC_TIME, '0');
2014  
2015          // Locale identifiers vary from system to system.  The
2016          // following code will attempt to discover which identifiers
2017          // are available.  We'll need to expand these lists to
2018          // improve support.
2019          // ISO identifiers: http://www.w3.org/WAI/ER/IG/ert/iso639.htm
2020          // Windows: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_language_strings.asp
2021          $guesses = array(
2022              'ar-dz' => array('ar_DZ.UTF-8', 'ar_DZ', 'ara', 'ar', 'arabic', 'ar_DZ.ISO_8859-6'),
2023              'bg-bg' => array('bg_BG.UTF-8', 'bg_BG', 'bg', 'bul', 'bulgarian', 'bg_BG.ISO8859-5'),
2024              'ca-es' => array('ca_ES.UTF-8', 'ca_ES', 'cat', 'ca', 'catalan', 'ca_ES.ISO_8859-1'),
2025              'cs-cz' => array('cs_CZ.UTF-8', 'cs_CZ', 'ces', 'cze', 'cs', 'csy', 'czech', 'cs_CZ.cs_CZ.ISO_8859-2'),
2026              'da-dk' => array('da_DK.UTF-8', 'da_DK'),
2027              'de-de' => array('de_DE.UTF-8', 'de_DE', 'de', 'deu', 'german', 'de_DE.ISO_8859-1'),
2028              'en-gb' => array('en_GB.UTF-8', 'en_GB', 'en_UK', 'eng', 'en', 'english-uk', 'english', 'en_GB.ISO_8859-1','C'),
2029              'en-us' => array('en_US.UTF-8', 'en_US', 'english-us', 'en_US.ISO_8859-1'),
2030              'es-es' => array('es_ES.UTF-8', 'es_ES', 'esp', 'spanish', 'es_ES.ISO_8859-1'),
2031              'et-ee' => array('et_EE.UTF-8', 'et_EE'),
2032              'el-gr' => array('el_GR.UTF-8', 'el_GR', 'el', 'gre', 'greek', 'el_GR.ISO_8859-7'),
2033              'fi-fi' => array('fi_FI.UTF-8', 'fi_FI', 'fin', 'fi', 'finnish', 'fi_FI.ISO_8859-1'),
2034              'fr-fr' => array('fr_FR.UTF-8', 'fr_FR', 'fra', 'fre', 'fr', 'french', 'fr_FR.ISO_8859-1'),
2035              'gl-gz' => array('gl_GZ.UTF-8', 'gl_GZ', 'glg', 'gl', '', ''),
2036              'he_il' => array('he_IL.UTF-8', 'he_IL', 'heb', 'he', 'hebrew', 'he_IL.ISO_8859-8'),
2037              'hr-hr' => array('hr_HR.UTF-8', 'hr_HR', 'hr'),
2038              'hu-hu' => array('hu_HU.UTF-8', 'hu_HU', 'hun', 'hu', 'hungarian', 'hu_HU.ISO8859-2'),
2039              'id-id' => array('id_ID.UTF-8', 'id_ID', 'id', 'ind', 'indonesian','id_ID.ISO_8859-1'),
2040              'is-is' => array('is_IS.UTF-8', 'is_IS'),
2041              'it-it' => array('it_IT.UTF-8', 'it_IT', 'it', 'ita', 'italian', 'it_IT.ISO_8859-1'),
2042              'ja-jp' => array('ja_JP.UTF-8', 'ja_JP', 'ja', 'jpn', 'japanese', 'ja_JP.ISO_8859-1'),
2043              'ko-kr' => array('ko_KR.UTF-8', 'ko_KR', 'ko', 'kor', 'korean'),
2044              'lv-lv' => array('lv_LV.UTF-8', 'lv_LV', 'lv', 'lav'),
2045              'nl-nl' => array('nl_NL.UTF-8', 'nl_NL', 'dut', 'nla', 'nl', 'nld', 'dutch', 'nl_NL.ISO_8859-1'),
2046              'no-no' => array('no_NO.UTF-8', 'no_NO', 'no', 'nor', 'norwegian', 'no_NO.ISO_8859-1'),
2047              'pl-pl' => array('pl_PL.UTF-8', 'pl_PL', 'pl', 'pol', 'polish', ''),
2048              'pt-br' => array('pt_BR.UTF-8', 'pt_BR', 'pt', 'ptb', 'portuguese-brazil', ''),
2049              'pt-pt' => array('pt_PT.UTF-8', 'pt_PT', 'por', 'portuguese', 'pt_PT.ISO_8859-1'),
2050              'ro-ro' => array('ro_RO.UTF-8', 'ro_RO', 'ron', 'rum', 'ro', 'romanian', 'ro_RO.ISO8859-2'),
2051              'ru-ru' => array('ru_RU.UTF-8', 'ru_RU', 'ru', 'rus', 'russian', 'ru_RU.ISO8859-5'),
2052              'sk-sk' => array('sk_SK.UTF-8', 'sk_SK', 'sk', 'slo', 'slk', 'sky', 'slovak', 'sk_SK.ISO_8859-1'),
2053              'sv-se' => array('sv_SE.UTF-8', 'sv_SE', 'sv', 'swe', 'sve', 'swedish', 'sv_SE.ISO_8859-1'),
2054              'th-th' => array('th_TH.UTF-8', 'th_TH', 'th', 'tha', 'thai', 'th_TH.ISO_8859-11'),
2055              'uk-ua' => array('uk_UA.UTF-8', 'uk_UA', 'uk', 'ukr'),
2056              'vi-vn' => array('vi_VN.UTF-8', 'vi_VN', 'vi', 'vie'),
2057              'zh-cn' => array('zh_CN.UTF-8', 'zh_CN'),
2058              'zh-tw' => array('zh_TW.UTF-8', 'zh_TW'),
2059          );
2060  
2061          if (!empty($guesses[$lang])) {
2062              $l = @setlocale(LC_TIME, $guesses[$lang]);
2063              if ($l !== false)
2064                  $locale = $l;
2065          }
2066          @setlocale(LC_TIME, $locale);
2067  
2068          return $locale;
2069      }
2070  
2071  //-------------------------------------------------------------
2072  	function assert_article() {
2073          global $thisarticle;
2074          if (empty($thisarticle))
2075              trigger_error(gTxt('error_article_context'));
2076      }
2077  
2078  //-------------------------------------------------------------
2079  	function assert_comment() {
2080          global $thiscomment;
2081          if (empty($thiscomment))
2082              trigger_error(gTxt('error_comment_context'));
2083      }
2084  
2085  //-------------------------------------------------------------
2086  	function assert_file() {
2087          global $thisfile;
2088          if (empty($thisfile))
2089              trigger_error(gTxt('error_file_context'));
2090      }
2091  
2092  //-------------------------------------------------------------
2093  	function assert_link() {
2094          global $thislink;
2095          if (empty($thislink))
2096              trigger_error(gTxt('error_link_context'));
2097      }
2098  
2099  //-------------------------------------------------------------
2100  	function assert_section() {
2101          global $thissection;
2102          if (empty($thissection))
2103              trigger_error(gTxt('error_section_context'));
2104      }
2105  
2106  //-------------------------------------------------------------
2107  	function assert_category() {
2108          global $thiscategory;
2109          if (empty($thiscategory))
2110              trigger_error(gTxt('error_category_context'));
2111      }
2112  
2113  //-------------------------------------------------------------
2114  	function assert_int($myvar) {
2115          global $production_status;
2116  
2117          if (is_numeric($myvar) and $myvar == intval($myvar)) {
2118              return (int) $myvar;
2119          }
2120  
2121          if (($production_status == 'debug') || (txpinterface == 'admin'))
2122          {
2123              trigger_error("<pre>Error: '".htmlspecialchars($myvar)."' is not an integer</pre>".
2124                  n.'<pre style="padding-left: 2em;" class="backtrace"><code>'.
2125                  htmlspecialchars(join(n, get_caller(5,1))).'</code></pre>', E_USER_ERROR);
2126          }
2127          else
2128          {
2129              trigger_error("'".htmlspecialchars($myvar)."' is not an integer.", E_USER_ERROR);
2130          }
2131  
2132          return false;
2133      }
2134  
2135  //-------------------------------------------------------------
2136  	function replace_relative_urls($html, $permalink='') {
2137  
2138          global $siteurl;
2139  
2140          # urls like "/foo/bar" - relative to the domain
2141          if (serverSet('HTTP_HOST')) {
2142              $html = preg_replace('@(<a[^>]+href=")/@','$1'.PROTOCOL.serverSet('HTTP_HOST').'/',$html);
2143              $html = preg_replace('@(<img[^>]+src=")/@','$1'.PROTOCOL.serverSet('HTTP_HOST').'/',$html);
2144          }
2145          # "foo/bar" - relative to the textpattern root
2146          # leave "http:", "mailto:" et al. as absolute urls
2147          $html = preg_replace('@(<a[^>]+href=")(?!\w+:)@','$1'.PROTOCOL.$siteurl.'/$2',$html);
2148          $html = preg_replace('@(<img[^>]+src=")(?!\w+:)@','$1'.PROTOCOL.$siteurl.'/$2',$html);
2149  
2150          if ($permalink)
2151              $html = preg_replace("/href=\\\"#(.*)\"/","href=\"".$permalink."#\\1\"",$html);
2152          return ($html);
2153      }
2154  
2155  //-------------------------------------------------------------
2156  	function show_clean_test($pretext) {
2157          echo md5(@$pretext['req']).n;
2158          if (serverSet('SERVER_ADDR') == serverSet('REMOTE_ADDR'))
2159          {
2160              var_export($pretext);
2161          }
2162      }
2163  
2164  //-------------------------------------------------------------
2165  
2166  	function pager($total, $limit, $page) {
2167          $total = (int) $total;
2168          $limit = (int) $limit;
2169          $page = (int) $page;
2170  
2171          $num_pages = ceil($total / $limit);
2172  
2173          $page = min(max($page, 1), $num_pages);
2174  
2175          $offset = max(($page - 1) * $limit, 0);
2176  
2177          return array($page, $offset, $num_pages);
2178      }
2179  
2180  //-------------------------------------------------------------
2181  // word-wrap a string using a zero width space
2182  	function soft_wrap($text, $width, $break='&#8203;')
2183      {
2184          $wbr = chr(226).chr(128).chr(139);
2185          $words = explode(' ', $text);
2186          foreach($words as $wordnr => $word) {
2187              $word = preg_replace('|([,./\\>?!:;@-]+)(?=.)|', '$1 ', $word);
2188              $parts = explode(' ', $word);
2189              foreach($parts as $partnr => $part) {
2190                  $len = strlen(utf8_decode($part));
2191                  if (!$len) continue;
2192                  $parts[$partnr] = preg_replace('/(.{'.ceil($len/ceil($len/$width)).'})(?=.)/u', '$1'.$wbr, $part);
2193              }
2194              $words[$wordnr] = join($wbr, $parts);
2195          }
2196          return join(' ', $words);
2197      }
2198  
2199  //-------------------------------------------------------------
2200  	function strip_prefix($str, $pfx) {
2201          return preg_replace('/^'.preg_quote($pfx, '/').'/', '', $str);
2202      }
2203  ?>


Generated: Thu May 21 23:03:01 2009 Cross-referenced by PHPXref 0.7