[ Index ]
 

Code source de Typo3 4.1.3

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/t3lib/ -> class.t3lib_div.php (source)

   1  <?php
   2  /***************************************************************
   3  *  Copyright notice
   4  *
   5  *  (c) 1999-2007 Kasper Skaarhoj (kasperYYYY@typo3.com)
   6  *  All rights reserved
   7  *
   8  *  This script is part of the TYPO3 project. The TYPO3 project is
   9  *  free software; you can redistribute it and/or modify
  10  *  it under the terms of the GNU General Public License as published by
  11  *  the Free Software Foundation; either version 2 of the License, or
  12  *  (at your option) any later version.
  13  *
  14  *  The GNU General Public License can be found at
  15  *  http://www.gnu.org/copyleft/gpl.html.
  16  *  A copy is found in the textfile GPL.txt and important notices to the license
  17  *  from the author is found in LICENSE.txt distributed with these scripts.
  18  *
  19  *
  20  *  This script is distributed in the hope that it will be useful,
  21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23  *  GNU General Public License for more details.
  24  *
  25  *  This copyright notice MUST APPEAR in all copies of the script!
  26  ***************************************************************/
  27  /**
  28   * Contains the reknown class "t3lib_div" with general purpose functions
  29   *
  30   * $Id: class.t3lib_div.php 2420 2007-07-16 12:28:45Z masi $
  31   * Revised for TYPO3 3.6 July/2003 by Kasper Skaarhoj
  32   * XHTML compliant
  33   * Usage counts are based on search 22/2 2003 through whole source including tslib/
  34   *
  35   * @author    Kasper Skaarhoj <kasperYYYY@typo3.com>
  36   */
  37  /**
  38   * [CLASS/FUNCTION INDEX of SCRIPT]
  39   *
  40   *
  41   *
  42   *  232: class t3lib_div
  43   *
  44   *              SECTION: GET/POST Variables
  45   *  262:     function _GP($var)
  46   *  280:     function _GET($var=NULL)
  47   *  297:     function _POST($var=NULL)
  48   *  313:     function _GETset($inputGet,$key='')
  49   *  336:     function GPvar($var,$strip=0)
  50   *  353:     function GParrayMerged($var)
  51   *
  52   *              SECTION: IMAGE FUNCTIONS
  53   *  397:     function gif_compress($theFile, $type)
  54   *  425:     function png_to_gif_by_imagemagick($theFile)
  55   *  450:     function read_png_gif($theFile,$output_png=0)
  56   *
  57   *              SECTION: STRING FUNCTIONS
  58   *  499:     function fixed_lgd($string,$origChars,$preStr='...')
  59   *  524:     function fixed_lgd_pre($string,$chars)
  60   *  538:     function fixed_lgd_cs($string,$chars)
  61   *  555:     function breakTextForEmail($str,$implChar="\n",$charWidth=76)
  62   *  574:     function breakLinesForEmail($str,$implChar="\n",$charWidth=76)
  63   *  610:     function cmpIP($baseIP, $list)
  64   *  626:     function cmpIPv4($baseIP, $list)
  65   *  668:     function cmpIPv6($baseIP, $list)
  66   *  711:     function IPv6Hex2Bin ($hex)
  67   *  726:     function normalizeIPv6($address)
  68   *  782:     function validIPv6($ip)
  69   *  805:     function cmpFQDN($baseIP, $list)
  70   *  835:     function inList($list,$item)
  71   *  847:     function rmFromList($element,$list)
  72   *  863:     function expandList($list)
  73   *  894:     function intInRange($theInt,$min,$max=2000000000,$zeroValue=0)
  74   *  910:     function intval_positive($theInt)
  75   *  923:     function int_from_ver($verNumberStr)
  76   *  934:     function compat_version($verNumberStr)
  77   *  952:     function md5int($str)
  78   *  965:     function shortMD5($input, $len=10)
  79   *  978:     function uniqueList($in_list, $secondParameter=NULL)
  80   *  992:     function split_fileref($fileref)
  81   * 1030:     function dirname($path)
  82   * 1046:     function modifyHTMLColor($color,$R,$G,$B)
  83   * 1066:     function modifyHTMLColorAll($color,$all)
  84   * 1077:     function rm_endcomma($string)
  85   * 1090:     function danish_strtoupper($string)
  86   * 1105:     function convUmlauts($str)
  87   * 1118:     function testInt($var)
  88   * 1130:     function isFirstPartOfStr($str,$partStr)
  89   * 1146:     function formatSize($sizeInBytes,$labels='')
  90   * 1181:     function convertMicrotime($microtime)
  91   * 1195:     function splitCalc($string,$operators)
  92   * 1217:     function calcPriority($string)
  93   * 1258:     function calcParenthesis($string)
  94   * 1284:     function htmlspecialchars_decode($value)
  95   * 1299:     function deHSCentities($str)
  96   * 1312:     function slashJS($string,$extended=0,$char="'")
  97   * 1325:     function rawUrlEncodeJS($str)
  98   * 1337:     function rawUrlEncodeFP($str)
  99   * 1348:     function validEmail($email)
 100   * 1363:     function formatForTextarea($content)
 101   *
 102   *              SECTION: ARRAY FUNCTIONS
 103   * 1394:     function inArray($in_array,$item)
 104   * 1411:     function intExplode($delim, $string)
 105   * 1430:     function revExplode($delim, $string, $count=0)
 106   * 1450:     function trimExplode($delim, $string, $onlyNonEmptyValues=0)
 107   * 1472:     function uniqueArray($valueArray)
 108   * 1484:     function removeArrayEntryByValue($array,$cmpValue)
 109   * 1513:     function implodeArrayForUrl($name,$theArray,$str='',$skipBlank=0,$rawurlencodeParamName=0)
 110   * 1538:     function explodeUrl2Array($string,$multidim=FALSE)
 111   * 1564:     function compileSelectedGetVarsFromArray($varList,$getArray,$GPvarAlt=1)
 112   * 1587:     function addSlashesOnArray(&$theArray)
 113   * 1611:     function stripSlashesOnArray(&$theArray)
 114   * 1633:     function slashArray($arr,$cmd)
 115   * 1650:     function array_merge_recursive_overrule($arr0,$arr1,$notAddKeys=0,$includeEmtpyValues=true)
 116   * 1683:     function array_merge($arr1,$arr2)
 117   * 1696:     function csvValues($row,$delim=',',$quote='"')
 118   *
 119   *              SECTION: HTML/XML PROCESSING
 120   * 1738:     function get_tag_attributes($tag)
 121   * 1775:     function split_tag_attributes($tag)
 122   * 1809:     function implodeAttributes($arr,$xhtmlSafe=FALSE,$dontOmitBlankAttribs=FALSE)
 123   * 1836:     function implodeParams($arr,$xhtmlSafe=FALSE,$dontOmitBlankAttribs=FALSE)
 124   * 1851:     function wrapJS($string, $linebreak=TRUE)
 125   * 1882:     function xml2tree($string,$depth=999)
 126   * 1969:     function array2xml($array,$NSprefix='',$level=0,$docTag='phparray',$spaceInd=0, $options=array(),$stackData=array())
 127   * 2088:     function xml2array($string,$NSprefix='',$reportDocTag=FALSE)
 128   * 2198:     function xmlRecompileFromStructValArray($vals)
 129   * 2242:     function xmlGetHeaderAttribs($xmlData)
 130   *
 131   *              SECTION: FILES FUNCTIONS
 132   * 2275:     function getURL($url, $includeHeader=0)
 133   * 2342:     function writeFile($file,$content)
 134   * 2367:     function fixPermissions($file)
 135   * 2384:     function writeFileToTypo3tempDir($filepath,$content)
 136   * 2427:     function mkdir($theNewFolder)
 137   * 2446:     function mkdir_deep($destination,$deepDir)
 138   * 2468:     function get_dirs($path)
 139   * 2493:     function getFilesInDir($path,$extensionList='',$prependPath=0,$order='')
 140   * 2547:     function getAllFilesAndFoldersInPath($fileArr,$path,$extList='',$regDirs=0,$recursivityLevels=99)
 141   * 2570:     function removePrefixPathFromList($fileArr,$prefixToRemove)
 142   * 2586:     function fixWindowsFilePath($theFile)
 143   * 2598:     function resolveBackPath($pathStr)
 144   * 2626:     function locationHeaderUrl($path)
 145   *
 146   *              SECTION: DEBUG helper FUNCTIONS
 147   * 2666:     function debug_ordvalue($string,$characters=100)
 148   * 2683:     function view_array($array_in)
 149   * 2711:     function print_array($array_in)
 150   * 2726:     function debug($var="",$brOrHeader=0)
 151   * 2757:     function debug_trail()
 152   * 2779:     function debugRows($rows,$header='')
 153   *
 154   *              SECTION: SYSTEM INFORMATION
 155   * 2857:     function getThisUrl()
 156   * 2873:     function linkThisScript($getParams=array())
 157   * 2897:     function linkThisUrl($url,$getParams=array())
 158   * 2920:     function getIndpEnv($getEnvName)
 159   * 3113:     function milliseconds()
 160   * 3125:     function clientInfo($useragent='')
 161   *
 162   *              SECTION: TYPO3 SPECIFIC FUNCTIONS
 163   * 3212:     function getFileAbsFileName($filename,$onlyRelative=1,$relToTYPO3_mainDir=0)
 164   * 3248:     function validPathStr($theFile)
 165   * 3259:     function isAbsPath($path)
 166   * 3270:     function isAllowedAbsPath($path)
 167   * 3287:     function verifyFilenameAgainstDenyPattern($filename)
 168   * 3305:     function upload_copy_move($source,$destination)
 169   * 3331:     function upload_to_tempfile($uploadedFileName)
 170   * 3349:     function unlink_tempfile($uploadedTempFileName)
 171   * 3365:     function tempnam($filePrefix)
 172   * 3379:     function stdAuthCode($uid_or_record,$fields='',$codeLength=8)
 173   * 3410:     function cHashParams($addQueryParams)
 174   * 3433:     function hideIfNotTranslated($l18n_cfg_fieldValue)
 175   * 3448:     function readLLfile($fileRef,$langKey)
 176   * 3472:     function readLLXMLfile($fileRef,$langKey)
 177   * 3589:     function llXmlAutoFileName($fileRef,$language)
 178   * 3633:     function loadTCA($table)
 179   * 3653:     function resolveSheetDefInDS($dataStructArray,$sheet='sDEF')
 180   * 3686:     function resolveAllSheetsInDS($dataStructArray)
 181   * 3715:     function callUserFunction($funcName,&$params,&$ref,$checkPrefix='user_',$silent=0)
 182   * 3813:     function &getUserObj($classRef,$checkPrefix='user_',$silent=0)
 183   * 3871:     function &makeInstance($className)
 184   * 3883:     function makeInstanceClassName($className)
 185   * 3897:     function &makeInstanceService($serviceType, $serviceSubType='', $excludeServiceKeys=array())
 186   * 3961:     function plainMailEncoded($email,$subject,$message,$headers='',$enc='',$charset='',$dontEncodeHeader=false)
 187   * 4031:     function quoted_printable($string,$maxlen=76)
 188   * 4078:     function encodeHeader($line,$enc='',$charset='ISO-8859-1')
 189   * 4121:     function substUrlsInPlainText($message,$urlmode='76',$index_script_url='')
 190   * 4155:     function makeRedirectUrl($inUrl,$l=0,$index_script_url='')
 191   * 4182:     function freetypeDpiComp($font_size)
 192   * 4194:     function initSysLog()
 193   * 4251:     function sysLog($msg, $extKey, $severity=0)
 194   * 4334:     function devLog($msg, $extKey, $severity=0, $dataVar=FALSE)
 195   * 4355:     function arrayToLogString($arr, $valueList=array(), $valueLength=20)
 196   * 4378:     function imageMagickCommand($command, $parameters, $path='')
 197   * 4425:     function unQuoteFilenames($parameters,$unQuote=FALSE)
 198   * 4459:     function quoteJSvalue($value, $inScriptTags = false)
 199   *
 200   * TOTAL FUNCTIONS: 138
 201   * (This index is automatically created/updated by the extension "extdeveval")
 202   *
 203   */
 204  
 205  
 206  
 207  
 208  
 209  
 210  
 211  
 212  
 213  
 214  
 215  
 216  /**
 217   * The legendary "t3lib_div" class - Miscellaneous functions for general purpose.
 218   * Most of the functions does not relate specifically to TYPO3
 219   * However a section of functions requires certain TYPO3 features available
 220   * See comments in the source.
 221   * You are encouraged to use this library in your own scripts!
 222   *
 223   * USE:
 224   * The class is intended to be used without creating an instance of it.
 225   * So: Don't instantiate - call functions with "t3lib_div::" prefixed the function name.
 226   * So use t3lib_div::[method-name] to refer to the functions, eg. 't3lib_div::milliseconds()'
 227   *
 228   * @author    Kasper Skaarhoj <kasperYYYY@typo3.com>
 229   * @package TYPO3
 230   * @subpackage t3lib
 231   */
 232  class t3lib_div {
 233  
 234  
 235  
 236  
 237  
 238      /*************************
 239       *
 240       * GET/POST Variables
 241       *
 242       * Background:
 243       * Input GET/POST variables in PHP may have their quotes escaped with "\" or not depending on configuration.
 244       * TYPO3 has always converted quotes to BE escaped if the configuration told that they would not be so.
 245       * But the clean solution is that quotes are never escaped and that is what the functions below offers.
 246       * Eventually TYPO3 should provide this in the global space as well.
 247       * In the transitional phase (or forever..?) we need to encourage EVERY to read and write GET/POST vars through the API functions below.
 248       *
 249       *************************/
 250  
 251      /**
 252       * Returns the 'GLOBAL' value of incoming data from POST or GET, with priority to POST (that is equalent to 'GP' order)
 253       * Strips slashes from all output, both strings and arrays.
 254       * This function substitutes t3lib_div::GPvar()
 255       * To enhancement security in your scripts, please consider using t3lib_div::_GET or t3lib_div::_POST if you already know by which method your data is arriving to the scripts!
 256       * Usage: 537
 257       *
 258       * @param    string        GET/POST var to return
 259       * @return    mixed        POST var named $var and if not set, the GET var of the same name.
 260       * @see GPvar()
 261       */
 262  	function _GP($var)    {
 263          if(empty($var)) return;
 264          $value = isset($_POST[$var]) ? $_POST[$var] : $_GET[$var];
 265          if (isset($value))    {
 266              if (is_array($value))    { t3lib_div::stripSlashesOnArray($value); } else { $value = stripslashes($value); }
 267          }
 268          return $value;
 269      }
 270  
 271      /**
 272       * Returns the global GET array (or value from) normalized to contain un-escaped values.
 273       * ALWAYS use this API function to acquire the GET variables!
 274       * Usage: 27
 275       *
 276       * @param    string        Optional pointer to value in GET array (basically name of GET var)
 277       * @return    mixed        If $var is set it returns the value of $_GET[$var]. If $var is NULL (default), returns $_GET itself. In any case *slashes are stipped from the output!*
 278       * @see _POST(), _GP(), _GETset()
 279       */
 280  	function _GET($var=NULL)    {
 281          $value = ($var === NULL) ? $_GET : (empty($var) ? NULL : $_GET[$var]);
 282          if (isset($value))    {    // Removes slashes since TYPO3 has added them regardless of magic_quotes setting.
 283              if (is_array($value))    { t3lib_div::stripSlashesOnArray($value); } else { $value = stripslashes($value); }
 284          }
 285          return $value;
 286      }
 287  
 288      /**
 289       * Returns the global POST array (or value from) normalized to contain un-escaped values.
 290       * ALWAYS use this API function to acquire the POST variables!
 291       * Usage: 41
 292       *
 293       * @param    string        Optional pointer to value in POST array (basically name of POST var)
 294       * @return    mixed        If $var is set it returns the value of $_POST[$var]. If $var is NULL (default), returns $_POST itself. In any case *slashes are stipped from the output!*
 295       * @see _GET(), _GP()
 296       */
 297  	function _POST($var=NULL)    {
 298          $value = ($var === NULL) ? $_POST : (empty($var) ? NULL : $_POST[$var]);
 299          if (isset($value))    {    // Removes slashes since TYPO3 has added them regardless of magic_quotes setting.
 300              if (is_array($value))    { t3lib_div::stripSlashesOnArray($value); } else { $value = stripslashes($value); }
 301          }
 302          return $value;
 303      }
 304  
 305      /**
 306       * Writes input value to $_GET
 307       * Usage: 2
 308       *
 309       * @param    array        Array to write to $_GET. Values should NOT be escaped at input time (but will be escaped before writing according to TYPO3 standards).
 310       * @param    string        Alternative key; If set, this will not set the WHOLE GET array, but only the key in it specified by this value!
 311       * @return    void
 312       */
 313  	function _GETset($inputGet,$key='')    {
 314              // ADDS slashes since TYPO3 standard currently is that slashes MUST be applied (regardless of magic_quotes setting).
 315          if (strcmp($key,''))    {
 316              if (is_array($inputGet))    { t3lib_div::addSlashesOnArray($inputGet); } else { $inputGet = addslashes($inputGet); }
 317              $GLOBALS['HTTP_GET_VARS'][$key] = $_GET[$key] = $inputGet;
 318          } elseif (is_array($inputGet)){
 319              t3lib_div::addSlashesOnArray($inputGet);
 320              $GLOBALS['HTTP_GET_VARS'] = $_GET = $inputGet;
 321          }
 322      }
 323  
 324      /**
 325       * GET/POST variable
 326       * Returns the 'GLOBAL' value of incoming data from POST or GET, with priority to POST (that is equalent to 'GP' order)
 327       * Strips slashes of string-outputs, but not arrays UNLESS $strip is set. If $strip is set all output will have escaped characters unescaped.
 328       * Usage: 2
 329       *
 330       * @param    string        GET/POST var to return
 331       * @param    boolean        If set, values are stripped of return values that are *arrays!* - string/integer values returned are always strip-slashed()
 332       * @return    mixed        POST var named $var and if not set, the GET var of the same name.
 333       * @deprecated        Use t3lib_div::_GP instead (ALWAYS delivers a value with un-escaped values!)
 334       * @see _GP()
 335       */
 336  	function GPvar($var,$strip=0)    {
 337          if(empty($var)) return;
 338          $value = isset($_POST[$var]) ? $_POST[$var] : $_GET[$var];
 339          if (isset($value) && is_string($value))    { $value = stripslashes($value); }    // Originally check '&& get_magic_quotes_gpc() ' but the values of $_GET are always slashed regardless of get_magic_quotes_gpc() because HTTP_POST/GET_VARS are run through addSlashesOnArray in the very beginning of index_ts.php eg.
 340          if ($strip && isset($value) && is_array($value)) { t3lib_div::stripSlashesOnArray($value); }
 341          return $value;
 342      }
 343  
 344      /**
 345       * Returns the GET/POST global arrays merged with POST taking precedence.
 346       * Usage: 1
 347       *
 348       * @param    string        Key (variable name) from GET or POST vars
 349       * @return    array        Returns the GET vars merged recursively onto the POST vars.
 350       * @ignore
 351       * @deprecated
 352       */
 353  	function GParrayMerged($var)    {
 354          $postA = is_array($_POST[$var]) ? $_POST[$var] : array();
 355          $getA = is_array($_GET[$var]) ? $_GET[$var] : array();
 356          $mergedA = t3lib_div::array_merge_recursive_overrule($getA,$postA);
 357          t3lib_div::stripSlashesOnArray($mergedA);
 358          return $mergedA;
 359      }
 360  
 361  
 362  
 363  
 364  
 365  
 366  
 367  
 368  
 369  
 370      /*************************
 371       *
 372       * IMAGE FUNCTIONS
 373       *
 374       *************************/
 375  
 376  
 377      /**
 378       * Compressing a GIF file if not already LZW compressed
 379       * This function is a workaround for the fact that ImageMagick and/or GD does not compress GIF-files to their minimun size (that is RLE or no compression used)
 380       *
 381       *         The function takes a file-reference, $theFile, and saves it again through GD or ImageMagick in order to compress the file
 382       *         GIF:
 383       *         If $type is not set, the compression is done with ImageMagick (provided that $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw'] is pointing to the path of a lzw-enabled version of 'convert') else with GD (should be RLE-enabled!)
 384       *         If $type is set to either 'IM' or 'GD' the compression is done with ImageMagick and GD respectively
 385       *         PNG:
 386       *         No changes.
 387       *
 388       *         $theFile is expected to be a valid GIF-file!
 389       *         The function returns a code for the operation.
 390       * Usage: 9
 391       *
 392       * @param    string        Filepath
 393       * @param    string        See description of function
 394       * @return    string        Returns "GD" if GD was used, otherwise "IM" if ImageMagick was used. If nothing done at all, it returns empty string.
 395       * @internal
 396       */
 397  	function gif_compress($theFile, $type)    {
 398          $gfxConf = $GLOBALS['TYPO3_CONF_VARS']['GFX'];
 399          $returnCode='';
 400          if ($gfxConf['gif_compress'] && strtolower(substr($theFile,-4,4))=='.gif')    {    // GIF...
 401              if (($type=='IM' || !$type) && $gfxConf['im'] && $gfxConf['im_path_lzw'])    {    // IM
 402                  $cmd = t3lib_div::imageMagickCommand('convert', '"'.$theFile.'" "'.$theFile.'"', $gfxConf['im_path_lzw']);
 403                  exec($cmd);
 404  
 405                  $returnCode='IM';
 406              } elseif (($type=='GD' || !$type) && $gfxConf['gdlib'] && !$gfxConf['gdlib_png'])    {    // GD
 407                  $tempImage = imageCreateFromGif($theFile);
 408                  imageGif($tempImage, $theFile);
 409                  imageDestroy($tempImage);
 410                  $returnCode='GD';
 411              }
 412          }
 413          return $returnCode;
 414      }
 415  
 416      /**
 417       * Converts a png file to gif
 418       * This converts a png file to gif IF the FLAG $GLOBALS['TYPO3_CONF_VARS']['FE']['png_to_gif'] is set true.
 419       * Usage: 5
 420       *
 421       * @param    string        $theFile    the filename with path
 422       * @return    string        new filename
 423       * @internal
 424       */
 425  	function png_to_gif_by_imagemagick($theFile)    {
 426          if ($GLOBALS['TYPO3_CONF_VARS']['FE']['png_to_gif']
 427              && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im']
 428              && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw']
 429              && strtolower(substr($theFile,-4,4))=='.png'
 430              && @is_file($theFile))    {    // IM
 431                  $newFile = substr($theFile,0,-4).'.gif';
 432                  $cmd = t3lib_div::imageMagickCommand('convert', '"'.$theFile.'" "'.$newFile.'"', $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw']);
 433                  exec($cmd);
 434                  $theFile = $newFile;
 435                      // unlink old file?? May be bad idea bacause TYPO3 would then recreate the file every time as TYPO3 thinks the file is not generated because it's missing!! So do not unlink $theFile here!!
 436          }
 437          return $theFile;
 438      }
 439  
 440      /**
 441       * Returns filename of the png/gif version of the input file (which can be png or gif).
 442       * If input file type does not match the wanted output type a conversion is made and temp-filename returned.
 443       * Usage: 2
 444       *
 445       * @param    string        Filepath of image file
 446       * @param    boolean        If set, then input file is converted to PNG, otherwise to GIF
 447       * @return    string        If the new image file exists, it's filepath is returned
 448       * @internal
 449       */
 450  	function read_png_gif($theFile,$output_png=0)    {
 451          if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['im'] && @is_file($theFile))    {
 452              $ext = strtolower(substr($theFile,-4,4));
 453              if (
 454                      ((string)$ext=='.png' && $output_png)    ||
 455                      ((string)$ext=='.gif' && !$output_png)
 456                  )    {
 457                  return $theFile;
 458              } else {
 459                  $newFile = PATH_site.'typo3temp/readPG_'.md5($theFile.'|'.filemtime($theFile)).($output_png?'.png':'.gif');
 460                  exec($GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path'].'convert "'.$theFile.'" "'.$newFile.'"');
 461                  if (@is_file($newFile))    return $newFile;
 462              }
 463          }
 464      }
 465  
 466  
 467  
 468  
 469  
 470  
 471  
 472  
 473  
 474  
 475  
 476  
 477  
 478  
 479  
 480      /*************************
 481       *
 482       * STRING FUNCTIONS
 483       *
 484       *************************/
 485  
 486      /**
 487       * Truncate string
 488       * Returns a new string of max. $chars length.
 489       * If the string is longer, it will be truncated and appended with '...'.
 490       * Usage: 39
 491       *
 492       * @param    string        string to truncate
 493       * @param    integer        must be an integer with an absolute value of at least 4. if negative the string is cropped from the right end.
 494       * @param    string        String to append to the output if it is truncated, default is '...'
 495       * @return    string        new string
 496       * @deprecated        Works ONLY for single-byte charsets! USE t3lib_div::fixed_lgd_cs() instead
 497       * @see fixed_lgd_pre()
 498       */
 499  	function fixed_lgd($string,$origChars,$preStr='...')    {
 500          $chars = abs($origChars);
 501          if ($chars >= 4)    {
 502              if(strlen($string)>$chars)  {
 503                  return $origChars < 0 ?
 504                      $preStr.trim(substr($string, -($chars-3))) :
 505                      trim(substr($string, 0, $chars-3)).$preStr;
 506              }
 507          }
 508          return $string;
 509      }
 510  
 511      /**
 512       * Truncate string
 513       * Returns a new string of max. $chars length.
 514       * If the string is longer, it will be truncated and prepended with '...'.
 515       * This works like fixed_lgd, but is truncated in the start of the string instead of the end
 516       * Usage: 6
 517       *
 518       * @param    string        string to truncate
 519       * @param    integer        must be an integer of at least 4
 520       * @return    string        new string
 521       * @deprecated        Use either fixed_lgd() or fixed_lgd_cs() (with negative input value for $chars)
 522       * @see fixed_lgd()
 523       */
 524  	function fixed_lgd_pre($string,$chars)    {
 525          return strrev(t3lib_div::fixed_lgd(strrev($string),$chars));
 526      }
 527  
 528      /**
 529       * Truncates a string with appended/prepended "..." and takes backend character set into consideration
 530       * Use only from backend!
 531       * Usage: 75
 532       *
 533       * @param    string        string to truncate
 534       * @param    integer        must be an integer with an absolute value of at least 4. if negative the string is cropped from the right end.
 535       * @return    string        New string
 536       * @see fixed_lgd()
 537       */
 538  	function fixed_lgd_cs($string,$chars)    {
 539          if (is_object($GLOBALS['LANG']))    {
 540              return $GLOBALS['LANG']->csConvObj->crop($GLOBALS['LANG']->charSet,$string,$chars,'...');
 541          } else {
 542              return t3lib_div::fixed_lgd($string, $chars);
 543          }
 544      }
 545  
 546      /**
 547       * Breaks up the text for emails
 548       * Usage: 1
 549       *
 550       * @param    string        The string to break up
 551       * @param    string        The string to implode the broken lines with (default/typically \n)
 552       * @param    integer        The line length
 553       * @deprecated        Use PHP function wordwrap()
 554       * @return    string
 555       */
 556  	function breakTextForEmail($str,$implChar="\n",$charWidth=76)    {
 557          $lines = explode(chr(10),$str);
 558          $outArr=array();
 559          while(list(,$lStr)=each($lines))    {
 560              $outArr[] = t3lib_div::breakLinesForEmail($lStr,$implChar,$charWidth);
 561          }
 562          return implode(chr(10),$outArr);
 563      }
 564  
 565      /**
 566       * Breaks up a single line of text for emails
 567       * Usage: 5
 568       *
 569       * @param    string        The string to break up
 570       * @param    string        The string to implode the broken lines with (default/typically \n)
 571       * @param    integer        The line length
 572       * @return    string
 573       * @see breakTextForEmail()
 574       */
 575  	function breakLinesForEmail($str,$implChar="\n",$charWidth=76)    {
 576          $lines=array();
 577          $l=$charWidth;
 578          $p=0;
 579          while(strlen($str)>$p)    {
 580              $substr=substr($str,$p,$l);
 581              if (strlen($substr)==$l)    {
 582                  $count = count(explode(' ',trim(strrev($substr))));
 583                  if ($count>1)    {    // OK...
 584                      $parts = explode(' ',strrev($substr),2);
 585                      $theLine = strrev($parts[1]);
 586                  } else {
 587                      $afterParts = explode(' ',substr($str,$l+$p),2);
 588                      $theLine = $substr.$afterParts[0];
 589                  }
 590                  if (!strlen($theLine))    {break; }    // Error, because this would keep us in an endless loop.
 591              } else {
 592                  $theLine=$substr;
 593              }
 594  
 595              $lines[]=trim($theLine);
 596              $p+=strlen($theLine);
 597              if (!trim(substr($str,$p,$l)))    break;    // added...
 598          }
 599          return implode($implChar,$lines);
 600      }
 601  
 602      /**
 603       * Match IP number with list of numbers with wildcard
 604       * Dispatcher method for switching into specialised IPv4 and IPv6 methods.
 605       * Usage: 10
 606       *
 607       * @param    string        $baseIP is the current remote IP address for instance, typ. REMOTE_ADDR
 608       * @param    string        $list is a comma-list of IP-addresses to match with. *-wildcard allowed instead of number, plus leaving out parts in the IP number is accepted as wildcard (eg. 192.168.*.* equals 192.168). If list is "*" no check is done and the function returns TRUE immediately.
 609       * @return    boolean        True if an IP-mask from $list matches $baseIP
 610       */
 611  	function cmpIP($baseIP, $list)    {
 612          if ($list==='*')    return TRUE;
 613          if (strstr($baseIP, ':') && t3lib_div::validIPv6($baseIP))    {
 614              return t3lib_div::cmpIPv6($baseIP, $list);
 615          } else {
 616              return t3lib_div::cmpIPv4($baseIP, $list);
 617          }
 618      }
 619  
 620      /**
 621       * Match IPv4 number with list of numbers with wildcard
 622       *
 623       * @param    string        $baseIP is the current remote IP address for instance, typ. REMOTE_ADDR
 624       * @param    string        $list is a comma-list of IP-addresses to match with. *-wildcard allowed instead of number, plus leaving out parts in the IP number is accepted as wildcard (eg. 192.168.*.* equals 192.168)
 625       * @return    boolean        True if an IP-mask from $list matches $baseIP
 626       */
 627  	function cmpIPv4($baseIP, $list)    {
 628          $IPpartsReq = explode('.',$baseIP);
 629          if (count($IPpartsReq)==4)    {
 630              $values = t3lib_div::trimExplode(',',$list,1);
 631  
 632              foreach($values as $test)    {
 633                  list($test,$mask) = explode('/',$test);
 634  
 635                  if(intval($mask)) {
 636                          // "192.168.3.0/24"
 637                      $lnet = ip2long($test);
 638                      $lip = ip2long($baseIP);
 639                      $binnet = str_pad( decbin($lnet),32,'0','STR_PAD_LEFT');
 640                      $firstpart = substr($binnet,0,$mask);
 641                      $binip = str_pad( decbin($lip),32,'0','STR_PAD_LEFT');
 642                      $firstip = substr($binip,0,$mask);
 643                      $yes = (strcmp($firstpart,$firstip)==0);
 644                  } else {
 645                          // "192.168.*.*"
 646                      $IPparts = explode('.',$test);
 647                      $yes = 1;
 648                      reset($IPparts);
 649                      while(list($index,$val)=each($IPparts))    {
 650                          $val = trim($val);
 651                          if (strcmp($val,'*') && strcmp($IPpartsReq[$index],$val))    {
 652                              $yes=0;
 653                          }
 654                      }
 655                  }
 656                  if ($yes) return true;
 657              }
 658          }
 659          return false;
 660      }
 661  
 662      /**
 663       * Match IPv6 address with a list of IPv6 prefixes
 664       *
 665       * @param    string        $baseIP is the current remote IP address for instance
 666       * @param    string        $list is a comma-list of IPv6 prefixes, could also contain IPv4 addresses
 667       * @return    boolean        True if an baseIP matches any prefix
 668       */
 669  	function cmpIPv6($baseIP, $list)    {
 670          $success = false;    // Policy default: Deny connection
 671          $baseIP = t3lib_div::normalizeIPv6($baseIP);
 672  
 673          $values = t3lib_div::trimExplode(',',$list,1);
 674          foreach ($values as $test)    {
 675              list($test,$mask) = explode('/',$test);
 676              if (t3lib_div::validIPv6($test))    {
 677                  $test = t3lib_div::normalizeIPv6($test);
 678                  if (intval($mask))    {
 679                      switch ($mask) {    // test on /48 /64
 680                          case '48':
 681                              $testBin = substr(t3lib_div::IPv6Hex2Bin($test), 0, 48);
 682                              $baseIPBin = substr(t3lib_div::IPv6Hex2Bin($baseIP), 0, 48);
 683                              $success = strcmp($testBin, $baseIPBin)==0 ? true : false;
 684                          break;
 685                          case '64':
 686                              $testBin = substr(t3lib_div::IPv6Hex2Bin($test), 0, 64);
 687                              $baseIPBin = substr(t3lib_div::IPv6Hex2Bin($baseIP), 0, 64);
 688                              $success = strcmp($testBin, $baseIPBin)==0 ? true : false;
 689                          break;
 690                          default:
 691                              $success = false;
 692                      }
 693                  } else {
 694                      if (t3lib_div::validIPv6($test))    {    // test on full ip address 128 bits
 695                          $testBin = t3lib_div::IPv6Hex2Bin($test);
 696                          $baseIPBin = t3lib_div::IPv6Hex2Bin($baseIP);
 697                          $success = strcmp($testBin, $baseIPBin)==0 ? true : false;
 698                      }
 699                  }
 700              }
 701              if ($success) return true;
 702          }
 703          return false;
 704      }
 705  
 706      /**
 707       * [Describe function...]
 708       *
 709       * @param    [type]        $hex: ...
 710       * @return    [type]        ...
 711       */
 712  	function IPv6Hex2Bin ($hex)    {
 713          $bin = '';
 714          $hex = str_replace(':', '', $hex);    // Replace colon to nothing
 715          for ($i=0; $i<strlen($hex); $i=$i+2)    {
 716              $bin.= chr(hexdec(substr($hex, $i, 2)));
 717          }
 718          return $bin;
 719      }
 720  
 721      /**
 722       * Normalize an IPv6 address to full length
 723       *
 724       * @param    string        Given IPv6 address
 725       * @return    string        Normalized address
 726       */
 727  	function normalizeIPv6($address)    {
 728          $normalizedAddress = '';
 729          $stageOneAddress = '';
 730  
 731          $chunks = explode('::', $address);    // Count 2 if if address has hidden zero blocks
 732          if (count($chunks)==2)    {
 733              $chunksLeft = explode(':', $chunks[0]);
 734              $chunksRight = explode(':', $chunks[1]);
 735              $left = count($chunksLeft);
 736              $right = count($chunksRight);
 737  
 738                  // Special case: leading zero-only blocks count to 1, should be 0
 739              if ($left==1 && strlen($chunksLeft[0])==0)    $left=0;
 740  
 741              $hiddenBlocks = 8 - ($left + $right);
 742              $hiddenPart = '';
 743              while ($h<$hiddenBlocks)    {
 744                  $hiddenPart .= '0000:';
 745                  $h++;
 746              }
 747  
 748              if ($left == 0) {
 749                  $stageOneAddress = $hiddenPart . $chunks[1];
 750              } else {
 751                  $stageOneAddress = $chunks[0] . ':' . $hiddenPart . $chunks[1];
 752              }
 753          } else $stageOneAddress = $address;
 754  
 755              // normalize the blocks:
 756          $blocks = explode(':', $stageOneAddress);
 757          $divCounter = 0;
 758          foreach ($blocks as $block)    {
 759              $tmpBlock = '';
 760              $i = 0;
 761              $hiddenZeros = 4 - strlen($block);
 762              while ($i < $hiddenZeros)    {
 763                  $tmpBlock .= '0';
 764                  $i++;
 765              }
 766              $normalizedAddress .= $tmpBlock . $block;
 767              if ($divCounter < 7)    {
 768                  $normalizedAddress .= ':';
 769                  $divCounter++;
 770              }
 771          }
 772          return $normalizedAddress;
 773      }
 774  
 775      /**
 776       * Validate a given IP address to the IPv6 address format.
 777       *
 778       * Example for possible format:  43FB::BB3F:A0A0:0 | ::1
 779       *
 780       * @param    string        IP address to be tested
 781       * @return    boolean        True if $ip is of IPv6 format.
 782       */
 783  	function validIPv6($ip)    {
 784          $uppercaseIP = strtoupper($ip);
 785  
 786          $regex = '/^(';
 787          $regex.= '(([\dA-F]{1,4}:){7}[\dA-F]{1,4})|';
 788          $regex.= '(([\dA-F]{1,4}){1}::([\dA-F]{1,4}:){1,5}[\dA-F]{1,4})|';
 789          $regex.= '(([\dA-F]{1,4}:){2}:([\dA-F]{1,4}:){1,4}[\dA-F]{1,4})|';
 790          $regex.= '(([\dA-F]{1,4}:){3}:([\dA-F]{1,4}:){1,3}[\dA-F]{1,4})|';
 791          $regex.= '(([\dA-F]{1,4}:){4}:([\dA-F]{1,4}:){1,2}[\dA-F]{1,4})|';
 792          $regex.= '(([\dA-F]{1,4}:){5}:([\dA-F]{1,4}:){0,1}[\dA-F]{1,4})|';
 793          $regex.= '(::([\dA-F]{1,4}:){0,6}[\dA-F]{1,4})';
 794          $regex.= ')$/';
 795  
 796          return preg_match($regex, $uppercaseIP) ? true : false;
 797      }
 798  
 799      /**
 800       * Match fully qualified domain name with list of strings with wildcard
 801       *
 802       * @param    string        The current remote IP address for instance, typ. REMOTE_ADDR
 803       * @param    string        A comma-list of domain names to match with. *-wildcard allowed but cannot be part of a string, so it must match the full host name (eg. myhost.*.com => correct, myhost.*domain.com => wrong)
 804       * @return    boolean        True if a domain name mask from $list matches $baseIP
 805       */
 806  	function cmpFQDN($baseIP, $list)        {
 807          if (count(explode('.',$baseIP))==4)     {
 808              $resolvedHostName = explode('.', gethostbyaddr($baseIP));
 809              $values = t3lib_div::trimExplode(',',$list,1);
 810  
 811              foreach($values as $test)    {
 812                  $hostNameParts = explode('.',$test);
 813                  $yes = 1;
 814  
 815                  foreach($hostNameParts as $index => $val)    {
 816                      $val = trim($val);
 817                      if (strcmp($val,'*') && strcmp($resolvedHostName[$index],$val)) {
 818                          $yes=0;
 819                      }
 820                  }
 821                  if ($yes) return true;
 822              }
 823          }
 824          return false;
 825      }
 826  
 827      /**
 828       * Check for item in list
 829       * Check if an item exists in a comma-separated list of items.
 830       * Usage: 163
 831       *
 832       * @param    string        comma-separated list of items (string)
 833       * @param    string        item to check for
 834       * @return    boolean        true if $item is in $list
 835       */
 836  	function inList($list,$item)    {
 837          return strstr(','.$list.',', ','.$item.',') ? true : false;
 838      }
 839  
 840      /**
 841       * Removes an item from a comma-separated list of items.
 842       * Usage: 1
 843       *
 844       * @param    string        element to remove
 845       * @param    string        comma-separated list of items (string)
 846       * @return    string        new comma-separated list of items
 847       */
 848  	function rmFromList($element,$list)    {
 849          $items = explode(',',$list);
 850          while(list($k,$v)=each($items))    {
 851              if ($v==$element)    {unset($items[$k]);}
 852          }
 853          return implode(',',$items);
 854      }
 855  
 856      /**
 857       * Expand a comma-separated list of integers with ranges (eg 1,3-5,7 becomes 1,3,4,5,7).
 858       * Ranges are limited to 1000 values per range.
 859       *
 860       * @param    string        comma-separated list of integers with ranges (string)
 861       * @return    string        new comma-separated list of items
 862       * @author    Martin Kutschker <martin.kutschker@activesolution.at>
 863       */
 864  	function expandList($list)      {
 865          $items = explode(',',$list);
 866          $list = array();
 867          while(list(,$item)=each($items))    {
 868              $range = explode('-',$item);
 869              if (isset($range[1]))    {
 870                  $runAwayBrake = 1000;
 871                  for ($n=$range[0]; $n<=$range[1]; $n++)    {
 872                      $list[] = $n;
 873  
 874                      $runAwayBrake--;
 875                      if ($runAwayBrake<=0)    break;
 876                  }
 877              } else {
 878                  $list[] = $item;
 879              }
 880          }
 881  
 882          return implode(',',$list);
 883      }
 884  
 885      /**
 886       * Forces the integer $theInt into the boundaries of $min and $max. If the $theInt is 'false' then the $zeroValue is applied.
 887       * Usage: 224
 888       *
 889       * @param    integer        Input value
 890       * @param    integer        Lower limit
 891       * @param    integer        Higher limit
 892       * @param    integer        Default value if input is false.
 893       * @return    integer        The input value forced into the boundaries of $min and $max
 894       */
 895  	function intInRange($theInt,$min,$max=2000000000,$zeroValue=0)    {
 896          // Returns $theInt as an integer in the integerspace from $min to $max
 897          $theInt = intval($theInt);
 898          if ($zeroValue && !$theInt)    {$theInt=$zeroValue;}    // If the input value is zero after being converted to integer, zeroValue may set another default value for it.
 899          if ($theInt<$min){$theInt=$min;}
 900          if ($theInt>$max){$theInt=$max;}
 901          return $theInt;
 902      }
 903  
 904      /**
 905       * Returns the $integer if greater than zero, otherwise returns zero.
 906       * Usage: 1
 907       *
 908       * @param    integer        Integer string to process
 909       * @return    integer
 910       */
 911  	function intval_positive($theInt)    {
 912          $theInt = intval($theInt);
 913          if ($theInt<0){$theInt=0;}
 914          return $theInt;
 915      }
 916  
 917      /**
 918       * Returns an integer from a three part version number, eg '4.12.3' -> 4012003
 919       * Usage: 2
 920       *
 921       * @param    string        Version number on format x.x.x
 922       * @return    integer        Integer version of version number (where each part can count to 999)
 923       */
 924  	function int_from_ver($verNumberStr)    {
 925          $verParts = explode('.',$verNumberStr);
 926          return intval((int)$verParts[0].str_pad((int)$verParts[1],3,'0',STR_PAD_LEFT).str_pad((int)$verParts[2],3,'0',STR_PAD_LEFT));
 927      }
 928  
 929      /**
 930       * Returns true if the current TYPO3 version (or compatibility version) is compatible to the input version
 931       * Notice that this function compares branches, not versions (4.0.1 would be > 4.0.0 although they use the same compat_version)
 932       *
 933       * @param    string        Minimum branch number required (format x.y / e.g. "4.0" NOT "4.0.0"!)
 934       * @return    boolean        Returns true if this setup is compatible with the provided version number
 935       * @todo    Still needs a function to convert versions to branches
 936       */
 937  	function compat_version($verNumberStr)    {
 938          global $TYPO3_CONF_VARS;
 939          $currVersionStr = $TYPO3_CONF_VARS['SYS']['compat_version'] ? $TYPO3_CONF_VARS['SYS']['compat_version'] : TYPO3_branch;
 940  
 941          if (t3lib_div::int_from_ver($currVersionStr) < t3lib_div::int_from_ver($verNumberStr))    {
 942              return FALSE;
 943          } else {
 944              return TRUE;
 945          }
 946      }
 947  
 948      /**
 949       * Makes a positive integer hash out of the first 7 chars from the md5 hash of the input
 950       * Usage: 5
 951       *
 952       * @param    string        String to md5-hash
 953       * @return    integer        Returns 28bit integer-hash
 954       */
 955  	function md5int($str)    {
 956          return hexdec(substr(md5($str),0,7));
 957      }
 958  
 959      /**
 960       * Returns the first 10 positions of the MD5-hash        (changed from 6 to 10 recently)
 961       *
 962       * Usage: 37
 963       *
 964       * @param    string        Input string to be md5-hashed
 965       * @param    integer        The string-length of the output
 966       * @return    string        Substring of the resulting md5-hash, being $len chars long (from beginning)
 967       */
 968  	function shortMD5($input, $len=10)    {
 969          return substr(md5($input),0,$len);
 970      }
 971  
 972      /**
 973       * Takes comma-separated lists and arrays and removes all duplicates
 974       * If a value in the list is trim(empty), the value is ignored.
 975       * Usage: 16
 976       *
 977       * @param    string        Accept multiple parameters wich can be comma-separated lists of values and arrays.
 978       * @param    mixed        $secondParameter: Dummy field, which if set will show a warning!
 979       * @return    string        Returns the list without any duplicates of values, space around values are trimmed
 980       */
 981  	function uniqueList($in_list, $secondParameter=NULL)    {
 982          if (is_array($in_list))    die('t3lib_div::uniqueList() does NOT support array arguments anymore! Only string comma lists!');
 983          if (isset($secondParameter))    die('t3lib_div::uniqueList() does NOT support more than a single argument value anymore. You have specified more than one.');
 984  
 985          return implode(',',array_unique(t3lib_div::trimExplode(',',$in_list,1)));
 986      }
 987  
 988      /**
 989       * Splits a reference to a file in 5 parts
 990       * Usage: 43
 991       *
 992       * @param    string        Filename/filepath to be analysed
 993       * @return    array        Contains keys [path], [file], [filebody], [fileext], [realFileext]
 994       */
 995  	function split_fileref($fileref)    {
 996          $reg = array();
 997          if (    ereg('(.*/)(.*)$',$fileref,$reg)    )    {
 998              $info['path'] = $reg[1];
 999              $info['file'] = $reg[2];
1000          } else {
1001              $info['path'] = '';
1002              $info['file'] = $fileref;
1003          }
1004          $reg='';
1005          if (    ereg('(.*)\.([^\.]*$)',$info['file'],$reg)    )    {
1006              $info['filebody'] = $reg[1];
1007              $info['fileext'] = strtolower($reg[2]);
1008              $info['realFileext'] = $reg[2];
1009          } else {
1010              $info['filebody'] = $info['file'];
1011              $info['fileext'] = '';
1012          }
1013          reset($info);
1014          return $info;
1015      }
1016  
1017      /**
1018       * Returns the directory part of a path without trailing slash
1019       * If there is no dir-part, then an empty string is returned.
1020       * Behaviour:
1021       *
1022       * '/dir1/dir2/script.php' => '/dir1/dir2'
1023       * '/dir1/' => '/dir1'
1024       * 'dir1/script.php' => 'dir1'
1025       * 'd/script.php' => 'd'
1026       * '/script.php' => ''
1027       * '' => ''
1028       * Usage: 5
1029       *
1030       * @param    string        Directory name / path
1031       * @return    string        Processed input value. See function description.
1032       */
1033  	function dirname($path)    {
1034          $p=t3lib_div::revExplode('/',$path,2);
1035          return count($p)==2?$p[0]:'';
1036      }
1037  
1038      /**
1039       * Modifies a HTML Hex color by adding/subtracting $R,$G and $B integers
1040       * Usage: 11
1041       *
1042       * @param    string        A hexadecimal color code, #xxxxxx
1043       * @param    integer        Offset value 0-255
1044       * @param    integer        Offset value 0-255
1045       * @param    integer        Offset value 0-255
1046       * @return    string        A hexadecimal color code, #xxxxxx, modified according to input vars
1047       * @see modifyHTMLColorAll()
1048       */
1049  	function modifyHTMLColor($color,$R,$G,$B)    {
1050          // This takes a hex-color (# included!) and adds $R, $G and $B to the HTML-color (format: #xxxxxx) and returns the new color
1051          $nR = t3lib_div::intInRange(hexdec(substr($color,1,2))+$R,0,255);
1052          $nG = t3lib_div::intInRange(hexdec(substr($color,3,2))+$G,0,255);
1053          $nB = t3lib_div::intInRange(hexdec(substr($color,5,2))+$B,0,255);
1054          return '#'.
1055              substr('0'.dechex($nR),-2).
1056              substr('0'.dechex($nG),-2).
1057              substr('0'.dechex($nB),-2);
1058      }
1059  
1060      /**
1061       * Modifies a HTML Hex color by adding/subtracting $all integer from all R/G/B channels
1062       * Usage: 6
1063       *
1064       * @param    string        A hexadecimal color code, #xxxxxx
1065       * @param    integer        Offset value 0-255 for all three channels.
1066       * @return    string        A hexadecimal color code, #xxxxxx, modified according to input vars
1067       * @see modifyHTMLColor()
1068       */
1069  	function modifyHTMLColorAll($color,$all)    {
1070          return t3lib_div::modifyHTMLColor($color,$all,$all,$all);
1071      }
1072  
1073      /**
1074       * Removes comma (if present) in the end of string
1075       * Usage: 2
1076       *
1077       * @param    string        String from which the comma in the end (if any) will be removed.
1078       * @return    string
1079       */
1080  	function rm_endcomma($string)    {
1081          return ereg_replace(',$','',$string);
1082      }
1083  
1084      /**
1085       * strtoupper which converts danish (and other characters) characters as well
1086       * Usage: 0
1087       *
1088       * @param    string        String to process
1089       * @return    string
1090       * @deprecated        Use t3lib_cs::conv_case() instead or for HTML output, wrap your content in <span class="uppercase">...</span>)
1091       * @ignore
1092       */
1093  	function danish_strtoupper($string)    {
1094          $value = strtoupper($string);
1095          return strtr($value, 'áéúíâêûôîæøåäöü', 'ÁÉÚÍÄËÜÖÏÆØÅÄÖÜ');
1096      }
1097  
1098      /**
1099       * Change umlaut characters to plain ASCII with normally two character target
1100       * Only known characters will be converted, so don't expect a result for any character.
1101       *
1102       * ä => ae, Ö => Oe
1103       *
1104       * @param    string        String to convert.
1105       * @deprecated        Works only for western europe single-byte charsets! Use t3lib_cs::specCharsToASCII() instead!
1106       * @return    string
1107       */
1108  	function convUmlauts($str)    {
1109          $pat  = array (    '/ä/',    '/Ä/',    '/ö/',    '/Ö/',    '/ü/',    '/Ü/',    '/ß/',    '/å/',    '/Å/',    '/ø/',    '/Ø/',    '/æ/',    '/Æ/'    );
1110          $repl = array (    'ae',    'Ae',    'oe',    'Oe',    'ue',    'Ue',    'ss',    'aa',    'AA',    'oe',    'OE',    'ae',    'AE'    );
1111          return preg_replace($pat,$repl,$str);
1112      }
1113  
1114      /**
1115       * Tests if the input is an integer.
1116       * Usage: 77
1117       *
1118       * @param    mixed        Any input variable to test.
1119       * @return    boolean        Returns true if string is an integer
1120       */
1121  	function testInt($var)    {
1122          return !strcmp($var,intval($var));
1123      }
1124  
1125      /**
1126       * Returns true if the first part of $str matches the string $partStr
1127       * Usage: 59
1128       *
1129       * @param    string        Full string to check
1130       * @param    string        Reference string which must be found as the "first part" of the full string
1131       * @return    boolean        True if $partStr was found to be equal to the first part of $str
1132       */
1133  	function isFirstPartOfStr($str,$partStr)    {
1134          // Returns true, if the first part of a $str equals $partStr and $partStr is not ''
1135          $psLen = strlen($partStr);
1136          if ($psLen)    {
1137              return substr($str,0,$psLen)==(string)$partStr;
1138          } else return false;
1139      }
1140  
1141      /**
1142       * Formats the input integer $sizeInBytes as bytes/kilobytes/megabytes (-/K/M)
1143       * Usage: 53
1144       *
1145       * @param    integer        Number of bytes to format.
1146       * @param    string        Labels for bytes, kilo, mega and giga separated by vertical bar (|) and possibly encapsulated in "". Eg: " | K| M| G" (which is the default value)
1147       * @return    string        Formatted representation of the byte number, for output.
1148       */
1149  	function formatSize($sizeInBytes,$labels='')    {
1150  
1151              // Set labels:
1152          if (strlen($labels) == 0) {
1153              $labels = ' | K| M| G';
1154          } else {
1155              $labels = str_replace('"','',$labels);
1156          }
1157          $labelArr = explode('|',$labels);
1158  
1159              // Find size:
1160          if ($sizeInBytes>900)    {
1161              if ($sizeInBytes>900000000)    {    // GB
1162                  $val = $sizeInBytes/(1024*1024*1024);
1163                  return number_format($val, (($val<20)?1:0), '.', '').$labelArr[3];
1164              }
1165              elseif ($sizeInBytes>900000)    {    // MB
1166                  $val = $sizeInBytes/(1024*1024);
1167                  return number_format($val, (($val<20)?1:0), '.', '').$labelArr[2];
1168              } else {    // KB
1169                  $val = $sizeInBytes/(1024);
1170                  return number_format($val, (($val<20)?1:0), '.', '').$labelArr[1];
1171              }
1172          } else {    // Bytes
1173              return $sizeInBytes.$labelArr[0];
1174          }
1175      }
1176  
1177      /**
1178       * Returns microtime input to milliseconds
1179       * Usage: 2
1180       *
1181       * @param    string        Microtime
1182       * @return    integer        Microtime input string converted to an integer (milliseconds)
1183       */
1184  	function convertMicrotime($microtime)    {
1185          $parts = explode(' ',$microtime);
1186          return round(($parts[0]+$parts[1])*1000);
1187      }
1188  
1189      /**
1190       * This splits a string by the chars in $operators (typical /+-*) and returns an array with them in
1191       * Usage: 2
1192       *
1193       * @param    string        Input string, eg "123 + 456 / 789 - 4"
1194       * @param    string        Operators to split by, typically "/+-*"
1195       * @return    array        Array with operators and operands separated.
1196       * @see tslib_cObj::calc(), tslib_gifBuilder::calcOffset()
1197       */
1198  	function splitCalc($string,$operators)    {
1199          $res = Array();
1200          $sign='+';
1201          while($string)    {
1202              $valueLen=strcspn($string,$operators);
1203              $value=substr($string,0,$valueLen);
1204              $res[] = Array($sign,trim($value));
1205              $sign=substr($string,$valueLen,1);
1206              $string=substr($string,$valueLen+1);
1207          }
1208          reset($res);
1209          return $res;
1210      }
1211  
1212      /**
1213       * Calculates the input by +,-,*,/,%,^ with priority to + and -
1214       * Usage: 1
1215       *
1216       * @param    string        Input string, eg "123 + 456 / 789 - 4"
1217       * @return    integer        Calculated value. Or error string.
1218       * @see calcParenthesis()
1219       */
1220  	function calcPriority($string)    {
1221          $string=ereg_replace('[[:space:]]*','',$string);    // removing all whitespace
1222          $string='+'.$string;    // Ensuring an operator for the first entrance
1223          $qm='\*\/\+-^%';
1224          $regex = '(['.$qm.'])(['.$qm.']?[0-9\.]*)';
1225              // split the expression here:
1226          $reg = array();
1227          preg_match_all('/'.$regex.'/',$string,$reg);
1228  
1229          reset($reg[2]);
1230          $number=0;
1231          $Msign='+';
1232          $err='';
1233          $buffer=doubleval(current($reg[2]));
1234          next($reg[2]);    // Advance pointer
1235          while(list($k,$v)=each($reg[2]))    {
1236              $v=doubleval($v);
1237              $sign = $reg[1][$k];
1238              if ($sign=='+' || $sign=='-')    {
1239                  $number = $Msign=='-' ? $number-=$buffer : $number+=$buffer;
1240                  $Msign = $sign;
1241                  $buffer=$v;
1242              } else {
1243                  if ($sign=='/')    {if ($v) $buffer/=$v; else $err='dividing by zero';}
1244                  if ($sign=='%')    {if ($v) $buffer%=$v; else $err='dividing by zero';}
1245                  if ($sign=='*')    {$buffer*=$v;}
1246                  if ($sign=='^')    {$buffer=pow($buffer,$v);}
1247              }
1248          }
1249          $number = $Msign=='-' ? $number-=$buffer : $number+=$buffer;
1250          return $err ? 'ERROR: '.$err : $number;
1251      }
1252  
1253      /**
1254       * Calculates the input with parenthesis levels
1255       * Usage: 2
1256       *
1257       * @param    string        Input string, eg "(123 + 456) / 789 - 4"
1258       * @return    integer        Calculated value. Or error string.
1259       * @see calcPriority(), tslib_cObj::stdWrap()
1260       */
1261  	function calcParenthesis($string)    {
1262          $securC=100;
1263          do {
1264              $valueLenO=strcspn($string,'(');
1265              $valueLenC=strcspn($string,')');
1266              if ($valueLenC==strlen($string) || $valueLenC < $valueLenO)    {
1267                  $value = t3lib_div::calcPriority(substr($string,0,$valueLenC));
1268                  $string = $value.substr($string,$valueLenC+1);
1269                  return $string;
1270              } else {
1271                  $string = substr($string,0,$valueLenO).t3lib_div::calcParenthesis(substr($string,$valueLenO+1));
1272              }
1273                  // Security:
1274              $securC--;
1275              if ($securC<=0)    break;
1276          } while($valueLenO<strlen($string));
1277          return $string;
1278      }
1279  
1280      /**
1281       * Inverse version of htmlspecialchars()
1282       * Usage: 4
1283       *
1284       * @param    string        Value where &gt;, &lt;, &quot; and &amp; should be converted to regular chars.
1285       * @return    string        Converted result.
1286       */
1287  	function htmlspecialchars_decode($value)    {
1288          $value = str_replace('&gt;','>',$value);
1289          $value = str_replace('&lt;','<',$value);
1290          $value = str_replace('&quot;','"',$value);
1291          $value = str_replace('&amp;','&',$value);
1292          return $value;
1293      }
1294  
1295      /**
1296       * Re-converts HTML entities if they have been converted by htmlspecialchars()
1297       * Usage: 10
1298       *
1299       * @param    string        String which contains eg. "&amp;amp;" which should stay "&amp;". Or "&amp;#1234;" to "&#1234;". Or "&amp;#x1b;" to "&#x1b;"
1300       * @return    string        Converted result.
1301       */
1302  	function deHSCentities($str)    {
1303          return ereg_replace('&amp;([#[:alnum:]]*;)','&\1',$str);
1304      }
1305  
1306      /**
1307       * This function is used to escape any ' -characters when transferring text to JavaScript!
1308       * Usage: 3
1309       *
1310       * @param    string        String to escape
1311       * @param    boolean        If set, also backslashes are escaped.
1312       * @param    string        The character to escape, default is ' (single-quote)
1313       * @return    string        Processed input string
1314       */
1315  	function slashJS($string,$extended=0,$char="'")    {
1316          if ($extended)    {$string = str_replace ("\\", "\\\\", $string);}
1317          return str_replace ($char, "\\".$char, $string);
1318      }
1319  
1320      /**
1321       * Version of rawurlencode() where all spaces (%20) are re-converted to space-characters.
1322       * Usefull when passing text to JavaScript where you simply url-encode it to get around problems with syntax-errors, linebreaks etc.
1323       * Usage: 4
1324       *
1325       * @param    string        String to raw-url-encode with spaces preserved
1326       * @return    string        Rawurlencoded result of input string, but with all %20 (space chars) converted to real spaces.
1327       */
1328  	function rawUrlEncodeJS($str)    {
1329          return str_replace('%20',' ',rawurlencode($str));
1330      }
1331  
1332      /**
1333       * rawurlencode which preserves "/" chars
1334       * Usefull when filepaths should keep the "/" chars, but have all other special chars encoded.
1335       * Usage: 5
1336       *
1337       * @param    string        Input string
1338       * @return    string        Output string
1339       */
1340  	function rawUrlEncodeFP($str)    {
1341          return str_replace('%2F','/',rawurlencode($str));
1342      }
1343  
1344      /**
1345       * Checking syntax of input email address
1346       * Usage: 5
1347       *
1348       * @param    string        Input string to evaluate
1349       * @return    boolean        Returns true if the $email address (input string) is valid; Has a "@", domain name with at least one period and only allowed a-z characters.
1350       */
1351  	function validEmail($email)    {
1352          $email = trim ($email);
1353          if (strstr($email,' '))     return FALSE;
1354          return ereg('^[A-Za-z0-9\._-]+[@][A-Za-z0-9\._-]+[\.].[A-Za-z0-9]+$',$email) ? TRUE : FALSE;
1355      }
1356  
1357      /**
1358       * Formats a string for output between <textarea>-tags
1359       * All content outputted in a textarea form should be passed through this function
1360       * Not only is the content htmlspecialchar'ed on output but there is also a single newline added in the top. The newline is necessary because browsers will ignore the first newline after <textarea> if that is the first character. Therefore better set it!
1361       * Usage: 23
1362       *
1363       * @param    string        Input string to be formatted.
1364       * @return    string        Formatted for <textarea>-tags
1365       */
1366  	function formatForTextarea($content)    {
1367          return chr(10).htmlspecialchars($content);
1368      }
1369  
1370  
1371  
1372  
1373  
1374  
1375  
1376  
1377  
1378  
1379  
1380  
1381      /*************************
1382       *
1383       * ARRAY FUNCTIONS
1384       *
1385       *************************/
1386  
1387      /**
1388       * Check if an item exists in an array
1389       * Please note that the order of parameters is reverse compared to the php4-function in_array()!!!
1390       * Usage: 3
1391       *
1392       * @param    array        one-dimensional array of items
1393       * @param    string        item to check for
1394       * @return    boolean        true if $item is in the one-dimensional array $in_array
1395       * @internal
1396       */
1397  	function inArray($in_array,$item)    {
1398          if (is_array($in_array))    {
1399              while (list(,$val)=each($in_array))    {
1400                  if (!is_array($val) && !strcmp($val,$item)) return true;
1401              }
1402          }
1403      }
1404  
1405      /**
1406       * Explodes a $string delimited by $delim and passes each item in the array through intval().
1407       * Corresponds to explode(), but with conversion to integers for all values.
1408       * Usage: 76
1409       *
1410       * @param    string        Delimiter string to explode with
1411       * @param    string        The string to explode
1412       * @return    array        Exploded values, all converted to integers
1413       */
1414  	function intExplode($delim, $string)    {
1415          $temp = explode($delim,$string);
1416          while(list($key,$val)=each($temp))    {
1417              $temp[$key]=intval($val);
1418          }
1419          reset($temp);
1420          return $temp;
1421      }
1422  
1423      /**
1424       * Reverse explode which explodes the string counting from behind.
1425       * Thus t3lib_div::revExplode(':','my:words:here',2) will return array('my:words','here')
1426       * Usage: 8
1427       *
1428       * @param    string        Delimiter string to explode with
1429       * @param    string        The string to explode
1430       * @param    integer        Number of array entries
1431       * @return    array        Exploded values
1432       */
1433  	function revExplode($delim, $string, $count=0)    {
1434          $temp = explode($delim,strrev($string),$count);
1435          while(list($key,$val)=each($temp))    {
1436              $temp[$key]=strrev($val);
1437          }
1438          $temp=array_reverse($temp);
1439          reset($temp);
1440          return $temp;
1441      }
1442  
1443      /**
1444       * Explodes a string and trims all values for whitespace in the ends.
1445       * If $onlyNonEmptyValues is set, then all blank ('') values are removed.
1446       * Usage: 256
1447       *
1448       * @param    string        Delimiter string to explode with
1449       * @param    string        The string to explode
1450       * @param    boolean        If set, all empty values (='') will NOT be set in output
1451       * @return    array        Exploded values
1452       */
1453  	function trimExplode($delim, $string, $onlyNonEmptyValues=0)    {
1454          $temp = explode($delim,$string);
1455          $newtemp=array();
1456          while(list($key,$val)=each($temp))    {
1457              if (!$onlyNonEmptyValues || strcmp('',trim($val)))    {
1458                  $newtemp[]=trim($val);
1459              }
1460          }
1461          reset($newtemp);
1462          return $newtemp;
1463      }
1464  
1465      /**
1466       * Remove duplicate values from an array
1467       * Usage: 0
1468       *
1469       * @param    array        Array of values to make unique
1470       * @return    array
1471       * @ignore
1472       * @deprecated        Use the PHP function array_unique instead
1473       */
1474  	function uniqueArray($valueArray)    {
1475          return array_unique($valueArray);
1476      }
1477  
1478      /**
1479       * Removes the value $cmpValue from the $array if found there. Returns the modified array
1480       * Usage: 3
1481       *
1482       * @param    array        Array containing the values
1483       * @param    string        Value to search for and if found remove array entry where found.
1484       * @return    array        Output array with entries removed if search string is found
1485       */
1486  	function removeArrayEntryByValue($array,$cmpValue)    {
1487          if (is_array($array))    {
1488              reset($array);
1489              while(list($k,$v)=each($array))    {
1490                  if (is_array($v))    {
1491                      $array[$k] = t3lib_div::removeArrayEntryByValue($v,$cmpValue);
1492                  } else {
1493                      if (!strcmp($v,$cmpValue))    {
1494                          unset($array[$k]);
1495                      }
1496                  }
1497              }
1498          }
1499          reset($array);
1500          return $array;
1501      }
1502  
1503      /**
1504       * Implodes a multidim-array into GET-parameters (eg. &param[key][key2]=value2&param[key][key3]=value3)
1505       * Usage: 24
1506       *
1507       * @param    string        Name prefix for entries. Set to blank if you wish none.
1508       * @param    array        The (multidim) array to implode
1509       * @param    string        (keep blank)
1510       * @param    boolean        If set, parameters which were blank strings would be removed.
1511       * @param    boolean        If set, the param name itself (for example "param[key][key2]") would be rawurlencoded as well.
1512       * @return    string        Imploded result, fx. &param[key][key2]=value2&param[key][key3]=value3
1513       * @see explodeUrl2Array()
1514       */
1515  	function implodeArrayForUrl($name,$theArray,$str='',$skipBlank=0,$rawurlencodeParamName=0)    {
1516          if (is_array($theArray))    {
1517              foreach($theArray as $Akey => $AVal)    {
1518                  $thisKeyName = $name ? $name.'['.$Akey.']' : $Akey;
1519                  if (is_array($AVal))    {
1520                      $str = t3lib_div::implodeArrayForUrl($thisKeyName,$AVal,$str,$skipBlank,$rawurlencodeParamName);
1521                  } else {
1522                      if (!$skipBlank || strcmp($AVal,''))    {
1523                          $str.='&'.($rawurlencodeParamName ? rawurlencode($thisKeyName) : $thisKeyName).
1524                              '='.rawurlencode($AVal);
1525                      }
1526                  }
1527              }
1528          }
1529          return $str;
1530      }
1531  
1532      /**
1533       * Explodes a string with GETvars (eg. "&id=1&type=2&ext[mykey]=3") into an array
1534       *
1535       * @param    string        GETvars string
1536       * @param    boolean        If set, the string will be parsed into a multidimensional array if square brackets are used in variable names (using PHP function parse_str())
1537       * @return    array        Array of values. All values AND keys are rawurldecoded() as they properly should be. But this means that any implosion of the array again must rawurlencode it!
1538       * @see implodeArrayForUrl()
1539       */
1540  	function explodeUrl2Array($string,$multidim=FALSE)    {
1541          $output = array();
1542          if ($multidim)    {
1543              parse_str($string,$output);
1544          } else {
1545              $p = explode('&',$string);
1546              foreach($p as $v)    {
1547                  if (strlen($v))    {
1548                      list($pK,$pV) = explode('=',$v,2);
1549                      $output[rawurldecode($pK)] = rawurldecode($pV);
1550                  }
1551              }
1552          }
1553          return $output;
1554      }
1555  
1556      /**
1557       * Returns an array with selected keys from incoming data.
1558       * (Better read source code if you want to find out...)
1559       * Usage: 3
1560       *
1561       * @param    string        List of variable/key names
1562       * @param    array        Array from where to get values based on the keys in $varList
1563       * @param    boolean        If set, then t3lib_div::_GP() is used to fetch the value if not found (isset) in the $getArray
1564       * @return    array        Output array with selected variables.
1565       */
1566  	function compileSelectedGetVarsFromArray($varList,$getArray,$GPvarAlt=1)    {
1567          $keys = t3lib_div::trimExplode(',',$varList,1);
1568          $outArr=array();
1569          foreach($keys as $v)    {
1570              if (isset($getArray[$v]))    {
1571                  $outArr[$v]=$getArray[$v];
1572              } elseif ($GPvarAlt) {
1573                  $outArr[$v]=t3lib_div::_GP($v);
1574              }
1575          }
1576          return $outArr;
1577      }
1578  
1579      /**
1580       * AddSlash array
1581       * This function traverses a multidimentional array and adds slashes to the values.
1582       * NOTE that the input array is and argument by reference.!!
1583       * Twin-function to stripSlashesOnArray
1584       * Usage: 8
1585       *
1586       * @param    array        Multidimensional input array, (REFERENCE!)
1587       * @return    array
1588       */
1589  	function addSlashesOnArray(&$theArray)    {
1590          if (is_array($theArray))    {
1591              reset($theArray);
1592              while(list($Akey,$AVal)=each($theArray))    {
1593                  if (is_array($AVal))    {
1594                      t3lib_div::addSlashesOnArray($theArray[$Akey]);
1595                  } else {
1596                      $theArray[$Akey] = addslashes($AVal);
1597                  }
1598              }
1599              reset($theArray);
1600          }
1601      }
1602  
1603      /**
1604       * StripSlash array
1605       * This function traverses a multidimentional array and strips slashes to the values.
1606       * NOTE that the input array is and argument by reference.!!
1607       * Twin-function to addSlashesOnArray
1608       * Usage: 10
1609       *
1610       * @param    array        Multidimensional input array, (REFERENCE!)
1611       * @return    array
1612       */
1613  	function stripSlashesOnArray(&$theArray)    {
1614          if (is_array($theArray))    {
1615              reset($theArray);
1616              while(list($Akey,$AVal)=each($theArray))    {
1617                  if (is_array($AVal))    {
1618                      t3lib_div::stripSlashesOnArray($theArray[$Akey]);
1619                  } else {
1620                      $theArray[$Akey] = stripslashes($AVal);
1621                  }
1622              }
1623              reset($theArray);
1624          }
1625      }
1626  
1627      /**
1628       * Either slashes ($cmd=add) or strips ($cmd=strip) array $arr depending on $cmd
1629       * Usage: 0
1630       *
1631       * @param    array        Multidimensional input array
1632       * @param    string        "add" or "strip", depending on usage you wish.
1633       * @return    array
1634       */
1635  	function slashArray($arr,$cmd)    {
1636          if ($cmd=='strip')    t3lib_div::stripSlashesOnArray($arr);
1637          if ($cmd=='add')    t3lib_div::addSlashesOnArray($arr);
1638          return $arr;
1639      }
1640  
1641      /**
1642       * Merges two arrays recursively and "binary safe" (integer keys are overridden as well), overruling similar values in the first array ($arr0) with the values of the second array ($arr1)
1643       * In case of identical keys, ie. keeping the values of the second.
1644       * Usage: 0
1645       *
1646       * @param    array        First array
1647       * @param    array        Second array, overruling the first array
1648       * @param    boolean        If set, keys that are NOT found in $arr0 (first array) will not be set. Thus only existing value can/will be overruled from second array.
1649       * @param    boolean        If set, values from $arr1 will overrule if they are empty or zero. Default: true
1650       * @return    array        Resulting array where $arr1 values has overruled $arr0 values
1651       */
1652  	function array_merge_recursive_overrule($arr0,$arr1,$notAddKeys=0,$includeEmtpyValues=true) {
1653          reset($arr1);
1654          while(list($key,$val) = each($arr1)) {
1655              if(is_array($arr0[$key])) {
1656                  if (is_array($arr1[$key]))    {
1657                      $arr0[$key] = t3lib_div::array_merge_recursive_overrule($arr0[$key],$arr1[$key],$notAddKeys,$includeEmtpyValues);
1658                  }
1659              } else {
1660                  if ($notAddKeys) {
1661                      if (isset($arr0[$key])) {
1662                          if ($includeEmtpyValues || $val) {
1663                              $arr0[$key] = $val;
1664                          }
1665                      }
1666                  } else {
1667                      if ($includeEmtpyValues || $val) {
1668                          $arr0[$key] = $val;
1669                      }
1670                  }
1671              }
1672          }
1673          reset($arr0);
1674          return $arr0;
1675      }
1676  
1677      /**
1678       * An array_merge function where the keys are NOT renumbered as they happen to be with the real php-array_merge function. It is "binary safe" in the sense that integer keys are overridden as well.
1679       * Usage: 16
1680       *
1681       * @param    array        First array
1682       * @param    array        Second array
1683       * @return    array        Merged result.
1684       */
1685  	function array_merge($arr1,$arr2)    {
1686          return $arr2+$arr1;
1687      }
1688  
1689      /**
1690       * Takes a row and returns a CSV string of the values with $delim (default is ,) and $quote (default is ") as separator chars.
1691       * Usage: 5
1692       *
1693       * @param    array        Input array of values
1694       * @param    string        Delimited, default is comman
1695       * @param    string        Quote-character to wrap around the values.
1696       * @return    string        A single line of CSV
1697       */
1698  	function csvValues($row,$delim=',',$quote='"')    {
1699          reset($row);
1700          $out=array();
1701          while(list(,$value)=each($row))    {
1702              list($valPart) = explode(chr(10),$value);
1703              $valPart = trim($valPart);
1704              $out[]=str_replace($quote,$quote.$quote,$valPart);
1705          }
1706          $str = $quote.implode($quote.$delim.$quote,$out).$quote;
1707          return $str;
1708      }
1709  
1710      /**
1711       * Removes dots "." from end of a key identifier of TypoScript styled array.
1712       * array('key.' => array('property.' => 'value')) --> array('key' => array('property' => 'value'))
1713       *
1714       * @param    array    $ts: TypoScript configuration array
1715       * @return    array    TypoScript configuration array without dots at the end of all keys
1716       */
1717  	function removeDotsFromTS($ts) {
1718          $out = array();
1719          if (is_array($ts)) {
1720              foreach ($ts as $key => $value) {
1721                  if (is_array($value)) {
1722                      $key = rtrim($key, '.');
1723                      $out[$key] = t3lib_div::removeDotsFromTS($value);
1724                  } else {
1725                      $out[$key] = $value;
1726                  }
1727              }
1728          }
1729          return $out;
1730      }
1731  
1732  
1733  
1734  
1735  
1736  
1737  
1738  
1739  
1740  
1741  
1742  
1743  
1744  
1745  
1746  
1747      /*************************
1748       *
1749       * HTML/XML PROCESSING
1750       *
1751       *************************/
1752  
1753      /**
1754       * Returns an array with all attributes of the input HTML tag as key/value pairs. Attributes are only lowercase a-z
1755       * $tag is either a whole tag (eg '<TAG OPTION ATTRIB=VALUE>') or the parameterlist (ex ' OPTION ATTRIB=VALUE>')
1756       * If a attribute is empty (I call it 'an option'), then the value for the key is empty. You can check if it existed with isset()
1757       * Usage: 8
1758       *
1759       * @param    string        HTML-tag string (or attributes only)
1760       * @return    array        Array with the attribute values.
1761       */
1762  	function get_tag_attributes($tag)    {
1763          $components = t3lib_div::split_tag_attributes($tag);
1764          $name = '';     // attribute name is stored here
1765          $valuemode = '';
1766          if (is_array($components))    {
1767              while (list($key,$val) = each ($components))    {
1768                  if ($val != '=')    {    // Only if $name is set (if there is an attribute, that waits for a value), that valuemode is enabled. This ensures that the attribute is assigned it's value
1769                      if ($valuemode)    {
1770                          if ($name)    {
1771                              $attributes[$name] = $val;
1772                              $name = '';
1773                          }
1774                      } else {
1775                          if ($key = strtolower(ereg_replace('[^a-zA-Z0-9]','',$val)))    {
1776                              $attributes[$key] = '';
1777                              $name = $key;
1778                          }
1779                      }
1780                      $valuemode = '';
1781                  } else {
1782                      $valuemode = 'on';
1783                  }
1784              }
1785              if (is_array($attributes))    reset($attributes);
1786              return $attributes;
1787          }
1788      }
1789  
1790      /**
1791       * Returns an array with the 'components' from an attribute list from an HTML tag. The result is normally analyzed by get_tag_attributes
1792       * Removes tag-name if found
1793       * Usage: 2
1794       *
1795       * @param    string        HTML-tag string (or attributes only)
1796       * @return    array        Array with the attribute values.
1797       * @internal
1798       */
1799  	function split_tag_attributes($tag)    {
1800          $tag_tmp = trim(eregi_replace ('^<[^[:space:]]*','',trim($tag)));
1801              // Removes any > in the end of the string
1802          $tag_tmp = trim(eregi_replace ('>$','',$tag_tmp));
1803  
1804          while (strcmp($tag_tmp,''))    {    // Compared with empty string instead , 030102
1805              $firstChar=substr($tag_tmp,0,1);
1806              if (!strcmp($firstChar,'"') || !strcmp($firstChar,"'"))    {
1807                  $reg=explode($firstChar,$tag_tmp,3);
1808                  $value[]=$reg[1];
1809                  $tag_tmp=trim($reg[2]);
1810              } elseif (!strcmp($firstChar,'=')) {
1811                  $value[] = '=';
1812                  $tag_tmp = trim(substr($tag_tmp,1));        // Removes = chars.
1813              } else {
1814                      // There are '' around the value. We look for the next ' ' or '>'
1815                  $reg = split('[[:space:]=]',$tag_tmp,2);
1816                  $value[] = trim($reg[0]);
1817                  $tag_tmp = trim(substr($tag_tmp,strlen($reg[0]),1).$reg[1]);
1818              }
1819          }
1820          if (is_array($value))    reset($value);
1821          return $value;
1822      }
1823  
1824      /**
1825       * Implodes attributes in the array $arr for an attribute list in eg. and HTML tag (with quotes)
1826       * Usage: 14
1827       *
1828       * @param    array        Array with attribute key/value pairs, eg. "bgcolor"=>"red", "border"=>0
1829       * @param    boolean        If set the resulting attribute list will have a) all attributes in lowercase (and duplicates weeded out, first entry taking precedence) and b) all values htmlspecialchar()'ed. It is recommended to use this switch!
1830       * @param    boolean        If true, don't check if values are blank. Default is to omit attributes with blank values.
1831       * @return    string        Imploded attributes, eg. 'bgcolor="red" border="0"'
1832       */
1833  	function implodeAttributes($arr,$xhtmlSafe=FALSE,$dontOmitBlankAttribs=FALSE)    {
1834          if (is_array($arr))    {
1835              if ($xhtmlSafe)    {
1836                  $newArr=array();
1837                  foreach($arr as $p => $v)    {
1838                      if (!isset($newArr[strtolower($p)])) $newArr[strtolower($p)] = htmlspecialchars($v);
1839                  }
1840                  $arr = $newArr;
1841              }
1842              $list = array();
1843              foreach($arr as $p => $v)    {
1844                  if (strcmp($v,'') || $dontOmitBlankAttribs)    {$list[]=$p.'="'.$v.'"';}
1845              }
1846              return implode(' ',$list);
1847          }
1848      }
1849  
1850      /**
1851       * Implodes attributes in the array $arr for an attribute list in eg. and HTML tag (with quotes)
1852       *
1853       * @param    array        See implodeAttributes()
1854       * @param    boolean        See implodeAttributes()
1855       * @param    boolean        See implodeAttributes()
1856       * @return    string        See implodeAttributes()
1857       * @deprecated    Name was changed into implodeAttributes
1858       * @see implodeAttributes()
1859       */
1860  	function implodeParams($arr,$xhtmlSafe=FALSE,$dontOmitBlankAttribs=FALSE)    {
1861          return t3lib_div::implodeAttributes($arr,$xhtmlSafe,$dontOmitBlankAttribs);
1862      }
1863  
1864      /**
1865       * Wraps JavaScript code XHTML ready with <script>-tags
1866       * Automatic re-identing of the JS code is done by using the first line as ident reference.
1867       * This is nice for identing JS code with PHP code on the same level.
1868       *
1869       * @param    string        JavaScript code
1870       * @param    boolean        Wrap script element in linebreaks? Default is TRUE.
1871       * @return    string        The wrapped JS code, ready to put into a XHTML page
1872       * @author    Ingmar Schlecht <ingmars@web.de>
1873       * @author    René Fritz <r.fritz@colorcube.de>
1874       */
1875  	function wrapJS($string, $linebreak=TRUE) {
1876          if(trim($string)) {
1877                  // <script wrapped in nl?
1878              $cr = $linebreak? "\n" : '';
1879  
1880                  // remove nl from the beginning
1881              $string = preg_replace ('/^\n+/', '', $string);
1882                  // re-ident to one tab using the first line as reference
1883              $match = array();
1884              if(preg_match('/^(\t+)/',$string,$match)) {
1885                  $string = str_replace($match[1],"\t", $string);
1886              }
1887              $string = $cr.'<script type="text/javascript">
1888  /*<![CDATA[*/
1889  '.$string.'
1890  /*]]>*/
1891  </script>'.$cr;
1892          }
1893          return trim($string);
1894      }
1895  
1896  
1897      /**
1898       * Parses XML input into a PHP array with associative keys
1899       * Usage: 0
1900       *
1901       * @param    string        XML data input
1902       * @param    integer        Number of element levels to resolve the XML into an array. Any further structure will be set as XML.
1903       * @return    mixed        The array with the parsed structure unless the XML parser returns with an error in which case the error message string is returned.
1904       * @author bisqwit at iki dot fi dot not dot for dot ads dot invalid / http://dk.php.net/xml_parse_into_struct + kasperYYYY@typo3.com
1905       */
1906  	function xml2tree($string,$depth=999) {
1907          $parser = xml_parser_create();
1908          $vals = array();
1909          $index = array();
1910  
1911          xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
1912          xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
1913          xml_parse_into_struct($parser, $string, $vals, $index);
1914  
1915          if (xml_get_error_code($parser))    return 'Line '.xml_get_current_line_number($parser).': '.xml_error_string(xml_get_error_code($parser));
1916          xml_parser_free($parser);
1917  
1918          $stack = array( array() );
1919          $stacktop = 0;
1920          $startPoint=0;
1921  
1922  // FIXME don't use unset() - what does that mean? Use NULL or similar.
1923          unset($tagi);
1924          foreach($vals as $key => $val) {
1925              $type = $val['type'];
1926  
1927                  // open tag:
1928              if ($type=='open' || $type=='complete') {
1929                  $stack[$stacktop++] = $tagi;
1930  
1931                  if ($depth==$stacktop)    {
1932                      $startPoint=$key;
1933                  }
1934  
1935                  $tagi = array('tag' => $val['tag']);
1936  
1937                  if(isset($val['attributes']))  $tagi['attrs'] = $val['attributes'];
1938                  if(isset($val['value']))    $tagi['values'][] = $val['value'];
1939              }
1940                  // finish tag:
1941              if ($type=='complete' || $type=='close')    {
1942                  $oldtagi = $tagi;
1943                  $tagi = $stack[--$stacktop];
1944                  $oldtag = $oldtagi['tag'];
1945                  unset($oldtagi['tag']);
1946  
1947                  if ($depth==($stacktop+1))    {
1948                      if ($key-$startPoint > 0)    {
1949                          $partArray = array_slice(
1950                              $vals,
1951                              $startPoint+1,
1952                              $key-$startPoint-1
1953                          );
1954                          #$oldtagi=array('XMLvalue'=>t3lib_div::xmlRecompileFromStructValArray($partArray));
1955                          $oldtagi['XMLvalue']=t3lib_div::xmlRecompileFromStructValArray($partArray);
1956                      } else {
1957                          $oldtagi['XMLvalue']=$oldtagi['values'][0];
1958                      }
1959                  }
1960  
1961                  $tagi['ch'][$oldtag][] = $oldtagi;
1962                  unset($oldtagi);
1963              }
1964                  // cdata
1965              if($type=='cdata') {
1966                  $tagi['values'][] = $val['value'];
1967              }
1968          }
1969          return $tagi['ch'];
1970      }
1971  
1972      /**
1973       * Turns PHP array into XML. See array2xml()
1974       *
1975       * @param    array        The input PHP array with any kind of data; text, binary, integers. Not objects though.
1976       * @param    string        Alternative document tag. Default is "phparray".
1977       * @param    array        Options for the compilation. See array2xml() for description.
1978       * @param    string        Forced charset to prologue
1979       * @return    string        An XML string made from the input content in the array.
1980       * @see xml2array(),array2xml()
1981       */
1982  	function array2xml_cs($array,$docTag='phparray',$options=array(),$charset='')    {
1983  
1984              // Figure out charset if not given explicitly:
1985          if (!$charset)    {
1986              if ($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'])    {    // First priority: forceCharset! If set, this will be authoritative!
1987                  $charset = $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'];
1988              } elseif (is_object($GLOBALS['LANG']))    {
1989                  $charset = $GLOBALS['LANG']->charSet;    // If "LANG" is around, that will hold the current charset
1990              } else {
1991                  $charset = 'iso-8859-1';    // THIS is just a hopeful guess!
1992              }
1993          }
1994  
1995              // Return XML:
1996          return '<?xml version="1.0" encoding="'.htmlspecialchars($charset).'" standalone="yes" ?>'.chr(10).
1997                  t3lib_div::array2xml($array,'',0,$docTag,0, $options);
1998      }
1999  
2000      /**
2001       * Deprecated to call directly (unless you are aware of using XML prologues)! Use "array2xml_cs" instead (which adds an XML-prologue)
2002       *
2003       * Converts a PHP array into an XML string.
2004       * The XML output is optimized for readability since associative keys are used as tagnames.
2005       * This also means that only alphanumeric characters are allowed in the tag names AND only keys NOT starting with numbers (so watch your usage of keys!). However there are options you can set to avoid this problem.
2006       * Numeric keys are stored with the default tagname "numIndex" but can be overridden to other formats)
2007       * The function handles input values from the PHP array in a binary-safe way; All characters below 32 (except 9,10,13) will trigger the content to be converted to a base64-string
2008       * The PHP variable type of the data IS preserved as long as the types are strings, arrays, integers and booleans. Strings are the default type unless the "type" attribute is set.
2009       * The output XML has been tested with the PHP XML-parser and parses OK under all tested circumstances with 4.x versions. However, with PHP5 there seems to be the need to add an XML prologue a la <?xml version="1.0" encoding="[charset]" standalone="yes" ?> - otherwise UTF-8 is assumed! Unfortunately, many times the output from this function is used without adding that prologue meaning that non-ASCII characters will break the parsing!! This suchs of course! Effectively it means that the prologue should always be prepended setting the right characterset, alternatively the system should always run as utf-8!
2010       * However using MSIE to read the XML output didn't always go well: One reason could be that the character encoding is not observed in the PHP data. The other reason may be if the tag-names are invalid in the eyes of MSIE. Also using the namespace feature will make MSIE break parsing. There might be more reasons...
2011       * Usage: 5
2012       *
2013       * @param    array        The input PHP array with any kind of data; text, binary, integers. Not objects though.
2014       * @param    string        tag-prefix, eg. a namespace prefix like "T3:"
2015       * @param    integer        Current recursion level. Don't change, stay at zero!
2016       * @param    string        Alternative document tag. Default is "phparray".
2017       * @param    integer        If greater than zero, then the number of spaces corresponding to this number is used for indenting, if less than zero - no indentation, if zero - a single chr(9) (TAB) is used
2018       * @param    array        Options for the compilation. Key "useNindex" => 0/1 (boolean: whether to use "n0, n1, n2" for num. indexes); Key "useIndexTagForNum" => "[tag for numerical indexes]"; Key "useIndexTagForAssoc" => "[tag for associative indexes"; Key "parentTagMap" => array('parentTag' => 'thisLevelTag')
2019       * @param    string        Stack data. Don't touch.
2020       * @return    string        An XML string made from the input content in the array.
2021       * @see xml2array()
2022       */
2023  	function array2xml($array,$NSprefix='',$level=0,$docTag='phparray',$spaceInd=0, $options=array(),$stackData=array())    {
2024              // The list of byte values which will trigger binary-safe storage. If any value has one of these char values in it, it will be encoded in base64
2025          $binaryChars = chr(0).chr(1).chr(2).chr(3).chr(4).chr(5).chr(6).chr(7).chr(8).
2026                          chr(11).chr(12).chr(14).chr(15).chr(16).chr(17).chr(18).chr(19).
2027                          chr(20).chr(21).chr(22).chr(23).chr(24).chr(25).chr(26).chr(27).chr(28).chr(29).
2028                          chr(30).chr(31);
2029              // Set indenting mode:
2030          $indentChar = $spaceInd ? ' ' : chr(9);
2031          $indentN = $spaceInd>0 ? $spaceInd : 1;
2032          $nl = ($spaceInd >= 0 ? chr(10) : '');
2033  
2034              // Init output variable:
2035          $output='';
2036  
2037              // Traverse the input array
2038          if (is_array($array))    {
2039              foreach($array as $k=>$v)    {
2040                  $attr = '';
2041                  $tagName = $k;
2042  
2043                      // Construct the tag name.
2044                  if(isset($options['grandParentTagMap'][$stackData['grandParentTagName'].'/'.$stackData['parentTagName']])) {        // Use tag based on grand-parent + parent tag name
2045                      $attr.=' index="'.htmlspecialchars($tagName).'"';
2046                      $tagName = (string)$options['grandParentTagMap'][$stackData['grandParentTagName'].'/'.$stackData['parentTagName']];
2047                  }elseif(isset($options['parentTagMap'][$stackData['parentTagName'].':_IS_NUM']) && t3lib_div::testInt($tagName)) {        // Use tag based on parent tag name + if current tag is numeric
2048                      $attr.=' index="'.htmlspecialchars($tagName).'"';
2049                      $tagName = (string)$options['parentTagMap'][$stackData['parentTagName'].':_IS_NUM'];
2050                  }elseif(isset($options['parentTagMap'][$stackData['parentTagName'].':'.$tagName])) {        // Use tag based on parent tag name + current tag
2051                      $attr.=' index="'.htmlspecialchars($tagName).'"';
2052                      $tagName = (string)$options['parentTagMap'][$stackData['parentTagName'].':'.$tagName];
2053                  } elseif(isset($options['parentTagMap'][$stackData['parentTagName']])) {        // Use tag based on parent tag name:
2054                      $attr.=' index="'.htmlspecialchars($tagName).'"';
2055                      $tagName = (string)$options['parentTagMap'][$stackData['parentTagName']];
2056                  } elseif (!strcmp(intval($tagName),$tagName))    {    // If integer...;
2057                      if ($options['useNindex']) {    // If numeric key, prefix "n"
2058                          $tagName = 'n'.$tagName;
2059                      } else {    // Use special tag for num. keys:
2060                          $attr.=' index="'.$tagName.'"';
2061                          $tagName = $options['useIndexTagForNum'] ? $options['useIndexTagForNum'] : 'numIndex';
2062                      }
2063                  } elseif($options['useIndexTagForAssoc']) {        // Use tag for all associative keys:
2064                      $attr.=' index="'.htmlspecialchars($tagName).'"';
2065                      $tagName = $options['useIndexTagForAssoc'];
2066                  }
2067  
2068                      // The tag name is cleaned up so only alphanumeric chars (plus - and _) are in there and not longer than 100 chars either.
2069                  $tagName = substr(ereg_replace('[^[:alnum:]_-]','',$tagName),0,100);
2070  
2071                      // If the value is an array then we will call this function recursively:
2072                  if (is_array($v))    {
2073  
2074                          // Sub elements:
2075                      if ($options['alt_options'][$stackData['path'].'/'.$tagName])    {
2076                          $subOptions = $options['alt_options'][$stackData['path'].'/'.$tagName];
2077                          $clearStackPath = $subOptions['clearStackPath'];
2078                      } else {
2079                          $subOptions = $options;
2080                          $clearStackPath = FALSE;
2081                      }
2082  
2083                      $content = $nl .
2084                                  t3lib_div::array2xml(
2085                                      $v,
2086                                      $NSprefix,
2087                                      $level+1,
2088                                      '',
2089                                      $spaceInd,
2090                                      $subOptions,
2091                                      array(
2092                                          'parentTagName' => $tagName,
2093                                          'grandParentTagName' => $stackData['parentTagName'],
2094                                          'path' => $clearStackPath ? '' : $stackData['path'].'/'.$tagName,
2095                                      )
2096                                  ).
2097                                  ($spaceInd >= 0 ? str_pad('',($level+1)*$indentN,$indentChar) : '');
2098                      if ((int)$options['disableTypeAttrib']!=2)    {    // Do not set "type = array". Makes prettier XML but means that empty arrays are not restored with xml2array
2099                          $attr.=' type="array"';
2100                      }
2101                  } else {    // Just a value:
2102  
2103                          // Look for binary chars:
2104                      $vLen = strlen($v);    // check for length, because PHP 5.2.0 may crash when first argument of strcspn is empty
2105                      if ($vLen && strcspn($v,$binaryChars) != $vLen)    {    // Go for base64 encoding if the initial segment NOT matching any binary char has the same length as the whole string!
2106                              // If the value contained binary chars then we base64-encode it an set an attribute to notify this situation:
2107                          $content = $nl.chunk_split(base64_encode($v));
2108                          $attr.=' base64="1"';
2109                      } else {
2110                              // Otherwise, just htmlspecialchar the stuff:
2111                          $content = htmlspecialchars($v);
2112                          $dType = gettype($v);
2113                          if ($dType == 'string') {
2114                              if ($options['useCDATA'] && $content != $v) {
2115                                  $content = '<![CDATA[' . $v . ']]>';
2116                              }
2117                          } elseif (!$options['disableTypeAttrib']) {
2118                              $attr.= ' type="'.$dType.'"';
2119                          }
2120                      }
2121                  }
2122  
2123                      // Add the element to the output string:
2124                  $output.=($spaceInd >= 0 ? str_pad('',($level+1)*$indentN,$indentChar) : '').'<'.$NSprefix.$tagName.$attr.'>'.$content.'</'.$NSprefix.$tagName.'>'.$nl;
2125              }
2126          }
2127  
2128              // If we are at the outer-most level, then we finally wrap it all in the document tags and return that as the value:
2129          if (!$level)    {
2130              $output =
2131                  '<'.$docTag.'>'.$nl.
2132                  $output.
2133                  '</'.$docTag.'>';
2134          }
2135  
2136          return $output;
2137      }
2138  
2139      /**
2140       * Converts an XML string to a PHP array.
2141       * This is the reverse function of array2xml()
2142       * Usage: 17
2143       *
2144       * @param    string        XML content to convert into an array
2145       * @param    string        The tag-prefix resolve, eg. a namespace like "T3:"
2146       * @param    boolean        If set, the document tag will be set in the key "_DOCUMENT_TAG" of the output array
2147       * @return    mixed        If the parsing had errors, a string with the error message is returned. Otherwise an array with the content.
2148       * @see array2xml()
2149       */
2150  	function xml2array($string,$NSprefix='',$reportDocTag=FALSE) {
2151          global $TYPO3_CONF_VARS;
2152  
2153              // Create parser:
2154          $parser = xml_parser_create();
2155          $vals = array();
2156          $index = array();
2157  
2158          xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2159          xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
2160  
2161              //  PHP4 doesn't like Unicode byte order marks (BOM), so we have to check for them
2162              // The BOM check comes first, so that the PHP5 preg_match() below doesn't have to check for it
2163          if(substr($string,0,3)=="\xEF\xBB\xBF")    {
2164              xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'utf-8');
2165          }
2166              // PHP 4.x: output charset is the same as the input charset, charsets are handled transparently if not specified in xml_parser_create()
2167              // PHP 5.0.0 & 5.0.1: default output charset is ISO-8859-1, only ASCII, ISO-8859-1 and UTF-8 are supported!!!
2168              // PHP 5.0.2+: default output charset is UTF-8    , only ASCII, ISO-8859-1 and UTF-8 are supported!!!
2169          elseif ((double)phpversion()>=5)    {
2170              $match = array();
2171              preg_match('/^[[:space:]]*<\?xml[^>]*encoding[[:space:]]*=[[:space:]]*"([^"]*)"/',substr($string,0,200),$match);
2172              $theCharset = $match[1] ? $match[1] : ($TYPO3_CONF_VARS['BE']['forceCharset'] ? $TYPO3_CONF_VARS['BE']['forceCharset'] : 'iso-8859-1');
2173              xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $theCharset);  // us-ascii / utf-8 / iso-8859-1
2174          }
2175  
2176              // Parse content:
2177          xml_parse_into_struct($parser, $string, $vals, $index);
2178  
2179              // If error, return error message:
2180          if (xml_get_error_code($parser))    {
2181              return 'Line '.xml_get_current_line_number($parser).': '.xml_error_string(xml_get_error_code($parser));
2182          }
2183          xml_parser_free($parser);
2184  
2185              // Init vars:
2186          $stack = array(array());
2187          $stacktop = 0;
2188          $current=array();
2189          $tagName = '';
2190          $documentTag = '';
2191  
2192              // Traverse the parsed XML structure:
2193          foreach($vals as $key => $val) {
2194  
2195                  // First, process the tag-name (which is used in both cases, whether "complete" or "close")
2196              $tagName = $val['tag'];
2197              if (!$documentTag)    $documentTag = $tagName;
2198  
2199                  // Test for name space:
2200              $tagName = ($NSprefix && substr($tagName,0,strlen($NSprefix))==$NSprefix) ? substr($tagName,strlen($NSprefix)) : $tagName;
2201  
2202                  // Test for numeric tag, encoded on the form "nXXX":
2203              $testNtag = substr($tagName,1);    // Closing tag.
2204              $tagName = (substr($tagName,0,1)=='n' && !strcmp(intval($testNtag),$testNtag)) ? intval($testNtag) : $tagName;
2205  
2206                  // Test for alternative index value:
2207              if (strlen($val['attributes']['index']))    { $tagName = $val['attributes']['index']; }
2208  
2209                  // Setting tag-values, manage stack:
2210              switch($val['type'])    {
2211                  case 'open':        // If open tag it means there is an array stored in sub-elements. Therefore increase the stackpointer and reset the accumulation array:
2212                      $current[$tagName] = array();    // Setting blank place holder
2213                      $stack[$stacktop++] = $current;
2214                      $current = array();
2215                  break;
2216                  case 'close':    // If the tag is "close" then it is an array which is closing and we decrease the stack pointer.
2217                      $oldCurrent = $current;
2218                      $current = $stack[--$stacktop];
2219                      end($current);    // Going to the end of array to get placeholder key, key($current), and fill in array next:
2220                      $current[key($current)] = $oldCurrent;
2221                      unset($oldCurrent);
2222                  break;
2223                  case 'complete':    // If "complete", then it's a value. If the attribute "base64" is set, then decode the value, otherwise just set it.
2224                      if ($val['attributes']['base64'])    {
2225                          $current[$tagName] = base64_decode($val['value']);
2226                      } else {
2227                          $current[$tagName] = (string)$val['value']; // Had to cast it as a string - otherwise it would be evaluate false if tested with isset()!!
2228  
2229                              // Cast type:
2230                          switch((string)$val['attributes']['type'])    {
2231                              case 'integer':
2232                                  $current[$tagName] = (integer)$current[$tagName];
2233                              break;
2234                              case 'double':
2235                                  $current[$tagName] = (double)$current[$tagName];
2236                              break;
2237                              case 'boolean':
2238                                  $current[$tagName] = (bool)$current[$tagName];
2239                              break;
2240                              case 'array':
2241                                  $current[$tagName] = array();    // MUST be an empty array since it is processed as a value; Empty arrays would end up here because they would have no tags inside...
2242                              break;
2243                          }
2244                      }
2245                  break;
2246              }
2247          }
2248  
2249          if ($reportDocTag)    {
2250              $current[$tagName]['_DOCUMENT_TAG'] = $documentTag;
2251          }
2252  
2253              // Finally return the content of the document tag.
2254          return $current[$tagName];
2255      }
2256  
2257      /**
2258       * This implodes an array of XML parts (made with xml_parse_into_struct()) into XML again.
2259       * Usage: 2
2260       *
2261       * @param    array        A array of XML parts, see xml2tree
2262       * @return    string        Re-compiled XML data.
2263       */
2264  	function xmlRecompileFromStructValArray($vals)    {
2265          $XMLcontent='';
2266  
2267          foreach($vals as $val) {
2268              $type = $val['type'];
2269  
2270                  // open tag:
2271              if ($type=='open' || $type=='complete') {
2272                  $XMLcontent.='<'.$val['tag'];
2273                  if(isset($val['attributes']))  {
2274                      foreach($val['attributes'] as $k => $v)    {
2275                          $XMLcontent.=' '.$k.'="'.htmlspecialchars($v).'"';
2276                      }
2277                  }
2278                  if ($type=='complete')    {
2279                      if(isset($val['value']))    {
2280                          $XMLcontent.='>'.htmlspecialchars($val['value']).'</'.$val['tag'].'>';
2281                      } else $XMLcontent.='/>';
2282                  } else $XMLcontent.='>';
2283  
2284                  if ($type=='open' && isset($val['value']))    {
2285                      $XMLcontent.=htmlspecialchars($val['value']);
2286                  }
2287              }
2288                  // finish tag:
2289              if ($type=='close')    {
2290                  $XMLcontent.='</'.$val['tag'].'>';
2291              }
2292                  // cdata
2293              if($type=='cdata') {
2294                  $XMLcontent.=htmlspecialchars($val['value']);
2295              }
2296          }
2297  
2298          return $XMLcontent;
2299      }
2300  
2301      /**
2302       * Extract the encoding scheme as found in the first line of an XML document (typically)
2303       * Usage: 1
2304       *
2305       * @param    string        XML data
2306       * @return    string        Encoding scheme (lowercase), if found.
2307       */
2308  	function xmlGetHeaderAttribs($xmlData)    {
2309          $xmlHeader = substr(trim($xmlData),0,200);
2310          $reg=array();
2311          if (eregi('^<\?xml([^>]*)\?\>',$xmlHeader,$reg))    {
2312              return t3lib_div::get_tag_attributes($reg[1]);
2313          }
2314      }
2315  
2316  
2317  
2318  
2319  
2320  
2321  
2322  
2323  
2324  
2325  
2326      /*************************
2327       *
2328       * FILES FUNCTIONS
2329       *
2330       *************************/
2331  
2332      /**
2333       * Reads the file or url $url and returns the content
2334       * If you are having trouble with proxys when reading URLs you can configure your way out of that with settings like $TYPO3_CONF_VARS['SYS']['curlUse'] etc.
2335       * Usage: 83
2336       *
2337       * @param    string        Filepath/URL to read
2338       * @param    integer        Whether the HTTP header should be fetched or not. 0=disable, 1=fetch header+content, 2=fetch header only
2339       * @param    array        HTTP headers to be used in the request
2340       * @return    string        The content from the resource given as input.
2341       */
2342  	function getURL($url, $includeHeader = 0, $requestHeaders = false)    {
2343          $content = false;
2344  
2345              // (Proxy support implemented by Arco <arco@appeltaart.mine.nu>)
2346          if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlUse'] == '1' && preg_match('/^https?:\/\//', $url))    {
2347                  // External URL without error checking.
2348              $ch = curl_init();
2349              if (!$ch)    {
2350                  return false;
2351              }
2352  
2353              curl_setopt($ch, CURLOPT_URL, $url);
2354              curl_setopt($ch, CURLOPT_HEADER, $includeHeader ? 1 : 0);
2355              curl_setopt($ch, CURLOPT_NOBODY, $includeHeader == 2 ? 1 : 0);
2356              curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
2357              curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
2358              curl_setopt($ch, CURLOPT_FAILONERROR, 1);
2359              if (is_array($requestHeaders))    {
2360                  curl_setopt($ch, CURLOPT_HTTPHEADER, $requestHeaders);
2361              }
2362  
2363              if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyServer'])    {
2364                  curl_setopt($ch, CURLOPT_PROXY, $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyServer']);
2365  
2366                      // Not sure if this is needed
2367                  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyTunnel'])    {
2368                      curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyTunnel']);
2369                  }
2370                  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyUserPass'])    {
2371                      curl_setopt($ch, CURLOPT_PROXYUSERPWD, $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyUserPass']);
2372                  }
2373              }
2374              $content = curl_exec($ch);
2375              curl_close($ch);
2376  
2377          } elseif ($includeHeader)    {
2378              $parsedURL = parse_url($url);
2379              if (!t3lib_div::inList('ftp,ftps,http,https,gopher,telnet', $parsedURL['scheme']))    {
2380                  return false;
2381              }
2382  
2383              $fp = @fsockopen($parsedURL['host'], ($parsedURL['port'] > 0 ? $parsedURL['port'] : 80), $errno, $errstr, 2.0);
2384              if (!$fp)    {
2385                  return false;
2386              }
2387  
2388              $msg = 'GET ' . $parsedURL['path'] .
2389                      ($parsedURL['query'] ? '?' . $parsedURL['query'] : '') .
2390                      ' HTTP/1.0' . "\r\n" . 'Host: ' .
2391                      $parsedURL['host'] . "\r\n\r\n";
2392              fputs($fp, $msg);
2393              while (!feof($fp))    {
2394                  $line = fgets($fp, 2048);
2395                  $content.= $line;
2396                  if ($includeHeader == 2 && !strlen(trim($line)))    {
2397                      break;    // Stop at the first empty line (= end of header)
2398                  }
2399              }
2400              fclose($fp);
2401  
2402          } elseif (is_array($requestHeaders))    {
2403              $ctx = stream_context_create(array(
2404                          'http' => array(
2405                              'header' => implode("\r\n", $requestHeaders)
2406                          )
2407                      )
2408                  );
2409              if (version_compare(phpversion(), '5.0', '>=')) {
2410                  $content = @file_get_contents($url, false, $ctx);
2411              }
2412              elseif (false !== ($fd = @fopen($url, 'rb', false, $ctx)))    {
2413                  $content = '';
2414                  while (!feof($fd))    {
2415                      $content.= @fread($fd, 4096);
2416                  }
2417                  fclose($fd);
2418              }
2419          }
2420          else    {
2421              $content = @file_get_contents($url);
2422          }
2423  
2424          return $content;
2425      }
2426  
2427      /**
2428       * Writes $content to the file $file
2429       * Usage: 30
2430       *
2431       * @param    string        Filepath to write to
2432       * @param    string        Content to write
2433       * @return    boolean        True if the file was successfully opened and written to.
2434       */
2435  	function writeFile($file,$content)    {
2436          if (!@is_file($file))    $changePermissions = true;
2437  
2438          if ($fd = fopen($file,'wb'))    {
2439              $res = fwrite($fd,$content);
2440              fclose($fd);
2441  
2442              if ($res===false)    return false;
2443  
2444              if ($changePermissions)    {    // Change the permissions only if the file has just been created
2445                  t3lib_div::fixPermissions($file);
2446              }
2447  
2448              return true;
2449          }
2450  
2451          return false;
2452      }
2453  
2454      /**
2455       * Setting file system mode & group ownership of file
2456       *
2457       * @param    string        Filepath of newly created file
2458       * @return    void
2459       */
2460  	function fixPermissions($file)    {
2461          if (@is_file($file) && TYPO3_OS!='WIN')    {
2462              @chmod($file, octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask']));        // "@" is there because file is not necessarily OWNED by the user
2463              if($GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup'])    {    // skip this if createGroup is empty
2464                  @chgrp($file, $GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup']);        // "@" is there because file is not necessarily OWNED by the user
2465              }
2466          }
2467      }
2468  
2469      /**
2470       * Writes $content to a filename in the typo3temp/ folder (and possibly one or two subfolders...)
2471       * Accepts an additional subdirectory in the file path!
2472       *
2473       * @param    string        Absolute filepath to write to inside "typo3temp/". First part of this string must match PATH_site."typo3temp/"
2474       * @param    string        Content string to write
2475       * @return    string        Returns false on success, otherwise an error string telling about the problem.
2476       */
2477  	function writeFileToTypo3tempDir($filepath,$content)    {
2478  
2479              // Parse filepath into directory and basename:
2480          $fI = pathinfo($filepath);
2481          $fI['dirname'].= '/';
2482  
2483              // Check parts:
2484          if (t3lib_div::validPathStr($filepath) && $fI['basename'] && strlen($fI['basename'])<60)    {
2485              if (defined('PATH_site'))    {
2486                  $dirName = PATH_site.'typo3temp/';    // Setting main temporary directory name (standard)
2487                  if (@is_dir($dirName))    {
2488                      if (t3lib_div::isFirstPartOfStr($fI['dirname'],$dirName))    {
2489  
2490                              // Checking if the "subdir" is found:
2491                          $subdir = substr($fI['dirname'],strlen($dirName));
2492                          if ($subdir)    {
2493                              if (ereg('^[[:alnum:]_]+\/$',$subdir) || ereg('^[[:alnum:]_]+\/[[:alnum:]_]+\/$',$subdir))    {
2494                                  $dirName.= $subdir;
2495                                  if (!@is_dir($dirName))    {
2496                                      t3lib_div::mkdir_deep(PATH_site.'typo3temp/', $subdir);
2497                                  }
2498                              } else return 'Subdir, "'.$subdir.'", was NOT on the form "[[:alnum:]_]/" or  "[[:alnum:]_]/[[:alnum:]_]/"';
2499                          }
2500                              // Checking dir-name again (sub-dir might have been created):
2501                          if (@is_dir($dirName))    {
2502                              if ($filepath == $dirName.$fI['basename'])    {
2503                                  t3lib_div::writeFile($filepath, $content);
2504                                  if (!@is_file($filepath))    return 'File not written to disk! Write permission error in filesystem?';
2505                              } else return 'Calculated filelocation didn\'t match input $filepath!';
2506                          } else return '"'.$dirName.'" is not a directory!';
2507                      } else return '"'.$fI['dirname'].'" was not within directory PATH_site + "typo3temp/"';
2508                  } else return 'PATH_site + "typo3temp/" was not a directory!';
2509              } else return 'PATH_site constant was NOT defined!';
2510          } else return 'Input filepath "'.$filepath.'" was generally invalid!';
2511      }
2512  
2513      /**
2514       * Wrapper function for mkdir, setting folder permissions according to $GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] and group ownership according to $GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup']
2515       * Usage: 6
2516       *
2517       * @param    string        Absolute path to folder, see PHP mkdir() function. Removes trailing slash internally.
2518       * @return    boolean        TRUE if @mkdir went well!
2519       */
2520  	function mkdir($theNewFolder)    {
2521          $theNewFolder = preg_replace('|/$|','',$theNewFolder);
2522          if (mkdir($theNewFolder, octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask']))){
2523              chmod($theNewFolder, octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'])); //added this line, because the mode at 'mkdir' has a strange behaviour sometimes
2524  
2525              if($GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup'])    {    // skip this if createGroup is empty
2526                  chgrp($theNewFolder, $GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup']);
2527              }
2528              return TRUE;
2529          }
2530      }
2531  
2532      /**
2533       * Creates a directory - including parent directories if necessary - in the file system
2534       *
2535       * @param    string        Base folder. This must exist! Must have trailing slash! Example "/root/typo3site/"
2536       * @param    string        Deep directory to create, eg. "xx/yy/" which creates "/root/typo3site/xx/yy/" if $destination is "/root/typo3site/"
2537       * @return    string        If error, returns error string.
2538       */
2539  	function mkdir_deep($destination,$deepDir)    {
2540          $allParts = t3lib_div::trimExplode('/',$deepDir,1);
2541          $root = '';
2542          foreach($allParts as $part)    {
2543              $root.= $part.'/';
2544              if (!is_dir($destination.$root))    {
2545                  t3lib_div::mkdir($destination.$root);
2546                  if (!@is_dir($destination.$root))    {
2547                      return 'Error: The directory "'.$destination.$root.'" could not be created...';
2548                  }
2549              }
2550          }
2551      }
2552  
2553      /**
2554       * Returns an array with the names of folders in a specific path
2555       * Will return 'error' (string) if there were an error with reading directory content.
2556       * Usage: 11
2557       *
2558       * @param    string        Path to list directories from
2559       * @return    array        Returns an array with the directory entries as values. If no path, the return value is nothing.
2560       */
2561  	function get_dirs($path)    {
2562          if ($path)    {
2563              $d = @dir($path);
2564              if (is_object($d))    {
2565                  while($entry=$d->read()) {
2566                      if (@is_dir($path.'/'.$entry) && $entry!= '..' && $entry!= '.')    {
2567                          $filearray[]=$entry;
2568                      }
2569                  }
2570                  $d->close();
2571              } else return 'error';
2572              return $filearray;
2573          }
2574      }
2575  
2576      /**
2577       * Returns an array with the names of files in a specific path
2578       * Usage: 18
2579       *
2580       * @param    string        $path: Is the path to the file
2581       * @param    string        $extensionList is the comma list of extensions to read only (blank = all)
2582       * @param    boolean        If set, then the path is prepended the filenames. Otherwise only the filenames are returned in the array
2583       * @param    string        $order is sorting: 1= sort alphabetically, 'mtime' = sort by modification time.
2584       * @param    string        A comma seperated list of filenames to exclude, no wildcards
2585       * @return    array        Array of the files found
2586       */
2587  	function getFilesInDir($path,$extensionList='',$prependPath=0,$order='',$excludePattern='')    {
2588  
2589              // Initialize variabels:
2590          $filearray = array();
2591          $sortarray = array();
2592          $path = ereg_replace('\/$','',$path);
2593  
2594              // Find files+directories:
2595          if (@is_dir($path))    {
2596              $extensionList = strtolower($extensionList);
2597              $d = dir($path);
2598              if (is_object($d))    {
2599                  while($entry=$d->read()) {
2600                      if (@is_file($path.'/'.$entry))    {
2601                          $fI = pathinfo($entry);
2602                          $key = md5($path.'/'.$entry);    // Don't change this ever - extensions may depend on the fact that the hash is an md5 of the path! (import/export extension)
2603                          if ((!strlen($extensionList) || t3lib_div::inList($extensionList,strtolower($fI['extension']))) && (!strlen($excludePattern) || !preg_match('/^'.$excludePattern.'$/',$entry)))    {
2604                              $filearray[$key]=($prependPath?$path.'/':'').$entry;
2605                                  if ($order=='mtime') {$sortarray[$key]=filemtime($path.'/'.$entry);}
2606                                  elseif ($order)    {$sortarray[$key]=$entry;}
2607                          }
2608                      }
2609                  }
2610                  $d->close();
2611              } else return 'error opening path: "'.$path.'"';
2612          }
2613  
2614              // Sort them:
2615          if ($order) {
2616              asort($sortarray);
2617              reset($sortarray);
2618              $newArr=array();
2619              while(list($k,$v)=each($sortarray))    {
2620                  $newArr[$k]=$filearray[$k];
2621              }
2622              $filearray=$newArr;
2623          }
2624  
2625              // Return result
2626          reset($filearray);
2627          return $filearray;
2628      }
2629  
2630      /**
2631       * Recursively gather all files and folders of a path.
2632       * Usage: 5
2633       *
2634       * @param    array        $fileArr: Empty input array (will have files added to it)
2635       * @param    string        $path: The path to read recursively from (absolute) (include trailing slash!)
2636       * @param    string        $extList: Comma list of file extensions: Only files with extensions in this list (if applicable) will be selected.
2637       * @param    boolean        $regDirs: If set, directories are also included in output.
2638       * @param    integer        $recursivityLevels: The number of levels to dig down...
2639       * @param string        $excludePattern: regex pattern of files/directories to exclude
2640       * @return    array        An array with the found files/directories.
2641       */
2642  	function getAllFilesAndFoldersInPath($fileArr,$path,$extList='',$regDirs=0,$recursivityLevels=99,$excludePattern='')    {
2643          if ($regDirs)    $fileArr[] = $path;
2644          $fileArr = array_merge($fileArr, t3lib_div::getFilesInDir($path,$extList,1,1,$excludePattern));
2645  
2646          $dirs = t3lib_div::get_dirs($path);
2647          if (is_array($dirs) && $recursivityLevels>0)    {
2648              foreach ($dirs as $subdirs)    {
2649                  if ((string)$subdirs!='' && (!strlen($excludePattern) || !preg_match('/^'.$excludePattern.'$/',$subdirs)))    {
2650                      $fileArr = t3lib_div::getAllFilesAndFoldersInPath($fileArr,$path.$subdirs.'/',$extList,$regDirs,$recursivityLevels-1,$excludePattern);
2651                  }
2652              }
2653          }
2654          return $fileArr;
2655      }
2656  
2657      /**
2658       * Removes the absolute part of all files/folders in fileArr
2659       * Usage: 2
2660       *
2661       * @param    array        $fileArr: The file array to remove the prefix from
2662       * @param    string        $prefixToRemove: The prefix path to remove (if found as first part of string!)
2663       * @return    array        The input $fileArr processed.
2664       */
2665  	function removePrefixPathFromList($fileArr,$prefixToRemove)    {
2666          foreach($fileArr as $k => $absFileRef)    {
2667              if(t3lib_div::isFirstPartOfStr($absFileRef,$prefixToRemove))    {
2668                  $fileArr[$k] = substr($absFileRef,strlen($prefixToRemove));
2669              } else return 'ERROR: One or more of the files was NOT prefixed with the prefix-path!';
2670          }
2671          return $fileArr;
2672      }
2673  
2674      /**
2675       * Fixes a path for windows-backslashes and reduces double-slashes to single slashes
2676       * Usage: 2
2677       *
2678       * @param    string        File path to process
2679       * @return    string
2680       */
2681  	function fixWindowsFilePath($theFile)    {
2682          return str_replace('//','/', str_replace('\\','/', $theFile));
2683      }
2684  
2685      /**
2686       * Resolves "../" sections in the input path string.
2687       * For example "fileadmin/directory/../other_directory/" will be resolved to "fileadmin/other_directory/"
2688       * Usage: 2
2689       *
2690       * @param    string        File path in which "/../" is resolved
2691       * @return    string
2692       */
2693  	function resolveBackPath($pathStr)    {
2694          $parts = explode('/',$pathStr);
2695          $output=array();
2696          $c = 0;
2697          foreach($parts as $pV)    {
2698              if ($pV=='..')    {
2699                  if ($c)    {
2700                      array_pop($output);
2701                      $c--;
2702                  } else $output[]=$pV;
2703              } else {
2704                  $c++;
2705                  $output[]=$pV;
2706              }
2707          }
2708          return implode('/',$output);
2709      }
2710  
2711      /**
2712       * Prefixes a URL used with 'header-location' with 'http://...' depending on whether it has it already.
2713       * - If already having a scheme, nothing is prepended
2714       * - If having REQUEST_URI slash '/', then prefixing 'http://[host]' (relative to host)
2715       * - Otherwise prefixed with TYPO3_REQUEST_DIR (relative to current dir / TYPO3_REQUEST_DIR)
2716       * Usage: 30
2717       *
2718       * @param    string        URL / path to prepend full URL addressing to.
2719       * @return    string
2720       */
2721  	function locationHeaderUrl($path)    {
2722          $uI = parse_url($path);
2723          if (substr($path,0,1)=='/')    { // relative to HOST
2724              $path = t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST').$path;
2725          } elseif (!$uI['scheme'])    { // No scheme either
2726              $path = t3lib_div::getIndpEnv('TYPO3_REQUEST_DIR').$path;
2727          }
2728          return $path;
2729      }
2730  
2731  
2732  
2733  
2734  
2735  
2736  
2737  
2738  
2739  
2740  
2741  
2742  
2743  
2744  
2745  
2746      /*************************
2747       *
2748       * DEBUG helper FUNCTIONS
2749       *
2750       *************************/
2751  
2752      /**
2753       * Returns a string with a list of ascii-values for the first $characters characters in $string
2754       * Usage: 0
2755       *
2756       * @param    string        String to show ASCII value for
2757       * @param    integer        Number of characters to show
2758       * @return    string        The string with ASCII values in separated by a space char.
2759       * @internal
2760       */
2761  	function debug_ordvalue($string,$characters=100)    {
2762          if(strlen($string) < $characters)    $characters = strlen($string);
2763          for ($i=0; $i<$characters; $i++)    {
2764              $valuestring.=' '.ord(substr($string,$i,1));
2765          }
2766          return trim($valuestring);
2767      }
2768  
2769      /**
2770       * Returns HTML-code, which is a visual representation of a multidimensional array
2771       * use t3lib_div::print_array() in order to print an array
2772       * Returns false if $array_in is not an array
2773       * Usage: 31
2774       *
2775       * @param    array        Array to view
2776       * @return    string        HTML output
2777       */
2778  	function view_array($array_in)    {
2779          if (is_array($array_in))    {
2780              $result='<table border="1" cellpadding="1" cellspacing="0" bgcolor="white">';
2781              if (!count($array_in))    {$result.= '<tr><td><font face="Verdana,Arial" size="1"><b>'.htmlspecialchars("EMPTY!").'</b></font></td></tr>';}
2782              while (list($key,$val)=each($array_in))    {
2783                  $result.= '<tr><td valign="top"><font face="Verdana,Arial" size="1">'.htmlspecialchars((string)$key).'</font></td><td>';
2784                  if (is_array($array_in[$key]))    {
2785                      $result.=t3lib_div::view_array($array_in[$key]);
2786                  } else
2787                      $result.= '<font face="Verdana,Arial" size="1" color="red">'.nl2br(htmlspecialchars((string)$val)).'<br /></font>';
2788                  $result.= '</td></tr>';
2789              }
2790              $result.= '</table>';
2791          } else    {
2792              $result  = '<table border="1" cellpadding="1" cellspacing="0" bgcolor="white">
2793                  <tr>
2794                      <td><font face="Verdana,Arial" size="1" color="red">'.nl2br(htmlspecialchars((string)$array_in)).'<br /></font></td>
2795                  </tr>
2796              </table>';    // Output it as a string.
2797          }
2798          return $result;
2799      }
2800  
2801      /**
2802       * Prints an array
2803       * Usage: 6
2804       *
2805       * @param    array        Array to print visually (in a table).
2806       * @return    void
2807       * @internal
2808       * @see view_array()
2809       */
2810  	function print_array($array_in)    {
2811          echo t3lib_div::view_array($array_in);
2812      }
2813  
2814      /**
2815       * Makes debug output
2816       * Prints $var in bold between two vertical lines
2817       * If not $var the word 'debug' is printed
2818       * If $var is an array, the array is printed by t3lib_div::print_array()
2819       * Usage: 8
2820       *
2821       * @param    mixed        Variable to print
2822       * @param    mixed        If the parameter is a string it will be used as header. Otherwise number of break tags to apply after (positive integer) or before (negative integer) the output.
2823       * @return    void
2824       */
2825  	function debug($var="",$brOrHeader=0)    {
2826          if ($brOrHeader && !t3lib_div::testInt($brOrHeader))    {
2827              echo '<table class="typo3-debug" border="0" cellpadding="0" cellspacing="0" bgcolor="white" style="border:0px; margin-top:3px; margin-bottom:3px;"><tr><td style="background-color:#bbbbbb; font-family: verdana,arial; font-weight: bold; font-size: 10px;">'.htmlspecialchars((string)$brOrHeader).'</td></tr><tr><td>';
2828          } elseif ($brOrHeader<0)    {
2829              for($a=0;$a<abs(intval($brOrHeader));$a++){echo '<br />';}
2830          }
2831  
2832          if (is_array($var))    {
2833              t3lib_div::print_array($var);
2834          } elseif (is_object($var))    {
2835              echo '<b>|Object:<pre>';
2836              print_r($var);
2837              echo '</pre>|</b>';
2838          } elseif ((string)$var!='')    {
2839              echo '<b>|'.htmlspecialchars((string)$var).'|</b>';
2840          } else {
2841              echo '<b>| debug |</b>';
2842          }
2843  
2844          if ($brOrHeader && !t3lib_div::testInt($brOrHeader))    {
2845              echo '</td></tr></table>';
2846          } elseif ($brOrHeader>0)    {
2847              for($a=0;$a<intval($brOrHeader);$a++){echo '<br />';}
2848          }
2849      }
2850  
2851      /**
2852       * Displays the "path" of the function call stack in a string, using debug_backtrace
2853       *
2854       * @return    string
2855       */
2856  	function debug_trail()    {
2857          $trail = debug_backtrace();
2858          $trail = array_reverse($trail);
2859          array_pop($trail);
2860  
2861          $path = array();
2862          foreach($trail as $dat)    {
2863              $path[] = $dat['class'].$dat['type'].$dat['function'];
2864          }
2865  
2866          return implode(' // ',$path);
2867      }
2868  
2869      /**
2870       * Displays an array as rows in a table. Useful to debug output like an array of database records.
2871       *
2872       * @param    array        Array of arrays with similar keys
2873       * @param    string        Table header
2874       * @return    void        Outputs to browser.
2875       */
2876  	function debugRows($rows,$header='')    {
2877          if (is_array($rows))    {
2878              reset($rows);
2879              $firstEl = current($rows);
2880              if (is_array($firstEl))    {
2881                  $headerColumns = array_keys($firstEl);
2882                  $tRows = array();
2883  
2884                      // Header:
2885                  $tRows[] = '<tr><td colspan="'.count($headerColumns).'" style="background-color:#bbbbbb; font-family: verdana,arial; font-weight: bold; font-size: 10px;"><strong>'.htmlspecialchars($header).'</strong></td></tr>';
2886                  $tCells = array();
2887                  foreach($headerColumns as $key)    {
2888                      $tCells[] = '
2889                              <td><font face="Verdana,Arial" size="1"><strong>'.htmlspecialchars($key).'</strong></font></td>';
2890                  }
2891                  $tRows[] = '
2892                          <tr>'.implode('',$tCells).'
2893                          </tr>';
2894  
2895                      // Rows:
2896                  foreach($rows as $singleRow)    {
2897                      $tCells = array();
2898                      foreach($headerColumns as $key)    {
2899                          $tCells[] = '
2900                              <td><font face="Verdana,Arial" size="1">'.htmlspecialchars($singleRow[$key]).'</font></td>';
2901                      }
2902                      $tRows[] = '
2903                          <tr>'.implode('',$tCells).'
2904                          </tr>';
2905                  }
2906  
2907                  $table = '
2908                      <table border="1" cellpadding="1" cellspacing="0" bgcolor="white">'.implode('',$tRows).'
2909                      </table>';
2910                  echo $table;
2911              } else debug('Empty array of rows',$header);
2912          } else debug('No array of rows',$header);
2913      }
2914  
2915  
2916  
2917  
2918  
2919  
2920  
2921  
2922  
2923  
2924  
2925  
2926  
2927  
2928  
2929  
2930  
2931  
2932  
2933  
2934  
2935  
2936  
2937  
2938  
2939  
2940  
2941  
2942      /*************************
2943       *
2944       * SYSTEM INFORMATION
2945       *
2946       *************************/
2947  
2948      /**
2949       * Returns the HOST+DIR-PATH of the current script (The URL, but without 'http://' and without script-filename)
2950       * Usage: 1
2951       *
2952       * @return    string
2953       */
2954  	function getThisUrl()    {
2955          $p=parse_url(t3lib_div::getIndpEnv('TYPO3_REQUEST_SCRIPT'));        // Url of this script
2956          $dir=t3lib_div::dirname($p['path']).'/';    // Strip file
2957          $url = str_replace('//','/',$p['host'].($p['port']?':'.$p['port']:'').$dir);
2958          return $url;
2959      }
2960  
2961      /**
2962       * Returns the link-url to the current script.
2963       * In $getParams you can set associative keys corresponding to the GET-vars you wish to add to the URL. If you set them empty, they will remove existing GET-vars from the current URL.
2964       * REMEMBER to always use htmlspecialchars() for content in href-properties to get ampersands converted to entities (XHTML requirement and XSS precaution)
2965       * Usage: 52
2966       *
2967       * @param    array        Array of GET parameters to include
2968       * @return    string
2969       */
2970  	function linkThisScript($getParams=array())    {
2971          $parts = t3lib_div::getIndpEnv('SCRIPT_NAME');
2972          $params = t3lib_div::_GET();
2973  
2974          foreach($getParams as $k => $v)    {
2975              if (strcmp($v,''))    {
2976                  $params[$k]=$v;
2977              } else unset($params[$k]);
2978          }
2979  
2980          $pString = t3lib_div::implodeArrayForUrl('',$params);
2981  
2982          return $pString ? $parts.'?'.ereg_replace('^&','',$pString) : $parts;
2983      }
2984  
2985      /**
2986       * Takes a full URL, $url, possibly with a querystring and overlays the $getParams arrays values onto the quirystring, packs it all together and returns the URL again.
2987       * So basically it adds the parameters in $getParams to an existing URL, $url
2988       * Usage: 2
2989       *
2990       * @param    string        URL string
2991       * @param    array        Array of key/value pairs for get parameters to add/overrule with. Can be multidimensional.
2992       * @return    string        Output URL with added getParams.
2993       */
2994  	function linkThisUrl($url,$getParams=array())    {
2995          $parts = parse_url($url);
2996          $getP = array();
2997          if ($parts['query'])    {
2998              parse_str($parts['query'],$getP);
2999          }
3000          $getP = t3lib_div::array_merge_recursive_overrule($getP,$getParams);
3001          $uP = explode('?',$url);
3002  
3003          $params = t3lib_div::implodeArrayForUrl('',$getP);
3004          $outurl = $uP[0].($params ? '?'.substr($params, 1) : '');
3005  
3006          return $outurl;
3007      }
3008  
3009      /**
3010       * Abstraction method which returns System Environment Variables regardless of server OS, CGI/MODULE version etc. Basically this is SERVER variables for most of them.
3011       * This should be used instead of getEnv() and $_SERVER/ENV_VARS to get reliable values for all situations.
3012       * Usage: 221
3013       *
3014       * @param    string        Name of the "environment variable"/"server variable" you wish to use. Valid values are SCRIPT_NAME, SCRIPT_FILENAME, REQUEST_URI, PATH_INFO, REMOTE_ADDR, REMOTE_HOST, HTTP_REFERER, HTTP_HOST, HTTP_USER_AGENT, HTTP_ACCEPT_LANGUAGE, QUERY_STRING, TYPO3_DOCUMENT_ROOT, TYPO3_HOST_ONLY, TYPO3_HOST_ONLY, TYPO3_REQUEST_HOST, TYPO3_REQUEST_URL, TYPO3_REQUEST_SCRIPT, TYPO3_REQUEST_DIR, TYPO3_SITE_URL, _ARRAY
3015       * @return    string        Value based on the input key, independent of server/os environment.
3016       */
3017  	function getIndpEnv($getEnvName)    {
3018          /*
3019              Conventions:
3020              output from parse_url():
3021              URL:    http://username:password@192.168.1.4:8080/typo3/32/temp/phpcheck/index.php/arg1/arg2/arg3/?arg1,arg2,arg3&p1=parameter1&p2[key]=value#link1
3022                  [scheme] => 'http'
3023                  [user] => 'username'
3024                  [pass] => 'password'
3025                  [host] => '192.168.1.4'
3026                  [port] => '8080'
3027                  [path] => '/typo3/32/temp/phpcheck/index.php/arg1/arg2/arg3/'
3028                  [query] => 'arg1,arg2,arg3&p1=parameter1&p2[key]=value'
3029                  [fragment] => 'link1'
3030  
3031                  Further definition: [path_script] = '/typo3/32/temp/phpcheck/index.php'
3032                                      [path_dir] = '/typo3/32/temp/phpcheck/'
3033                                      [path_info] = '/arg1/arg2/arg3/'
3034                                      [path] = [path_script/path_dir][path_info]
3035  
3036  
3037              Keys supported:
3038  
3039              URI______:
3040                  REQUEST_URI        =    [path]?[query]        = /typo3/32/temp/phpcheck/index.php/arg1/arg2/arg3/?arg1,arg2,arg3&p1=parameter1&p2[key]=value
3041                  HTTP_HOST        =    [host][:[port]]        = 192.168.1.4:8080
3042                  SCRIPT_NAME        =    [path_script]++        = /typo3/32/temp/phpcheck/index.php        // NOTICE THAT SCRIPT_NAME will return the php-script name ALSO. [path_script] may not do that (eg. '/somedir/' may result in SCRIPT_NAME '/somedir/index.php')!
3043                  PATH_INFO        =    [path_info]            = /arg1/arg2/arg3/
3044                  QUERY_STRING    =    [query]                = arg1,arg2,arg3&p1=parameter1&p2[key]=value
3045                  HTTP_REFERER    =    [scheme]://[host][:[port]][path]    = http://192.168.1.4:8080/typo3/32/temp/phpcheck/index.php/arg1/arg2/arg3/?arg1,arg2,arg3&p1=parameter1&p2[key]=value
3046                                          (Notice: NO username/password + NO fragment)
3047  
3048              CLIENT____:
3049                  REMOTE_ADDR        =    (client IP)
3050                  REMOTE_HOST        =    (client host)
3051                  HTTP_USER_AGENT    =    (client user agent)
3052                  HTTP_ACCEPT_LANGUAGE    = (client accept language)
3053  
3054              SERVER____:
3055                  SCRIPT_FILENAME    =    Absolute filename of script        (Differs between windows/unix). On windows 'C:\\blabla\\blabl\\' will be converted to 'C:/blabla/blabl/'
3056  
3057              Special extras:
3058                  TYPO3_HOST_ONLY =        [host] = 192.168.1.4
3059                  TYPO3_PORT =            [port] = 8080 (blank if 80, taken from host value)
3060                  TYPO3_REQUEST_HOST =     [scheme]://[host][:[port]]
3061                  TYPO3_REQUEST_URL =        [scheme]://[host][:[port]][path]?[query] (scheme will by default be "http" until we can detect something different)
3062                  TYPO3_REQUEST_SCRIPT =  [scheme]://[host][:[port]][path_script]
3063                  TYPO3_REQUEST_DIR =        [scheme]://[host][:[port]][path_dir]
3064                  TYPO3_SITE_URL =         [scheme]://[host][:[port]][path_dir] of the TYPO3 website frontend
3065                  TYPO3_SITE_SCRIPT =     [script / Speaking URL] of the TYPO3 website
3066                  TYPO3_DOCUMENT_ROOT =    Absolute path of root of documents: TYPO3_DOCUMENT_ROOT.SCRIPT_NAME = SCRIPT_FILENAME (typically)
3067                  TYPO3_SSL =             Returns TRUE if this session uses SSL (HTTPS)
3068  
3069              Notice: [fragment] is apparently NEVER available to the script!
3070  
3071  
3072              Testing suggestions:
3073              - Output all the values.
3074              - In the script, make a link to the script it self, maybe add some parameters and click the link a few times so HTTP_REFERER is seen
3075              - ALSO TRY the script from the ROOT of a site (like 'http://www.mytest.com/' and not 'http://www.mytest.com/test/' !!)
3076  
3077          */
3078  
3079  #        if ($getEnvName=='HTTP_REFERER')    return '';
3080  
3081          $retVal = '';
3082  
3083          switch ((string)$getEnvName)    {
3084              case 'SCRIPT_NAME':
3085                  $retVal = (php_sapi_name()=='cgi'||php_sapi_name()=='cgi-fcgi')&&($_SERVER['ORIG_PATH_INFO']?$_SERVER['ORIG_PATH_INFO']:$_SERVER['PATH_INFO']) ? ($_SERVER['ORIG_PATH_INFO']?$_SERVER['ORIG_PATH_INFO']:$_SERVER['PATH_INFO']) : ($_SERVER['ORIG_SCRIPT_NAME']?$_SERVER['ORIG_SCRIPT_NAME']:$_SERVER['SCRIPT_NAME']);
3086              break;
3087              case 'SCRIPT_FILENAME':
3088                  $retVal = str_replace('//','/', str_replace('\\','/', (php_sapi_name()=='cgi'||php_sapi_name()=='isapi' ||php_sapi_name()=='cgi-fcgi')&&($_SERVER['ORIG_PATH_TRANSLATED']?$_SERVER['ORIG_PATH_TRANSLATED']:$_SERVER['PATH_TRANSLATED'])? ($_SERVER['ORIG_PATH_TRANSLATED']?$_SERVER['ORIG_PATH_TRANSLATED']:$_SERVER['PATH_TRANSLATED']):($_SERVER['ORIG_SCRIPT_FILENAME']?$_SERVER['ORIG_SCRIPT_FILENAME']:$_SERVER['SCRIPT_FILENAME'])));
3089              break;
3090              case 'REQUEST_URI':
3091                      // Typical application of REQUEST_URI is return urls, forms submitting to itself etc. Example: returnUrl='.rawurlencode(t3lib_div::getIndpEnv('REQUEST_URI'))
3092                  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['requestURIvar'])    {    // This is for URL rewriters that store the original URI in a server variable (eg ISAPI_Rewriter for IIS: HTTP_X_REWRITE_URL)
3093                      list($v,$n) = explode('|',$GLOBALS['TYPO3_CONF_VARS']['SYS']['requestURIvar']);
3094                      $retVal = $GLOBALS[$v][$n];
3095                  } elseif (!$_SERVER['REQUEST_URI'])    {    // This is for ISS/CGI which does not have the REQUEST_URI available.
3096                      $retVal = '/'.ereg_replace('^/','',t3lib_div::getIndpEnv('SCRIPT_NAME')).
3097                          ($_SERVER['QUERY_STRING']?'?'.$_SERVER['QUERY_STRING']:'');
3098                  } else $retVal = $_SERVER['REQUEST_URI'];
3099              break;
3100              case 'PATH_INFO':
3101                      // $_SERVER['PATH_INFO']!=$_SERVER['SCRIPT_NAME'] is necessary because some servers (Windows/CGI) are seen to set PATH_INFO equal to script_name
3102                      // Further, there must be at least one '/' in the path - else the PATH_INFO value does not make sense.
3103                      // IF 'PATH_INFO' never works for our purpose in TYPO3 with CGI-servers, then 'php_sapi_name()=='cgi'' might be a better check. Right now strcmp($_SERVER['PATH_INFO'],t3lib_div::getIndpEnv('SCRIPT_NAME')) will always return false for CGI-versions, but that is only as long as SCRIPT_NAME is set equal to PATH_INFO because of php_sapi_name()=='cgi' (see above)
3104  //                if (strcmp($_SERVER['PATH_INFO'],t3lib_div::getIndpEnv('SCRIPT_NAME')) && count(explode('/',$_SERVER['PATH_INFO']))>1)    {
3105                  if (php_sapi_name()!='cgi'&&php_sapi_name()!='cgi-fcgi')    {
3106                      $retVal = $_SERVER['PATH_INFO'];
3107                  }
3108              break;
3109                  // These are let through without modification
3110              case 'REMOTE_ADDR':
3111              case 'REMOTE_HOST':
3112              case 'HTTP_REFERER':
3113              case 'HTTP_HOST':
3114              case 'HTTP_USER_AGENT':
3115              case 'HTTP_ACCEPT_ENCODING':
3116              case 'HTTP_ACCEPT_LANGUAGE':
3117              case 'QUERY_STRING':
3118                  $retVal = $_SERVER[$getEnvName];
3119              break;
3120              case 'TYPO3_DOCUMENT_ROOT':
3121                  // Some CGI-versions (LA13CGI) and mod-rewrite rules on MODULE versions will deliver a 'wrong' DOCUMENT_ROOT (according to our description). Further various aliases/mod_rewrite rules can disturb this as well.
3122                  // Therefore the DOCUMENT_ROOT is now always calculated as the SCRIPT_FILENAME minus the end part shared with SCRIPT_NAME.
3123                  $SFN = t3lib_div::getIndpEnv('SCRIPT_FILENAME');
3124                  $SN_A = explode('/',strrev(t3lib_div::getIndpEnv('SCRIPT_NAME')));
3125                  $SFN_A = explode('/',strrev($SFN));
3126                  $acc = array();
3127                  while(list($kk,$vv)=each($SN_A))    {
3128                      if (!strcmp($SFN_A[$kk],$vv))    {
3129                          $acc[] = $vv;
3130                      } else break;
3131                  }
3132                  $commonEnd=strrev(implode('/',$acc));
3133                  if (strcmp($commonEnd,''))    { $DR = substr($SFN,0,-(strlen($commonEnd)+1)); }
3134                  $retVal = $DR;
3135              break;
3136              case 'TYPO3_HOST_ONLY':
3137                  $p = explode(':',$_SERVER['HTTP_HOST']);
3138                  $retVal = $p[0];
3139              break;
3140              case 'TYPO3_PORT':
3141                  $p = explode(':',$_SERVER['HTTP_HOST']);
3142                  $retVal = $p[1];
3143              break;
3144              case 'TYPO3_REQUEST_HOST':
3145                  $retVal = (t3lib_div::getIndpEnv('TYPO3_SSL') ? 'https://' : 'http://').
3146                      $_SERVER['HTTP_HOST'];
3147              break;
3148              case 'TYPO3_REQUEST_URL':
3149                  $retVal = t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST').t3lib_div::getIndpEnv('REQUEST_URI');
3150              break;
3151              case 'TYPO3_REQUEST_SCRIPT':
3152                  $retVal = t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST').t3lib_div::getIndpEnv('SCRIPT_NAME');
3153              break;
3154              case 'TYPO3_REQUEST_DIR':
3155                  $retVal = t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST').t3lib_div::dirname(t3lib_div::getIndpEnv('SCRIPT_NAME')).'/';
3156              break;
3157              case 'TYPO3_SITE_URL':
3158                  if (defined('PATH_thisScript') && defined('PATH_site'))    {
3159                      $lPath = substr(dirname(PATH_thisScript),strlen(PATH_site)).'/';
3160                      $url = t3lib_div::getIndpEnv('TYPO3_REQUEST_DIR');
3161                      $siteUrl = substr($url,0,-strlen($lPath));
3162                      if (substr($siteUrl,-1)!='/')    $siteUrl.='/';
3163                      $retVal = $siteUrl;
3164                  }
3165              break;
3166              case 'TYPO3_SITE_SCRIPT':
3167                  $retVal = substr(t3lib_div::getIndpEnv('TYPO3_REQUEST_URL'),strlen(t3lib_div::getIndpEnv('TYPO3_SITE_URL')));
3168              break;
3169              case 'TYPO3_SSL':
3170                  $retVal = $_SERVER['SSL_SESSION_ID'] || !strcmp($_SERVER['HTTPS'],'on') || !strcmp($_SERVER['HTTPS'],'1') ? TRUE : FALSE;    // see http://bugs.typo3.org/view.php?id=3909
3171              break;
3172              case '_ARRAY':
3173                  $out = array();
3174                      // Here, list ALL possible keys to this function for debug display.
3175                  $envTestVars = t3lib_div::trimExplode(',','
3176                      HTTP_HOST,
3177                      TYPO3_HOST_ONLY,
3178                      TYPO3_PORT,
3179                      PATH_INFO,
3180                      QUERY_STRING,
3181                      REQUEST_URI,
3182                      HTTP_REFERER,
3183                      TYPO3_REQUEST_HOST,
3184                      TYPO3_REQUEST_URL,
3185                      TYPO3_REQUEST_SCRIPT,
3186                      TYPO3_REQUEST_DIR,
3187                      TYPO3_SITE_URL,
3188                      TYPO3_SITE_SCRIPT,
3189                      TYPO3_SSL,
3190                      SCRIPT_NAME,
3191                      TYPO3_DOCUMENT_ROOT,
3192                      SCRIPT_FILENAME,
3193                      REMOTE_ADDR,
3194                      REMOTE_HOST,
3195                      HTTP_USER_AGENT,
3196                      HTTP_ACCEPT_LANGUAGE',1);
3197                  reset($envTestVars);
3198                  while(list(,$v)=each($envTestVars))    {
3199                      $out[$v]=t3lib_div::getIndpEnv($v);
3200                  }
3201                  reset($out);
3202                  $retVal = $out;
3203              break;
3204          }
3205          return $retVal;
3206      }
3207  
3208      /**
3209       * milliseconds
3210       * microtime recalculated to t3lib_div::milliseconds(1/1000 sec)
3211       * Usage: 20
3212       *
3213       * @return    integer
3214       */
3215  	function milliseconds()    {
3216          $p=explode(' ',microtime());
3217          return round(($p[0]+$p[1])*1000);
3218      }
3219  
3220      /**
3221       * Client Browser Information
3222       * Usage: 4
3223       *
3224       * @param    string        Alternative User Agent string (if empty, t3lib_div::getIndpEnv('HTTP_USER_AGENT') is used)
3225       * @return    array        Parsed information about the HTTP_USER_AGENT in categories BROWSER, VERSION, SYSTEM and FORMSTYLE
3226       */
3227  	function clientInfo($useragent='')    {
3228          if (!$useragent) $useragent=t3lib_div::getIndpEnv('HTTP_USER_AGENT');
3229  
3230          $bInfo=array();
3231              // Which browser?
3232          if (strstr($useragent,'Konqueror'))    {
3233              $bInfo['BROWSER']= 'konqu';
3234          } elseif (strstr($useragent,'Opera'))    {
3235              $bInfo['BROWSER']= 'opera';
3236          } elseif (preg_match('/MSIE [4567]/', $useragent))    {
3237              $bInfo['BROWSER']= 'msie';
3238          } elseif (strstr($useragent,'Mozilla/4') || strstr($useragent,'Mozilla/5'))    {
3239              $bInfo['BROWSER']='net';
3240          }
3241          if ($bInfo['BROWSER'])    {
3242                  // Browser version
3243              switch($bInfo['BROWSER'])    {
3244                  case 'net':
3245                      $bInfo['VERSION']= doubleval(substr($useragent,8));
3246                      if (strstr($useragent,'Netscape6/')) {$bInfo['VERSION'] = doubleval(substr(strstr($useragent,'Netscape6/'),10));}    // Will we ever know if this was a typo or intention...?! :-(
3247                      if (strstr($useragent,'Netscape/6')) {$bInfo['VERSION'] = doubleval(substr(strstr($useragent,'Netscape/6'),10));}
3248                      if (strstr($useragent,'Netscape/7')) {$bInfo['VERSION']=doubleval(substr(strstr($useragent,'Netscape/7'),9));}
3249                  break;
3250                  case 'msie':
3251                      $tmp = strstr($useragent,'MSIE');
3252                      $bInfo['VERSION'] = doubleval(ereg_replace('^[^0-9]*','',substr($tmp,4)));
3253                  break;
3254                  case 'opera':
3255                      $tmp = strstr($useragent,'Opera');
3256                      $bInfo['VERSION'] = doubleval(ereg_replace('^[^0-9]*','',substr($tmp,5)));
3257                  break;
3258                  case 'konqu':
3259                      $tmp = strstr($useragent,'Konqueror/');
3260                      $bInfo['VERSION'] = doubleval(substr($tmp,10));
3261                  break;
3262              }
3263                  // Client system
3264              if (strstr($useragent,'Win'))    {
3265                  $bInfo['SYSTEM'] = 'win';
3266              } elseif (strstr($useragent,'Mac'))    {
3267                  $bInfo['SYSTEM'] = 'mac';
3268              } elseif (strstr($useragent,'Linux') || strstr($useragent,'X11') || strstr($useragent,'SGI') || strstr($useragent,' SunOS ') || strstr($useragent,' HP-UX '))    {
3269                  $bInfo['SYSTEM'] = 'unix';
3270              }
3271          }
3272              // Is true if the browser supports css to format forms, especially the width
3273          $bInfo['FORMSTYLE']=($bInfo['BROWSER']=='msie' || ($bInfo['BROWSER']=='net'&&$bInfo['VERSION']>=5) || $bInfo['BROWSER']=='opera' || $bInfo['BROWSER']=='konqu');
3274  
3275          return $bInfo;
3276      }
3277  
3278      /**
3279       * Get the fully-qualified domain name of the host.
3280       * Usage: 2
3281       *
3282       * @param    boolean        Use request host (when not in CLI mode).
3283       * @return    string        The fully-qualified host name.
3284       */
3285  	function getHostname($requestHost=TRUE)    {
3286          $host = '';
3287          if ($requestHost && (!defined('TYPO3_cliMode') || !TYPO3_cliMode))    {
3288              $host = t3lib_div::getIndpEnv('HTTP_HOST');
3289          }
3290          if (!$host)    {
3291                  // will fail for PHP 4.1 and 4.2
3292              $host = @php_uname('n');
3293                  // 'n' is ignored in broken installations
3294              if (strpos($host, ' '))    $host = '';
3295          }
3296              // we have not found a FQDN yet
3297          if ($host && strpos('.',$host) === FALSE)    {
3298              $ip = gethostbyname($host);
3299                  // we got an IP address
3300              if ($ip != $host)    {
3301                  $fqdn = gethostbyaddr($ip);
3302                  if ($ip != $fqdn)    $host = $fqdn;
3303              }
3304          }
3305          if (!$host)    $host = 'localhost.localdomain';
3306  
3307          return $host;
3308      }
3309  
3310  
3311  
3312  
3313  
3314  
3315  
3316  
3317  
3318  
3319  
3320  
3321  
3322  
3323  
3324  
3325  
3326  
3327  
3328  
3329  
3330  
3331      /*************************
3332       *
3333       * TYPO3 SPECIFIC FUNCTIONS
3334       *
3335       *************************/
3336  
3337      /**
3338       * Returns the absolute filename of a relative reference, resolves the "EXT:" prefix (way of referring to files inside extensions) and checks that the file is inside the PATH_site of the TYPO3 installation and implies a check with t3lib_div::validPathStr(). Returns false if checks failed. Does not check if the file exists.
3339       * Usage: 24
3340       *
3341       * @param    string        The input filename/filepath to evaluate
3342       * @param    boolean        If $onlyRelative is set (which it is by default), then only return values relative to the current PATH_site is accepted.
3343       * @param    boolean        If $relToTYPO3_mainDir is set, then relative paths are relative to PATH_typo3 constant - otherwise (default) they are relative to PATH_site
3344       * @return    string        Returns the absolute filename of $filename IF valid, otherwise blank string.
3345       */
3346  	function getFileAbsFileName($filename,$onlyRelative=1,$relToTYPO3_mainDir=0)    {
3347          if (!strcmp($filename,''))        return '';
3348  
3349          if ($relToTYPO3_mainDir)    {
3350              if (!defined('PATH_typo3'))    return '';
3351              $relPathPrefix = PATH_typo3;
3352          } else {
3353              $relPathPrefix = PATH_site;
3354          }
3355          if (substr($filename,0,4)=='EXT:')    {    // extension
3356              list($extKey,$local) = explode('/',substr($filename,4),2);
3357              $filename='';
3358              if (strcmp($extKey,'') && t3lib_extMgm::isLoaded($extKey) && strcmp($local,''))    {
3359                  $filename = t3lib_extMgm::extPath($extKey).$local;
3360              }
3361          } elseif (!t3lib_div::isAbsPath($filename))    {    // relative. Prepended with $relPathPrefix
3362              $filename=$relPathPrefix.$filename;
3363          } elseif ($onlyRelative && !t3lib_div::isFirstPartOfStr($filename,$relPathPrefix)) {    // absolute, but set to blank if not allowed
3364              $filename='';
3365          }
3366          if (strcmp($filename,'') && t3lib_div::validPathStr($filename))    {    // checks backpath.
3367              return $filename;
3368          }
3369      }
3370  
3371      /**
3372       * Checks for malicious file paths.
3373       * Returns true if no '//', '..' or '\' is in the $theFile
3374       * This should make sure that the path is not pointing 'backwards' and further doesn't contain double/back slashes.
3375       * So it's compatible with the UNIX style path strings valid for TYPO3 internally.
3376       * Usage: 14
3377       *
3378       * @param    string        Filepath to evaluate
3379       * @return    boolean        True, if no '//', '\', '/../' is in the $theFile and $theFile doesn't begin with '../'
3380       * @todo    Possible improvement: Should it rawurldecode the string first to check if any of these characters is encoded ?
3381       */
3382  	function validPathStr($theFile)    {
3383          if (!strstr($theFile,'//') && !strstr($theFile,'\\') && !preg_match('#(?:^\.\.|/\.\./)#',$theFile))    return true;
3384      }
3385  
3386      /**
3387       * Checks if the $path is absolute or relative (detecting either '/' or 'x:/' as first part of string) and returns true if so.
3388       * Usage: 8
3389       *
3390       * @param    string        Filepath to evaluate
3391       * @return    boolean
3392       */
3393  	function isAbsPath($path)    {
3394          return TYPO3_OS=='WIN' ? substr($path,1,2)==':/' :  substr($path,0,1)=='/';
3395      }
3396  
3397      /**
3398       * Returns true if the path is absolute, without backpath '..' and within the PATH_site OR within the lockRootPath
3399       * Usage: 5
3400       *
3401       * @param    string        Filepath to evaluate
3402       * @return    boolean
3403       */
3404  	function isAllowedAbsPath($path)    {
3405          if (t3lib_div::isAbsPath($path) &&
3406              t3lib_div::validPathStr($path) &&
3407                  (    t3lib_div::isFirstPartOfStr($path,PATH_site)
3408                      ||
3409                      ($GLOBALS['TYPO3_CONF_VARS']['BE']['lockRootPath'] && t3lib_div::isFirstPartOfStr($path,$GLOBALS['TYPO3_CONF_VARS']['BE']['lockRootPath']))
3410                  )
3411              )    return true;
3412      }
3413  
3414      /**
3415       * Verifies the input filename againts the 'fileDenyPattern'. Returns true if OK.
3416       * Usage: 2
3417       *
3418       * @param    string        Filepath to evaluate
3419       * @return    boolean
3420       */
3421  	function verifyFilenameAgainstDenyPattern($filename)    {
3422          if (strcmp($filename,'') && strcmp($GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'],''))    {
3423              $result = eregi($GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'],$filename);
3424              if ($result)    return false;    // so if a matching filename is found, return false;
3425          }
3426          return true;
3427      }
3428  
3429      /**
3430       * Moves $source file to $destination if uploaded, otherwise try to make a copy
3431       * Usage: 4
3432       *
3433       * @param    string        Source file, absolute path
3434       * @param    string        Destination file, absolute path
3435       * @return    boolean        Returns true if the file was moved.
3436       * @coauthor    Dennis Petersen <fessor@software.dk>
3437       * @see upload_to_tempfile()
3438       */
3439  	function upload_copy_move($source,$destination)    {
3440          if (is_uploaded_file($source))    {
3441              $uploaded = TRUE;
3442              // Return the value of move_uploaded_file, and if false the temporary $source is still around so the user can use unlink to delete it:
3443              $uploadedResult = move_uploaded_file($source, $destination);
3444          } else {
3445              $uploaded = FALSE;
3446              @copy($source,$destination);
3447          }
3448  
3449          t3lib_div::fixPermissions($destination);    // Change the permissions of the file
3450  
3451              // If here the file is copied and the temporary $source is still around, so when returning false the user can try unlink to delete the $source
3452          return $uploaded ? $uploadedResult : FALSE;
3453      }
3454  
3455      /**
3456       * Will move an uploaded file (normally in "/tmp/xxxxx") to a temporary filename in PATH_site."typo3temp/" from where TYPO3 can use it under safe_mode.
3457       * Use this function to move uploaded files to where you can work on them.
3458       * REMEMBER to use t3lib_div::unlink_tempfile() afterwards - otherwise temp-files will build up! They are NOT automatically deleted in PATH_site."typo3temp/"!
3459       * Usage: 6
3460       *
3461       * @param    string        The temporary uploaded filename, eg. $_FILES['[upload field name here]']['tmp_name']
3462       * @return    string        If a new file was successfully created, return its filename, otherwise blank string.
3463       * @see unlink_tempfile(), upload_copy_move()
3464       */
3465  	function upload_to_tempfile($uploadedFileName)    {
3466          if (is_uploaded_file($uploadedFileName))    {
3467              $tempFile = t3lib_div::tempnam('upload_temp_');
3468              move_uploaded_file($uploadedFileName, $tempFile);
3469              return @is_file($tempFile) ? $tempFile : '';
3470          }
3471      }
3472  
3473      /**
3474       * Deletes (unlink) a temporary filename in 'PATH_site."typo3temp/"' given as input.
3475       * The function will check that the file exists, is in PATH_site."typo3temp/" and does not contain back-spaces ("../") so it should be pretty safe.
3476       * Use this after upload_to_tempfile() or tempnam() from this class!
3477       * Usage: 9
3478       *
3479       * @param    string        Filepath for a file in PATH_site."typo3temp/". Must be absolute.
3480       * @return    boolean        Returns true if the file was unlink()'ed
3481       * @see upload_to_tempfile(), tempnam()
3482       */
3483  	function unlink_tempfile($uploadedTempFileName)    {
3484          if ($uploadedTempFileName && t3lib_div::validPathStr($uploadedTempFileName) && t3lib_div::isFirstPartOfStr($uploadedTempFileName,PATH_site.'typo3temp/') && @is_file($uploadedTempFileName))    {
3485              if (unlink($uploadedTempFileName))    return TRUE;
3486          }
3487      }
3488  
3489      /**
3490       * Create temporary filename (Create file with unique file name)
3491       * This function should be used for getting temporary filenames - will make your applications safe for open_basedir = on
3492       * REMEMBER to delete the temporary files after use! This is done by t3lib_div::unlink_tempfile()
3493       * Usage: 7
3494       *
3495       * @param    string        Prefix to temp file (which will have no extension btw)
3496       * @return    string        result from PHP function tempnam() with PATH_site.'typo3temp/' set for temp path.
3497       * @see unlink_tempfile(), upload_to_tempfile()
3498       */
3499  	function tempnam($filePrefix)    {
3500          return tempnam(PATH_site.'typo3temp/',$filePrefix);
3501      }
3502  
3503      /**
3504       * Standard authentication code (used in Direct Mail, checkJumpUrl and setfixed links computations)
3505       * Usage: 2
3506       *
3507       * @param    mixed        Uid (integer) or record (array)
3508       * @param    string        List of fields from the record if that is given.
3509       * @param    integer        Length of returned authentication code.
3510       * @return    string        MD5 hash of 8 chars.
3511       * @internal
3512       */
3513  	function stdAuthCode($uid_or_record,$fields='',$codeLength=8)    {
3514  
3515          if (is_array($uid_or_record))    {
3516              $recCopy_temp=array();
3517              if ($fields)    {
3518                  $fieldArr = t3lib_div::trimExplode(',',$fields,1);
3519                  reset($fieldArr);
3520                  while(list($k,$v)=each($fieldArr))    {
3521                      $recCopy_temp[$k]=$uid_or_record[$v];
3522                  }
3523              } else {
3524                  $recCopy_temp=$uid_or_record;
3525              }
3526              $preKey = implode('|',$recCopy_temp);
3527          } else {
3528              $preKey = $uid_or_record;
3529          }
3530  
3531          $authCode = $preKey.'||'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
3532          $authCode = substr(md5($authCode),0,$codeLength);
3533          return $authCode;
3534      }
3535  
3536      /**
3537       * Splits the input query-parameters into an array with certain parameters filtered out.
3538       * Used to create the cHash value
3539       *
3540       * @param    string        Query-parameters: "&xxx=yyy&zzz=uuu"
3541       * @return    array        Array with key/value pairs of query-parameters WITHOUT a certain list of variable names (like id, type, no_cache etc.) and WITH a variable, encryptionKey, specific for this server/installation
3542       * @see tslib_fe::makeCacheHash(), tslib_cObj::typoLink()
3543       */
3544  	function cHashParams($addQueryParams) {
3545          $params = explode('&',substr($addQueryParams,1));    // Splitting parameters up
3546  
3547              // Make array:
3548          $pA = array();
3549          foreach($params as $theP)    {
3550              $pKV = explode('=', $theP);    // Splitting single param by '=' sign
3551              if (!t3lib_div::inList('id,type,no_cache,cHash,MP,ftu',$pKV[0]) && !preg_match('/TSFE_ADMIN_PANEL\[.*?\]/',$pKV[0]))    {
3552                  $pA[rawurldecode($pKV[0])] = (string)rawurldecode($pKV[1]);
3553              }
3554          }
3555          $pA['encryptionKey'] = $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
3556          ksort($pA);
3557  
3558          return $pA;
3559      }
3560  
3561      /**
3562       * Responds on input localization setting value whether the page it comes from should be hidden if no translation exists or not.
3563       *
3564       * @param    integer        Value from "l18n_cfg" field of a page record
3565       * @return    boolean        True if the page should be hidden
3566       */
3567  	function hideIfNotTranslated($l18n_cfg_fieldValue)    {
3568          if ($GLOBALS['TYPO3_CONF_VARS']['FE']['hidePagesIfNotTranslatedByDefault'])    {
3569              return $l18n_cfg_fieldValue&2 ? FALSE : TRUE;
3570          } else {
3571              return $l18n_cfg_fieldValue&2 ? TRUE : FALSE;
3572          }
3573      }
3574  
3575      /**
3576       * Includes a locallang file and returns the $LOCAL_LANG array found inside.
3577       *
3578       * @param    string        Input is a file-reference (see t3lib_div::getFileAbsFileName) which, if exists, is included. That file is expected to be a 'local_lang' file containing a $LOCAL_LANG array.
3579       * @param    string        Language key
3580       * @return    array        Value of $LOCAL_LANG found in the included file. If that array is found it's returned. Otherwise an empty array
3581       */
3582  	function readLLfile($fileRef,$langKey)    {
3583  
3584          $file = t3lib_div::getFileAbsFileName($fileRef);
3585          if ($file)    {
3586              $baseFile = ereg_replace('\.(php|xml)$', '', $file);
3587  
3588              if (@is_file($baseFile.'.xml'))    {
3589                  $LOCAL_LANG = t3lib_div::readLLXMLfile($baseFile.'.xml', $langKey);
3590              } elseif (@is_file($baseFile.'.php'))    {
3591                  include($baseFile.'.php');
3592              } else die('Filereference, "'.$file.'", not found!');
3593          }
3594  
3595          return is_array($LOCAL_LANG)?$LOCAL_LANG:array();
3596      }
3597  
3598      /**
3599       * Includes a locallang-xml file and returns the $LOCAL_LANG array
3600       * Works only when the frontend or backend has been initialized with a charset conversion object. See first code lines.
3601       *
3602       * @param    string        Absolute reference to locallang-XML file
3603       * @param    string        TYPO3 language key, eg. "dk" or "de" or "default"
3604       * @return    array        LOCAL_LANG array in return.
3605       */
3606  	function readLLXMLfile($fileRef,$langKey)    {
3607  
3608          if (is_object($GLOBALS['LANG']))    {
3609              $csConvObj = &$GLOBALS['LANG']->csConvObj;
3610          } elseif (is_object($GLOBALS['TSFE']))    {
3611              $csConvObj = &$GLOBALS['TSFE']->csConvObj;
3612          } else $csConvObj = NULL;
3613  
3614          if (@is_file($fileRef) && $langKey && is_object($csConvObj))    {
3615  
3616                  // Set charset:
3617              $origCharset = $csConvObj->parse_charset($csConvObj->charSetArray[$langKey] ? $csConvObj->charSetArray[$langKey] : 'iso-8859-1');
3618  
3619                  // Cache file name:
3620              $hashSource = substr($fileRef,strlen(PATH_site)).'|'.date('d-m-Y H:i:s',filemtime($fileRef)).'|version=2.2';
3621              $cacheFileName = PATH_site.'typo3temp/llxml/'.
3622                              #str_replace('_','',ereg_replace('^.*\/','',dirname($fileRef))).
3623                              #'_'.basename($fileRef).
3624                              substr(basename($fileRef),10,15).
3625                              '_'.t3lib_div::shortMD5($hashSource).'.'.$langKey.'.'.$origCharset.'.cache';
3626  
3627                  // Check if cache file exists...
3628              if (!@is_file($cacheFileName))    {    // ... if it doesn't, create content and write it:
3629  
3630                      // Read XML, parse it.
3631                  $xmlString = t3lib_div::getUrl($fileRef);
3632                  $xmlContent = t3lib_div::xml2array($xmlString);
3633                  if (!is_array($xmlContent))    {
3634                      die($fileRef.' was not XML!: '.$xmlContent);
3635                  }
3636  
3637                      // Set default LOCAL_LANG array content:
3638                  $LOCAL_LANG = array();
3639                  $LOCAL_LANG['default'] = $xmlContent['data']['default'];
3640  
3641                      // Converting charset of default language from utf-8 to iso-8859-1 (since that is what the system would expect for default langauge in the core due to historical reasons)
3642                      // This conversion is unneccessary for 99,99% of all default labels since they are in english, therefore ASCII.
3643                      // However, an extension like TemplaVoila uses an extended character in its name, even in Default language. To accommodate that (special chars for default) this conversion must be made.
3644                      // Since the output from this function is probably always cached it is considered insignificant to do this conversion.
3645                      // - kasper
3646                  if (is_array($LOCAL_LANG['default']))    {
3647                      foreach($LOCAL_LANG['default'] as $labelKey => $labelValue)    {
3648                          $LOCAL_LANG['default'][$labelKey] = $csConvObj->utf8_decode($labelValue,'iso-8859-1');
3649                      }
3650                  }
3651  
3652                      // Specific language, convert from utf-8 to backend language charset:
3653                      // NOTICE: Converting from utf-8 back to "native" language may be a temporary solution until we can totally discard "locallang.php" files altogether (and use utf-8 for everything). But doing this conversion is the quickest way to migrate now and the source is in utf-8 anyway which is the main point.
3654                  if ($langKey!='default')    {
3655  
3656                          // If no entry is found for the language key, then force a value depending on meta-data setting. By default an automated filename will be used:
3657                      if (!isset($xmlContent['data'][$langKey]))    {
3658                          $LOCAL_LANG[$langKey] = t3lib_div::llXmlAutoFileName($fileRef, $langKey);
3659                      } else {
3660                          $LOCAL_LANG[$langKey] = $xmlContent['data'][$langKey];
3661                      }
3662  
3663                          // Checking if charset should be converted.
3664                      if (is_array($LOCAL_LANG[$langKey]) && $origCharset!='utf-8')    {
3665                          foreach($LOCAL_LANG[$langKey] as $labelKey => $labelValue)    {
3666                              $LOCAL_LANG[$langKey][$labelKey] = $csConvObj->utf8_decode($labelValue,$origCharset);
3667                          }
3668                      }
3669                  }
3670  
3671                      // Cache the content now:
3672                  $serContent = array('origFile'=>$hashSource, 'LOCAL_LANG'=>$LOCAL_LANG);
3673                  $res = t3lib_div::writeFileToTypo3tempDir($cacheFileName, serialize($serContent));
3674                  if ($res)    die('ERROR: '.$res);
3675              } else {
3676                      // Get content from cache:
3677                  $serContent = unserialize(t3lib_div::getUrl($cacheFileName));
3678                  $LOCAL_LANG = $serContent['LOCAL_LANG'];
3679              }
3680  
3681                  // Checking for EXTERNAL file for non-default language:
3682              if ($langKey!='default' && is_string($LOCAL_LANG[$langKey]) && strlen($LOCAL_LANG[$langKey]))    {
3683  
3684                      // Look for localized file:
3685                  $localized_file = t3lib_div::getFileAbsFileName($LOCAL_LANG[$langKey]);
3686                  if ($localized_file && @is_file($localized_file))    {
3687  
3688                          // Cache file name:
3689                      $hashSource = substr($localized_file,strlen(PATH_site)).'|'.date('d-m-Y H:i:s',filemtime($localized_file));
3690                      $cacheFileName = PATH_site.'typo3temp/llxml/ext_'.
3691                                      substr(basename($localized_file),10,15).
3692                                      '_'.t3lib_div::shortMD5($hashSource).'.'.$langKey.'.'.$origCharset.'.cache';
3693  
3694                          // Check if cache file exists...
3695                      if (!@is_file($cacheFileName))    {    // ... if it doesn't, create content and write it:
3696  
3697                              // Read and parse XML content:
3698                          $local_xmlString = t3lib_div::getUrl($localized_file);
3699                          $local_xmlContent = t3lib_div::xml2array($local_xmlString);
3700                          $LOCAL_LANG[$langKey] = is_array($local_xmlContent['data'][$langKey]) ? $local_xmlContent['data'][$langKey] : array();
3701  
3702                              // Checking if charset should be converted.
3703                          if (is_array($LOCAL_LANG[$langKey]) && $origCharset!='utf-8')    {
3704                              foreach($LOCAL_LANG[$langKey] as $labelKey => $labelValue)    {
3705                                  $LOCAL_LANG[$langKey][$labelKey] = $csConvObj->utf8_decode($labelValue,$origCharset);
3706                              }
3707                          }
3708  
3709                              // Cache the content now:
3710                          $serContent = array('extlang'=>$langKey, 'origFile'=>$LOCAL_LANG[$langKey], 'EXT_DATA'=>$LOCAL_LANG[$langKey]);
3711                          $res = t3lib_div::writeFileToTypo3tempDir($cacheFileName, serialize($serContent));
3712                          if ($res)    die('ERROR: '.$res);
3713                      } else {
3714                              // Get content from cache:
3715                          $serContent = unserialize(t3lib_div::getUrl($cacheFileName));
3716                          $LOCAL_LANG[$langKey] = $serContent['EXT_DATA'];
3717                      }
3718                  } else {
3719                      $LOCAL_LANG[$langKey] = array();
3720                  }
3721              }
3722  
3723              return $LOCAL_LANG;
3724          }
3725      }
3726  
3727      /**
3728       * Returns auto-filename for locallang-XML localizations.
3729       *
3730       * @param    string        Absolute file reference to locallang-XML file. Must be inside system/global/local extension
3731       * @param    string        Language key
3732       * @return    string        Returns the filename reference for the language unless error occured (or local mode is used) in which case it will be NULL
3733       */
3734  	function llXmlAutoFileName($fileRef,$language)    {
3735              // Analyse file reference:
3736          $location = 'typo3conf/l10n/'.$language.'/';    // Default location of translations
3737          if (t3lib_div::isFirstPartOfStr($fileRef,PATH_typo3.'sysext/'))    {    // Is system:
3738              $validatedPrefix = PATH_typo3.'sysext/';
3739              #$location = 'EXT:csh_'.$language.'/';    // For system extensions translations are found in "csh_*" extensions (language packs)
3740          } elseif (t3lib_div::isFirstPartOfStr($fileRef,PATH_typo3.'ext/'))    {    // Is global:
3741              $validatedPrefix = PATH_typo3.'ext/';
3742          } elseif (t3lib_div::isFirstPartOfStr($fileRef,PATH_typo3conf.'ext/'))    {    // Is local:
3743              $validatedPrefix = PATH_typo3conf.'ext/';
3744          } else {
3745              $validatedPrefix = '';
3746          }
3747  
3748          if ($validatedPrefix)    {
3749  
3750                  // Divide file reference into extension key, directory (if any) and base name:
3751              list($file_extKey,$file_extPath) = explode('/',substr($fileRef,strlen($validatedPrefix)),2);
3752              $temp = t3lib_div::revExplode('/',$file_extPath,2);
3753              if (count($temp)==1)    array_unshift($temp,'');    // Add empty first-entry if not there.
3754              list($file_extPath,$file_fileName) = $temp;
3755  
3756                  // The filename is prefixed with "[language key]." because it prevents the llxmltranslate tool from detecting it.
3757              return $location.
3758                  $file_extKey.'/'.
3759                  ($file_extPath?$file_extPath.'/':'').
3760                  $language.'.'.$file_fileName;
3761          } else return NULL;
3762      }
3763  
3764  
3765      /**
3766       * Loads the $TCA (Table Configuration Array) for the $table
3767       *
3768       * Requirements:
3769       * 1) must be configured table (the ctrl-section configured),
3770       * 2) columns must not be an array (which it is always if whole table loaded), and
3771       * 3) there is a value for dynamicConfigFile (filename in typo3conf)
3772       *
3773       * Note: For the frontend this loads only 'ctrl' and 'feInterface' parts.
3774       * For complete TCA use $GLOBALS['TSFE']->includeTCA() instead.
3775       *
3776       * Usage: 84
3777       *
3778       * @param    string        Table name for which to load the full TCA array part into the global $TCA
3779       * @return    void
3780       */
3781  	function loadTCA($table)    {
3782          global $TCA,$LANG_GENERAL_LABELS;
3783          if (isset($TCA[$table]) && !is_array($TCA[$table]['columns']) && $TCA[$table]['ctrl']['dynamicConfigFile'])    {
3784              if (!strcmp(substr($TCA[$table]['ctrl']['dynamicConfigFile'],0,6),'T3LIB:'))    {
3785                  include(PATH_t3lib.'stddb/'.substr($TCA[$table]['ctrl']['dynamicConfigFile'],6));
3786              } elseif (t3lib_div::isAbsPath($TCA[$table]['ctrl']['dynamicConfigFile']) && @is_file($TCA[$table]['ctrl']['dynamicConfigFile']))    {    // Absolute path...
3787                  include($TCA[$table]['ctrl']['dynamicConfigFile']);
3788              } else include(PATH_typo3conf.$TCA[$table]['ctrl']['dynamicConfigFile']);
3789          }
3790      }
3791  
3792      /**
3793       * Looks for a sheet-definition in the input data structure array. If found it will return the data structure for the sheet given as $sheet (if found).
3794       * If the sheet definition is in an external file that file is parsed and the data structure inside of that is returned.
3795       * Usage: 5
3796       *
3797       * @param    array        Input data structure, possibly with a sheet-definition and references to external data source files.
3798       * @param    string        The sheet to return, preferably.
3799       * @return    array        An array with two num. keys: key0: The data structure is returned in this key (array) UNLESS an error happend in which case an error string is returned (string). key1: The used sheet key value!
3800       */
3801  	function resolveSheetDefInDS($dataStructArray,$sheet='sDEF')    {
3802          if (!is_array ($dataStructArray)) return 'Data structure must be an array';
3803  
3804          if (is_array($dataStructArray['sheets']))    {
3805              $singleSheet = FALSE;
3806              if (!isset($dataStructArray['sheets'][$sheet]))    {
3807                  $sheet='sDEF';
3808              }
3809              $dataStruct =  $dataStructArray['sheets'][$sheet];
3810  
3811                  // If not an array, but still set, then regard it as a relative reference to a file:
3812              if ($dataStruct && !is_array($dataStruct))    {
3813                  $file = t3lib_div::getFileAbsFileName($dataStruct);
3814                  if ($file && @is_file($file))    {
3815                      $dataStruct = t3lib_div::xml2array(t3lib_div::getUrl($file));
3816                  }
3817              }
3818          } else {
3819              $singleSheet = TRUE;
3820              $dataStruct = $dataStructArray;
3821              if (isset($dataStruct['meta'])) unset($dataStruct['meta']);    // Meta data should not appear there.
3822              $sheet = 'sDEF';    // Default sheet
3823          }
3824          return array($dataStruct,$sheet,$singleSheet);
3825      }
3826  
3827      /**
3828       * Resolves ALL sheet definitions in dataStructArray
3829       * If no sheet is found, then the default "sDEF" will be created with the dataStructure inside.
3830       *
3831       * @param    array        Input data structure, possibly with a sheet-definition and references to external data source files.
3832       * @return    array        Output data structure with all sheets resolved as arrays.
3833       */
3834  	function resolveAllSheetsInDS($dataStructArray)    {
3835          if (is_array($dataStructArray['sheets']))    {
3836              $out=array('sheets'=>array());
3837              foreach($dataStructArray['sheets'] as $sheetId => $sDat)    {
3838                  list($ds,$aS) = t3lib_div::resolveSheetDefInDS($dataStructArray,$sheetId);
3839                  if ($sheetId==$aS)    {
3840                      $out['sheets'][$aS]=$ds;
3841                  }
3842              }
3843          } else {
3844              list($ds) = t3lib_div::resolveSheetDefInDS($dataStructArray);
3845              $out = array('sheets' => array('sDEF' => $ds));
3846          }
3847          return $out;
3848      }
3849  
3850      /**
3851       * Calls a userdefined function/method in class
3852       * Such a function/method should look like this: "function proc(&$params, &$ref)    {...}"
3853       * Usage: 17
3854       *
3855       * @param    string        Function/Method reference, '[file-reference":"]["&"]class/function["->"method-name]'. You can prefix this reference with "[file-reference]:" and t3lib_div::getFileAbsFileName() will then be used to resolve the filename and subsequently include it by "require_once()" which means you don't have to worry about including the class file either! Example: "EXT:realurl/class.tx_realurl.php:&tx_realurl->encodeSpURL". Finally; you can prefix the class name with "&" if you want to reuse a former instance of the same object call ("singleton").
3856       * @param    mixed        Parameters to be pass along (typically an array) (REFERENCE!)
3857       * @param    mixed        Reference to be passed along (typically "$this" - being a reference to the calling object) (REFERENCE!)
3858       * @param    string        Required prefix of class or function name
3859       * @param    boolean        If set, no debug() error message is shown if class/function is not present.
3860       * @return    mixed        Content from method/function call
3861       * @see getUserObj()
3862       */
3863  	function callUserFunction($funcName,&$params,&$ref,$checkPrefix='user_',$silent=0)    {
3864          global $TYPO3_CONF_VARS;
3865  
3866              // Check persistent object and if found, call directly and exit.
3867          if (is_array($GLOBALS['T3_VAR']['callUserFunction'][$funcName]))    {
3868              return call_user_func_array(
3869                          array(&$GLOBALS['T3_VAR']['callUserFunction'][$funcName]['obj'],
3870                              $GLOBALS['T3_VAR']['callUserFunction'][$funcName]['method']),
3871                          array(&$params, &$ref)
3872                      );
3873          }
3874  
3875              // Check file-reference prefix; if found, require_once() the file (should be library of code)
3876          if (strstr($funcName,':'))    {
3877              list($file,$funcRef) = t3lib_div::revExplode(':',$funcName,2);
3878              $requireFile = t3lib_div::getFileAbsFileName($file);
3879              if ($requireFile) t3lib_div::requireOnce($requireFile);
3880          } else {
3881              $funcRef = $funcName;
3882          }
3883  
3884              // Check for persistent object token, "&"
3885          if (substr($funcRef,0,1)=='&')    {
3886              $funcRef = substr($funcRef,1);
3887              $storePersistentObject = TRUE;
3888          } else {
3889              $storePersistentObject = FALSE;
3890          }
3891  
3892              // Check prefix is valid:
3893          if ($checkPrefix &&
3894              !t3lib_div::isFirstPartOfStr(trim($funcRef),$checkPrefix) &&
3895              !t3lib_div::isFirstPartOfStr(trim($funcRef),'tx_')
3896              )    {
3897              if (!$silent)    debug("Function/Class '".$funcRef."' was not prepended with '".$checkPrefix."'",1);
3898              return FALSE;
3899          }
3900  
3901              // Call function or method:
3902          $parts = explode('->',$funcRef);
3903          if (count($parts)==2)    {    // Class
3904  
3905                  // Check if class/method exists:
3906              if (class_exists($parts[0]))    {
3907  
3908                      // Get/Create object of class:
3909                  if ($storePersistentObject)    {    // Get reference to current instance of class:
3910                      if (!is_object($GLOBALS['T3_VAR']['callUserFunction_classPool'][$parts[0]]))    {
3911                          $GLOBALS['T3_VAR']['callUserFunction_classPool'][$parts[0]] = &t3lib_div::makeInstance($parts[0]);
3912                      }
3913                      $classObj = &$GLOBALS['T3_VAR']['callUserFunction_classPool'][$parts[0]];
3914                  } else {    // Create new object:
3915                      $classObj = &t3lib_div::makeInstance($parts[0]);
3916                  }
3917  
3918                  if (method_exists($classObj, $parts[1]))    {
3919  
3920                          // If persistent object should be created, set reference:
3921                      if ($storePersistentObject)    {
3922                          $GLOBALS['T3_VAR']['callUserFunction'][$funcName] = array (
3923                              'method' => $parts[1],
3924                              'obj' => &$classObj
3925                          );
3926                      }
3927                          // Call method:
3928                      $content = call_user_func_array(
3929                          array(&$classObj, $parts[1]),
3930                          array(&$params, &$ref)
3931                      );
3932                  } else {
3933                      if (!$silent)    debug("<strong>ERROR:</strong> No method name '".$parts[1]."' in class ".$parts[0],1);
3934                  }
3935              } else {
3936                  if (!$silent)    debug("<strong>ERROR:</strong> No class named: ".$parts[0],1);
3937              }
3938          } else {    // Function
3939              if (function_exists($funcRef))    {
3940                   $content = call_user_func_array($funcRef, array(&$params, &$ref));
3941              } else {
3942                  if (!$silent)    debug("<strong>ERROR:</strong> No function named: ".$funcRef,1);
3943              }
3944          }
3945          return $content;
3946      }
3947  
3948      /**
3949       * Creates and returns reference to a user defined object.
3950       * This function can return an object reference if you like. Just prefix the function call with "&": "$objRef = &t3lib_div::getUserObj('EXT:myext/class.tx_myext_myclass.php:&tx_myext_myclass');". This will work ONLY if you prefix the class name with "&" as well. See description of function arguments.
3951       * Usage: 5
3952       *
3953       * @param    string        Class reference, '[file-reference":"]["&"]class-name'. You can prefix the class name with "[file-reference]:" and t3lib_div::getFileAbsFileName() will then be used to resolve the filename and subsequently include it by "require_once()" which means you don't have to worry about including the class file either! Example: "EXT:realurl/class.tx_realurl.php:&tx_realurl". Finally; for the class name you can prefix it with "&" and you will reuse the previous instance of the object identified by the full reference string (meaning; if you ask for the same $classRef later in another place in the code you will get a reference to the first created one!).
3954       * @param    string        Required prefix of class name. By default "tx_" is allowed.
3955       * @param    boolean        If set, no debug() error message is shown if class/function is not present.
3956       * @return    object        The instance of the class asked for. Instance is created with t3lib_div::makeInstance
3957       * @see callUserFunction()
3958       */
3959      function &getUserObj($classRef,$checkPrefix='user_',$silent=0)    {
3960          global $TYPO3_CONF_VARS;
3961              // Check persistent object and if found, call directly and exit.
3962          if (is_object($GLOBALS['T3_VAR']['getUserObj'][$classRef]))    {
3963              return $GLOBALS['T3_VAR']['getUserObj'][$classRef];
3964          } else {
3965  
3966                  // Check file-reference prefix; if found, require_once() the file (should be library of code)
3967              if (strstr($classRef,':'))    {
3968                  list($file,$class) = t3lib_div::revExplode(':',$classRef,2);
3969                  $requireFile = t3lib_div::getFileAbsFileName($file);
3970                  if ($requireFile)    t3lib_div::requireOnce($requireFile);
3971              } else {
3972                  $class = $classRef;
3973              }
3974  
3975                  // Check for persistent object token, "&"
3976              if (substr($class,0,1)=='&')    {
3977                  $class = substr($class,1);
3978                  $storePersistentObject = TRUE;
3979              } else {
3980                  $storePersistentObject = FALSE;
3981              }
3982  
3983                  // Check prefix is valid:
3984              if ($checkPrefix &&
3985                  !t3lib_div::isFirstPartOfStr(trim($class),$checkPrefix) &&
3986                  !t3lib_div::isFirstPartOfStr(trim($class),'tx_')
3987                  )    {
3988                  if (!$silent)    debug("Class '".$class."' was not prepended with '".$checkPrefix."'",1);
3989                  return FALSE;
3990              }
3991  
3992                  // Check if class exists:
3993              if (class_exists($class))    {
3994                  $classObj = &t3lib_div::makeInstance($class);
3995  
3996                      // If persistent object should be created, set reference:
3997                  if ($storePersistentObject)    {
3998                      $GLOBALS['T3_VAR']['getUserObj'][$classRef] = &$classObj;
3999                  }
4000  
4001                  return $classObj;
4002              } else {
4003                  if (!$silent)    debug("<strong>ERROR:</strong> No class named: ".$class,1);
4004              }
4005          }
4006      }
4007  
4008      /**
4009       * Make instance of class
4010       * Takes the class-extensions API of TYPO3 into account
4011       * Please USE THIS instead of the PHP "new" keyword. Eg. "$obj = new myclass;" should be "$obj = t3lib_div::makeInstance("myclass")" instead!
4012       * Usage: 447
4013       *
4014       * @param    string        Class name to instantiate
4015       * @return    object        A reference to the object
4016       */
4017      function &makeInstance($className)    {
4018  
4019              // Load class file if not found:
4020          if (!class_exists($className))    {
4021              if (substr($className,0,6)=='t3lib_')    {
4022                  t3lib_div::requireOnce(PATH_t3lib.'class.'.strtolower($className).'.php');
4023              }
4024          }
4025  
4026              // Return object.
4027          return class_exists('ux_'.$className) ? t3lib_div::makeInstance('ux_'.$className) : new $className;
4028      }
4029  
4030      /**
4031       * Return classname for new instance
4032       * Takes the class-extensions API of TYPO3 into account
4033       * Usage: 17
4034       *
4035       * @param    string        Base Class name to evaluate
4036       * @return    string        Final class name to instantiate with "new [classname]"
4037       */
4038  	function makeInstanceClassName($className)    {
4039          return class_exists('ux_'.$className) ? t3lib_div::makeInstanceClassName('ux_'.$className) : $className;
4040      }
4041  
4042      /**
4043       * Find the best service and check if it works.
4044       * Returns object of the service class.
4045       *
4046       * @param    string        Type of service (service key).
4047       * @param    string        Sub type like file extensions or similar. Defined by the service.
4048       * @param    mixed        List of service keys which should be exluded in the search for a service. Array or comma list.
4049       * @return    object        The service object or an array with error info's.
4050       * @author    René Fritz <r.fritz@colorcube.de>
4051       */
4052      function &makeInstanceService($serviceType, $serviceSubType='', $excludeServiceKeys=array())    {
4053          global $T3_SERVICES, $T3_VAR, $TYPO3_CONF_VARS;
4054  
4055          $error = FALSE;
4056  
4057          if (!is_array($excludeServiceKeys) ) {
4058              $excludeServiceKeys = t3lib_div::trimExplode(',', $excludeServiceKeys, 1);
4059          }
4060          while ($info = t3lib_extMgm::findService($serviceType, $serviceSubType, $excludeServiceKeys))    {
4061  
4062                  // Check persistent object and if found, call directly and exit.
4063              if (is_object($GLOBALS['T3_VAR']['makeInstanceService'][$info['className']]))    {
4064                      // reset service and return object
4065                  $T3_VAR['makeInstanceService'][$info['className']]->reset();
4066                  return $GLOBALS['T3_VAR']['makeInstanceService'][$info['className']];
4067  
4068                  // include file and create object
4069              } else {
4070                  $requireFile = t3lib_div::getFileAbsFileName($info['classFile']);
4071                  if (@is_file($requireFile)) {
4072                      t3lib_div::requireOnce ($requireFile);
4073                      $obj = t3lib_div::makeInstance($info['className']);
4074                      if (is_object($obj)) {
4075                          if(!@is_callable(array($obj,'init')))    {
4076                                  // use silent logging??? I don't think so.
4077                              die ('Broken service:'.t3lib_div::view_array($info));
4078                          }
4079                          $obj->info = $info;
4080                          if ($obj->init()) { // service available?
4081  
4082                                  // create persistent object
4083                              $T3_VAR['makeInstanceService'][$info['className']] = &$obj;
4084  
4085                                  // needed to delete temp files
4086                              register_shutdown_function(array(&$obj, '__destruct'));
4087  
4088                              return $obj; // object is passed as reference by function definition
4089                          }
4090                          $error = $obj->getLastErrorArray();
4091                          unset($obj);
4092                      }
4093                  }
4094              }
4095                  // deactivate the service
4096              t3lib_extMgm::deactivateService($info['serviceType'],$info['serviceKey']);
4097          }
4098          return $error;
4099      }
4100  
4101      /**
4102       * Require a class for TYPO3
4103       * Useful to require classes from inside other classes (not global scope). A limited set of global variables are available (see function)
4104       */
4105  	function requireOnce($requireFile)    {
4106          global $T3_SERVICES, $T3_VAR, $TYPO3_CONF_VARS;
4107  
4108          require_once ($requireFile);
4109      }
4110  
4111      /**
4112       * Simple substitute for the PHP function mail() which allows you to specify encoding and character set
4113       * The fifth parameter ($encoding) will allow you to specify 'base64' encryption for the output (set $encoding=base64)
4114       * Further the output has the charset set to ISO-8859-1 by default.
4115       * Usage: 4
4116       *
4117       * @param    string        Email address to send to. (see PHP function mail())
4118       * @param    string        Subject line, non-encoded. (see PHP function mail())
4119       * @param    string        Message content, non-encoded. (see PHP function mail())
4120       * @param    string        Headers, separated by chr(10)
4121       * @param    string        Encoding type: "base64", "quoted-printable", "8bit". Default value is "quoted-printable".
4122       * @param    string        Charset used in encoding-headers (only if $encoding is set to a valid value which produces such a header)
4123       * @param    boolean        If set, the header content will not be encoded.
4124       * @return    void
4125       */
4126  	function plainMailEncoded($email,$subject,$message,$headers='',$encoding='quoted-printable',$charset='',$dontEncodeHeader=false)    {
4127          if (!$charset)    {
4128              $charset = $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] ? $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] : 'ISO-8859-1';
4129          }
4130  
4131          if (!$dontEncodeHeader)    {
4132                  // Mail headers must be ASCII, therefore we convert the whole header to either base64 or quoted_printable
4133              $newHeaders=array();
4134              foreach (explode(chr(10),$headers) as $line)    {    // Split the header in lines and convert each line separately
4135                  $parts = explode(': ',$line,2);    // Field tags must not be encoded
4136                  if (count($parts)==2)    {
4137                      $parts[1] = t3lib_div::encodeHeader($parts[1],$encoding,$charset);
4138                      $newHeaders[] = implode(': ',$parts);
4139                  } else {
4140                      $newHeaders[] = $line;    // Should never happen - is such a mail header valid? Anyway, just add the unchanged line...
4141                  }
4142              }
4143              $headers = implode(chr(10),$newHeaders);
4144              unset($newHeaders);
4145  
4146              $email = t3lib_div::encodeHeader($email,$encoding,$charset);        // Email address must not be encoded, but it could be appended by a name which should be so (e.g. "Kasper Skårhøj <kasperYYYY@typo3.com>")
4147              $subject = t3lib_div::encodeHeader($subject,$encoding,$charset);
4148          }
4149  
4150          switch ((string)$encoding)    {
4151              case 'base64':
4152                  $headers=trim($headers).chr(10).
4153                  'Mime-Version: 1.0'.chr(10).
4154                  'Content-Type: text/plain; charset="'.$charset.'"'.chr(10).
4155                  'Content-Transfer-Encoding: base64';
4156  
4157                  $message=trim(chunk_split(base64_encode($message.chr(10)))).chr(10);    // Adding chr(10) because I think MS outlook 2002 wants it... may be removed later again.
4158              break;
4159              case '8bit':
4160                  $headers=trim($headers).chr(10).
4161                  'Mime-Version: 1.0'.chr(10).
4162                  'Content-Type: text/plain; charset='.$charset.chr(10).
4163                  'Content-Transfer-Encoding: 8bit';
4164              break;
4165              case 'quoted-printable':
4166              default:
4167                  $headers=trim($headers).chr(10).
4168                  'Mime-Version: 1.0'.chr(10).
4169                  'Content-Type: text/plain; charset='.$charset.chr(10).
4170                  'Content-Transfer-Encoding: quoted-printable';
4171  
4172                  $message=t3lib_div::quoted_printable($message);
4173              break;
4174          }
4175  
4176          $linebreak = chr(10);            // Default line break for Unix systems.
4177          if (TYPO3_OS=='WIN')    {
4178              $linebreak = chr(13).chr(10);    // Line break for Windows. This is needed because PHP on Windows systems send mails via SMTP instead of using sendmail, and thus the linebreak needs to be \r\n.
4179          }
4180  
4181          $headers=trim(implode($linebreak,t3lib_div::trimExplode(chr(10),$headers,1)));    // Make sure no empty lines are there.
4182  
4183          mail($email,$subject,$message,$headers);
4184      }
4185  
4186      /**
4187       * Implementation of quoted-printable encode.
4188       * This functions is buggy. It seems that in the part where the lines are breaked every 76th character, that it fails if the break happens right in a quoted_printable encode character!
4189       * See RFC 1521, section 5.1 Quoted-Printable Content-Transfer-Encoding
4190       * Usage: 2
4191       *
4192       * @param    string        Content to encode
4193       * @param    integer        Length of the lines, default is 76
4194       * @return    string        The QP encoded string
4195       */
4196  	function quoted_printable($string,$maxlen=76)    {
4197              // Make sure the string contains only Unix linebreaks
4198          $string = str_replace(chr(13).chr(10), chr(10), $string);    // Replace Windows breaks (\r\n)
4199          $string = str_replace(chr(13), chr(10), $string);        // Replace Mac breaks (\r)
4200  
4201          $linebreak = chr(10);            // Default line break for Unix systems.
4202          if (TYPO3_OS=='WIN')    {
4203              $linebreak = chr(13).chr(10);    // Line break for Windows. This is needed because PHP on Windows systems send mails via SMTP instead of using sendmail, and thus the linebreak needs to be \r\n.
4204          }
4205  
4206          $newString = '';
4207          $theLines = explode(chr(10),$string);    // Split lines
4208          foreach ($theLines as $val)    {
4209              $newVal = '';
4210              $theValLen = strlen($val);
4211              $len = 0;
4212              for ($index=0; $index < $theValLen; $index++)    {    // Walk through each character of this line
4213                  $char = substr($val,$index,1);
4214                  $ordVal = ord($char);
4215                  if ($len>($maxlen-4) || ($len>(($maxlen-10)-4)&&$ordVal==32))    {
4216                      $newVal.='='.$linebreak;    // Add a line break
4217                      $len=0;            // Reset the length counter
4218                  }
4219                  if (($ordVal>=33 && $ordVal<=60) || ($ordVal>=62 && $ordVal<=126) || $ordVal==9 || $ordVal==32)    {
4220                      $newVal.=$char;        // This character is ok, add it to the message
4221                      $len++;
4222                  } else {
4223                      $newVal.=sprintf('=%02X',$ordVal);    // Special character, needs to be encoded
4224                      $len+=3;
4225                  }
4226              }
4227              $newVal = preg_replace('/'.chr(32).'$/','=20',$newVal);        // Replaces a possible SPACE-character at the end of a line
4228              $newVal = preg_replace('/'.chr(9).'$/','=09',$newVal);        // Replaces a possible TAB-character at the end of a line
4229              $newString.=$newVal.$linebreak;
4230          }
4231          return preg_replace('/'.$linebreak.'$/','',$newString);        // Remove last newline
4232      }
4233  
4234      /**
4235       * Encode header lines
4236       * Email headers must be ASCII, therefore they will be encoded to quoted_printable (default) or base64.
4237       *
4238       * @param    string        Content to encode
4239       * @param    string        Encoding type: "base64" or "quoted-printable". Default value is "quoted-printable".
4240       * @param    string        Charset used for encoding
4241       * @return    string        The encoded string
4242       */
4243  	function encodeHeader($line,$enc='quoted-printable',$charset='ISO-8859-1')    {
4244              // Avoid problems if "###" is found in $line (would conflict with the placeholder which is used below)
4245          if (strstr($line,'###'))    return $line;
4246  
4247              // Check if any non-ASCII characters are found - otherwise encoding is not needed
4248          if (!preg_match('/[^'.chr(32).'-'.chr(127).']/',$line))    return $line;
4249  
4250              // Wrap email addresses in a special marker
4251          $line = preg_replace('/([^ ]+@[^ ]+)/', '###$1###', $line);
4252  
4253          $matches = preg_split('/(.?###.+###.?|\(|\))/', $line, -1, PREG_SPLIT_NO_EMPTY);
4254          foreach ($matches as $part)    {
4255              $oldPart = $part;
4256              switch ((string)$enc)    {
4257                  case 'base64':
4258                      $part = '=?'.$charset.'?B?'.base64_encode($part).'?=';
4259                  break;
4260                  case 'quoted-printable':
4261                  default:
4262                      $qpValue = t3lib_div::quoted_printable($part,1000);
4263                      if ($part!=$qpValue)    {
4264                          $qpValue = str_replace(' ','_',$qpValue);    // Encoded words in the header should not contain non-encoded spaces. "_" is a shortcut for "=20". See RFC 2047 for details.
4265                          $part = '=?'.$charset.'?Q?'.$qpValue.'?=';
4266                      }
4267                  break;
4268              }
4269              $line = str_replace($oldPart, $part, $line);
4270          }
4271          $line = preg_replace('/###(.+?)###/', '$1', $line);    // Remove the wrappers
4272  
4273          return $line;
4274      }
4275  
4276      /**
4277       * Takes a clear-text message body for a plain text email, finds all 'http://' links and if they are longer than 76 chars they are converted to a shorter URL with a hash parameter. The real parameter is stored in the database and the hash-parameter/URL will be redirected to the real parameter when the link is clicked.
4278       * This function is about preserving long links in messages.
4279       * Usage: 3
4280       *
4281       * @param    string        Message content
4282       * @param    string        URL mode; "76" or "all"
4283       * @param    string        URL of index script (see makeRedirectUrl())
4284       * @return    string        Processed message content
4285       * @see makeRedirectUrl()
4286       */
4287  	function substUrlsInPlainText($message,$urlmode='76',$index_script_url='')    {
4288              // Substitute URLs with shorter links:
4289          foreach (array('http','https') as $protocol)    {
4290              $urlSplit = explode($protocol.'://',$message);
4291              reset($urlSplit);
4292              while (list($c,$v) = each($urlSplit))    {
4293                  if ($c)    {
4294                      $newParts = preg_split('/\s|[<>"{}|\\\^`()\']/', $v, 2);
4295                      $newURL = $protocol.'://'.$newParts[0];
4296  
4297                      switch ((string)$urlmode)    {
4298                          case 'all':
4299                              $newURL = t3lib_div::makeRedirectUrl($newURL,0,$index_script_url);
4300                          break;
4301                          case '76':
4302                              $newURL = t3lib_div::makeRedirectUrl($newURL,76,$index_script_url);
4303                          break;
4304                      }
4305                      $urlSplit[$c] = $newURL . substr($v,strlen($newParts[0]));
4306                  }
4307              }
4308              $message = implode('',$urlSplit);
4309          }
4310  
4311          return $message;
4312      }
4313  
4314      /**
4315       * Subfunction for substUrlsInPlainText() above.
4316       * Usage: 2
4317       *
4318       * @param    string        Input URL
4319       * @param    integer        URL string length limit
4320       * @param    string        URL of "index script" - the prefix of the "?RDCT=..." parameter. If not supplyed it will default to t3lib_div::getIndpEnv('TYPO3_REQUEST_DIR').'index.php'
4321       * @return    string        Processed URL
4322       * @internal
4323       */
4324  	function makeRedirectUrl($inUrl,$l=0,$index_script_url='')    {
4325          if (strlen($inUrl)>$l)    {
4326              $md5 = substr(md5($inUrl),0,20);
4327              $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('md5hash', 'cache_md5params', 'md5hash='.$GLOBALS['TYPO3_DB']->fullQuoteStr($md5, 'cache_md5params'));
4328              if (!$GLOBALS['TYPO3_DB']->sql_num_rows($res))    {
4329                  $insertFields = array(
4330                      'md5hash' => $md5,
4331                      'tstamp' => time(),
4332                      'type' => 2,
4333                      'params' => $inUrl
4334                  );
4335  
4336                  $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_md5params', $insertFields);
4337              }
4338              $inUrl=($index_script_url ? $index_script_url : t3lib_div::getIndpEnv('TYPO3_REQUEST_DIR').'index.php').
4339                  '?RDCT='.$md5;
4340          }
4341  
4342          return $inUrl;
4343      }
4344  
4345      /**
4346       * Function to compensate for FreeType2 96 dpi
4347       * Usage: 21
4348       *
4349       * @param    integer        Fontsize for freetype function call
4350       * @return    integer        Compensated fontsize based on $GLOBALS['TYPO3_CONF_VARS']['GFX']['TTFdpi']
4351       */
4352  	function freetypeDpiComp($font_size)    {
4353          $dpi = intval($GLOBALS['TYPO3_CONF_VARS']['GFX']['TTFdpi']);
4354          if ($dpi!=72)    $font_size = $font_size/$dpi*72;
4355          return $font_size;
4356      }
4357  
4358      /**
4359       * Init system error log.
4360       *
4361       * @return    void
4362       * @see sysLog()
4363       */
4364  	function initSysLog()    {
4365          global $TYPO3_CONF_VARS;
4366  
4367              // for CLI logging name is <fqdn-hostname>:<TYPO3-path>
4368          if (defined('TYPO3_cliMode') && TYPO3_cliMode)    {
4369              $TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'] = t3lib_div::getHostname($requestHost=FALSE).':'.PATH_site;
4370          }
4371              // for Web logging name is <protocol>://<request-hostame>/<site-path>
4372          else {
4373              $TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'] = t3lib_div::getIndpEnv('TYPO3_SITE_URL');
4374          }
4375  
4376              // init custom logging
4377          if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog']))    {
4378              $params = array('initLog'=>TRUE);
4379              $fakeThis = FALSE;
4380              foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog'] as $hookMethod)    {
4381                  t3lib_div::callUserFunction($hookMethod,$params,$fakeThis);
4382              }
4383          }
4384  
4385              // init TYPO3 logging
4386          foreach (explode(';',$TYPO3_CONF_VARS['SYS']['systemLog'],2) as $log)    {
4387              list($type,$destination) = explode(',',$log,3);
4388  
4389              if ($type == 'syslog')    {
4390                  define_syslog_variables();
4391                  if (TYPO3_OS == 'WIN')    {
4392                      $facility = LOG_USER;
4393                  } else {
4394                      $facility = constant('LOG_'.strtoupper($destination));
4395                  }
4396                  openlog($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'], LOG_ODELAY, $facility);
4397              }
4398          }
4399  
4400          $TYPO3_CONF_VARS['SYS']['systemLogLevel'] = t3lib_div::intInRange($TYPO3_CONF_VARS['SYS']['systemLogLevel'],0,4);
4401          $TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogInit'] = TRUE;
4402      }
4403  
4404      /**
4405       * System error log; This should be implemented around the source code, including the Core and both frontend and backend, logging serious errors.
4406       * If you want to implement the sysLog in your applications, simply add lines like:
4407       *         t3lib_div::sysLog('[write message in English here]', 'extension key');
4408       *
4409       * @param    string        Message (in English).
4410       * @param    string        Extension key (from which extension you are calling the log) or "Core"
4411       * @param    integer        Severity: 0 is info, 1 is notice, 2 is warning, 3 is error, 4 is fatal error
4412       * @return    void
4413       */
4414  	function sysLog($msg, $extKey, $severity=0) {
4415          global $TYPO3_CONF_VARS;
4416  
4417          $severity = t3lib_div::intInRange($severity,0,4);
4418  
4419              // is message worth logging?
4420          if (intval($TYPO3_CONF_VARS['SYS']['systemLogLevel']) > $severity)    return;
4421  
4422              // initialize logging
4423          if (!$TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogInit'])    {
4424              t3lib_div::initSysLog();
4425          }
4426  
4427              // do custom logging
4428          if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog']))    {
4429              $params = array('msg'=>$msg, 'extKey'=>$extKey, 'backTrace'=>debug_backtrace());
4430              $fakeThis = FALSE;
4431              foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog'] as $hookMethod)    {
4432                  t3lib_div::callUserFunction($hookMethod,$params,$fakeThis);
4433              }
4434          }
4435  
4436              // TYPO3 logging enabled?
4437          if (!$TYPO3_CONF_VARS['SYS']['systemLog'])    return;
4438  
4439          $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
4440          $timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
4441  
4442              // use all configured logging options
4443          foreach (explode(';',$TYPO3_CONF_VARS['SYS']['systemLog'],2) as $log)    {
4444              list($type,$destination,$level) = explode(',',$log,4);
4445  
4446                  // is message worth logging for this log type?
4447              if (intval($level) > $severity)    continue;
4448  
4449              $msgLine = ' - '.$extKey.': '.$msg;
4450  
4451                  // write message to a file
4452              if ($type == 'file')    {
4453                  $file = fopen($destination, 'a');
4454                  if ($file)     {
4455                      flock($file, LOCK_EX);  // try locking, but ignore if not available (eg. on NFS and FAT)
4456                      fwrite($file, date($dateFormat.' '.$timeFormat).$msgLine.chr(10));
4457                      flock($file, LOCK_UN);    // release the lock
4458                      fclose($file);
4459                  }
4460              }
4461                  // send message per mail
4462              elseif ($type == 'mail')    {
4463                  list($to,$from) = explode('/',$destination);
4464                  mail($to, 'Warning - error in TYPO3 installation',
4465                      'Host: '.$TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost']."\n".
4466                      'Extension: '.$extKey."\n".
4467                      'Severity: '.$severity."\n".
4468                      "\n".$msg,
4469                      ($from ? 'From: '.$from : '')
4470                  );
4471              }
4472                  // use the PHP error log
4473              elseif ($type == 'error_log')    {
4474                  error_log($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'].$msgLine, 0);
4475              }
4476                  // use the system log
4477              elseif ($type == 'syslog')    {
4478                  $priority = array(LOG_INFO,LOG_NOTICE,LOG_WARNING,LOG_ERR,LOG_CRIT);
4479                  syslog($priority[(int)$severity], $msgLine);
4480              }
4481          }
4482      }
4483  
4484      /**
4485       * Developer log; This should be implemented around the source code, both frontend and backend, logging everything from the flow through an application, messages, results from comparisons to fatal errors.
4486       * The result is meant to make sense to developers during development or debugging of a site.
4487       * The idea is that this function is only a wrapper for external extensions which can set a hook which will be allowed to handle the logging of the information to any format they might wish and with any kind of filter they would like.
4488       * If you want to implement the devLog in your applications, simply add lines like:
4489       *         if (TYPO3_DLOG)    t3lib_div::devLog('[write message in english here]', 'extension key');
4490       *
4491       * @param    string        Message (in english).
4492       * @param    string        Extension key (from which extension you are calling the log)
4493       * @param    integer        Severity: 0 is info, 1 is notice, 2 is warning, 3 is fatal error, -1 is "OK" message
4494       * @param    array        Additional data you want to pass to the logger.
4495       * @return    void
4496       */
4497  	function devLog($msg, $extKey, $severity=0, $dataVar=FALSE)    {
4498          global $TYPO3_CONF_VARS;
4499  
4500          if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['devLog']))    {
4501              $params = array('msg'=>$msg, 'extKey'=>$extKey, 'severity'=>$severity, 'dataVar'=>$dataVar);
4502              $fakeThis = FALSE;
4503              foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['devLog'] as $hookMethod)    {
4504                  t3lib_div::callUserFunction($hookMethod,$params,$fakeThis);
4505              }
4506          }
4507      }
4508  
4509      /**
4510       * Converts a one dimensional array to a one line string which can be used for logging or debugging output
4511       * Example: "loginType: FE; refInfo: Array; HTTP_HOST: www.example.org; REMOTE_ADDR: 192.168.1.5; REMOTE_HOST:; security_level:; showHiddenRecords: 0;"
4512       *
4513       * @param    array        Data array which should be outputted
4514       * @param    mixed        List of keys which should be listed in the output string. Pass a comma list or an array. An empty list outputs the whole array.
4515       * @param    integer        Long string values are shortened to this length. Default: 20
4516       * @return    string        Output string with key names and their value as string
4517       */
4518  	function arrayToLogString($arr, $valueList=array(), $valueLength=20) {
4519          $str = '';
4520          if (is_array($arr))    {
4521              if (!is_array($valueList))    {
4522                  $valueList = t3lib_div::trimExplode(',', $valueList, 1);
4523              }
4524              $valListCnt = count($valueList);
4525              foreach ($arr as $key => $value)    {
4526                  if (!$valListCnt || in_array($key, $valueList))    {
4527                      $str .= (string)$key.trim(': '.t3lib_div::fixed_lgd(str_replace("\n",'|',(string)$value), $valueLength)).'; ';
4528                  }
4529              }
4530          }
4531          return $str;
4532      }
4533  
4534      /**
4535       * Compile the command for running ImageMagick/GraphicsMagick.
4536       *
4537       * @param    string        Command to be run: identify, convert or combine/composite
4538       * @param    string        The parameters string
4539       * @param    string        Override the default path
4540       * @return    string        Compiled command that deals with IM6 & GraphicsMagick
4541       */
4542  	function imageMagickCommand($command, $parameters, $path='')    {
4543          $gfxConf = $GLOBALS['TYPO3_CONF_VARS']['GFX'];
4544          $isExt = (TYPO3_OS=='WIN' ? '.exe' : '');
4545          $switchCompositeParameters=false;
4546  
4547          if(!$path)    { $path = $gfxConf['im_path']; }
4548  
4549          $im_version = strtolower($gfxConf['im_version_5']);
4550          $combineScript = $gfxConf['im_combine_filename'] ? trim($gfxConf['im_combine_filename']) : 'combine';
4551  
4552          if($command==='combine')    {    // This is only used internally, has no effect outside
4553              $command = 'composite';
4554          }
4555  
4556              // Compile the path & command
4557          if($im_version==='gm')    {
4558              $switchCompositeParameters=true;
4559              $path .= 'gm'.$isExt.' '.$command;
4560          } else    {
4561              if($im_version==='im6')    { $switchCompositeParameters=true; }
4562              $path .= (($command=='composite') ? $combineScript : $command).$isExt;
4563          }
4564  
4565          $cmdLine = $path.' '.$parameters;
4566  
4567          if($command=='composite' && $switchCompositeParameters)    {    // Because of some weird incompatibilities between ImageMagick 4 and 6 (plus GraphicsMagick), it is needed to change the parameters order under some preconditions
4568              $paramsArr = t3lib_div::unQuoteFilenames($parameters);
4569  
4570              if(count($paramsArr)>5)    {    // The mask image has been specified => swap the parameters
4571                  $tmp = $paramsArr[count($paramsArr)-3];
4572                  $paramsArr[count($paramsArr)-3] = $paramsArr[count($paramsArr)-4];
4573                  $paramsArr[count($paramsArr)-4] = $tmp;
4574              }
4575  
4576              $cmdLine = $path.' '.implode(' ', $paramsArr);
4577          }
4578  
4579          return $cmdLine;
4580      }
4581  
4582      /**
4583       * Explode a string (normally a list of filenames) with whitespaces by considering quotes in that string. This is mostly needed by the imageMagickCommand function above.
4584       *
4585       * @param    string        The whole parameters string
4586       * @param    boolean        If set, the elements of the resulting array are unquoted.
4587       * @return    array        Exploded parameters
4588       */
4589  	function unQuoteFilenames($parameters,$unQuote=FALSE)    {
4590          $paramsArr = explode(' ', trim($parameters));
4591  
4592          $quoteActive = -1;    // Whenever a quote character (") is found, $quoteActive is set to the element number inside of $params. A value of -1 means that there are not open quotes at the current position.
4593          foreach($paramsArr as $k=>$v)    {
4594              if($quoteActive > -1)    {
4595                  $paramsArr[$quoteActive] .= ' '.$v;
4596                  unset($paramsArr[$k]);
4597                  if(ereg('"$', $v))    { $quoteActive = -1; }
4598  
4599              } elseif(!trim($v))    {
4600                  unset($paramsArr[$k]);    // Remove empty elements
4601  
4602              } elseif(ereg('^"', $v))    {
4603                  $quoteActive = $k;
4604              }
4605          }
4606  
4607          if($unQuote) {
4608              foreach($paramsArr as $key=>$val) {
4609                  $paramsArr[$key]=preg_replace('/(^"|"$)/','',$val);
4610              }
4611          }
4612          return $paramsArr;
4613      }
4614  
4615  
4616      /**
4617       * Quotes a string for usage as JS parameter. Depends wheter the value is used in script tags (it doesn't need/must not get htmlspecialchar'ed in this case)
4618       *
4619       * @param    string        The string to encode.
4620       * @param    boolean        If the values get's used in <script> tags.
4621       * @return    string        The encoded value already quoted
4622       */
4623  	function quoteJSvalue($value, $inScriptTags = false)    {
4624          $value = addcslashes($value, '\''.chr(10).chr(13));
4625          if (!$inScriptTags)    {
4626              $value = htmlspecialchars($value);
4627          }
4628          return '\''.$value.'\'';
4629      }
4630  
4631  
4632  }
4633  
4634  ?>


Généré le : Sun Nov 25 17:13:16 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics