class.t3lib_befunc.php

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