class.t3lib_div.php

Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 1999-2010 Kasper Skaarhoj (kasperYYYY@typo3.com)
00006 *  All rights reserved
00007 *
00008 *  This script is part of the TYPO3 project. The TYPO3 project is
00009 *  free software; you can redistribute it and/or modify
00010 *  it under the terms of the GNU General Public License as published by
00011 *  the Free Software Foundation; either version 2 of the License, or
00012 *  (at your option) any later version.
00013 *
00014 *  The GNU General Public License can be found at
00015 *  http://www.gnu.org/copyleft/gpl.html.
00016 *  A copy is found in the textfile GPL.txt and important notices to the license
00017 *  from the author is found in LICENSE.txt distributed with these scripts.
00018 *
00019 *
00020 *  This script is distributed in the hope that it will be useful,
00021 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 *  GNU General Public License for more details.
00024 *
00025 *  This copyright notice MUST APPEAR in all copies of the script!
00026 ***************************************************************/
00027 /**
00028  * Contains the reknown class "t3lib_div" with general purpose functions
00029  *
00030  * $Id: class.t3lib_div.php 8190 2010-07-14 11:50:15Z dmitry $
00031  * Revised for TYPO3 3.6 July/2003 by Kasper Skaarhoj
00032  * XHTML compliant
00033  * Usage counts are based on search 22/2 2003 through whole source including tslib/
00034  *
00035  * @author  Kasper Skaarhoj <kasperYYYY@typo3.com>
00036  */
00037 /**
00038  * [CLASS/FUNCTION INDEX of SCRIPT]
00039  *
00040  *
00041  *
00042  *  232: class t3lib_div
00043  *
00044  *              SECTION: GET/POST Variables
00045  *  262:     function _GP($var)
00046  *  280:     function _GET($var=NULL)
00047  *  297:     function _POST($var=NULL)
00048  *  313:     function _GETset($inputGet,$key='')
00049  *  336:     function GPvar($var,$strip=0)
00050  *  353:     function GParrayMerged($var)
00051  *
00052  *              SECTION: IMAGE FUNCTIONS
00053  *  397:     function gif_compress($theFile, $type)
00054  *  425:     function png_to_gif_by_imagemagick($theFile)
00055  *  450:     function read_png_gif($theFile,$output_png=0)
00056  *
00057  *              SECTION: STRING FUNCTIONS
00058  *  499:     function fixed_lgd($string,$origChars,$preStr='...')
00059  *  524:     function fixed_lgd_pre($string,$chars)
00060  *  538:     function fixed_lgd_cs($string,$chars)
00061  *  555:     function breakTextForEmail($str,$implChar=LF,$charWidth=76)
00062  *  574:     function breakLinesForEmail($str,$implChar=LF,$charWidth=76)
00063  *  610:     function cmpIP($baseIP, $list)
00064  *  626:     function cmpIPv4($baseIP, $list)
00065  *  668:     function cmpIPv6($baseIP, $list)
00066  *  711:     function IPv6Hex2Bin ($hex)
00067  *  726:     function normalizeIPv6($address)
00068  *  782:     function validIPv6($ip)
00069  *  805:     function cmpFQDN($baseIP, $list)
00070  *  835:     function inList($list,$item)
00071  *  847:     function rmFromList($element,$list)
00072  *  863:     function expandList($list)
00073  *  894:     function intInRange($theInt,$min,$max=2000000000,$zeroValue=0)
00074  *  910:     function intval_positive($theInt)
00075  *  923:     function int_from_ver($verNumberStr)
00076  *  934:     function compat_version($verNumberStr)
00077  *  952:     function md5int($str)
00078  *  965:     function shortMD5($input, $len=10)
00079  *  978:     function uniqueList($in_list, $secondParameter=NULL)
00080  *  992:     function split_fileref($fileref)
00081  * 1030:     function dirname($path)
00082  * 1046:     function modifyHTMLColor($color,$R,$G,$B)
00083  * 1066:     function modifyHTMLColorAll($color,$all)
00084  * 1077:     function rm_endcomma($string)
00085  * 1090:     function danish_strtoupper($string)
00086  * 1105:     function convUmlauts($str)
00087  * 1118:     function testInt($var)
00088  * 1130:     function isFirstPartOfStr($str,$partStr)
00089  * 1146:     function formatSize($sizeInBytes,$labels='')
00090  * 1181:     function convertMicrotime($microtime)
00091  * 1195:     function splitCalc($string,$operators)
00092  * 1217:     function calcPriority($string)
00093  * 1258:     function calcParenthesis($string)
00094  * 1284:     function htmlspecialchars_decode($value)
00095  * 1299:     function deHSCentities($str)
00096  * 1312:     function slashJS($string,$extended=0,$char="'")
00097  * 1325:     function rawUrlEncodeJS($str)
00098  * 1337:     function rawUrlEncodeFP($str)
00099  * 1348:     function validEmail($email)
00100  * 1363:     function formatForTextarea($content)
00101  *
00102  *              SECTION: ARRAY FUNCTIONS
00103  * 1394:     function inArray($in_array,$item)
00104  * 1411:     function intExplode($delim, $string)
00105  * 1430:     function revExplode($delim, $string, $count=0)
00106  * 1450:     function trimExplode($delim, $string, $onlyNonEmptyValues=0)
00107  * 1472:     function uniqueArray($valueArray)
00108  * 1484:     function removeArrayEntryByValue($array,$cmpValue)
00109  * 1513:     function implodeArrayForUrl($name,$theArray,$str='',$skipBlank=0,$rawurlencodeParamName=0)
00110  * 1538:     function explodeUrl2Array($string,$multidim=FALSE)
00111  * 1564:     function compileSelectedGetVarsFromArray($varList,$getArray,$GPvarAlt=1)
00112  * 1587:     function addSlashesOnArray(&$theArray)
00113  * 1611:     function stripSlashesOnArray(&$theArray)
00114  * 1633:     function slashArray($arr,$cmd)
00115  * 1650:     function array_merge_recursive_overrule($arr0,$arr1,$notAddKeys=0,$includeEmtpyValues=true)
00116  * 1683:     function array_merge($arr1,$arr2)
00117  * 1696:     function csvValues($row,$delim=',',$quote='"')
00118  *
00119  *              SECTION: HTML/XML PROCESSING
00120  * 1738:     function get_tag_attributes($tag)
00121  * 1775:     function split_tag_attributes($tag)
00122  * 1809:     function implodeAttributes($arr,$xhtmlSafe=FALSE,$dontOmitBlankAttribs=FALSE)
00123  * 1836:     function implodeParams($arr,$xhtmlSafe=FALSE,$dontOmitBlankAttribs=FALSE)
00124  * 1851:     function wrapJS($string, $linebreak=TRUE)
00125  * 1882:     function xml2tree($string,$depth=999)
00126  * 1969:     function array2xml($array,$NSprefix='',$level=0,$docTag='phparray',$spaceInd=0, $options=array(),$stackData=array())
00127  * 2088:     function xml2array($string,$NSprefix='',$reportDocTag=FALSE)
00128  * 2198:     function xmlRecompileFromStructValArray($vals)
00129  * 2242:     function xmlGetHeaderAttribs($xmlData)
00130  *
00131  *              SECTION: FILES FUNCTIONS
00132  * 2275:     function getURL($url, $includeHeader=0)
00133  * 2342:     function writeFile($file,$content)
00134  * 2367:     function fixPermissions($file)
00135  * 2384:     function writeFileToTypo3tempDir($filepath,$content)
00136  * 2427:     function mkdir($theNewFolder)
00137  * 2446:     function mkdir_deep($destination,$deepDir)
00138  * 2468:     function get_dirs($path)
00139  * 2493:     function getFilesInDir($path,$extensionList='',$prependPath=0,$order='')
00140  * 2547:     function getAllFilesAndFoldersInPath($fileArr,$path,$extList='',$regDirs=0,$recursivityLevels=99)
00141  * 2570:     function removePrefixPathFromList($fileArr,$prefixToRemove)
00142  * 2586:     function fixWindowsFilePath($theFile)
00143  * 2598:     function resolveBackPath($pathStr)
00144  * 2626:     function locationHeaderUrl($path)
00145  *
00146  *              SECTION: DEBUG helper FUNCTIONS
00147  * 2666:     function debug_ordvalue($string,$characters=100)
00148  * 2683:     function view_array($array_in)
00149  * 2711:     function print_array($array_in)
00150  * 2726:     function debug($var="",$brOrHeader=0)
00151  * 2757:     function debug_trail()
00152  * 2779:     function debugRows($rows,$header='')
00153  *
00154  *              SECTION: SYSTEM INFORMATION
00155  * 2857:     function getThisUrl()
00156  * 2873:     function linkThisScript($getParams=array())
00157  * 2897:     function linkThisUrl($url,$getParams=array())
00158  * 2920:     function getIndpEnv($getEnvName)
00159  * 3113:     function milliseconds()
00160  * 3125:     function clientInfo($useragent='')
00161  *
00162  *              SECTION: TYPO3 SPECIFIC FUNCTIONS
00163  * 3212:     function getFileAbsFileName($filename,$onlyRelative=1,$relToTYPO3_mainDir=0)
00164  * 3248:     function validPathStr($theFile)
00165  * 3259:     function isAbsPath($path)
00166  * 3270:     function isAllowedAbsPath($path)
00167  * 3287:     function verifyFilenameAgainstDenyPattern($filename)
00168  * 3305:     function upload_copy_move($source,$destination)
00169  * 3331:     function upload_to_tempfile($uploadedFileName)
00170  * 3349:     function unlink_tempfile($uploadedTempFileName)
00171  * 3365:     function tempnam($filePrefix)
00172  * 3379:     function stdAuthCode($uid_or_record,$fields='',$codeLength=8)
00173  * 3410:     function cHashParams($addQueryParams)
00174  * 3433:     function hideIfNotTranslated($l18n_cfg_fieldValue)
00175  * 3448:     function readLLfile($fileRef,$langKey)
00176  * 3472:     function readLLXMLfile($fileRef,$langKey)
00177  * 3589:     function llXmlAutoFileName($fileRef,$language)
00178  * 3633:     function loadTCA($table)
00179  * 3653:     function resolveSheetDefInDS($dataStructArray,$sheet='sDEF')
00180  * 3686:     function resolveAllSheetsInDS($dataStructArray)
00181  * 3715:     function callUserFunction($funcName,&$params,&$ref,$checkPrefix='user_',$silent=0)
00182  * 3813:     function &getUserObj($classRef,$checkPrefix='user_',$silent=0)
00183  * 3871:     function &makeInstance($className)
00184  * 3883:     function makeInstanceClassName($className)
00185  * 3897:     function &makeInstanceService($serviceType, $serviceSubType='', $excludeServiceKeys=array())
00186  * 3961:     function plainMailEncoded($email,$subject,$message,$headers='',$enc='',$charset='',$dontEncodeHeader=false)
00187  * 4031:     function quoted_printable($string,$maxlen=76)
00188  * 4078:     function encodeHeader($line,$enc='',$charset='ISO-8859-1')
00189  * 4121:     function substUrlsInPlainText($message,$urlmode='76',$index_script_url='')
00190  * 4155:     function makeRedirectUrl($inUrl,$l=0,$index_script_url='')
00191  * 4182:     function freetypeDpiComp($font_size)
00192  * 4194:     function initSysLog()
00193  * 4251:     function sysLog($msg, $extKey, $severity=0)
00194  * 4334:     function devLog($msg, $extKey, $severity=0, $dataVar=FALSE)
00195  * 4355:     function arrayToLogString($arr, $valueList=array(), $valueLength=20)
00196  * 4378:     function imageMagickCommand($command, $parameters, $path='')
00197  * 4425:     function unQuoteFilenames($parameters,$unQuote=FALSE)
00198  * 4459:     function quoteJSvalue($value, $inScriptTags = false)
00199  *
00200  * TOTAL FUNCTIONS: 138
00201  * (This index is automatically created/updated by the extension "extdeveval")
00202  *
00203  */
00204 
00205     // a tabulator
00206 define('TAB', chr(9));
00207     // a linefeed
00208 define('LF', chr(10));
00209     // a carriage return
00210 define('CR', chr(13));
00211     // a CR-LF combination
00212 define('CRLF', CR . LF);
00213 
00214 /**
00215  * The legendary "t3lib_div" class - Miscellaneous functions for general purpose.
00216  * Most of the functions does not relate specifically to TYPO3
00217  * However a section of functions requires certain TYPO3 features available
00218  * See comments in the source.
00219  * You are encouraged to use this library in your own scripts!
00220  *
00221  * USE:
00222  * The class is intended to be used without creating an instance of it.
00223  * So: Don't instantiate - call functions with "t3lib_div::" prefixed the function name.
00224  * So use t3lib_div::[method-name] to refer to the functions, eg. 't3lib_div::milliseconds()'
00225  *
00226  * @author  Kasper Skaarhoj <kasperYYYY@typo3.com>
00227  * @package TYPO3
00228  * @subpackage t3lib
00229  */
00230 final class t3lib_div {
00231 
00232         // Severity constants used by t3lib_div::sysLog()
00233     const SYSLOG_SEVERITY_INFO = 0;
00234     const SYSLOG_SEVERITY_NOTICE = 1;
00235     const SYSLOG_SEVERITY_WARNING = 2;
00236     const SYSLOG_SEVERITY_ERROR = 3;
00237     const SYSLOG_SEVERITY_FATAL = 4;
00238 
00239 
00240     /*************************
00241      *
00242      * GET/POST Variables
00243      *
00244      * Background:
00245      * Input GET/POST variables in PHP may have their quotes escaped with "\" or not depending on configuration.
00246      * TYPO3 has always converted quotes to BE escaped if the configuration told that they would not be so.
00247      * But the clean solution is that quotes are never escaped and that is what the functions below offers.
00248      * Eventually TYPO3 should provide this in the global space as well.
00249      * In the transitional phase (or forever..?) we need to encourage EVERY to read and write GET/POST vars through the API functions below.
00250      *
00251      *************************/
00252 
00253     /**
00254      * Returns the 'GLOBAL' value of incoming data from POST or GET, with priority to POST (that is equalent to 'GP' order)
00255      * Strips slashes from all output, both strings and arrays.
00256      * This function substitutes t3lib_div::GPvar()
00257      * 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!
00258      * Usage: 537
00259      *
00260      * @param   string      GET/POST var to return
00261      * @return  mixed       POST var named $var and if not set, the GET var of the same name.
00262      */
00263     public static function _GP($var)    {
00264         if(empty($var)) return;
00265         $value = isset($_POST[$var]) ? $_POST[$var] : $_GET[$var];
00266         if (isset($value))  {
00267             if (is_array($value))   { self::stripSlashesOnArray($value); } else { $value = stripslashes($value); }
00268         }
00269         return $value;
00270     }
00271 
00272     /**
00273      * Returns the global arrays $_GET and $_POST merged with $_POST taking precedence.
00274      *
00275      * @param   string      Key (variable name) from GET or POST vars
00276      * @return  array       Returns the GET vars merged recursively onto the POST vars.
00277      */
00278     public static function _GPmerged($parameter) {
00279         $postParameter = (isset($_POST[$parameter]) && is_array($_POST[$parameter])) ? $_POST[$parameter] : array();
00280         $getParameter  = (isset($_GET[$parameter]) && is_array($_GET[$parameter])) ? $_GET[$parameter] : array();
00281 
00282         $mergedParameters = self::array_merge_recursive_overrule($getParameter, $postParameter);
00283         self::stripSlashesOnArray($mergedParameters);
00284 
00285         return $mergedParameters;
00286     }
00287 
00288     /**
00289      * Returns the global $_GET array (or value from) normalized to contain un-escaped values.
00290      * ALWAYS use this API function to acquire the GET variables!
00291      * Usage: 27
00292      *
00293      * @param   string      Optional pointer to value in GET array (basically name of GET var)
00294      * @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!*
00295      * @see _POST(), _GP(), _GETset()
00296      */
00297     public static function _GET($var=NULL)  {
00298         $value = ($var === NULL) ? $_GET : (empty($var) ? NULL : $_GET[$var]);
00299         if (isset($value))  {   // Removes slashes since TYPO3 has added them regardless of magic_quotes setting.
00300             if (is_array($value))   { self::stripSlashesOnArray($value); } else { $value = stripslashes($value); }
00301         }
00302         return $value;
00303     }
00304 
00305     /**
00306      * Returns the global $_POST array (or value from) normalized to contain un-escaped values.
00307      * ALWAYS use this API function to acquire the $_POST variables!
00308      * Usage: 41
00309      *
00310      * @param   string      Optional pointer to value in POST array (basically name of POST var)
00311      * @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!*
00312      * @see _GET(), _GP()
00313      */
00314     public static function _POST($var=NULL) {
00315         $value = ($var === NULL) ? $_POST : (empty($var) ? NULL : $_POST[$var]);
00316         if (isset($value))  {   // Removes slashes since TYPO3 has added them regardless of magic_quotes setting.
00317             if (is_array($value))   { self::stripSlashesOnArray($value); } else { $value = stripslashes($value); }
00318         }
00319         return $value;
00320     }
00321 
00322     /**
00323      * Writes input value to $_GET.
00324      * Usage: 2
00325      *
00326      * @param mixed $inputGet
00327      *        array or single value to write to $_GET. Values should NOT be
00328      *        escaped at input time (but will be escaped before writing
00329      *        according to TYPO3 standards).
00330      * @param string $key
00331      *        alternative key; If set, this will not set the WHOLE GET array,
00332      *        but only the key in it specified by this value!
00333      *        You can specify to replace keys on deeper array levels by
00334      *        separating the keys with a pipe.
00335      *        Example: 'parentKey|childKey' will result in
00336      *        array('parentKey' => array('childKey' => $inputGet))
00337      *
00338      * @return  void
00339      */
00340     public static function _GETset($inputGet, $key = '') {
00341             // adds slashes since TYPO3 standard currently is that slashes
00342             // must be applied (regardless of magic_quotes setting)
00343         if (is_array($inputGet)) {
00344             self::addSlashesOnArray($inputGet);
00345         } else {
00346             $inputGet = addslashes($inputGet);
00347         }
00348 
00349         if ($key != '') {
00350             if (strpos($key, '|') !== FALSE) {
00351                 $pieces = explode('|', $key);
00352                 $newGet = array();
00353                 $pointer =& $newGet;
00354                 foreach ($pieces as $piece) {
00355                     $pointer =& $pointer[$piece];
00356                 }
00357                 $pointer = $inputGet;
00358                 $mergedGet = self::array_merge_recursive_overrule(
00359                     $_GET, $newGet
00360                 );
00361 
00362                 $_GET = $mergedGet;
00363                 $GLOBALS['HTTP_GET_VARS'] = $mergedGet;
00364             } else {
00365                 $_GET[$key] = $inputGet;
00366                 $GLOBALS['HTTP_GET_VARS'][$key] = $inputGet;
00367             }
00368         } elseif (is_array($inputGet)) {
00369             $_GET = $inputGet;
00370             $GLOBALS['HTTP_GET_VARS'] = $inputGet;
00371         }
00372     }
00373 
00374     /**
00375      * Returns the  value of incoming data from globals variable $_POST or $_GET, with priority to $_POST (that is equalent to 'GP' order).
00376      * Strips slashes of string-outputs, but not arrays UNLESS $strip is set. If $strip is set all output will have escaped characters unescaped.
00377      * Usage: 2
00378      *
00379      * @param   string      GET/POST var to return
00380      * @param   boolean     If set, values are stripped of return values that are *arrays!* - string/integer values returned are always strip-slashed()
00381      * @return  mixed       POST var named $var and if not set, the GET var of the same name.
00382      * @deprecated since TYPO3 3.6 - Use t3lib_div::_GP instead (ALWAYS delivers a value with un-escaped values!)
00383      * @see _GP()
00384      */
00385     public static function GPvar($var,$strip=0) {
00386         self::logDeprecatedFunction();
00387 
00388         if(empty($var)) return;
00389         $value = isset($_POST[$var]) ? $_POST[$var] : $_GET[$var];
00390         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.
00391         if ($strip && isset($value) && is_array($value)) { self::stripSlashesOnArray($value); }
00392         return $value;
00393     }
00394 
00395     /**
00396      * Returns the global arrays $_GET and $_POST merged with $_POST taking precedence.
00397      * Usage: 1
00398      *
00399      * @param   string      Key (variable name) from GET or POST vars
00400      * @return  array       Returns the GET vars merged recursively onto the POST vars.
00401      * @deprecated since TYPO3 3.7 - Use t3lib_div::_GPmerged instead
00402      * @see _GP()
00403      */
00404     public static function GParrayMerged($var)  {
00405         self::logDeprecatedFunction();
00406 
00407         return self::_GPmerged($var);
00408     }
00409 
00410     /**
00411      * Wrapper for the RemoveXSS function.
00412      * Removes potential XSS code from an input string.
00413      *
00414      * Using an external class by Travis Puderbaugh <kallahar@quickwired.com>
00415      *
00416      * @param   string      Input string
00417      * @return  string      Input string with potential XSS code removed
00418      */
00419     public static function removeXSS($string)   {
00420         require_once(PATH_typo3.'contrib/RemoveXSS/RemoveXSS.php');
00421         $string = RemoveXSS::process($string);
00422         return $string;
00423     }
00424 
00425 
00426 
00427 
00428 
00429 
00430 
00431 
00432 
00433 
00434     /*************************
00435      *
00436      * IMAGE FUNCTIONS
00437      *
00438      *************************/
00439 
00440 
00441     /**
00442      * Compressing a GIF file if not already LZW compressed.
00443      * 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)
00444      *
00445      *      The function takes a file-reference, $theFile, and saves it again through GD or ImageMagick in order to compress the file
00446      *      GIF:
00447      *      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!)
00448      *      If $type is set to either 'IM' or 'GD' the compression is done with ImageMagick and GD respectively
00449      *      PNG:
00450      *      No changes.
00451      *
00452      *      $theFile is expected to be a valid GIF-file!
00453      *      The function returns a code for the operation.
00454      * Usage: 9
00455      *
00456      * @param   string      Filepath
00457      * @param   string      See description of function
00458      * @return  string      Returns "GD" if GD was used, otherwise "IM" if ImageMagick was used. If nothing done at all, it returns empty string.
00459      */
00460     public static function gif_compress($theFile, $type)    {
00461         $gfxConf = $GLOBALS['TYPO3_CONF_VARS']['GFX'];
00462         $returnCode='';
00463         if ($gfxConf['gif_compress'] && strtolower(substr($theFile,-4,4))=='.gif')  {   // GIF...
00464             if (($type=='IM' || !$type) && $gfxConf['im'] && $gfxConf['im_path_lzw'])   {   // IM
00465                 $cmd = self::imageMagickCommand('convert', '"'.$theFile.'" "'.$theFile.'"', $gfxConf['im_path_lzw']);
00466                 exec($cmd);
00467 
00468                 $returnCode='IM';
00469             } elseif (($type=='GD' || !$type) && $gfxConf['gdlib'] && !$gfxConf['gdlib_png'])   {   // GD
00470                 $tempImage = imageCreateFromGif($theFile);
00471                 imageGif($tempImage, $theFile);
00472                 imageDestroy($tempImage);
00473                 $returnCode='GD';
00474             }
00475         }
00476         return $returnCode;
00477     }
00478 
00479     /**
00480      * Converts a png file to gif.
00481      * This converts a png file to gif IF the FLAG $GLOBALS['TYPO3_CONF_VARS']['FE']['png_to_gif'] is set true.
00482      * Usage: 5
00483      *
00484      * @param   string      $theFile    the filename with path
00485      * @return  string      new filename
00486      */
00487     public static function png_to_gif_by_imagemagick($theFile)  {
00488         if ($GLOBALS['TYPO3_CONF_VARS']['FE']['png_to_gif']
00489             && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im']
00490             && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw']
00491             && strtolower(substr($theFile,-4,4))=='.png'
00492             && @is_file($theFile))  {   // IM
00493                 $newFile = substr($theFile,0,-4).'.gif';
00494                 $cmd = self::imageMagickCommand('convert', '"'.$theFile.'" "'.$newFile.'"', $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw']);
00495                 exec($cmd);
00496                 $theFile = $newFile;
00497                     // 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!!
00498         }
00499         return $theFile;
00500     }
00501 
00502     /**
00503      * Returns filename of the png/gif version of the input file (which can be png or gif).
00504      * If input file type does not match the wanted output type a conversion is made and temp-filename returned.
00505      * Usage: 2
00506      *
00507      * @param   string      Filepath of image file
00508      * @param   boolean     If set, then input file is converted to PNG, otherwise to GIF
00509      * @return  string      If the new image file exists, it's filepath is returned
00510      */
00511     public static function read_png_gif($theFile,$output_png=0) {
00512         if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['im'] && @is_file($theFile)) {
00513             $ext = strtolower(substr($theFile,-4,4));
00514             if (
00515                     ((string)$ext=='.png' && $output_png)   ||
00516                     ((string)$ext=='.gif' && !$output_png)
00517                 )   {
00518                 return $theFile;
00519             } else {
00520                 $newFile = PATH_site.'typo3temp/readPG_'.md5($theFile.'|'.filemtime($theFile)).($output_png?'.png':'.gif');
00521                 $cmd = self::imageMagickCommand('convert', '"'.$theFile.'" "'.$newFile.'"', $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path']);
00522                 exec($cmd);
00523                 if (@is_file($newFile)) return $newFile;
00524             }
00525         }
00526     }
00527 
00528 
00529 
00530 
00531 
00532 
00533 
00534 
00535 
00536 
00537 
00538 
00539 
00540 
00541 
00542     /*************************
00543      *
00544      * STRING FUNCTIONS
00545      *
00546      *************************/
00547 
00548     /**
00549      * Truncates string.
00550      * Returns a new string of max. $chars length.
00551      * If the string is longer, it will be truncated and appended with '...'.
00552      * Usage: 39
00553      *
00554      * @param   string      string to truncate
00555      * @param   integer     must be an integer with an absolute value of at least 4. if negative the string is cropped from the right end.
00556      * @param   string      String to append to the output if it is truncated, default is '...'
00557      * @return  string      new string
00558      * @deprecated since TYPO3 4.1 - Works ONLY for single-byte charsets! Use t3lib_div::fixed_lgd_cs() instead
00559      * @see fixed_lgd_pre()
00560      */
00561     public static function fixed_lgd($string,$origChars,$preStr='...')  {
00562         self::logDeprecatedFunction();
00563 
00564         $chars = abs($origChars);
00565         if ($chars >= 4)    {
00566             if(strlen($string)>$chars)  {
00567                 return $origChars < 0 ?
00568                     $preStr.trim(substr($string, -($chars-3))) :
00569                     trim(substr($string, 0, $chars-3)).$preStr;
00570             }
00571         }
00572         return $string;
00573     }
00574 
00575     /**
00576      * Truncates string.
00577      * Returns a new string of max. $chars length.
00578      * If the string is longer, it will be truncated and prepended with '...'.
00579      * This works like fixed_lgd(), but is truncated in the start of the string instead of the end
00580      * Usage: 6
00581      *
00582      * @param   string      string to truncate
00583      * @param   integer     must be an integer of at least 4
00584      * @return  string      new string
00585      * @deprecated since TYPO3 4.1 - Use either fixed_lgd() or fixed_lgd_cs() (with negative input value for $chars)
00586      * @see fixed_lgd()
00587      */
00588     public static function fixed_lgd_pre($string,$chars)    {
00589         self::logDeprecatedFunction();
00590 
00591         return strrev(self::fixed_lgd(strrev($string),$chars));
00592     }
00593 
00594     /**
00595      * Truncates a string with appended/prepended "..." and takes current character set into consideration.
00596      * Usage: 75
00597      *
00598      * @param   string      string to truncate
00599      * @param   integer     must be an integer with an absolute value of at least 4. if negative the string is cropped from the right end.
00600      * @param   string      appendix to the truncated string
00601      * @return  string      cropped string
00602      */
00603     public static function fixed_lgd_cs($string, $chars, $appendString='...') {
00604         if (is_object($GLOBALS['LANG'])) {
00605             return $GLOBALS['LANG']->csConvObj->crop($GLOBALS['LANG']->charSet, $string, $chars, $appendString);
00606         } elseif (is_object($GLOBALS['TSFE'])) {
00607             $charSet = ($GLOBALS['TSFE']->renderCharset != '' ? $GLOBALS['TSFE']->renderCharset : $GLOBALS['TSFE']->defaultCharSet);
00608             return $GLOBALS['TSFE']->csConvObj->crop($charSet, $string, $chars, $appendString);
00609         } else {
00610                 // this case should not happen
00611             $csConvObj = self::makeInstance('t3lib_cs');
00612             return $csConvObj->crop('iso-8859-1', $string, $chars, $appendString);
00613         }
00614     }
00615 
00616     /**
00617      * Breaks up the text for emails
00618      * Usage: 1
00619      *
00620      * @param   string      The string to break up
00621      * @param   string      The string to implode the broken lines with (default/typically \n)
00622      * @param   integer     The line length
00623      * @deprecated since TYPO3 4.1 - Use PHP function wordwrap()
00624      * @return  string
00625      */
00626     public static function breakTextForEmail($str,$implChar=LF,$charWidth=76)   {
00627         self::logDeprecatedFunction();
00628 
00629         $lines = explode(LF,$str);
00630         $outArr=array();
00631         foreach ($lines as $lStr) {
00632             $outArr[] = self::breakLinesForEmail($lStr,$implChar,$charWidth);
00633         }
00634         return implode(LF,$outArr);
00635     }
00636 
00637     /**
00638      * Breaks up a single line of text for emails
00639      * Usage: 5
00640      *
00641      * @param   string      The string to break up
00642      * @param   string      The string to implode the broken lines with (default/typically \n)
00643      * @param   integer     The line length
00644      * @return  string
00645      * @see breakTextForEmail()
00646      */
00647     public static function breakLinesForEmail($str,$implChar=LF,$charWidth=76)  {
00648         $lines=array();
00649         $l=$charWidth;
00650         $p=0;
00651         while(strlen($str)>$p)  {
00652             $substr=substr($str,$p,$l);
00653             if (strlen($substr)==$l)    {
00654                 $count = count(explode(' ',trim(strrev($substr))));
00655                 if ($count>1)   {   // OK...
00656                     $parts = explode(' ',strrev($substr),2);
00657                     $theLine = strrev($parts[1]);
00658                 } else {
00659                     $afterParts = explode(' ',substr($str,$l+$p),2);
00660                     $theLine = $substr.$afterParts[0];
00661                 }
00662                 if (!strlen($theLine))  {break; }   // Error, because this would keep us in an endless loop.
00663             } else {
00664                 $theLine=$substr;
00665             }
00666 
00667             $lines[]=trim($theLine);
00668             $p+=strlen($theLine);
00669             if (!trim(substr($str,$p,$l)))  break;  // added...
00670         }
00671         return implode($implChar,$lines);
00672     }
00673 
00674     /**
00675      * Match IP number with list of numbers with wildcard
00676      * Dispatcher method for switching into specialised IPv4 and IPv6 methods.
00677      * Usage: 10
00678      *
00679      * @param   string      $baseIP is the current remote IP address for instance, typ. REMOTE_ADDR
00680      * @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. An empty list always returns FALSE.
00681      * @return  boolean     True if an IP-mask from $list matches $baseIP
00682      */
00683     public static function cmpIP($baseIP, $list)    {
00684         $list = trim($list);
00685         if ($list === '')   {
00686             return false;
00687         } elseif ($list === '*')    {
00688             return true;
00689         }
00690         if (strpos($baseIP, ':') !== false && self::validIPv6($baseIP)) {
00691             return self::cmpIPv6($baseIP, $list);
00692         } else {
00693             return self::cmpIPv4($baseIP, $list);
00694         }
00695     }
00696 
00697     /**
00698      * Match IPv4 number with list of numbers with wildcard
00699      *
00700      * @param   string      $baseIP is the current remote IP address for instance, typ. REMOTE_ADDR
00701      * @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)
00702      * @return  boolean     True if an IP-mask from $list matches $baseIP
00703      */
00704     public static function cmpIPv4($baseIP, $list)  {
00705         $IPpartsReq = explode('.',$baseIP);
00706         if (count($IPpartsReq)==4)  {
00707             $values = self::trimExplode(',',$list,1);
00708 
00709             foreach($values as $test)   {
00710                 list($test,$mask) = explode('/',$test);
00711 
00712                 if(intval($mask)) {
00713                         // "192.168.3.0/24"
00714                     $lnet = ip2long($test);
00715                     $lip = ip2long($baseIP);
00716                     $binnet = str_pad( decbin($lnet),32,'0','STR_PAD_LEFT');
00717                     $firstpart = substr($binnet,0,$mask);
00718                     $binip = str_pad( decbin($lip),32,'0','STR_PAD_LEFT');
00719                     $firstip = substr($binip,0,$mask);
00720                     $yes = (strcmp($firstpart,$firstip)==0);
00721                 } else {
00722                         // "192.168.*.*"
00723                     $IPparts = explode('.',$test);
00724                     $yes = 1;
00725                     foreach ($IPparts as $index => $val) {
00726                         $val = trim($val);
00727                         if (strcmp($val,'*') && strcmp($IPpartsReq[$index],$val))   {
00728                             $yes=0;
00729                         }
00730                     }
00731                 }
00732                 if ($yes) return true;
00733             }
00734         }
00735         return false;
00736     }
00737 
00738     /**
00739      * Match IPv6 address with a list of IPv6 prefixes
00740      *
00741      * @param   string      $baseIP is the current remote IP address for instance
00742      * @param   string      $list is a comma-list of IPv6 prefixes, could also contain IPv4 addresses
00743      * @return  boolean     True if an baseIP matches any prefix
00744      */
00745     public static function cmpIPv6($baseIP, $list)  {
00746         $success = false;   // Policy default: Deny connection
00747         $baseIP = self::normalizeIPv6($baseIP);
00748 
00749         $values = self::trimExplode(',',$list,1);
00750         foreach ($values as $test)  {
00751             list($test,$mask) = explode('/',$test);
00752             if (self::validIPv6($test)) {
00753                 $test = self::normalizeIPv6($test);
00754                 if (intval($mask))  {
00755                     switch ($mask) {    // test on /48 /64
00756                         case '48':
00757                             $testBin = substr(self::IPv6Hex2Bin($test), 0, 48);
00758                             $baseIPBin = substr(self::IPv6Hex2Bin($baseIP), 0, 48);
00759                             $success = strcmp($testBin, $baseIPBin)==0 ? true : false;
00760                         break;
00761                         case '64':
00762                             $testBin = substr(self::IPv6Hex2Bin($test), 0, 64);
00763                             $baseIPBin = substr(self::IPv6Hex2Bin($baseIP), 0, 64);
00764                             $success = strcmp($testBin, $baseIPBin)==0 ? true : false;
00765                         break;
00766                         default:
00767                             $success = false;
00768                     }
00769                 } else {
00770                     if (self::validIPv6($test)) {   // test on full ip address 128 bits
00771                         $testBin = self::IPv6Hex2Bin($test);
00772                         $baseIPBin = self::IPv6Hex2Bin($baseIP);
00773                         $success = strcmp($testBin, $baseIPBin)==0 ? true : false;
00774                     }
00775                 }
00776             }
00777             if ($success) return true;
00778         }
00779         return false;
00780     }
00781 
00782     /**
00783      * [Describe function...]
00784      *
00785      * @param   [type]      $hex: ...
00786      * @return  [type]      ...
00787      */
00788     public static function IPv6Hex2Bin ($hex)   {
00789         $bin = '';
00790         $hex = str_replace(':', '', $hex);  // Replace colon to nothing
00791         for ($i=0; $i<strlen($hex); $i=$i+2)    {
00792             $bin.= chr(hexdec(substr($hex, $i, 2)));
00793         }
00794         return $bin;
00795     }
00796 
00797     /**
00798      * Normalize an IPv6 address to full length
00799      *
00800      * @param   string      Given IPv6 address
00801      * @return  string      Normalized address
00802      */
00803     public static function normalizeIPv6($address)  {
00804         $normalizedAddress = '';
00805         $stageOneAddress = '';
00806 
00807         $chunks = explode('::', $address);  // Count 2 if if address has hidden zero blocks
00808         if (count($chunks)==2)  {
00809             $chunksLeft = explode(':', $chunks[0]);
00810             $chunksRight = explode(':', $chunks[1]);
00811             $left = count($chunksLeft);
00812             $right = count($chunksRight);
00813 
00814                 // Special case: leading zero-only blocks count to 1, should be 0
00815             if ($left==1 && strlen($chunksLeft[0])==0)  $left=0;
00816 
00817             $hiddenBlocks = 8 - ($left + $right);
00818             $hiddenPart = '';
00819             while ($h<$hiddenBlocks)    {
00820                 $hiddenPart .= '0000:';
00821                 $h++;
00822             }
00823 
00824             if ($left == 0) {
00825                 $stageOneAddress = $hiddenPart . $chunks[1];
00826             } else {
00827                 $stageOneAddress = $chunks[0] . ':' . $hiddenPart . $chunks[1];
00828             }
00829         } else $stageOneAddress = $address;
00830 
00831             // normalize the blocks:
00832         $blocks = explode(':', $stageOneAddress);
00833         $divCounter = 0;
00834         foreach ($blocks as $block) {
00835             $tmpBlock = '';
00836             $i = 0;
00837             $hiddenZeros = 4 - strlen($block);
00838             while ($i < $hiddenZeros)   {
00839                 $tmpBlock .= '0';
00840                 $i++;
00841             }
00842             $normalizedAddress .= $tmpBlock . $block;
00843             if ($divCounter < 7)    {
00844                 $normalizedAddress .= ':';
00845                 $divCounter++;
00846             }
00847         }
00848         return $normalizedAddress;
00849     }
00850 
00851     /**
00852      * Validate a given IP address.
00853      *
00854      * Possible format are IPv4 and IPv6.
00855      *
00856      * @param   string      IP address to be tested
00857      * @return  boolean     True if $ip is either of IPv4 or IPv6 format.
00858      */
00859     public static function validIP($ip) {
00860         return (filter_var($ip, FILTER_VALIDATE_IP) !== false);
00861     }
00862 
00863     /**
00864      * Validate a given IP address to the IPv4 address format.
00865      *
00866      * Example for possible format:  10.0.45.99
00867      *
00868      * @param   string      IP address to be tested
00869      * @return  boolean     True if $ip is of IPv4 format.
00870      */
00871     public static function validIPv4($ip) {
00872         return (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false);
00873     }
00874 
00875     /**
00876      * Validate a given IP address to the IPv6 address format.
00877      *
00878      * Example for possible format:  43FB::BB3F:A0A0:0 | ::1
00879      *
00880      * @param   string      IP address to be tested
00881      * @return  boolean     True if $ip is of IPv6 format.
00882      */
00883     public static function validIPv6($ip)   {
00884         return (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false);
00885     }
00886 
00887     /**
00888      * Match fully qualified domain name with list of strings with wildcard
00889      *
00890      * @param   string      The current remote IP address for instance, typ. REMOTE_ADDR
00891      * @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)
00892      * @return  boolean     True if a domain name mask from $list matches $baseIP
00893      */
00894     public static function cmpFQDN($baseIP, $list)        {
00895         if (count(explode('.',$baseIP))==4)     {
00896             $resolvedHostName = explode('.', gethostbyaddr($baseIP));
00897             $values = self::trimExplode(',',$list,1);
00898 
00899             foreach($values as $test)   {
00900                 $hostNameParts = explode('.',$test);
00901                 $yes = 1;
00902 
00903                 foreach($hostNameParts as $index => $val)   {
00904                     $val = trim($val);
00905                     if (strcmp($val,'*') && strcmp($resolvedHostName[$index],$val)) {
00906                         $yes=0;
00907                     }
00908                 }
00909                 if ($yes) return true;
00910             }
00911         }
00912         return false;
00913     }
00914 
00915     /**
00916      * Checks if a given URL matches the host that currently handles this HTTP request.
00917      * Scheme, hostname and (optional) port of the given URL are compared.
00918      *
00919      * @param   string      $url: URL to compare with the TYPO3 request host
00920      * @return  boolean     Whether the URL matches the TYPO3 request host
00921      */
00922     public static function isOnCurrentHost($url) {
00923         return (stripos($url . '/', self::getIndpEnv('TYPO3_REQUEST_HOST') . '/') === 0);
00924     }
00925 
00926     /**
00927      * Check for item in list
00928      * Check if an item exists in a comma-separated list of items.
00929      * Usage: 163
00930      *
00931      * @param   string      comma-separated list of items (string)
00932      * @param   string      item to check for
00933      * @return  boolean     true if $item is in $list
00934      */
00935     public static function inList($list, $item) {
00936         return (strpos(','.$list.',', ','.$item.',')!==false ? true : false);
00937     }
00938 
00939     /**
00940      * Removes an item from a comma-separated list of items.
00941      * Usage: 1
00942      *
00943      * @param   string      element to remove
00944      * @param   string      comma-separated list of items (string)
00945      * @return  string      new comma-separated list of items
00946      */
00947     public static function rmFromList($element,$list)   {
00948         $items = explode(',',$list);
00949         foreach ($items as $k => $v) {
00950             if ($v==$element) {
00951                 unset($items[$k]);
00952             }
00953         }
00954         return implode(',',$items);
00955     }
00956 
00957     /**
00958      * Expand a comma-separated list of integers with ranges (eg 1,3-5,7 becomes 1,3,4,5,7).
00959      * Ranges are limited to 1000 values per range.
00960      *
00961      * @param   string      comma-separated list of integers with ranges (string)
00962      * @return  string      new comma-separated list of items
00963      * @author  Martin Kutschker <martin.kutschker@activesolution.at>
00964      */
00965     public static function expandList($list)      {
00966         $items = explode(',',$list);
00967         $list = array();
00968         foreach ($items as $item) {
00969             $range = explode('-',$item);
00970             if (isset($range[1]))   {
00971                 $runAwayBrake = 1000;
00972                 for ($n=$range[0]; $n<=$range[1]; $n++) {
00973                     $list[] = $n;
00974 
00975                     $runAwayBrake--;
00976                     if ($runAwayBrake<=0)   break;
00977                 }
00978             } else {
00979                 $list[] = $item;
00980             }
00981         }
00982         return implode(',',$list);
00983     }
00984 
00985     /**
00986      * Forces the integer $theInt into the boundaries of $min and $max. If the $theInt is 'false' then the $zeroValue is applied.
00987      * Usage: 224
00988      *
00989      * @param   integer     Input value
00990      * @param   integer     Lower limit
00991      * @param   integer     Higher limit
00992      * @param   integer     Default value if input is false.
00993      * @return  integer     The input value forced into the boundaries of $min and $max
00994      */
00995     public static function intInRange($theInt,$min,$max=2000000000,$zeroValue=0)    {
00996         // Returns $theInt as an integer in the integerspace from $min to $max
00997         $theInt = intval($theInt);
00998         if ($zeroValue && !$theInt) {$theInt=$zeroValue;}   // If the input value is zero after being converted to integer, zeroValue may set another default value for it.
00999         if ($theInt<$min){$theInt=$min;}
01000         if ($theInt>$max){$theInt=$max;}
01001         return $theInt;
01002     }
01003 
01004     /**
01005      * Returns the $integer if greater than zero, otherwise returns zero.
01006      * Usage: 1
01007      *
01008      * @param   integer     Integer string to process
01009      * @return  integer
01010      */
01011     public static function intval_positive($theInt) {
01012         $theInt = intval($theInt);
01013         if ($theInt<0){$theInt=0;}
01014         return $theInt;
01015     }
01016 
01017     /**
01018      * Returns an integer from a three part version number, eg '4.12.3' -> 4012003
01019      * Usage: 2
01020      *
01021      * @param   string      Version number on format x.x.x
01022      * @return  integer     Integer version of version number (where each part can count to 999)
01023      */
01024     public static function int_from_ver($verNumberStr)  {
01025         $verParts = explode('.',$verNumberStr);
01026         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));
01027     }
01028 
01029     /**
01030      * Returns true if the current TYPO3 version (or compatibility version) is compatible to the input version
01031      * Notice that this function compares branches, not versions (4.0.1 would be > 4.0.0 although they use the same compat_version)
01032      *
01033      * @param   string      Minimum branch number required (format x.y / e.g. "4.0" NOT "4.0.0"!)
01034      * @return  boolean     Returns true if this setup is compatible with the provided version number
01035      * @todo    Still needs a function to convert versions to branches
01036      */
01037     public static function compat_version($verNumberStr)    {
01038         global $TYPO3_CONF_VARS;
01039         $currVersionStr = $TYPO3_CONF_VARS['SYS']['compat_version'] ? $TYPO3_CONF_VARS['SYS']['compat_version'] : TYPO3_branch;
01040 
01041         if (self::int_from_ver($currVersionStr) < self::int_from_ver($verNumberStr))    {
01042             return FALSE;
01043         } else {
01044             return TRUE;
01045         }
01046     }
01047 
01048     /**
01049      * Makes a positive integer hash out of the first 7 chars from the md5 hash of the input
01050      * Usage: 5
01051      *
01052      * @param   string      String to md5-hash
01053      * @return  integer     Returns 28bit integer-hash
01054      */
01055     public static function md5int($str) {
01056         return hexdec(substr(md5($str),0,7));
01057     }
01058 
01059     /**
01060      * Returns the first 10 positions of the MD5-hash       (changed from 6 to 10 recently)
01061      *
01062      * Usage: 37
01063      *
01064      * @param   string      Input string to be md5-hashed
01065      * @param   integer     The string-length of the output
01066      * @return  string      Substring of the resulting md5-hash, being $len chars long (from beginning)
01067      */
01068     public static function shortMD5($input, $len=10)    {
01069         return substr(md5($input),0,$len);
01070     }
01071 
01072     /**
01073      * Returns a proper HMAC on a given input string and secret TYPO3 encryption key.
01074      *
01075      * @param   string      Input string to create HMAC from
01076      * @return  string      resulting (hexadecimal) HMAC currently with a length of 40 (HMAC-SHA-1)
01077      */
01078     public static function hmac($input) {
01079         $hashAlgorithm = 'sha1';
01080         $hashBlocksize = 64;
01081         $hmac = '';
01082 
01083         if (extension_loaded('hash') && function_exists('hash_hmac') && function_exists('hash_algos') && in_array($hashAlgorithm, hash_algos())) {
01084             $hmac = hash_hmac($hashAlgorithm, $input, $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']);
01085         } else {
01086                 // outer padding
01087             $opad = str_repeat(chr(0x5C), $hashBlocksize);
01088                 // innner padding
01089             $ipad = str_repeat(chr(0x36), $hashBlocksize);
01090             if (strlen($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']) > $hashBlocksize) {
01091                     // keys longer than blocksize are shorten
01092                 $key = str_pad(pack('H*', call_user_func($hashAlgorithm, $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])), $hashBlocksize, chr(0x00));
01093             } else {
01094                     // keys shorter than blocksize are zero-padded
01095                 $key = str_pad($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'], $hashBlocksize, chr(0x00));
01096             }
01097             $hmac = call_user_func($hashAlgorithm, ($key^$opad) . pack('H*', call_user_func($hashAlgorithm, ($key^$ipad) . $input)));
01098         }
01099         return $hmac;
01100     }
01101 
01102     /**
01103      * Takes comma-separated lists and arrays and removes all duplicates
01104      * If a value in the list is trim(empty), the value is ignored.
01105      * Usage: 16
01106      *
01107      * @param   string      Accept multiple parameters wich can be comma-separated lists of values and arrays.
01108      * @param   mixed       $secondParameter: Dummy field, which if set will show a warning!
01109      * @return  string      Returns the list without any duplicates of values, space around values are trimmed
01110      */
01111     public static function uniqueList($in_list, $secondParameter=NULL)  {
01112         if (is_array($in_list)) {
01113             throw new InvalidArgumentException(
01114                 'TYPO3 Fatal Error: t3lib_div::uniqueList() does NOT support array arguments anymore! Only string comma lists!',
01115                 1270853885
01116             );
01117         }
01118         if (isset($secondParameter)) {
01119             throw new InvalidArgumentException(
01120                 'TYPO3 Fatal Error: t3lib_div::uniqueList() does NOT support more than a single argument value anymore. You have specified more than one!',
01121                 1270853886
01122             );
01123         }
01124 
01125         return implode(',',array_unique(self::trimExplode(',',$in_list,1)));
01126     }
01127 
01128     /**
01129      * Splits a reference to a file in 5 parts
01130      * Usage: 43
01131      *
01132      * @param   string      Filename/filepath to be analysed
01133      * @return  array       Contains keys [path], [file], [filebody], [fileext], [realFileext]
01134      */
01135     public static function split_fileref($fileref)  {
01136         $reg = array();
01137         if (preg_match('/(.*\/)(.*)$/', $fileref, $reg)) {
01138             $info['path'] = $reg[1];
01139             $info['file'] = $reg[2];
01140         } else {
01141             $info['path'] = '';
01142             $info['file'] = $fileref;
01143         }
01144 
01145         $reg = '';
01146         if (!is_dir($fileref) && preg_match('/(.*)\.([^\.]*$)/', $info['file'], $reg)) {
01147             $info['filebody'] = $reg[1];
01148             $info['fileext'] = strtolower($reg[2]);
01149             $info['realFileext'] = $reg[2];
01150         } else {
01151             $info['filebody'] = $info['file'];
01152             $info['fileext'] = '';
01153         }
01154         reset($info);
01155         return $info;
01156     }
01157 
01158     /**
01159      * Returns the directory part of a path without trailing slash
01160      * If there is no dir-part, then an empty string is returned.
01161      * Behaviour:
01162      *
01163      * '/dir1/dir2/script.php' => '/dir1/dir2'
01164      * '/dir1/' => '/dir1'
01165      * 'dir1/script.php' => 'dir1'
01166      * 'd/script.php' => 'd'
01167      * '/script.php' => ''
01168      * '' => ''
01169      * Usage: 5
01170      *
01171      * @param   string      Directory name / path
01172      * @return  string      Processed input value. See function description.
01173      */
01174     public static function dirname($path)   {
01175         $p = self::revExplode('/',$path,2);
01176         return count($p)==2 ? $p[0] : '';
01177     }
01178 
01179     /**
01180      * Modifies a HTML Hex color by adding/subtracting $R,$G and $B integers
01181      * Usage: 11
01182      *
01183      * @param   string      A hexadecimal color code, #xxxxxx
01184      * @param   integer     Offset value 0-255
01185      * @param   integer     Offset value 0-255
01186      * @param   integer     Offset value 0-255
01187      * @return  string      A hexadecimal color code, #xxxxxx, modified according to input vars
01188      * @see modifyHTMLColorAll()
01189      */
01190     public static function modifyHTMLColor($color,$R,$G,$B) {
01191         // This takes a hex-color (# included!) and adds $R, $G and $B to the HTML-color (format: #xxxxxx) and returns the new color
01192         $nR = self::intInRange(hexdec(substr($color,1,2))+$R,0,255);
01193         $nG = self::intInRange(hexdec(substr($color,3,2))+$G,0,255);
01194         $nB = self::intInRange(hexdec(substr($color,5,2))+$B,0,255);
01195         return '#'.
01196             substr('0'.dechex($nR),-2).
01197             substr('0'.dechex($nG),-2).
01198             substr('0'.dechex($nB),-2);
01199     }
01200 
01201     /**
01202      * Modifies a HTML Hex color by adding/subtracting $all integer from all R/G/B channels
01203      * Usage: 6
01204      *
01205      * @param   string      A hexadecimal color code, #xxxxxx
01206      * @param   integer     Offset value 0-255 for all three channels.
01207      * @return  string      A hexadecimal color code, #xxxxxx, modified according to input vars
01208      * @see modifyHTMLColor()
01209      */
01210     public static function modifyHTMLColorAll($color,$all)  {
01211         return self::modifyHTMLColor($color,$all,$all,$all);
01212     }
01213 
01214     /**
01215      * Removes comma (if present) in the end of string
01216      * Usage: 2
01217      *
01218      * @param   string      String from which the comma in the end (if any) will be removed.
01219      * @return  string
01220      */
01221     public static function rm_endcomma($string) {
01222         return rtrim($string, ',');
01223     }
01224 
01225     /**
01226      * strtoupper which converts danish (and other characters) characters as well
01227      * Usage: 0
01228      *
01229      * @param   string      String to process
01230      * @return  string
01231      * @deprecated since TYPO3 3.5 - Use t3lib_cs::conv_case() instead or for HTML output, wrap your content in <span class="uppercase">...</span>)
01232      * @ignore
01233      */
01234     public static function danish_strtoupper($string)   {
01235         self::logDeprecatedFunction();
01236 
01237         $value = strtoupper($string);
01238         return strtr($value, 'áéúíâêûôîæøåäöü', 'ÁÉÚÍÄËÜÖÏÆØÅÄÖÜ');
01239     }
01240 
01241     /**
01242      * Change umlaut characters to plain ASCII with normally two character target
01243      * Only known characters will be converted, so don't expect a result for any character.
01244      *
01245      * ä => ae, Ö => Oe
01246      *
01247      * @param   string      String to convert.
01248      * @deprecated since TYPO3 4.1 - Works only for western europe single-byte charsets! Use t3lib_cs::specCharsToASCII() instead!
01249      * @return  string
01250      */
01251     public static function convUmlauts($str)    {
01252         self::logDeprecatedFunction();
01253 
01254         $pat  = array ( '/ä/',  '/Ä/',  '/ö/',  '/Ö/',  '/ü/',  '/Ü/',  '/ß/',  '/å/',  '/Å/',  '/ø/',  '/Ø/',  '/æ/',  '/Æ/'   );
01255         $repl = array ( 'ae',   'Ae',   'oe',   'Oe',   'ue',   'Ue',   'ss',   'aa',   'AA',   'oe',   'OE',   'ae',   'AE'    );
01256         return preg_replace($pat,$repl,$str);
01257     }
01258 
01259     /**
01260      * Tests if the input is an integer.
01261      * Usage: 77
01262      *
01263      * @param   mixed       Any input variable to test.
01264      * @return  boolean     Returns true if string is an integer
01265      */
01266     public static function testInt($var)    {
01267         return !strcmp($var,intval($var));
01268     }
01269 
01270     /**
01271      * Returns true if the first part of $str matches the string $partStr
01272      * Usage: 59
01273      *
01274      * @param   string      Full string to check
01275      * @param   string      Reference string which must be found as the "first part" of the full string
01276      * @return  boolean     True if $partStr was found to be equal to the first part of $str
01277      */
01278     public static function isFirstPartOfStr($str,$partStr)  {
01279         // Returns true, if the first part of a $str equals $partStr and $partStr is not ''
01280         $psLen = strlen($partStr);
01281         if ($psLen) {
01282             return substr($str,0,$psLen)==(string)$partStr;
01283         } else return false;
01284     }
01285 
01286     /**
01287      * Formats the input integer $sizeInBytes as bytes/kilobytes/megabytes (-/K/M)
01288      * Usage: 53
01289      *
01290      * @param   integer     Number of bytes to format.
01291      * @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)
01292      * @return  string      Formatted representation of the byte number, for output.
01293      */
01294     public static function formatSize($sizeInBytes,$labels='')  {
01295 
01296             // Set labels:
01297         if (strlen($labels) == 0) {
01298             $labels = ' | K| M| G';
01299         } else {
01300             $labels = str_replace('"','',$labels);
01301         }
01302         $labelArr = explode('|',$labels);
01303 
01304             // Find size:
01305         if ($sizeInBytes>900)   {
01306             if ($sizeInBytes>900000000) {   // GB
01307                 $val = $sizeInBytes/(1024*1024*1024);
01308                 return number_format($val, (($val<20)?1:0), '.', '').$labelArr[3];
01309             }
01310             elseif ($sizeInBytes>900000)    {   // MB
01311                 $val = $sizeInBytes/(1024*1024);
01312                 return number_format($val, (($val<20)?1:0), '.', '').$labelArr[2];
01313             } else {    // KB
01314                 $val = $sizeInBytes/(1024);
01315                 return number_format($val, (($val<20)?1:0), '.', '').$labelArr[1];
01316             }
01317         } else {    // Bytes
01318             return $sizeInBytes.$labelArr[0];
01319         }
01320     }
01321 
01322     /**
01323      * Returns microtime input to milliseconds
01324      * Usage: 2
01325      *
01326      * @param   string      Microtime
01327      * @return  integer     Microtime input string converted to an integer (milliseconds)
01328      */
01329     public static function convertMicrotime($microtime) {
01330         $parts = explode(' ',$microtime);
01331         return round(($parts[0]+$parts[1])*1000);
01332     }
01333 
01334     /**
01335      * This splits a string by the chars in $operators (typical /+-*) and returns an array with them in
01336      * Usage: 2
01337      *
01338      * @param   string      Input string, eg "123 + 456 / 789 - 4"
01339      * @param   string      Operators to split by, typically "/+-*"
01340      * @return  array       Array with operators and operands separated.
01341      * @see tslib_cObj::calc(), tslib_gifBuilder::calcOffset()
01342      */
01343     public static function splitCalc($string,$operators)    {
01344         $res = Array();
01345         $sign='+';
01346         while($string)  {
01347             $valueLen=strcspn($string,$operators);
01348             $value=substr($string,0,$valueLen);
01349             $res[] = Array($sign,trim($value));
01350             $sign=substr($string,$valueLen,1);
01351             $string=substr($string,$valueLen+1);
01352         }
01353         reset($res);
01354         return $res;
01355     }
01356 
01357     /**
01358      * Calculates the input by +,-,*,/,%,^ with priority to + and -
01359      * Usage: 1
01360      *
01361      * @param   string      Input string, eg "123 + 456 / 789 - 4"
01362      * @return  integer     Calculated value. Or error string.
01363      * @see calcParenthesis()
01364      */
01365     public static function calcPriority($string)    {
01366         $string=preg_replace('/[[:space:]]*/','',$string);  // removing all whitespace
01367         $string='+'.$string;    // Ensuring an operator for the first entrance
01368         $qm='\*\/\+-^%';
01369         $regex = '(['.$qm.'])(['.$qm.']?[0-9\.]*)';
01370             // split the expression here:
01371         $reg = array();
01372         preg_match_all('/'.$regex.'/',$string,$reg);
01373 
01374         reset($reg[2]);
01375         $number=0;
01376         $Msign='+';
01377         $err='';
01378         $buffer=doubleval(current($reg[2]));
01379         next($reg[2]);  // Advance pointer
01380 
01381         while(list($k,$v)=each($reg[2])) {
01382             $v=doubleval($v);
01383             $sign = $reg[1][$k];
01384             if ($sign=='+' || $sign=='-')   {
01385                 $number = $Msign=='-' ? $number-=$buffer : $number+=$buffer;
01386                 $Msign = $sign;
01387                 $buffer=$v;
01388             } else {
01389                 if ($sign=='/') {if ($v) $buffer/=$v; else $err='dividing by zero';}
01390                 if ($sign=='%') {if ($v) $buffer%=$v; else $err='dividing by zero';}
01391                 if ($sign=='*') {$buffer*=$v;}
01392                 if ($sign=='^') {$buffer=pow($buffer,$v);}
01393             }
01394         }
01395         $number = $Msign=='-' ? $number-=$buffer : $number+=$buffer;
01396         return $err ? 'ERROR: '.$err : $number;
01397     }
01398 
01399     /**
01400      * Calculates the input with parenthesis levels
01401      * Usage: 2
01402      *
01403      * @param   string      Input string, eg "(123 + 456) / 789 - 4"
01404      * @return  integer     Calculated value. Or error string.
01405      * @see calcPriority(), tslib_cObj::stdWrap()
01406      */
01407     public static function calcParenthesis($string) {
01408         $securC=100;
01409         do {
01410             $valueLenO=strcspn($string,'(');
01411             $valueLenC=strcspn($string,')');
01412             if ($valueLenC==strlen($string) || $valueLenC < $valueLenO) {
01413                 $value = self::calcPriority(substr($string,0,$valueLenC));
01414                 $string = $value.substr($string,$valueLenC+1);
01415                 return $string;
01416             } else {
01417                 $string = substr($string,0,$valueLenO).self::calcParenthesis(substr($string,$valueLenO+1));
01418             }
01419                 // Security:
01420             $securC--;
01421             if ($securC<=0) break;
01422         } while($valueLenO<strlen($string));
01423         return $string;
01424     }
01425 
01426     /**
01427      * Inverse version of htmlspecialchars()
01428      * Usage: 4
01429      *
01430      * @param   string      Value where &gt;, &lt;, &quot; and &amp; should be converted to regular chars.
01431      * @return  string      Converted result.
01432      */
01433     public static function htmlspecialchars_decode($value)  {
01434         $value = str_replace('&gt;','>',$value);
01435         $value = str_replace('&lt;','<',$value);
01436         $value = str_replace('&quot;','"',$value);
01437         $value = str_replace('&amp;','&',$value);
01438         return $value;
01439     }
01440 
01441     /**
01442      * Re-converts HTML entities if they have been converted by htmlspecialchars()
01443      * Usage: 10
01444      *
01445      * @param   string      String which contains eg. "&amp;amp;" which should stay "&amp;". Or "&amp;#1234;" to "&#1234;". Or "&amp;#x1b;" to "&#x1b;"
01446      * @return  string      Converted result.
01447      */
01448     public static function deHSCentities($str)  {
01449         return preg_replace('/&amp;([#[:alnum:]]*;)/','&\1',$str);
01450     }
01451 
01452     /**
01453      * This function is used to escape any ' -characters when transferring text to JavaScript!
01454      * Usage: 3
01455      *
01456      * @param   string      String to escape
01457      * @param   boolean     If set, also backslashes are escaped.
01458      * @param   string      The character to escape, default is ' (single-quote)
01459      * @return  string      Processed input string
01460      */
01461     public static function slashJS($string,$extended=0,$char="'")   {
01462         if ($extended)  {$string = str_replace ("\\", "\\\\", $string);}
01463         return str_replace ($char, "\\".$char, $string);
01464     }
01465 
01466     /**
01467      * Version of rawurlencode() where all spaces (%20) are re-converted to space-characters.
01468      * Usefull when passing text to JavaScript where you simply url-encode it to get around problems with syntax-errors, linebreaks etc.
01469      * Usage: 4
01470      *
01471      * @param   string      String to raw-url-encode with spaces preserved
01472      * @return  string      Rawurlencoded result of input string, but with all %20 (space chars) converted to real spaces.
01473      */
01474     public static function rawUrlEncodeJS($str) {
01475         return str_replace('%20',' ',rawurlencode($str));
01476     }
01477 
01478     /**
01479      * rawurlencode which preserves "/" chars
01480      * Usefull when filepaths should keep the "/" chars, but have all other special chars encoded.
01481      * Usage: 5
01482      *
01483      * @param   string      Input string
01484      * @return  string      Output string
01485      */
01486     public static function rawUrlEncodeFP($str) {
01487         return str_replace('%2F','/',rawurlencode($str));
01488     }
01489 
01490     /**
01491      * Checking syntax of input email address
01492      * Usage: 5
01493      *
01494      * @param   string      Input string to evaluate
01495      * @return  boolean     Returns true if the $email address (input string) is valid
01496      */
01497     public static function validEmail($email)   {
01498         return (filter_var($email, FILTER_VALIDATE_EMAIL) !== false);
01499     }
01500 
01501     /**
01502      * Checks if current e-mail sending method does not accept recipient/sender name
01503      * in a call to PHP mail() function. Windows version of mail() and mini_sendmail
01504      * program are known not to process such input correctly and they cause SMTP
01505      * errors. This function will return true if current mail sending method has
01506      * problem with recipient name in recipient/sender argument for mail().
01507      *
01508      * TODO: 4.3 should have additional configuration variable, which is combined
01509      * by || with the rest in this function.
01510      *
01511      * @return  boolean true if mail() does not accept recipient name
01512      */
01513     public static function isBrokenEmailEnvironment() {
01514         return TYPO3_OS == 'WIN' || (false !== strpos(ini_get('sendmail_path'), 'mini_sendmail'));
01515     }
01516 
01517     /**
01518      * Changes from/to arguments for mail() function to work in any environment.
01519      *
01520      * @param   string  $address    Address to adjust
01521      * @return  string  Adjusted address
01522      * @see t3lib_::isBrokenEmailEnvironment()
01523      */
01524     public static function normalizeMailAddress($address) {
01525         if (self::isBrokenEmailEnvironment() && false !== ($pos1 = strrpos($address, '<'))) {
01526             $pos2 = strpos($address, '>', $pos1);
01527             $address = substr($address, $pos1 + 1, ($pos2 ? $pos2 : strlen($address)) - $pos1 - 1);
01528         }
01529         return $address;
01530     }
01531 
01532     /**
01533      * Formats a string for output between <textarea>-tags
01534      * All content outputted in a textarea form should be passed through this function
01535      * 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!
01536      * Usage: 23
01537      *
01538      * @param   string      Input string to be formatted.
01539      * @return  string      Formatted for <textarea>-tags
01540      */
01541     public static function formatForTextarea($content)  {
01542         return LF.htmlspecialchars($content);
01543     }
01544 
01545     /**
01546      * Converts string to uppercase
01547      * The function converts all Latin characters (a-z, but no accents, etc) to
01548      * uppercase. It is safe for all supported character sets (incl. utf-8).
01549      * Unlike strtoupper() it does not honour the locale.
01550      *
01551      * @param   string      Input string
01552      * @return  string      Uppercase String
01553      */
01554     public static function strtoupper($str) {
01555         return strtr((string)$str, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
01556     }
01557 
01558     /**
01559      * Converts string to lowercase
01560      * The function converts all Latin characters (A-Z, but no accents, etc) to
01561      * lowercase. It is safe for all supported character sets (incl. utf-8).
01562      * Unlike strtolower() it does not honour the locale.
01563      *
01564      * @param   string      Input string
01565      * @return  string      Lowercase String
01566      */
01567     public static function strtolower($str) {
01568         return strtr((string)$str, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
01569     }
01570 
01571     /**
01572      * Returns a string of highly randomized bytes (over the full 8-bit range).
01573      *
01574      * @copyright   Drupal CMS
01575      * @license     GNU General Public License version 2
01576      * @param       integer  Number of characters (bytes) to return
01577      * @return      string   Random Bytes
01578      */
01579     public static function generateRandomBytes($count) {
01580         $output = '';
01581             // /dev/urandom is available on many *nix systems and is considered
01582             // the best commonly available pseudo-random source.
01583         if (TYPO3_OS != 'WIN' && ($fh = @fopen('/dev/urandom', 'rb'))) {
01584             $output = fread($fh, $count);
01585             fclose($fh);
01586         }
01587 
01588             // fallback if /dev/urandom is not available
01589         if (!isset($output{$count - 1})) {
01590                 // We initialize with the somewhat random.
01591             $randomState = $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']
01592                             . microtime() . getmypid();
01593             while (!isset($output{$count - 1})) {
01594                 $randomState = md5(microtime() . mt_rand() . $randomState);
01595                 $output .= md5(mt_rand() . $randomState, true);
01596             }
01597             $output = substr($output, strlen($output) - $count, $count);
01598         }
01599         return $output;
01600     }
01601 
01602     /**
01603      * Returns a given string with underscores as UpperCamelCase.
01604      * Example: Converts blog_example to BlogExample
01605      *
01606      * @param   string      $string: String to be converted to camel case
01607      * @return  string      UpperCamelCasedWord
01608      */
01609     public static function underscoredToUpperCamelCase($string) {
01610         $upperCamelCase = str_replace(' ', '', ucwords(str_replace('_', ' ', self::strtolower($string))));
01611         return $upperCamelCase;
01612     }
01613 
01614     /**
01615      * Returns a given string with underscores as lowerCamelCase.
01616      * Example: Converts minimal_value to minimalValue
01617      *
01618      * @param   string      $string: String to be converted to camel case
01619      * @return  string      lowerCamelCasedWord
01620      */
01621     public static function underscoredToLowerCamelCase($string) {
01622         $upperCamelCase = str_replace(' ', '', ucwords(str_replace('_', ' ', self::strtolower($string))));
01623         $lowerCamelCase = self::lcfirst($upperCamelCase);
01624         return $lowerCamelCase;
01625     }
01626 
01627     /**
01628      * Returns a given CamelCasedString as an lowercase string with underscores.
01629      * Example: Converts BlogExample to blog_example, and minimalValue to minimal_value
01630      *
01631      * @param   string      $string: String to be converted to lowercase underscore
01632      * @return  string      lowercase_and_underscored_string
01633      */
01634     public static function camelCaseToLowerCaseUnderscored($string) {
01635         return self::strtolower(preg_replace('/(?<=\w)([A-Z])/', '_\\1', $string));
01636     }
01637 
01638     /**
01639      * Converts the first char of a string to lowercase if it is a latin character (A-Z).
01640      * Example: Converts "Hello World" to "hello World"
01641      *
01642      * @param   string      $string: The string to be used to lowercase the first character
01643      * @return  string      The string with the first character as lowercase
01644      */
01645     public static function lcfirst($string) {
01646         return self::strtolower(substr($string, 0, 1)) . substr($string, 1);
01647     }
01648 
01649     /**
01650      * Checks if a given string is a Uniform Resource Locator (URL).
01651      *
01652      * @param   string      $url: The URL to be validated
01653      * @return  boolean     Whether the given URL is valid
01654      */
01655     public static function isValidUrl($url) {
01656         return (filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED) !== false);
01657     }
01658 
01659 
01660 
01661 
01662 
01663 
01664 
01665 
01666 
01667 
01668     /*************************
01669      *
01670      * ARRAY FUNCTIONS
01671      *
01672      *************************/
01673 
01674     /**
01675      * Check if an string item exists in an array.
01676      * Please note that the order of function parameters is reverse compared to the PHP function in_array()!!!
01677      *
01678      * Comparison to PHP in_array():
01679      * -> $array = array(0, 1, 2, 3);
01680      * -> variant_a := t3lib_div::inArray($array, $needle)
01681      * -> variant_b := in_array($needle, $array)
01682      * -> variant_c := in_array($needle, $array, true)
01683      * +---------+-----------+-----------+-----------+
01684      * | $needle | variant_a | variant_b | variant_c |
01685      * +---------+-----------+-----------+-----------+
01686      * | '1a'    | false     | true      | false     |
01687      * | ''      | false     | true      | false     |
01688      * | '0'     | true      | true      | false     |
01689      * | 0       | true      | true      | true      |
01690      * +---------+-----------+-----------+-----------+
01691      * Usage: 3
01692      *
01693      * @param   array       one-dimensional array of items
01694      * @param   string      item to check for
01695      * @return  boolean     true if $item is in the one-dimensional array $in_array
01696      */
01697     public static function inArray(array $in_array, $item) {
01698         foreach ($in_array as $val) {
01699             if (!is_array($val) && !strcmp($val, $item)) {
01700                 return true;
01701             }
01702         }
01703         return false;
01704     }
01705 
01706     /**
01707      * Explodes a $string delimited by $delim and passes each item in the array through intval().
01708      * Corresponds to t3lib_div::trimExplode(), but with conversion to integers for all values.
01709      * Usage: 76
01710      *
01711      * @param   string      Delimiter string to explode with
01712      * @param   string      The string to explode
01713      * @param   boolean     If set, all empty values (='') will NOT be set in output
01714      * @param   integer     If positive, the result will contain a maximum of limit elements,
01715      *                      if negative, all components except the last -limit are returned,
01716      *                      if zero (default), the result is not limited at all
01717      * @return  array       Exploded values, all converted to integers
01718      */
01719     public static function intExplode($delimiter, $string, $onlyNonEmptyValues = FALSE, $limit = 0) {
01720         $explodedValues = self::trimExplode($delimiter, $string, $onlyNonEmptyValues, $limit);
01721         return array_map('intval', $explodedValues);
01722     }
01723 
01724     /**
01725      * Reverse explode which explodes the string counting from behind.
01726      * Thus t3lib_div::revExplode(':','my:words:here',2) will return array('my:words','here')
01727      * Usage: 8
01728      *
01729      * @param   string      Delimiter string to explode with
01730      * @param   string      The string to explode
01731      * @param   integer     Number of array entries
01732      * @return  array       Exploded values
01733      */
01734     public static function revExplode($delimiter, $string, $count=0) {
01735         $explodedValues = explode($delimiter, strrev($string), $count);
01736         $explodedValues = array_map('strrev', $explodedValues);
01737         return array_reverse($explodedValues);
01738     }
01739 
01740     /**
01741      * Explodes a string and trims all values for whitespace in the ends.
01742      * If $onlyNonEmptyValues is set, then all blank ('') values are removed.
01743      * Usage: 256
01744      *
01745      * @param   string      Delimiter string to explode with
01746      * @param   string      The string to explode
01747      * @param   boolean     If set, all empty values will be removed in output
01748      * @param   integer     If positive, the result will contain a maximum of
01749      *                      $limit elements, if negative, all components except
01750      *                      the last -$limit are returned, if zero (default),
01751      *                      the result is not limited at all. Attention though
01752      *                      that the use of this parameter can slow down this
01753      *                      function.
01754      * @return  array       Exploded values
01755      */
01756     public static function trimExplode($delim, $string, $removeEmptyValues = false, $limit = 0) {
01757         $explodedValues = explode($delim, $string);
01758 
01759         $result = array_map('trim', $explodedValues);
01760 
01761         if ($removeEmptyValues) {
01762             $temp = array();
01763             foreach($result as $value) {
01764                 if ($value !== '') {
01765                     $temp[] = $value;
01766                 }
01767             }
01768             $result = $temp;
01769         }
01770 
01771         if ($limit != 0) {
01772             if ($limit < 0) {
01773                 $result = array_slice($result, 0, $limit);
01774             } elseif (count($result) > $limit) {
01775                 $lastElements = array_slice($result, $limit - 1);
01776                 $result = array_slice($result, 0, $limit - 1);
01777                 $result[] = implode($delim, $lastElements);
01778             }
01779         }
01780 
01781         return $result;
01782     }
01783 
01784     /**
01785      * Remove duplicate values from an array
01786      * Usage: 0
01787      *
01788      * @param   array       Array of values to make unique
01789      * @return  array
01790      * @ignore
01791      * @deprecated since TYPO3 3.5 - Use the PHP function array_unique instead
01792      */
01793     public static function uniqueArray(array $valueArray)   {
01794         self::logDeprecatedFunction();
01795 
01796         return array_unique($valueArray);
01797     }
01798 
01799     /**
01800      * Removes the value $cmpValue from the $array if found there. Returns the modified array
01801      * Usage: 3
01802      *
01803      * @param   array       Array containing the values
01804      * @param   string      Value to search for and if found remove array entry where found.
01805      * @return  array       Output array with entries removed if search string is found
01806      */
01807     public static function removeArrayEntryByValue(array $array, $cmpValue) {
01808         foreach ($array as $k => $v) {
01809             if (is_array($v)) {
01810                 $array[$k] = self::removeArrayEntryByValue($v, $cmpValue);
01811             } elseif (!strcmp($v, $cmpValue)) {
01812                 unset($array[$k]);
01813             }
01814         }
01815         return $array;
01816     }
01817 
01818     /**
01819      * Filters an array to reduce its elements to match the condition.
01820      * The values in $keepItems can be optionally evaluated by a custom callback function.
01821      *
01822      * Example (arguments used to call this function):
01823      * $array = array(
01824      *      array('aa' => array('first', 'second'),
01825      *      array('bb' => array('third', 'fourth'),
01826      *      array('cc' => array('fifth', 'sixth'),
01827      * );
01828      * $keepItems = array('third');
01829      * $getValueFunc = create_function('$value', 'return $value[0];');
01830      *
01831      * Returns:
01832      * array(
01833      *      array('bb' => array('third', 'fourth'),
01834      * )
01835      *
01836      * @param   array       $array: The initial array to be filtered/reduced
01837      * @param   mixed       $keepItems: The items which are allowed/kept in the array - accepts array or csv string
01838      * @param   string      $getValueFunc: (optional) Unique function name set by create_function() used to get the value to keep
01839      * @return  array       The filtered/reduced array with the kept items
01840      */
01841     public static function keepItemsInArray(array $array, $keepItems, $getValueFunc=null) {
01842         if ($array) {
01843                 // Convert strings to arrays:
01844             if (is_string($keepItems)) {
01845                 $keepItems = self::trimExplode(',', $keepItems);
01846             }
01847                 // create_function() returns a string:
01848             if (!is_string($getValueFunc)) {
01849                 $getValueFunc = null;
01850             }
01851                 // Do the filtering:
01852             if (is_array($keepItems) && count($keepItems)) {
01853                 foreach ($array as $key => $value) {
01854                         // Get the value to compare by using the callback function:
01855                     $keepValue = (isset($getValueFunc) ? $getValueFunc($value) : $value);
01856                     if (!in_array($keepValue, $keepItems)) {
01857                         unset($array[$key]);
01858                     }
01859                 }
01860             }
01861         }
01862         return $array;
01863     }
01864 
01865     /**
01866      * Implodes a multidim-array into GET-parameters (eg. &param[key][key2]=value2&param[key][key3]=value3)
01867      * Usage: 24
01868      *
01869      * @param   string      Name prefix for entries. Set to blank if you wish none.
01870      * @param   array       The (multidim) array to implode
01871      * @param   string      (keep blank)
01872      * @param   boolean     If set, parameters which were blank strings would be removed.
01873      * @param   boolean     If set, the param name itself (for example "param[key][key2]") would be rawurlencoded as well.
01874      * @return  string      Imploded result, fx. &param[key][key2]=value2&param[key][key3]=value3
01875      * @see explodeUrl2Array()
01876      */
01877     public static function implodeArrayForUrl($name, array $theArray, $str = '', $skipBlank = false, $rawurlencodeParamName = false) {
01878         foreach($theArray as $Akey => $AVal)    {
01879             $thisKeyName = $name ? $name.'['.$Akey.']' : $Akey;
01880             if (is_array($AVal))    {
01881                 $str = self::implodeArrayForUrl($thisKeyName,$AVal,$str,$skipBlank,$rawurlencodeParamName);
01882             } else {
01883                 if (!$skipBlank || strcmp($AVal,''))    {
01884                     $str.='&'.($rawurlencodeParamName ? rawurlencode($thisKeyName) : $thisKeyName).
01885                         '='.rawurlencode($AVal);
01886                 }
01887             }
01888         }
01889         return $str;
01890     }
01891 
01892     /**
01893      * Explodes a string with GETvars (eg. "&id=1&type=2&ext[mykey]=3") into an array
01894      *
01895      * @param   string      GETvars string
01896      * @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())
01897      * @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!
01898      * @see implodeArrayForUrl()
01899      */
01900     public static function explodeUrl2Array($string,$multidim=FALSE)    {
01901         $output = array();
01902         if ($multidim)  {
01903             parse_str($string,$output);
01904         } else {
01905             $p = explode('&',$string);
01906             foreach($p as $v)   {
01907                 if (strlen($v)) {
01908                     list($pK,$pV) = explode('=',$v,2);
01909                     $output[rawurldecode($pK)] = rawurldecode($pV);
01910                 }
01911             }
01912         }
01913         return $output;
01914     }
01915 
01916     /**
01917      * Returns an array with selected keys from incoming data.
01918      * (Better read source code if you want to find out...)
01919      * Usage: 3
01920      *
01921      * @param   string      List of variable/key names
01922      * @param   array       Array from where to get values based on the keys in $varList
01923      * @param   boolean     If set, then t3lib_div::_GP() is used to fetch the value if not found (isset) in the $getArray
01924      * @return  array       Output array with selected variables.
01925      */
01926     public static function compileSelectedGetVarsFromArray($varList,array $getArray,$GPvarAlt=1)    {
01927         $keys = self::trimExplode(',',$varList,1);
01928         $outArr = array();
01929         foreach($keys as $v)    {
01930             if (isset($getArray[$v]))   {
01931                 $outArr[$v] = $getArray[$v];
01932             } elseif ($GPvarAlt) {
01933                 $outArr[$v] = self::_GP($v);
01934             }
01935         }
01936         return $outArr;
01937     }
01938 
01939     /**
01940      * AddSlash array
01941      * This function traverses a multidimentional array and adds slashes to the values.
01942      * NOTE that the input array is and argument by reference.!!
01943      * Twin-function to stripSlashesOnArray
01944      * Usage: 8
01945      *
01946      * @param   array       Multidimensional input array, (REFERENCE!)
01947      * @return  array
01948      */
01949     public static function addSlashesOnArray(array &$theArray)  {
01950         foreach ($theArray as &$value) {
01951             if (is_array($value)) {
01952                 self::addSlashesOnArray($value);
01953             } else {
01954                 $value = addslashes($value);
01955             }
01956             unset($value);
01957         }
01958         reset($theArray);
01959     }
01960 
01961     /**
01962      * StripSlash array
01963      * This function traverses a multidimentional array and strips slashes to the values.
01964      * NOTE that the input array is and argument by reference.!!
01965      * Twin-function to addSlashesOnArray
01966      * Usage: 10
01967      *
01968      * @param   array       Multidimensional input array, (REFERENCE!)
01969      * @return  array
01970      */
01971     public static function stripSlashesOnArray(array &$theArray)    {
01972         foreach ($theArray as &$value) {
01973             if (is_array($value)) {
01974                 self::stripSlashesOnArray($value);
01975             } else {
01976                 $value = stripslashes($value);
01977             }
01978             unset($value);
01979         }
01980         reset($theArray);
01981     }
01982 
01983     /**
01984      * Either slashes ($cmd=add) or strips ($cmd=strip) array $arr depending on $cmd
01985      * Usage: 0
01986      *
01987      * @param   array       Multidimensional input array
01988      * @param   string      "add" or "strip", depending on usage you wish.
01989      * @return  array
01990      */
01991     public static function slashArray(array $arr,$cmd)  {
01992         if ($cmd=='strip')  self::stripSlashesOnArray($arr);
01993         if ($cmd=='add')    self::addSlashesOnArray($arr);
01994         return $arr;
01995     }
01996 
01997     /**
01998     * Rename Array keys with a given mapping table
01999     * @param    array   Array by reference which should be remapped
02000     * @param    array   Array with remap information, array/$oldKey => $newKey)
02001     */
02002     function remapArrayKeys(&$array, $mappingTable) {
02003         if (is_array($mappingTable)) {
02004             foreach ($mappingTable as $old => $new) {
02005                 if ($new && isset($array[$old])) {
02006                     $array[$new] = $array[$old];
02007                     unset ($array[$old]);
02008                 }
02009             }
02010         }
02011     }
02012 
02013 
02014     /**
02015      * Merges two arrays recursively and "binary safe" (integer keys are
02016      * overridden as well), overruling similar values in the first array
02017      * ($arr0) with the values of the second array ($arr1)
02018      * In case of identical keys, ie. keeping the values of the second.
02019      * Usage: 0
02020      *
02021      * @param   array       First array
02022      * @param   array       Second array, overruling the first array
02023      * @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.
02024      * @param   boolean     If set, values from $arr1 will overrule if they are empty or zero. Default: true
02025      * @return  array       Resulting array where $arr1 values has overruled $arr0 values
02026      */
02027     public static function array_merge_recursive_overrule(array $arr0,array $arr1,$notAddKeys=0,$includeEmtpyValues=true) {
02028         foreach ($arr1 as $key => $val) {
02029             if(is_array($arr0[$key])) {
02030                 if (is_array($arr1[$key]))  {
02031                     $arr0[$key] = self::array_merge_recursive_overrule($arr0[$key],$arr1[$key],$notAddKeys,$includeEmtpyValues);
02032                 }
02033             } else {
02034                 if ($notAddKeys) {
02035                     if (isset($arr0[$key])) {
02036                         if ($includeEmtpyValues || $val) {
02037                             $arr0[$key] = $val;
02038                         }
02039                     }
02040                 } else {
02041                     if ($includeEmtpyValues || $val) {
02042                         $arr0[$key] = $val;
02043                     }
02044                 }
02045             }
02046         }
02047         reset($arr0);
02048         return $arr0;
02049     }
02050 
02051     /**
02052      * 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.
02053      * Usage: 16
02054      *
02055      * @param   array       First array
02056      * @param   array       Second array
02057      * @return  array       Merged result.
02058      */
02059     public static function array_merge(array $arr1,array $arr2) {
02060         return $arr2+$arr1;
02061     }
02062 
02063     /**
02064      * Filters keys off from first array that also exist in second array. Comparision is done by keys.
02065      * This method is a recursive version of php array_diff_assoc()
02066      *
02067      * @param   array       Source array
02068      * @param   array       Reduce source array by this array
02069      * @return  array       Source array reduced by keys also present in second array
02070      */
02071     public static function arrayDiffAssocRecursive(array $array1, array $array2) {
02072         $differenceArray = array();
02073         foreach ($array1 as $key => $value) {
02074             if (!array_key_exists($key, $array2)) {
02075                 $differenceArray[$key] = $value;
02076             } elseif (is_array($value)) {
02077                 if (is_array($array2[$key])) {
02078                     $differenceArray[$key] = self::arrayDiffAssocRecursive($value, $array2[$key]);
02079                 }
02080             }
02081         }
02082 
02083         return $differenceArray;
02084     }
02085 
02086     /**
02087      * Takes a row and returns a CSV string of the values with $delim (default is ,) and $quote (default is ") as separator chars.
02088      * Usage: 5
02089      *
02090      * @param   array       Input array of values
02091      * @param   string      Delimited, default is comman
02092      * @param   string      Quote-character to wrap around the values.
02093      * @return  string      A single line of CSV
02094      */
02095     public static function csvValues(array $row,$delim=',',$quote='"')  {
02096         reset($row);
02097         $out=array();
02098         foreach ($row as $value) {
02099             $out[] = str_replace($quote, $quote.$quote, $value);
02100         }
02101         $str = $quote.implode($quote.$delim.$quote,$out).$quote;
02102         return $str;
02103     }
02104 
02105     /**
02106      * Creates recursively a JSON literal from a multidimensional associative array.
02107      * Uses native function of PHP >= 5.2.0
02108      *
02109      * @param   array       $jsonArray: The array to be transformed to JSON
02110      * @return  string      JSON string
02111      * @deprecated since TYPO3 4.3, use PHP native function json_encode() instead, will be removed in TYPO3 4.5
02112      */
02113     public static function array2json(array $jsonArray) {
02114         self::logDeprecatedFunction();
02115 
02116         return json_encode($jsonArray);
02117     }
02118 
02119     /**
02120      * Removes dots "." from end of a key identifier of TypoScript styled array.
02121      * array('key.' => array('property.' => 'value')) --> array('key' => array('property' => 'value'))
02122      *
02123      * @param   array   $ts: TypoScript configuration array
02124      * @return  array   TypoScript configuration array without dots at the end of all keys
02125      */
02126     public static function removeDotsFromTS(array $ts) {
02127         $out = array();
02128         foreach ($ts as $key => $value) {
02129             if (is_array($value)) {
02130                 $key = rtrim($key, '.');
02131                 $out[$key] = self::removeDotsFromTS($value);
02132             } else {
02133                 $out[$key] = $value;
02134             }
02135         }
02136         return $out;
02137     }
02138 
02139 
02140 
02141 
02142 
02143 
02144 
02145 
02146 
02147 
02148 
02149 
02150 
02151 
02152 
02153 
02154     /*************************
02155      *
02156      * HTML/XML PROCESSING
02157      *
02158      *************************/
02159 
02160     /**
02161      * Returns an array with all attributes of the input HTML tag as key/value pairs. Attributes are only lowercase a-z
02162      * $tag is either a whole tag (eg '<TAG OPTION ATTRIB=VALUE>') or the parameterlist (ex ' OPTION ATTRIB=VALUE>')
02163      * If an attribute is empty, then the value for the key is empty. You can check if it existed with isset()
02164      * Usage: 8
02165      *
02166      * @param   string      HTML-tag string (or attributes only)
02167      * @return  array       Array with the attribute values.
02168      */
02169     public static function get_tag_attributes($tag) {
02170         $components = self::split_tag_attributes($tag);
02171         $name = '';  // attribute name is stored here
02172         $valuemode = false;
02173         $attributes = array();
02174         foreach ($components as $key => $val)   {
02175             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
02176                 if ($valuemode) {
02177                     if ($name)  {
02178                         $attributes[$name] = $val;
02179                         $name = '';
02180                     }
02181                 } else {
02182                     if ($key = strtolower(preg_replace('/[^a-zA-Z0-9]/','',$val)))  {
02183                         $attributes[$key] = '';
02184                         $name = $key;
02185                     }
02186                 }
02187                 $valuemode = false;
02188             } else {
02189                 $valuemode = true;
02190             }
02191         }
02192         return $attributes;
02193     }
02194 
02195     /**
02196      * Returns an array with the 'components' from an attribute list from an HTML tag. The result is normally analyzed by get_tag_attributes
02197      * Removes tag-name if found
02198      * Usage: 2
02199      *
02200      * @param   string      HTML-tag string (or attributes only)
02201      * @return  array       Array with the attribute values.
02202      */
02203     public static function split_tag_attributes($tag)   {
02204         $tag_tmp = trim(preg_replace('/^<[^[:space:]]*/','',trim($tag)));
02205             // Removes any > in the end of the string
02206         $tag_tmp = trim(rtrim($tag_tmp, '>'));
02207 
02208         $value = array();
02209         while (strcmp($tag_tmp,'')) {   // Compared with empty string instead , 030102
02210             $firstChar=substr($tag_tmp,0,1);
02211             if (!strcmp($firstChar,'"') || !strcmp($firstChar,"'")) {
02212                 $reg=explode($firstChar,$tag_tmp,3);
02213                 $value[]=$reg[1];
02214                 $tag_tmp=trim($reg[2]);
02215             } elseif (!strcmp($firstChar,'=')) {
02216                 $value[] = '=';
02217                 $tag_tmp = trim(substr($tag_tmp,1));        // Removes = chars.
02218             } else {
02219                     // There are '' around the value. We look for the next ' ' or '>'
02220                 $reg = preg_split('/[[:space:]=]/', $tag_tmp, 2);
02221                 $value[] = trim($reg[0]);
02222                 $tag_tmp = trim(substr($tag_tmp,strlen($reg[0]),1).$reg[1]);
02223             }
02224         }
02225         reset($value);
02226         return $value;
02227     }
02228 
02229     /**
02230      * Implodes attributes in the array $arr for an attribute list in eg. and HTML tag (with quotes)
02231      * Usage: 14
02232      *
02233      * @param   array       Array with attribute key/value pairs, eg. "bgcolor"=>"red", "border"=>0
02234      * @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!
02235      * @param   boolean     If true, don't check if values are blank. Default is to omit attributes with blank values.
02236      * @return  string      Imploded attributes, eg. 'bgcolor="red" border="0"'
02237      */
02238     public static function implodeAttributes(array $arr,$xhtmlSafe=FALSE,$dontOmitBlankAttribs=FALSE)   {
02239         if ($xhtmlSafe) {
02240             $newArr=array();
02241             foreach($arr as $p => $v)   {
02242                 if (!isset($newArr[strtolower($p)])) $newArr[strtolower($p)] = htmlspecialchars($v);
02243             }
02244             $arr = $newArr;
02245         }
02246         $list = array();
02247         foreach($arr as $p => $v)   {
02248             if (strcmp($v,'') || $dontOmitBlankAttribs) {$list[]=$p.'="'.$v.'"';}
02249         }
02250         return implode(' ',$list);
02251     }
02252 
02253     /**
02254      * Implodes attributes in the array $arr for an attribute list in eg. and HTML tag (with quotes)
02255      *
02256      * @param   array       See implodeAttributes()
02257      * @param   boolean     See implodeAttributes()
02258      * @param   boolean     See implodeAttributes()
02259      * @return  string      See implodeAttributes()
02260      * @deprecated since TYPO3 3.7 - Name was changed into implodeAttributes
02261      * @see implodeAttributes()
02262      */
02263     public static function implodeParams(array $arr,$xhtmlSafe=FALSE,$dontOmitBlankAttribs=FALSE)   {
02264         self::logDeprecatedFunction();
02265 
02266         return self::implodeAttributes($arr,$xhtmlSafe,$dontOmitBlankAttribs);
02267     }
02268 
02269     /**
02270      * Wraps JavaScript code XHTML ready with <script>-tags
02271      * Automatic re-identing of the JS code is done by using the first line as ident reference.
02272      * This is nice for identing JS code with PHP code on the same level.
02273      *
02274      * @param   string      JavaScript code
02275      * @param   boolean     Wrap script element in linebreaks? Default is TRUE.
02276      * @return  string      The wrapped JS code, ready to put into a XHTML page
02277      * @author  Ingmar Schlecht <ingmars@web.de>
02278      * @author  René Fritz <r.fritz@colorcube.de>
02279      */
02280     public static function wrapJS($string, $linebreak=TRUE) {
02281         if(trim($string)) {
02282                 // <script wrapped in nl?
02283             $cr = $linebreak? LF : '';
02284 
02285                 // remove nl from the beginning
02286             $string = preg_replace ('/^\n+/', '', $string);
02287                 // re-ident to one tab using the first line as reference
02288             $match = array();
02289             if(preg_match('/^(\t+)/',$string,$match)) {
02290                 $string = str_replace($match[1],TAB, $string);
02291             }
02292             $string = $cr.'<script type="text/javascript">
02293 /*<![CDATA[*/
02294 '.$string.'
02295 /*]]>*/
02296 </script>'.$cr;
02297         }
02298         return trim($string);
02299     }
02300 
02301 
02302     /**
02303      * Parses XML input into a PHP array with associative keys
02304      * Usage: 0
02305      *
02306      * @param   string      XML data input
02307      * @param   integer     Number of element levels to resolve the XML into an array. Any further structure will be set as XML.
02308      * @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.
02309      * @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
02310      */
02311     public static function xml2tree($string,$depth=999) {
02312         $parser = xml_parser_create();
02313         $vals = array();
02314         $index = array();
02315 
02316         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
02317         xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
02318         xml_parse_into_struct($parser, $string, $vals, $index);
02319 
02320         if (xml_get_error_code($parser))    return 'Line '.xml_get_current_line_number($parser).': '.xml_error_string(xml_get_error_code($parser));
02321         xml_parser_free($parser);
02322 
02323         $stack = array( array() );
02324         $stacktop = 0;
02325         $startPoint=0;
02326 
02327 // FIXME don't use unset() - what does that mean? Use NULL or similar.
02328         unset($tagi);
02329         foreach($vals as $key => $val) {
02330             $type = $val['type'];
02331 
02332                 // open tag:
02333             if ($type=='open' || $type=='complete') {
02334                 $stack[$stacktop++] = $tagi;
02335 
02336                 if ($depth==$stacktop)  {
02337                     $startPoint=$key;
02338                 }
02339 
02340                 $tagi = array('tag' => $val['tag']);
02341 
02342                 if(isset($val['attributes']))  $tagi['attrs'] = $val['attributes'];
02343                 if(isset($val['value']))    $tagi['values'][] = $val['value'];
02344             }
02345                 // finish tag:
02346             if ($type=='complete' || $type=='close')    {
02347                 $oldtagi = $tagi;
02348                 $tagi = $stack[--$stacktop];
02349                 $oldtag = $oldtagi['tag'];
02350                 unset($oldtagi['tag']);
02351 
02352                 if ($depth==($stacktop+1))  {
02353                     if ($key-$startPoint > 0)   {
02354                         $partArray = array_slice(
02355                             $vals,
02356                             $startPoint+1,
02357                             $key-$startPoint-1
02358                         );
02359                         #$oldtagi=array('XMLvalue'=>self::xmlRecompileFromStructValArray($partArray));
02360                         $oldtagi['XMLvalue']=self::xmlRecompileFromStructValArray($partArray);
02361                     } else {
02362                         $oldtagi['XMLvalue']=$oldtagi['values'][0];
02363                     }
02364                 }
02365 
02366                 $tagi['ch'][$oldtag][] = $oldtagi;
02367                 unset($oldtagi);
02368             }
02369                 // cdata
02370             if($type=='cdata') {
02371                 $tagi['values'][] = $val['value'];
02372             }
02373         }
02374         return $tagi['ch'];
02375     }
02376 
02377     /**
02378      * Turns PHP array into XML. See array2xml()
02379      *
02380      * @param   array       The input PHP array with any kind of data; text, binary, integers. Not objects though.
02381      * @param   string      Alternative document tag. Default is "phparray".
02382      * @param   array       Options for the compilation. See array2xml() for description.
02383      * @param   string      Forced charset to prologue
02384      * @return  string      An XML string made from the input content in the array.
02385      * @see xml2array(),array2xml()
02386      */
02387     public static function array2xml_cs(array $array,$docTag='phparray',array $options=array(),$charset='') {
02388 
02389             // Figure out charset if not given explicitly:
02390         if (!$charset)  {
02391             if ($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'])  {   // First priority: forceCharset! If set, this will be authoritative!
02392                 $charset = $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'];
02393             } elseif (is_object($GLOBALS['LANG']))  {
02394                 $charset = $GLOBALS['LANG']->charSet;   // If "LANG" is around, that will hold the current charset
02395             } else {
02396                 $charset = 'iso-8859-1';    // THIS is just a hopeful guess!
02397             }
02398         }
02399 
02400             // Return XML:
02401         return '<?xml version="1.0" encoding="'.htmlspecialchars($charset).'" standalone="yes" ?>'.LF.
02402                 self::array2xml($array,'',0,$docTag,0, $options);
02403     }
02404 
02405     /**
02406      * Deprecated to call directly (unless you are aware of using XML prologues)! Use "array2xml_cs" instead (which adds an XML-prologue)
02407      *
02408      * Converts a PHP array into an XML string.
02409      * The XML output is optimized for readability since associative keys are used as tagnames.
02410      * 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.
02411      * Numeric keys are stored with the default tagname "numIndex" but can be overridden to other formats)
02412      * 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
02413      * 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.
02414      * 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!
02415      * 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...
02416      * Usage: 5
02417      *
02418      * @param   array       The input PHP array with any kind of data; text, binary, integers. Not objects though.
02419      * @param   string      tag-prefix, eg. a namespace prefix like "T3:"
02420      * @param   integer     Current recursion level. Don't change, stay at zero!
02421      * @param   string      Alternative document tag. Default is "phparray".
02422      * @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 TAB is used
02423      * @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')
02424      * @param   string      Stack data. Don't touch.
02425      * @return  string      An XML string made from the input content in the array.
02426      * @see xml2array()
02427      */
02428     public static function array2xml(array $array,$NSprefix='',$level=0,$docTag='phparray',$spaceInd=0,array $options=array(),array $stackData=array()) {
02429             // 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
02430         $binaryChars = chr(0).chr(1).chr(2).chr(3).chr(4).chr(5).chr(6).chr(7).chr(8).
02431                         chr(11).chr(12).chr(14).chr(15).chr(16).chr(17).chr(18).chr(19).
02432                         chr(20).chr(21).chr(22).chr(23).chr(24).chr(25).chr(26).chr(27).chr(28).chr(29).
02433                         chr(30).chr(31);
02434             // Set indenting mode:
02435         $indentChar = $spaceInd ? ' ' : TAB;
02436         $indentN = $spaceInd>0 ? $spaceInd : 1;
02437         $nl = ($spaceInd >= 0 ? LF : '');
02438 
02439             // Init output variable:
02440         $output='';
02441 
02442             // Traverse the input array
02443         foreach($array as $k=>$v)   {
02444             $attr = '';
02445             $tagName = $k;
02446 
02447                 // Construct the tag name.
02448             if(isset($options['grandParentTagMap'][$stackData['grandParentTagName'].'/'.$stackData['parentTagName']])) {        // Use tag based on grand-parent + parent tag name
02449                 $attr.=' index="'.htmlspecialchars($tagName).'"';
02450                 $tagName = (string)$options['grandParentTagMap'][$stackData['grandParentTagName'].'/'.$stackData['parentTagName']];
02451             }elseif(isset($options['parentTagMap'][$stackData['parentTagName'].':_IS_NUM']) && self::testInt($tagName)) {       // Use tag based on parent tag name + if current tag is numeric
02452                 $attr.=' index="'.htmlspecialchars($tagName).'"';
02453                 $tagName = (string)$options['parentTagMap'][$stackData['parentTagName'].':_IS_NUM'];
02454             }elseif(isset($options['parentTagMap'][$stackData['parentTagName'].':'.$tagName])) {        // Use tag based on parent tag name + current tag
02455                 $attr.=' index="'.htmlspecialchars($tagName).'"';
02456                 $tagName = (string)$options['parentTagMap'][$stackData['parentTagName'].':'.$tagName];
02457             } elseif(isset($options['parentTagMap'][$stackData['parentTagName']])) {        // Use tag based on parent tag name:
02458                 $attr.=' index="'.htmlspecialchars($tagName).'"';
02459                 $tagName = (string)$options['parentTagMap'][$stackData['parentTagName']];
02460             } elseif (!strcmp(intval($tagName),$tagName))   {   // If integer...;
02461                 if ($options['useNindex']) {    // If numeric key, prefix "n"
02462                     $tagName = 'n'.$tagName;
02463                 } else {    // Use special tag for num. keys:
02464                     $attr.=' index="'.$tagName.'"';
02465                     $tagName = $options['useIndexTagForNum'] ? $options['useIndexTagForNum'] : 'numIndex';
02466                 }
02467             } elseif($options['useIndexTagForAssoc']) {     // Use tag for all associative keys:
02468                 $attr.=' index="'.htmlspecialchars($tagName).'"';
02469                 $tagName = $options['useIndexTagForAssoc'];
02470             }
02471 
02472                 // The tag name is cleaned up so only alphanumeric chars (plus - and _) are in there and not longer than 100 chars either.
02473             $tagName = substr(preg_replace('/[^[:alnum:]_-]/','',$tagName),0,100);
02474 
02475                 // If the value is an array then we will call this function recursively:
02476             if (is_array($v))   {
02477 
02478                     // Sub elements:
02479                 if ($options['alt_options'][$stackData['path'].'/'.$tagName])   {
02480                     $subOptions = $options['alt_options'][$stackData['path'].'/'.$tagName];
02481                     $clearStackPath = $subOptions['clearStackPath'];
02482                 } else {
02483                     $subOptions = $options;
02484                     $clearStackPath = FALSE;
02485                 }
02486 
02487                 $content = $nl .
02488                             self::array2xml(
02489                                 $v,
02490                                 $NSprefix,
02491                                 $level+1,
02492                                 '',
02493                                 $spaceInd,
02494                                 $subOptions,
02495                                 array(
02496                                     'parentTagName' => $tagName,
02497                                     'grandParentTagName' => $stackData['parentTagName'],
02498                                     'path' => $clearStackPath ? '' : $stackData['path'].'/'.$tagName,
02499                                 )
02500                             ).
02501                             ($spaceInd >= 0 ? str_pad('',($level+1)*$indentN,$indentChar) : '');
02502                 if ((int)$options['disableTypeAttrib']!=2)  {   // Do not set "type = array". Makes prettier XML but means that empty arrays are not restored with xml2array
02503                     $attr.=' type="array"';
02504                 }
02505             } else {    // Just a value:
02506 
02507                     // Look for binary chars:
02508                 $vLen = strlen($v); // check for length, because PHP 5.2.0 may crash when first argument of strcspn is empty
02509                 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!
02510                         // If the value contained binary chars then we base64-encode it an set an attribute to notify this situation:
02511                     $content = $nl.chunk_split(base64_encode($v));
02512                     $attr.=' base64="1"';
02513                 } else {
02514                         // Otherwise, just htmlspecialchar the stuff:
02515                     $content = htmlspecialchars($v);
02516                     $dType = gettype($v);
02517                     if ($dType == 'string') {
02518                         if ($options['useCDATA'] && $content != $v) {
02519                             $content = '<![CDATA[' . $v . ']]>';
02520                         }
02521                     } elseif (!$options['disableTypeAttrib']) {
02522                         $attr.= ' type="'.$dType.'"';
02523                     }
02524                 }
02525             }
02526 
02527                 // Add the element to the output string:
02528             $output.=($spaceInd >= 0 ? str_pad('',($level+1)*$indentN,$indentChar) : '').'<'.$NSprefix.$tagName.$attr.'>'.$content.'</'.$NSprefix.$tagName.'>'.$nl;
02529         }
02530 
02531         // If we are at the outer-most level, then we finally wrap it all in the document tags and return that as the value:
02532         if (!$level)    {
02533             $output =
02534                 '<'.$docTag.'>'.$nl.
02535                 $output.
02536                 '</'.$docTag.'>';
02537         }
02538 
02539         return $output;
02540     }
02541 
02542     /**
02543      * Converts an XML string to a PHP array.
02544      * This is the reverse function of array2xml()
02545      * This is a wrapper for xml2arrayProcess that adds a two-level cache
02546      * Usage: 17
02547      *
02548      * @param   string      XML content to convert into an array
02549      * @param   string      The tag-prefix resolve, eg. a namespace like "T3:"
02550      * @param   boolean     If set, the document tag will be set in the key "_DOCUMENT_TAG" of the output array
02551      * @return  mixed       If the parsing had errors, a string with the error message is returned. Otherwise an array with the content.
02552      * @see array2xml(),xml2arrayProcess()
02553      * @author  Fabrizio Branca <typo3@fabrizio-branca.de> (added caching)
02554      */
02555     public static function xml2array($string,$NSprefix='',$reportDocTag=FALSE) {
02556         static $firstLevelCache = array();
02557 
02558         $identifier = md5($string . $NSprefix . ($reportDocTag ? '1' : '0'));
02559 
02560             // look up in first level cache
02561         if (!empty($firstLevelCache[$identifier])) {
02562             $array = $firstLevelCache[$identifier];
02563         } else {
02564                 // look up in second level cache
02565             $cacheContent = t3lib_pageSelect::getHash($identifier, 0);
02566             $array = unserialize($cacheContent);
02567 
02568             if ($array === false) {
02569                 $array = self::xml2arrayProcess($string, $NSprefix, $reportDocTag);
02570                 t3lib_pageSelect::storeHash($identifier, serialize($array), 'ident_xml2array');
02571             }
02572                 // store content in first level cache
02573             $firstLevelCache[$identifier] = $array;
02574         }
02575         return $array;
02576     }
02577 
02578     /**
02579      * Converts an XML string to a PHP array.
02580      * This is the reverse function of array2xml()
02581      * Usage: 1
02582      *
02583      * @param   string      XML content to convert into an array
02584      * @param   string      The tag-prefix resolve, eg. a namespace like "T3:"
02585      * @param   boolean     If set, the document tag will be set in the key "_DOCUMENT_TAG" of the output array
02586      * @return  mixed       If the parsing had errors, a string with the error message is returned. Otherwise an array with the content.
02587      * @see array2xml()
02588      */
02589     protected function xml2arrayProcess($string,$NSprefix='',$reportDocTag=FALSE) {
02590         global $TYPO3_CONF_VARS;
02591 
02592             // Create parser:
02593         $parser = xml_parser_create();
02594         $vals = array();
02595         $index = array();
02596 
02597         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
02598         xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
02599 
02600             // default output charset is UTF-8, only ASCII, ISO-8859-1 and UTF-8 are supported!!!
02601         $match = array();
02602         preg_match('/^[[:space:]]*<\?xml[^>]*encoding[[:space:]]*=[[:space:]]*"([^"]*)"/',substr($string,0,200),$match);
02603         $theCharset = $match[1] ? $match[1] : ($TYPO3_CONF_VARS['BE']['forceCharset'] ? $TYPO3_CONF_VARS['BE']['forceCharset'] : 'iso-8859-1');
02604         xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $theCharset);  // us-ascii / utf-8 / iso-8859-1
02605 
02606             // Parse content:
02607         xml_parse_into_struct($parser, $string, $vals, $index);
02608 
02609             // If error, return error message:
02610         if (xml_get_error_code($parser))    {
02611             return 'Line '.xml_get_current_line_number($parser).': '.xml_error_string(xml_get_error_code($parser));
02612         }
02613         xml_parser_free($parser);
02614 
02615             // Init vars:
02616         $stack = array(array());
02617         $stacktop = 0;
02618         $current = array();
02619         $tagName = '';
02620         $documentTag = '';
02621 
02622             // Traverse the parsed XML structure:
02623         foreach($vals as $key => $val) {
02624 
02625                 // First, process the tag-name (which is used in both cases, whether "complete" or "close")
02626             $tagName = $val['tag'];
02627             if (!$documentTag)  $documentTag = $tagName;
02628 
02629                 // Test for name space:
02630             $tagName = ($NSprefix && substr($tagName,0,strlen($NSprefix))==$NSprefix) ? substr($tagName,strlen($NSprefix)) : $tagName;
02631 
02632                 // Test for numeric tag, encoded on the form "nXXX":
02633             $testNtag = substr($tagName,1); // Closing tag.
02634             $tagName = (substr($tagName,0,1)=='n' && !strcmp(intval($testNtag),$testNtag)) ? intval($testNtag) : $tagName;
02635 
02636                 // Test for alternative index value:
02637             if (strlen($val['attributes']['index']))    { $tagName = $val['attributes']['index']; }
02638 
02639                 // Setting tag-values, manage stack:
02640             switch($val['type'])    {
02641                 case 'open':        // If open tag it means there is an array stored in sub-elements. Therefore increase the stackpointer and reset the accumulation array:
02642                     $current[$tagName] = array();   // Setting blank place holder
02643                     $stack[$stacktop++] = $current;
02644                     $current = array();
02645                 break;
02646                 case 'close':   // If the tag is "close" then it is an array which is closing and we decrease the stack pointer.
02647                     $oldCurrent = $current;
02648                     $current = $stack[--$stacktop];
02649                     end($current);  // Going to the end of array to get placeholder key, key($current), and fill in array next:
02650                     $current[key($current)] = $oldCurrent;
02651                     unset($oldCurrent);
02652                 break;
02653                 case 'complete':    // If "complete", then it's a value. If the attribute "base64" is set, then decode the value, otherwise just set it.
02654                     if ($val['attributes']['base64'])   {
02655                         $current[$tagName] = base64_decode($val['value']);
02656                     } else {
02657                         $current[$tagName] = (string)$val['value']; // Had to cast it as a string - otherwise it would be evaluate false if tested with isset()!!
02658 
02659                             // Cast type:
02660                         switch((string)$val['attributes']['type'])  {
02661                             case 'integer':
02662                                 $current[$tagName] = (integer)$current[$tagName];
02663                             break;
02664                             case 'double':
02665                                 $current[$tagName] = (double)$current[$tagName];
02666                             break;
02667                             case 'boolean':
02668                                 $current[$tagName] = (bool)$current[$tagName];
02669                             break;
02670                             case 'array':
02671                                 $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...
02672                             break;
02673                         }
02674                     }
02675                 break;
02676             }
02677         }
02678 
02679         if ($reportDocTag)  {
02680             $current[$tagName]['_DOCUMENT_TAG'] = $documentTag;
02681         }
02682 
02683             // Finally return the content of the document tag.
02684         return $current[$tagName];
02685     }
02686 
02687     /**
02688      * This implodes an array of XML parts (made with xml_parse_into_struct()) into XML again.
02689      * Usage: 2
02690      *
02691      * @param   array       A array of XML parts, see xml2tree
02692      * @return  string      Re-compiled XML data.
02693      */
02694     public static function xmlRecompileFromStructValArray(array $vals)  {
02695         $XMLcontent='';
02696 
02697         foreach($vals as $val) {
02698             $type = $val['type'];
02699 
02700                 // open tag:
02701             if ($type=='open' || $type=='complete') {
02702                 $XMLcontent.='<'.$val['tag'];
02703                 if(isset($val['attributes']))  {
02704                     foreach($val['attributes'] as $k => $v) {
02705                         $XMLcontent.=' '.$k.'="'.htmlspecialchars($v).'"';
02706                     }
02707                 }
02708                 if ($type=='complete')  {
02709                     if(isset($val['value']))    {
02710                         $XMLcontent.='>'.htmlspecialchars($val['value']).'</'.$val['tag'].'>';
02711                     } else $XMLcontent.='/>';
02712                 } else $XMLcontent.='>';
02713 
02714                 if ($type=='open' && isset($val['value']))  {
02715                     $XMLcontent.=htmlspecialchars($val['value']);
02716                 }
02717             }
02718                 // finish tag:
02719             if ($type=='close') {
02720                 $XMLcontent.='</'.$val['tag'].'>';
02721             }
02722                 // cdata
02723             if($type=='cdata') {
02724                 $XMLcontent.=htmlspecialchars($val['value']);
02725             }
02726         }
02727 
02728         return $XMLcontent;
02729     }
02730 
02731     /**
02732      * Extracts the attributes (typically encoding and version) of an XML prologue (header).
02733      * Usage: 1
02734      *
02735      * @param   string      XML data
02736      * @return  array       Attributes of the xml prologue (header)
02737      */
02738     public static function xmlGetHeaderAttribs($xmlData)    {
02739         $match = array();
02740         if (preg_match('/^\s*<\?xml([^>]*)\?\>/', $xmlData, $match))    {
02741             return self::get_tag_attributes($match[1]);
02742         }
02743     }
02744 
02745     /**
02746      * Minifies JavaScript
02747      *
02748      * @param   string  $script Script to minify
02749      * @param   string  $error  Error message (if any)
02750      * @return  string  Minified script or source string if error happened
02751      */
02752     public static function minifyJavaScript($script, &$error = '') {
02753         require_once(PATH_typo3 . 'contrib/jsmin/jsmin.php');
02754         try {
02755             $error = '';
02756             $script = trim(JSMin::minify(str_replace(CR, '', $script)));
02757         }
02758         catch(JSMinException $e) {
02759             $error = 'Error while minifying JavaScript: ' . $e->getMessage();
02760             self::devLog($error, 't3lib_div', 2,
02761                 array('JavaScript' => $script, 'Stack trace' => $e->getTrace()));
02762         }
02763         return $script;
02764     }
02765 
02766 
02767 
02768 
02769 
02770 
02771 
02772 
02773     /*************************
02774      *
02775      * FILES FUNCTIONS
02776      *
02777      *************************/
02778 
02779     /**
02780      * Reads the file or url $url and returns the content
02781      * 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.
02782      * Usage: 83
02783      *
02784      * @param   string      File/URL to read
02785      * @param   integer     Whether the HTTP header should be fetched or not. 0=disable, 1=fetch header+content, 2=fetch header only
02786      * @param   array           HTTP headers to be used in the request
02787      * @param   array           Error code/message and, if $includeHeader is 1, response meta data (HTTP status and content type)
02788      * @return  string  The content from the resource given as input. FALSE if an error has occured.
02789      */
02790     public static function getURL($url, $includeHeader = 0, $requestHeaders = false, &$report = NULL)   {
02791         $content = false;
02792 
02793         if (isset($report)) {
02794             $report['error'] = 0;
02795             $report['message'] = '';
02796         }
02797 
02798             // use cURL for: http, https, ftp, ftps, sftp and scp
02799         if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlUse'] == '1' && preg_match('/^(?:http|ftp)s?|s(?:ftp|cp):/', $url)) {
02800             if (isset($report)) {
02801                 $report['lib'] = 'cURL';
02802             }
02803 
02804                 // External URL without error checking.
02805             $ch = curl_init();
02806             if (!$ch)   {
02807                 if (isset($report)) {
02808                     $report['error'] = -1;
02809                     $report['message'] = 'Couldn\'t initialize cURL.';
02810                 }
02811                 return false;
02812             }
02813 
02814             curl_setopt($ch, CURLOPT_URL, $url);
02815             curl_setopt($ch, CURLOPT_HEADER, $includeHeader ? 1 : 0);
02816             curl_setopt($ch, CURLOPT_NOBODY, $includeHeader == 2 ? 1 : 0);
02817             curl_setopt($ch, CURLOPT_HTTPGET, $includeHeader == 2 ? 'HEAD' : 'GET');
02818             curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
02819             curl_setopt($ch, CURLOPT_FAILONERROR, 1);
02820             curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, max(0, intval($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlTimeout'])));
02821 
02822                 // may fail (PHP 5.2.0+ and 5.1.5+) when open_basedir or safe_mode are enabled
02823             $followLocation = @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
02824 
02825             if (is_array($requestHeaders))  {
02826                 curl_setopt($ch, CURLOPT_HTTPHEADER, $requestHeaders);
02827             }
02828 
02829                 // (Proxy support implemented by Arco <arco@appeltaart.mine.nu>)
02830             if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyServer'])  {
02831                 curl_setopt($ch, CURLOPT_PROXY, $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyServer']);
02832 
02833                 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyTunnel'])  {
02834                     curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyTunnel']);
02835                 }
02836                 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyUserPass'])    {
02837                     curl_setopt($ch, CURLOPT_PROXYUSERPWD, $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyUserPass']);
02838                 }
02839             }
02840             $content = curl_exec($ch);
02841             if (isset($report)) {
02842                 if ($content===FALSE)   {
02843                     $report['error'] = curl_errno($ch);
02844                     $report['message'] = curl_error($ch);
02845                 } else {
02846                     $curlInfo = curl_getinfo($ch);
02847                         // We hit a redirection but we couldn't follow it
02848                     if (!$followLocation && $curlInfo['status'] >= 300 && $curlInfo['status'] < 400)     {
02849                         $report['error'] = -1;
02850                         $report['message'] = 'Couldn\'t follow location redirect (either PHP configuration option safe_mode or open_basedir is in effect).';
02851                     } elseif($includeHeader) {
02852                             // Set only for $includeHeader to work exactly like PHP variant
02853                         $report['http_code'] = $curlInfo['http_code'];
02854                         $report['content_type'] = $curlInfo['content_type'];
02855                     }
02856                 }
02857             }
02858             curl_close($ch);
02859 
02860         } elseif ($includeHeader)   {
02861             if (isset($report)) {
02862                 $report['lib'] = 'socket';
02863             }
02864             $parsedURL = parse_url($url);
02865             if (!preg_match('/^https?/', $parsedURL['scheme'])) {
02866                 if (isset($report)) {
02867                     $report['error'] = -1;
02868                     $report['message'] = 'Reading headers is not allowed for this protocol.';
02869                 }
02870                 return false;
02871             }
02872             $port = intval($parsedURL['port']);
02873             if ($port < 1)  {
02874                 if ($parsedURL['scheme'] == 'http') {
02875                     $port = ($port>0 ? $port : 80);
02876                     $scheme = '';
02877                 } else {
02878                     $port = ($port>0 ? $port : 443);
02879                     $scheme = 'ssl://';
02880                 }
02881             }
02882             $errno = 0;
02883             // $errstr = '';
02884             $fp = @fsockopen($scheme.$parsedURL['host'], $port, $errno, $errstr, 2.0);
02885             if (!$fp || $errno > 0) {
02886                 if (isset($report)) {
02887                     $report['error'] = $errno ? $errno : -1;
02888                     $report['message'] = $errno ? ($errstr ? $errstr : 'Socket error.') : 'Socket initialization error.';
02889                 }
02890                 return false;
02891             }
02892             $method = ($includeHeader == 2) ? 'HEAD' : 'GET';
02893             $msg = $method . ' ' . $parsedURL['path'] .
02894                     ($parsedURL['query'] ? '?' . $parsedURL['query'] : '') .
02895                     ' HTTP/1.0' . CRLF . 'Host: ' .
02896                     $parsedURL['host'] . "\r\nConnection: close\r\n";
02897             if (is_array($requestHeaders))  {
02898                 $msg .= implode(CRLF, $requestHeaders) . CRLF;
02899             }
02900             $msg .= CRLF;
02901 
02902             fputs($fp, $msg);
02903             while (!feof($fp))  {
02904                 $line = fgets($fp, 2048);
02905                 if (isset($report)) {
02906                     if (preg_match('|^HTTP/\d\.\d +(\d+)|', $line, $status))    {
02907                         $report['http_code'] = $status[1];
02908                     }
02909                     elseif (preg_match('/^Content-Type: *(.*)/i', $line, $type))    {
02910                         $report['content_type'] = $type[1];
02911                     }
02912                 }
02913                 $content .= $line;
02914                 if (!strlen(trim($line)))   {
02915                     break;  // Stop at the first empty line (= end of header)
02916                 }
02917             }
02918             if ($includeHeader != 2)    {
02919                 $content .= stream_get_contents($fp);
02920             }
02921             fclose($fp);
02922 
02923         } elseif (is_array($requestHeaders))    {
02924             if (isset($report)) {
02925                 $report['lib'] = 'file/context';
02926             }
02927             $parsedURL = parse_url($url);
02928             if (!preg_match('/^https?/', $parsedURL['scheme'])) {
02929                 if (isset($report)) {
02930                     $report['error'] = -1;
02931                     $report['message'] = 'Sending request headers is not allowed for this protocol.';
02932                 }
02933                 return false;
02934             }
02935             $ctx = stream_context_create(array(
02936                         'http' => array(
02937                             'header' => implode(CRLF, $requestHeaders)
02938                         )
02939                     )
02940                 );
02941             $content = @file_get_contents($url, false, $ctx);
02942             if ($content === false && isset($report)) {
02943                 $phpError = error_get_last();
02944                 $report['error'] = $phpError['type'];
02945                 $report['message'] = $phpError['message'];
02946             }
02947         } else  {
02948             if (isset($report)) {
02949                 $report['lib'] = 'file';
02950             }
02951             $content = @file_get_contents($url);
02952             if ($content === false && isset($report))   {
02953                 if (function_exists('error_get_last')) {
02954                     $phpError = error_get_last();
02955                     $report['error'] = $phpError['type'];
02956                     $report['message'] = $phpError['message'];
02957                 } else {
02958                     $report['error'] = -1;
02959                     $report['message'] = 'Couldn\'t get URL.';
02960                 }
02961             }
02962         }
02963 
02964         return $content;
02965     }
02966 
02967     /**
02968      * Writes $content to the file $file
02969      * Usage: 30
02970      *
02971      * @param   string      Filepath to write to
02972      * @param   string      Content to write
02973      * @return  boolean     True if the file was successfully opened and written to.
02974      */
02975     public static function writeFile($file,$content)    {
02976         if (!@is_file($file))   $changePermissions = true;
02977 
02978         if ($fd = fopen($file,'wb'))    {
02979             $res = fwrite($fd,$content);
02980             fclose($fd);
02981 
02982             if ($res===false)   return false;
02983 
02984             if ($changePermissions) {   // Change the permissions only if the file has just been created
02985                 self::fixPermissions($file);
02986             }
02987 
02988             return true;
02989         }
02990 
02991         return false;
02992     }
02993 
02994     /**
02995      * Sets the file system mode and group ownership of a file or a folder.
02996      *
02997      * @param   string   Absolute filepath of file or folder, must not be escaped.
02998      * @param   boolean  If set, also fixes permissions of files and folders in the folder (if $path is a folder)
02999      * @return  mixed    TRUE on success, FALSE on error, always TRUE on Windows OS
03000      */
03001     public static function fixPermissions($path, $recursive = FALSE) {
03002         if (TYPO3_OS != 'WIN') {
03003             $result = FALSE;
03004             if (self::isAllowedAbsPath($path)) {
03005                 if (@is_file($path)) {
03006                         // "@" is there because file is not necessarily OWNED by the user
03007                     $result = @chmod($path, octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask']));
03008                 } elseif (@is_dir($path)) {
03009                     $path = preg_replace('|/$|', '', $path);
03010                         // "@" is there because file is not necessarily OWNED by the user
03011                     $result = @chmod($path, octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask']));
03012                 }
03013 
03014                     // Set createGroup if not empty
03015                 if($GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup']) {
03016                         // "@" is there because file is not necessarily OWNED by the user
03017                     $changeGroupResult = @chgrp($path, $GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup']);
03018                     $result = $changeGroupResult ? $result : FALSE;
03019                 }
03020 
03021                     // Call recursive if recursive flag if set and $path is directory
03022                 if ($recursive && @is_dir($path)) {
03023                     $handle = opendir($path);
03024                     while (($file = readdir($handle)) !== FALSE) {
03025                         unset($recursionResult);
03026                         if ($file !== '.' && $file !== '..') {
03027                             if (@is_file($path . '/' . $file)) {
03028                                 $recursionResult = self::fixPermissions($path . '/' . $file);
03029                             } elseif (@is_dir($path . '/' . $file)) {
03030                                 $recursionResult = self::fixPermissions($path . '/' . $file, TRUE);
03031                             }
03032                             if (isset($recursionResult) && !$recursionResult) {
03033                                 $result = FALSE;
03034                             }
03035                         }
03036                     }
03037                     closedir($handle);
03038                 }
03039             }
03040         } else {
03041             $result = TRUE;
03042         }
03043         return $result;
03044     }
03045 
03046     /**
03047      * Writes $content to a filename in the typo3temp/ folder (and possibly one or two subfolders...)
03048      * Accepts an additional subdirectory in the file path!
03049      *
03050      * @param   string      Absolute filepath to write to inside "typo3temp/". First part of this string must match PATH_site."typo3temp/"
03051      * @param   string      Content string to write
03052      * @return  string      Returns false on success, otherwise an error string telling about the problem.
03053      */
03054     public static function writeFileToTypo3tempDir($filepath,$content)  {
03055 
03056             // Parse filepath into directory and basename:
03057         $fI = pathinfo($filepath);
03058         $fI['dirname'].= '/';
03059 
03060             // Check parts:
03061         if (self::validPathStr($filepath) && $fI['basename'] && strlen($fI['basename'])<60) {
03062             if (defined('PATH_site'))   {
03063                 $dirName = PATH_site.'typo3temp/';  // Setting main temporary directory name (standard)
03064                 if (@is_dir($dirName))  {
03065                     if (self::isFirstPartOfStr($fI['dirname'],$dirName))    {
03066 
03067                             // Checking if the "subdir" is found:
03068                         $subdir = substr($fI['dirname'],strlen($dirName));
03069                         if ($subdir)    {
03070                             if (preg_match('/^[[:alnum:]_]+\/$/',$subdir) || preg_match('/^[[:alnum:]_]+\/[[:alnum:]_]+\/$/',$subdir))  {
03071                                 $dirName.= $subdir;
03072                                 if (!@is_dir($dirName)) {
03073                                     self::mkdir_deep(PATH_site.'typo3temp/', $subdir);
03074                                 }
03075                             } else return 'Subdir, "'.$subdir.'", was NOT on the form "[[:alnum:]_]/" or  "[[:alnum:]_]/[[:alnum:]_]/"';
03076                         }
03077                             // Checking dir-name again (sub-dir might have been created):
03078                         if (@is_dir($dirName))  {
03079                             if ($filepath == $dirName.$fI['basename'])  {
03080                                 self::writeFile($filepath, $content);
03081                                 if (!@is_file($filepath))   return 'File not written to disk! Write permission error in filesystem?';
03082                             } else return 'Calculated filelocation didn\'t match input $filepath!';
03083                         } else return '"'.$dirName.'" is not a directory!';
03084                     } else return '"'.$fI['dirname'].'" was not within directory PATH_site + "typo3temp/"';
03085                 } else return 'PATH_site + "typo3temp/" was not a directory!';
03086             } else return 'PATH_site constant was NOT defined!';
03087         } else return 'Input filepath "'.$filepath.'" was generally invalid!';
03088     }
03089 
03090     /**
03091      * Wrapper function for mkdir.
03092      * Sets folder permissions according to $GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask']
03093      * and group ownership according to $GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup']
03094      *
03095      * @param   string      Absolute path to folder, see PHP mkdir() function. Removes trailing slash internally.
03096      * @return  boolean     TRUE if @mkdir went well!
03097      */
03098     public static function mkdir($newFolder) {
03099         $newFolder = preg_replace('|/$|', '', $newFolder);
03100         $result = @mkdir($newFolder, octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask']));
03101         if ($result) {
03102             self::fixPermissions($newFolder);
03103         }
03104         return $result;
03105     }
03106 
03107     /**
03108      * Creates a directory - including parent directories if necessary - in the file system
03109      *
03110      * @param   string      Base folder. This must exist! Must have trailing slash! Example "/root/typo3site/"
03111      * @param   string      Deep directory to create, eg. "xx/yy/" which creates "/root/typo3site/xx/yy/" if $destination is "/root/typo3site/"
03112      * @return  string      If error, returns error string.
03113      */
03114     public static function mkdir_deep($destination,$deepDir)    {
03115         $allParts = self::trimExplode('/',$deepDir,1);
03116         $root = '';
03117         foreach($allParts as $part) {
03118             $root.= $part.'/';
03119             if (!is_dir($destination.$root))    {
03120                 self::mkdir($destination.$root);
03121                 if (!@is_dir($destination.$root))   {
03122                     return 'Error: The directory "'.$destination.$root.'" could not be created...';
03123                 }
03124             }
03125         }
03126     }
03127 
03128     /**
03129      * Wrapper function for rmdir, allowing recursive deletion of folders and files
03130      *
03131      * @param   string      Absolute path to folder, see PHP rmdir() function. Removes trailing slash internally.
03132      * @param   boolean     Allow deletion of non-empty directories
03133      * @return  boolean     true if @rmdir went well!
03134      */
03135     public static function rmdir($path,$removeNonEmpty=false)   {
03136         $OK = false;
03137         $path = preg_replace('|/$|','',$path);  // Remove trailing slash
03138 
03139         if (file_exists($path)) {
03140             $OK = true;
03141 
03142             if (is_dir($path))  {
03143                 if ($removeNonEmpty==true && $handle = opendir($path))  {
03144                     while ($OK && false !== ($file = readdir($handle))) {
03145                         if ($file=='.' || $file=='..') continue;
03146                         $OK = self::rmdir($path.'/'.$file,$removeNonEmpty);
03147                     }
03148                     closedir($handle);
03149                 }
03150                 if ($OK)    { $OK = rmdir($path); }
03151 
03152             } else {    // If $dirname is a file, simply remove it
03153                 $OK = unlink($path);
03154             }
03155 
03156             clearstatcache();
03157         }
03158 
03159         return $OK;
03160     }
03161 
03162     /**
03163      * Returns an array with the names of folders in a specific path
03164      * Will return 'error' (string) if there were an error with reading directory content.
03165      * Usage: 11
03166      *
03167      * @param   string      Path to list directories from
03168      * @return  array       Returns an array with the directory entries as values. If no path, the return value is nothing.
03169      */
03170     public static function get_dirs($path)  {
03171         if ($path) {
03172             if (is_dir($path)) {
03173                 $dir = scandir($path);
03174                 $dirs = array();
03175                 foreach ($dir as $entry) {
03176                     if (is_dir($path . '/' . $entry) && $entry != '..' && $entry != '.') {
03177                         $dirs[] = $entry;
03178                     }
03179                 }
03180             } else {
03181                 $dirs = 'error';
03182             }
03183         }
03184         return $dirs;
03185     }
03186 
03187     /**
03188      * Returns an array with the names of files in a specific path
03189      * Usage: 18
03190      *
03191      * @param   string      $path: Is the path to the file
03192      * @param   string      $extensionList is the comma list of extensions to read only (blank = all)
03193      * @param   boolean     If set, then the path is prepended the filenames. Otherwise only the filenames are returned in the array
03194      * @param   string      $order is sorting: 1= sort alphabetically, 'mtime' = sort by modification time.
03195      * @param   string      A comma seperated list of filenames to exclude, no wildcards
03196      * @return  array       Array of the files found
03197      */
03198     public static function getFilesInDir($path,$extensionList='',$prependPath=0,$order='',$excludePattern='')   {
03199 
03200             // Initialize variabels:
03201         $filearray = array();
03202         $sortarray = array();
03203         $path = rtrim($path, '/');
03204 
03205             // Find files+directories:
03206         if (@is_dir($path)) {
03207             $extensionList = strtolower($extensionList);
03208             $d = dir($path);
03209             if (is_object($d))  {
03210                 while($entry=$d->read()) {
03211                     if (@is_file($path.'/'.$entry)) {
03212                         $fI = pathinfo($entry);
03213                         $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)
03214                         if ((!strlen($extensionList) || self::inList($extensionList,strtolower($fI['extension']))) && (!strlen($excludePattern) || !preg_match('/^'.$excludePattern.'$/',$entry)))  {
03215                             $filearray[$key]=($prependPath?$path.'/':'').$entry;
03216                                 if ($order=='mtime') {$sortarray[$key]=filemtime($path.'/'.$entry);}
03217                                 elseif ($order) {$sortarray[$key]=$entry;}
03218                         }
03219                     }
03220                 }
03221                 $d->close();
03222             } else return 'error opening path: "'.$path.'"';
03223         }
03224 
03225             // Sort them:
03226         if ($order) {
03227             asort($sortarray);
03228             $newArr=array();
03229             foreach ($sortarray as $k => $v) {
03230                 $newArr[$k]=$filearray[$k];
03231             }
03232             $filearray=$newArr;
03233         }
03234 
03235             // Return result
03236         reset($filearray);
03237         return $filearray;
03238     }
03239 
03240     /**
03241      * Recursively gather all files and folders of a path.
03242      * Usage: 5
03243      *
03244      * @param   array       $fileArr: Empty input array (will have files added to it)
03245      * @param   string      $path: The path to read recursively from (absolute) (include trailing slash!)
03246      * @param   string      $extList: Comma list of file extensions: Only files with extensions in this list (if applicable) will be selected.
03247      * @param   boolean     $regDirs: If set, directories are also included in output.
03248      * @param   integer     $recursivityLevels: The number of levels to dig down...
03249      * @param string        $excludePattern: regex pattern of files/directories to exclude
03250      * @return  array       An array with the found files/directories.
03251      */
03252     public static function getAllFilesAndFoldersInPath(array $fileArr,$path,$extList='',$regDirs=0,$recursivityLevels=99,$excludePattern='')    {
03253         if ($regDirs)   $fileArr[] = $path;
03254         $fileArr = array_merge($fileArr, self::getFilesInDir($path,$extList,1,1,$excludePattern));
03255 
03256         $dirs = self::get_dirs($path);
03257         if (is_array($dirs) && $recursivityLevels>0)    {
03258             foreach ($dirs as $subdirs) {
03259                 if ((string)$subdirs!='' && (!strlen($excludePattern) || !preg_match('/^'.$excludePattern.'$/',$subdirs)))  {
03260                     $fileArr = self::getAllFilesAndFoldersInPath($fileArr,$path.$subdirs.'/',$extList,$regDirs,$recursivityLevels-1,$excludePattern);
03261                 }
03262             }
03263         }
03264         return $fileArr;
03265     }
03266 
03267     /**
03268      * Removes the absolute part of all files/folders in fileArr
03269      * Usage: 2
03270      *
03271      * @param   array       $fileArr: The file array to remove the prefix from
03272      * @param   string      $prefixToRemove: The prefix path to remove (if found as first part of string!)
03273      * @return  array       The input $fileArr processed.
03274      */
03275     public static function removePrefixPathFromList(array $fileArr,$prefixToRemove) {
03276         foreach ($fileArr as $k => &$absFileRef) {
03277             if (self::isFirstPartOfStr($absFileRef, $prefixToRemove)) {
03278                 $absFileRef = substr($absFileRef, strlen($prefixToRemove));
03279             } else {
03280                 return 'ERROR: One or more of the files was NOT prefixed with the prefix-path!';
03281             }
03282         }
03283         return $fileArr;
03284     }
03285 
03286     /**
03287      * Fixes a path for windows-backslashes and reduces double-slashes to single slashes
03288      * Usage: 2
03289      *
03290      * @param   string      File path to process
03291      * @return  string
03292      */
03293     public static function fixWindowsFilePath($theFile) {
03294         return str_replace('//','/', str_replace('\\','/', $theFile));
03295     }
03296 
03297     /**
03298      * Resolves "../" sections in the input path string.
03299      * For example "fileadmin/directory/../other_directory/" will be resolved to "fileadmin/other_directory/"
03300      * Usage: 2
03301      *
03302      * @param   string      File path in which "/../" is resolved
03303      * @return  string
03304      */
03305     public static function resolveBackPath($pathStr)    {
03306         $parts = explode('/',$pathStr);
03307         $output=array();
03308         $c = 0;
03309         foreach($parts as $pV)  {
03310             if ($pV=='..')  {
03311                 if ($c) {
03312                     array_pop($output);
03313                     $c--;
03314                 } else $output[]=$pV;
03315             } else {
03316                 $c++;
03317                 $output[]=$pV;
03318             }
03319         }
03320         return implode('/',$output);
03321     }
03322 
03323     /**
03324      * Prefixes a URL used with 'header-location' with 'http://...' depending on whether it has it already.
03325      * - If already having a scheme, nothing is prepended
03326      * - If having REQUEST_URI slash '/', then prefixing 'http://[host]' (relative to host)
03327      * - Otherwise prefixed with TYPO3_REQUEST_DIR (relative to current dir / TYPO3_REQUEST_DIR)
03328      * Usage: 30
03329      *
03330      * @param   string      URL / path to prepend full URL addressing to.
03331      * @return  string
03332      */
03333     public static function locationHeaderUrl($path) {
03334         $uI = parse_url($path);
03335         if (substr($path,0,1)=='/') { // relative to HOST
03336             $path = self::getIndpEnv('TYPO3_REQUEST_HOST').$path;
03337         } elseif (!$uI['scheme'])   { // No scheme either
03338             $path = self::getIndpEnv('TYPO3_REQUEST_DIR').$path;
03339         }
03340         return $path;
03341     }
03342 
03343     /**
03344      * Returns the maximum upload size for a file that is allowed. Measured in KB.
03345      * This might be handy to find out the real upload limit that is possible for this
03346      * TYPO3 installation. The first parameter can be used to set something that overrides
03347      * the maxFileSize, usually for the TCA values.
03348      *
03349      * @param   integer     $localLimit: the number of Kilobytes (!) that should be used as
03350      *                      the initial Limit, otherwise $TYPO3_CONF_VARS['BE']['maxFileSize'] will be used
03351      * @return  integer     the maximum size of uploads that are allowed (measuered in kilobytes)
03352      */
03353     public static function getMaxUploadFileSize($localLimit = 0) {
03354             // don't allow more than the global max file size at all
03355         $t3Limit = (intval($localLimit > 0 ? $localLimit : $GLOBALS['TYPO3_CONF_VARS']['BE']['maxFileSize']));
03356             // as TYPO3 is handling the file size in KB, multiply by 1024 to get bytes
03357         $t3Limit = $t3Limit * 1024;
03358 
03359             // check for PHP restrictions of the maximum size of one of the $_FILES
03360         $phpUploadLimit = self::getBytesFromSizeMeasurement(ini_get('upload_max_filesize'));
03361             // check for PHP restrictions of the maximum $_POST size
03362         $phpPostLimit = self::getBytesFromSizeMeasurement(ini_get('post_max_size'));
03363             // if the total amount of post data is smaller (!) than the upload_max_filesize directive,
03364             // then this is the real limit in PHP
03365         $phpUploadLimit = ($phpPostLimit < $phpUploadLimit ? $phpPostLimit : $phpUploadLimit);
03366 
03367             // is the allowed PHP limit (upload_max_filesize) lower than the TYPO3 limit?, also: revert back to KB
03368         return floor($phpUploadLimit < $t3Limit ? $phpUploadLimit : $t3Limit) / 1024;
03369     }
03370 
03371     /**
03372      * Gets the bytes value from a measurement string like "100k".
03373      *
03374      * @param   string      $measurement: The measurement (e.g. "100k")
03375      * @return  integer     The bytes value (e.g. 102400)
03376      */
03377     public static function getBytesFromSizeMeasurement($measurement) {
03378         if (stripos($measurement, 'G')) {
03379             $bytes = intval($measurement) * 1024 * 1024 * 1024;
03380         } else if (stripos($measurement, 'M')) {
03381             $bytes = intval($measurement) * 1024 * 1024;
03382         } else if (stripos($measurement, 'K')) {
03383             $bytes = intval($measurement) * 1024;
03384         } else {
03385             $bytes = intval($measurement);
03386         }
03387         return $bytes;
03388     }
03389 
03390     /**
03391      * Retrieves the maximum path length that is valid in the current environment.
03392      *
03393      * @return integer The maximum available path length
03394      * @author Ingo Renner <ingo@typo3.org>
03395      */
03396     public static function getMaximumPathLength() {
03397         $maximumPathLength = 0;
03398 
03399         if (version_compare(PHP_VERSION, '5.3.0', '<')) {
03400                 // rough assumptions
03401             if (TYPO3_OS == 'WIN') {
03402                     // WIN is usually 255, Vista 260, although NTFS can hold about 2k
03403                 $maximumPathLength = 255;
03404             } else {
03405                 $maximumPathLength = 2048;
03406             }
03407         } else {
03408                 // precise information is available since PHP 5.3
03409             $maximumPathLength = PHP_MAXPATHLEN;
03410         }
03411 
03412         return $maximumPathLength;
03413     }
03414 
03415 
03416     /**
03417      * Function for static version numbers on files, based on the filemtime
03418      *
03419      * This will make the filename automatically change when a file is
03420      * changed, and by that re-cached by the browser. If the file does not
03421      * exist physically the original file passed to the function is
03422      * returned without the timestamp.
03423      *
03424      * Behaviour is influenced by the setting
03425      * TYPO3_CONF_VARS[TYPO3_MODE][versionNumberInFilename]
03426      * = true (BE) / "embed" (FE) : modify filename
03427      * = false (BE) / "querystring" (FE) : add timestamp as parameter
03428      *
03429      * @param string $file Relative path to file including all potential query parameters (not htmlspecialchared yet)
03430      * @param boolean $forceQueryString If settings would suggest to embed in filename, this parameter allows us to force the versioning to occur in the query string. This is needed for scriptaculous.js which cannot have a different filename in order to load its modules (?load=...)
03431      * @return Relative path with version filename including the timestamp
03432      * @author Lars Houmark <lars@houmark.com>
03433      */
03434     public static function createVersionNumberedFilename($file, $forceQueryString = FALSE) {
03435         $lookupFile = explode('?', $file);
03436         $path = self::resolveBackPath(self::dirname(PATH_thisScript) .'/'. $lookupFile[0]);
03437 
03438         if (TYPO3_MODE == 'FE') {
03439             $mode = strtolower($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['versionNumberInFilename']);
03440             if ($mode === 'embed') {
03441                 $mode = TRUE;
03442             } else if ($mode === 'querystring') {
03443                 $mode = FALSE;
03444             } else {
03445                 $doNothing = TRUE;
03446             }
03447         } else {
03448             $mode = $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['versionNumberInFilename'];
03449         }
03450 
03451         if (! file_exists($path) || $doNothing) {
03452                 // File not found, return filename unaltered
03453             $fullName = $file;
03454 
03455         } else if (! $mode || $forceQueryString) {
03456                 // If use of .htaccess rule is not configured,
03457                 // we use the default query-string method
03458             if ($lookupFile[1]) {
03459                 $separator = '&';
03460             } else {
03461                 $separator = '?';
03462             }
03463             $fullName = $file . $separator . filemtime($path);
03464 
03465         } else {
03466                 // Change the filename
03467             $name = explode('.', $lookupFile[0]);
03468             $extension = array_pop($name);
03469 
03470             array_push($name, filemtime($path), $extension);
03471             $fullName = implode('.', $name);
03472                 // append potential query string
03473             $fullName .= $lookupFile[1] ? '?' . $lookupFile[1] : '';
03474         }
03475 
03476         return $fullName;
03477     }
03478 
03479 
03480 
03481 
03482 
03483 
03484 
03485 
03486 
03487     /*************************
03488      *
03489      * DEBUG helper FUNCTIONS
03490      *
03491      *************************/
03492 
03493     /**
03494      * Returns a string with a list of ascii-values for the first $characters characters in $string
03495      * Usage: 0
03496      *
03497      * @param   string      String to show ASCII value for
03498      * @param   integer     Number of characters to show
03499      * @return  string      The string with ASCII values in separated by a space char.
03500      */
03501     public static function debug_ordvalue($string,$characters=100)  {
03502         if(strlen($string) < $characters)   $characters = strlen($string);
03503         for ($i=0; $i<$characters; $i++)    {
03504             $valuestring.=' '.ord(substr($string,$i,1));
03505         }
03506         return trim($valuestring);
03507     }
03508 
03509     /**
03510      * Returns HTML-code, which is a visual representation of a multidimensional array
03511      * use t3lib_div::print_array() in order to print an array
03512      * Returns false if $array_in is not an array
03513      * Usage: 31
03514      *
03515      * @param   mixed       Array to view
03516      * @return  string      HTML output
03517      */
03518     public static function view_array($array_in)    {
03519         if (is_array($array_in))    {
03520             $result='
03521             <table border="1" cellpadding="1" cellspacing="0" bgcolor="white">';
03522             if (count($array_in) == 0)  {
03523                 $result.= '<tr><td><font face="Verdana,Arial" size="1"><strong>EMPTY!</strong></font></td></tr>';
03524             } else  {
03525                 foreach ($array_in as $key => $val) {
03526                     $result.= '<tr>
03527                         <td valign="top"><font face="Verdana,Arial" size="1">'.htmlspecialchars((string)$key).'</font></td>
03528                         <td>';
03529                     if (is_array($val)) {
03530                         $result.=self::view_array($val);
03531                     } elseif (is_object($val))  {
03532                         $string = get_class($val);
03533                         if (method_exists($val, '__toString'))  {
03534                             $string .= ': '.(string)$val;
03535                         }
03536                         $result .= '<font face="Verdana,Arial" size="1" color="red">'.nl2br(htmlspecialchars($string)).'<br /></font>';
03537                     } else  {
03538                         if (gettype($val) == 'object')  {
03539                             $string = 'Unknown object';
03540                         } else  {
03541                             $string = (string)$val;
03542                         }
03543                         $result.= '<font face="Verdana,Arial" size="1" color="red">'.nl2br(htmlspecialchars($string)).'<br /></font>';
03544                     }
03545                     $result.= '</td>
03546                     </tr>';
03547                 }
03548             }
03549             $result.= '</table>';
03550         } else {
03551             $result  = '<table border="1" cellpadding="1" cellspacing="0" bgcolor="white">
03552                 <tr>
03553                     <td><font face="Verdana,Arial" size="1" color="red">'.nl2br(htmlspecialchars((string)$array_in)).'<br /></font></td>
03554                 </tr>
03555             </table>';  // Output it as a string.
03556         }
03557         return $result;
03558     }
03559 
03560     /**
03561      * Prints an array
03562      * Usage: 6
03563      *
03564      * @param   mixed       Array to print visually (in a table).
03565      * @return  void
03566      * @see view_array()
03567      */
03568     public static function print_array($array_in)   {
03569         echo self::view_array($array_in);
03570     }
03571 
03572     /**
03573      * Makes debug output
03574      * Prints $var in bold between two vertical lines
03575      * If not $var the word 'debug' is printed
03576      * If $var is an array, the array is printed by t3lib_div::print_array()
03577      * Usage: 8
03578      *
03579      * @param   mixed       Variable to print
03580      * @param   string      The header.
03581      * @param   string      Group for the debug console
03582      * @return  void
03583      */
03584     public static function debug($var = '', $header = '', $group = 'Debug') {
03585             // buffer the output of debug if no buffering started before
03586         if (ob_get_level()==0) {
03587             ob_start();
03588         }
03589         $debug = '';
03590 
03591         if ($header) {
03592             $debug .= '
03593             <table class="typo3-debug" border="0" cellpadding="0" cellspacing="0" bgcolor="white" style="border:0px; margin-top:3px; margin-bottom:3px;">
03594                 <tr>
03595                     <td style="background-color:#bbbbbb; font-family: verdana,arial; font-weight: bold; font-size: 10px;">' .
03596                         htmlspecialchars((string) $header) .
03597                     '</td>
03598                 </tr>
03599                 <tr>
03600                     <td>';
03601         }
03602 
03603         if (is_array($var)) {
03604             $debug .= self::view_array($var);
03605         } elseif (is_object($var)) {
03606             $debug .=  '<strong>|Object:<pre>';
03607             $debug .= print_r($var, TRUE);
03608             $debug .=  '</pre>|</strong>';
03609         } elseif ((string) $var !== '') {
03610             $debug .= '<strong>|' . htmlspecialchars((string)$var) . '|</strong>';
03611         } else {
03612             $debug .= '<strong>| debug |</strong>';
03613         }
03614 
03615         if ($header) {
03616             $debug .=  '
03617                     </td>
03618                 </tr>
03619             </table>';
03620         }
03621 
03622         if (TYPO3_MODE === 'BE') {
03623             $group = htmlspecialchars($group);
03624 
03625             if ($header !== '') {
03626                 $tabHeader = htmlspecialchars($header);
03627             } else {
03628                 $tabHeader = 'Debug';
03629             }
03630 
03631             if (is_object($var)) {
03632                 $debug = str_replace(
03633                     array('"', '/', '<', "\n", "\r"),
03634                     array('\"', '\/', '<', '<br />', ''),
03635                     $debug
03636                 );
03637             } else {
03638                 $debug = str_replace(
03639                     array('"', '/', '<', "\n", "\r"),
03640                     array('\"', '\/', '<', '', ''),
03641                     $debug
03642                 );
03643             }
03644 
03645             $script = '
03646                 (function debug() {
03647                     var debugMessage = "' . $debug . '";
03648                     var header = "' . $tabHeader . '";
03649                     var group = "' . $group . '";
03650 
03651                     if (typeof Ext !== "object" && (top && typeof top.Ext !== "object")) {
03652                         document.write(debugMessage);
03653                         return;
03654                     }
03655 
03656                     if (top && typeof Ext !== "object") {
03657                         Ext = top.Ext;
03658                     }
03659 
03660                     Ext.onReady(function() {
03661                         var TYPO3ViewportInstance = null;
03662 
03663                         if (top && top.TYPO3 && typeof top.TYPO3.Backend === "object") {
03664                             TYPO3ViewportInstance = top.TYPO3.Backend;
03665                         } else if (typeof TYPO3 === "object" && typeof TYPO3.Backend === "object") {
03666                             TYPO3ViewportInstance = TYPO3.Backend;
03667                         }
03668 
03669                         if (TYPO3ViewportInstance !== null) {
03670                             TYPO3ViewportInstance.DebugConsole.addTab(debugMessage, header, group);
03671                         } else {
03672                             document.write(debugMessage);
03673                         }
03674                     });
03675                 })();
03676             ';
03677             echo self::wrapJS($script);
03678         } else {
03679             echo $debug;
03680         }
03681     }
03682 
03683     /**
03684      * Displays the "path" of the function call stack in a string, using debug_backtrace
03685      *
03686      * @return  string
03687      */
03688     public static function debug_trail()    {
03689         $trail = debug_backtrace();
03690         $trail = array_reverse($trail);
03691         array_pop($trail);
03692 
03693         $path = array();
03694         foreach($trail as $dat) {
03695             $path[] = $dat['class'].$dat['type'].$dat['function'].'#'.$dat['line'];
03696         }
03697 
03698         return implode(' // ',$path);
03699     }
03700 
03701     /**
03702      * Displays an array as rows in a table. Useful to debug output like an array of database records.
03703      *
03704      * @param   mixed       Array of arrays with similar keys
03705      * @param   string      Table header
03706      * @param   boolean     If TRUE, will return content instead of echo'ing out.
03707      * @return  void        Outputs to browser.
03708      */
03709     public static function debugRows($rows,$header='',$returnHTML=FALSE)    {
03710         if (is_array($rows))    {
03711             reset($rows);
03712             $firstEl = current($rows);
03713             if (is_array($firstEl)) {
03714                 $headerColumns = array_keys($firstEl);
03715                 $tRows = array();
03716 
03717                     // Header:
03718                 $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>';
03719                 $tCells = array();
03720                 foreach($headerColumns as $key) {
03721                     $tCells[] = '
03722                             <td><font face="Verdana,Arial" size="1"><strong>'.htmlspecialchars($key).'</strong></font></td>';
03723                 }
03724                 $tRows[] = '
03725                         <tr>'.implode('',$tCells).'
03726                         </tr>';
03727 
03728                     // Rows:
03729                 foreach($rows as $singleRow)    {
03730                     $tCells = array();
03731                     foreach($headerColumns as $key) {
03732                         $tCells[] = '
03733                             <td><font face="Verdana,Arial" size="1">'.(is_array($singleRow[$key]) ? self::debugRows($singleRow[$key],'',TRUE) : htmlspecialchars($singleRow[$key])).'</font></td>';
03734                     }
03735                     $tRows[] = '
03736                         <tr>'.implode('',$tCells).'
03737                         </tr>';
03738                 }
03739 
03740                 $table = '
03741                     <table border="1" cellpadding="1" cellspacing="0" bgcolor="white">'.implode('',$tRows).'
03742                     </table>';
03743                 if ($returnHTML)    return $table; else echo $table;
03744             } else debug('Empty array of rows',$header);
03745         } else {
03746             debug('No array of rows',$header);
03747         }
03748     }
03749 
03750 
03751 
03752 
03753 
03754 
03755 
03756 
03757 
03758 
03759 
03760 
03761 
03762 
03763 
03764 
03765 
03766 
03767 
03768 
03769 
03770 
03771 
03772 
03773 
03774 
03775 
03776 
03777     /*************************
03778      *
03779      * SYSTEM INFORMATION
03780      *
03781      *************************/
03782 
03783     /**
03784      * Returns the HOST+DIR-PATH of the current script (The URL, but without 'http://' and without script-filename)
03785      * Usage: 1
03786      *
03787      * @return  string
03788      */
03789     public static function getThisUrl() {
03790         $p=parse_url(self::getIndpEnv('TYPO3_REQUEST_SCRIPT'));     // Url of this script
03791         $dir=self::dirname($p['path']).'/'; // Strip file
03792         $url = str_replace('//','/',$p['host'].($p['port']?':'.$p['port']:'').$dir);
03793         return $url;
03794     }
03795 
03796     /**
03797      * Returns the link-url to the current script.
03798      * 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.
03799      * REMEMBER to always use htmlspecialchars() for content in href-properties to get ampersands converted to entities (XHTML requirement and XSS precaution)
03800      * Usage: 52
03801      *
03802      * @param   array       Array of GET parameters to include
03803      * @return  string
03804      */
03805     public static function linkThisScript(array $getParams = array()) {
03806         $parts = self::getIndpEnv('SCRIPT_NAME');
03807         $params = self::_GET();
03808 
03809         foreach ($getParams as $key => $value) {
03810             if ($value !== '') {
03811                 $params[$key] = $value;
03812             } else {
03813                 unset($params[$key]);
03814             }
03815         }
03816 
03817         $pString = self::implodeArrayForUrl('', $params);
03818 
03819         return $pString ? $parts . '?' . preg_replace('/^&/', '', $pString) : $parts;
03820     }
03821 
03822     /**
03823      * 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.
03824      * So basically it adds the parameters in $getParams to an existing URL, $url
03825      * Usage: 2
03826      *
03827      * @param   string      URL string
03828      * @param   array       Array of key/value pairs for get parameters to add/overrule with. Can be multidimensional.
03829      * @return  string      Output URL with added getParams.
03830      */
03831     public static function linkThisUrl($url,array $getParams=array())   {
03832         $parts = parse_url($url);
03833         $getP = array();
03834         if ($parts['query'])    {
03835             parse_str($parts['query'],$getP);
03836         }
03837         $getP = self::array_merge_recursive_overrule($getP,$getParams);
03838         $uP = explode('?',$url);
03839 
03840         $params = self::implodeArrayForUrl('',$getP);
03841         $outurl = $uP[0].($params ? '?'.substr($params, 1) : '');
03842 
03843         return $outurl;
03844     }
03845 
03846     /**
03847      * Abstraction method which returns System Environment Variables regardless of server OS, CGI/MODULE version etc. Basically this is SERVER variables for most of them.
03848      * This should be used instead of getEnv() and $_SERVER/ENV_VARS to get reliable values for all situations.
03849      * Usage: 221
03850      *
03851      * @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
03852      * @return  string      Value based on the input key, independent of server/os environment.
03853      */
03854     public static function getIndpEnv($getEnvName)  {
03855         /*
03856             Conventions:
03857             output from parse_url():
03858             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
03859                 [scheme] => 'http'
03860                 [user] => 'username'
03861                 [pass] => 'password'
03862                 [host] => '192.168.1.4'
03863                 [port] => '8080'
03864                 [path] => '/typo3/32/temp/phpcheck/index.php/arg1/arg2/arg3/'
03865                 [query] => 'arg1,arg2,arg3&p1=parameter1&p2[key]=value'
03866                 [fragment] => 'link1'
03867 
03868                 Further definition: [path_script] = '/typo3/32/temp/phpcheck/index.php'
03869                                     [path_dir] = '/typo3/32/temp/phpcheck/'
03870                                     [path_info] = '/arg1/arg2/arg3/'
03871                                     [path] = [path_script/path_dir][path_info]
03872 
03873 
03874             Keys supported:
03875 
03876             URI______:
03877                 REQUEST_URI     =   [path]?[query]      = /typo3/32/temp/phpcheck/index.php/arg1/arg2/arg3/?arg1,arg2,arg3&p1=parameter1&p2[key]=value
03878                 HTTP_HOST       =   [host][:[port]]     = 192.168.1.4:8080
03879                 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')!
03880                 PATH_INFO       =   [path_info]         = /arg1/arg2/arg3/
03881                 QUERY_STRING    =   [query]             = arg1,arg2,arg3&p1=parameter1&p2[key]=value
03882                 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
03883                                         (Notice: NO username/password + NO fragment)
03884 
03885             CLIENT____:
03886                 REMOTE_ADDR     =   (client IP)
03887                 REMOTE_HOST     =   (client host)
03888                 HTTP_USER_AGENT =   (client user agent)
03889                 HTTP_ACCEPT_LANGUAGE    = (client accept language)
03890 
03891             SERVER____:
03892                 SCRIPT_FILENAME =   Absolute filename of script     (Differs between windows/unix). On windows 'C:\\blabla\\blabl\\' will be converted to 'C:/blabla/blabl/'
03893 
03894             Special extras:
03895                 TYPO3_HOST_ONLY =       [host] = 192.168.1.4
03896                 TYPO3_PORT =            [port] = 8080 (blank if 80, taken from host value)
03897                 TYPO3_REQUEST_HOST =        [scheme]://[host][:[port]]
03898                 TYPO3_REQUEST_URL =     [scheme]://[host][:[port]][path]?[query] (scheme will by default be "http" until we can detect something different)
03899                 TYPO3_REQUEST_SCRIPT =      [scheme]://[host][:[port]][path_script]
03900                 TYPO3_REQUEST_DIR =     [scheme]://[host][:[port]][path_dir]
03901                 TYPO3_SITE_URL =        [scheme]://[host][:[port]][path_dir] of the TYPO3 website frontend
03902                 TYPO3_SITE_PATH =       [path_dir] of the TYPO3 website frontend
03903                 TYPO3_SITE_SCRIPT =         [script / Speaking URL] of the TYPO3 website
03904                 TYPO3_DOCUMENT_ROOT =       Absolute path of root of documents: TYPO3_DOCUMENT_ROOT.SCRIPT_NAME = SCRIPT_FILENAME (typically)
03905                 TYPO3_SSL =             Returns TRUE if this session uses SSL/TLS (https)
03906                 TYPO3_PROXY =           Returns TRUE if this session runs over a well known proxy
03907 
03908             Notice: [fragment] is apparently NEVER available to the script!
03909 
03910 
03911             Testing suggestions:
03912             - Output all the values.
03913             - 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
03914             - ALSO TRY the script from the ROOT of a site (like 'http://www.mytest.com/' and not 'http://www.mytest.com/test/' !!)
03915 
03916         */
03917 
03918 #       if ($getEnvName=='HTTP_REFERER')    return '';
03919 
03920         $retVal = '';
03921 
03922         switch ((string)$getEnvName)    {
03923             case 'SCRIPT_NAME':
03924                 $retVal = (PHP_SAPI=='cgi'||PHP_SAPI=='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']);
03925                     // add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix
03926                 if (self::cmpIP($_SERVER['REMOTE_ADDR'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'])) {
03927                     if (self::getIndpEnv('TYPO3_SSL') && $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefixSSL']) {
03928                         $retVal = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefixSSL'].$retVal;
03929                     } elseif ($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefix']) {
03930                         $retVal = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefix'].$retVal;
03931                     }
03932                 }
03933             break;
03934             case 'SCRIPT_FILENAME':
03935                 $retVal = str_replace('//','/', str_replace('\\','/', (PHP_SAPI=='cgi'||PHP_SAPI=='isapi' ||PHP_SAPI=='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'])));
03936             break;
03937             case 'REQUEST_URI':
03938                     // Typical application of REQUEST_URI is return urls, forms submitting to itself etc. Example: returnUrl='.rawurlencode(t3lib_div::getIndpEnv('REQUEST_URI'))
03939                 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)
03940                     list($v,$n) = explode('|',$GLOBALS['TYPO3_CONF_VARS']['SYS']['requestURIvar']);
03941                     $retVal = $GLOBALS[$v][$n];
03942                 } elseif (!$_SERVER['REQUEST_URI']) {   // This is for ISS/CGI which does not have the REQUEST_URI available.
03943                     $retVal = '/'.ltrim(self::getIndpEnv('SCRIPT_NAME'), '/').
03944                         ($_SERVER['QUERY_STRING']?'?'.$_SERVER['QUERY_STRING']:'');
03945                 } else {
03946                     $retVal = $_SERVER['REQUEST_URI'];
03947                 }
03948                     // add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix
03949                 if (self::cmpIP($_SERVER['REMOTE_ADDR'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'])) {
03950                     if (self::getIndpEnv('TYPO3_SSL') && $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefixSSL']) {
03951                         $retVal = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefixSSL'].$retVal;
03952                     } elseif ($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefix']) {
03953                         $retVal = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefix'].$retVal;
03954                     }
03955                 }
03956             break;
03957             case 'PATH_INFO':
03958                     // $_SERVER['PATH_INFO']!=$_SERVER['SCRIPT_NAME'] is necessary because some servers (Windows/CGI) are seen to set PATH_INFO equal to script_name
03959                     // Further, there must be at least one '/' in the path - else the PATH_INFO value does not make sense.
03960                     // IF 'PATH_INFO' never works for our purpose in TYPO3 with CGI-servers, then 'PHP_SAPI=='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=='cgi' (see above)
03961 //              if (strcmp($_SERVER['PATH_INFO'],self::getIndpEnv('SCRIPT_NAME')) && count(explode('/',$_SERVER['PATH_INFO']))>1)   {
03962                 if (PHP_SAPI!='cgi' && PHP_SAPI!='cgi-fcgi')    {
03963                     $retVal = $_SERVER['PATH_INFO'];
03964                 }
03965             break;
03966             case 'TYPO3_REV_PROXY':
03967                 $retVal = self::cmpIP($_SERVER['REMOTE_ADDR'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP']);
03968             break;
03969             case 'REMOTE_ADDR':
03970                 $retVal = $_SERVER['REMOTE_ADDR'];
03971                 if (self::cmpIP($_SERVER['REMOTE_ADDR'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'])) {
03972                     $ip = self::trimExplode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
03973                         // choose which IP in list to use
03974                     if (count($ip)) {
03975                         switch ($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyHeaderMultiValue']) {
03976                             case 'last':
03977                                 $ip = array_pop($ip);
03978                             break;
03979                             case 'first':
03980                                 $ip = array_shift($ip);
03981                             break;
03982                             case 'none':
03983                             default:
03984                                 $ip = '';
03985                             break;
03986                         }
03987                     }
03988                     if (self::validIP($ip)) {
03989                         $retVal = $ip;
03990                     }
03991                 }
03992             break;
03993             case 'HTTP_HOST':
03994                 $retVal = $_SERVER['HTTP_HOST'];
03995                 if (self::cmpIP($_SERVER['REMOTE_ADDR'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'])) {
03996                     $host = self::trimExplode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
03997                         // choose which host in list to use
03998                     if (count($host)) {
03999                         switch ($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyHeaderMultiValue']) {
04000                             case 'last':
04001                                 $host = array_pop($host);
04002                             break;
04003                             case 'first':
04004                                 $host = array_shift($host);
04005                             break;
04006                             case 'none':
04007                             default:
04008                                 $host = '';
04009                             break;
04010                         }
04011                     }
04012                     if ($host)  {
04013                         $retVal = $host;
04014                     }
04015                 }
04016             break;
04017                 // These are let through without modification
04018             case 'HTTP_REFERER':
04019             case 'HTTP_USER_AGENT':
04020             case 'HTTP_ACCEPT_ENCODING':
04021             case 'HTTP_ACCEPT_LANGUAGE':
04022             case 'REMOTE_HOST':
04023             case 'QUERY_STRING':
04024                 $retVal = $_SERVER[$getEnvName];
04025             break;
04026             case 'TYPO3_DOCUMENT_ROOT':
04027                 // 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.
04028                 // Therefore the DOCUMENT_ROOT is now always calculated as the SCRIPT_FILENAME minus the end part shared with SCRIPT_NAME.
04029                 $SFN = self::getIndpEnv('SCRIPT_FILENAME');
04030                 $SN_A = explode('/',strrev(self::getIndpEnv('SCRIPT_NAME')));
04031                 $SFN_A = explode('/',strrev($SFN));
04032                 $acc = array();
04033                 foreach ($SN_A as $kk => $vv) {
04034                     if (!strcmp($SFN_A[$kk],$vv))   {
04035                         $acc[] = $vv;
04036                     } else break;
04037                 }
04038                 $commonEnd=strrev(implode('/',$acc));
04039                 if (strcmp($commonEnd,''))  { $DR = substr($SFN,0,-(strlen($commonEnd)+1)); }
04040                 $retVal = $DR;
04041             break;
04042             case 'TYPO3_HOST_ONLY':
04043                 $p = explode(':',self::getIndpEnv('HTTP_HOST'));
04044                 $retVal = $p[0];
04045             break;
04046             case 'TYPO3_PORT':
04047                 $p = explode(':',self::getIndpEnv('HTTP_HOST'));
04048                 $retVal = $p[1];
04049             break;
04050             case 'TYPO3_REQUEST_HOST':
04051                 $retVal = (self::getIndpEnv('TYPO3_SSL') ? 'https://' : 'http://').
04052                     self::getIndpEnv('HTTP_HOST');
04053             break;
04054             case 'TYPO3_REQUEST_URL':
04055                 $retVal = self::getIndpEnv('TYPO3_REQUEST_HOST').self::getIndpEnv('REQUEST_URI');
04056             break;
04057             case 'TYPO3_REQUEST_SCRIPT':
04058                 $retVal = self::getIndpEnv('TYPO3_REQUEST_HOST').self::getIndpEnv('SCRIPT_NAME');
04059             break;
04060             case 'TYPO3_REQUEST_DIR':
04061                 $retVal = self::getIndpEnv('TYPO3_REQUEST_HOST').self::dirname(self::getIndpEnv('SCRIPT_NAME')).'/';
04062             break;
04063             case 'TYPO3_SITE_URL':
04064                 if (defined('PATH_thisScript') && defined('PATH_site')) {
04065                     $lPath = substr(dirname(PATH_thisScript),strlen(PATH_site)).'/';
04066                     $url = self::getIndpEnv('TYPO3_REQUEST_DIR');
04067                     $siteUrl = substr($url,0,-strlen($lPath));
04068                     if (substr($siteUrl,-1)!='/')   $siteUrl.='/';
04069                     $retVal = $siteUrl;
04070                 }
04071             break;
04072             case 'TYPO3_SITE_PATH':
04073                 $retVal = substr(self::getIndpEnv('TYPO3_SITE_URL'), strlen(self::getIndpEnv('TYPO3_REQUEST_HOST')));
04074             break;
04075             case 'TYPO3_SITE_SCRIPT':
04076                 $retVal = substr(self::getIndpEnv('TYPO3_REQUEST_URL'),strlen(self::getIndpEnv('TYPO3_SITE_URL')));
04077             break;
04078             case 'TYPO3_SSL':
04079                 $proxySSL = trim($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxySSL']);
04080                 if ($proxySSL == '*') {
04081                     $proxySSL = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'];
04082                 }
04083                 if (self::cmpIP($_SERVER['REMOTE_ADDR'], $proxySSL))    {
04084                     $retVal = true;
04085                 } else {
04086                     $retVal = $_SERVER['SSL_SESSION_ID'] || !strcasecmp($_SERVER['HTTPS'], 'on') || !strcmp($_SERVER['HTTPS'], '1') ? true : false; // see http://bugs.typo3.org/view.php?id=3909
04087                 }
04088             break;
04089             case '_ARRAY':
04090                 $out = array();
04091                     // Here, list ALL possible keys to this function for debug display.
04092                 $envTestVars = self::trimExplode(',','
04093                     HTTP_HOST,
04094                     TYPO3_HOST_ONLY,
04095                     TYPO3_PORT,
04096                     PATH_INFO,
04097                     QUERY_STRING,
04098                     REQUEST_URI,
04099                     HTTP_REFERER,
04100                     TYPO3_REQUEST_HOST,
04101                     TYPO3_REQUEST_URL,
04102                     TYPO3_REQUEST_SCRIPT,
04103                     TYPO3_REQUEST_DIR,
04104                     TYPO3_SITE_URL,
04105                     TYPO3_SITE_SCRIPT,
04106                     TYPO3_SSL,
04107                     TYPO3_REV_PROXY,
04108                     SCRIPT_NAME,
04109                     TYPO3_DOCUMENT_ROOT,
04110                     SCRIPT_FILENAME,
04111                     REMOTE_ADDR,
04112                     REMOTE_HOST,
04113                     HTTP_USER_AGENT,
04114                     HTTP_ACCEPT_LANGUAGE',1);
04115                 foreach ($envTestVars as $v) {
04116                     $out[$v]=self::getIndpEnv($v);
04117                 }
04118                 reset($out);
04119                 $retVal = $out;
04120             break;
04121         }
04122         return $retVal;
04123     }
04124 
04125     /**
04126      * Gets the unixtime as milliseconds.
04127      *
04128      * @return  integer     The unixtime as milliseconds
04129      */
04130     public static function milliseconds() {
04131         return round(microtime(true) * 1000);
04132     }
04133 
04134     /**
04135      * Client Browser Information
04136      * Usage: 4
04137      *
04138      * @param   string      Alternative User Agent string (if empty, t3lib_div::getIndpEnv('HTTP_USER_AGENT') is used)
04139      * @return  array       Parsed information about the HTTP_USER_AGENT in categories BROWSER, VERSION, SYSTEM and FORMSTYLE
04140      */
04141     public static function clientInfo($useragent='')    {
04142         if (!$useragent) $useragent=self::getIndpEnv('HTTP_USER_AGENT');
04143 
04144         $bInfo=array();
04145             // Which browser?
04146         if (strpos($useragent,'Konqueror') !== false)   {
04147             $bInfo['BROWSER']= 'konqu';
04148         } elseif (strpos($useragent,'Opera') !== false) {
04149             $bInfo['BROWSER']= 'opera';
04150         } elseif (strpos($useragent, 'MSIE') !== false) {
04151             $bInfo['BROWSER']= 'msie';
04152         } elseif (strpos($useragent, 'Mozilla') !== false) {
04153             $bInfo['BROWSER']='net';
04154         } elseif (strpos($useragent, 'Flash') !== false) {
04155             $bInfo['BROWSER'] = 'flash';
04156         }
04157         if ($bInfo['BROWSER'])  {
04158                 // Browser version
04159             switch($bInfo['BROWSER'])   {
04160                 case 'net':
04161                     $bInfo['VERSION']= doubleval(substr($useragent,8));
04162                     if (strpos($useragent,'Netscape6/') !== false) { $bInfo['VERSION'] = doubleval(substr(strstr($useragent,'Netscape6/'),10)); }   // Will we ever know if this was a typo or intention...?! :-(
04163                     if (strpos($useragent,'Netscape/6') !== false) { $bInfo['VERSION'] = doubleval(substr(strstr($useragent,'Netscape/6'),10)); }
04164                     if (strpos($useragent,'Netscape/7') !== false) { $bInfo['VERSION'] = doubleval(substr(strstr($useragent,'Netscape/7'),9)); }
04165                 break;
04166                 case 'msie':
04167                     $tmp = strstr($useragent,'MSIE');
04168                     $bInfo['VERSION'] = doubleval(preg_replace('/^[^0-9]*/','',substr($tmp,4)));
04169                 break;
04170                 case 'opera':
04171                     $tmp = strstr($useragent,'Opera');
04172                     $bInfo['VERSION'] = doubleval(preg_replace('/^[^0-9]*/','',substr($tmp,5)));
04173                 break;
04174                 case 'konqu':
04175                     $tmp = strstr($useragent,'Konqueror/');
04176                     $bInfo['VERSION'] = doubleval(substr($tmp,10));
04177                 break;
04178             }
04179                 // Client system
04180             if (strpos($useragent,'Win') !== false) {
04181                 $bInfo['SYSTEM'] = 'win';
04182             } elseif (strpos($useragent,'Mac') !== false)   {
04183                 $bInfo['SYSTEM'] = 'mac';
04184             } elseif (strpos($useragent,'Linux') !== false || strpos($useragent,'X11') !== false || strpos($useragent,'SGI') !== false || strpos($useragent,' SunOS ') !== false || strpos($useragent,' HP-UX ') !== false) {
04185                 $bInfo['SYSTEM'] = 'unix';
04186             }
04187         }
04188             // Is true if the browser supports css to format forms, especially the width
04189         $bInfo['FORMSTYLE']=($bInfo['BROWSER']=='msie' || ($bInfo['BROWSER']=='net' && $bInfo['VERSION']>=5) || $bInfo['BROWSER']=='opera' || $bInfo['BROWSER']=='konqu');
04190 
04191         return $bInfo;
04192     }
04193 
04194     /**
04195      * Get the fully-qualified domain name of the host.
04196      * Usage: 2
04197      *
04198      * @param   boolean     Use request host (when not in CLI mode).
04199      * @return  string      The fully-qualified host name.
04200      */
04201     public static function getHostname($requestHost=TRUE)   {
04202         $host = '';
04203             // If not called from the command-line, resolve on getIndpEnv()
04204             // Note that TYPO3_REQUESTTYPE is not used here as it may not yet be defined
04205         if ($requestHost && (!defined('TYPO3_cliMode') || !TYPO3_cliMode))  {
04206             $host = self::getIndpEnv('HTTP_HOST');
04207         }
04208         if (!$host) {
04209                 // will fail for PHP 4.1 and 4.2
04210             $host = @php_uname('n');
04211                 // 'n' is ignored in broken installations
04212             if (strpos($host, ' ')) $host = '';
04213         }
04214             // we have not found a FQDN yet
04215         if ($host && strpos($host, '.') === false) {
04216             $ip = gethostbyname($host);
04217                 // we got an IP address
04218             if ($ip != $host)   {
04219                 $fqdn = gethostbyaddr($ip);
04220                 if ($ip != $fqdn)   $host = $fqdn;
04221             }
04222         }
04223         if (!$host) $host = 'localhost.localdomain';
04224 
04225         return $host;
04226     }
04227 
04228 
04229 
04230 
04231 
04232 
04233 
04234 
04235 
04236 
04237 
04238 
04239 
04240 
04241 
04242 
04243 
04244 
04245 
04246 
04247 
04248 
04249     /*************************
04250      *
04251      * TYPO3 SPECIFIC FUNCTIONS
04252      *
04253      *************************/
04254 
04255     /**
04256      * 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.
04257      * Usage: 24
04258      *
04259      * @param   string      The input filename/filepath to evaluate
04260      * @param   boolean     If $onlyRelative is set (which it is by default), then only return values relative to the current PATH_site is accepted.
04261      * @param   boolean     If $relToTYPO3_mainDir is set, then relative paths are relative to PATH_typo3 constant - otherwise (default) they are relative to PATH_site
04262      * @return  string      Returns the absolute filename of $filename IF valid, otherwise blank string.
04263      */
04264     public static function getFileAbsFileName($filename,$onlyRelative=TRUE,$relToTYPO3_mainDir=FALSE)   {
04265         if (!strcmp($filename,''))      return '';
04266 
04267         if ($relToTYPO3_mainDir)    {
04268             if (!defined('PATH_typo3')) return '';
04269             $relPathPrefix = PATH_typo3;
04270         } else {
04271             $relPathPrefix = PATH_site;
04272         }
04273         if (substr($filename,0,4)=='EXT:')  {   // extension
04274             list($extKey,$local) = explode('/',substr($filename,4),2);
04275             $filename='';
04276             if (strcmp($extKey,'') && t3lib_extMgm::isLoaded($extKey) && strcmp($local,'')) {
04277                 $filename = t3lib_extMgm::extPath($extKey).$local;
04278             }
04279         } elseif (!self::isAbsPath($filename))  {   // relative. Prepended with $relPathPrefix
04280             $filename=$relPathPrefix.$filename;
04281         } elseif ($onlyRelative && !self::isFirstPartOfStr($filename,$relPathPrefix)) { // absolute, but set to blank if not allowed
04282             $filename='';
04283         }
04284         if (strcmp($filename,'') && self::validPathStr($filename))  {   // checks backpath.
04285             return $filename;
04286         }
04287     }
04288 
04289     /**
04290      * Checks for malicious file paths.
04291      * Returns true if no '//', '..' or '\' is in the $theFile
04292      * This should make sure that the path is not pointing 'backwards' and further doesn't contain double/back slashes.
04293      * So it's compatible with the UNIX style path strings valid for TYPO3 internally.
04294      * Usage: 14
04295      *
04296      * @param   string      Filepath to evaluate
04297      * @return  boolean     True, if no '//', '\', '/../' is in the $theFile and $theFile doesn't begin with '../'
04298      * @todo    Possible improvement: Should it rawurldecode the string first to check if any of these characters is encoded ?
04299      */
04300     public static function validPathStr($theFile)   {
04301         if (strpos($theFile, '//')===false && strpos($theFile, '\\')===false && !preg_match('#(?:^\.\.|/\.\./)#', $theFile)) {
04302             return true;
04303         }
04304     }
04305 
04306     /**
04307      * Checks if the $path is absolute or relative (detecting either '/' or 'x:/' as first part of string) and returns true if so.
04308      * Usage: 8
04309      *
04310      * @param   string      Filepath to evaluate
04311      * @return  boolean
04312      */
04313     public static function isAbsPath($path) {
04314         return TYPO3_OS=='WIN' ? substr($path,1,2)==':/' :  substr($path,0,1)=='/';
04315     }
04316 
04317     /**
04318      * Returns true if the path is absolute, without backpath '..' and within the PATH_site OR within the lockRootPath
04319      * Usage: 5
04320      *
04321      * @param   string      Filepath to evaluate
04322      * @return  boolean
04323      */
04324     public static function isAllowedAbsPath($path)  {
04325         if (self::isAbsPath($path) &&
04326             self::validPathStr($path) &&
04327                 (   self::isFirstPartOfStr($path,PATH_site)
04328                     ||
04329                     ($GLOBALS['TYPO3_CONF_VARS']['BE']['lockRootPath'] && self::isFirstPartOfStr($path,$GLOBALS['TYPO3_CONF_VARS']['BE']['lockRootPath']))
04330                 )
04331             )   return true;
04332     }
04333 
04334     /**
04335      * Verifies the input filename againts the 'fileDenyPattern'. Returns true if OK.
04336      * Usage: 2
04337      *
04338      * @param   string      Filepath to evaluate
04339      * @return  boolean
04340      */
04341     public static function verifyFilenameAgainstDenyPattern($filename)  {
04342         if (strcmp($filename,'') && strcmp($GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'],''))    {
04343             $result = preg_match('/'.$GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'].'/i',$filename);
04344             if ($result)    return false;   // so if a matching filename is found, return false;
04345         }
04346         return true;
04347     }
04348 
04349     /**
04350      * Checks if a given string is a valid frame URL to be loaded in the
04351      * backend.
04352      *
04353      * @param string $url potential URL to check
04354      *
04355      * @return string either $url if $url is considered to be harmless, or an
04356      *                empty string otherwise
04357      */
04358     public static function sanitizeLocalUrl($url = '') {
04359         $sanitizedUrl = '';
04360         $decodedUrl = rawurldecode($url);
04361 
04362         if (!empty($url) && self::removeXSS($decodedUrl) === $decodedUrl) {
04363             $testAbsoluteUrl = self::resolveBackPath($decodedUrl);
04364             $testRelativeUrl = self::resolveBackPath(
04365                 self::dirname(self::getIndpEnv('SCRIPT_NAME')) . '/' . $decodedUrl
04366             );
04367 
04368                 // Pass if URL is on the current host:
04369             if (self::isValidUrl($decodedUrl)) {
04370                 if (self::isOnCurrentHost($decodedUrl) && strpos($decodedUrl, self::getIndpEnv('TYPO3_SITE_URL')) === 0) {
04371                     $sanitizedUrl = $url;
04372                 }
04373                 // Pass if URL is an absolute file path:
04374             } elseif (self::isAbsPath($decodedUrl) && self::isAllowedAbsPath($decodedUrl)) {
04375                 $sanitizedUrl = $url;
04376                 // Pass if URL is absolute and below TYPO3 base directory:
04377             } elseif (strpos($testAbsoluteUrl, self::getIndpEnv('TYPO3_SITE_PATH')) === 0 && substr($decodedUrl, 0, 1) === '/') {
04378                 $sanitizedUrl = $url;
04379                 // Pass if URL is relative and below TYPO3 base directory:
04380             } elseif (strpos($testRelativeUrl, self::getIndpEnv('TYPO3_SITE_PATH')) === 0 && substr($decodedUrl, 0, 1) !== '/') {
04381                 $sanitizedUrl = $url;
04382             }
04383         }
04384 
04385         if (!empty($url) && empty($sanitizedUrl)) {
04386             self::sysLog('The URL "' . $url . '" is not considered to be local and was denied.', 'Core', self::SYSLOG_SEVERITY_NOTICE);
04387         }
04388 
04389         return $sanitizedUrl;
04390     }
04391 
04392     /**
04393      * Moves $source file to $destination if uploaded, otherwise try to make a copy
04394      * Usage: 4
04395      *
04396      * @param   string      Source file, absolute path
04397      * @param   string      Destination file, absolute path
04398      * @return  boolean     Returns true if the file was moved.
04399      * @coauthor    Dennis Petersen <fessor@software.dk>
04400      * @see upload_to_tempfile()
04401      */
04402     public static function upload_copy_move($source,$destination)   {
04403         if (is_uploaded_file($source))  {
04404             $uploaded = TRUE;
04405             // 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:
04406             $uploadedResult = move_uploaded_file($source, $destination);
04407         } else {
04408             $uploaded = FALSE;
04409             @copy($source,$destination);
04410         }
04411 
04412         self::fixPermissions($destination); // Change the permissions of the file
04413 
04414             // 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
04415         return $uploaded ? $uploadedResult : FALSE;
04416     }
04417 
04418     /**
04419      * 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.
04420      * Use this function to move uploaded files to where you can work on them.
04421      * REMEMBER to use t3lib_div::unlink_tempfile() afterwards - otherwise temp-files will build up! They are NOT automatically deleted in PATH_site."typo3temp/"!
04422      * Usage: 6
04423      *
04424      * @param   string      The temporary uploaded filename, eg. $_FILES['[upload field name here]']['tmp_name']
04425      * @return  string      If a new file was successfully created, return its filename, otherwise blank string.
04426      * @see unlink_tempfile(), upload_copy_move()
04427      */
04428     public static function upload_to_tempfile($uploadedFileName)    {
04429         if (is_uploaded_file($uploadedFileName))    {
04430             $tempFile = self::tempnam('upload_temp_');
04431             move_uploaded_file($uploadedFileName, $tempFile);
04432             return @is_file($tempFile) ? $tempFile : '';
04433         }
04434     }
04435 
04436     /**
04437      * Deletes (unlink) a temporary filename in 'PATH_site."typo3temp/"' given as input.
04438      * 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.
04439      * Use this after upload_to_tempfile() or tempnam() from this class!
04440      * Usage: 9
04441      *
04442      * @param   string      Filepath for a file in PATH_site."typo3temp/". Must be absolute.
04443      * @return  boolean     Returns true if the file was unlink()'ed
04444      * @see upload_to_tempfile(), tempnam()
04445      */
04446     public static function unlink_tempfile($uploadedTempFileName)   {
04447         if ($uploadedTempFileName && self::validPathStr($uploadedTempFileName) && self::isFirstPartOfStr($uploadedTempFileName,PATH_site.'typo3temp/') && @is_file($uploadedTempFileName))  {
04448             if (unlink($uploadedTempFileName))  return TRUE;
04449         }
04450     }
04451 
04452     /**
04453      * Create temporary filename (Create file with unique file name)
04454      * This function should be used for getting temporary filenames - will make your applications safe for open_basedir = on
04455      * REMEMBER to delete the temporary files after use! This is done by t3lib_div::unlink_tempfile()
04456      * Usage: 7
04457      *
04458      * @param   string      Prefix to temp file (which will have no extension btw)
04459      * @return  string      result from PHP function tempnam() with PATH_site.'typo3temp/' set for temp path.
04460      * @see unlink_tempfile(), upload_to_tempfile()
04461      */
04462     public static function tempnam($filePrefix) {
04463         return tempnam(PATH_site.'typo3temp/',$filePrefix);
04464     }
04465 
04466     /**
04467      * Standard authentication code (used in Direct Mail, checkJumpUrl and setfixed links computations)
04468      * Usage: 2
04469      *
04470      * @param   mixed       Uid (integer) or record (array)
04471      * @param   string      List of fields from the record if that is given.
04472      * @param   integer     Length of returned authentication code.
04473      * @return  string      MD5 hash of 8 chars.
04474      */
04475     public static function stdAuthCode($uid_or_record,$fields='',$codeLength=8) {
04476 
04477         if (is_array($uid_or_record))   {
04478             $recCopy_temp=array();
04479             if ($fields)    {
04480                 $fieldArr = self::trimExplode(',',$fields,1);
04481                 foreach ($fieldArr as $k => $v) {
04482                     $recCopy_temp[$k]=$uid_or_record[$v];
04483                 }
04484             } else {
04485                 $recCopy_temp=$uid_or_record;
04486             }
04487             $preKey = implode('|',$recCopy_temp);
04488         } else {
04489             $preKey = $uid_or_record;
04490         }
04491 
04492         $authCode = $preKey.'||'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
04493         $authCode = substr(md5($authCode),0,$codeLength);
04494         return $authCode;
04495     }
04496 
04497     /**
04498      * Splits the input query-parameters into an array with certain parameters filtered out.
04499      * Used to create the cHash value
04500      *
04501      * @param   string      Query-parameters: "&xxx=yyy&zzz=uuu"
04502      * @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
04503      * @see tslib_fe::makeCacheHash(), tslib_cObj::typoLink(), t3lib_div::calculateCHash()
04504      */
04505     public static function cHashParams($addQueryParams) {
04506         $params = explode('&',substr($addQueryParams,1));   // Splitting parameters up
04507 
04508             // Make array:
04509         $pA = array();
04510         foreach($params as $theP)   {
04511             $pKV = explode('=', $theP); // Splitting single param by '=' sign
04512             if (!self::inList('id,type,no_cache,cHash,MP,ftu',$pKV[0]) && !preg_match('/TSFE_ADMIN_PANEL\[.*?\]/',$pKV[0])) {
04513                 $pA[rawurldecode($pKV[0])] = (string)rawurldecode($pKV[1]);
04514             }
04515         }
04516             // Hook: Allows to manipulate the parameters which are taken to build the chash:
04517         if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['cHashParamsHook']))   {
04518             $cHashParamsHook =& $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['cHashParamsHook'];
04519             if (is_array($cHashParamsHook)) {
04520                 $hookParameters = array(
04521                     'addQueryParams' => &$addQueryParams,
04522                     'params' => &$params,
04523                     'pA' => &$pA,
04524                 );
04525                 $hookReference = null;
04526                 foreach ($cHashParamsHook as $hookFunction) {
04527                     self::callUserFunction($hookFunction, $hookParameters, $hookReference);
04528                 }
04529             }
04530         }
04531             // Finish and sort parameters array by keys:
04532         $pA['encryptionKey'] = $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
04533         ksort($pA);
04534 
04535         return $pA;
04536     }
04537 
04538     /**
04539      * Returns the cHash based on provided query parameters and added values from internal call
04540      *
04541      * @param   string      Query-parameters: "&xxx=yyy&zzz=uuu"
04542      * @return  string      Hash of all the values
04543      * @see t3lib_div::cHashParams(), t3lib_div::calculateCHash()
04544      */
04545     public static function generateCHash($addQueryParams) {
04546         $cHashParams = self::cHashParams($addQueryParams);
04547         $cHash = self::calculateCHash($cHashParams);
04548         return $cHash;
04549     }
04550 
04551     /**
04552      * Calculates the cHash based on the provided parameters
04553      *
04554      * @param   array       Array of key-value pairs
04555      * @return  string      Hash of all the values
04556      */
04557     public static function calculateCHash($params) {
04558         $cHash = md5(serialize($params));
04559         return $cHash;
04560     }
04561 
04562     /**
04563      * Responds on input localization setting value whether the page it comes from should be hidden if no translation exists or not.
04564      *
04565      * @param   integer     Value from "l18n_cfg" field of a page record
04566      * @return  boolean     True if the page should be hidden
04567      */
04568     public static function hideIfNotTranslated($l18n_cfg_fieldValue)    {
04569         if ($GLOBALS['TYPO3_CONF_VARS']['FE']['hidePagesIfNotTranslatedByDefault']) {
04570             return $l18n_cfg_fieldValue&2 ? FALSE : TRUE;
04571         } else {
04572             return $l18n_cfg_fieldValue&2 ? TRUE : FALSE;
04573         }
04574     }
04575 
04576     /**
04577      * Includes a locallang file and returns the $LOCAL_LANG array found inside.
04578      *
04579      * @param   string      Input is a file-reference (see t3lib_div::getFileAbsFileName). That file is expected to be a 'locallang.php' file containing a $LOCAL_LANG array (will be included!) or a 'locallang.xml' file conataining a valid XML TYPO3 language structure.
04580      * @param   string      Language key
04581      * @param   string      Character set (option); if not set, determined by the language key
04582      * @param   integer     Error mode (when file could not be found): 0 - syslog entry, 1 - do nothing, 2 - throw an exception
04583      * @return  array       Value of $LOCAL_LANG found in the included file. If that array is found it  will returned.
04584      *                      Otherwise an empty array and it is FALSE in error case.
04585      */
04586     public static function readLLfile($fileRef, $langKey, $charset = '', $errorMode = 0)    {
04587 
04588         $result = FALSE;
04589         $file = self::getFileAbsFileName($fileRef);
04590         if ($file)  {
04591             $baseFile = preg_replace('/\.(php|xml)$/', '', $file);
04592 
04593             if (@is_file($baseFile.'.xml')) {
04594                 $LOCAL_LANG = self::readLLXMLfile($baseFile.'.xml', $langKey, $charset);
04595             } elseif (@is_file($baseFile.'.php'))   {
04596                 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] || $charset)  {
04597                     $LOCAL_LANG = self::readLLPHPfile($baseFile.'.php', $langKey, $charset);
04598                 } else {
04599                     include($baseFile.'.php');
04600                     if (is_array($LOCAL_LANG))      {
04601                         $LOCAL_LANG = array('default'=>$LOCAL_LANG['default'], $langKey=>$LOCAL_LANG[$langKey]); }
04602                 }
04603             } else {
04604                 $errorMsg = 'File "' . $fileRef. '" not found!';
04605                 if ($errorMode == 2) {
04606                     throw new t3lib_exception($errorMsg);
04607                 } elseif(!$errorMode) {
04608                     self::sysLog($errorMsg, 'Core', self::SYSLOG_SEVERITY_ERROR);
04609                 }
04610                 $fileNotFound = TRUE;
04611             }
04612             if (is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride'][$fileRef])) {
04613                 foreach ($GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride'][$fileRef] as $overrideFile) {
04614                     $languageOverrideFileName = self::getFileAbsFileName($overrideFile);
04615                     if (@is_file($languageOverrideFileName)) {
04616                         $languageOverrideArray = self::readLLXMLfile($languageOverrideFileName, $langKey, $charset);
04617                         $LOCAL_LANG = self::array_merge_recursive_overrule($LOCAL_LANG, $languageOverrideArray);
04618                     }
04619                 }
04620             }
04621         }
04622         if ($fileNotFound !== TRUE) {
04623             $result = is_array($LOCAL_LANG) ? $LOCAL_LANG : array();
04624         }
04625         return $result;
04626     }
04627 
04628     /**
04629      * Includes a locallang-php file and returns the $LOCAL_LANG array
04630      * Works only when the frontend or backend has been initialized with a charset conversion object. See first code lines.
04631      *
04632      * @param   string      Absolute reference to locallang-PHP file
04633      * @param   string      TYPO3 language key, eg. "dk" or "de" or "default"
04634      * @param   string      Character set (optional)
04635      * @return  array       LOCAL_LANG array in return.
04636      */
04637     public static function readLLPHPfile($fileRef, $langKey, $charset='')   {
04638 
04639         if (is_object($GLOBALS['LANG']))    {
04640             $csConvObj = $GLOBALS['LANG']->csConvObj;
04641         } elseif (is_object($GLOBALS['TSFE']))  {
04642             $csConvObj = $GLOBALS['TSFE']->csConvObj;
04643         } else {
04644             $csConvObj = self::makeInstance('t3lib_cs');
04645         }
04646 
04647         if (@is_file($fileRef) && $langKey) {
04648 
04649                 // Set charsets:
04650             $sourceCharset = $csConvObj->parse_charset($csConvObj->charSetArray[$langKey] ? $csConvObj->charSetArray[$langKey] : 'iso-8859-1');
04651             if ($charset)   {
04652                 $targetCharset = $csConvObj->parse_charset($charset);
04653             } elseif ($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'])  {
04654                     // when forceCharset is set, we store ALL labels in this charset!!!
04655                 $targetCharset = $csConvObj->parse_charset($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset']);
04656             } else {
04657                 $targetCharset = $csConvObj->parse_charset($csConvObj->charSetArray[$langKey] ? $csConvObj->charSetArray[$langKey] : 'iso-8859-1');
04658             }
04659 
04660                 // Cache file name:
04661             $hashSource = substr($fileRef,strlen(PATH_site)).'|'.date('d-m-Y H:i:s',filemtime($fileRef)).'|version=2.3';
04662             $cacheFileName = PATH_site.'typo3temp/llxml/'.
04663                             substr(basename($fileRef),10,15).
04664                             '_'.self::shortMD5($hashSource).'.'.$langKey.'.'.$targetCharset.'.cache';
04665                 // Check if cache file exists...
04666             if (!@is_file($cacheFileName))  {   // ... if it doesn't, create content and write it:
04667 
04668                     // Get PHP data
04669                 include($fileRef);
04670                 if (!is_array($LOCAL_LANG)) {
04671                     $fileName = substr($fileRef, strlen(PATH_site));
04672                     throw new RuntimeException(
04673                         'TYPO3 Fatal Error: "' . $fileName . '" is no TYPO3 language file!',
04674                         1270853900
04675                     );
04676                 }
04677 
04678                     // converting the default language (English)
04679                     // this needs to be done for a few accented loan words and extension names
04680                 if (is_array($LOCAL_LANG['default']) && $targetCharset != 'iso-8859-1') {
04681                     foreach ($LOCAL_LANG['default'] as &$labelValue)    {
04682                         $labelValue = $csConvObj->conv($labelValue, 'iso-8859-1', $targetCharset);
04683                     }
04684                 }
04685 
04686                 if ($langKey!='default' && is_array($LOCAL_LANG[$langKey]) && $sourceCharset!=$targetCharset)   {
04687                     foreach ($LOCAL_LANG[$langKey] as &$labelValue) {
04688                         $labelValue = $csConvObj->conv($labelValue, $sourceCharset, $targetCharset);
04689                     }
04690                 }
04691 
04692                     // Cache the content now:
04693                 $serContent = array('origFile'=>$hashSource, 'LOCAL_LANG'=>array('default'=>$LOCAL_LANG['default'], $langKey=>$LOCAL_LANG[$langKey]));
04694                 $res = self::writeFileToTypo3tempDir($cacheFileName, serialize($serContent));
04695                 if ($res) {
04696                     throw new RuntimeException(
04697                         'TYPO3 Fatal Error: "' . $res,
04698                         1270853901
04699                     );
04700                 }
04701             } else {
04702                     // Get content from cache:
04703                 $serContent = unserialize(self::getUrl($cacheFileName));
04704                 $LOCAL_LANG = $serContent['LOCAL_LANG'];
04705             }
04706 
04707             return $LOCAL_LANG;
04708         }
04709     }
04710 
04711     /**
04712      * Includes a locallang-xml file and returns the $LOCAL_LANG array
04713      * Works only when the frontend or backend has been initialized with a charset conversion object. See first code lines.
04714      *
04715      * @param   string      Absolute reference to locallang-XML file
04716      * @param   string      TYPO3 language key, eg. "dk" or "de" or "default"
04717      * @param   string      Character set (optional)
04718      * @return  array       LOCAL_LANG array in return.
04719      */
04720     public static function readLLXMLfile($fileRef, $langKey, $charset='')   {
04721 
04722         if (is_object($GLOBALS['LANG']))    {
04723             $csConvObj = $GLOBALS['LANG']->csConvObj;
04724         } elseif (is_object($GLOBALS['TSFE']))  {
04725             $csConvObj = $GLOBALS['TSFE']->csConvObj;
04726         } else {
04727             $csConvObj = self::makeInstance('t3lib_cs');
04728         }
04729 
04730         $LOCAL_LANG = NULL;
04731         if (@is_file($fileRef) && $langKey) {
04732 
04733                 // Set charset:
04734             if ($charset)   {
04735                 $targetCharset = $csConvObj->parse_charset($charset);
04736             } elseif ($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'])  {
04737                     // when forceCharset is set, we store ALL labels in this charset!!!
04738                 $targetCharset = $csConvObj->parse_charset($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset']);
04739             } else {
04740                 $targetCharset = $csConvObj->parse_charset($csConvObj->charSetArray[$langKey] ? $csConvObj->charSetArray[$langKey] : 'iso-8859-1');
04741             }
04742 
04743                 // Cache file name:
04744             $hashSource = substr($fileRef,strlen(PATH_site)).'|'.date('d-m-Y H:i:s',filemtime($fileRef)).'|version=2.3';
04745             $cacheFileName = PATH_site.'typo3temp/llxml/'.
04746                         substr(basename($fileRef),10,15).
04747                         '_'.self::shortMD5($hashSource).'.'.$langKey.'.'.$targetCharset.'.cache';
04748 
04749                 // Check if cache file exists...
04750             if (!@is_file($cacheFileName))  {   // ... if it doesn't, create content and write it:
04751 
04752                     // Read XML, parse it.
04753                 $xmlString = self::getUrl($fileRef);
04754                 $xmlContent = self::xml2array($xmlString);
04755                 if (!is_array($xmlContent)) {
04756                     $fileName = substr($fileRef, strlen(PATH_site));
04757                     throw new RuntimeException(
04758                         'TYPO3 Fatal Error: The file "' . $fileName . '" is no TYPO3 language file!',
04759                         1270853902
04760                     );
04761                 }
04762 
04763                     // Set default LOCAL_LANG array content:
04764                 $LOCAL_LANG = array();
04765                 $LOCAL_LANG['default'] = $xmlContent['data']['default'];
04766 
04767                     // converting the default language (English)
04768                     // this needs to be done for a few accented loan words and extension names
04769                     // NOTE: no conversion is done when in UTF-8 mode!
04770                 if (is_array($LOCAL_LANG['default']) && $targetCharset != 'utf-8') {
04771                     foreach ($LOCAL_LANG['default'] as &$labelValue)    {
04772                         $labelValue = $csConvObj->utf8_decode($labelValue, $targetCharset);
04773                     }
04774                     unset($labelValue);
04775                 }
04776 
04777                     // converting other languages to their "native" charsets
04778                     // NOTE: no conversion is done when in UTF-8 mode!
04779                 if ($langKey!='default')    {
04780 
04781                         // 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:
04782                     $LOCAL_LANG[$langKey] = self::llXmlAutoFileName($fileRef, $langKey);
04783                     $localized_file = self::getFileAbsFileName($LOCAL_LANG[$langKey]);
04784                     if (!@is_file($localized_file) && isset($xmlContent['data'][$langKey])) {
04785                         $LOCAL_LANG[$langKey] = $xmlContent['data'][$langKey];
04786                     }
04787 
04788                         // Checking if charset should be converted.
04789                     if (is_array($LOCAL_LANG[$langKey]) && $targetCharset!='utf-8') {
04790                         foreach($LOCAL_LANG[$langKey] as $labelKey => $labelValue)  {
04791                             $LOCAL_LANG[$langKey][$labelKey] = $csConvObj->utf8_decode($labelValue,$targetCharset);
04792                         }
04793                     }
04794                 }
04795 
04796                     // Cache the content now:
04797                 $serContent = array('origFile'=>$hashSource, 'LOCAL_LANG'=>array('default'=>$LOCAL_LANG['default'], $langKey=>$LOCAL_LANG[$langKey]));
04798                 $res = self::writeFileToTypo3tempDir($cacheFileName, serialize($serContent));
04799                 if ($res) {
04800                     throw new RuntimeException(
04801                         'TYPO3 Fatal Error: ' . $res,
04802                         1270853903
04803                     );
04804                 }
04805             } else {
04806                     // Get content from cache:
04807                 $serContent = unserialize(self::getUrl($cacheFileName));
04808                 $LOCAL_LANG = $serContent['LOCAL_LANG'];
04809             }
04810 
04811                 // Checking for EXTERNAL file for non-default language:
04812             if ($langKey!='default' && is_string($LOCAL_LANG[$langKey]) && strlen($LOCAL_LANG[$langKey]))   {
04813 
04814                     // Look for localized file:
04815                 $localized_file = self::getFileAbsFileName($LOCAL_LANG[$langKey]);
04816                 if ($localized_file && @is_file($localized_file))   {
04817 
04818                         // Cache file name:
04819                     $hashSource = substr($localized_file,strlen(PATH_site)).'|'.date('d-m-Y H:i:s',filemtime($localized_file)).'|version=2.3';
04820                     $cacheFileName = PATH_site.'typo3temp/llxml/EXT_'.
04821                                     substr(basename($localized_file),10,15).
04822                                     '_'.self::shortMD5($hashSource).'.'.$langKey.'.'.$targetCharset.'.cache';
04823 
04824                         // Check if cache file exists...
04825                     if (!@is_file($cacheFileName))  {   // ... if it doesn't, create content and write it:
04826 
04827                             // Read and parse XML content:
04828                         $local_xmlString = self::getUrl($localized_file);
04829                         $local_xmlContent = self::xml2array($local_xmlString);
04830                         if (!is_array($local_xmlContent)) {
04831                             $fileName = substr($localized_file, strlen(PATH_site));
04832                             throw new RuntimeException(
04833                                 'TYPO3 Fatal Error: The file "' . $fileName . '" is no TYPO3 language file!',
04834                                 1270853904
04835                             );
04836                         }
04837                         $LOCAL_LANG[$langKey] = is_array($local_xmlContent['data'][$langKey]) ? $local_xmlContent['data'][$langKey] : array();
04838 
04839                             // Checking if charset should be converted.
04840                         if (is_array($LOCAL_LANG[$langKey]) && $targetCharset!='utf-8') {
04841                             foreach($LOCAL_LANG[$langKey] as $labelKey => $labelValue)  {
04842                                 $LOCAL_LANG[$langKey][$labelKey] = $csConvObj->utf8_decode($labelValue,$targetCharset);
04843                             }
04844                         }
04845 
04846                             // Cache the content now:
04847                         $serContent = array('extlang'=>$langKey, 'origFile'=>$hashSource, 'EXT_DATA'=>$LOCAL_LANG[$langKey]);
04848                         $res = self::writeFileToTypo3tempDir($cacheFileName, serialize($serContent));
04849                         if ($res) {
04850                             throw new RuntimeException(
04851                                 'TYPO3 Fatal Error: ' . $res,
04852                                 1270853905
04853                             );
04854                         }
04855                     } else {
04856                             // Get content from cache:
04857                         $serContent = unserialize(self::getUrl($cacheFileName));
04858                         $LOCAL_LANG[$langKey] = $serContent['EXT_DATA'];
04859                     }
04860                 } else {
04861                     $LOCAL_LANG[$langKey] = array();
04862                 }
04863             }
04864 
04865             return $LOCAL_LANG;
04866         }
04867     }
04868 
04869     /**
04870      * Returns auto-filename for locallang-XML localizations.
04871      *
04872      * @param   string      Absolute file reference to locallang-XML file. Must be inside system/global/local extension
04873      * @param   string      Language key
04874      * @return  string      Returns the filename reference for the language unless error occured (or local mode is used) in which case it will be NULL
04875      */
04876     public static function llXmlAutoFileName($fileRef,$language)    {
04877             // Analyse file reference:
04878         $location = 'typo3conf/l10n/'.$language.'/';    // Default location of translations
04879         if (self::isFirstPartOfStr($fileRef,PATH_typo3.'sysext/'))  {   // Is system:
04880             $validatedPrefix = PATH_typo3.'sysext/';
04881             #$location = 'EXT:csh_'.$language.'/';  // For system extensions translations are found in "csh_*" extensions (language packs)
04882         } elseif (self::isFirstPartOfStr($fileRef,PATH_typo3.'ext/'))   {   // Is global:
04883             $validatedPrefix = PATH_typo3.'ext/';
04884         } elseif (self::isFirstPartOfStr($fileRef,PATH_typo3conf.'ext/'))   {   // Is local:
04885             $validatedPrefix = PATH_typo3conf.'ext/';
04886         } else {
04887             $validatedPrefix = '';
04888         }
04889 
04890         if ($validatedPrefix)   {
04891 
04892                 // Divide file reference into extension key, directory (if any) and base name:
04893             list($file_extKey,$file_extPath) = explode('/',substr($fileRef,strlen($validatedPrefix)),2);
04894             $temp = self::revExplode('/',$file_extPath,2);
04895             if (count($temp)==1)    array_unshift($temp,'');    // Add empty first-entry if not there.
04896             list($file_extPath,$file_fileName) = $temp;
04897 
04898                 // The filename is prefixed with "[language key]." because it prevents the llxmltranslate tool from detecting it.
04899             return $location.
04900                 $file_extKey.'/'.
04901                 ($file_extPath?$file_extPath.'/':'').
04902                 $language.'.'.$file_fileName;
04903         } else {
04904             return NULL;
04905         }
04906     }
04907 
04908 
04909     /**
04910      * Loads the $TCA (Table Configuration Array) for the $table
04911      *
04912      * Requirements:
04913      * 1) must be configured table (the ctrl-section configured),
04914      * 2) columns must not be an array (which it is always if whole table loaded), and
04915      * 3) there is a value for dynamicConfigFile (filename in typo3conf)
04916      *
04917      * Note: For the frontend this loads only 'ctrl' and 'feInterface' parts.
04918      * For complete TCA use $GLOBALS['TSFE']->includeTCA() instead.
04919      *
04920      * Usage: 84
04921      *
04922      * @param   string      Table name for which to load the full TCA array part into the global $TCA
04923      * @return  void
04924      */
04925     public static function loadTCA($table)  {
04926         global $TCA;
04927 
04928         if (isset($TCA[$table])) {
04929             $tca = &$TCA[$table];
04930             if (!$tca['columns']) {
04931                 $dcf = $tca['ctrl']['dynamicConfigFile'];
04932                 if ($dcf) {
04933                     if (!strcmp(substr($dcf,0,6),'T3LIB:')) {
04934                         include(PATH_t3lib.'stddb/'.substr($dcf,6));
04935                     } elseif (self::isAbsPath($dcf) && @is_file($dcf))  {   // Absolute path...
04936                         include($dcf);
04937                     } else include(PATH_typo3conf.$dcf);
04938                 }
04939             }
04940         }
04941     }
04942 
04943     /**
04944      * 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).
04945      * If the sheet definition is in an external file that file is parsed and the data structure inside of that is returned.
04946      * Usage: 5
04947      *
04948      * @param   array       Input data structure, possibly with a sheet-definition and references to external data source files.
04949      * @param   string      The sheet to return, preferably.
04950      * @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!
04951      */
04952     public static function resolveSheetDefInDS($dataStructArray,$sheet='sDEF')  {
04953         if (!is_array ($dataStructArray)) return 'Data structure must be an array';
04954 
04955         if (is_array($dataStructArray['sheets']))   {
04956             $singleSheet = FALSE;
04957             if (!isset($dataStructArray['sheets'][$sheet])) {
04958                 $sheet='sDEF';
04959             }
04960             $dataStruct =  $dataStructArray['sheets'][$sheet];
04961 
04962                 // If not an array, but still set, then regard it as a relative reference to a file:
04963             if ($dataStruct && !is_array($dataStruct))  {
04964                 $file = self::getFileAbsFileName($dataStruct);
04965                 if ($file && @is_file($file))   {
04966                     $dataStruct = self::xml2array(self::getUrl($file));
04967                 }
04968             }
04969         } else {
04970             $singleSheet = TRUE;
04971             $dataStruct = $dataStructArray;
04972             if (isset($dataStruct['meta'])) unset($dataStruct['meta']); // Meta data should not appear there.
04973             $sheet = 'sDEF';    // Default sheet
04974         }
04975         return array($dataStruct,$sheet,$singleSheet);
04976     }
04977 
04978     /**
04979      * Resolves ALL sheet definitions in dataStructArray
04980      * If no sheet is found, then the default "sDEF" will be created with the dataStructure inside.
04981      *
04982      * @param   array       Input data structure, possibly with a sheet-definition and references to external data source files.
04983      * @return  array       Output data structure with all sheets resolved as arrays.
04984      */
04985     public static function resolveAllSheetsInDS(array $dataStructArray) {
04986         if (is_array($dataStructArray['sheets']))   {
04987             $out=array('sheets'=>array());
04988             foreach($dataStructArray['sheets'] as $sheetId => $sDat)    {
04989                 list($ds,$aS) = self::resolveSheetDefInDS($dataStructArray,$sheetId);
04990                 if ($sheetId==$aS)  {
04991                     $out['sheets'][$aS]=$ds;
04992                 }
04993             }
04994         } else {
04995             list($ds) = self::resolveSheetDefInDS($dataStructArray);
04996             $out = array('sheets' => array('sDEF' => $ds));
04997         }
04998         return $out;
04999     }
05000 
05001     /**
05002      * Calls a userdefined function/method in class
05003      * Such a function/method should look like this: "function proc(&$params, &$ref)    {...}"
05004      * Usage: 17
05005      *
05006      * @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").
05007      * @param   mixed       Parameters to be pass along (typically an array) (REFERENCE!)
05008      * @param   mixed       Reference to be passed along (typically "$this" - being a reference to the calling object) (REFERENCE!)
05009      * @param   string      Required prefix of class or function name
05010      * @param   integer     Error mode (when class/function could not be found): 0 - call debug(), 1 - do nothing, 2 - raise an exception (allows to call a user function that may return FALSE)
05011      * @return  mixed       Content from method/function call or false if the class/method/function was not found
05012      * @see getUserObj()