TYPO3 API  SVNRelease
class.t3lib_befunc.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003  *  Copyright notice
00004  *
00005  *  (c) 1999-2011 Kasper Skårhøj (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  * Standard functions available for the TYPO3 backend.
00029  * You are encouraged to use this class in your own applications (Backend Modules)
00030  *
00031  * Call ALL methods without making an object!
00032  * Eg. to get a page-record 51 do this: 't3lib_BEfunc::getRecord('pages',51)'
00033  *
00034  * $Id: class.t3lib_befunc.php 10547 2011-02-22 20:03:57Z lolli $
00035  * Usage counts are based on search 22/2 2003 through whole backend source of typo3/
00036  * Revised for TYPO3 3.6 July/2003 by Kasper Skårhøj
00037  * XHTML compliant
00038  *
00039  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00040  */
00041 /**
00042  * [CLASS/FUNCTION INDEX of SCRIPT]
00043  *
00044  *
00045  *
00046  *  185: class t3lib_BEfunc
00047  *
00048  *            SECTION: SQL-related, selecting records, searching
00049  *  206:     function deleteClause($table,$tableAlias='')
00050  *  230:     function getRecord($table,$uid,$fields='*',$where='',$useDeleteClause=true)
00051  *  253:     function getRecordWSOL($table,$uid,$fields='*',$where='',$useDeleteClause=true)
00052  *  286:     function getRecordRaw($table,$where='',$fields='*')
00053  *  309:     function getRecordsByField($theTable,$theField,$theValue,$whereClause='',$groupBy='',$orderBy='',$limit='',$useDeleteClause=true)
00054  *  342:     function searchQuery($searchWords,$fields,$table='')
00055  *  357:     function listQuery($field,$value)
00056  *  369:     function splitTable_Uid($str)
00057  *  384:     function getSQLselectableList($in_list,$tablename,$default_tablename)
00058  *  412:     function BEenableFields($table,$inv=0)
00059  *
00060  *            SECTION: SQL-related, DEPRECATED functions
00061  *  476:     function mm_query($select,$local_table,$mm_table,$foreign_table,$whereClause='',$groupBy='',$orderBy='',$limit='')
00062  *  498:     function DBcompileInsert($table,$fields_values)
00063  *  512:     function DBcompileUpdate($table,$where,$fields_values)
00064  *
00065  *            SECTION: Page tree, TCA related
00066  *  542:     function BEgetRootLine($uid,$clause='',$workspaceOL=FALSE)
00067  *  598:     function openPageTree($pid,$clearExpansion)
00068  *  643:     function getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit=0)
00069  *  686:     function getExcludeFields()
00070  *  716:     function getExplicitAuthFieldValues()
00071  *  787:     function getSystemLanguages()
00072  *  812:     function readPageAccess($id,$perms_clause)
00073  *  843:     function getTCAtypes($table,$rec,$useFieldNameAsKey=0)
00074  *  896:     function getTCAtypeValue($table,$rec)
00075  *  919:     function getSpecConfParts($str, $defaultExtras)
00076  *  950:     function getSpecConfParametersFromArray($pArr)
00077  *  978:     function getFlexFormDS($conf,$row,$table,$fieldName='',$WSOL=TRUE)
00078  *
00079  *            SECTION: Caching related
00080  * 1105:     function storeHash($hash,$data,$ident)
00081  * 1125:     function getHash($hash)
00082  *
00083  *            SECTION: TypoScript related
00084  * 1161:     function getPagesTSconfig($id,$rootLine='',$returnPartArray=0)
00085  * 1217:     function updatePagesTSconfig($id,$pageTS,$TSconfPrefix,$impParams='')
00086  * 1272:     function implodeTSParams($p,$k='')
00087  *
00088  *            SECTION: Users / Groups related
00089  * 1309:     function getUserNames($fields='username,usergroup,usergroup_cached_list,uid',$where='')
00090  * 1327:     function getGroupNames($fields='title,uid', $where='')
00091  * 1344:     function getListGroupNames($fields='title,uid')
00092  * 1363:     function blindUserNames($usernames,$groupArray,$excludeBlindedFlag=0)
00093  * 1396:     function blindGroupNames($groups,$groupArray,$excludeBlindedFlag=0)
00094  *
00095  *            SECTION: Output related
00096  * 1437:     function daysUntil($tstamp)
00097  * 1449:     function date($tstamp)
00098  * 1460:     function datetime($value)
00099  * 1472:     function time($value)
00100  * 1488:     function calcAge($seconds,$labels = 'min|hrs|days|yrs')
00101  * 1514:     function dateTimeAge($tstamp,$prefix=1,$date='')
00102  * 1532:     function titleAttrib($content='',$hsc=0)
00103  * 1545:     function titleAltAttrib($content)
00104  * 1569:     function thumbCode($row,$table,$field,$backPath,$thumbScript='',$uploaddir=NULL,$abs=0,$tparams='',$size='')
00105  * 1637:     function getThumbNail($thumbScript,$theFile,$tparams='',$size='')
00106  * 1654:     function titleAttribForPages($row,$perms_clause='',$includeAttrib=1)
00107  * 1716:     function getRecordIconAltText($row,$table='pages')
00108  * 1758:     function getLabelFromItemlist($table,$col,$key)
00109  * 1784:     function getItemLabel($table,$col,$printAllWrap='')
00110  * 1809:     function getRecordTitle($table,$row,$prep=0)
00111  * 1847:     function getProcessedValue($table,$col,$value,$fixed_lgd_chars=0,$defaultPassthrough=0,$noRecordLookup=FALSE,$uid=0)
00112  * 2009:     function getProcessedValueExtra($table,$fN,$fV,$fixed_lgd_chars=0,$uid=0)
00113  * 2033:     function getFileIcon($ext)
00114  * 2047:     function getCommonSelectFields($table,$prefix='')
00115  * 2090:     function makeConfigForm($configArray,$defaults,$dataPrefix)
00116  *
00117  *            SECTION: Backend Modules API functions
00118  * 2165:     function helpTextIcon($table,$field,$BACK_PATH,$force=0)
00119  * 2187:     function helpText($table,$field,$BACK_PATH,$styleAttrib='')
00120  * 2239:     function cshItem($table,$field,$BACK_PATH,$wrap='',$onlyIconMode=FALSE, $styleAttrib='')
00121  * 2277:     function editOnClick($params,$backPath='',$requestUri='')
00122  * 2296:     function viewOnClick($id,$backPath='',$rootLine='',$anchor='',$altUrl='',$additionalGetVars='',$switchFocus=TRUE)
00123  * 2328:     function getModTSconfig($id,$TSref)
00124  * 2349:     function getFuncMenu($mainParams,$elementName,$currentValue,$menuItems,$script='',$addparams='')
00125  * 2392:     function getFuncCheck($mainParams,$elementName,$currentValue,$script='',$addparams='',$tagParams='')
00126  * 2417:     function getFuncInput($mainParams,$elementName,$currentValue,$size=10,$script="",$addparams="")
00127  * 2438:     function unsetMenuItems($modTSconfig,$itemArray,$TSref)
00128  * 2461:     function getSetUpdateSignal($set='')
00129  * 2512:     function getModuleData($MOD_MENU, $CHANGED_SETTINGS, $modName, $type='', $dontValidateList='', $setDefaultList='')
00130  *
00131  *            SECTION: Core
00132  * 2585:     function compilePreviewKeyword($getVarsStr, $beUserUid, $ttl=172800)
00133  * 2613:     function lockRecords($table='',$uid=0,$pid=0)
00134  * 2642:     function isRecordLocked($table,$uid)
00135  * 2682:     function exec_foreign_table_where_query($fieldValue,$field='',$TSconfig=array(),$prefix='')
00136  * 2763:     function getTCEFORM_TSconfig($table,$row)
00137  * 2814:     function getTSconfig_pidValue($table,$uid,$pid)
00138  * 2844:     function getPidForModTSconfig($table,$uid,$pid)
00139  * 2860:     function getTSCpid($table,$uid,$pid)
00140  * 2876:     function firstDomainRecord($rootLine)
00141  * 2898:     function getDomainStartPage($domain, $path='')
00142  * 2928:     function RTEsetup($RTEprop,$table,$field,$type='')
00143  * 2947:     function &RTEgetObj()
00144  * 2986:     function &softRefParserObj($spKey)
00145  * 3018:     function explodeSoftRefParserList($parserList)
00146  * 3050:     function isModuleSetInTBE_MODULES($modName)
00147  * 3073:     function referenceCount($table,$ref,$msg='')
00148  *
00149  *            SECTION: Workspaces / Versioning
00150  * 3132:     function selectVersionsOfRecord($table, $uid, $fields='*', $workspace=0)
00151  * 3180:     function fixVersioningPid($table,&$rr,$ignoreWorkspaceMatch=FALSE)
00152  * 3220:     function workspaceOL($table,&$row,$wsid=-99)
00153  * 3268:     function getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields='*')
00154  * 3297:     function getLiveVersionOfRecord($table,$uid,$fields='*')
00155  * 3319:     function isPidInVersionizedBranch($pid, $table='',$returnStage=FALSE)
00156  * 3342:     function versioningPlaceholderClause($table)
00157  * 3356:     function countVersionsOfRecordsOnPage($workspace,$pageId, $allTables=FALSE)
00158  * 3391:     function wsMapId($table,$uid)
00159  *
00160  *            SECTION: Miscellaneous
00161  * 3421:     function typo3PrintError($header,$text,$js='',$head=1)
00162  * 3465:     function TYPO3_copyRightNotice()
00163  * 3489:     function displayWarningMessages()
00164  * 3546:     function getPathType_web_nonweb($path)
00165  * 3558:     function ADMCMD_previewCmds($pageinfo)
00166  * 3580:     function processParams($params)
00167  * 3606:     function getListOfBackendModules($name,$perms_clause,$backPath='',$script='index.php')
00168  *
00169  * TOTAL FUNCTIONS: 99
00170  * (This index is automatically created/updated by the extension "extdeveval")
00171  *
00172  */
00173 
00174 
00175 /**
00176  * Standard functions available for the TYPO3 backend.
00177  * Don't instantiate - call functions with "t3lib_BEfunc::" prefixed the function name.
00178  *
00179  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00180  * @package TYPO3
00181  * @subpackage t3lib
00182  */
00183 final class t3lib_BEfunc {
00184 
00185 
00186     /*******************************************
00187      *
00188      * SQL-related, selecting records, searching
00189      *
00190      *******************************************/
00191 
00192 
00193     /**
00194      * Returns the WHERE clause " AND NOT [tablename].[deleted-field]" if a deleted-field is configured in $TCA for the tablename, $table
00195      * This function should ALWAYS be called in the backend for selection on tables which are configured in TCA since it will ensure consistent selection of records, even if they are marked deleted (in which case the system must always treat them as non-existent!)
00196      * In the frontend a function, ->enableFields(), is known to filter hidden-field, start- and endtime and fe_groups as well. But that is a job of the frontend, not the backend. If you need filtering on those fields as well in the backend you can use ->BEenableFields() though.
00197      * Usage: 71
00198      *
00199      * @param   string      Table name present in $TCA
00200      * @param   string      Table alias if any
00201      * @return  string      WHERE clause for filtering out deleted records, eg " AND tablename.deleted=0"
00202      */
00203     public static function deleteClause($table, $tableAlias = '') {
00204         global $TCA;
00205         if ($TCA[$table]['ctrl']['delete']) {
00206             return ' AND ' . ($tableAlias ? $tableAlias : $table) . '.' . $TCA[$table]['ctrl']['delete'] . '=0';
00207         } else {
00208             return '';
00209         }
00210     }
00211 
00212     /**
00213      * Gets record with uid = $uid from $table
00214      * You can set $field to a list of fields (default is '*')
00215      * Additional WHERE clauses can be added by $where (fx. ' AND blabla = 1')
00216      * Will automatically check if records has been deleted and if so, not return anything.
00217      * $table must be found in $TCA
00218      * Usage: 99
00219      *
00220      * @param   string      Table name present in $TCA
00221      * @param   integer     UID of record
00222      * @param   string      List of fields to select
00223      * @param   string      Additional WHERE clause, eg. " AND blablabla = 0"
00224      * @param   boolean     Use the deleteClause to check if a record is deleted (default true)
00225      * @return  array       Returns the row if found, otherwise nothing
00226      */
00227     public static function getRecord($table, $uid, $fields = '*', $where = '', $useDeleteClause = TRUE) {
00228         if ($GLOBALS['TCA'][$table]) {
00229             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
00230                 $fields,
00231                 $table,
00232                     'uid=' . intval($uid) . ($useDeleteClause ? self::deleteClause($table) : '') . $where
00233             );
00234             $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00235             $GLOBALS['TYPO3_DB']->sql_free_result($res);
00236             if ($row) {
00237                 return $row;
00238             }
00239         }
00240     }
00241 
00242     /**
00243      * Like getRecord(), but overlays workspace version if any.
00244      *
00245      * @param   string      Table name present in $TCA
00246      * @param   integer     UID of record
00247      * @param   string      List of fields to select
00248      * @param   string      Additional WHERE clause, eg. " AND blablabla = 0"
00249      * @param   boolean     Use the deleteClause to check if a record is deleted (default true)
00250      * @param   boolean     If true the function does not return a "pointer" row for moved records in a workspace
00251      * @return  array       Returns the row if found, otherwise nothing
00252      */
00253     public static function getRecordWSOL($table, $uid, $fields = '*', $where = '', $useDeleteClause = TRUE, $unsetMovePointers = FALSE) {
00254         if ($fields !== '*') {
00255             $internalFields = t3lib_div::uniqueList($fields . ',uid,pid' . ($table == 'pages' ? ',t3ver_swapmode' : ''));
00256             $row = self::getRecord($table, $uid, $internalFields, $where, $useDeleteClause);
00257             self::workspaceOL($table, $row, -99, $unsetMovePointers);
00258 
00259             if (is_array($row)) {
00260                 foreach (array_keys($row) as $key) {
00261                     if (!t3lib_div::inList($fields, $key) && $key{0} !== '_') {
00262                         unset ($row[$key]);
00263                     }
00264                 }
00265             }
00266         } else {
00267             $row = self::getRecord($table, $uid, $fields, $where, $useDeleteClause);
00268             self::workspaceOL($table, $row, -99, $unsetMovePointers);
00269         }
00270         return $row;
00271     }
00272 
00273     /**
00274      * Returns the first record found from $table with $where as WHERE clause
00275      * This function does NOT check if a record has the deleted flag set.
00276      * $table does NOT need to be configured in $TCA
00277      * The query used is simply this:
00278      * $query = 'SELECT '.$fields.' FROM '.$table.' WHERE '.$where;
00279      * Usage: 5 (ext: sys_todos)
00280      *
00281      * @param   string      Table name (not necessarily in TCA)
00282      * @param   string      WHERE clause
00283      * @param   string      $fields is a list of fields to select, default is '*'
00284      * @return  array       First row found, if any, FALSE otherwise
00285      */
00286     public static function getRecordRaw($table, $where = '', $fields = '*') {
00287         $row = FALSE;
00288         if (FALSE !== ($res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fields, $table, $where, '', '', '1'))) {
00289             $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00290             $GLOBALS['TYPO3_DB']->sql_free_result($res);
00291         }
00292         return $row;
00293     }
00294 
00295     /**
00296      * Returns records from table, $theTable, where a field ($theField) equals the value, $theValue
00297      * The records are returned in an array
00298      * If no records were selected, the function returns nothing
00299      * Usage: 8
00300      *
00301      * @param   string      Table name present in $TCA
00302      * @param   string      Field to select on
00303      * @param   string      Value that $theField must match
00304      * @param   string      Optional additional WHERE clauses put in the end of the query. DO NOT PUT IN GROUP BY, ORDER BY or LIMIT!
00305      * @param   string      Optional GROUP BY field(s), if none, supply blank string.
00306      * @param   string      Optional ORDER BY field(s), if none, supply blank string.
00307      * @param   string      Optional LIMIT value ([begin,]max), if none, supply blank string.
00308      * @param   boolean     Use the deleteClause to check if a record is deleted (default true)
00309      * @return  mixed       Multidimensional array with selected records (if any is selected)
00310      */
00311     public static function getRecordsByField($theTable, $theField, $theValue, $whereClause = '', $groupBy = '', $orderBy = '', $limit = '', $useDeleteClause = TRUE) {
00312         global $TCA;
00313         if (is_array($TCA[$theTable])) {
00314             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
00315                 '*',
00316                 $theTable,
00317                     $theField . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($theValue, $theTable) .
00318                             ($useDeleteClause ? self::deleteClause($theTable) . ' ' : '') .
00319                             self::versioningPlaceholderClause($theTable) . ' ' .
00320                             $whereClause, // whereClauseMightContainGroupOrderBy
00321                 $groupBy,
00322                 $orderBy,
00323                 $limit
00324             );
00325             $rows = array();
00326             while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
00327                 $rows[] = $row;
00328             }
00329             $GLOBALS['TYPO3_DB']->sql_free_result($res);
00330             if (count($rows)) {
00331                 return $rows;
00332             }
00333         }
00334     }
00335 
00336     /**
00337      * Makes an backwards explode on the $str and returns an array with ($table, $uid).
00338      * Example: tt_content_45 => array('tt_content', 45)
00339      * Usage: 1
00340      *
00341      * @param   string      [tablename]_[uid] string to explode
00342      * @return  array
00343      */
00344     public static function splitTable_Uid($str) {
00345         list($uid, $table) = explode('_', strrev($str), 2);
00346         return array(strrev($table), strrev($uid));
00347     }
00348 
00349     /**
00350      * Returns a list of pure integers based on $in_list being a list of records with table-names prepended.
00351      * Ex: $in_list = "pages_4,tt_content_12,45" would result in a return value of "4,45" if $tablename is "pages" and $default_tablename is 'pages' as well.
00352      * Usage: 1 (t3lib_userauthgroup)
00353      *
00354      * @param   string      Input list
00355      * @param   string      Table name from which ids is returned
00356      * @param   string      $default_tablename denotes what table the number '45' is from (if nothing is prepended on the value)
00357      * @return  string      List of ids
00358      */
00359     public static function getSQLselectableList($in_list, $tablename, $default_tablename) {
00360         $list = Array();
00361         if ((string) trim($in_list) != '') {
00362             $tempItemArray = explode(',', trim($in_list));
00363             foreach ($tempItemArray as $key => $val) {
00364                 $val = strrev($val);
00365                 $parts = explode('_', $val, 2);
00366                 if ((string) trim($parts[0]) != '') {
00367                     $theID = intval(strrev($parts[0]));
00368                     $theTable = trim($parts[1]) ? strrev(trim($parts[1])) : $default_tablename;
00369                     if ($theTable == $tablename) {
00370                         $list[] = $theID;
00371                     }
00372                 }
00373             }
00374         }
00375         return implode(',', $list);
00376     }
00377 
00378     /**
00379      * Backend implementation of enableFields()
00380      * Notice that "fe_groups" is not selected for - only disabled, starttime and endtime.
00381      * Notice that deleted-fields are NOT filtered - you must ALSO call deleteClause in addition.
00382      * $GLOBALS["SIM_ACCESS_TIME"] is used for date.
00383      * Usage: 5
00384      *
00385      * @param   string      $table is the table from which to return enableFields WHERE clause. Table name must have a 'ctrl' section in $TCA.
00386      * @param   boolean     $inv means that the query will select all records NOT VISIBLE records (inverted selection)
00387      * @return  string      WHERE clause part
00388      */
00389     public static function BEenableFields($table, $inv = 0) {
00390         $ctrl = $GLOBALS['TCA'][$table]['ctrl'];
00391         $query = array();
00392         $invQuery = array();
00393         if (is_array($ctrl)) {
00394             if (is_array($ctrl['enablecolumns'])) {
00395                 if ($ctrl['enablecolumns']['disabled']) {
00396                     $field = $table . '.' . $ctrl['enablecolumns']['disabled'];
00397                     $query[] = $field . '=0';
00398                     $invQuery[] = $field . '!=0';
00399                 }
00400                 if ($ctrl['enablecolumns']['starttime']) {
00401                     $field = $table . '.' . $ctrl['enablecolumns']['starttime'];
00402                     $query[] = '(' . $field . '<=' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
00403                     $invQuery[] = '(' . $field . '!=0 AND ' . $field . '>' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
00404                 }
00405                 if ($ctrl['enablecolumns']['endtime']) {
00406                     $field = $table . '.' . $ctrl['enablecolumns']['endtime'];
00407                     $query[] = '(' . $field . '=0 OR ' . $field . '>' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
00408                     $invQuery[] = '(' . $field . '!=0 AND ' . $field . '<=' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
00409                 }
00410             }
00411         }
00412         $outQ = ($inv ? '(' . implode(' OR ', $invQuery) . ')' : implode(' AND ', $query));
00413 
00414         return $outQ ? ' AND ' . $outQ : '';
00415     }
00416 
00417     /**
00418      * Fetches the localization for a given record.
00419      *
00420      * @param   string      $table: Table name present in $TCA
00421      * @param   integer     $uid: The uid of the record
00422      * @param   integer     $language: The uid of the language record in sys_language
00423      * @param   string      $andWhereClause: Optional additional WHERE clause (default: '')
00424      * @return  mixed       Multidimensional array with selected records; if none exist, false is returned
00425      */
00426     public static function getRecordLocalization($table, $uid, $language, $andWhereClause = '') {
00427         $recordLocalization = FALSE;
00428         if (self::isTableLocalizable($table)) {
00429             $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl'];
00430             $recordLocalization = self::getRecordsByField(
00431                 $table,
00432                 $tcaCtrl['transOrigPointerField'],
00433                 $uid,
00434                     'AND ' . $tcaCtrl['languageField'] . '=' . intval($language) . ($andWhereClause ? ' ' . $andWhereClause : ''),
00435                 '',
00436                 '',
00437                 '1'
00438             );
00439         }
00440         return $recordLocalization;
00441     }
00442 
00443 
00444     /*******************************************
00445      *
00446      * Page tree, TCA related
00447      *
00448      *******************************************/
00449 
00450     /**
00451      * Returns what is called the 'RootLine'. That is an array with information about the page records from a page id ($uid) and back to the root.
00452      * By default deleted pages are filtered.
00453      * This RootLine will follow the tree all the way to the root. This is opposite to another kind of root line known from the frontend where the rootline stops when a root-template is found.
00454      * Usage: 1
00455      *
00456      * @param   integer     Page id for which to create the root line.
00457      * @param   string      $clause can be used to select other criteria. It would typically be where-clauses that stops the process if we meet a page, the user has no reading access to.
00458      * @param   boolean     If true, version overlay is applied. This must be requested specifically because it is usually only wanted when the rootline is used for visual output while for permission checking you want the raw thing!
00459      * @return  array       Root line array, all the way to the page tree root (or as far as $clause allows!)
00460      */
00461     public static function BEgetRootLine($uid, $clause = '', $workspaceOL = FALSE) {
00462         static $BEgetRootLine_cache = array();
00463 
00464         $output = array();
00465         $pid = $uid;
00466         $ident = $pid . '-' . $clause . '-' . $workspaceOL;
00467 
00468         if (is_array($BEgetRootLine_cache[$ident])) {
00469             $output = $BEgetRootLine_cache[$ident];
00470         } else {
00471             $loopCheck = 100;
00472             $theRowArray = array();
00473             while ($uid != 0 && $loopCheck) {
00474                 $loopCheck--;
00475                 $row = self::getPageForRootline($uid, $clause, $workspaceOL);
00476                 if (is_array($row)) {
00477                     $uid = $row['pid'];
00478                     $theRowArray[] = $row;
00479                 } else {
00480                     break;
00481                 }
00482             }
00483             if ($uid == 0) {
00484                 $theRowArray[] = array('uid' => 0, 'title' => '');
00485             }
00486             $c = count($theRowArray);
00487 
00488             foreach ($theRowArray as $val) {
00489                 $c--;
00490                 $output[$c] = array(
00491                     'uid' => $val['uid'],
00492                     'pid' => $val['pid'],
00493                     'title' => $val['title'],
00494                     'TSconfig' => $val['TSconfig'],
00495                     'is_siteroot' => $val['is_siteroot'],
00496                     'storage_pid' => $val['storage_pid'],
00497                     't3ver_oid' => $val['t3ver_oid'],
00498                     't3ver_wsid' => $val['t3ver_wsid'],
00499                     't3ver_state' => $val['t3ver_state'],
00500                     't3ver_swapmode' => $val['t3ver_swapmode'],
00501                     't3ver_stage' => $val['t3ver_stage'],
00502                     'backend_layout_next_level' => $val['backend_layout_next_level']
00503                 );
00504                 if (isset($val['_ORIG_pid'])) {
00505                     $output[$c]['_ORIG_pid'] = $val['_ORIG_pid'];
00506                 }
00507             }
00508             $BEgetRootLine_cache[$ident] = $output;
00509         }
00510         return $output;
00511     }
00512 
00513     /**
00514      * Gets the cached page record for the rootline
00515      *
00516      * @param   integer     $uid: Page id for which to create the root line.
00517      * @param   string      $clause: can be used to select other criteria. It would typically be where-clauses that stops the process if we meet a page, the user has no reading access to.
00518      * @param   boolean     $workspaceOL: If true, version overlay is applied. This must be requested specifically because it is usually only wanted when the rootline is used for visual output while for permission checking you want the raw thing!
00519      * @return  array       Cached page record for the rootline
00520      * @see     BEgetRootLine
00521      */
00522     protected static function getPageForRootline($uid, $clause, $workspaceOL) {
00523         static $getPageForRootline_cache = array();
00524         $ident = $uid . '-' . $clause . '-' . $workspaceOL;
00525 
00526         if (is_array($getPageForRootline_cache[$ident])) {
00527             $row = $getPageForRootline_cache[$ident];
00528         } else {
00529             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
00530                 'pid,uid,title,TSconfig,is_siteroot,storage_pid,t3ver_oid,t3ver_wsid,t3ver_state,t3ver_swapmode,t3ver_stage,backend_layout_next_level',
00531                 'pages',
00532                     'uid=' . intval($uid) . ' ' .
00533                             self::deleteClause('pages') . ' ' .
00534                             $clause // whereClauseMightContainGroupOrderBy
00535             );
00536 
00537             $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00538             if ($row) {
00539                 if ($workspaceOL) {
00540                     self::workspaceOL('pages', $row);
00541                 }
00542                 if (is_array($row)) {
00543                     self::fixVersioningPid('pages', $row);
00544                     $getPageForRootline_cache[$ident] = $row;
00545                 }
00546             }
00547             $GLOBALS['TYPO3_DB']->sql_free_result($res);
00548         }
00549         return $row;
00550     }
00551 
00552     /**
00553      * Opens the page tree to the specified page id
00554      *
00555      * @param   integer     Page id.
00556      * @param   boolean     If set, then other open branches are closed.
00557      * @return  void
00558      */
00559     public static function openPageTree($pid, $clearExpansion) {
00560         global $BE_USER;
00561 
00562             // Get current expansion data:
00563         if ($clearExpansion) {
00564             $expandedPages = array();
00565         } else {
00566             $expandedPages = unserialize($BE_USER->uc['browseTrees']['browsePages']);
00567         }
00568 
00569             // Get rootline:
00570         $rL = self::BEgetRootLine($pid);
00571 
00572             // First, find out what mount index to use (if more than one DB mount exists):
00573         $mountIndex = 0;
00574         $mountKeys = array_flip($BE_USER->returnWebmounts());
00575         foreach ($rL as $rLDat) {
00576             if (isset($mountKeys[$rLDat['uid']])) {
00577                 $mountIndex = $mountKeys[$rLDat['uid']];
00578                 break;
00579             }
00580         }
00581 
00582             // Traverse rootline and open paths:
00583         foreach ($rL as $rLDat) {
00584             $expandedPages[$mountIndex][$rLDat['uid']] = 1;
00585         }
00586 
00587             // Write back:
00588         $BE_USER->uc['browseTrees']['browsePages'] = serialize($expandedPages);
00589         $BE_USER->writeUC();
00590     }
00591 
00592     /**
00593      * Returns the path (visually) of a page $uid, fx. "/First page/Second page/Another subpage"
00594      * Each part of the path will be limited to $titleLimit characters
00595      * Deleted pages are filtered out.
00596      * Usage: 15
00597      *
00598      * @param   integer     Page uid for which to create record path
00599      * @param   string      $clause is additional where clauses, eg. "
00600      * @param   integer     Title limit
00601      * @param   integer     Title limit of Full title (typ. set to 1000 or so)
00602      * @return  mixed       Path of record (string) OR array with short/long title if $fullTitleLimit is set.
00603      */
00604     public static function getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit = 0) {
00605         if (!$titleLimit) {
00606             $titleLimit = 1000;
00607         }
00608 
00609         $loopCheck = 100;
00610         $output = $fullOutput = '/';
00611 
00612         $clause = trim($clause);
00613         if ($clause !== '' && substr($clause, 0, 3) !== 'AND') {
00614             $clause = 'AND ' . $clause;
00615         }
00616         $data = self::BEgetRootLine($uid, $clause);
00617 
00618         foreach ($data as $record) {
00619             if ($record['uid'] === 0) {
00620                 continue;
00621             }
00622             if ($record['_ORIG_pid'] && $record['t3ver_swapmode'] > 0) { // Branch points
00623                 $output = ' [#VEP#]' . $output; // Adding visual token - Versioning Entry Point - that tells that THIS position was where the versionized branch got connected to the main tree. I will have to find a better name or something...
00624             }
00625             $output = '/' . t3lib_div::fixed_lgd_cs(strip_tags($record['title']), $titleLimit) . $output;
00626             if ($fullTitleLimit) {
00627                 $fullOutput = '/' . t3lib_div::fixed_lgd_cs(strip_tags($record['title']), $fullTitleLimit) . $fullOutput;
00628             }
00629         }
00630 
00631         if ($fullTitleLimit) {
00632             return array($output, $fullOutput);
00633         } else {
00634             return $output;
00635         }
00636     }
00637 
00638     /**
00639      * Returns an array with the exclude-fields as defined in TCA and FlexForms
00640      * Used for listing the exclude-fields in be_groups forms
00641      * Usage: 2 (t3lib_tceforms + t3lib_transferdata)
00642      *
00643      * @return  array       Array of arrays with excludeFields (fieldname, table:fieldname) from all TCA entries and from FlexForms (fieldname, table:extkey;sheetname;fieldname)
00644      */
00645     public static function getExcludeFields() {
00646         global $TCA;
00647             // All TCA keys:
00648         $theExcludeArray = Array();
00649         $tc_keys = array_keys($TCA);
00650         foreach ($tc_keys as $table) {
00651                 // Load table
00652             t3lib_div::loadTCA($table);
00653                 // All field names configured:
00654             if (is_array($TCA[$table]['columns'])) {
00655                 $f_keys = array_keys($TCA[$table]['columns']);
00656                 foreach ($f_keys as $field) {
00657                     if ($TCA[$table]['columns'][$field]['exclude']) {
00658                             // Get Human Readable names of fields and table:
00659                         $Fname = $GLOBALS['LANG']->sl($TCA[$table]['ctrl']['title']) . ': ' . $GLOBALS['LANG']->sl($TCA[$table]['columns'][$field]['label']);
00660                             // add entry:
00661                         $theExcludeArray[] = Array($Fname, $table . ':' . $field);
00662                     }
00663                 }
00664             }
00665         }
00666             // All FlexForm fields
00667         $table = (!empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['contentTable']) ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['contentTable'] : 'tt_content');
00668         $flexFormArray = self::getRegisteredFlexForms($table);
00669         foreach ($flexFormArray as $tableField => $flexForms) {
00670                 // Prefix for field label, e.g. "Plugin Options:"
00671             $labelPrefix = '';
00672             if (!empty($GLOBALS['TCA'][$table]['columns'][$tableField]['label'])) {
00673                 $labelPrefix = $GLOBALS['LANG']->sl($GLOBALS['TCA'][$table]['columns'][$tableField]['label']);
00674             }
00675                 // Get all sheets and title
00676             foreach ($flexForms as $extIdent => $extConf) {
00677                 $extTitle = $GLOBALS['LANG']->sl($extConf['title']);
00678                     // Get all fields in sheet
00679                 foreach ($extConf['ds']['sheets'] as $sheetName => $sheet) {
00680                     if (empty($sheet['ROOT']['el']) || !is_array($sheet['ROOT']['el'])) {
00681                         continue;
00682                     }
00683                     foreach ($sheet['ROOT']['el'] as $fieldName => $field) {
00684                             // Use only excludeable fields
00685                         if (empty($field['TCEforms']['exclude'])) {
00686                             continue;
00687                         }
00688                         $fieldLabel = (!empty($field['TCEforms']['label']) ? $GLOBALS['LANG']->sl($field['TCEforms']['label']) : $fieldName);
00689                         $fieldIdent = $table . ':' . $tableField . ';' . $extIdent . ';' . $sheetName . ';' . $fieldName;
00690                         $theExcludeArray[] = array(trim($labelPrefix . ' ' . $extTitle, ': ') . ': ' . $fieldLabel, $fieldIdent);
00691                     }
00692                 }
00693             }
00694         }
00695 
00696             // Sort fields by label
00697         usort($theExcludeArray, array(t3lib_TCEforms_Flexforms, 'compareArraysByFirstValue'));
00698 
00699         return $theExcludeArray;
00700     }
00701 
00702     /**
00703      * Returns an array with explicit Allow/Deny fields.
00704      * Used for listing these field/value pairs in be_groups forms
00705      *
00706      * @return  array       Array with information from all of $TCA
00707      */
00708     public static function getExplicitAuthFieldValues() {
00709         global $TCA;
00710 
00711             // Initialize:
00712         $adLabel = array(
00713             'ALLOW' => $GLOBALS['LANG']->sl('LLL:EXT:lang/locallang_core.xml:labels.allow'),
00714             'DENY' => $GLOBALS['LANG']->sl('LLL:EXT:lang/locallang_core.xml:labels.deny'),
00715         );
00716 
00717             // All TCA keys:
00718         $allowDenyOptions = Array();
00719         $tc_keys = array_keys($TCA);
00720         foreach ($tc_keys as $table) {
00721 
00722                 // Load table
00723             t3lib_div::loadTCA($table);
00724 
00725                 // All field names configured:
00726             if (is_array($TCA[$table]['columns'])) {
00727                 $f_keys = array_keys($TCA[$table]['columns']);
00728                 foreach ($f_keys as $field) {
00729                     $fCfg = $TCA[$table]['columns'][$field]['config'];
00730                     if ($fCfg['type'] == 'select' && $fCfg['authMode']) {
00731 
00732                             // Check for items:
00733                         if (is_array($fCfg['items'])) {
00734                                 // Get Human Readable names of fields and table:
00735                             $allowDenyOptions[$table . ':' . $field]['tableFieldLabel'] = $GLOBALS['LANG']->sl($TCA[$table]['ctrl']['title']) . ': ' . $GLOBALS['LANG']->sl($TCA[$table]['columns'][$field]['label']);
00736 
00737                                 // Check for items:
00738                             foreach ($fCfg['items'] as $iVal) {
00739                                 if (strcmp($iVal[1], '')) { // Values '' is not controlled by this setting.
00740 
00741                                         // Find iMode:
00742                                     $iMode = '';
00743                                     switch ((string) $fCfg['authMode']) {
00744                                         case 'explicitAllow':
00745                                             $iMode = 'ALLOW';
00746                                             break;
00747                                         case 'explicitDeny':
00748                                             $iMode = 'DENY';
00749                                             break;
00750                                         case 'individual':
00751                                             if (!strcmp($iVal[4], 'EXPL_ALLOW')) {
00752                                                 $iMode = 'ALLOW';
00753                                             } elseif (!strcmp($iVal[4], 'EXPL_DENY')) {
00754                                                 $iMode = 'DENY';
00755                                             }
00756                                             break;
00757                                     }
00758 
00759                                         // Set iMode:
00760                                     if ($iMode) {
00761                                         $allowDenyOptions[$table . ':' . $field]['items'][$iVal[1]] = array($iMode, $GLOBALS['LANG']->sl($iVal[0]), $adLabel[$iMode]);
00762                                     }
00763                                 }
00764                             }
00765                         }
00766                     }
00767                 }
00768             }
00769         }
00770 
00771         return $allowDenyOptions;
00772     }
00773 
00774     /**
00775      * Returns an array with system languages:
00776      *
00777      * Since TYPO3 4.5 the flagIcon is not returned as a filename in "gfx/flags/*" anymore,
00778      * but as a string <flags-xx>. The calling party should call
00779      * t3lib_iconWorks::getSpriteIcon(<flags-xx>) to get an HTML which will represent
00780      * the flag of this language.
00781      *
00782      * @return  array       Array with languages (title, uid, flagIcon)
00783      */
00784     public static function getSystemLanguages() {
00785         $languages = t3lib_div::makeInstance('t3lib_transl8tools')->getSystemLanguages();
00786         $sysLanguages = array();
00787         foreach ($languages as $language) {
00788             if ($language['uid'] !== -1) {
00789                 $sysLanguages[] = array(
00790                     0 => htmlspecialchars($language['title']) . ' [' . $language['uid'] . ']',
00791                     1 => $language['uid'],
00792                     2 => $language['flagIcon']
00793                 );
00794             }
00795         }
00796 
00797         return $sysLanguages;
00798     }
00799 
00800     /**
00801      * Determines whether a table is localizable and has the languageField and transOrigPointerField set in $TCA.
00802      *
00803      * @param   string      $table: The table to check
00804      * @return  boolean     Whether a table is localizable
00805      */
00806     public static function isTableLocalizable($table) {
00807         $isLocalizable = FALSE;
00808         if (isset($GLOBALS['TCA'][$table]['ctrl']) && is_array($GLOBALS['TCA'][$table]['ctrl'])) {
00809             $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl'];
00810             $isLocalizable = (isset($tcaCtrl['languageField']) && $tcaCtrl['languageField'] && isset($tcaCtrl['transOrigPointerField']) && $tcaCtrl['transOrigPointerField']);
00811         }
00812         return $isLocalizable;
00813     }
00814 
00815     /**
00816      * Returns the value of the property localizationMode in the given $config array ($TCA[<table>]['columns'][<field>]['config']).
00817      * If the table is prepared for localization and no localizationMode is set, 'select' is returned by default.
00818      * If the table is not prepared for localization or not defined at all in $TCA, false is returned.
00819      *
00820      * @param   string      $table: The name of the table to lookup in TCA
00821      * @param   mixed       $fieldOrConfig: The fieldname (string) or the configuration of the field to check (array)
00822      * @return  mixed       If table is localizable, the set localizationMode is returned (if property is not set, 'select' is returned by default); if table is not localizable, false is returned
00823      */
00824     public static function getInlineLocalizationMode($table, $fieldOrConfig) {
00825         $localizationMode = FALSE;
00826         if (is_array($fieldOrConfig) && count($fieldOrConfig)) {
00827             $config = $fieldOrConfig;
00828         } elseif (is_string($fieldOrConfig) && isset($GLOBALS['TCA'][$table]['columns'][$fieldOrConfig]['config'])) {
00829             $config = $GLOBALS['TCA'][$table]['columns'][$fieldOrConfig]['config'];
00830         }
00831         if (is_array($config) && isset($config['type']) && $config['type'] == 'inline' && self::isTableLocalizable($table)) {
00832             $localizationMode = (isset($config['behaviour']['localizationMode']) && $config['behaviour']['localizationMode'] ? $config['behaviour']['localizationMode'] : 'select');
00833                 // The mode 'select' is not possible when child table is not localizable at all:
00834             if ($localizationMode == 'select' && !self::isTableLocalizable($config['foreign_table'])) {
00835                 $localizationMode = FALSE;
00836             }
00837         }
00838         return $localizationMode;
00839     }
00840 
00841     /**
00842      * Returns a page record (of page with $id) with an extra field "_thePath" set to the record path IF the WHERE clause, $perms_clause, selects the record. Thus is works as an access check that returns a page record if access was granted, otherwise not.
00843      * If $id is zero a pseudo root-page with "_thePath" set is returned IF the current BE_USER is admin.
00844      * In any case ->isInWebMount must return true for the user (regardless of $perms_clause)
00845      * Usage: 21
00846      *
00847      * @param   integer     Page uid for which to check read-access
00848      * @param   string      $perms_clause is typically a value generated with $BE_USER->getPagePermsClause(1);
00849      * @return  array       Returns page record if OK, otherwise false.
00850      */
00851     public static function readPageAccess($id, $perms_clause) {
00852         if ((string) $id != '') {
00853             $id = intval($id);
00854             if (!$id) {
00855                 if ($GLOBALS['BE_USER']->isAdmin()) {
00856                     $path = '/';
00857                     $pageinfo['_thePath'] = $path;
00858                     return $pageinfo;
00859                 }
00860             } else {
00861                 $pageinfo = self::getRecord('pages', $id, '*', ($perms_clause ? ' AND ' . $perms_clause : ''));
00862                 if ($pageinfo['uid'] && $GLOBALS['BE_USER']->isInWebMount($id, $perms_clause)) {
00863                     self::workspaceOL('pages', $pageinfo);
00864                     if (is_array($pageinfo)) {
00865                         self::fixVersioningPid('pages', $pageinfo);
00866                         list($pageinfo['_thePath'], $pageinfo['_thePathFull']) = self::getRecordPath(intval($pageinfo['uid']), $perms_clause, 15, 1000);
00867                         return $pageinfo;
00868                     }
00869                 }
00870             }
00871         }
00872         return FALSE;
00873     }
00874 
00875     /**
00876      * Returns the "types" configuration parsed into an array for the record, $rec, from table, $table
00877      * Usage: 6
00878      *
00879      * @param   string      Table name (present in TCA)
00880      * @param   array       Record from $table
00881      * @param   boolean     If $useFieldNameAsKey is set, then the fieldname is associative keys in the return array, otherwise just numeric keys.
00882      * @return  array
00883      */
00884     public static function getTCAtypes($table, $rec, $useFieldNameAsKey = 0) {
00885         global $TCA;
00886 
00887         t3lib_div::loadTCA($table);
00888         if ($TCA[$table]) {
00889 
00890                 // Get type value:
00891             $fieldValue = self::getTCAtypeValue($table, $rec);
00892 
00893                 // Get typesConf
00894             $typesConf = $TCA[$table]['types'][$fieldValue];
00895 
00896                 // Get fields list and traverse it
00897             $fieldList = explode(',', $typesConf['showitem']);
00898             $altFieldList = array();
00899 
00900                 // Traverse fields in types config and parse the configuration into a nice array:
00901             foreach ($fieldList as $k => $v) {
00902                 list($pFieldName, $pAltTitle, $pPalette, $pSpec) = t3lib_div::trimExplode(';', $v);
00903                 $defaultExtras = is_array($TCA[$table]['columns'][$pFieldName]) ? $TCA[$table]['columns'][$pFieldName]['defaultExtras'] : '';
00904                 $specConfParts = self::getSpecConfParts($pSpec, $defaultExtras);
00905 
00906                 $fieldList[$k] = array(
00907                     'field' => $pFieldName,
00908                     'title' => $pAltTitle,
00909                     'palette' => $pPalette,
00910                     'spec' => $specConfParts,
00911                     'origString' => $v
00912                 );
00913                 if ($useFieldNameAsKey) {
00914                     $altFieldList[$fieldList[$k]['field']] = $fieldList[$k];
00915                 }
00916             }
00917             if ($useFieldNameAsKey) {
00918                 $fieldList = $altFieldList;
00919             }
00920 
00921                 // Return array:
00922             return $fieldList;
00923         }
00924     }
00925 
00926     /**
00927      * Returns the "type" value of $rec from $table which can be used to look up the correct "types" rendering section in $TCA
00928      * If no "type" field is configured in the "ctrl"-section of the $TCA for the table, zero is used.
00929      * If zero is not an index in the "types" section of $TCA for the table, then the $fieldValue returned will default to 1 (no matter if that is an index or not)
00930      * Usage: 7
00931      *
00932      * @param   string      Table name present in TCA
00933      * @param   array       Record from $table
00934      * @return  string      Field value
00935      * @see getTCAtypes()
00936      */
00937     public static function getTCAtypeValue($table, $rec) {
00938         global $TCA;
00939 
00940             // If no field-value, set it to zero. If there is no type matching the field-value (which now may be zero...) test field-value '1' as default.
00941         t3lib_div::loadTCA($table);
00942         if ($TCA[$table]) {
00943             $field = $TCA[$table]['ctrl']['type'];
00944             $fieldValue = $field ? ($rec[$field] ? $rec[$field] : 0) : 0;
00945             if (!is_array($TCA[$table]['types'][$fieldValue])) {
00946                 $fieldValue = 1;
00947             }
00948             return $fieldValue;
00949         }
00950     }
00951 
00952     /**
00953      * Parses a part of the field lists in the "types"-section of $TCA arrays, namely the "special configuration" at index 3 (position 4)
00954      * Elements are splitted by ":" and within those parts, parameters are splitted by "|".
00955      * Everything is returned in an array and you should rather see it visually than listen to me anymore now...  Check out example in Inside TYPO3
00956      * Usage: 5
00957      *
00958      * @param   string      Content from the "types" configuration of TCA (the special configuration) - see description of function
00959      * @param   string      The ['defaultExtras'] value from field configuration
00960      * @return  array
00961      */
00962     public static function getSpecConfParts($str, $defaultExtras) {
00963 
00964             // Add defaultExtras:
00965         $specConfParts = t3lib_div::trimExplode(':', $defaultExtras . ':' . $str, 1);
00966 
00967         $reg = array();
00968         if (count($specConfParts)) {
00969             foreach ($specConfParts as $k2 => $v2) {
00970                 unset($specConfParts[$k2]);
00971                 if (preg_match('/(.*)\[(.*)\]/', $v2, $reg)) {
00972                     $specConfParts[trim($reg[1])] = array(
00973                         'parameters' => t3lib_div::trimExplode('|', $reg[2], 1)
00974                     );
00975                 } else {
00976                     $specConfParts[trim($v2)] = 1;
00977                 }
00978             }
00979         } else {
00980             $specConfParts = array();
00981         }
00982         return $specConfParts;
00983     }
00984 
00985     /**
00986      * Takes an array of "[key] = [value]" strings and returns an array with the keys set as keys pointing to the value.
00987      * Better see it in action! Find example in Inside TYPO3
00988      * Usage: 6
00989      *
00990      * @param   array       Array of "[key] = [value]" strings to convert.
00991      * @return  array
00992      */
00993     public static function getSpecConfParametersFromArray($pArr) {
00994         $out = array();
00995         if (is_array($pArr)) {
00996             foreach ($pArr as $k => $v) {
00997                 $parts = explode('=', $v, 2);
00998                 if (count($parts) == 2) {
00999                     $out[trim($parts[0])] = trim($parts[1]);
01000                 } else {
01001                     $out[$k] = $v;
01002                 }
01003             }
01004         }
01005         return $out;
01006     }
01007 
01008     /**
01009      * Finds the Data Structure for a FlexForm field
01010      * NOTE ON data structures for deleted records: This function may fail to deliver the data structure for a record for a few reasons: a) The data structure could be deleted (either with deleted-flagged or hard-deleted), b) the data structure is fetched using the ds_pointerField_searchParent in which case any deleted record on the route to the final location of the DS will make it fail. In theory, we can solve the problem in the case where records that are deleted-flagged keeps us from finding the DS - this is done at the markers ###NOTE_A### where we make sure to also select deleted records. However, we generally want the DS lookup to fail for deleted records since for the working website we expect a deleted-flagged record to be as inaccessible as one that is completely deleted from the DB. Any way we look at it, this may lead to integrity problems of the reference index and even lost files if attached. However, that is not really important considering that a single change to a data structure can instantly invalidate large amounts of the reference index which we do accept as a cost for the flexform features. Other than requiring a reference index update, deletion of/changes in data structure or the failure to look them up when completely deleting records may lead to lost files in the uploads/ folders since those are now without a proper reference.
01011      * Usage: 5
01012      *
01013      * @param   array       Field config array
01014      * @param   array       Record data
01015      * @param   string      The table name
01016      * @param   string      Optional fieldname passed to hook object
01017      * @param   boolean     Boolean; If set, workspace overlay is applied to records. This is correct behaviour for all presentation and export, but NOT if you want a true reflection of how things are in the live workspace.
01018      * @param   integer     SPECIAL CASES: Use this, if the DataStructure may come from a parent record and the INPUT row doesn't have a uid yet (hence, the pid cannot be looked up). Then it is necessary to supply a PID value to search recursively in for the DS (used from TCEmain)
01019      * @return  mixed       If array, the data structure was found and returned as an array. Otherwise (string) it is an error message.
01020      * @see t3lib_TCEforms::getSingleField_typeFlex()
01021      */
01022     public static function getFlexFormDS($conf, $row, $table, $fieldName = '', $WSOL = TRUE, $newRecordPidValue = 0) {
01023         global $TYPO3_CONF_VARS;
01024 
01025             // Get pointer field etc from TCA-config:
01026         $ds_pointerField = $conf['ds_pointerField'];
01027         $ds_array = $conf['ds'];
01028         $ds_tableField = $conf['ds_tableField'];
01029         $ds_searchParentField = $conf['ds_pointerField_searchParent'];
01030 
01031             // Find source value:
01032         $dataStructArray = '';
01033         if (is_array($ds_array)) { // If there is a data source array, that takes precedence
01034                 // If a pointer field is set, take the value from that field in the $row array and use as key.
01035             if ($ds_pointerField) {
01036 
01037                     // Up to two pointer fields can be specified in a comma separated list.
01038                 $pointerFields = t3lib_div::trimExplode(',', $ds_pointerField);
01039                 if (count($pointerFields) == 2) { // If we have two pointer fields, the array keys should contain both field values separated by comma. The asterisk "*" catches all values. For backwards compatibility, it's also possible to specify only the value of the first defined ds_pointerField.
01040                     if ($ds_array[$row[$pointerFields[0]] . ',' . $row[$pointerFields[1]]]) { // Check if we have a DS for the combination of both pointer fields values
01041                         $srcPointer = $row[$pointerFields[0]] . ',' . $row[$pointerFields[1]];
01042                     } elseif ($ds_array[$row[$pointerFields[1]] . ',*']) { // Check if we have a DS for the value of the first pointer field suffixed with ",*"
01043                         $srcPointer = $row[$pointerFields[1]] . ',*';
01044                     } elseif ($ds_array['*,' . $row[$pointerFields[1]]]) { // Check if we have a DS for the value of the second pointer field prefixed with "*,"
01045                         $srcPointer = '*,' . $row[$pointerFields[1]];
01046                     } elseif ($ds_array[$row[$pointerFields[0]]]) { // Check if we have a DS for just the value of the first pointer field (mainly for backwards compatibility)
01047                         $srcPointer = $row[$pointerFields[0]];
01048                     }
01049                 } else {
01050                     $srcPointer = $row[$pointerFields[0]];
01051                 }
01052 
01053                 $srcPointer = isset($ds_array[$srcPointer]) ? $srcPointer : 'default';
01054             } else {
01055                 $srcPointer = 'default';
01056             }
01057 
01058                 // Get Data Source: Detect if it's a file reference and in that case read the file and parse as XML. Otherwise the value is expected to be XML.
01059             if (substr($ds_array[$srcPointer], 0, 5) == 'FILE:') {
01060                 $file = t3lib_div::getFileAbsFileName(substr($ds_array[$srcPointer], 5));
01061                 if ($file && @is_file($file)) {
01062                     $dataStructArray = t3lib_div::xml2array(t3lib_div::getUrl($file));
01063                 } else {
01064                     $dataStructArray = 'The file "' . substr($ds_array[$srcPointer], 5) . '" in ds-array key "' . $srcPointer . '" was not found ("' . $file . '")';
01065                 } // Error message.
01066             } else {
01067                 $dataStructArray = t3lib_div::xml2array($ds_array[$srcPointer]);
01068             }
01069 
01070         } elseif ($ds_pointerField) { // If pointer field AND possibly a table/field is set:
01071                 // Value of field pointed to:
01072             $srcPointer = $row[$ds_pointerField];
01073 
01074                 // Searching recursively back if 'ds_pointerField_searchParent' is defined (typ. a page rootline, or maybe a tree-table):
01075             if ($ds_searchParentField && !$srcPointer) {
01076                 $rr = self::getRecord($table, $row['uid'], 'uid,' . $ds_searchParentField); // Get the "pid" field - we cannot know that it is in the input record! ###NOTE_A###
01077                 if ($WSOL) {
01078                     self::workspaceOL($table, $rr);
01079                     self::fixVersioningPid($table, $rr, TRUE); // Added "TRUE" 23/03/06 before 4.0. (Also to similar call below!).  Reason: When t3lib_refindex is scanning the system in Live workspace all Pages with FlexForms will not find their inherited datastructure. Thus all references from workspaces are removed! Setting TRUE means that versioning PID doesn't check workspace of the record. I can't see that this should give problems anywhere. See more information inside t3lib_refindex!
01080                 }
01081                 $uidAcc = array(); // Used to avoid looping, if any should happen.
01082                 $subFieldPointer = $conf['ds_pointerField_searchParent_subField'];
01083                 while (!$srcPointer) {
01084 
01085                     $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
01086                         'uid,' . $ds_pointerField . ',' . $ds_searchParentField . ($subFieldPointer ? ',' . $subFieldPointer : ''),
01087                         $table,
01088                             'uid=' . intval($newRecordPidValue ? $newRecordPidValue : $rr[$ds_searchParentField]) . self::deleteClause($table) ###NOTE_A###
01089                     );
01090                     $newRecordPidValue = 0;
01091                     $rr = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
01092                     $GLOBALS['TYPO3_DB']->sql_free_result($res);
01093 
01094                         // break if no result from SQL db or if looping...
01095                     if (!is_array($rr) || isset($uidAcc[$rr['uid']])) {
01096                         break;
01097                     }
01098                     $uidAcc[$rr['uid']] = 1;
01099 
01100                     if ($WSOL) {
01101                         self::workspaceOL($table, $rr);
01102                         self::fixVersioningPid($table, $rr, TRUE);
01103                     }
01104                     $srcPointer = ($subFieldPointer && $rr[$subFieldPointer]) ? $rr[$subFieldPointer] : $rr[$ds_pointerField];
01105                 }
01106             }
01107 
01108                 // If there is a srcPointer value:
01109             if ($srcPointer) {
01110                 if (t3lib_div::testInt($srcPointer)) { // If integer, then its a record we will look up:
01111                     list($tName, $fName) = explode(':', $ds_tableField, 2);
01112                     if ($tName && $fName && is_array($GLOBALS['TCA'][$tName])) {
01113                         $dataStructRec = self::getRecord($tName, $srcPointer);
01114                         if ($WSOL) {
01115                             self::workspaceOL($tName, $dataStructRec);
01116                         }
01117                         $dataStructArray = t3lib_div::xml2array($dataStructRec[$fName]);
01118                     } else {
01119                         $dataStructArray = 'No tablename (' . $tName . ') or fieldname (' . $fName . ') was found an valid!';
01120                     }
01121                 } else { // Otherwise expect it to be a file:
01122                     $file = t3lib_div::getFileAbsFileName($srcPointer);
01123                     if ($file && @is_file($file)) {
01124                         $dataStructArray = t3lib_div::xml2array(t3lib_div::getUrl($file));
01125                     } else {
01126                         $dataStructArray = 'The file "' . $srcPointer . '" was not found ("' . $file . '")';
01127                     } // Error message.
01128                 }
01129             } else {
01130                 $dataStructArray = 'No source value in fieldname "' . $ds_pointerField . '"';
01131             } // Error message.
01132         } else {
01133             $dataStructArray = 'No proper configuration!';
01134         }
01135 
01136             // Hook for post-processing the Flexform DS. Introduces the possibility to configure Flexforms via TSConfig
01137         if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['getFlexFormDSClass'])) {
01138             foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['getFlexFormDSClass'] as $classRef) {
01139                 $hookObj = t3lib_div::getUserObj($classRef);
01140                 if (method_exists($hookObj, 'getFlexFormDS_postProcessDS')) {
01141                     $hookObj->getFlexFormDS_postProcessDS($dataStructArray, $conf, $row, $table, $fieldName);
01142                 }
01143             }
01144         }
01145 
01146         return $dataStructArray;
01147     }
01148 
01149     /**
01150      * Returns all registered FlexForm definitions with title and fields
01151      * Usage: 1
01152      *
01153      * @param   string      The content table
01154      * @return  array       The data structures with speaking extension title
01155      * @see t3lib_BEfunc::getExcludeFields()
01156      */
01157     public static function getRegisteredFlexForms($table = 'tt_content') {
01158         if (empty($table) || empty($GLOBALS['TCA'][$table]['columns'])) {
01159             return array();
01160         }
01161 
01162 
01163         $flexForms = array();
01164 
01165         foreach ($GLOBALS['TCA'][$table]['columns'] as $tableField => $fieldConf) {
01166             if (!empty($fieldConf['config']['type']) && !empty($fieldConf['config']['ds']) && $fieldConf['config']['type'] == 'flex') {
01167                 $flexForms[$tableField] = array();
01168 
01169                 unset($fieldConf['config']['ds']['default']);
01170 
01171                     // Get pointer fields
01172                 $pointerFields = (!empty($fieldConf['config']['ds_pointerField']) ? $fieldConf['config']['ds_pointerField'] : 'list_type,CType');
01173                 $pointerFields = t3lib_div::trimExplode(',', $pointerFields);
01174 
01175                     // Get FlexForms
01176                 foreach ($fieldConf['config']['ds'] as $flexFormKey => $dataStruct) {
01177                         // Get extension identifier (uses second value if it's not empty, "list" or "*", else first one)
01178                     $identFields = t3lib_div::trimExplode(',', $flexFormKey);
01179                     $extIdent = $identFields[0];
01180                     if (!empty($identFields[1]) && $identFields[1] != 'list' && $identFields[1] != '*') {
01181                         $extIdent = $identFields[1];
01182                     }
01183 
01184                         // Load external file references
01185                     if (!is_array($dataStruct)) {
01186                         $file = t3lib_div::getFileAbsFileName(str_ireplace('FILE:', '', $dataStruct));
01187                         if ($file && @is_file($file)) {
01188                             $dataStruct = t3lib_div::getUrl($file);
01189                         }
01190                         $dataStruct = t3lib_div::xml2array($dataStruct);
01191                         if (!is_array($dataStruct)) {
01192                             continue;
01193                         }
01194                     }
01195                         // Get flexform content
01196                     $dataStruct = t3lib_div::resolveAllSheetsInDS($dataStruct);
01197                     if (empty($dataStruct['sheets']) || !is_array($dataStruct['sheets'])) {
01198                         continue;
01199                     }
01200 
01201                         // Use DS pointer to get extension title from TCA
01202                     $title = $extIdent;
01203                     $keyFields = t3lib_div::trimExplode(',', $flexFormKey);
01204                     foreach ($pointerFields as $pointerKey => $pointerName) {
01205                         if (empty($keyFields[$pointerKey]) || $keyFields[$pointerKey] == '*' || $keyFields[$pointerKey] == 'list') {
01206                             continue;
01207                         }
01208                         if (!empty($GLOBALS['TCA'][$table]['columns'][$pointerName]['config']['items'])) {
01209                             $items = $GLOBALS['TCA'][$table]['columns'][$pointerName]['config']['items'];
01210                             if (!is_array($items)) {
01211                                 continue;
01212                             }
01213                             foreach ($items as $itemConf) {
01214                                 if (!empty($itemConf[0]) && !empty($itemConf[1]) && $itemConf[1] == $keyFields[$pointerKey]) {
01215                                     $title = $itemConf[0];
01216                                     break 2;
01217                                 }
01218                             }
01219                         }
01220                     }
01221 
01222                     $flexForms[$tableField][$extIdent] = array(
01223                         'title' => $title,
01224                         'ds' => $dataStruct,
01225                     );
01226                 }
01227             }
01228         }
01229 
01230         return $flexForms;
01231     }
01232 
01233 
01234     /*******************************************
01235      *
01236      * Caching related
01237      *
01238      *******************************************/
01239 
01240     /**
01241      * Stores the string value $data in the 'cache_hash' cache with the
01242      * hash key, $hash, and visual/symbolic identification, $ident
01243      * IDENTICAL to the function by same name found in t3lib_page:
01244      * Usage: 2
01245      *
01246      * @param   string      32 bit hash string (eg. a md5 hash of a serialized array identifying the data being stored)
01247      * @param   string      The data string. If you want to store an array, then just serialize it first.
01248      * @param   string      $ident is just a textual identification in order to inform about the content!
01249      * @return  void
01250      */
01251     public static function storeHash($hash, $data, $ident) {
01252         if (TYPO3_UseCachingFramework) {
01253             $GLOBALS['typo3CacheManager']->getCache('cache_hash')->set(
01254                 $hash,
01255                 $data,
01256                 array('ident_' . $ident),
01257                 0 // unlimited lifetime
01258             );
01259         } else {
01260             $insertFields = array(
01261                 'hash' => $hash,
01262                 'content' => $data,
01263                 'ident' => $ident,
01264                 'tstamp' => $GLOBALS['EXEC_TIME']
01265             );
01266             $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_hash', 'hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($hash, 'cache_hash'));
01267             $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_hash', $insertFields);
01268         }
01269     }
01270 
01271     /**
01272      * Returns string value stored for the hash string in the cache "cache_hash"
01273      * Can be used to retrieved a cached value
01274      *
01275      * IDENTICAL to the function by same name found in t3lib_page
01276      *
01277      * @param   string      The hash-string which was used to store the data value
01278      * @return  string
01279      */
01280     public static function getHash($hash, $expTime = 0) {
01281         $hashContent = NULL;
01282         if (TYPO3_UseCachingFramework) {
01283             $contentHashCache = $GLOBALS['typo3CacheManager']->getCache('cache_hash');
01284             $cacheEntry = $contentHashCache->get($hash);
01285 
01286             if ($cacheEntry) {
01287                 $hashContent = $cacheEntry;
01288             }
01289         } else {
01290             $expTime = intval($expTime);
01291             if ($expTime) {
01292                 $whereAdd = ' AND tstamp > ' . (time() - $expTime);
01293             }
01294             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('content', 'cache_hash', 'hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($hash, 'cache_hash') . $whereAdd);
01295             $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
01296             $GLOBALS['TYPO3_DB']->sql_free_result($res);
01297 
01298             $hashContent = (is_array($row) ? $row['content'] : NULL);
01299         }
01300         return $hashContent;
01301     }
01302 
01303 
01304     /*******************************************
01305      *
01306      * TypoScript related
01307      *
01308      *******************************************/
01309 
01310     /**
01311      * Returns the Page TSconfig for page with id, $id
01312      * Requires class "t3lib_TSparser"
01313      * Usage: 26 (spec. in ext info_pagetsconfig)
01314      *
01315      * @param   integer     Page uid for which to create Page TSconfig
01316      * @param   array       If $rootLine is an array, that is used as rootline, otherwise rootline is just calculated
01317      * @param   boolean     If $returnPartArray is set, then the array with accumulated Page TSconfig is returned non-parsed. Otherwise the output will be parsed by the TypoScript parser.
01318      * @return  array       Page TSconfig
01319      * @see t3lib_TSparser
01320      */
01321     public static function getPagesTSconfig($id, $rootLine = '', $returnPartArray = 0) {
01322         $id = intval($id);
01323         if (!is_array($rootLine)) {
01324             $rootLine = self::BEgetRootLine($id, '', TRUE);
01325         }
01326         ksort($rootLine); // Order correctly
01327         $TSdataArray = array();
01328         $TSdataArray['defaultPageTSconfig'] = $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPageTSconfig']; // Setting default configuration:
01329         foreach ($rootLine as $k => $v) {
01330             $TSdataArray['uid_' . $v['uid']] = $v['TSconfig'];
01331         }
01332         $TSdataArray = t3lib_TSparser::checkIncludeLines_array($TSdataArray);
01333         if ($returnPartArray) {
01334             return $TSdataArray;
01335         }
01336 
01337             // Parsing the page TS-Config (or getting from cache)
01338         $pageTS = implode(LF . '[GLOBAL]' . LF, $TSdataArray);
01339         if ($GLOBALS['TYPO3_CONF_VARS']['BE']['TSconfigConditions']) {
01340             /* @var $parseObj t3lib_TSparser_TSconfig */
01341             $parseObj = t3lib_div::makeInstance('t3lib_TSparser_TSconfig');
01342             $res = $parseObj->parseTSconfig($pageTS, 'PAGES', $id, $rootLine);
01343             if ($res) {
01344                 $TSconfig = $res['TSconfig'];
01345             }
01346         } else {
01347             $hash = md5('pageTS:' . $pageTS);
01348             $cachedContent = self::getHash($hash);
01349             $TSconfig = array();
01350             if (isset($cachedContent)) {
01351                 $TSconfig = unserialize($cachedContent);
01352             } else {
01353                 $parseObj = t3lib_div::makeInstance('t3lib_TSparser');
01354                 $parseObj->parse($pageTS);
01355                 $TSconfig = $parseObj->setup;
01356                 self::storeHash($hash, serialize($TSconfig), 'PAGES_TSconfig');
01357             }
01358         }
01359 
01360             // get User TSconfig overlay
01361         $userTSconfig = $GLOBALS['BE_USER']->userTS['page.'];
01362         if (is_array($userTSconfig)) {
01363             $TSconfig = t3lib_div::array_merge_recursive_overrule($TSconfig, $userTSconfig);
01364         }
01365         return $TSconfig;
01366     }
01367 
01368     /**
01369      * Updates Page TSconfig for a page with $id
01370      * The function seems to take $pageTS as an array with properties and compare the values with those that already exists for the "object string", $TSconfPrefix, for the page, then sets those values which were not present.
01371      * $impParams can be supplied as already known Page TSconfig, otherwise it's calculated.
01372      *
01373      * THIS DOES NOT CHECK ANY PERMISSIONS. SHOULD IT?
01374      * More documentation is needed.
01375      *
01376      * Usage: 1 (ext. direct_mail)
01377      *
01378      * @param   integer     Page id
01379      * @param   array       Page TS array to write
01380      * @param   string      Prefix for object paths
01381      * @param   array       [Description needed.]
01382      * @return  void
01383      * @internal
01384      * @see implodeTSParams(), getPagesTSconfig()
01385      */
01386     public static function updatePagesTSconfig($id, $pageTS, $TSconfPrefix, $impParams = '') {
01387         $id = intval($id);
01388         if (is_array($pageTS) && $id > 0) {
01389             if (!is_array($impParams)) {
01390                 $impParams = self::implodeTSParams(self::getPagesTSconfig($id));
01391             }
01392             $set = array();
01393             foreach ($pageTS as $f => $v) {
01394                 $f = $TSconfPrefix . $f;
01395                 if ((!isset($impParams[$f]) && trim($v)) || strcmp(trim($impParams[$f]), trim($v))) {
01396                     $set[$f] = trim($v);
01397                 }
01398             }
01399             if (count($set)) {
01400                     // Get page record and TS config lines
01401                 $pRec = self::getRecord('pages', $id);
01402                 $TSlines = explode(LF, $pRec['TSconfig']);
01403                 $TSlines = array_reverse($TSlines);
01404                     // Reset the set of changes.
01405                 foreach ($set as $f => $v) {
01406                     $inserted = 0;
01407                     foreach ($TSlines as $ki => $kv) {
01408                         if (substr($kv, 0, strlen($f) + 1) == $f . '=') {
01409                             $TSlines[$ki] = $f . '=' . $v;
01410                             $inserted = 1;
01411                             break;
01412                         }
01413                     }
01414                     if (!$inserted) {
01415                         $TSlines = array_reverse($TSlines);
01416                         $TSlines[] = $f . '=' . $v;
01417                         $TSlines = array_reverse($TSlines);
01418                     }
01419                 }
01420                 $TSlines = array_reverse($TSlines);
01421 
01422                     // store those changes
01423                 $TSconf = implode(LF, $TSlines);
01424 
01425                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery('pages', 'uid=' . intval($id), array('TSconfig' => $TSconf));
01426             }
01427         }
01428     }
01429 
01430     /**
01431      * Implodes a multi dimensional TypoScript array, $p, into a one-dimentional array (return value)
01432      * Usage: 3
01433      *
01434      * @param   array       TypoScript structure
01435      * @param   string      Prefix string
01436      * @return  array       Imploded TypoScript objectstring/values
01437      */
01438     public static function implodeTSParams($p, $k = '') {
01439         $implodeParams = array();
01440         if (is_array($p)) {
01441             foreach ($p as $kb => $val) {
01442                 if (is_array($val)) {
01443                     $implodeParams = array_merge($implodeParams, self::implodeTSParams($val, $k . $kb));
01444                 } else {
01445                     $implodeParams[$k . $kb] = $val;
01446                 }
01447             }
01448         }
01449         return $implodeParams;
01450     }
01451 
01452 
01453     /*******************************************
01454      *
01455      * Users / Groups related
01456      *
01457      *******************************************/
01458 
01459     /**
01460      * Returns an array with be_users records of all user NOT DELETED sorted by their username
01461      * Keys in the array is the be_users uid
01462      * Usage: 14 (spec. ext. "beuser" and module "web_perm")
01463      *
01464      * @param   string      Optional $fields list (default: username,usergroup,usergroup_cached_list,uid) can be used to set the selected fields
01465      * @param   string      Optional $where clause (fx. "AND username='pete'") can be used to limit query
01466      * @return  array
01467      */
01468     public static function getUserNames($fields = 'username,usergroup,usergroup_cached_list,uid', $where = '') {
01469         $be_user_Array = Array();
01470 
01471         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fields, 'be_users', 'pid=0 ' . $where . self::deleteClause('be_users'), '', 'username');
01472         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
01473             $be_user_Array[$row['uid']] = $row;
01474         }
01475         $GLOBALS['TYPO3_DB']->sql_free_result($res);
01476 
01477         return $be_user_Array;
01478     }
01479 
01480     /**
01481      * Returns an array with be_groups records (title, uid) of all groups NOT DELETED sorted by their title
01482      * Usage: 8 (spec. ext. "beuser" and module "web_perm")
01483      *
01484      * @param   string      Field list
01485      * @param   string      WHERE clause
01486      * @return  array
01487      */
01488     public static function getGroupNames($fields = 'title,uid', $where = '') {
01489         $be_group_Array = Array();
01490 
01491         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fields, 'be_groups', 'pid=0 ' . $where . self::deleteClause('be_groups'), '', 'title');
01492         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
01493             $be_group_Array[$row['uid']] = $row;
01494         }
01495         $GLOBALS['TYPO3_DB']->sql_free_result($res);
01496 
01497         return $be_group_Array;
01498     }
01499 
01500     /**
01501      * Returns an array with be_groups records (like ->getGroupNames) but:
01502      * - if the current BE_USER is admin, then all groups are returned, otherwise only groups that the current user is member of (usergroup_cached_list) will be returned.
01503      * Usage: 2 (module "web_perm" and ext. taskcenter)
01504      *
01505      * @param   string      Field list; $fields specify the fields selected (default: title,uid)
01506      * @return  array
01507      */
01508     public static function getListGroupNames($fields = 'title, uid') {
01509         $exQ = ' AND hide_in_lists=0';
01510         if (!$GLOBALS['BE_USER']->isAdmin()) {
01511             $exQ .= ' AND uid IN (' . ($GLOBALS['BE_USER']->user['usergroup_cached_list'] ? $GLOBALS['BE_USER']->user['usergroup_cached_list'] : 0) . ')';
01512         }
01513         return self::getGroupNames($fields, $exQ);
01514     }
01515 
01516     /**
01517      * Returns the array $usernames with the names of all users NOT IN $groupArray changed to the uid (hides the usernames!).
01518      * If $excludeBlindedFlag is set, then these records are unset from the array $usernames
01519      * Takes $usernames (array made by t3lib_BEfunc::getUserNames()) and a $groupArray (array with the groups a certain user is member of) as input
01520      * Usage: 8
01521      *
01522      * @param   array       User names
01523      * @param   array       Group names
01524      * @param   boolean     If $excludeBlindedFlag is set, then these records are unset from the array $usernames
01525      * @return  array       User names, blinded
01526      */
01527     public static function blindUserNames($usernames, $groupArray, $excludeBlindedFlag = 0) {
01528         if (is_array($usernames) && is_array($groupArray)) {
01529             foreach ($usernames as $uid => $row) {
01530                 $userN = $uid;
01531                 $set = 0;
01532                 if ($row['uid'] != $GLOBALS['BE_USER']->user['uid']) {
01533                     foreach ($groupArray as $v) {
01534                         if ($v && t3lib_div::inList($row['usergroup_cached_list'], $v)) {
01535                             $userN = $row['username'];
01536                             $set = 1;
01537                         }
01538                     }
01539                 } else {
01540                     $userN = $row['username'];
01541                     $set = 1;
01542                 }
01543                 $usernames[$uid]['username'] = $userN;
01544                 if ($excludeBlindedFlag && !$set) {
01545                     unset($usernames[$uid]);
01546                 }
01547             }
01548         }
01549         return $usernames;
01550     }
01551 
01552     /**
01553      * Corresponds to blindUserNames but works for groups instead
01554      * Usage: 2 (module web_perm)
01555      *
01556      * @param   array       Group names
01557      * @param   array       Group names (reference)
01558      * @param   boolean     If $excludeBlindedFlag is set, then these records are unset from the array $usernames
01559      * @return  array
01560      */
01561     public static function blindGroupNames($groups, $groupArray, $excludeBlindedFlag = 0) {
01562         if (is_array($groups) && is_array($groupArray)) {
01563             foreach ($groups as $uid => $row) {
01564                 $groupN = $uid;
01565                 $set = 0;
01566                 if (t3lib_div::inArray($groupArray, $uid)) {
01567                     $groupN = $row['title'];
01568                     $set = 1;
01569                 }
01570                 $groups[$uid]['title'] = $groupN;
01571                 if ($excludeBlindedFlag && !$set) {
01572                     unset($groups[$uid]);
01573                 }
01574             }
01575         }
01576         return $groups;
01577     }
01578 
01579 
01580     /*******************************************
01581      *
01582      * Output related
01583      *
01584      *******************************************/
01585 
01586     /**
01587      * Returns the difference in days between input $tstamp and $EXEC_TIME
01588      * Usage: 2 (class t3lib_BEfunc)
01589      *
01590      * @param   integer     Time stamp, seconds
01591      * @return  integer
01592      */
01593     public static function daysUntil($tstamp) {
01594         $delta_t = $tstamp - $GLOBALS['EXEC_TIME'];
01595         return ceil($delta_t / (3600 * 24));
01596     }
01597 
01598     /**
01599      * Returns $tstamp formatted as "ddmmyy" (According to $TYPO3_CONF_VARS['SYS']['ddmmyy'])
01600      * Usage: 11
01601      *
01602      * @param   integer     Time stamp, seconds
01603      * @return  string      Formatted time
01604      */
01605     public static function date($tstamp) {
01606         return date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], (int) $tstamp);
01607     }
01608 
01609     /**
01610      * Returns $tstamp formatted as "ddmmyy hhmm" (According to $TYPO3_CONF_VARS['SYS']['ddmmyy'] AND $TYPO3_CONF_VARS['SYS']['hhmm'])
01611      * Usage: 28
01612      *
01613      * @param   integer     Time stamp, seconds
01614      * @return  string      Formatted time
01615      */
01616     public static function datetime($value) {
01617         return date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $value);
01618     }
01619 
01620     /**
01621      * Returns $value (in seconds) formatted as hh:mm:ss
01622      * For instance $value = 3600 + 60*2 + 3 should return "01:02:03"
01623      * Usage: 1 (class t3lib_BEfunc)
01624      *
01625      * @param   integer     Time stamp, seconds
01626      * @param   boolean     Output hh:mm:ss. If false: hh:mm
01627      * @return  string      Formatted time
01628      */
01629     public static function time($value, $withSeconds = TRUE) {
01630         $hh = floor($value / 3600);
01631         $min = floor(($value - $hh * 3600) / 60);
01632         $sec = $value - $hh * 3600 - $min * 60;
01633         $l = sprintf('%02d', $hh) . ':' . sprintf('%02d', $min);
01634         if ($withSeconds) {
01635             $l .= ':' . sprintf('%02d', $sec);
01636         }
01637         return $l;
01638     }
01639 
01640     /**
01641      * Returns the "age" in minutes / hours / days / years of the number of $seconds inputted.
01642      * Usage: 15
01643      *
01644      * @param   integer     $seconds could be the difference of a certain timestamp and time()
01645      * @param   string      $labels should be something like ' min| hrs| days| yrs'. This value is typically delivered by this function call: $GLOBALS["LANG"]->sL("LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears")
01646      * @return  string      Formatted time
01647      */
01648     public static function calcAge($seconds, $labels = 'min|hrs|days|yrs') {
01649         $labelArr = explode('|', $labels);
01650         $prefix = '';
01651         if ($seconds < 0) {
01652             $prefix = '-';
01653             $seconds = abs($seconds);
01654         }
01655         if ($seconds < 3600) {
01656             $seconds = round($seconds / 60) . ' ' . trim($labelArr[0]);
01657         } elseif ($seconds < 24 * 3600) {
01658             $seconds = round($seconds / 3600) . ' ' . trim($labelArr[1]);
01659         } elseif ($seconds < 365 * 24 * 3600) {
01660             $seconds = round($seconds / (24 * 3600)) . ' ' . trim($labelArr[2]);
01661         } else {
01662             $seconds = round($seconds / (365 * 24 * 3600)) . ' ' . trim($labelArr[3]);
01663         }
01664         return $prefix . $seconds;
01665     }
01666 
01667     /**
01668      * Returns a formatted timestamp if $tstamp is set.
01669      * The date/datetime will be followed by the age in parenthesis.
01670      * Usage: 3
01671      *
01672      * @param   integer     Time stamp, seconds
01673      * @param   integer     1/-1 depending on polarity of age.
01674      * @param   string      $date=="date" will yield "dd:mm:yy" formatting, otherwise "dd:mm:yy hh:mm"
01675      * @return  string
01676      */
01677     public static function dateTimeAge($tstamp, $prefix = 1, $date = '') {
01678         return $tstamp ?
01679                 ($date == 'date' ? self::date($tstamp) : self::datetime($tstamp)) .
01680                         ' (' . self::calcAge($prefix * ($GLOBALS['EXEC_TIME'] - $tstamp), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears')) . ')'
01681                 : '';
01682     }
01683 
01684     /**
01685      * Returns alt="" and title="" attributes with the value of $content.
01686      * Usage: 7
01687      *
01688      * @param   string      Value for 'alt' and 'title' attributes (will be htmlspecialchars()'ed before output)
01689      * @return  string
01690      */
01691     public static function titleAltAttrib($content) {
01692         $out = '';
01693         $out .= ' alt="' . htmlspecialchars($content) . '"';
01694         $out .= ' title="' . htmlspecialchars($content) . '"';
01695         return $out;
01696     }
01697 
01698     /**
01699      * Returns a linked image-tag for thumbnail(s)/fileicons/truetype-font-previews from a database row with a list of image files in a field
01700      * All $TYPO3_CONF_VARS['GFX']['imagefile_ext'] extension are made to thumbnails + ttf file (renders font-example)
01701      * Thumbsnails are linked to the show_item.php script which will display further details.
01702      * Usage: 7
01703      *
01704      * @param   array       $row is the database row from the table, $table.
01705      * @param   string      Table name for $row (present in TCA)
01706      * @param   string      $field is pointing to the field with the list of image files
01707      * @param   string      Back path prefix for image tag src="" field
01708      * @param   string      Optional: $thumbScript os by default 'thumbs.php' if you don't set it otherwise
01709      * @param   string      Optional: $uploaddir is the directory relative to PATH_site where the image files from the $field value is found (Is by default set to the entry in $TCA for that field! so you don't have to!)
01710      * @param   boolean     If set, uploaddir is NOT prepended with "../"
01711      * @param   string      Optional: $tparams is additional attributes for the image tags
01712      * @param   integer     Optional: $size is [w]x[h] of the thumbnail. 56 is default.
01713      * @return  string      Thumbnail image tag.
01714      */
01715     public static function thumbCode($row, $table, $field, $backPath, $thumbScript = '', $uploaddir = NULL, $abs = 0, $tparams = '', $size = '') {
01716         global $TCA;
01717             // Load table.
01718         t3lib_div::loadTCA($table);
01719 
01720             // Find uploaddir automatically
01721         $uploaddir = (is_null($uploaddir)) ? $TCA[$table]['columns'][$field]['config']['uploadfolder'] : $uploaddir;
01722         $uploaddir = preg_replace('#/$#', '', $uploaddir);
01723 
01724             // Set thumbs-script:
01725         if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails']) {
01726             $thumbScript = 'gfx/notfound_thumb.gif';
01727         } elseif (!$thumbScript) {
01728             $thumbScript = 'thumbs.php';
01729         }
01730             // Check and parse the size parameter
01731         $sizeParts = array();
01732         if ($size = trim($size)) {
01733             $sizeParts = explode('x', $size . 'x' . $size);
01734             if (!intval($sizeParts[0])) {
01735                 $size = '';
01736             }
01737         }
01738 
01739             // Traverse files:
01740         $thumbs = explode(',', $row[$field]);
01741         $thumbData = '';
01742         foreach ($thumbs as $theFile) {
01743             if (trim($theFile)) {
01744                 $fI = t3lib_div::split_fileref($theFile);
01745                 $ext = $fI['fileext'];
01746                     // New 190201 start
01747                 $max = 0;
01748                 if (t3lib_div::inList('gif,jpg,png', $ext)) {
01749                     $imgInfo = @getimagesize(PATH_site . $uploaddir . '/' . $theFile);
01750                     if (is_array($imgInfo)) {
01751                         $max = max($imgInfo[0], $imgInfo[1]);
01752                     }
01753                 }
01754                     // use the original image if it's size fits to the thumbnail size
01755                 if ($max && $max <= (count($sizeParts) && max($sizeParts) ? max($sizeParts) : 56)) {
01756                     $theFile = $url = ($abs ? '' : '../') . ($uploaddir ? $uploaddir . '/' : '') . trim($theFile);
01757                     $onClick = 'top.launchView(\'' . $theFile . '\',\'\',\'' . $backPath . '\');return false;';
01758                     $thumbData .= '<a href="#" onclick="' . htmlspecialchars($onClick) . '"><img src="' . $backPath . $url . '" ' . $imgInfo[3] . ' hspace="2" border="0" title="' . trim($url) . '"' . $tparams . ' alt="" /></a> ';
01759                     // New 190201 stop
01760                 } elseif ($ext == 'ttf' || t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $ext)) {
01761                     $theFile_abs = PATH_site . ($uploaddir ? $uploaddir . '/' : '') . trim($theFile);
01762                     $theFile = ($abs ? '' : '../') . ($uploaddir ? $uploaddir . '/' : '') . trim($theFile);
01763 
01764                     if (!is_readable($theFile_abs)) {
01765                         $flashMessage = t3lib_div::makeInstance(
01766                             't3lib_FlashMessage',
01767                                 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.file_missing_text') . ' <abbr title="' . $theFile_abs . '">' . $theFile . '</abbr>',
01768                             $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.file_missing'),
01769                             t3lib_FlashMessage::ERROR
01770                         );
01771                         $thumbData .= $flashMessage->render();
01772                         continue;
01773                     }
01774 
01775                     $check = basename($theFile_abs) . ':' . filemtime($theFile_abs) . ':' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
01776                     $params = '&file=' . rawurlencode($theFile);
01777                     $params .= $size ? '&size=' . $size : '';
01778                     $params .= '&md5sum=' . t3lib_div::shortMD5($check);
01779 
01780                     $url = $thumbScript . '?&dummy=' . $GLOBALS['EXEC_TIME'] . $params;
01781                     $onClick = 'top.launchView(\'' . $theFile . '\',\'\',\'' . $backPath . '\');return false;';
01782                     $thumbData .= '<a href="#" onclick="' . htmlspecialchars($onClick) . '"><img src="' . htmlspecialchars($backPath . $url) . '" hspace="2" border="0" title="' . trim($theFile) . '"' . $tparams . ' alt="" /></a> ';
01783                 } else {
01784                         // Icon
01785                     $theFile_abs = PATH_site . ($uploaddir ? $uploaddir . '/' : '') . trim($theFile);
01786                     $theFile = ($abs ? '' : '../') . ($uploaddir ? $uploaddir . '/' : '') . trim($theFile);
01787 
01788                     $fileIcon = t3lib_iconWorks::getSpriteIconForFile(
01789                         strtolower($ext),
01790                         array('title' => htmlspecialchars(trim($theFile)))
01791                     );
01792 
01793                     $check = basename($theFile_abs) . ':' . filemtime($theFile_abs) . ':' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
01794                     $params = '&file=' . rawurlencode($theFile);
01795                     $params .= $size ? '&size=' . $size : '';
01796                     $params .= '&md5sum=' . t3lib_div::shortMD5($check);
01797 
01798                     $url = $thumbScript . '?&dummy=' . $GLOBALS['EXEC_TIME'] . $params;
01799                     $onClick = 'top.launchView(\'' . $theFile . '\',\'\',\'' . $backPath . '\');return false;';
01800                     $thumbData .= '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' . $fileIcon . '</a> ';
01801                 }
01802             }
01803         }
01804         return $thumbData;
01805     }
01806 
01807     /**
01808      * Returns single image tag to thumbnail using a thumbnail script (like thumbs.php)
01809      * Usage: 3
01810      *
01811      * @param   string      $thumbScript must point to "thumbs.php" relative to the script position
01812      * @param   string      $theFile must be the proper reference to the file thumbs.php should show
01813      * @param   string      $tparams are additional attributes for the image tag
01814      * @param   integer     $size is the size of the thumbnail send along to "thumbs.php"
01815      * @return  string      Image tag
01816      */
01817     public static function getThumbNail($thumbScript, $theFile, $tparams = '', $size = '') {
01818         $check = basename($theFile) . ':' . filemtime($theFile) . ':' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
01819         $params = '&file=' . rawurlencode($theFile);
01820         $params .= trim($size) ? '&size=' . trim($size) : '';
01821         $params .= '&md5sum=' . t3lib_div::shortMD5($check);
01822 
01823         $url = $thumbScript . '?&dummy=' . $GLOBALS['EXEC_TIME'] . $params;
01824         $th = '<img src="' . htmlspecialchars($url) . '" title="' . trim(basename($theFile)) . '"' . ($tparams ? " " . $tparams : "") . ' alt="" />';
01825         return $th;
01826     }
01827 
01828     /**
01829      * Returns title-attribute information for a page-record informing about id, alias, doktype, hidden, starttime, endtime, fe_group etc.
01830      * Usage: 8
01831      *
01832      * @param   array       Input must be a page row ($row) with the proper fields set (be sure - send the full range of fields for the table)
01833      * @param   string      $perms_clause is used to get the record path of the shortcut page, if any (and doktype==4)
01834      * @param   boolean     If $includeAttrib is set, then the 'title=""' attribute is wrapped about the return value, which is in any case htmlspecialchar()'ed already
01835      * @return  string
01836      */
01837     public static function titleAttribForPages($row, $perms_clause = '', $includeAttrib = 1) {
01838         global $TCA, $LANG;
01839         $parts = array();
01840         $parts[] = 'id=' . $row['uid'];
01841         if ($row['alias']) {
01842             $parts[] = $LANG->sL($TCA['pages']['columns']['alias']['label']) . ' ' . $row['alias'];
01843         }
01844         if ($row['pid'] < 0) {
01845             $parts[] = 'v#1.' . $row['t3ver_id'];
01846         }
01847 
01848         switch ($row['t3ver_state']) {
01849             case 1:
01850                 $parts[] = 'PLH WSID#' . $row['t3ver_wsid'];
01851                 break;
01852             case 2:
01853                 $parts[] = 'Deleted element!';
01854                 break;
01855             case 3:
01856                 $parts[] = 'NEW LOCATION (PLH) WSID#' . $row['t3ver_wsid'];
01857                 break;
01858             case 4:
01859                 $parts[] = 'OLD LOCATION (PNT) WSID#' . $row['t3ver_wsid'];
01860                 break;
01861             case -1:
01862                 $parts[] = 'New element!';
01863                 break;
01864         }
01865 
01866         if ($row['doktype'] == t3lib_pageSelect::DOKTYPE_LINK) {
01867             $parts[] = $LANG->sL($TCA['pages']['columns']['url']['label']) . ' ' . $row['url'];
01868         } elseif ($row['doktype'] == t3lib_pageSelect::DOKTYPE_SHORTCUT) {
01869             if ($perms_clause) {
01870                 $label = self::getRecordPath(intval($row['shortcut']), $perms_clause, 20);
01871             } else {
01872                 $lRec = self::getRecordWSOL('pages', intval($row['shortcut']), 'title');
01873                 $label = $lRec['title'];
01874             }
01875             if ($row['shortcut_mode'] != t3lib_pageSelect::SHORTCUT_MODE_NONE) {
01876                 $label .= ', ' . $LANG->sL($TCA['pages']['columns']['shortcut_mode']['label']) . ' ' .
01877                         $LANG->sL(self::getLabelFromItemlist('pages', 'shortcut_mode', $row['shortcut_mode']));
01878             }
01879             $parts[] = $LANG->sL($TCA['pages']['columns']['shortcut']['label']) . ' ' . $label;
01880         } elseif ($row['doktype'] == t3lib_pageSelect::DOKTYPE_MOUNTPOINT) {
01881             if ($perms_clause) {
01882                 $label = self::getRecordPath(intval($row['mount_pid']), $perms_clause, 20);
01883             } else {
01884                 $lRec = self::getRecordWSOL('pages', intval($row['mount_pid']), 'title');
01885                 $label = $lRec['title'];
01886             }
01887             $parts[] = $LANG->sL($TCA['pages']['columns']['mount_pid']['label']) . ' ' . $label;
01888             if ($row['mount_pid_ol']) {
01889                 $parts[] = $LANG->sL($TCA['pages']['columns']['mount_pid_ol']['label']);
01890             }
01891         }
01892         if ($row['nav_hide']) {
01893             $parts[] = rtrim($LANG->sL($TCA['pages']['columns']['nav_hide']['label']), ':');
01894         }
01895         if ($row['hidden']) {
01896             $parts[] = $LANG->sL('LLL:EXT:lang/locallang_core.php:labels.hidden');
01897         }
01898         if ($row['starttime']) {
01899             $parts[] = $LANG->sL($TCA['pages']['columns']['starttime']['label']) . ' ' . self::dateTimeAge($row['starttime'], -1, 'date');
01900         }
01901         if ($row['endtime']) {
01902             $parts[] = $LANG->sL($TCA['pages']['columns']['endtime']['label']) . ' ' . self::dateTimeAge($row['endtime'], -1, 'date');
01903         }
01904         if ($row['fe_group']) {
01905             $fe_groups = array();
01906             foreach (t3lib_div::intExplode(',', $row['fe_group']) as $fe_group) {
01907                 if ($fe_group < 0) {
01908                     $fe_groups[] = $LANG->sL(self::getLabelFromItemlist('pages', 'fe_group', $fe_group));
01909                 } else {
01910                     $lRec = self::getRecordWSOL('fe_groups', $fe_group, 'title');
01911                     $fe_groups[] = $lRec['title'];
01912                 }
01913             }
01914             $label = implode(', ', $fe_groups);
01915             $parts[] = $LANG->sL($TCA['pages']['columns']['fe_group']['label']) . ' ' . $label;
01916         }
01917         $out = htmlspecialchars(implode(' - ', $parts));
01918         return $includeAttrib ? 'title="' . $out . '"' : $out;
01919     }
01920 
01921     /**
01922      * Returns title-attribute information for ANY record (from a table defined in TCA of course)
01923      * The included information depends on features of the table, but if hidden, starttime, endtime and fe_group fields are configured for, information about the record status in regard to these features are is included.
01924      * "pages" table can be used as well and will return the result of ->titleAttribForPages() for that page.
01925      * Usage: 10
01926      *
01927      * @param   array       Table row; $row is a row from the table, $table
01928      * @param   string      Table name
01929      * @return  string
01930      */
01931     public static function getRecordIconAltText($row, $table = 'pages') {
01932         if ($table == 'pages') {
01933             $out = self::titleAttribForPages($row, '', 0);
01934         } else {
01935             $ctrl = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns'];
01936 
01937             $out = 'id=' . $row['uid']; // Uid is added
01938             if ($table == 'pages' && $row['alias']) {
01939                 $out .= ' / ' . $row['alias'];
01940             }
01941             if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS'] && $row['pid'] < 0) {
01942                 $out .= ' - v#1.' . $row['t3ver_id'];
01943             }
01944             if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
01945                 switch ($row['t3ver_state']) {
01946                     case 1:
01947                         $out .= ' - PLH WSID#' . $row['t3ver_wsid'];
01948                         break;
01949                     case 2:
01950                         $out .= ' - Deleted element!';
01951                         break;
01952                     case 3:
01953                         $out .= ' - NEW LOCATION (PLH) WSID#' . $row['t3ver_wsid'];
01954                         break;
01955                     case 4:
01956                         $out .= ' - OLD LOCATION (PNT)  WSID#' . $row['t3ver_wsid'];
01957                         break;
01958                     case -1:
01959                         $out .= ' - New element!';
01960                         break;
01961                 }
01962             }
01963 
01964             if ($ctrl['disabled']) { // Hidden ...
01965                 $out .= ($row[$ctrl['disabled']] ? ' - ' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.hidden') : '');
01966             }
01967             if ($ctrl['starttime']) {
01968                 if ($row[$ctrl['starttime']] > $GLOBALS['EXEC_TIME']) {
01969                     $out .= ' - ' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.starttime') . ':' .
01970                             self::date($row[$ctrl['starttime']]) . ' (' . self::daysUntil($row[$ctrl['starttime']]) . ' ' .
01971                             $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.days') . ')';
01972                 }
01973             }
01974             if ($row[$ctrl['endtime']]) {
01975                 $out .= ' - ' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.endtime') . ': ' .
01976                         self::date($row[$ctrl['endtime']]) . ' (' . self::daysUntil($row[$ctrl['endtime']]) . ' ' .
01977                         $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.days') . ')';
01978             }
01979         }
01980         return htmlspecialchars($out);
01981     }
01982 
01983     /**
01984      * Returns the label of the first found entry in an "items" array from $TCA (tablename = $table/fieldname = $col) where the value is $key
01985      * Usage: 9
01986      *
01987      * @param   string      Table name, present in $TCA
01988      * @param   string      Field name, present in $TCA
01989      * @param   string      items-array value to match
01990      * @return  string      Label for item entry
01991      */
01992     public static function getLabelFromItemlist($table, $col, $key) {
01993         global $TCA;
01994             // Load full TCA for $table
01995         t3lib_div::loadTCA($table);
01996 
01997             // Check, if there is an "items" array:
01998         if (is_array($TCA[$table]) && is_array($TCA[$table]['columns'][$col]) && is_array($TCA[$table]['columns'][$col]['config']['items'])) {
01999                 // Traverse the items-array...
02000             foreach ($TCA[$table]['columns'][$col]['config']['items'] as $k => $v) {
02001                     // ... and return the first found label where the value was equal to $key
02002                 if (!strcmp($v[1], $key)) {
02003                     return $v[0];
02004                 }
02005             }
02006         }
02007     }
02008 
02009     /**
02010      * Returns the label-value for fieldname $col in table, $table
02011      * If $printAllWrap is set (to a "wrap") then it's wrapped around the $col value IF THE COLUMN $col DID NOT EXIST in TCA!, eg. $printAllWrap = '<strong>|</strong>' and the fieldname was 'not_found_field' then the return value would be '<strong>not_found_field</strong>'
02012      * Usage: 17
02013      *
02014      * @param   string      Table name, present in $TCA
02015      * @param   string      Field name
02016      * @param   string      Wrap value - set function description
02017      * @return  string
02018      */
02019     public static function getItemLabel($table, $col, $printAllWrap = '') {
02020         global $TCA;
02021             // Load full TCA for $table
02022         t3lib_div::loadTCA($table);
02023             // Check if column exists
02024         if (is_array($TCA[$table]) && is_array($TCA[$table]['columns'][$col])) {
02025                 // Re
02026             return $TCA[$table]['columns'][$col]['label'];
02027         }
02028         if ($printAllWrap) {
02029             $parts = explode('|', $printAllWrap);
02030             return $parts[0] . $col . $parts[1];
02031         }
02032     }
02033 
02034     /**
02035      * Returns the "title"-value in record, $row, from table, $table
02036      * The field(s) from which the value is taken is determined by the "ctrl"-entries 'label', 'label_alt' and 'label_alt_force'
02037      * Usage: 26
02038      *
02039      * @param   string      Table name, present in TCA
02040      * @param   array       Row from table
02041      * @param   boolean     If set, result is prepared for output: The output is cropped to a limited lenght (depending on BE_USER->uc['titleLen']) and if no value is found for the title, '<em>[No title]</em>' is returned (localized). Further, the output is htmlspecialchars()'ed
02042      * @param   boolean     If set, the function always returns an output. If no value is found for the title, '[No title]' is returned (localized).
02043      * @return  string
02044      */
02045     public static function getRecordTitle($table, $row, $prep = FALSE, $forceResult = TRUE) {
02046         global $TCA;
02047         if (is_array($TCA[$table])) {
02048 
02049                 // If configured, call userFunc
02050             if ($TCA[$table]['ctrl']['label_userFunc']) {
02051                 $params['table'] = $table;
02052                 $params['row'] = $row;
02053                 $params['title'] = '';
02054                     //create NULL-reference
02055                 $null = NULL;
02056                 t3lib_div::callUserFunction($TCA[$table]['ctrl']['label_userFunc'], $params, $null);
02057                 $t = $params['title'];
02058             } else {
02059 
02060                     // No userFunc: Build label
02061                 $t = self::getProcessedValue($table, $TCA[$table]['ctrl']['label'], $row[$TCA[$table]['ctrl']['label']], 0, 0, FALSE, $row['uid'], $forceResult);
02062                 if ($TCA[$table]['ctrl']['label_alt'] && ($TCA[$table]['ctrl']['label_alt_force'] || !strcmp($t, ''))) {
02063                     $altFields = t3lib_div::trimExplode(',', $TCA[$table]['ctrl']['label_alt'], 1);
02064                     $tA = array();
02065                     if (!empty($t)) {
02066                         $tA[] = $t;
02067                     }
02068                     foreach ($altFields as $fN) {
02069                         $t = trim(strip_tags($row[$fN]));
02070                         if (strcmp($t, '')) {
02071                             $t = self::getProcessedValue($table, $fN, $t, 0, 0, FALSE, $row['uid']);
02072                             if (!$TCA[$table]['ctrl']['label_alt_force']) {
02073                                 break;
02074                             }
02075                             $tA[] = $t;
02076                         }
02077                     }
02078                     if ($TCA[$table]['ctrl']['label_alt_force']) {
02079                         $t = implode(', ', $tA);
02080                     }
02081                 }
02082             }
02083 
02084                 // If the current result is empty, set it to '[No title]' (localized) and prepare for output if requested
02085             if ($prep || $forceResult) {
02086                 if ($prep) {
02087                     $t = self::getRecordTitlePrep($t);
02088                 }
02089                 if (!strcmp(trim($t), '')) {
02090                     $t = self::getNoRecordTitle($prep);
02091                 }
02092             }
02093 
02094             return $t;
02095         }
02096     }
02097 
02098     /**
02099      * Crops a title string to a limited lenght and if it really was cropped, wrap it in a <span title="...">|</span>,
02100      * which offers a tooltip with the original title when moving mouse over it.
02101      *
02102      * @param   string      $title: The title string to be cropped
02103      * @param   integer     $titleLength: Crop title after this length - if not set, BE_USER->uc['titleLen'] is used
02104      * @return  string      The processed title string, wrapped in <span title="...">|</span> if cropped
02105      */
02106     public static function getRecordTitlePrep($title, $titleLength = 0) {
02107             // If $titleLength is not a valid positive integer, use BE_USER->uc['titleLen']:
02108         if (!$titleLength || !t3lib_div::testInt($titleLength) || $titleLength < 0) {
02109             $titleLength = $GLOBALS['BE_USER']->uc['titleLen'];
02110         }
02111         $titleOrig = htmlspecialchars($title);
02112         $title = htmlspecialchars(t3lib_div::fixed_lgd_cs($title, $titleLength));
02113             // If title was cropped, offer a tooltip:
02114         if ($titleOrig != $title) {
02115             $title = '<span title="' . $titleOrig . '">' . $title . '</span>';
02116         }
02117         return $title;
02118     }
02119 
02120     /**
02121      * Get a localized [No title] string, wrapped in <em>|</em> if $prep is true.
02122      *
02123      * @param   boolean     $prep: Wrap result in <em>|</em>
02124      * @return  string      Localized [No title] string
02125      */
02126     public static function getNoRecordTitle($prep = FALSE) {
02127         $noTitle = '[' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.no_title', 1) . ']';
02128         if ($prep) {
02129             $noTitle = '<em>' . $noTitle . '</em>';
02130         }
02131         return $noTitle;
02132     }
02133 
02134     /**
02135      * Returns a human readable output of a value from a record
02136      * For instance a database record relation would be looked up to display the title-value of that record. A checkbox with a "1" value would be "Yes", etc.
02137      * $table/$col is tablename and fieldname
02138      * REMEMBER to pass the output through htmlspecialchars() if you output it to the browser! (To protect it from XSS attacks and be XHTML compliant)
02139      * Usage: 24
02140      *
02141      * @param   string      Table name, present in TCA
02142      * @param   string      Field name, present in TCA
02143      * @param   string      $value is the value of that field from a selected record
02144      * @param   integer     $fixed_lgd_chars is the max amount of characters the value may occupy
02145      * @param   boolean     $defaultPassthrough flag means that values for columns that has no conversion will just be pass through directly (otherwise cropped to 200 chars or returned as "N/A")
02146      * @param   boolean     If set, no records will be looked up, UIDs are just shown.
02147      * @param   integer     uid of the current record
02148      * @param   boolean     If t3lib_BEfunc::getRecordTitle is used to process the value, this parameter is forwarded.
02149      * @return  string
02150      */
02151     public static function getProcessedValue($table, $col, $value, $fixed_lgd_chars = 0, $defaultPassthrough = 0, $noRecordLookup = FALSE, $uid = 0, $forceResult = TRUE) {
02152         global $TCA;
02153         global $TYPO3_CONF_VARS;
02154 
02155         if ($col == 'uid') {
02156                 // no need to load TCA as uid is not in TCA-array
02157             return $value;
02158         }
02159             // Load full TCA for $table
02160         t3lib_div::loadTCA($table);
02161             // Check if table and field is configured:
02162         if (is_array($TCA[$table]) && is_array($TCA[$table]['columns'][$col])) {
02163                 // Depending on the fields configuration, make a meaningful output value.
02164             $theColConf = $TCA[$table]['columns'][$col]['config'];
02165 
02166             /*****************
02167              *HOOK: pre-processing the human readable output from a record
02168              ****************/
02169             if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['preProcessValue'])) {
02170                     // create NULL-reference
02171                 $null = NULL;
02172                 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['preProcessValue'] as $_funcRef) {
02173                     t3lib_div::callUserFunction($_funcRef, $theColConf, $null);
02174                 }
02175             }
02176 
02177             $l = '';
02178             switch ((string) $theColConf['type']) {
02179                 case 'radio':
02180                     $l = self::getLabelFromItemlist($table, $col, $value);
02181                     $l = $GLOBALS['LANG']->sL($l);
02182                     break;
02183                 case 'select':
02184                     if ($theColConf['MM']) {
02185                         if ($uid) {
02186                                 // Display the title of MM related records in lists
02187                             if ($noRecordLookup) {
02188                                 $MMfield = $theColConf['foreign_table'] . '.uid';
02189                             } else {
02190                                 $MMfields = array($theColConf['foreign_table'] . '.' . $TCA[$theColConf['foreign_table']]['ctrl']['label']);
02191                                 foreach (t3lib_div::trimExplode(',', $TCA[$theColConf['foreign_table']]['ctrl']['label_alt'], 1) as $f) {
02192                                     $MMfields[] = $theColConf['foreign_table'] . '.' . $f;
02193                                 }
02194                                 $MMfield = join(',', $MMfields);
02195                             }
02196 
02197                             $dbGroup = t3lib_div::makeInstance('t3lib_loadDBGroup');
02198                             $dbGroup->start($value, $theColConf['foreign_table'], $theColConf['MM'], $uid, $table, $theColConf);
02199                             $selectUids = $dbGroup->tableArray[$theColConf['foreign_table']];
02200 
02201                             if (is_array($selectUids) && count($selectUids) > 0) {
02202                                 $MMres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
02203                                     'uid, ' . $MMfield,
02204                                     $theColConf['foreign_table'],
02205                                         'uid IN (' . implode(',', $selectUids) . ')'
02206                                 );
02207                                 while ($MMrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($MMres)) {
02208                                     $mmlA[] = ($noRecordLookup ? $MMrow['uid'] : self::getRecordTitle($theColConf['foreign_table'], $MMrow, FALSE, $forceResult));
02209                                 }
02210                                 $GLOBALS['TYPO3_DB']->sql_free_result($MMres);
02211 
02212                                 if (is_array($mmlA)) {
02213                                     $l = implode('; ', $mmlA);
02214                                 } else {
02215                                     $l = '';
02216                                 }
02217                             } else {
02218                                 $l = 'N/A';
02219                             }
02220                         } else {
02221                             $l = 'N/A';
02222                         }
02223                     } else {
02224                         $l = self::getLabelFromItemlist($table, $col, $value);
02225                         $l = $GLOBALS['LANG']->sL($l);
02226                         if ($theColConf['foreign_table'] && !$l && $TCA[$theColConf['foreign_table']]) {
02227                             if ($noRecordLookup) {
02228                                 $l = $value;
02229                             } else {
02230                                 $rParts = t3lib_div::trimExplode(',', $value, 1);
02231                                 $lA = array();
02232                                 foreach ($rParts as $rVal) {
02233                                     $rVal = intval($rVal);
02234                                     if ($rVal > 0) {
02235                                         $r = self::getRecordWSOL($theColConf['foreign_table'], $rVal);
02236                                     } else {
02237                                         $r = self::getRecordWSOL($theColConf['neg_foreign_table'], -$rVal);
02238                                     }
02239                                     if (is_array($r)) {
02240                                         $lA[] = $GLOBALS['LANG']->sL($rVal > 0 ? $theColConf['foreign_table_prefix'] : $theColConf['neg_foreign_table_prefix']) . self::getRecordTitle($rVal > 0 ? $theColConf['foreign_table'] : $theColConf['neg_foreign_table'], $r, FALSE, $forceResult);
02241                                     } else {
02242                                         $lA[] = $rVal ? '[' . $rVal . '!]' : '';
02243                                     }
02244                                 }
02245                                 $l = implode(', ', $lA);
02246                             }
02247                         }
02248                     }
02249                     break;
02250                 case 'group':
02251                     $l = implode(', ', t3lib_div::trimExplode(',', $value, 1));
02252                     break;
02253                 case 'check':
02254                     if (!is_array($theColConf['items']) || count($theColConf['items']) == 1) {
02255                         $l = $value ? $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes') : $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:no');
02256                     } else {
02257                         $lA = Array();
02258                         foreach ($theColConf['items'] as $key => $val) {
02259                             if ($value & pow(2, $key)) {
02260                                 $lA[] = $GLOBALS['LANG']->sL($val[0]);
02261                             }
02262                         }
02263                         $l = implode(', ', $lA);
02264                     }
02265                     break;
02266                 case 'input':
02267                     if (isset($value)) {
02268                         if (t3lib_div::inList($theColConf['eval'], 'date')) {
02269                             $l = self::date($value) .
02270                                     ' (' .
02271                                     ($GLOBALS['EXEC_TIME'] - $value > 0 ? '-' : '') .
02272                                     self::calcAge(abs($GLOBALS['EXEC_TIME'] - $value), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears')) .
02273                                     ')';
02274                         } elseif (t3lib_div::inList($theColConf['eval'], 'time')) {
02275                             $l = self::time($value, FALSE);
02276                         } elseif (t3lib_div::inList($theColConf['eval'], 'timesec')) {
02277                             $l = self::time($value);
02278                         } elseif (t3lib_div::inList($theColConf['eval'], 'datetime')) {
02279                             $l = self::datetime($value);
02280                         } else {
02281                             $l = $value;
02282                         }
02283                     }
02284                     break;
02285                 case 'flex':
02286                     $l = strip_tags($value);
02287                     break;
02288                 default:
02289                     if ($defaultPassthrough) {
02290                         $l = $value;
02291                     } elseif ($theColConf['MM']) {
02292                         $l = 'N/A';
02293                     } elseif ($value) {
02294                         $l = t3lib_div::fixed_lgd_cs(strip_tags($value), 200);
02295                     }
02296                     break;
02297             }
02298 
02299                 // If this field is a password field, then hide the password by changing it to a random number of asterisk (*)
02300             if (stristr($theColConf['eval'], 'password')) {
02301                 unset($l);
02302                 $randomNumber = rand(5, 12);
02303                 for ($i = 0; $i < $randomNumber; $i++) {
02304                     $l .= '*';
02305                 }
02306             }
02307 
02308             /*****************
02309              *HOOK: post-processing the human readable output from a record
02310              ****************/
02311             if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['postProcessValue'])) {
02312                     // create NULL-reference
02313                 $null = NULL;
02314                 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['postProcessValue'] as $_funcRef) {
02315                     $params = array(
02316                         'value' => $l,
02317                         'colConf' => $theColConf
02318                     );
02319                     $l = t3lib_div::callUserFunction($_funcRef, $params, $null);
02320                 }
02321             }
02322 
02323             if ($fixed_lgd_chars) {
02324                 return t3lib_div::fixed_lgd_cs($l, $fixed_lgd_chars);
02325             } else {
02326                 return $l;
02327             }
02328         }
02329     }
02330 
02331     /**
02332      * Same as ->getProcessedValue() but will go easy on fields like "tstamp" and "pid" which are not configured in TCA - they will be formatted by this function instead.
02333      * Usage: 2
02334      *
02335      * @param   string      Table name, present in TCA
02336      * @param   string      Field name
02337      * @param   string      Field value
02338      * @param   integer     $fixed_lgd_chars is the max amount of characters the value may occupy
02339      * @param   integer     uid of the current record
02340      * @param   boolean     If t3lib_BEfunc::getRecordTitle is used to process the value, this parameter is forwarded.
02341      * @return  string
02342      * @see getProcessedValue()
02343      */
02344     public static function getProcessedValueExtra($table, $fN, $fV, $fixed_lgd_chars = 0, $uid = 0, $forceResult = TRUE) {
02345         global $TCA;
02346         $fVnew = self::getProcessedValue($table, $fN, $fV, $fixed_lgd_chars, 1, 0, $uid, $forceResult);
02347         if (!isset($fVnew)) {
02348             if (is_array($TCA[$table])) {
02349                 if ($fN == $TCA[$table]['ctrl']['tstamp'] || $fN == $TCA[$table]['ctrl']['crdate']) {
02350                     $fVnew = self::datetime($fV);
02351                 } elseif ($fN == 'pid') {
02352                     $fVnew = self::getRecordPath($fV, '1=1', 20); // Fetches the path with no regard to the users permissions to select pages.
02353                 } else {
02354                     $fVnew = $fV;
02355                 }
02356             }
02357         }
02358         return $fVnew;
02359     }
02360 
02361     /**
02362      * Returns file icon name (from $FILEICONS) for the fileextension $ext
02363      * Usage: 10
02364      *
02365      * @param   string      File extension, lowercase
02366      * @return  string      File icon filename
02367      */
02368     public static function getFileIcon($ext) {
02369         return $GLOBALS['FILEICONS'][$ext] ? $GLOBALS['FILEICONS'][$ext] : $GLOBALS['FILEICONS']['default'];
02370     }
02371 
02372     /**
02373      * Returns fields for a table, $table, which would typically be interesting to select
02374      * This includes uid, the fields defined for title, icon-field.
02375      * Returned as a list ready for query ($prefix can be set to eg. "pages." if you are selecting from the pages table and want the table name prefixed)
02376      * Usage: 3
02377      *
02378      * @param   string      Table name, present in TCA
02379      * @param   string      Table prefix
02380      * @param   array       Preset fields (must include prefix if that is used)
02381      * @return  string      List of fields.
02382      */
02383     public static function getCommonSelectFields($table, $prefix = '', $fields = array()) {
02384         global $TCA;
02385         $fields[] = $prefix . 'uid';
02386         $fields[] = $prefix . $TCA[$table]['ctrl']['label'];
02387 
02388         if ($TCA[$table]['ctrl']['label_alt']) {
02389             $secondFields = t3lib_div::trimExplode(',', $TCA[$table]['ctrl']['label_alt'], 1);
02390             foreach ($secondFields as $fieldN) {
02391                 $fields[] = $prefix . $fieldN;
02392             }
02393         }
02394         if ($TCA[$table]['ctrl']['versioningWS']) {
02395             $fields[] = $prefix . 't3ver_id';
02396             $fields[] = $prefix . 't3ver_state';
02397             $fields[] = $prefix . 't3ver_wsid';
02398             $fields[] = $prefix . 't3ver_count';
02399         }
02400 
02401         if ($TCA[$table]['ctrl']['selicon_field']) {
02402             $fields[] = $prefix . $TCA[$table]['ctrl']['selicon_field'];
02403         }
02404         if ($TCA[$table]['ctrl']['typeicon_column']) {
02405             $fields[] = $prefix . $TCA[$table]['ctrl']['typeicon_column'];
02406         }
02407 
02408         if (is_array($TCA[$table]['ctrl']['enablecolumns'])) {
02409             if ($TCA[$table]['ctrl']['enablecolumns']['disabled']) {
02410                 $fields[] = $prefix . $TCA[$table]['ctrl']['enablecolumns']['disabled'];
02411             }
02412             if ($TCA[$table]['ctrl']['enablecolumns']['starttime']) {
02413                 $fields[] = $prefix . $TCA[$table]['ctrl']['enablecolumns']['starttime'];
02414             }
02415             if ($TCA[$table]['ctrl']['enablecolumns']['endtime']) {
02416                 $fields[] = $prefix . $TCA[$table]['ctrl']['enablecolumns']['endtime'];
02417             }
02418             if ($TCA[$table]['ctrl']['enablecolumns']['fe_group']) {
02419                 $fields[] = $prefix . $TCA[$table]['ctrl']['enablecolumns']['fe_group'];
02420             }
02421         }
02422 
02423         return implode(',', array_unique($fields));
02424     }
02425 
02426     /**
02427      * Makes a form for configuration of some values based on configuration found in the array $configArray, with default values from $defaults and a data-prefix $dataPrefix
02428      * <form>-tags must be supplied separately
02429      * Needs more documentation and examples, in particular syntax for configuration array. See Inside TYPO3. That's were you can expect to find example, if anywhere.
02430      * Usage: 1 (ext. direct_mail)
02431      *
02432      * @param   array       Field configuration code.
02433      * @param   array       Defaults
02434      * @param   string      Prefix for formfields
02435      * @return  string      HTML for a form.
02436      */
02437     public static function makeConfigForm($configArray, $defaults, $dataPrefix) {
02438         $params = $defaults;
02439         if (is_array($configArray)) {
02440             $lines = array();
02441             foreach ($configArray as $fname => $config) {
02442                 if (is_array($config)) {
02443                     $lines[$fname] = '<strong>' . htmlspecialchars($config[1]) . '</strong><br />';
02444                     $lines[$fname] .= $config[2] . '<br />';
02445                     switch ($config[0]) {
02446                         case 'string':
02447                         case 'short':
02448                             $formEl = '<input type="text" name="' . $dataPrefix . '[' . $fname . ']" value="' . $params[$fname] . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth($config[0] == 'short' ? 24 : 48) . ' />';
02449                             break;
02450                         case 'check':
02451                             $formEl = '<input type="hidden" name="' . $dataPrefix . '[' . $fname . ']" value="0" /><input type="checkbox" name="' . $dataPrefix . '[' . $fname . ']" value="1"' . ($params[$fname] ? ' checked="checked"' : '') . ' />';
02452                             break;
02453                         case 'comment':
02454                             $formEl = '';
02455                             break;
02456                         case 'select':
02457                             $opt = array();
02458                             foreach ($config[3] as $k => $v) {
02459                                 $opt[] = '<option value="' . htmlspecialchars($k) . '"' . ($params[$fname] == $k ? ' selected="selected"' : '') . '>' . htmlspecialchars($v) . '</option>';
02460                             }
02461                             $formEl = '<select name="' . $dataPrefix . '[' . $fname . ']">' . implode('', $opt) . '</select>';
02462                             break;
02463                         default:
02464                             debug($config);
02465                             break;
02466                     }
02467                     $lines[$fname] .= $formEl;
02468                     $lines[$fname] .= '<br /><br />';
02469                 } else {
02470                     $lines[$fname] = '<hr />';
02471                     if ($config) {
02472                         $lines[$fname] .= '<strong>' . strtoupper(htmlspecialchars($config)) . '</strong><br />';
02473                     }
02474                     if ($config) {
02475                         $lines[$fname] .= '<br />';
02476                     }
02477                 }
02478             }
02479         }
02480         $out = implode('', $lines);
02481         $out .= '<input type="submit" name="submit" value="Update configuration" />';
02482         return $out;
02483     }
02484 
02485 
02486     /*******************************************
02487      *
02488      * Backend Modules API functions
02489      *
02490      *******************************************/
02491 
02492     /**
02493      * Returns help-text icon if configured for.
02494      * TCA_DESCR must be loaded prior to this function and $BE_USER must
02495      * have 'edit_showFieldHelp' set to 'icon', otherwise nothing is returned
02496      * Usage: 6
02497      *
02498      * Please note: since TYPO3 4.5 the UX team decided to not use CSH in its former way,
02499      * but to wrap the given text (where before the help icon was, and you could hover over it)
02500      * Please also note that since TYPO3 4.5 the option to enable help (none, icon only, full text)
02501      * was completely removed.
02502      *
02503      * @param   string      Table name
02504      * @param   string      Field name
02505      * @param   string      Back path
02506      * @param   boolean     Force display of icon nomatter BE_USER setting for help
02507      * @return  string      HTML content for a help icon/text
02508      */
02509     public static function helpTextIcon($table, $field, $BACK_PATH, $force = 0) {
02510         global $TCA_DESCR, $BE_USER;
02511 
02512         if (is_array($TCA_DESCR[$table]) && is_array($TCA_DESCR[$table]['columns'][$field]) && (isset($BE_USER->uc['edit_showFieldHelp']) || $force)) {
02513             return self::wrapInHelp($table, $field);
02514         }
02515     }
02516 
02517     /**
02518      * Returns CSH help text (description), if configured for, as an array (title, description)
02519      * Will automatically call t3lib_BEfunc::helpTextIcon() to get the icon for the text.
02520      *
02521      * @param   string  Table name
02522      * @param   string  Field name
02523      * @return  array   With keys 'description' (raw, as available in locallang), 'title' (optional), 'moreInfo'
02524      */
02525     public static function helpTextArray($table, $field) {
02526         if (!isset($GLOBALS['TCA_DESCR'][$table]['columns'])) {
02527             $GLOBALS['LANG']->loadSingleTableDescription($table);
02528         }
02529         $output = array(
02530             'description' => NULL,
02531             'title' => NULL,
02532             'moreInfo' => FALSE,
02533         );
02534         if (is_array($GLOBALS['TCA_DESCR'][$table]) && is_array($GLOBALS['TCA_DESCR'][$table]['columns'][$field])) {
02535             $data = $GLOBALS['TCA_DESCR'][$table]['columns'][$field];
02536 
02537                 // add alternative title, if defined
02538             if ($data['alttitle']) {
02539                 $output['title'] = $data['alttitle'];
02540             }
02541 
02542                 // if we have more information to show
02543             if ($data['image_descr'] || $data['seeAlso'] || $data['details'] || $data['syntax']) {
02544                 $output['moreInfo'] = TRUE;
02545             }
02546 
02547                 // add description
02548             if ($data['description']) {
02549                 $output['description'] = $data['description'];
02550             }
02551         }
02552         return $output;
02553     }
02554 
02555     /**
02556      * Returns CSH help text (description), if configured for.
02557      * TCA_DESCR must be loaded prior to this function and $BE_USER must have "edit_showFieldHelp" set to "text",
02558      * otherwise nothing is returned
02559      * Will automatically call t3lib_BEfunc::helpTextIcon() to get the icon for the text.
02560      * Usage: 4
02561      *
02562      * @param   string      Table name
02563      * @param   string      Field name
02564      * @param   string      Back path, deprecated since TYPO3 4.5, will be removed in TYPO3 4.7, because not used at all
02565      * @param   string      DEPRECATED: Additional style-attribute content for wrapping table (now: only in function cshItem needed)
02566      * @return  string      HTML content for help text
02567      */
02568     public static function helpText($table, $field, $BACK_PATH = '', $styleAttrib = '') {
02569         $helpTextArray = self::helpTextArray($table, $field);
02570 
02571         $output = '';
02572 
02573             // put header before the rest of the text
02574         if ($helpTextArray['title'] !== NULL) {
02575             $output .= '<h2 class="t3-row-header">' . $helpTextArray['title'] . '</h2>';
02576         }
02577             // add the content
02578         if ($helpTextArray['description'] !== NULL) {
02579             $output .= $helpTextArray['description'];
02580         }
02581             // add see also arrow if we have more info
02582         if ($helpTextArray['moreInfo']) {
02583             $arrow = t3lib_iconWorks::getSpriteIcon('actions-view-go-forward');
02584         }
02585             // add description text
02586         if ($helpTextArray['description'] || $arrow) {
02587             $output['description'] = '<p class="t3-help-short">' . nl2br(htmlspecialchars($helpTextArray['description'])) . $arrow . '</p>';
02588         }
02589 
02590         return $output;
02591     }
02592 
02593     /**
02594      * API function that wraps the text / html in help text, so if a user hovers over it
02595      * the help text will show up
02596      * This is the new help API function since TYPO3 4.5, and uses the new behaviour
02597      * (hover over text, no icon, no fulltext option, no option to disable the help)
02598      *
02599      * @param   string  $table  The table name for which the help should be shown
02600      * @param   string  $field  The field name for which the help should be shown
02601      * @param   string  $text   the text which should be wrapped with the help text
02602      * @return  string  the HTML code ready to render
02603      * @api public
02604      */
02605     public static function wrapInHelp($table, $field, $text = '', array $overloadHelpText = array()) {
02606             // Initialize some variables
02607         $helpText = '';
02608         $abbrClassAdd = '';
02609         $wrappedText = $text;
02610         $hasHelpTextOverload = count($overloadHelpText) > 0;
02611 
02612             // Get the help text that should be shown on hover
02613         if (!$hasHelpTextOverload) {
02614             $helpText = self::helpText($table, $field);
02615         }
02616 
02617             // If there's a help text or some overload information, proceed with preparing an output
02618         if (!empty($helpText) || $hasHelpTextOverload) {
02619                 // If no text was given, just use the regular help icon
02620             if ($text == '') {
02621                 $text = t3lib_iconWorks::getSpriteIcon('actions-system-help-open');
02622                 $abbrClassAdd = '-icon';
02623             }
02624             $text = '<abbr class="t3-help-teaser' . $abbrClassAdd . '">' . $text . '</abbr>';
02625             $wrappedText = '<span class="t3-help-link" href="#" data-table="' . $table . '" data-field="' . $field . '"';
02626                 // The overload array may provide a title and a description
02627                 // If either one is defined, add them to the "data" attributes
02628             if ($hasHelpTextOverload) {
02629                 if (isset($overloadHelpText['title'])) {
02630                     $wrappedText .= ' data-title="' . htmlspecialchars($overloadHelpText['title']) . '"';
02631                 }
02632                 if (isset($overloadHelpText['description'])) {
02633                     $wrappedText .= ' data-description="' . htmlspecialchars($overloadHelpText['description']) . '"';
02634                 }
02635             }
02636             $wrappedText .= '>' . $text . '</span>';
02637         }
02638 
02639         return $wrappedText;
02640     }
02641 
02642 
02643     /**
02644      * API for getting CSH icons/text for use in backend modules.
02645      * TCA_DESCR will be loaded if it isn't already
02646      * Usage: ?
02647      *
02648      * @param   string      Table name ('_MOD_'+module name)
02649      * @param   string      Field name (CSH locallang main key)
02650      * @param   string      Back path
02651      * @param   string      Wrap code for icon-mode, splitted by "|". Not used for full-text mode.
02652      * @param   boolean     If set, the full text will never be shown (only icon).
02653      *               Useful for places where it will break the page if the table with full text is shown.
02654      * @param   string      Additional style-attribute content for wrapping table (full text mode only)
02655      * @return  string      HTML content for help text
02656      * @see helpText(), helpTextIcon()
02657      */
02658     public static function cshItem($table, $field, $BACK_PATH, $wrap = '', $onlyIconMode = FALSE, $styleAttrib = '') {
02659         global $TCA_DESCR, $LANG, $BE_USER;
02660 
02661         if ($BE_USER->uc['edit_showFieldHelp']) {
02662             $LANG->loadSingleTableDescription($table);
02663 
02664             if (is_array($TCA_DESCR[$table])) {
02665                     // Creating CSH icon and short description:
02666                 $fullText = self::helpText($table, $field, $BACK_PATH, '');
02667                 $icon = self::helpTextIcon($table, $field, $BACK_PATH);
02668 
02669                 if ($fullText && !$onlyIconMode && $BE_USER->uc['edit_showFieldHelp'] == 'text') {
02670 
02671                         // Additional styles?
02672                     $params = $styleAttrib ? ' style="' . $styleAttrib . '"' : '';
02673 
02674                         // Compile table with CSH information:
02675                     $fullText = '<table border="0" cellpadding="0" cellspacing="0" class="typo3-csh-inline"' . $params . '>
02676                     <tr>
02677                     <td valign="top" width="14"><div class="t3-row-header">' . $icon . '</div></td>
02678                     <td valign="top">' . $fullText . '</td>
02679                     </tr>
02680                     </table>';
02681 
02682                     $output = $LANG->hscAndCharConv($fullText, FALSE);
02683                 } else {
02684                     $output = $icon;
02685 
02686                     if ($output && $wrap) {
02687                         $wrParts = explode('|', $wrap);
02688                         $output = $wrParts[0] . $output . $wrParts[1];
02689                     }
02690                 }
02691 
02692                 return $output;
02693             }
02694         }
02695     }
02696 
02697     /**
02698      * Returns a JavaScript string (for an onClick handler) which will load the alt_doc.php script that shows the form for editing of the record(s) you have send as params.
02699      * REMEMBER to always htmlspecialchar() content in href-properties to ampersands get converted to entities (XHTML requirement and XSS precaution)
02700      * Usage: 35
02701      *
02702      * @param   string      $params is parameters sent along to alt_doc.php. This requires a much more details description which you must seek in Inside TYPO3s documentation of the alt_doc.php API. And example could be '&edit[pages][123] = edit' which will show edit form for page record 123.
02703      * @param   string      $backPath must point back to the TYPO3_mainDir directory (where alt_doc.php is)
02704      * @param   string      $requestUri is an optional returnUrl you can set - automatically set to REQUEST_URI.
02705      * @return  string
02706      * @see template::issueCommand()
02707      */
02708     public static function editOnClick($params, $backPath = '', $requestUri = '') {
02709         $retUrl = 'returnUrl=' . ($requestUri == -1 ? "'+T3_THIS_LOCATION+'" : rawurlencode($requestUri ? $requestUri : t3lib_div::getIndpEnv('REQUEST_URI')));
02710         return "window.location.href='" . $backPath . "alt_doc.php?" . $retUrl . $params . "'; return false;";
02711     }
02712 
02713     /**
02714      * Returns a JavaScript string for viewing the page id, $id
02715      * It will detect the correct domain name if needed and provide the link with the right back path. Also it will re-use any window already open.
02716      * Usage: 8
02717      *
02718      * @param   integer     $pageUid is page id
02719      * @param   string      $backPath must point back to TYPO3_mainDir (where the site is assumed to be one level above)
02720      * @param   array       $rootLine If root line is supplied the function will look for the first found domain record and use that URL instead (if found)
02721      * @param   string      $anchorSection is optional anchor to the URL
02722      * @param   string      $alternativeUrl is an alternative URL which - if set - will make all other parameters ignored: The function will just return the window.open command wrapped around this URL!
02723      * @param   string      $additionalGetVars Additional GET variables.
02724      * @param   boolean     If true, then the preview window will gain the focus.
02725      * @return  string
02726      */
02727     public static function viewOnClick($pageUid, $backPath = '', $rootLine = '', $anchorSection = '', $alternativeUrl = '', $additionalGetVars = '', $switchFocus = TRUE) {
02728         $viewScript = '/index.php?id=';
02729         if ($alternativeUrl) {
02730             $viewScript = $alternativeUrl;
02731         }
02732 
02733         if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['viewOnClickClass'])
02734                 && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['viewOnClickClass'])) {
02735             foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['viewOnClickClass'] as $funcRef) {
02736                 $hookObj = t3lib_div::getUserObj($funcRef);
02737                 if (method_exists($hookObj, 'preProcess')) {
02738                     $hookObj->preProcess($pageUid, $backPath, $rootLine, $anchorSection, $viewScript, $additionalGetVars, $switchFocus);
02739                 }
02740             }
02741         }
02742 
02743             // Look if a fixed preview language should be added:
02744         $viewLanguageOrder = $GLOBALS['BE_USER']->getTSConfigVal('options.view.languageOrder');
02745         if (strlen($viewLanguageOrder)) {
02746             $suffix = '';
02747 
02748                 // Find allowed languages (if none, all are allowed!)
02749             if (!$GLOBALS['BE_USER']->user['admin'] &&
02750                     strlen($GLOBALS['BE_USER']->groupData['allowed_languages'])) {
02751                 $allowedLanguages = array_flip(explode(',', $GLOBALS['BE_USER']->groupData['allowed_languages']));
02752             }
02753 
02754                 // Traverse the view order, match first occurence:
02755             $languageOrder = t3lib_div::intExplode(',', $viewLanguageOrder);
02756             foreach ($languageOrder as $langUid) {
02757                 if (is_array($allowedLanguages) && count($allowedLanguages)) {
02758                         // Choose if set.
02759                     if (isset($allowedLanguages[$langUid])) {
02760                         $suffix = '&L=' . $langUid;
02761                         break;
02762                     }
02763                 } else {
02764                         // All allowed since no lang. are listed.
02765                     $suffix = '&L=' . $langUid;
02766                     break;
02767                 }
02768             }
02769                 // Add it:
02770             $additionalGetVars .= $suffix;
02771         }
02772 
02773             // check a mount point needs to be previewed
02774         $sys_page = t3lib_div::makeInstance('t3lib_pageSelect');
02775         $sys_page->init(FALSE);
02776         $mountPointInfo = $sys_page->getMountPointInfo($pageUid);
02777         if ($mountPointInfo && $mountPointInfo['overlay']) {
02778             $pageUid = $mountPointInfo['mount_pid'];
02779             $additionalGetVars .= '&MP=' . $mountPointInfo['MPvar'];
02780         }
02781 
02782         $viewDomain = self::getViewDomain($pageUid, $rootLine);
02783         $previewUrl = $viewDomain . $viewScript . $pageUid . $additionalGetVars . $anchorSection;
02784         $onclickCode = "var previewWin = window.open('" . $previewUrl . "','newTYPO3frontendWindow');" . ($switchFocus ? 'previewWin.focus();' : '');
02785         return $onclickCode;
02786     }
02787 
02788     /**
02789      * Builds the frontend view domain for a given page ID with a given root
02790      * line.
02791      *
02792      * @param integer $pageId the page ID to use, must be > 0
02793      * @param array $rootLine the root line structure to use
02794      *
02795      * @return string the full domain including the protocol http:// or https://, but without the trailing '/'
02796      *
02797      * @author Michael Klapper <michael.klapper@aoemedia.de>
02798      */
02799     public static function getViewDomain($pageId, $rootLine = NULL) {
02800         $domain = rtrim(t3lib_div::getIndpEnv('TYPO3_SITE_URL'), '/');
02801 
02802         if (!is_array($rootLine)) {
02803             $rootLine = self::BEgetRootLine($pageId);
02804         }
02805 
02806             // checks alternate domains
02807         if (count($rootLine) > 0) {
02808             $urlParts = parse_url($domain);
02809             if (self::getDomainStartPage($urlParts['host'], $urlParts['path'])) {
02810                 $protocol = t3lib_div::getIndpEnv('TYPO3_SSL') ? 'https://' : 'http://';
02811                 $domain = $protocol . self::firstDomainRecord($rootLine);
02812             }
02813         }
02814 
02815         return $domain;
02816     }
02817 
02818     /**
02819      * Returns the merged User/Page TSconfig for page id, $id.
02820      * Please read details about module programming elsewhere!
02821      * Usage: 15
02822      *
02823      * @param   integer     Page uid
02824      * @param   string      $TSref is an object string which determines the path of the TSconfig to return.
02825      * @return  array
02826      */
02827     public static function getModTSconfig($id, $TSref) {
02828         $pageTS_modOptions = $GLOBALS['BE_USER']->getTSConfig($TSref, self::getPagesTSconfig($id));
02829         $BE_USER_modOptions = $GLOBALS['BE_USER']->getTSConfig($TSref);
02830         $modTSconfig = t3lib_div::array_merge_recursive_overrule($pageTS_modOptions, $BE_USER_modOptions);
02831         return $modTSconfig;
02832     }
02833 
02834     /**
02835      * Returns a selector box "function menu" for a module
02836      * Requires the JS function jumpToUrl() to be available
02837      * See Inside TYPO3 for details about how to use / make Function menus
02838      * Usage: 50
02839      *
02840      * @param   mixed       $id is the "&id=" parameter value to be sent to the module, but it can be also a parameter array which will be passed instead of the &id=...
02841      * @param   string      $elementName it the form elements name, probably something like "SET[...]"
02842      * @param   string      $currentValue is the value to be selected currently.
02843      * @param   array       $menuItems is an array with the menu items for the selector box
02844      * @param   string      $script is the script to send the &id to, if empty it's automatically found
02845      * @param   string      $addParams is additional parameters to pass to the script.
02846      * @return  string      HTML code for selector box
02847      */
02848     public static function getFuncMenu($mainParams, $elementName, $currentValue, $menuItems, $script = '', $addparams = '') {
02849         if (is_array($menuItems)) {
02850             if (!is_array($mainParams)) {
02851                 $mainParams = array('id' => $mainParams);
02852             }
02853             $mainParams = t3lib_div::implodeArrayForUrl('', $mainParams);
02854 
02855             if (!$script) {
02856                 $script = basename(PATH_thisScript);
02857                 $mainParams .= (t3lib_div::_GET('M') ? '&M=' . rawurlencode(t3lib_div::_GET('M')) : '');
02858             }
02859 
02860             $options = array();
02861             foreach ($menuItems as $value => $label) {
02862                 $options[] = '<option value="' . htmlspecialchars($value) . '"' . (!strcmp($currentValue, $value) ? ' selected="selected"' : '') . '>' .
02863                         t3lib_div::deHSCentities(htmlspecialchars($label)) .
02864                         '</option>';
02865             }
02866             if (count($options)) {
02867                 $onChange = 'jumpToUrl(\'' . $script . '?' . $mainParams . $addparams . '&' . $elementName . '=\'+this.options[this.selectedIndex].value,this);';
02868                 return '
02869 
02870                     <!-- Function Menu of module -->
02871                     <select name="' . $elementName . '" onchange="' . htmlspecialchars($onChange) . '">
02872                         ' . implode('
02873                         ', $options) . '
02874                     </select>
02875                             ';
02876             }
02877         }
02878     }
02879 
02880     /**
02881      * Checkbox function menu.
02882      * Works like ->getFuncMenu() but takes no $menuItem array since this is a simple checkbox.
02883      * Usage: 34
02884      *
02885      * @param   mixed       $mainParams $id is the "&id=" parameter value to be sent to the module, but it can be also a parameter array which will be passed instead of the &id=...
02886      * @param   string      $elementName it the form elements name, probably something like "SET[...]"
02887      * @param   string      $currentValue is the value to be selected currently.
02888      * @param   string      $script is the script to send the &id to, if empty it's automatically found
02889      * @param   string      $addParams is additional parameters to pass to the script.
02890      * @param   string      Additional attributes for the checkbox input tag
02891      * @return  string      HTML code for checkbox
02892      * @see getFuncMenu()
02893      */
02894     public static function getFuncCheck($mainParams, $elementName, $currentValue, $script = '', $addparams = '', $tagParams = '') {
02895         if (!is_array($mainParams)) {
02896             $mainParams = array('id' => $mainParams);
02897         }
02898         $mainParams = t3lib_div::implodeArrayForUrl('', $mainParams);
02899 
02900         if (!$script) {
02901             $script = basename(PATH_thisScript);
02902             $mainParams .= (t3lib_div::_GET('M') ? '&M=' . rawurlencode(t3lib_div::_GET('M')) : '');
02903         }
02904 
02905         $onClick = 'jumpToUrl(\'' . $script . '?' . $mainParams . $addparams . '&' . $elementName . '=\'+(this.checked?1:0),this);';
02906         return '<input type="checkbox" class="checkbox" name="' . $elementName . '"' . ($currentValue ? ' checked="checked"' : '') . ' onclick="' . htmlspecialchars($onClick) . '"' . ($tagParams ? ' ' . $tagParams : '') . ' />';
02907     }
02908 
02909     /**
02910      * Input field function menu
02911      * Works like ->getFuncMenu() / ->getFuncCheck() but displays a input field instead which updates the script "onchange"
02912      * Usage: 1
02913      *
02914      * @param   mixed       $id is the "&id=" parameter value to be sent to the module, but it can be also a parameter array which will be passed instead of the &id=...
02915      * @param   string      $elementName it the form elements name, probably something like "SET[...]"
02916      * @param   string      $currentValue is the value to be selected currently.
02917      * @param   integer     Relative size of input field, max is 48
02918      * @param   string      $script is the script to send the &id to, if empty it's automatically found
02919      * @param   string      $addParams is additional parameters to pass to the script.
02920      * @return  string      HTML code for input text field.
02921      * @see getFuncMenu()
02922      */
02923     public static function getFuncInput($mainParams, $elementName, $currentValue, $size = 10, $script = "", $addparams = "") {
02924         if (!is_array($mainParams)) {
02925             $mainParams = array('id' => $mainParams);
02926         }
02927         $mainParams = t3lib_div::implodeArrayForUrl('', $mainParams);
02928 
02929         if (!$script) {
02930             $script = basename(PATH_thisScript);
02931             $mainParams .= (t3lib_div::_GET('M') ? '&M=' . rawurlencode(t3lib_div::_GET('M')) : '');
02932         }
02933 
02934         $onChange = 'jumpToUrl(\'' . $script . '?' . $mainParams . $addparams . '&' . $elementName . '=\'+escape(this.value),this);';
02935         return '<input type="text"' . $GLOBALS['TBE_TEMPLATE']->formWidth($size) . ' name="' . $elementName . '" value="' . htmlspecialchars($currentValue) . '" onchange="' . htmlspecialchars($onChange) . '" />';
02936     }
02937 
02938     /**
02939      * Removes menu items from $itemArray if they are configured to be removed by TSconfig for the module ($modTSconfig)
02940      * See Inside TYPO3 about how to program modules and use this API.
02941      * Usage: 4
02942      *
02943      * @param   array       Module TS config array
02944      * @param   array       Array of items from which to remove items.
02945      * @param   string      $TSref points to the "object string" in $modTSconfig
02946      * @return  array       The modified $itemArray is returned.
02947      */
02948     public static function unsetMenuItems($modTSconfig, $itemArray, $TSref) {
02949             // Getting TS-config options for this module for the Backend User:
02950         $conf = $GLOBALS['BE_USER']->getTSConfig($TSref, $modTSconfig);
02951         if (is_array($conf['properties'])) {
02952             foreach ($conf['properties'] as $key => $val) {
02953                 if (!$val) {
02954                     unset($itemArray[$key]);
02955                 }
02956             }
02957         }
02958         return $itemArray;
02959     }
02960 
02961     /**
02962      * Call to update the page tree frame (or something else..?) after
02963      * use 'updatePageTree' as a first parameter will set the page tree to be updated.
02964      * Usage: 10
02965      *
02966      * @param   string      Key to set the update signal. When setting, this value contains strings telling WHAT to set. At this point it seems that the value "updatePageTree" is the only one it makes sense to set. If empty, all update signals will be removed.
02967      * @param   mixed       Additional information for the update signal, used to only refresh a branch of the tree
02968      * @return  void
02969      * @see t3lib_BEfunc::getUpdateSignalCode()
02970      */
02971     public static function setUpdateSignal($set = '', $params = '') {
02972         global $BE_USER;
02973         $modData = $BE_USER->getModuleData('t3lib_BEfunc::getUpdateSignal', 'ses');
02974 
02975         if ($set) {
02976             $modData[$set] = array(
02977                 'set' => $set,
02978                 'parameter' => $params);
02979         } else { // clear the module data
02980             $modData = array();
02981         }
02982         $BE_USER->pushModuleData('t3lib_BEfunc::getUpdateSignal', $modData);
02983     }
02984 
02985 
02986     /**
02987      * Call to update the page tree frame (or something else..?) if this is set by the function
02988      * setUpdateSignal(). It will return some JavaScript that does the update (called in the typo3/template.php file, end() function)
02989      * Usage: 1
02990      *
02991      * @return  string      HTML javascript code
02992      * @see t3lib_BEfunc::setUpdateSignal()
02993      */
02994     public static function getUpdateSignalCode() {
02995         $signals = array();
02996         $modData = $GLOBALS['BE_USER']->getModuleData('t3lib_BEfunc::getUpdateSignal', 'ses');
02997         if (!count($modData)) {
02998             return '';
02999         }
03000 
03001             // Hook: Allows to let TYPO3 execute your JS code
03002         if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['updateSignalHook'])) {
03003             $updateSignals = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['updateSignalHook'];
03004         } else {
03005             $updateSignals = array();
03006         }
03007 
03008             // loop through all setUpdateSignals and get the JS code
03009         foreach ($modData as $set => $val) {
03010             if (isset($updateSignals[$set])) {
03011                 $params = array('set' => $set, 'parameter' => $val['parameter'], 'JScode' => '');
03012                 $ref = NULL;
03013                 t3lib_div::callUserFunction($updateSignals[$set], $params, $ref);
03014                 $signals[] = $params['JScode'];
03015             } else {
03016                 switch ($set) {
03017                     case 'updatePageTree':
03018                         $signals[] = '
03019                             if (top && top.TYPO3.Backend.NavigationContainer.PageTree) {
03020                                 top.TYPO3.Backend.NavigationContainer.PageTree.refreshTree();
03021                             }
03022                         ';
03023                         break;
03024                     case 'updateFolderTree':
03025                         $signals[] = '
03026                             if (top && top.TYPO3.Backend.NavigationIframe) {
03027                                 top.TYPO3.Backend.NavigationIframe.refresh();
03028                             }';
03029                         break;
03030                     case 'updateModuleMenu':
03031                         $signals[] = '
03032                             if (top && top.TYPO3.ModuleMenu.App) {
03033                                 top.TYPO3.ModuleMenu.App.refreshMenu();
03034                             }';
03035                         break;
03036                 }
03037             }
03038         }
03039 
03040         $content = implode(LF, $signals);
03041 
03042         self::setUpdateSignal(); // for backwards compatibility, should be replaced
03043         return $content;
03044     }
03045 
03046 
03047     /**
03048      * Returns an array which is most backend modules becomes MOD_SETTINGS containing values from function menus etc. determining the function of the module.
03049      * This is kind of session variable management framework for the backend users.
03050      * If a key from MOD_MENU is set in the CHANGED_SETTINGS array (eg. a value is passed to the script from the outside), this value is put into the settings-array
03051      * Ultimately, see Inside TYPO3 for how to use this function in relation to your modules.
03052      * Usage: 23
03053      *
03054      * @param   array       MOD_MENU is an array that defines the options in menus.
03055      * @param   array       CHANGED_SETTINGS represents the array used when passing values to the script from the menus.
03056      * @param   string      modName is the name of this module. Used to get the correct module data.
03057      * @param   string      If type is 'ses' then the data is stored as session-lasting data. This means that it'll be wiped out the next time the user logs in.
03058      * @param   string      dontValidateList can be used to list variables that should not be checked if their value is found in the MOD_MENU array. Used for dynamically generated menus.
03059      * @param   string      List of default values from $MOD_MENU to set in the output array (only if the values from MOD_MENU are not arrays)
03060      * @return  array       The array $settings, which holds a key for each MOD_MENU key and the values of each key will be within the range of values for each menuitem
03061      */
03062     public static function getModuleData($MOD_MENU, $CHANGED_SETTINGS, $modName, $type = '', $dontValidateList = '', $setDefaultList = '') {
03063 
03064         if ($modName && is_string($modName)) {
03065                 // GETTING stored user-data from this module:
03066             $settings = $GLOBALS['BE_USER']->getModuleData($modName, $type);
03067 
03068             $changed = 0;
03069             if (!is_array($settings)) {
03070                 $changed = 1;
03071                 $settings = array();
03072             }
03073             if (is_array($MOD_MENU)) {
03074                 foreach ($MOD_MENU as $key => $var) {
03075 
03076                         // If a global var is set before entering here. eg if submitted, then it's substituting the current value the array.
03077                     if (is_array($CHANGED_SETTINGS) && isset($CHANGED_SETTINGS[$key])) {
03078                         if (is_array($CHANGED_SETTINGS[$key])) {
03079                             $serializedSettings = serialize($CHANGED_SETTINGS[$key]);
03080                             if (strcmp($settings[$key], $serializedSettings)) {
03081                                 $settings[$key] = $serializedSettings;
03082                                 $changed = 1;
03083                             }
03084                         } else {
03085                             if (strcmp($settings[$key], $CHANGED_SETTINGS[$key])) {
03086                                 $settings[$key] = $CHANGED_SETTINGS[$key];
03087                                 $changed = 1;
03088                             }
03089                         }
03090                     }
03091 
03092                         // If the $var is an array, which denotes the existence of a menu, we check if the value is permitted
03093                     if (is_array($var) && (!$dontValidateList || !t3lib_div::inList($dontValidateList, $key))) {
03094                             // If the setting is an array or not present in the menu-array, MOD_MENU, then the default value is inserted.
03095                         if (is_array($settings[$key]) || !isset($MOD_MENU[$key][$settings[$key]])) {
03096                             $settings[$key] = (string) key($var);
03097                             $changed = 1;
03098                         }
03099                     }
03100                     if ($setDefaultList && !is_array($var)) { // Sets default values (only strings/checkboxes, not menus)
03101                         if (t3lib_div::inList($setDefaultList, $key) && !isset($settings[$key])) {
03102                             $settings[$key] = (string) $var;
03103                         }
03104                     }
03105                 }
03106             } else {
03107                 die ('No menu!');
03108             }
03109 
03110             if ($changed) {
03111                 $GLOBALS['BE_USER']->pushModuleData($modName, $settings);
03112             }
03113 
03114             return $settings;
03115         } else {
03116             die ('Wrong module name: "' . $modName . '"');
03117         }
03118     }
03119 
03120 
03121 
03122     /**
03123      * Returns the URL to a given module
03124      *
03125      * @param string $moduleName Name of the module
03126      * @param array $urlParameters URL parameters that should be added as key value pairs
03127      * @param bool/string $backPathOverride backpath that should be used instead of the global $BACK_PATH
03128      * @param bool $returnAbsoluteUrl If set to true, the URL returned will be absolute, $backPathOverride will be ignored in this case
03129      * @return bool/string calculated URL or FALSE
03130      */
03131     public static function getModuleUrl($moduleName, $urlParameters = array(), $backPathOverride = FALSE, $returnAbsoluteUrl = FALSE) {
03132         if (!$GLOBALS['BE_USER']->check('modules', $moduleName)) {
03133             return FALSE;
03134         }
03135 
03136         if ($backPathOverride === FALSE) {
03137             $backPath = $GLOBALS['BACK_PATH'];
03138         } else {
03139             $backPath = $backPathOverride;
03140         }
03141 
03142         $allUrlParameters = array();
03143         $allUrlParameters['M'] = $moduleName;
03144         $allUrlParameters = array_merge($allUrlParameters, $urlParameters);
03145 
03146         $url = 'mod.php?' . t3lib_div::implodeArrayForUrl('', $allUrlParameters, '', TRUE);
03147 
03148         if ($returnAbsoluteUrl) {
03149             return t3lib_div::getIndpEnv('TYPO3_REQUEST_DIR') . $url;
03150         } else {
03151             return $backPath . $url;
03152         }
03153     }
03154 
03155     /**
03156      * Return a link to the list view
03157      *
03158      * @param array $urlParameters URL parameters that should be added as key value pairs
03159      * @param string $linkTitle title for the link tag
03160      * @param string $linkText optional link text after the icon
03161      * @return string a complete link tag or empty string
03162      */
03163     public static function getListViewLink($urlParameters = array(), $linkTitle = '', $linkText = '') {
03164         $url = self::getModuleUrl('web_list', $urlParameters);
03165 
03166         if (!t3lib_extMgm::isLoaded('recordlist') || $url === FALSE) {
03167             return '';
03168         } else {
03169             return '<a href="' . htmlspecialchars($url) . '" title="' . htmlspecialchars($linkTitle) . '">' .
03170                     t3lib_iconWorks::getSpriteIcon('actions-system-list-open') .
03171                     htmlspecialchars($linkText) .
03172                     '</a>';
03173         }
03174     }
03175 
03176     /**
03177      * Generates a token and returns a parameter for the URL
03178      *
03179      * @param string $formName Context of the token
03180      * @param string $tokenName The name of the token GET variable
03181      * @return string a URL GET variable including ampersand
03182      */
03183     public static function getUrlToken($formName = 'securityToken', $tokenName = 'formToken') {
03184         $formprotection = t3lib_formprotection_Factory::get();
03185         return '&' . $tokenName . '=' . $formprotection->generateToken($formName) . '-' . $formName;
03186     }
03187 
03188     /*******************************************
03189      *
03190      * Core
03191      *
03192      *******************************************/
03193 
03194     /**
03195      * Set preview keyword, eg:
03196      *   $previewUrl = t3lib_div::getIndpEnv('TYPO3_SITE_URL').'index.php?ADMCMD_prev='.t3lib_BEfunc::compilePreviewKeyword('id='.$pageId.'&L='.$language.'&ADMCMD_view=1&ADMCMD_editIcons=1&ADMCMD_previewWS='.$this->workspace, $GLOBALS['BE_USER']->user['uid'], 120);
03197      *
03198      * todo for sys_preview:
03199      * - Add a comment which can be shown to previewer in frontend in some way (plus maybe ability to write back, take other action?)
03200      * - Add possibility for the preview keyword to work in the backend as well: So it becomes a quick way to a certain action of sorts?
03201      *
03202      * @param   string      Get variables to preview, eg. 'id=1150&L=0&ADMCMD_view=1&ADMCMD_editIcons=1&ADMCMD_previewWS=8'
03203      * @param   string      32 byte MD5 hash keyword for the URL: "?ADMCMD_prev=[keyword]"
03204      * @param   integer     Time-To-Live for keyword
03205      * @param   integer     Which workspace to preview. Workspace UID, -1 or >0. If set, the getVars is ignored in the frontend, so that string can be empty
03206      * @return  string      Returns keyword to use in URL for ADMCMD_prev=
03207      */
03208     public static function compilePreviewKeyword($getVarsStr, $beUserUid, $ttl = 172800, $fullWorkspace = NULL) {
03209         $field_array = array(
03210             'keyword' => md5(uniqid(microtime())),
03211             'tstamp' => $GLOBALS['EXEC_TIME'],
03212             'endtime' => $GLOBALS['EXEC_TIME'] + $ttl,
03213             'config' => serialize(array(
03214                 'fullWorkspace' => $fullWorkspace,
03215                 'getVars' => $getVarsStr,
03216                 'BEUSER_uid' => $beUserUid
03217             ))
03218         );
03219 
03220         $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_preview', $field_array);
03221 
03222         return $field_array['keyword'];
03223     }
03224 
03225     /**
03226      * Unlock or Lock a record from $table with $uid
03227      * If $table and $uid is not set, then all locking for the current BE_USER is removed!
03228      * Usage: 5
03229      *
03230      * @param   string      Table name
03231      * @param   integer     Record uid
03232      * @param   integer     Record pid
03233      * @return  void
03234      * @internal
03235      * @see t3lib_transferData::lockRecord(), alt_doc.php, db_layout.php, db_list.php, wizard_rte.php
03236      */
03237     public static function lockRecords($table = '', $uid = 0, $pid = 0) {
03238         $user_id = intval($GLOBALS['BE_USER']->user['uid']);
03239         if ($table && $uid) {
03240             $fields_values = array(
03241                 'userid' => $user_id,
03242                 'feuserid' => 0,
03243                 'tstamp' => $GLOBALS['EXEC_TIME'],
03244                 'record_table' => $table,
03245                 'record_uid' => $uid,
03246                 'username' => $GLOBALS['BE_USER']->user['username'],
03247                 'record_pid' => $pid
03248             );
03249 
03250             $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_lockedrecords', $fields_values);
03251         } else {
03252             $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_lockedrecords', 'userid=' . intval($user_id));
03253         }
03254     }
03255 
03256     /**
03257      * Returns information about whether the record from table, $table, with uid, $uid is currently locked (edited by another user - which should issue a warning).
03258      * Notice: Locking is not strictly carried out since locking is abandoned when other backend scripts are activated - which means that a user CAN have a record "open" without having it locked. So this just serves as a warning that counts well in 90% of the cases, which should be sufficient.
03259      * Usage: 5
03260      *
03261      * @param   string      Table name
03262      * @param   integer     Record uid
03263      * @return  array
03264      * @internal
03265      * @see class.db_layout.inc, alt_db_navframe.php, alt_doc.php, db_layout.php
03266      */
03267     public static function isRecordLocked($table, $uid) {
03268         global $LOCKED_RECORDS;
03269         if (!is_array($LOCKED_RECORDS)) {
03270             $LOCKED_RECORDS = array();
03271             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
03272                 '*',
03273                 'sys_lockedrecords',
03274                     'sys_lockedrecords.userid!=' . intval($GLOBALS['BE_USER']->user['uid']) . '
03275                                 AND sys_lockedrecords.tstamp > ' . ($GLOBALS['EXEC_TIME'] - 2 * 3600)
03276             );
03277             while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
03278                     // Get the type of the user that locked this record:
03279                 if ($row['userid']) {
03280                     $userTypeLabel = 'beUser';
03281                 } elseif ($row['feuserid']) {
03282                     $userTypeLabel = 'feUser';
03283                 } else {
03284                     $userTypeLabel = 'user';
03285                 }
03286                 $userType = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.' . $userTypeLabel);
03287                     // Get the username (if available):
03288                 if ($row['username']) {
03289                     $userName = $row['username'];
03290                 } else {
03291                     $userName = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.unknownUser');
03292                 }
03293 
03294                 $LOCKED_RECORDS[$row['record_table'] . ':' . $row['record_uid']] = $row;
03295                 $LOCKED_RECORDS[$row['record_table'] . ':' . $row['record_uid']]['msg'] = sprintf(
03296                     $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.lockedRecordUser'),
03297                     $userType,
03298                     $userName,
03299                     self::calcAge($GLOBALS['EXEC_TIME'] - $row['tstamp'], $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears'))
03300                 );
03301                 if ($row['record_pid'] && !isset($LOCKED_RECORDS[$row['record_table'] . ':' . $row['record_pid']])) {
03302                     $LOCKED_RECORDS['pages:' . $row['record_pid']]['msg'] = sprintf(
03303                         $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.lockedRecordUser_content'),
03304                         $userType,
03305                         $userName,
03306                         self::calcAge($GLOBALS['EXEC_TIME'] - $row['tstamp'], $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears'))
03307                     );
03308                 }
03309             }
03310             $GLOBALS['TYPO3_DB']->sql_free_result($res);
03311         }
03312         return $LOCKED_RECORDS[$table . ':' . $uid];
03313     }
03314 
03315     /**
03316      * Returns select statement for MM relations (as used by TCEFORMs etc)
03317      * Usage: 3
03318      *
03319      * @param   array       Configuration array for the field, taken from $TCA
03320      * @param   string      Field name
03321      * @param   array       TSconfig array from which to get further configuration settings for the field name
03322      * @param   string      Prefix string for the key "*foreign_table_where" from $fieldValue array
03323      * @return  string      Part of query
03324      * @internal
03325      * @see t3lib_transferData::renderRecord(), t3lib_TCEforms::foreignTable()
03326      */
03327     public static function exec_foreign_table_where_query($fieldValue, $field = '', $TSconfig = array(), $prefix = '') {
03328         global $TCA;
03329 
03330         $foreign_table = $fieldValue['config'][$prefix . 'foreign_table'];
03331         t3lib_div::loadTCA($foreign_table);
03332         $rootLevel = $TCA[$foreign_table]['ctrl']['rootLevel'];
03333 
03334         $fTWHERE = $fieldValue['config'][$prefix . 'foreign_table_where'];
03335         if (strstr($fTWHERE, '###REC_FIELD_')) {
03336             $fTWHERE_parts = explode('###REC_FIELD_', $fTWHERE);
03337             foreach ($fTWHERE_parts as $kk => $vv) {
03338                 if ($kk) {
03339                     $fTWHERE_subpart = explode('###', $vv, 2);
03340                     if (substr($fTWHERE_parts[0], -1) === '\'' && $fTWHERE_subpart[1]{0} === '\'') {
03341                         $fTWHERE_parts[$kk] = $GLOBALS['TYPO3_DB']->quoteStr($TSconfig['_THIS_ROW'][$fTWHERE_subpart[0]], $foreign_table) . $fTWHERE_subpart[1];
03342                     } else {
03343                         $fTWHERE_parts[$kk] = $GLOBALS['TYPO3_DB']->fullQuoteStr($TSconfig['_THIS_ROW'][$fTWHERE_subpart[0]], $foreign_table) . $fTWHERE_subpart[1];
03344                     }
03345                 }
03346             }
03347             $fTWHERE = implode('', $fTWHERE_parts);
03348         }
03349 
03350         $fTWHERE = str_replace('###CURRENT_PID###', intval($TSconfig['_CURRENT_PID']), $fTWHERE);
03351         $fTWHERE = str_replace('###THIS_UID###', intval($TSconfig['_THIS_UID']), $fTWHERE);
03352         $fTWHERE = str_replace('###THIS_CID###', intval($TSconfig['_THIS_CID']), $fTWHERE);
03353         $fTWHERE = str_replace('###STORAGE_PID###', intval($TSconfig['_STORAGE_PID']), $fTWHERE);
03354         $fTWHERE = str_replace('###SITEROOT###', intval($TSconfig['_SITEROOT']), $fTWHERE);
03355         $fTWHERE = str_replace('###PAGE_TSCONFIG_ID###', intval($TSconfig[$field]['PAGE_TSCONFIG_ID']), $fTWHERE);
03356         $fTWHERE = str_replace('###PAGE_TSCONFIG_IDLIST###', $GLOBALS['TYPO3_DB']->cleanIntList($TSconfig[$field]['PAGE_TSCONFIG_IDLIST']), $fTWHERE);
03357         $fTWHERE = str_replace('###PAGE_TSCONFIG_STR###', $GLOBALS['TYPO3_DB']->quoteStr($TSconfig[$field]['PAGE_TSCONFIG_STR'], $foreign_table), $fTWHERE);
03358 
03359             // rootLevel = -1 is not handled 'properly' here - it goes as if it was rootLevel = 1 (that is pid=0)
03360         $wgolParts = $GLOBALS['TYPO3_DB']->splitGroupOrderLimit($fTWHERE);
03361         if ($rootLevel) {
03362             $queryParts = array(
03363                 'SELECT' => self::getCommonSelectFields($foreign_table, $foreign_table . '.'),
03364                 'FROM' => $foreign_table,
03365                 'WHERE' => $foreign_table . '.pid=0 ' .
03366                         self::deleteClause($foreign_table) . ' ' .
03367                         $wgolParts['WHERE'],
03368                 'GROUPBY' => $wgolParts['GROUPBY'],
03369                 'ORDERBY' => $wgolParts['ORDERBY'],
03370                 'LIMIT' => $wgolParts['LIMIT']
03371             );
03372         } else {
03373             $pageClause = $GLOBALS['BE_USER']->getPagePermsClause(1);
03374             if ($foreign_table != 'pages') {
03375                 $queryParts = array(
03376                     'SELECT' => self::getCommonSelectFields($foreign_table, $foreign_table . '.'),
03377                     'FROM' => $foreign_table . ', pages',
03378                     'WHERE' => 'pages.uid=' . $foreign_table . '.pid
03379                                 AND pages.deleted=0 ' .
03380                             self::deleteClause($foreign_table) .
03381                             ' AND ' . $pageClause . ' ' .
03382                             $wgolParts['WHERE'],
03383                     'GROUPBY' => $wgolParts['GROUPBY'],
03384                     'ORDERBY' => $wgolParts['ORDERBY'],
03385                     'LIMIT' => $wgolParts['LIMIT']
03386                 );
03387             } else {
03388                 $queryParts = array(
03389                     'SELECT' => self::getCommonSelectFields($foreign_table, $foreign_table . '.'),
03390                     'FROM' => 'pages',
03391                     'WHERE' => 'pages.deleted=0
03392                                 AND ' . $pageClause . ' ' .
03393                             $wgolParts['WHERE'],
03394                     'GROUPBY' => $wgolParts['GROUPBY'],
03395                     'ORDERBY' => $wgolParts['ORDERBY'],
03396                     'LIMIT' => $wgolParts['LIMIT']
03397                 );
03398             }
03399         }
03400 
03401         return $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($queryParts);
03402     }
03403 
03404     /**
03405      * Returns TSConfig for the TCEFORM object in Page TSconfig.
03406      * Used in TCEFORMs
03407      * Usage: 4
03408      *
03409      * @param   string      Table name present in TCA
03410      * @param   array       Row from table
03411      * @return  array
03412      * @see t3lib_transferData::renderRecord(), t3lib_TCEforms::setTSconfig(), SC_wizard_list::main(), SC_wizard_add::main()
03413      */
03414     public static function getTCEFORM_TSconfig($table, $row) {
03415         self::fixVersioningPid($table, $row);
03416 
03417         $res = array();
03418         $typeVal = self::getTCAtypeValue($table, $row);
03419 
03420             // Get main config for the table
03421         list($TScID, $cPid) = self::getTSCpid($table, $row['uid'], $row['pid']);
03422 
03423         $rootLine = self::BEgetRootLine($TScID, '', TRUE);
03424         if ($TScID >= 0) {
03425             $tempConf = $GLOBALS['BE_USER']->getTSConfig('TCEFORM.' . $table, self::getPagesTSconfig($TScID, $rootLine));
03426             if (is_array($tempConf['properties'])) {
03427                 foreach ($tempConf['properties'] as $key => $val) {
03428                     if (is_array($val)) {
03429                         $fieldN = substr($key, 0, -1);
03430                         $res[$fieldN] = $val;
03431                         unset($res[$fieldN]['types.']);
03432                         if (strcmp($typeVal, '') && is_array($val['types.'][$typeVal . '.'])) {
03433                             $res[$fieldN] = t3lib_div::array_merge_recursive_overrule($res[$fieldN], $val['types.'][$typeVal . '.']);
03434                         }
03435                     }
03436                 }
03437             }
03438         }
03439         $res['_CURRENT_PID'] = $cPid;
03440         $res['_THIS_UID'] = $row['uid'];
03441         $res['_THIS_CID'] = $row['cid'];
03442         $res['_THIS_ROW'] = $row; // So the row will be passed to foreign_table_where_query()
03443 
03444         foreach ($rootLine as $rC) {
03445             if (!$res['_STORAGE_PID']) {
03446                 $res['_STORAGE_PID'] = intval($rC['storage_pid']);
03447             }
03448             if (!$res['_SITEROOT']) {
03449                 $res['_SITEROOT'] = $rC['is_siteroot'] ? intval($rC['uid']) : 0;
03450             }
03451         }
03452 
03453         return $res;
03454     }
03455 
03456     /**
03457      * Find the real PID of the record (with $uid from $table). This MAY be impossible if the pid is set as a reference to the former record or a page (if two records are created at one time).
03458      * NOTICE: Make sure that the input PID is never negative because the record was an offline version! Therefore, you should always use t3lib_BEfunc::fixVersioningPid($table,$row); on the data you input before calling this function!
03459      * Usage: 2
03460      *
03461      * @param   string      Table name
03462      * @param   integer     Record uid
03463      * @param   integer     Record pid, could be negative then pointing to a record from same table whose pid to find and return.
03464      * @return  integer
03465      * @internal
03466      * @see t3lib_TCEmain::copyRecord(), getTSCpid()
03467      */
03468     public static function getTSconfig_pidValue($table, $uid, $pid) {
03469 
03470         if (t3lib_div::testInt($pid)) { // If pid is an integer this takes precedence in our lookup.
03471             $thePidValue = intval($pid);
03472             if ($thePidValue < 0) { // If ref to another record, look that record up.
03473                 $pidRec = self::getRecord($table, abs($thePidValue), 'pid');
03474                 $thePidValue = is_array($pidRec) ? $pidRec['pid'] : -2; // Returns -2 if the record did not exist.
03475             }
03476             // ... else the pos/zero pid is just returned here.
03477         } else { // No integer pid and we are forced to look up the $pid
03478             $rr = self::getRecord($table, $uid); // Try to fetch the record pid from uid. If the uid is 'NEW...' then this will of course return nothing...
03479 
03480             if (is_array($rr)) {
03481                     // First check if the pid is -1 which means it is a workspaced element. Get the "real" record:
03482                 if ($rr['pid'] == '-1') {
03483                     $rr = self::getRecord($table, $rr['t3ver_oid'], 'pid');
03484                     if (is_array($rr)) {
03485                         $thePidValue = $rr['pid'];
03486                     }
03487                 } else {
03488                     $thePidValue = $rr['pid']; // Returning the "pid" of the record
03489                 }
03490             }
03491 
03492             if (!$thePidValue) {
03493                 $thePidValue = -1;
03494             } // Returns -1 if the record with this pid was not found.
03495         }
03496 
03497         return $thePidValue;
03498     }
03499 
03500     /**
03501      * Return $uid if $table is pages and $uid is integer - otherwise the $pid
03502      * Usage: 1
03503      *
03504      * @param   string      Table name
03505      * @param   integer     Record uid
03506      * @param   integer     Record pid
03507      * @return  integer
03508      * @internal
03509      * @see t3lib_TCEforms::getTSCpid()
03510      */
03511     public static function getPidForModTSconfig($table, $uid, $pid) {
03512         $retVal = ($table == 'pages' && t3lib_div::testInt($uid)) ? $uid : $pid;
03513         return $retVal;
03514     }
03515 
03516     /**
03517      * Returns the REAL pid of the record, if possible. If both $uid and $pid is strings, then pid=-1 is returned as an error indication.
03518      * Usage: 8
03519      *
03520      * @param   string      Table name
03521      * @param   integer     Record uid
03522      * @param   integer     Record pid
03523      * @return  array       Array of two integers; first is the REAL PID of a record and if its a new record negative values are resolved to the true PID, second value is the PID value for TSconfig (uid if table is pages, otherwise the pid)
03524      * @internal
03525      * @see t3lib_TCEmain::setHistory(), t3lib_TCEmain::process_datamap()
03526      */
03527     public static function getTSCpid($table, $uid, $pid) {
03528             // If pid is negative (referring to another record) the pid of the other record is fetched and returned.
03529         $cPid = self::getTSconfig_pidValue($table, $uid, $pid);
03530             // $TScID is the id of $table = pages, else it's the pid of the record.
03531         $TScID = self::getPidForModTSconfig($table, $uid, $cPid);
03532 
03533         return array($TScID, $cPid);
03534     }
03535 
03536     /**
03537      * Returns first found domain record "domainName" (without trailing slash) if found in the input $rootLine
03538      * Usage: 2
03539      *
03540      * @param   array       Root line array
03541      * @return  string      Domain name, if found.
03542      */
03543     public static function firstDomainRecord($rootLine) {
03544         if (t3lib_extMgm::isLoaded('cms')) {
03545             foreach ($rootLine as $row) {
03546                 $dRec = self::getRecordsByField('sys_domain', 'pid', $row['uid'], ' AND redirectTo=\'\' AND hidden=0', '', 'sorting');
03547                 if (is_array($dRec)) {
03548                     reset($dRec);
03549                     $dRecord = current($dRec);
03550                     return rtrim($dRecord['domainName'], '/');
03551                 }
03552             }
03553         }
03554     }
03555 
03556     /**
03557      * Returns the sys_domain record for $domain, optionally with $path appended.
03558      * Usage: 2
03559      *
03560      * @param   string      Domain name
03561      * @param   string      Appended path
03562      * @return  array       Domain record, if found
03563      */
03564     public static function getDomainStartPage($domain, $path = '') {
03565         if (t3lib_extMgm::isLoaded('cms')) {
03566             $domain = explode(':', $domain);
03567             $domain = strtolower(preg_replace('/\.$/', '', $domain[0]));
03568                 // path is calculated.
03569             $path = trim(preg_replace('/\/[^\/]*$/', '', $path));
03570                 // stuff:
03571             $domain .= $path;
03572 
03573             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('sys_domain.*', 'pages,sys_domain', '
03574                 pages.uid=sys_domain.pid
03575                 AND sys_domain.hidden=0
03576                 AND (sys_domain.domainName=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($domain, 'sys_domain') . ' OR sys_domain.domainName=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($domain . '/', 'sys_domain') . ')' .
03577                     self::deleteClause('pages'),
03578                 '', '', '1');
03579             $result = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
03580             $GLOBALS['TYPO3_DB']->sql_free_result($res);
03581             return $result;
03582         }
03583     }
03584 
03585     /**
03586      * Returns overlayered RTE setup from an array with TSconfig. Used in TCEforms and TCEmain
03587      * Usage: 8
03588      *
03589      * @param   array       The properties of Page TSconfig in the key "RTE."
03590      * @param   string      Table name
03591      * @param   string      Field name
03592      * @param   string      Type value of the current record (like from CType of tt_content)
03593      * @return  array       Array with the configuration for the RTE
03594      * @internal
03595      */
03596     public static function RTEsetup($RTEprop, $table, $field, $type = '') {
03597         $thisConfig = is_array($RTEprop['default.']) ? $RTEprop['default.'] : array();
03598         $thisFieldConf = $RTEprop['config.'][$table . '.'][$field . '.'];
03599         if (is_array($thisFieldConf)) {
03600             unset($thisFieldConf['types.']);
03601             $thisConfig = t3lib_div::array_merge_recursive_overrule($thisConfig, $thisFieldConf);
03602         }
03603         if ($type && is_array($RTEprop['config.'][$table . '.'][$field . '.']['types.'][$type . '.'])) {
03604             $thisConfig = t3lib_div::array_merge_recursive_overrule($thisConfig, $RTEprop['config.'][$table . '.'][$field . '.']['types.'][$type . '.']);
03605         }
03606         return $thisConfig;
03607     }
03608 
03609     /**
03610      * Returns first possible RTE object if available.
03611      * Usage: $RTEobj = &t3lib_BEfunc::RTEgetObj();
03612      *
03613      * @return  mixed       If available, returns RTE object, otherwise an array of messages from possible RTEs
03614      */
03615     public static function &RTEgetObj() {
03616 
03617             // If no RTE object has been set previously, try to create it:
03618         if (!isset($GLOBALS['T3_VAR']['RTEobj'])) {
03619 
03620                 // Set the object string to blank by default:
03621             $GLOBALS['T3_VAR']['RTEobj'] = array();
03622 
03623                 // Traverse registered RTEs:
03624             if (is_array($GLOBALS['TYPO3_CONF_VARS']['BE']['RTE_reg'])) {
03625                 foreach ($GLOBALS['TYPO3_CONF_VARS']['BE']['RTE_reg'] as $extKey => $rteObjCfg) {
03626                     $rteObj = t3lib_div::getUserObj($rteObjCfg['objRef']);
03627                     if (is_object($rteObj)) {
03628                         if ($rteObj->isAvailable()) {
03629                             $GLOBALS['T3_VAR']['RTEobj'] = $rteObj;
03630                             break;
03631                         } else {
03632                             $GLOBALS['T3_VAR']['RTEobj'] = array_merge($GLOBALS['T3_VAR']['RTEobj'], $rteObj->errorLog);
03633                         }
03634                     }
03635                 }
03636             }
03637 
03638             if (!count($GLOBALS['T3_VAR']['RTEobj'])) {
03639                 $GLOBALS['T3_VAR']['RTEobj'][] = 'No RTEs configured at all';
03640             }
03641         }
03642 
03643             // Return RTE object (if any!)
03644         return $GLOBALS['T3_VAR']['RTEobj'];
03645     }
03646 
03647     /**
03648      * Returns soft-reference parser for the softRef processing type
03649      * Usage: $softRefObj = &t3lib_BEfunc::softRefParserObj('[parser key]');
03650      *
03651      * @param   string      softRef parser key
03652      * @return  mixed       If available, returns Soft link parser object.
03653      */
03654     public static function &softRefParserObj($spKey) {
03655 
03656             // If no softRef parser object has been set previously, try to create it:
03657         if (!isset($GLOBALS['T3_VAR']['softRefParser'][$spKey])) {
03658 
03659                 // Set the object string to blank by default:
03660             $GLOBALS['T3_VAR']['softRefParser'][$spKey] = '';
03661 
03662                 // Now, try to create parser object:
03663             $objRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser'][$spKey] ?
03664                     $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser'][$spKey] :
03665                     $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'][$spKey];
03666             if ($objRef) {
03667                 $softRefParserObj = t3lib_div::getUserObj($objRef, '');
03668                 if (is_object($softRefParserObj)) {
03669                     $GLOBALS['T3_VAR']['softRefParser'][$spKey] = $softRefParserObj;
03670                 }
03671             }
03672         }
03673 
03674             // Return RTE object (if any!)
03675         return $GLOBALS['T3_VAR']['softRefParser'][$spKey];
03676     }
03677 
03678     /**
03679      * Returns array of soft parser references
03680      *
03681      * @param   string      softRef parser list
03682      * @param   string      Table name
03683      * @param   string      Field name
03684      * @return  array       Array where the parser key is the key and the value is the parameter string
03685      */
03686     public static function explodeSoftRefParserList($parserList) {
03687 
03688             // Looking for global parsers:
03689         if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'])) {
03690             $parserList = implode(',', array_keys($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'])) . ',' . $parserList;
03691         }
03692 
03693             // Return immediately if list is blank:
03694         if (!strlen($parserList)) {
03695             return FALSE;
03696         }
03697 
03698             // Otherwise parse the list:
03699         $keyList = t3lib_div::trimExplode(',', $parserList, 1);
03700         $output = array();
03701 
03702         foreach ($keyList as $val) {
03703             $reg = array();
03704             if (preg_match('/^([[:alnum:]_-]+)\[(.*)\]$/', $val, $reg)) {
03705                 $output[$reg[1]] = t3lib_div::trimExplode(';', $reg[2], 1);
03706             } else {
03707                 $output[$val] = '';
03708             }
03709         }
03710         return $output;
03711     }
03712 
03713     /**
03714      * Returns true if $modName is set and is found as a main- or submodule in $TBE_MODULES array
03715      * Usage: 1
03716      *
03717      * @param   string      Module name
03718      * @return  boolean
03719      */
03720     public static function isModuleSetInTBE_MODULES($modName) {
03721         $loaded = array();
03722 
03723         foreach ($GLOBALS['TBE_MODULES'] as $mkey => $list) {
03724             $loaded[$mkey] = 1;
03725             if (!is_array($list) && trim($list)) {
03726                 $subList = t3lib_div::trimExplode(',', $list, 1);
03727                 foreach ($subList as $skey) {
03728                     $loaded[$mkey . '_' . $skey] = 1;
03729                 }
03730             }
03731         }
03732         return $modName && isset($loaded[$modName]);
03733     }
03734 
03735     /**
03736      * Counting references to a record/file
03737      *
03738      * @param   string      Table name (or "_FILE" if its a file)
03739      * @param   string      Reference: If table, then integer-uid, if _FILE, then file reference (relative to PATH_site)
03740      * @param   string      Message with %s, eg. "There were %s records pointing to this file!"
03741      * @param   string      reference count
03742      * @return  string      Output string (or integer count value if no msg string specified)
03743      */
03744     public static function referenceCount($table, $ref, $msg = '', $count = NULL) {
03745         if ($count === NULL) {
03746 
03747                 // Look up the path:
03748             if ($table == '_FILE') {
03749                 if (t3lib_div::isFirstPartOfStr($ref, PATH_site)) {
03750                     $ref = substr($ref, strlen(PATH_site));
03751                     $condition = 'ref_string=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($ref, 'sys_refindex');
03752                 } else {
03753                     return '';
03754                 }
03755             } else {
03756                 $condition = 'ref_uid=' . intval($ref);
03757             }
03758 
03759             $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows(
03760                 '*',
03761                 'sys_refindex',
03762                     'ref_table=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_refindex') .
03763                             ' AND ' . $condition .
03764                             ' AND deleted=0'
03765             );
03766         }
03767 
03768         return ($count ? ($msg ? sprintf($msg, $count) : $count) : '');
03769     }
03770 
03771 
03772     /**
03773      * Counting translations of records
03774      *
03775      * @param   string      Table name
03776      * @param   string      Reference: the record's uid
03777      * @param   string      Message with %s, eg. "This record has %s translation(s) which will be deleted, too!"
03778      * @return  string      Output string (or integer count value if no msg string specified)
03779      */
03780     public static function translationCount($table, $ref, $msg = '') {
03781         if (empty($GLOBALS['TCA'][$table]['ctrl']['transForeignTable']) &&
03782                 $GLOBALS['TCA'][$table]['ctrl']['languageField'] &&
03783                 $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] &&
03784                 !$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']) {
03785 
03786             $where = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . '=' . intval($ref) .
03787                     ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '!=0';
03788 
03789             if (!empty($GLOBALS['TCA'][$table]['ctrl']['delete'])) {
03790                 $where .= ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['delete'] . '=0';
03791             }
03792 
03793             $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows(
03794                 '*',
03795                 $table,
03796                 $where
03797             );
03798         }
03799 
03800         return ($count ? ($msg ? sprintf($msg, $count) : $count) : '');
03801     }
03802 
03803 
03804     /*******************************************
03805      *
03806      * Workspaces / Versioning
03807      *
03808      *******************************************/
03809 
03810     /**
03811      * Select all versions of a record, ordered by version id (DESC)
03812      *
03813      * @param   string      Table name to select from
03814      * @param   integer     Record uid for which to find versions.
03815      * @param   string      Field list to select
03816      * @param   integer     Workspace ID, if zero all versions regardless of workspace is found.
03817      * @param   boolean     If set, deleted-flagged versions are included! (Only for clean-up script!)
03818      * @param   array       The current record
03819      * @return  array       Array of versions of table/uid
03820      */
03821     public static function selectVersionsOfRecord($table, $uid, $fields = '*', $workspace = 0, $includeDeletedRecords = FALSE, $row = NULL) {
03822         global $TCA;
03823 
03824         $realPid = 0;
03825         $outputRows = array();
03826 
03827         if ($TCA[$table] && $TCA[$table]['ctrl']['versioningWS']) {
03828 
03829             if (is_array($row) && !$includeDeletedRecords) {
03830                 $row['_CURRENT_VERSION'] = TRUE;
03831                 $realPid = $row['pid'];
03832                 $outputRows[] = $row;
03833             } else {
03834                     // Select UID version:
03835                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
03836                     $fields,
03837                     $table,
03838                         'uid=' . intval($uid) .
03839                                 ($includeDeletedRecords ? '' : self::deleteClause($table))
03840                 );
03841 
03842                     // Add rows to output array:
03843                 if ($res) {
03844                     $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
03845                     if ($row) {
03846                         $row['_CURRENT_VERSION'] = TRUE;
03847                         $realPid = $row['pid'];
03848                         $outputRows[] = $row;
03849                     }
03850                     $GLOBALS['TYPO3_DB']->sql_free_result($res);
03851                 }
03852             }
03853 
03854                 // Select all offline versions of record:
03855             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
03856                 $fields,
03857                 $table,
03858                     'pid=-1 AND uid!=' . intval($uid) . ' AND t3ver_oid=' . intval($uid) . ($workspace != 0 ? ' AND t3ver_wsid=' . intval($workspace) : '') .
03859                             ($includeDeletedRecords ? '' : self::deleteClause($table)),
03860                 '',
03861                 't3ver_id DESC'
03862             );
03863 
03864                 // Add rows to output array:
03865             while (($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))) {
03866                 $outputRows[] = $row;
03867             }
03868 
03869             $GLOBALS['TYPO3_DB']->sql_free_result($res);
03870 
03871                 // Set real-pid:
03872             foreach ($outputRows as $idx => $oRow) {
03873                 $outputRows[$idx]['_REAL_PID'] = $realPid;
03874             }
03875 
03876             return $outputRows;
03877         }
03878     }
03879 
03880     /**
03881      * Find page-tree PID for versionized record
03882      * Will look if the "pid" value of the input record is -1 and if the table supports versioning - if so, it will translate the -1 PID into the PID of the original record
03883      * Used whenever you are tracking something back, like making the root line.
03884      * Will only translate if the workspace of the input record matches that of the current user (unless flag set)
03885      * Principle; Record offline! => Find online?
03886      *
03887      * @param   string      Table name
03888      * @param   array       Record array passed by reference. As minimum, "pid" and "uid" fields must exist! "t3ver_oid" and "t3ver_wsid" is nice and will save you a DB query.
03889      * @param   boolean     Ignore workspace match
03890      * @return  void        (Passed by ref). If the record had its pid corrected to the online versions pid, then "_ORIG_pid" is set to the original pid value (-1 of course). The field "_ORIG_pid" is used by various other functions to detect if a record was in fact in a versionized branch.
03891      * @see t3lib_page::fixVersioningPid()
03892      */
03893     public static function fixVersioningPid($table, &$rr, $ignoreWorkspaceMatch = FALSE) {
03894         global $TCA;
03895 
03896         if (t3lib_extMgm::isLoaded('version')) {
03897                 // Check that the input record is an offline version from a table that supports versioning:
03898             if (is_array($rr) && $rr['pid'] == -1 && $TCA[$table]['ctrl']['versioningWS']) {
03899 
03900                     // Check values for t3ver_oid and t3ver_wsid:
03901                 if (isset($rr['t3ver_oid']) && isset($rr['t3ver_wsid'])) { // If "t3ver_oid" is already a field, just set this:
03902                     $oid = $rr['t3ver_oid'];
03903                     $wsid = $rr['t3ver_wsid'];
03904                 } else { // Otherwise we have to expect "uid" to be in the record and look up based on this:
03905                     $newPidRec = self::getRecord($table, $rr['uid'], 't3ver_oid,t3ver_wsid');
03906                     if (is_array($newPidRec)) {
03907                         $oid = $newPidRec['t3ver_oid'];
03908                         $wsid = $newPidRec['t3ver_wsid'];
03909                     }
03910                 }
03911 
03912                     // If ID of current online version is found, look up the PID value of that:
03913                 if ($oid && ($ignoreWorkspaceMatch || !strcmp((int) $wsid, $GLOBALS['BE_USER']->workspace))) {
03914                     $oidRec = self::getRecord($table, $oid, 'pid');
03915                     if (is_array($oidRec)) {
03916                         $rr['_ORIG_pid'] = $rr['pid'];
03917                         $rr['pid'] = $oidRec['pid'];
03918                     }
03919                 }
03920             }
03921         }
03922     }
03923 
03924     /**
03925      * Workspace Preview Overlay
03926      * Generally ALWAYS used when records are selected based on uid or pid. If records are selected on other fields than uid or pid (eg. "email = ....") then usage might produce undesired results and that should be evaluated on individual basis.
03927      * Principle; Record online! => Find offline?
03928      * Recently, this function has been modified so it MAY set $row to FALSE. This happens if a version overlay with the move-id pointer is found in which case we would like a backend preview. In other words, you should check if the input record is still an array afterwards when using this function.
03929      *
03930      * @param   string      Table name
03931      * @param   array       Record array passed by reference. As minimum, the "uid", "pid" and "t3ver_swapmode" (pages) fields must exist! Fake fields cannot exist since the fields in the array is used as field names in the SQL look up. It would be nice to have fields like "t3ver_state" and "t3ver_mode_id" as well to avoid a new lookup inside movePlhOL().
03932      * @param   integer     Workspace ID, if not specified will use $GLOBALS['BE_USER']->workspace
03933      * @param   boolean     If true the function does not return a "pointer" row for moved records in a workspace
03934      * @return  void        (Passed by ref).
03935      * @see fixVersioningPid()
03936      */
03937     public static function workspaceOL($table, &$row, $wsid = -99, $unsetMovePointers = FALSE) {
03938         global $TCA;
03939         if (t3lib_extMgm::isLoaded('version')) {
03940 
03941             $previewMovePlaceholders = TRUE; // If this is false the placeholder is shown raw in the backend. I don't know if this move can be useful for users to toggle. Technically it can help debugging...
03942 
03943                 // Initialize workspace ID:
03944             if ($wsid == -99) {
03945                 $wsid = $GLOBALS['BE_USER']->workspace;
03946             }
03947 
03948                 // Check if workspace is different from zero and record is set:
03949             if ($wsid !== 0 && is_array($row)) {
03950 
03951                     // Check if input record is a move-placeholder and if so, find the pointed-to live record:
03952                 if ($previewMovePlaceholders) {
03953                     $orig_uid = $row['uid'];
03954                     $orig_pid = $row['pid'];
03955                     $movePldSwap = self::movePlhOL($table, $row);
03956                     #           if (!is_array($row)) return;
03957                 }
03958 
03959                 $wsAlt = self::getWorkspaceVersionOfRecord($wsid, $table, $row['uid'], implode(',', array_keys($row)));
03960 
03961                     // If version was found, swap the default record with that one.
03962                 if (is_array($wsAlt)) {
03963 
03964                         // Check if this is in move-state:
03965                     if ($previewMovePlaceholders && !$movePldSwap && ($table == 'pages' || (int) $TCA[$table]['ctrl']['versioningWS'] >= 2) && $unsetMovePointers) { // Only for WS ver 2... (moving)
03966 
03967                             // If t3ver_state is not found, then find it... (but we like best if it is here...)
03968                         if (!isset($wsAlt['t3ver_state'])) {
03969                             $stateRec = self::getRecord($table, $wsAlt['uid'], 't3ver_state');
03970                             $state = $stateRec['t3ver_state'];
03971                         } else {
03972                             $state = $wsAlt['t3ver_state'];
03973                         }
03974                         if ((int) $state === 4) {
03975                                 // TODO: Same problem as frontend in versionOL(). See TODO point there.
03976                             $row = FALSE;
03977                             return;
03978                         }
03979                     }
03980 
03981                         // Always correct PID from -1 to what it should be:
03982                     if (isset($wsAlt['pid'])) {
03983                         $wsAlt['_ORIG_pid'] = $wsAlt['pid']; // Keep the old (-1) - indicates it was a version...
03984                         $wsAlt['pid'] = $row['pid']; // Set in the online versions PID.
03985                     }
03986 
03987                         // For versions of single elements or page+content, swap UID and PID:
03988                     if ($table !== 'pages' || $wsAlt['t3ver_swapmode'] <= 0) {
03989                         $wsAlt['_ORIG_uid'] = $wsAlt['uid'];
03990                         $wsAlt['uid'] = $row['uid'];
03991 
03992                             // Backend css class:
03993                         $wsAlt['_CSSCLASS'] = $table === 'pages' && $wsAlt['t3ver_swapmode'] == 0 ? 'ver-page' : 'ver-element';
03994                     } else { // This is only for page-versions with BRANCH below!
03995                         $wsAlt['_ONLINE_uid'] = $row['uid'];
03996 
03997                             // Backend css class:
03998                         $wsAlt['_CSSCLASS'] = 'ver-branchpoint';
03999                         $wsAlt['_SUBCSSCLASS'] = 'ver-branch';
04000                     }
04001 
04002                         // Changing input record to the workspace version alternative:
04003                     $row = $wsAlt;
04004                 }
04005 
04006                     // If the original record was a move placeholder, the uid and pid of that is preserved here:
04007                 if ($movePldSwap) {
04008                     $row['_MOVE_PLH'] = TRUE;
04009                     $row['_MOVE_PLH_uid'] = $orig_uid;
04010                     $row['_MOVE_PLH_pid'] = $orig_pid;
04011                     $row['t3ver_state'] = 3; // For display; To make the icon right for the placeholder vs. the original
04012                 }
04013             }
04014         }
04015     }
04016 
04017     /**
04018      * Checks if record is a move-placeholder (t3ver_state==3) and if so it will set $row to be the pointed-to live record (and return TRUE)
04019      *
04020      * @param   string      Table name
04021      * @param   array       Row (passed by reference) - must be online record!
04022      * @return  boolean     True if overlay is made.
04023      * @see t3lib_page::movePlhOl()
04024      */
04025     public static function movePlhOL($table, &$row) {
04026         global $TCA;
04027 
04028         if ($table == 'pages' || (int) $TCA[$table]['ctrl']['versioningWS'] >= 2) { // Only for WS ver 2... (moving)
04029 
04030                 // If t3ver_move_id or t3ver_state is not found, then find it... (but we like best if it is here...)
04031             if (!isset($row['t3ver_move_id']) || !isset($row['t3ver_state'])) {
04032                 $moveIDRec = self::getRecord($table, $row['uid'], 't3ver_move_id, t3ver_state');
04033                 $moveID = $moveIDRec['t3ver_move_id'];
04034                 $state = $moveIDRec['t3ver_state'];
04035             } else {
04036                 $moveID = $row['t3ver_move_id'];
04037                 $state = $row['t3ver_state'];
04038             }
04039 
04040                 // Find pointed-to record.
04041             if ((int) $state === 3 && $moveID) {
04042                 if ($origRow = self::getRecord($table, $moveID, implode(',', array_keys($row)))) {
04043                     $row = $origRow;
04044                     return TRUE;
04045                 }
04046             }
04047         }
04048         return FALSE;
04049     }
04050 
04051     /**
04052      * Select the workspace version of a record, if exists
04053      *
04054      * @param   integer     Workspace ID
04055      * @param   string      Table name to select from
04056      * @param   integer     Record uid for which to find workspace version.
04057      * @param   string      Field list to select
04058      * @return  array       If found, return record, otherwise false
04059      */
04060     public static function getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields = '*') {
04061         global $TCA;
04062 
04063         if (t3lib_extMgm::isLoaded('version')) {
04064             if ($workspace !== 0 && $TCA[$table] && $TCA[$table]['ctrl']['versioningWS']) {
04065 
04066                     // Select workspace version of record:
04067                 $row = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
04068                     $fields,
04069                     $table,
04070                         'pid=-1 AND
04071                      t3ver_oid=' . intval($uid) . ' AND
04072                      t3ver_wsid=' . intval($workspace) .
04073                                 self::deleteClause($table)
04074                 );
04075 
04076                 if (is_array($row)) {
04077                     return $row;
04078                 }
04079             }
04080         }
04081         return FALSE;
04082     }
04083 
04084     /**
04085      * Returns live version of record
04086      *
04087      * @param   string      Table name
04088      * @param   integer     Record UID of draft, offline version
04089      * @param   string      Field list, default is *
04090      * @return  array       If found, the record, otherwise nothing.
04091      */
04092     public static function getLiveVersionOfRecord($table, $uid, $fields = '*') {
04093         $liveVersionId = self::getLiveVersionIdOfRecord($table, $uid);
04094 
04095         if (is_null($liveVersionId) === FALSE) {
04096             return self::getRecord($table, $liveVersionId, $fields);
04097         }
04098     }
04099 
04100     /**
04101      * Gets the id of the live version of a record.
04102      *
04103      * @param string $table Name of the table
04104      * @param integer $uid Uid of the offline/draft record
04105      * @return integer The id of the live version of the record (or NULL if nothing was found)
04106      */
04107     public static function getLiveVersionIdOfRecord($table, $uid) {
04108         $liveVersionId = NULL;
04109 
04110         if (self::isTableWorkspaceEnabled($table)) {
04111             $currentRecord = self::getRecord($table, $uid, 'pid,t3ver_oid');
04112             if (is_array($currentRecord) && $currentRecord['pid'] == -1) {
04113                 $liveVersionId = $currentRecord['t3ver_oid'];
04114             }
04115         }
04116 
04117         return $liveVersionId;
04118     }
04119 
04120     /**
04121      * Will fetch the rootline for the pid, then check if anywhere in the rootline there is a branch point and if so everything is allowed of course.
04122      * Alternatively; if the page of the PID itself is a version and swapmode is zero (page+content) then tables from versioning_followPages are allowed as well.
04123      *
04124      * @param   integer     Page id inside of which you want to edit/create/delete something.
04125      * @param   string      Table name you are checking for. If you don't give the table name ONLY "branch" types are found and returned true. Specifying table you might also get a positive response if the pid is a "page" versioning type AND the table has "versioning_followPages" set.
04126      * @param   boolean     If set, the keyword "branchpoint" or "first" is not returned by rather the "t3ver_stage" value of the branch-point.
04127      * @return  mixed       Returns either "branchpoint" (if branch) or "first" (if page) or false if nothing. Alternatively, it returns the value of "t3ver_stage" for the branchpoint (if any)
04128      */
04129     public static function isPidInVersionizedBranch($pid, $table = '', $returnStage = FALSE) {
04130         $rl = self::BEgetRootLine($pid);
04131         $c = 0;
04132 
04133         foreach ($rl as $rec) {
04134             if ($rec['_ORIG_pid'] == -1) {
04135                     // In any case: is it a branchpoint, then OK...
04136                 if ($rec['t3ver_swapmode'] > 0) {
04137                     return $returnStage ? (int) $rec['t3ver_stage'] : 'branchpoint'; // OK, we are in a versionized branch
04138                 } elseif ($c == 0 && $rec['t3ver_swapmode'] == 0 && $table && $GLOBALS['TCA'][$table]['ctrl']['versioning_followPages']) { // First level: So $table must be versioning_followPages
04139                     return $returnStage ? (int) $rec['t3ver_stage'] : 'first'; // OK, we are in a versionized branch
04140                 }
04141             }
04142             $c++;
04143         }
04144     }
04145 
04146     /**
04147      * Will return where clause de-selecting new(/deleted)-versions from other workspaces.
04148      * If in live-workspace, don't show "MOVE-TO-PLACEHOLDERS" records if versioningWS is 2 (allows moving)
04149      *
04150      * @param   string      Table name
04151      * @return  string      Where clause if applicable.
04152      */
04153     public static function versioningPlaceholderClause($table) {
04154         if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
04155             $currentWorkspace = intval($GLOBALS['BE_USER']->workspace);
04156             return ' AND (' . $table . '.t3ver_state <= 0 OR ' . $table . '.t3ver_wsid = ' . $currentWorkspace . ')';
04157         }
04158     }
04159 
04160     /**
04161      * Get additional where clause to select records of a specific workspace (includes live as well).
04162      *
04163      * @param  $table
04164      * @param  $workspaceId
04165      * @return string
04166      */
04167     public static function getWorkspaceWhereClause($table, $workspaceId = NULL) {
04168         $whereClause = '';
04169 
04170         if (is_null($workspaceId)) {
04171             $workspaceId = $GLOBALS['BE_USER']->workspace;
04172         }
04173 
04174         if (self::isTableWorkspaceEnabled($table)) {
04175             $workspaceId = intval($workspaceId);
04176             $pidOperator = ($workspaceId === 0 ? '!=' : '=');
04177             $whereClause = ' AND ' . $table . '.t3ver_wsid=' . $workspaceId . ' AND ' . $table . '.pid' . $pidOperator . '-1';
04178         }
04179 
04180         return $whereClause;
04181     }
04182 
04183     /**
04184      * Count number of versions on a page
04185      *
04186      * @param   integer     Workspace ID
04187      * @param   integer     Page ID
04188      * @param   boolean     If set, then all tables and not only "versioning_followPages" are found (except other pages)
04189      * @return  array       Overview of records
04190      */
04191     public static function countVersionsOfRecordsOnPage($workspace, $pageId, $allTables = FALSE) {
04192         $output = array();
04193         if ($workspace != 0) {
04194             foreach ($GLOBALS['TCA'] as $tableName => $cfg) {
04195                 if ($tableName != 'pages' && $cfg['ctrl']['versioningWS'] && ($cfg['ctrl']['versioning_followPages'] || $allTables)) {
04196 
04197                         // Select all records from this table in the database from the workspace
04198                         // This joins the online version with the offline version as tables A and B
04199                     $output[$tableName] = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
04200                         'B.uid as live_uid, A.uid as offline_uid',
04201                             $tableName . ' A,' . $tableName . ' B',
04202                             'A.pid=-1' . // Table A is the offline version and pid=-1 defines offline
04203                                     ' AND B.pid=' . intval($pageId) .
04204                                     ' AND A.t3ver_wsid=' . intval($workspace) .
04205                                     ' AND A.t3ver_oid=B.uid' . // ... and finally the join between the two tables.
04206                                     self::deleteClause($tableName, 'A') .
04207                                     self::deleteClause($tableName, 'B')
04208                     );
04209 
04210                     if (!is_array($output[$tableName]) || !count($output[$tableName])) {
04211                         unset($output[$tableName]);
04212                     }
04213                 }
04214             }
04215         }
04216         return $output;
04217     }
04218 
04219     /**
04220      * Performs mapping of new uids to new versions UID in case of import inside a workspace.
04221      *
04222      * @param   string      Table name
04223      * @param   integer     Record uid (of live record placeholder)
04224      * @return  integer     Uid of offline version if any, otherwise live uid.
04225      */
04226     public static function wsMapId($table, $uid) {
04227         if ($wsRec = self::getWorkspaceVersionOfRecord($GLOBALS['BE_USER']->workspace, $table, $uid, 'uid')) {
04228             return $wsRec['uid'];
04229         } else {
04230             return $uid;
04231         }
04232     }
04233 
04234     /**
04235      * Returns move placeholder of online (live) version
04236      *
04237      * @param   string      Table name
04238      * @param   integer     Record UID of online version
04239      * @param   string      Field list, default is *
04240      * @return  array       If found, the record, otherwise nothing.
04241      */
04242     public static function getMovePlaceholder($table, $uid, $fields = '*') {
04243         global $TCA;
04244 
04245         $workspace = $GLOBALS['BE_USER']->workspace;
04246         if ($workspace !== 0 && $TCA[$table] && (int) $TCA[$table]['ctrl']['versioningWS'] >= 2) {
04247 
04248                 // Select workspace version of record:
04249             $row = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
04250                 $fields,
04251                 $table,
04252                     'pid!=-1 AND
04253                  t3ver_state=3 AND
04254                  t3ver_move_id=' . intval($uid) . ' AND
04255                  t3ver_wsid=' . intval($workspace) .
04256                             self::deleteClause($table)
04257             );
04258 
04259             if (is_array($row)) {
04260                 return $row;
04261             }
04262         }
04263 
04264         return FALSE;
04265     }
04266 
04267 
04268     /*******************************************
04269      *
04270      * Miscellaneous
04271      *
04272      *******************************************/
04273 
04274     /**
04275      * Print error message with header, text etc.
04276      * Usage: 19
04277      *
04278      * @param   string      Header string
04279      * @param   string      Content string
04280      * @param   boolean     Will return an alert() with the content of header and text.
04281      * @param   boolean     Print header.
04282      * @return  void
04283      * @deprecated since TYPO3 4.5, will be removed in TYPO3 4.7 - use RuntimeException from now on
04284      */
04285     public static function typo3PrintError($header, $text, $js = '', $head = 1) {
04286             // This prints out a TYPO3 error message.
04287             // If $js is set the message will be output in JavaScript
04288         if ($js) {
04289             echo "alert('" . t3lib_div::slashJS($header . '\n' . $text) . "');";
04290         } else {
04291             t3lib_div::logDeprecatedFunction();
04292             $messageObj = t3lib_div::makeInstance('t3lib_message_ErrorPageMessage', $text, $header);
04293             $messageObj->output();
04294         }
04295     }
04296 
04297     /**
04298      * Prints TYPO3 Copyright notice for About Modules etc. modules.
04299      *
04300      * @return  void
04301      */
04302     public static function TYPO3_copyRightNotice() {
04303         global $TYPO3_CONF_VARS;
04304 
04305             // COPYRIGHT NOTICE:
04306         $loginCopyrightWarrantyProvider = strip_tags(trim($TYPO3_CONF_VARS['SYS']['loginCopyrightWarrantyProvider']));
04307         $loginCopyrightWarrantyURL = strip_tags(trim($TYPO3_CONF_VARS['SYS']['loginCopyrightWarrantyURL']));
04308 
04309         if (strlen($loginCopyrightWarrantyProvider) >= 2 && strlen($loginCopyrightWarrantyURL) >= 10) {
04310             $warrantyNote = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_login.xml:warranty.by'),
04311                 htmlspecialchars($loginCopyrightWarrantyProvider),
04312                     '<a href="' . htmlspecialchars($loginCopyrightWarrantyURL) . '" target="_blank">', '</a>'
04313             );
04314         } else {
04315             $warrantyNote = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_login.xml:no.warranty'),
04316                 '<a href="' . TYPO3_URL_LICENSE . '" target="_blank">', '</a>'
04317             );
04318         }
04319         $cNotice = '<a href="http://typo3.com/" target="_blank">' .
04320                 '<img' . t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'], 'gfx/loginlogo_transp.gif', 'width="75" height="19" vspace="2" hspace="4"') . ' alt="' .
04321                 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_login.xml:typo3.logo') . '" align="left" />' .
04322                 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_login.xml:typo3.cms') . ' ' .
04323                 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_login.xml:version.short') . ' ' .
04324                 htmlspecialchars(TYPO3_version) . '</a>. ' .
04325                 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_login.xml:copyright') . ' &copy; ' .
04326                 htmlspecialchars(TYPO3_copyright_year) . ' Kasper Sk&aring;rh&oslash;j. ' .
04327                 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_login.xml:extension.copyright') . ' ' .
04328                 sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_login.xml:details.link'),
04329                     '<a href="' . TYPO3_URL_GENERAL . '" target="_blank">' . TYPO3_URL_GENERAL . '</a>'
04330                 ) . ' ' .
04331                 strip_tags($warrantyNote, '<a>') . ' ' .
04332                 sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_login.xml:free.software'),
04333                     '<a href="' . TYPO3_URL_LICENSE . '" target="_blank">', '</a> '
04334                 ) .
04335                 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_login.xml:keep.notice');
04336 
04337         return $cNotice;
04338     }
04339 
04340     /**
04341      * Display some warning messages if this installation is obviously insecure!!
04342      * These warnings are only displayed to admin users
04343      *
04344      * @return  void
04345      */
04346     public static function displayWarningMessages() {
04347         if ($GLOBALS['BE_USER']->isAdmin()) {
04348             $warnings = array(); // Array containing warnings that must be displayed
04349             $enableInstallToolFile = PATH_site . 'typo3conf/ENABLE_INSTALL_TOOL'; // If this file exists and it isn't older than one hour, the Install Tool is enabled
04350 
04351             $cmd = t3lib_div::_GET('adminWarning_cmd'); // Cleanup command, if set
04352             switch ($cmd) {
04353                 case 'remove_ENABLE_INSTALL_TOOL':
04354                     if (unlink($enableInstallToolFile)) {
04355                         unset($enableInstallToolFile);
04356                     }
04357                     break;
04358             }
04359 
04360                 // Check if the Install Tool Password is still default: joh316
04361             if ($GLOBALS['TYPO3_CONF_VARS']['BE']['installToolPassword'] == md5('joh316')) {
04362                 $url = 'install/index.php?redirect_url=index.php' . urlencode('?TYPO3_INSTALL[type]=about');
04363                 $warnings["install_password"] = sprintf(
04364                     $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_password'),
04365                         '<a href="' . $url . '">',
04366                     '</a>');
04367             }
04368 
04369                 // Check if there is still a default user 'admin' with password 'password' (MD5sum = 5f4dcc3b5aa765d61d8327deb882cf99)
04370             $where_clause = 'username=' . $GLOBALS['TYPO3_DB']->fullQuoteStr('admin', 'be_users') . ' AND password=' .
04371                     $GLOBALS['TYPO3_DB']->fullQuoteStr('5f4dcc3b5aa765d61d8327deb882cf99', 'be_users') . self::deleteClause('be_users');
04372             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid, username, password', 'be_users', $where_clause);
04373             if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
04374                 $url = 'alt_doc.php?returnUrl=alt_intro.php&edit[be_users][' . $row['uid'] . ']=edit';
04375                 $warnings["backend_admin"] = sprintf(
04376                     $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.backend_admin'),
04377                         '<a href="' . htmlspecialchars($url) . '">',
04378                     '</a>');
04379 
04380             }
04381             $GLOBALS['TYPO3_DB']->sql_free_result($res);
04382 
04383                 // Check whether the file ENABLE_INSTALL_TOOL contains the string "KEEP_FILE" which permanently unlocks the install tool
04384             if (is_file($enableInstallToolFile) && trim(file_get_contents($enableInstallToolFile)) === 'KEEP_FILE') {
04385                 $url = t3lib_div::getIndpEnv('TYPO3_REQUEST_SCRIPT') . '?adminWarning_cmd=remove_ENABLE_INSTALL_TOOL';
04386                 $warnings['install_enabled'] = sprintf(
04387                     $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_enabled'),
04388                         '<span style="white-space:nowrap;">' . $enableInstallToolFile . '</span>');
04389                 $warnings['install_enabled'] .= ' <a href="' . $url . '">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_enabled_cmd') . '</a>';
04390             }
04391 
04392                 // Check if the encryption key is empty
04393             if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] == '') {
04394                 $url = 'install/index.php?redirect_url=index.php' . urlencode('?TYPO3_INSTALL[type]=config#set_encryptionKey');
04395                 $warnings["install_encryption"] = sprintf(
04396                     $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_encryption'),
04397                         '<a href="' . $url . '">',
04398                     '</a>');
04399             }
04400 
04401                 // Check if fileDenyPattern was changed which is dangerous on Apache
04402             if ($GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] != FILE_DENY_PATTERN_DEFAULT) {
04403                 $warnings['file_deny_pattern'] = sprintf(
04404                     $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.file_deny_pattern'),
04405                         '<br /><pre>' . htmlspecialchars(FILE_DENY_PATTERN_DEFAULT) . '</pre><br />');
04406             }
04407 
04408                 // Check if fileDenyPattern allows to upload .htaccess files which is dangerous on Apache
04409             if ($GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] != FILE_DENY_PATTERN_DEFAULT && t3lib_div::verifyFilenameAgainstDenyPattern(".htaccess")) {
04410                 $warnings['file_deny_htaccess'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.file_deny_htaccess');
04411             }
04412 
04413                 // Check if there are still updates to perform
04414             if (!t3lib_div::compat_version(TYPO3_branch)) {
04415                 $url = 'install/index.php?redirect_url=index.php' . urlencode('?TYPO3_INSTALL[type]=update');
04416                 $warnings["install_update"] = sprintf(
04417                     $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_update'),
04418                         '<a href="' . $url . '">',
04419                     '</a>');
04420             }
04421 
04422                 // Check if sys_refindex is empty
04423             $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', 'sys_refindex');
04424             $registry = t3lib_div::makeInstance('t3lib_Registry');
04425             $lastRefIndexUpdate = $registry->get('core', 'sys_refindex_lastUpdate');
04426             if (!$count && $lastRefIndexUpdate) {
04427                 $url = 'sysext/lowlevel/dbint/index.php?&id=0&SET[function]=refindex';
04428                 $warnings["backend_reference"] = sprintf(
04429                     $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.backend_reference_index'),
04430                         '<a href="' . $url . '">',
04431                     '</a>',
04432                     self::dateTime($lastRefIndexUpdate));
04433             }
04434 
04435                 // Check for memcached if configured
04436             $memCacheUse = FALSE;
04437             if (is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'])) {
04438                 foreach ($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'] as $table => $conf) {
04439                     if (is_array($conf)) {
04440                         foreach ($conf as $key => $value) {
04441                             if (!is_array($value) && $value === 't3lib_cache_backend_MemcachedBackend') {
04442                                 $servers = $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$table]['options']['servers'];
04443                                 $memCacheUse = TRUE;
04444                                 break;
04445                             }
04446                         }
04447                     }
04448                 }
04449                 if ($memCacheUse) {
04450                     $failed = array();
04451                     $defaultPort = ini_get('memcache.default_port');
04452                     if (function_exists('memcache_connect')) {
04453                         if (is_array($servers)) {
04454                             foreach ($servers as $testServer) {
04455                                 $configuredServer = $testServer;
04456                                 if (substr($testServer, 0, 7) == 'unix://') {
04457                                     $host = $testServer;
04458                                     $port = 0;
04459                                 } else {
04460                                     if (substr($testServer, 0, 6) === 'tcp://') {
04461                                         $testServer = substr($testServer, 6);
04462                                     }
04463                                     if (strstr($testServer, ':') !== FALSE) {
04464                                         list($host, $port) = explode(':', $testServer, 2);
04465                                     } else {
04466                                         $host = $testServer;
04467                                         $port = $defaultPort;
04468                                     }
04469                                 }
04470                                 $memcache_obj = @memcache_connect($host, $port);
04471                                 if ($memcache_obj != null) {
04472                                     memcache_close($memcache_obj);
04473                                 } else {
04474                                     $failed[] = $configuredServer;
04475                                 }
04476                             }
04477                         }
04478                     }
04479                     if (count($failed) > 0) {
04480                         $warnings['memcached'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.memcache_not_usable') . '<br/>' .
04481                                 implode(', ', $failed);
04482                     }
04483                 }
04484             }
04485 
04486                 // Hook for additional warnings
04487             if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['displayWarningMessages'])) {
04488                 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['displayWarningMessages'] as $classRef) {
04489                     $hookObj = t3lib_div::getUserObj($classRef);
04490                     if (method_exists($hookObj, 'displayWarningMessages_postProcess')) {
04491                         $hookObj->displayWarningMessages_postProcess($warnings);
04492                     }
04493                 }
04494             }
04495 
04496             if (count($warnings)) {
04497                 $style = ' style="margin-bottom:10px;"';
04498                 $securityWarnings = '<ul><li' . $style . '>'
04499                         . implode('</li><li' . $style . '>', $warnings)
04500                         . '</li></ul>';
04501 
04502                 $securityMessage = t3lib_div::makeInstance(
04503                     't3lib_FlashMessage',
04504                     $securityWarnings,
04505                     $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.header'),
04506                     t3lib_FlashMessage::ERROR
04507                 );
04508                 $content = '<div style="margin: 20px 0px;">'
04509                         . $securityMessage->render()
04510                         . '</div>';
04511 
04512                 unset($warnings);
04513                 return $content;
04514             }
04515         }
04516         return '<p>&nbsp;</p>';
04517     }
04518 
04519     /**
04520      * Returns "web" if the $path (absolute) is within the DOCUMENT ROOT - and thereby qualifies as a "web" folder.
04521      * Usage: 4
04522      *
04523      * @param   string      Path to evaluate
04524      * @return  boolean
04525      */
04526     public static function getPathType_web_nonweb($path) {
04527         return t3lib_div::isFirstPartOfStr($path, t3lib_div::getIndpEnv('TYPO3_DOCUMENT_ROOT')) ? 'web' : '';
04528     }
04529 
04530     /**
04531      * Creates ADMCMD parameters for the "viewpage" extension / "cms" frontend
04532      * Usage: 1
04533      *
04534      * @param   array       Page record
04535      * @return  string      Query-parameters
04536      * @internal
04537      */
04538     public static function ADMCMD_previewCmds($pageinfo) {
04539         if ($pageinfo['fe_group'] > 0) {
04540             $simUser = '&ADMCMD_simUser=' . $pageinfo['fe_group'];
04541         }
04542         if ($pageinfo['starttime'] > $GLOBALS['EXEC_TIME']) {
04543             $simTime = '&ADMCMD_simTime=' . $pageinfo['starttime'];
04544         }
04545         if ($pageinfo['endtime'] < $GLOBALS['EXEC_TIME'] && $pageinfo['endtime'] != 0) {
04546             $simTime = '&ADMCMD_simTime=' . ($pageinfo['endtime'] - 1);
04547         }
04548         return $simUser . $simTime;
04549     }
04550 
04551     /**
04552      * Returns an array with key=>values based on input text $params
04553      * $params is exploded by line-breaks and each line is supposed to be on the syntax [key] = [some value]
04554      * These pairs will be parsed into an array an returned.
04555      * Usage: 1
04556      *
04557      * @param   string      String of parameters on multiple lines to parse into key-value pairs (see function description)
04558      * @return  array
04559      */
04560     public static function processParams($params) {
04561         $paramArr = array();
04562         $lines = explode(LF, $params);
04563         foreach ($lines as $val) {
04564             $val = trim($val);
04565             if ($val) {
04566                 $pair = explode('=', $val, 2);
04567                 $paramArr[trim($pair[0])] = trim($pair[1]);
04568             }
04569         }
04570         return $paramArr;
04571     }
04572 
04573     /**
04574      * Returns the name of the backend script relative to the TYPO3 main directory.
04575      *
04576      * @param   string      Name of the backend interface  (backend, frontend) to look up the script name for. If no interface is given, the interface for the current backend user is used.
04577      * @return  string      The name of the backend script relative to the TYPO3 main directory.
04578      */
04579     public static function getBackendScript($interface = '') {
04580         if (!$interface) {
04581             $interface = $GLOBALS['BE_USER']->uc['interfaceSetup'];
04582         }
04583 
04584         switch ($interface) {
04585             case 'frontend':
04586                 $script = '../.';
04587                 break;
04588             case 'backend':
04589             default:
04590                 $script = 'backend.php';
04591                 break;
04592         }
04593 
04594         return $script;
04595     }
04596 
04597     /**
04598      * Determines whether a table is enabled for workspaces.
04599      *
04600      * @param  $table Name of the table to be checked
04601      * @return boolean
04602      */
04603     public static function isTableWorkspaceEnabled($table) {
04604         return (isset($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) && $GLOBALS['TCA'][$table]['ctrl']['versioningWS']);
04605     }
04606 
04607     /**
04608      * Gets the TCA configuration of a field.
04609      *
04610      * @param string $table Name of the table
04611      * @param string $field Name of the field
04612      * @return array
04613      */
04614     public static function getTcaFieldConfiguration($table, $field) {
04615         $configuration = array();
04616         t3lib_div::loadTCA($table);
04617 
04618         if (isset($GLOBALS['TCA'][$table]['columns'][$field]['config'])) {
04619             $configuration = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
04620         }
04621 
04622         return $configuration;
04623     }
04624 }
04625 
04626 ?>