TYPO3 API  SVNRelease
class.t3lib_page.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003  *  Copyright notice
00004  *
00005  *  (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
00006  *  All rights reserved
00007  *
00008  *  This script is part of the TYPO3 project. The TYPO3 project is
00009  *  free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  The GNU General Public License can be found at
00015  *  http://www.gnu.org/copyleft/gpl.html.
00016  *  A copy is found in the textfile GPL.txt and important notices to the license
00017  *  from the author is found in LICENSE.txt distributed with these scripts.
00018  *
00019  *
00020  *  This script is distributed in the hope that it will be useful,
00021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  *  GNU General Public License for more details.
00024  *
00025  *  This copyright notice MUST APPEAR in all copies of the script!
00026  ***************************************************************/
00027 /**
00028  * Contains a class with "Page functions" mainly for the frontend
00029  *
00030  * $Id: class.t3lib_page.php 10478 2011-02-17 11:08:43Z ohader $
00031  * Revised for TYPO3 3.6 2/2003 by Kasper Skårhøj
00032  * XHTML-trans compliant
00033  *
00034  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00035  */
00036 /**
00037  * [CLASS/FUNCTION INDEX of SCRIPT]
00038  *
00039  *
00040  *
00041  *  109: class t3lib_pageSelect
00042  *  134:     function init($show_hidden)
00043  *
00044  *            SECTION: Selecting page records
00045  *  184:     function getPage($uid, $disableGroupAccessCheck=FALSE)
00046  *  200:     function getPage_noCheck($uid)
00047  *  216:     function getFirstWebPage($uid)
00048  *  234:     function getPageIdFromAlias($alias)
00049  *  250:     function getPageOverlay($pageInput,$lUid=-1)
00050  *  314:     function getRecordOverlay($table,$row,$sys_language_content,$OLmode='')
00051  *
00052  *            SECTION: Page related: Menu, Domain record, Root line
00053  *  413:     function getMenu($uid,$fields='*',$sortField='sorting',$addWhere='',$checkShortcuts=1)
00054  *  471:     function getDomainStartPage($domain, $path='',$request_uri='')
00055  *  519:     function getRootLine($uid, $MP='', $ignoreMPerrors=FALSE)
00056  *  640:     function getPathFromRootline($rl,$len=20)
00057  *  661:     function getExtURL($pagerow,$disable=0)
00058  *  685:     function getMountPointInfo($pageId, $pageRec=FALSE, $prevMountPids=array(), $firstPageUid=0)
00059  *
00060  *            SECTION: Selecting records in general
00061  *  762:     function checkRecord($table,$uid,$checkPage=0)
00062  *  797:     function getRawRecord($table,$uid,$fields='*',$noWSOL=FALSE)
00063  *  823:     function getRecordsByField($theTable,$theField,$theValue,$whereClause='',$groupBy='',$orderBy='',$limit='')
00064  *
00065  *            SECTION: Caching and standard clauses
00066  *  875:     function getHash($hash)
00067  *  898:     function storeHash($hash,$data,$ident)
00068  *  916:     function deleteClause($table)
00069  *  936:     function enableFields($table,$show_hidden=-1,$ignore_array=array(),$noVersionPreview=FALSE)
00070  * 1008:     function getMultipleGroupsWhereClause($field, $table)
00071  *
00072  *            SECTION: Versioning Preview
00073  * 1055:     function fixVersioningPid($table,&$rr)
00074  * 1096:     function versionOL($table,&$row)
00075  * 1151:     function getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields='*')
00076  *
00077  * TOTAL FUNCTIONS: 24
00078  * (This index is automatically created/updated by the extension "extdeveval")
00079  *
00080  */
00081 
00082 
00083 /**
00084  * Page functions, a lot of sql/pages-related functions
00085  * Mainly used in the frontend but also in some cases in the backend.
00086  * It's important to set the right $where_hid_del in the object so that the functions operate properly
00087  *
00088  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00089  * @package TYPO3
00090  * @subpackage t3lib
00091  * @see tslib_fe::fetch_the_id()
00092  */
00093 class t3lib_pageSelect {
00094     var $urltypes = Array('', 'http://', 'ftp://', 'mailto:', 'https://');
00095     var $where_hid_del = ' AND pages.deleted=0'; // This is not the final clauses. There will normally be conditions for the hidden,starttime and endtime fields as well. You MUST initialize the object by the init() function
00096     var $where_groupAccess = ''; // Clause for fe_group access
00097     var $sys_language_uid = 0;
00098 
00099         // Versioning preview related:
00100     var $versioningPreview = FALSE; // If true, versioning preview of other record versions is allowed. THIS MUST ONLY BE SET IF the page is not cached and truely previewed by a backend user!!!
00101     var $versioningWorkspaceId = 0; // Workspace ID for preview
00102     var $workspaceCache = array();
00103 
00104 
00105         // Internal, dynamic:
00106     var $error_getRootLine = ''; // Error string set by getRootLine()
00107     var $error_getRootLine_failPid = 0; // Error uid set by getRootLine()
00108 
00109         // Internal caching
00110     protected $cache_getRootLine = array();
00111     protected $cache_getPage = array();
00112     protected $cache_getPage_noCheck = array();
00113     protected $cache_getPageIdFromAlias = array();
00114     protected $cache_getMountPointInfo = array();
00115 
00116     /**
00117      * Named constants for "magic numbers" of the field doktype
00118      */
00119     const DOKTYPE_DEFAULT = 1;
00120     const DOKTYPE_ADVANCED = 2; // @deprecated since TYPO3 4.2
00121     const DOKTYPE_LINK = 3;
00122     const DOKTYPE_SHORTCUT = 4;
00123     const DOKTYPE_HIDE_IN_MENU = 5; // @deprecated since TYPO3 4.2
00124     const DOKTYPE_BE_USER_SECTION = 6;
00125     const DOKTYPE_MOUNTPOINT = 7;
00126     const DOKTYPE_SPACER = 199;
00127     const DOKTYPE_SYSFOLDER = 254;
00128     const DOKTYPE_RECYCLER = 255;
00129 
00130 
00131     /**
00132      * Named constants for "magic numbers" of the field shortcut_mode
00133      */
00134     const SHORTCUT_MODE_NONE = 0;
00135     const SHORTCUT_MODE_FIRST_SUBPAGE = 1;
00136     const SHORTCUT_MODE_RANDOM_SUBPAGE = 2;
00137     const SHORTCUT_MODE_PARENT_PAGE = 3;
00138 
00139     /**
00140      * init() MUST be run directly after creating a new template-object
00141      * This sets the internal variable $this->where_hid_del to the correct where clause for page records taking deleted/hidden/starttime/endtime/t3ver_state into account
00142      *
00143      * @param   boolean     If $show_hidden is true, the hidden-field is ignored!! Normally this should be false. Is used for previewing.
00144      * @return  void
00145      * @see tslib_fe::fetch_the_id(), tx_tstemplateanalyzer::initialize_editor()
00146      */
00147     function init($show_hidden) {
00148         $this->where_groupAccess = '';
00149         $this->where_hid_del = ' AND pages.deleted=0 ';
00150         if (!$show_hidden) {
00151             $this->where_hid_del .= 'AND pages.hidden=0 ';
00152         }
00153         $this->where_hid_del .= 'AND pages.starttime<=' . $GLOBALS['SIM_ACCESS_TIME'] . ' AND (pages.endtime=0 OR pages.endtime>' . $GLOBALS['SIM_ACCESS_TIME'] . ') ';
00154 
00155             // Filter out new/deleted place-holder pages in case we are NOT in a versioning preview (that means we are online!)
00156         if (!$this->versioningPreview) {
00157             $this->where_hid_del .= ' AND NOT pages.t3ver_state>0';
00158         } else {
00159                 // For version previewing, make sure that enable-fields are not de-selecting hidden pages - we need versionOL() to unset them only if the overlay record instructs us to.
00160             $this->versioningPreview_where_hid_del = $this->where_hid_del; // Copy where_hid_del to other variable (used in relation to versionOL())
00161             $this->where_hid_del = ' AND pages.deleted=0 '; // Clear where_hid_del
00162         }
00163     }
00164 
00165 
00166     /*******************************************
00167      *
00168      * Selecting page records
00169      *
00170      ******************************************/
00171 
00172     /**
00173      * Returns the $row for the page with uid = $uid (observing ->where_hid_del)
00174      * Any pages_language_overlay will be applied before the result is returned.
00175      * If no page is found an empty array is returned.
00176      *
00177      * @param   integer     The page id to look up.
00178      * @param   boolean     If set, the check for group access is disabled. VERY rarely used
00179      * @return  array       The page row with overlayed localized fields. Empty it no page.
00180      * @see getPage_noCheck()
00181      */
00182     function getPage($uid, $disableGroupAccessCheck = FALSE) {
00183             // Hook to manipulate the page uid for special overlay handling
00184         if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPage'])) {
00185             foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPage'] as $classRef) {
00186                 $hookObject = t3lib_div::getUserObj($classRef);
00187 
00188                 if (!($hookObject instanceof t3lib_pageSelect_getPageHook)) {
00189                     throw new UnexpectedValueException('$hookObject must implement interface t3lib_pageSelect_getPageHook', 1251476766);
00190                 }
00191 
00192                 $hookObject->getPage_preProcess($uid, $disableGroupAccessCheck, $this);
00193             }
00194         }
00195 
00196         $accessCheck = $disableGroupAccessCheck ? '' : $this->where_groupAccess;
00197         $cacheKey = md5($accessCheck . '-' . $this->where_hid_del . '-' . $this->sys_language_uid);
00198 
00199         if (is_array($this->cache_getPage[$uid][$cacheKey])) {
00200             return $this->cache_getPage[$uid][$cacheKey];
00201         }
00202         $result = array();
00203         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'uid=' . intval($uid) . $this->where_hid_del . $accessCheck);
00204         $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00205         $GLOBALS['TYPO3_DB']->sql_free_result($res);
00206         if ($row) {
00207             $this->versionOL('pages', $row);
00208             if (is_array($row)) {
00209                 $result = $this->getPageOverlay($row);
00210             }
00211         }
00212         $this->cache_getPage[$uid][$cacheKey] = $result;
00213         return $result;
00214     }
00215 
00216     /**
00217      * Return the $row for the page with uid = $uid WITHOUT checking for ->where_hid_del (start- and endtime or hidden). Only "deleted" is checked!
00218      *
00219      * @param   integer     The page id to look up
00220      * @return  array       The page row with overlayed localized fields. Empty array if no page.
00221      * @see getPage()
00222      */
00223     function getPage_noCheck($uid) {
00224         if ($this->cache_getPage_noCheck[$uid]) {
00225             return $this->cache_getPage_noCheck[$uid];
00226         }
00227 
00228         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'uid=' . intval($uid) . $this->deleteClause('pages'));
00229         $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00230         $GLOBALS['TYPO3_DB']->sql_free_result($res);
00231 
00232         $result = array();
00233         if ($row) {
00234             $this->versionOL('pages', $row);
00235             if (is_array($row)) {
00236                 $result = $this->getPageOverlay($row);
00237             }
00238         }
00239         $this->cache_getPage_noCheck[$uid] = $result;
00240 
00241         return $result;
00242     }
00243 
00244     /**
00245      * Returns the $row of the first web-page in the tree (for the default menu...)
00246      *
00247      * @param   integer     The page id for which to fetch first subpages (PID)
00248      * @return  mixed       If found: The page record (with overlayed localized fields, if any). If NOT found: blank value (not array!)
00249      * @see tslib_fe::fetch_the_id()
00250      */
00251     function getFirstWebPage($uid) {
00252         $output = '';
00253         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'pid=' . intval($uid) . $this->where_hid_del . $this->where_groupAccess, '', 'sorting', '1');
00254         $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00255         $GLOBALS['TYPO3_DB']->sql_free_result($res);
00256         if ($row) {
00257             $this->versionOL('pages', $row);
00258             if (is_array($row)) {
00259                 $output = $this->getPageOverlay($row);
00260             }
00261         }
00262         return $output;
00263     }
00264 
00265     /**
00266      * Returns a pagerow for the page with alias $alias
00267      *
00268      * @param   string      The alias to look up the page uid for.
00269      * @return  integer     Returns page uid (integer) if found, otherwise 0 (zero)
00270      * @see tslib_fe::checkAndSetAlias(), tslib_cObj::typoLink()
00271      */
00272     function getPageIdFromAlias($alias) {
00273         $alias = strtolower($alias);
00274         if ($this->cache_getPageIdFromAlias[$alias]) {
00275             return $this->cache_getPageIdFromAlias[$alias];
00276         }
00277         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'alias=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($alias, 'pages') . ' AND pid>=0 AND pages.deleted=0'); // "AND pid>=0" because of versioning (means that aliases sent MUST be online!)
00278         $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00279         $GLOBALS['TYPO3_DB']->sql_free_result($res);
00280         if ($row) {
00281             $this->cache_getPageIdFromAlias[$alias] = $row['uid'];
00282             return $row['uid'];
00283         }
00284         $this->cache_getPageIdFromAlias[$alias] = 0;
00285         return 0;
00286     }
00287 
00288     /**
00289      * Returns the relevant page overlay record fields
00290      *
00291      * @param   mixed       If $pageInput is an integer, it's the pid of the pageOverlay record and thus the page overlay record is returned. If $pageInput is an array, it's a page-record and based on this page record the language record is found and OVERLAYED before the page record is returned.
00292      * @param   integer     Language UID if you want to set an alternative value to $this->sys_language_uid which is default. Should be >=0
00293      * @return  array       Page row which is overlayed with language_overlay record (or the overlay record alone)
00294      */
00295     function getPageOverlay($pageInput, $lUid = -1) {
00296 
00297             // Initialize:
00298         if ($lUid < 0) {
00299             $lUid = $this->sys_language_uid;
00300         }
00301         $row = NULL;
00302 
00303         if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPageOverlay'])) {
00304             foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPageOverlay'] as $classRef) {
00305                 $hookObject = t3lib_div::getUserObj($classRef);
00306 
00307                 if (!($hookObject instanceof t3lib_pageSelect_getPageOverlayHook)) {
00308                     throw new UnexpectedValueException('$hookObject must implement interface t3lib_pageSelect_getPageOverlayHook', 1269878881);
00309                 }
00310 
00311                 $hookObject->getPageOverlay_preProcess($pageInput, $lUid, $this);
00312             }
00313         }
00314 
00315             // If language UID is different from zero, do overlay:
00316         if ($lUid) {
00317             $fieldArr = explode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['pageOverlayFields']);
00318             if (is_array($pageInput)) {
00319                 $page_id = $pageInput['uid']; // Was the whole record
00320                 $fieldArr = array_intersect($fieldArr, array_keys($pageInput)); // Make sure that only fields which exist in the incoming record are overlaid!
00321             } else {
00322                 $page_id = $pageInput; // Was the id
00323             }
00324 
00325             if (count($fieldArr)) {
00326                 /*
00327                     NOTE to enabledFields('pages_language_overlay'):
00328                     Currently the showHiddenRecords of TSFE set will allow pages_language_overlay records to be selected as they are child-records of a page.
00329                     However you may argue that the showHiddenField flag should determine this. But that's not how it's done right now.
00330                 */
00331 
00332                     // Selecting overlay record:
00333                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
00334                     implode(',', $fieldArr),
00335                     'pages_language_overlay',
00336                     'pid=' . intval($page_id) . '
00337                                 AND sys_language_uid=' . intval($lUid) .
00338                     $this->enableFields('pages_language_overlay'),
00339                     '',
00340                     '',
00341                     '1'
00342                 );
00343                 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00344                 $GLOBALS['TYPO3_DB']->sql_free_result($res);
00345                 $this->versionOL('pages_language_overlay', $row);
00346 
00347                 if (is_array($row)) {
00348                     $row['_PAGES_OVERLAY'] = TRUE;
00349                     $row['_PAGES_OVERLAY_UID'] = $row['uid'];
00350 
00351                         // Unset vital fields that are NOT allowed to be overlaid:
00352                     unset($row['uid']);
00353                     unset($row['pid']);
00354                 }
00355             }
00356         }
00357 
00358             // Create output:
00359         if (is_array($pageInput)) {
00360             return is_array($row) ? array_merge($pageInput, $row) : $pageInput; // If the input was an array, simply overlay the newfound array and return...
00361         } else {
00362             return is_array($row) ? $row : array(); // always an array in return
00363         }
00364     }
00365 
00366     /**
00367      * Creates language-overlay for records in general (where translation is found in records from the same table)
00368      *
00369      * @param   string      Table name
00370      * @param   array       Record to overlay. Must containt uid, pid and $table]['ctrl']['languageField']
00371      * @param   integer     Pointer to the sys_language uid for content on the site.
00372      * @param   string      Overlay mode. If "hideNonTranslated" then records without translation will not be returned un-translated but unset (and return value is false)
00373      * @return  mixed       Returns the input record, possibly overlaid with a translation. But if $OLmode is "hideNonTranslated" then it will return false if no translation is found.
00374      */
00375     function getRecordOverlay($table, $row, $sys_language_content, $OLmode = '') {
00376         global $TCA;
00377 
00378         if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'])) {
00379             foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'] as $classRef) {
00380                 $hookObject = t3lib_div::getUserObj($classRef);
00381 
00382                 if (!($hookObject instanceof t3lib_pageSelect_getRecordOverlayHook)) {
00383                     throw new UnexpectedValueException('$hookObject must implement interface t3lib_pageSelect_getRecordOverlayHook', 1269881658);
00384                 }
00385                 $hookObject->getRecordOverlay_preProcess($table, $row, $sys_language_content, $OLmode, $this);
00386             }
00387         }
00388 
00389         if ($row['uid'] > 0 && $row['pid'] > 0) {
00390             if ($TCA[$table] && $TCA[$table]['ctrl']['languageField'] && $TCA[$table]['ctrl']['transOrigPointerField']) {
00391                 if (!$TCA[$table]['ctrl']['transOrigPointerTable']) { // Will not be able to work with other tables (Just didn't implement it yet; Requires a scan over all tables [ctrl] part for first FIND the table that carries localization information for this table (which could even be more than a single table) and then use that. Could be implemented, but obviously takes a little more....)
00392 
00393                         // Will try to overlay a record only if the sys_language_content value is larger than zero.
00394                     if ($sys_language_content > 0) {
00395 
00396                             // Must be default language or [All], otherwise no overlaying:
00397                         if ($row[$TCA[$table]['ctrl']['languageField']] <= 0) {
00398 
00399                                 // Select overlay record:
00400                             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
00401                                 '*',
00402                                 $table,
00403                                 'pid=' . intval($row['pid']) .
00404                                 ' AND ' . $TCA[$table]['ctrl']['languageField'] . '=' . intval($sys_language_content) .
00405                                 ' AND ' . $TCA[$table]['ctrl']['transOrigPointerField'] . '=' . intval($row['uid']) .
00406                                 $this->enableFields($table),
00407                                 '',
00408                                 '',
00409                                 '1'
00410                             );
00411                             $olrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00412                             $GLOBALS['TYPO3_DB']->sql_free_result($res);
00413                             $this->versionOL($table, $olrow);
00414 
00415                                 // Merge record content by traversing all fields:
00416                             if (is_array($olrow)) {
00417                                 if (isset($olrow['_ORIG_uid'])) {
00418                                     $row['_ORIG_uid'] = $olrow['_ORIG_uid'];
00419                                 }
00420                                 if (isset($olrow['_ORIG_pid'])) {
00421                                     $row['_ORIG_pid'] = $olrow['_ORIG_pid'];
00422                                 }
00423                                 foreach ($row as $fN => $fV) {
00424                                     if ($fN != 'uid' && $fN != 'pid' && isset($olrow[$fN])) {
00425 
00426                                         if ($GLOBALS['TSFE']->TCAcachedExtras[$table]['l10n_mode'][$fN] != 'exclude'
00427                                             && ($GLOBALS['TSFE']->TCAcachedExtras[$table]['l10n_mode'][$fN] != 'mergeIfNotBlank' || strcmp(trim($olrow[$fN]), ''))) {
00428                                             $row[$fN] = $olrow[$fN];
00429                                         }
00430                                     } elseif ($fN == 'uid') {
00431                                         $row['_LOCALIZED_UID'] = $olrow['uid'];
00432                                     }
00433                                 }
00434                             } elseif ($OLmode === 'hideNonTranslated' && $row[$TCA[$table]['ctrl']['languageField']] == 0) { // Unset, if non-translated records should be hidden. ONLY done if the source record really is default language and not [All] in which case it is allowed.
00435                                 unset($row);
00436                             }
00437 
00438                             // Otherwise, check if sys_language_content is different from the value of the record - that means a japanese site might try to display french content.
00439                         } elseif ($sys_language_content != $row[$TCA[$table]['ctrl']['languageField']]) {
00440                             unset($row);
00441                         }
00442                     } else {
00443                             // When default language is displayed, we never want to return a record carrying another language!
00444                         if ($row[$TCA[$table]['ctrl']['languageField']] > 0) {
00445                             unset($row);
00446                         }
00447                     }
00448                 }
00449             }
00450         }
00451         if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'])) {
00452             foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'] as $classRef) {
00453                 $hookObject = t3lib_div::getUserObj($classRef);
00454 
00455                 if (!($hookObject instanceof t3lib_pageSelect_getRecordOverlayHook)) {
00456                     throw new UnexpectedValueException('$hookObject must implement interface t3lib_pageSelect_getRecordOverlayHook', 1269881659);
00457                 }
00458                 $hookObject->getRecordOverlay_postProcess($table, $row, $sys_language_content, $OLmode, $this);
00459             }
00460         }
00461         return $row;
00462     }
00463 
00464 
00465     /*******************************************
00466      *
00467      * Page related: Menu, Domain record, Root line
00468      *
00469      ******************************************/
00470 
00471     /**
00472      * Returns an array with pagerows for subpages with pid=$uid (which is pid here!). This is used for menus.
00473      * If there are mount points in overlay mode the _MP_PARAM field is set to the corret MPvar.
00474      * If the $uid being input does in itself require MPvars to define a correct rootline these must be handled externally to this function.
00475      *
00476      * @param   integer     The page id for which to fetch subpages (PID)
00477      * @param   string      List of fields to select. Default is "*" = all
00478      * @param   string      The field to sort by. Default is "sorting"
00479      * @param   string      Optional additional where clauses. Like "AND title like '%blabla%'" for instance.
00480      * @param   boolean     check if shortcuts exist, checks by default
00481      * @return  array       Array with key/value pairs; keys are page-uid numbers. values are the corresponding page records (with overlayed localized fields, if any)
00482      * @see tslib_fe::getPageShortcut(), tslib_menu::makeMenu(), tx_wizardcrpages_webfunc_2, tx_wizardsortpages_webfunc_2
00483      */
00484     function getMenu($uid, $fields = '*', $sortField = 'sorting', $addWhere = '', $checkShortcuts = 1) {
00485 
00486         $output = Array();
00487         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fields, 'pages', 'pid=' . intval($uid) . $this->where_hid_del . $this->where_groupAccess . ' ' . $addWhere, '', $sortField);
00488         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
00489             $this->versionOL('pages', $row, TRUE);
00490             if (is_array($row)) {
00491                     // Keep mount point:
00492                 $origUid = $row['uid'];
00493                 $mount_info = $this->getMountPointInfo($origUid, $row); // $row MUST have "uid", "pid", "doktype", "mount_pid", "mount_pid_ol" fields in it
00494                 if (is_array($mount_info) && $mount_info['overlay']) { // There is a valid mount point.
00495                     $mp_row = $this->getPage($mount_info['mount_pid']); // Using "getPage" is OK since we need the check for enableFields AND for type 2 of mount pids we DO require a doktype < 200!
00496                     if (count($mp_row)) {
00497                         $row = $mp_row;
00498                         $row['_MP_PARAM'] = $mount_info['MPvar'];
00499                     } else {
00500                         unset($row);
00501                     } // If the mount point could not be fetched with respect to enableFields, unset the row so it does not become a part of the menu!
00502                 }
00503 
00504                     // if shortcut, look up if the target exists and is currently visible
00505                 if ($row['doktype'] == t3lib_pageSelect::DOKTYPE_SHORTCUT && ($row['shortcut'] || $row['shortcut_mode']) && $checkShortcuts) {
00506                     if ($row['shortcut_mode'] == self::SHORTCUT_MODE_NONE) {
00507                             // no shortcut_mode set, so target is directly set in $row['shortcut']
00508                         $searchField = 'uid';
00509                         $searchUid = intval($row['shortcut']);
00510                     } elseif ($row['shortcut_mode'] == self::SHORTCUT_MODE_FIRST_SUBPAGE || $row['shortcut_mode'] == self::SHORTCUT_MODE_RANDOM_SUBPAGE) {
00511                             // check subpages - first subpage or random subpage
00512                         $searchField = 'pid';
00513                             // If a shortcut mode is set and no valid page is given to select subpags from use the actual page.
00514                         $searchUid = intval($row['shortcut']) ? intval($row['shortcut']) : $row['uid'];
00515                     } elseif ($row['shortcut_mode'] == self::SHORTCUT_MODE_PARENT_PAGE) {
00516                             // shortcut to parent page
00517                         $searchField = 'uid';
00518                         $searchUid = $row['pid'];
00519                     }
00520                     $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows(
00521                         'uid',
00522                         'pages',
00523                         $searchField . '=' . $searchUid .
00524                         $this->where_hid_del .
00525                         $this->where_groupAccess .
00526                         ' ' . $addWhere
00527                     );
00528                     if (!$count) {
00529                         unset($row);
00530                     }
00531                 } elseif ($row['doktype'] == t3lib_pageSelect::DOKTYPE_SHORTCUT && $checkShortcuts) {
00532                         // Neither shortcut target nor mode is set. Remove the page from the menu.
00533                     unset($row);
00534                 }
00535 
00536                     // Add to output array after overlaying language:
00537                 if (is_array($row)) {
00538                     $output[$origUid] = $this->getPageOverlay($row);
00539                 }
00540             }
00541         }
00542         $GLOBALS['TYPO3_DB']->sql_free_result($res);
00543         return $output;
00544     }
00545 
00546     /**
00547      * Will find the page carrying the domain record matching the input domain.
00548      * Might exit after sending a redirect-header IF a found domain record instructs to do so.
00549      *
00550      * @param   string      Domain name to search for. Eg. "www.typo3.com". Typical the HTTP_HOST value.
00551      * @param   string      Path for the current script in domain. Eg. "/somedir/subdir". Typ. supplied by t3lib_div::getIndpEnv('SCRIPT_NAME')
00552      * @param   string      Request URI: Used to get parameters from if they should be appended. Typ. supplied by t3lib_div::getIndpEnv('REQUEST_URI')
00553      * @return  mixed       If found, returns integer with page UID where found. Otherwise blank. Might exit if location-header is sent, see description.
00554      * @see tslib_fe::findDomainRecord()
00555      */
00556     function getDomainStartPage($domain, $path = '', $request_uri = '') {
00557         $domain = explode(':', $domain);
00558         $domain = strtolower(preg_replace('/\.$/', '', $domain[0]));
00559             // Removing extra trailing slashes
00560         $path = trim(preg_replace('/\/[^\/]*$/', '', $path));
00561             // Appending to domain string
00562         $domain .= $path;
00563         $domain = preg_replace('/\/*$/', '', $domain);
00564 
00565         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
00566             'pages.uid,sys_domain.redirectTo,sys_domain.redirectHttpStatusCode,sys_domain.prepend_params',
00567             'pages,sys_domain',
00568             'pages.uid=sys_domain.pid
00569                         AND sys_domain.hidden=0
00570                         AND (sys_domain.domainName=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($domain, 'sys_domain') . ' OR sys_domain.domainName=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($domain . '/', 'sys_domain') . ') ' .
00571             $this->where_hid_del . $this->where_groupAccess,
00572             '',
00573             '',
00574             1
00575         );
00576         $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00577         $GLOBALS['TYPO3_DB']->sql_free_result($res);
00578         if ($row) {
00579             if ($row['redirectTo']) {
00580                 $redirectUrl = $row['redirectTo'];
00581                 if ($row['prepend_params']) {
00582                     $redirectUrl = rtrim($redirectUrl, '/');
00583                     $prependStr = ltrim(substr($request_uri, strlen($path)), '/');
00584                     $redirectUrl .= '/' . $prependStr;
00585                 }
00586 
00587                 $statusCode = intval($row['redirectHttpStatusCode']);
00588                 if ($statusCode && defined('t3lib_utility_Http::HTTP_STATUS_' . $statusCode)) {
00589                     t3lib_utility_Http::redirect($redirectUrl, constant('t3lib_utility_Http::HTTP_STATUS_' . $statusCode));
00590                 } else {
00591                     t3lib_utility_Http::redirect($redirectUrl, 't3lib_utility_Http::HTTP_STATUS_301');
00592                 }
00593                 exit;
00594             } else {
00595                 return $row['uid'];
00596             }
00597         }
00598     }
00599 
00600     /**
00601      * Returns array with fields of the pages from here ($uid) and back to the root
00602      * NOTICE: This function only takes deleted pages into account! So hidden, starttime and endtime restricted pages are included no matter what.
00603      * Further: If any "recycler" page is found (doktype=255) then it will also block for the rootline)
00604      * If you want more fields in the rootline records than default such can be added by listing them in $GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields']
00605      *
00606      * @param   integer     The page uid for which to seek back to the page tree root.
00607      * @param   string      Commalist of MountPoint parameters, eg. "1-2,3-4" etc. Normally this value comes from the GET var, MP
00608      * @param   boolean     If set, some errors related to Mount Points in root line are ignored.
00609      * @return  array       Array with page records from the root line as values. The array is ordered with the outer records first and root record in the bottom. The keys are numeric but in reverse order. So if you traverse/sort the array by the numeric keys order you will get the order from root and out. If an error is found (like eternal looping or invalid mountpoint) it will return an empty array.
00610      * @see tslib_fe::getPageAndRootline()
00611      */
00612     function getRootLine($uid, $MP = '', $ignoreMPerrors = FALSE) {
00613         $cacheUid = $uid = intval($uid);
00614         $cacheIgnoreMPerrors = ($ignoreMPerrors ? 1 : 0);
00615 
00616         if (is_array($this->cache_getRootLine[$cacheUid][$this->sys_language_uid][$MP][$cacheIgnoreMPerrors])) {
00617             return $this->cache_getRootLine[$cacheUid][$this->sys_language_uid][$MP][$cacheIgnoreMPerrors];
00618         }
00619 
00620             // Initialize:
00621         $selFields = t3lib_div::uniqueList('pid,uid,t3ver_oid,t3ver_wsid,t3ver_state,t3ver_swapmode,title,alias,nav_title,media,layout,hidden,starttime,endtime,fe_group,extendToSubpages,doktype,TSconfig,storage_pid,is_siteroot,mount_pid,mount_pid_ol,fe_login_mode,backend_layout_next_level,' . $GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields']);
00622         $this->error_getRootLine = '';
00623         $this->error_getRootLine_failPid = 0;
00624 
00625             // Splitting the $MP parameters if present
00626         $MPA = array();
00627         if ($MP) {
00628             $MPA = explode(',', $MP);
00629             foreach ($MPA as $MPAk => $v) {
00630                 $MPA[$MPAk] = explode('-', $MPA[$MPAk]);
00631             }
00632         }
00633 
00634         $loopCheck = 0;
00635         $theRowArray = Array();
00636 
00637         while ($uid != 0 && $loopCheck < 99) { // Max 99 levels in the page tree.
00638             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($selFields, 'pages', 'uid=' . intval($uid) . ' AND pages.deleted=0 AND pages.doktype!=255');
00639             $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00640             $GLOBALS['TYPO3_DB']->sql_free_result($res);
00641             if ($row) {
00642                 $this->versionOL('pages', $row, FALSE, TRUE);
00643                 $this->fixVersioningPid('pages', $row);
00644 
00645                 if (is_array($row)) {
00646                         // Mount Point page types are allowed ONLY a) if they are the outermost record in rootline and b) if the overlay flag is not set:
00647                     if ($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids'] && $row['doktype'] == t3lib_pageSelect::DOKTYPE_MOUNTPOINT && !$ignoreMPerrors) {
00648                         $mount_info = $this->getMountPointInfo($row['uid'], $row);
00649                         if ($loopCheck > 0 || $mount_info['overlay']) {
00650                             $this->error_getRootLine = 'Illegal Mount Point found in rootline';
00651                             return array();
00652                         }
00653                     }
00654 
00655                     $uid = $row['pid']; // Next uid
00656 
00657                     if (count($MPA) && $GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
00658                         $curMP = end($MPA);
00659                         if (!strcmp($row['uid'], $curMP[0])) {
00660 
00661                             array_pop($MPA);
00662                             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($selFields, 'pages', 'uid=' . intval($curMP[1]) . ' AND pages.deleted=0 AND pages.doktype!=255');
00663                             $mp_row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00664                             $GLOBALS['TYPO3_DB']->sql_free_result($res);
00665 
00666                             $this->versionOL('pages', $mp_row, FALSE, TRUE);
00667                             $this->fixVersioningPid('pages', $mp_row);
00668 
00669                             if (is_array($mp_row)) {
00670                                 $mount_info = $this->getMountPointInfo($mp_row['uid'], $mp_row);
00671                                 if (is_array($mount_info) && $mount_info['mount_pid'] == $curMP[0]) {
00672                                     $uid = $mp_row['pid']; // Setting next uid
00673 
00674                                     if ($mount_info['overlay']) { // Symlink style: Keep mount point (current row).
00675                                         $row['_MOUNT_OL'] = TRUE; // Set overlay mode:
00676                                         $row['_MOUNT_PAGE'] = array(
00677                                             'uid' => $mp_row['uid'],
00678                                             'pid' => $mp_row['pid'],
00679                                             'title' => $mp_row['title'],
00680                                         );
00681                                     } else { // Normal operation: Insert the mount page row in rootline instead mount point.
00682                                         if ($loopCheck > 0) {
00683                                             $row = $mp_row;
00684                                         } else {
00685                                             $this->error_getRootLine = 'Current Page Id is a mounted page of the overlay type and cannot be accessed directly!';
00686                                             return array(); // Matching the page id (first run, $loopCheck = 0) with the MPvar is ONLY allowed if the mount point is the "overlay" type (otherwise it could be forged!)
00687                                         }
00688                                     }
00689 
00690                                     $row['_MOUNTED_FROM'] = $curMP[0];
00691                                     $row['_MP_PARAM'] = $mount_info['MPvar'];
00692                                 } else {
00693                                     $this->error_getRootLine = 'MP var was corrupted';
00694                                     return array(); // The MP variables did NOT connect proper mount points:
00695                                 }
00696                             } else {
00697                                 $this->error_getRootLine = 'No moint point record found according to PID in MP var';
00698                                 return array(); // The second PID in MP var was NOT a valid page.
00699                             }
00700                         }
00701                     }
00702                 }
00703                     // Add row to rootline with language overlaid:
00704                 $theRowArray[] = $this->getPageOverlay($row);
00705             } else {
00706                 $this->error_getRootLine = 'Broken rootline';
00707                 $this->error_getRootLine_failPid = $uid;
00708                 return array(); // broken rootline.
00709             }
00710 
00711             $loopCheck++;
00712         }
00713 
00714             // If the MPA array is NOT empty, we have to return an error; All MP elements were not resolved!
00715         if (count($MPA)) {
00716             $this->error_getRootLine = 'MP value remain!';
00717             return array();
00718         }
00719 
00720             // Create output array (with reversed order of numeric keys):
00721         $output = Array();
00722         $c = count($theRowArray);
00723         foreach ($theRowArray as $key => $val) {
00724             $c--;
00725             $output[$c] = $val;
00726         }
00727 
00728             // Note: rootline errors are not cached
00729         $this->cache_getRootLine[$cacheUid][$this->sys_language_uid][$MP][$cacheIgnoreMPerrors] = $output;
00730         return $output;
00731     }
00732 
00733     /**
00734      * Creates a "path" string for the input root line array titles.
00735      * Used for writing statistics.
00736      *
00737      * @param   array       A rootline array!
00738      * @param   integer     The max length of each title from the rootline.
00739      * @return  string      The path in the form "/page title/This is another pageti.../Another page"
00740      * @see tslib_fe::getConfigArray()
00741      */
00742     function getPathFromRootline($rl, $len = 20) {
00743         if (is_array($rl)) {
00744             $c = count($rl);
00745             $path = '';
00746             for ($a = 0; $a < $c; $a++) {
00747                 if ($rl[$a]['uid']) {
00748                     $path .= '/' . t3lib_div::fixed_lgd_cs(strip_tags($rl[$a]['title']), $len);
00749                 }
00750             }
00751             return $path;
00752         }
00753     }
00754 
00755     /**
00756      * Returns the URL type for the input page row IF the doktype is 3 and not disabled.
00757      *
00758      * @param   array       The page row to return URL type for
00759      * @param   boolean     A flag to simply disable any output from here.
00760      * @return  string      The URL type from $this->urltypes array. False if not found or disabled.
00761      * @see tslib_fe::setExternalJumpUrl()
00762      */
00763     function getExtURL($pagerow, $disable = 0) {
00764         if ($pagerow['doktype'] == t3lib_pageSelect::DOKTYPE_LINK && !$disable) {
00765             $redirectTo = $this->urltypes[$pagerow['urltype']] . $pagerow['url'];
00766 
00767                 // If relative path, prefix Site URL:
00768             $uI = parse_url($redirectTo);
00769             if (!$uI['scheme'] && substr($redirectTo, 0, 1) != '/') { // relative path assumed now...
00770                 $redirectTo = t3lib_div::getIndpEnv('TYPO3_SITE_URL') . $redirectTo;
00771             }
00772             return $redirectTo;
00773         }
00774     }
00775 
00776     /**
00777      * Returns MountPoint id for page
00778      * Does a recursive search if the mounted page should be a mount page itself. It has a run-away break so it can't go into infinite loops.
00779      *
00780      * @param   integer     Page id for which to look for a mount pid. Will be returned only if mount pages are enabled, the correct doktype (7) is set for page and there IS a mount_pid (which has a valid record that is not deleted...)
00781      * @param   array       Optional page record for the page id. If not supplied it will be looked up by the system. Must contain at least uid,pid,doktype,mount_pid,mount_pid_ol
00782      * @param   array       Array accumulating formerly tested page ids for mount points. Used for recursivity brake.
00783      * @param   integer     The first page id.
00784      * @return  mixed       Returns FALSE if no mount point was found, "-1" if there should have been one, but no connection to it, otherwise an array with information about mount pid and modes.
00785      * @see tslib_menu
00786      */
00787     function getMountPointInfo($pageId, $pageRec = FALSE, $prevMountPids = array(), $firstPageUid = 0) {
00788         $result = FALSE;
00789 
00790         if ($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
00791 
00792             if (isset($this->cache_getMountPointInfo[$pageId])) {
00793                 return $this->cache_getMountPointInfo[$pageId];
00794             }
00795 
00796                 // Get pageRec if not supplied:
00797             if (!is_array($pageRec)) {
00798                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid,doktype,mount_pid,mount_pid_ol,t3ver_state', 'pages', 'uid=' . intval($pageId) . ' AND pages.deleted=0 AND pages.doktype!=255');
00799                 $pageRec = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00800                 $GLOBALS['TYPO3_DB']->sql_free_result($res);
00801                 $this->versionOL('pages', $pageRec); // Only look for version overlay if page record is not supplied; This assumes that the input record is overlaid with preview version, if any!
00802             }
00803 
00804                 // Set first Page uid:
00805             if (!$firstPageUid) {
00806                 $firstPageUid = $pageRec['uid'];
00807             }
00808 
00809                 // Look for mount pid value plus other required circumstances:
00810             $mount_pid = intval($pageRec['mount_pid']);
00811             if (is_array($pageRec) && $pageRec['doktype'] == t3lib_pageSelect::DOKTYPE_MOUNTPOINT && $mount_pid > 0 && !in_array($mount_pid, $prevMountPids)) {
00812 
00813                     // Get the mount point record (to verify its general existence):
00814                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid,doktype,mount_pid,mount_pid_ol,t3ver_state', 'pages', 'uid=' . $mount_pid . ' AND pages.deleted=0 AND pages.doktype!=255');
00815                 $mountRec = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00816                 $GLOBALS['TYPO3_DB']->sql_free_result($res);
00817                 $this->versionOL('pages', $mountRec);
00818 
00819                 if (is_array($mountRec)) {
00820                         // Look for recursive mount point:
00821                     $prevMountPids[] = $mount_pid;
00822                     $recursiveMountPid = $this->getMountPointInfo($mount_pid, $mountRec, $prevMountPids, $firstPageUid);
00823 
00824                         // Return mount point information:
00825                     $result = $recursiveMountPid ?
00826                             $recursiveMountPid :
00827                             array(
00828                                 'mount_pid' => $mount_pid,
00829                                 'overlay' => $pageRec['mount_pid_ol'],
00830                                 'MPvar' => $mount_pid . '-' . $firstPageUid,
00831                                 'mount_point_rec' => $pageRec,
00832                                 'mount_pid_rec' => $mountRec,
00833                             );
00834                 } else {
00835                     $result = -1; // Means, there SHOULD have been a mount point, but there was none!
00836                 }
00837             }
00838         }
00839 
00840         $this->cache_getMountPointInfo[$pageId] = $result;
00841         return $result;
00842     }
00843 
00844 
00845     /*********************************
00846      *
00847      * Selecting records in general
00848      *
00849      **********************************/
00850 
00851     /**
00852      * Checks if a record exists and is accessible.
00853      * The row is returned if everything's OK.
00854      *
00855      * @param   string      The table name to search
00856      * @param   integer     The uid to look up in $table
00857      * @param   boolean     If checkPage is set, it's also required that the page on which the record resides is accessible
00858      * @return  mixed       Returns array (the record) if OK, otherwise blank/0 (zero)
00859      */
00860     function checkRecord($table, $uid, $checkPage = 0) {
00861         global $TCA;
00862         $uid = intval($uid);
00863         if (is_array($TCA[$table]) && $uid > 0) {
00864             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid = ' . $uid . $this->enableFields($table));
00865             $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00866             $GLOBALS['TYPO3_DB']->sql_free_result($res);
00867             if ($row) {
00868                 $this->versionOL($table, $row);
00869                 if (is_array($row)) {
00870                     if ($checkPage) {
00871                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'uid=' . intval($row['pid']) . $this->enableFields('pages'));
00872                         $numRows = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
00873                         $GLOBALS['TYPO3_DB']->sql_free_result($res);
00874                         if ($numRows > 0) {
00875                             return $row;
00876                         } else {
00877                             return 0;
00878                         }
00879                     } else {
00880                         return $row;
00881                     }
00882                 }
00883             }
00884         }
00885     }
00886 
00887     /**
00888      * Returns record no matter what - except if record is deleted
00889      *
00890      * @param   string      The table name to search
00891      * @param   integer     The uid to look up in $table
00892      * @param   string      The fields to select, default is "*"
00893      * @param   boolean     If set, no version overlay is applied
00894      * @return  mixed       Returns array (the record) if found, otherwise blank/0 (zero)
00895      * @see getPage_noCheck()
00896      */
00897     function getRawRecord($table, $uid, $fields = '*', $noWSOL = FALSE) {
00898         global $TCA;
00899         $uid = intval($uid);
00900             // Excluding pages here so we can ask the function BEFORE TCA gets initialized. Support for this is followed up in deleteClause()...
00901         if ((is_array($TCA[$table]) || $table == 'pages') && $uid > 0) {
00902             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fields, $table, 'uid = ' . $uid . $this->deleteClause($table));
00903             $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00904             $GLOBALS['TYPO3_DB']->sql_free_result($res);
00905             if ($row) {
00906                 if (!$noWSOL) {
00907                     $this->versionOL($table, $row);
00908                 }
00909                 if (is_array($row)) {
00910                     return $row;
00911                 }
00912             }
00913         }
00914     }
00915 
00916     /**
00917      * Selects records based on matching a field (ei. other than UID) with a value
00918      *
00919      * @param   string      The table name to search, eg. "pages" or "tt_content"
00920      * @param   string      The fieldname to match, eg. "uid" or "alias"
00921      * @param   string      The value that fieldname must match, eg. "123" or "frontpage"
00922      * @param   string      Optional additional WHERE clauses put in the end of the query. DO NOT PUT IN GROUP BY, ORDER BY or LIMIT!
00923      * @param   string      Optional GROUP BY field(s), if none, supply blank string.
00924      * @param   string      Optional ORDER BY field(s), if none, supply blank string.
00925      * @param   string      Optional LIMIT value ([begin,]max), if none, supply blank string.
00926      * @return  mixed       Returns array (the record) if found, otherwise nothing (void)
00927      */
00928     function getRecordsByField($theTable, $theField, $theValue, $whereClause = '', $groupBy = '', $orderBy = '', $limit = '') {
00929         global $TCA;
00930         if (is_array($TCA[$theTable])) {
00931             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
00932                 '*',
00933                 $theTable,
00934                 $theField . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($theValue, $theTable) .
00935                 $this->deleteClause($theTable) . ' ' .
00936                 $whereClause, // whereClauseMightContainGroupOrderBy
00937                 $groupBy,
00938                 $orderBy,
00939                 $limit
00940             );
00941             $rows = array();
00942             while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
00943                 #$this->versionOL($theTable,$row);  // not used since records here are fetched based on other fields than uid!
00944                 if (is_array($row)) {
00945                     $rows[] = $row;
00946                 }
00947             }
00948             $GLOBALS['TYPO3_DB']->sql_free_result($res);
00949             if (count($rows)) {
00950                 return $rows;
00951             }
00952         }
00953     }
00954 
00955 
00956     /*********************************
00957      *
00958      * Caching and standard clauses
00959      *
00960      **********************************/
00961 
00962     /**
00963      * Returns string value stored for the hash string in the cache "cache_hash"
00964      * Can be used to retrieved a cached value
00965      * Can be used from your frontend plugins if you like. It is also used to
00966      * store the parsed TypoScript template structures. You can call it directly
00967      * like t3lib_pageSelect::getHash()
00968      *
00969      * IDENTICAL to the function by same name found in t3lib_page
00970      *
00971      * @param   string      The hash-string which was used to store the data value
00972      * @return  string      The "content" field of the "cache_hash" cache entry.
00973      * @see tslib_TStemplate::start(), storeHash()
00974      */
00975     public static function getHash($hash, $expTime = 0) {
00976         $hashContent = null;
00977 
00978         if (TYPO3_UseCachingFramework) {
00979             if (is_object($GLOBALS['typo3CacheManager'])) {
00980                 $contentHashCache = $GLOBALS['typo3CacheManager']->getCache('cache_hash');
00981                 $cacheEntry = $contentHashCache->get($hash);
00982 
00983                 if ($cacheEntry) {
00984                     $hashContent = $cacheEntry;
00985                 }
00986             }
00987         } else {
00988             $expTime = intval($expTime);
00989             if ($expTime) {
00990                 $whereAdd = ' AND tstamp > ' . ($GLOBALS['ACCESS_TIME'] - $expTime);
00991             }
00992             $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('content', 'cache_hash', 'hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($hash, 'cache_hash') . $whereAdd);
00993             $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00994             $GLOBALS['TYPO3_DB']->sql_free_result($res);
00995             if ($row) {
00996                 $hashContent = $row['content'];
00997             }
00998         }
00999         return $hashContent;
01000     }
01001 
01002     /**
01003      * Stores a string value in the cache_hash cache identified by $hash.
01004      * Can be used from your frontend plugins if you like. You can call it
01005      * directly like t3lib_pageSelect::storeHash()
01006      *
01007      * @param   string      32 bit hash string (eg. a md5 hash of a serialized array identifying the data being stored)
01008      * @param   string      The data string. If you want to store an array, then just serialize it first.
01009      * @param   string      $ident is just a textual identification in order to inform about the content!
01010      * @param   integer     The lifetime for the cache entry in seconds
01011      * @return  void
01012      * @see tslib_TStemplate::start(), getHash()
01013      */
01014     public static function storeHash($hash, $data, $ident, $lifetime = 0) {
01015         if (TYPO3_UseCachingFramework) {
01016             if (is_object($GLOBALS['typo3CacheManager'])) {
01017                 $GLOBALS['typo3CacheManager']->getCache('cache_hash')->set(
01018                     $hash,
01019                     $data,
01020                     array('ident_' . $ident),
01021                     intval($lifetime)
01022                 );
01023             }
01024         } else {
01025             $insertFields = array(
01026                 'hash' => $hash,
01027                 'content' => $data,
01028                 'ident' => $ident,
01029                 'tstamp' => $GLOBALS['EXEC_TIME']
01030             );
01031             $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_hash', 'hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($hash, 'cache_hash'));
01032             $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_hash', $insertFields);
01033         }
01034     }
01035 
01036     /**
01037      * Returns the "AND NOT deleted" clause for the tablename given IF $TCA configuration points to such a field.
01038      *
01039      * @param   string      Tablename
01040      * @return  string
01041      * @see enableFields()
01042      */
01043     function deleteClause($table) {
01044         global $TCA;
01045         if (!strcmp($table, 'pages')) { // Hardcode for pages because TCA might not be loaded yet (early frontend initialization)
01046             return ' AND pages.deleted=0';
01047         } else {
01048             return $TCA[$table]['ctrl']['delete'] ? ' AND ' . $table . '.' . $TCA[$table]['ctrl']['delete'] . '=0' : '';
01049         }
01050     }
01051 
01052     /**
01053      * Returns a part of a WHERE clause which will filter out records with start/end times or hidden/fe_groups fields set to values that should de-select them according to the current time, preview settings or user login. Definitely a frontend function.
01054      * Is using the $TCA arrays "ctrl" part where the key "enablefields" determines for each table which of these features applies to that table.
01055      *
01056      * @param   string      Table name found in the $TCA array
01057      * @param   integer     If $show_hidden is set (0/1), any hidden-fields in records are ignored. NOTICE: If you call this function, consider what to do with the show_hidden parameter. Maybe it should be set? See tslib_cObj->enableFields where it's implemented correctly.
01058      * @param   array       Array you can pass where keys can be "disabled", "starttime", "endtime", "fe_group" (keys from "enablefields" in TCA) and if set they will make sure that part of the clause is not added. Thus disables the specific part of the clause. For previewing etc.
01059      * @param   boolean     If set, enableFields will be applied regardless of any versioning preview settings which might otherwise disable enableFields
01060      * @return  string      The clause starting like " AND ...=... AND ...=..."
01061      * @see tslib_cObj::enableFields(), deleteClause()
01062      */
01063     function enableFields($table, $show_hidden = -1, $ignore_array = array(), $noVersionPreview = FALSE) {
01064         global $TYPO3_CONF_VARS;
01065 
01066         if ($show_hidden == -1 && is_object($GLOBALS['TSFE'])) { // If show_hidden was not set from outside and if TSFE is an object, set it based on showHiddenPage and showHiddenRecords from TSFE
01067             $show_hidden = $table == 'pages' ? $GLOBALS['TSFE']->showHiddenPage : $GLOBALS['TSFE']->showHiddenRecords;
01068         }
01069         if ($show_hidden == -1) {
01070             $show_hidden = 0;
01071         } // If show_hidden was not changed during the previous evaluation, do it here.
01072 
01073         $ctrl = $GLOBALS['TCA'][$table]['ctrl'];
01074         $query = '';
01075         if (is_array($ctrl)) {
01076 
01077                 // Delete field check:
01078             if ($ctrl['delete']) {
01079                 $query .= ' AND ' . $table . '.' . $ctrl['delete'] . '=0';
01080             }
01081 
01082                 // Filter out new place-holder records in case we are NOT in a versioning preview (that means we are online!)
01083             if ($ctrl['versioningWS'] && !$this->versioningPreview) {
01084                 $query .= ' AND ' . $table . '.t3ver_state<=0 AND ' . $table . '.pid!=-1'; // Shadow state for new items MUST be ignored!
01085             }
01086 
01087                 // Enable fields:
01088             if (is_array($ctrl['enablecolumns'])) {
01089                 if (!$this->versioningPreview || !$ctrl['versioningWS'] || $noVersionPreview) { // In case of versioning-preview, enableFields are ignored (checked in versionOL())
01090                     if ($ctrl['enablecolumns']['disabled'] && !$show_hidden && !$ignore_array['disabled']) {
01091                         $field = $table . '.' . $ctrl['enablecolumns']['disabled'];
01092                         $query .= ' AND ' . $field . '=0';
01093                     }
01094                     if ($ctrl['enablecolumns']['starttime'] && !$ignore_array['starttime']) {
01095                         $field = $table . '.' . $ctrl['enablecolumns']['starttime'];
01096                         $query .= ' AND ' . $field . '<=' . $GLOBALS['SIM_ACCESS_TIME'];
01097                     }
01098                     if ($ctrl['enablecolumns']['endtime'] && !$ignore_array['endtime']) {
01099                         $field = $table . '.' . $ctrl['enablecolumns']['endtime'];
01100                         $query .= ' AND (' . $field . '=0 OR ' . $field . '>' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
01101                     }
01102                     if ($ctrl['enablecolumns']['fe_group'] && !$ignore_array['fe_group']) {
01103                         $field = $table . '.' . $ctrl['enablecolumns']['fe_group'];
01104                         $query .= $this->getMultipleGroupsWhereClause($field, $table);
01105                     }
01106 
01107                         // Call hook functions for additional enableColumns
01108                         // It is used by the extension ingmar_accessctrl which enables assigning more than one usergroup to content and page records
01109                     if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_page.php']['addEnableColumns'])) {
01110                         $_params = array(
01111                             'table' => $table,
01112                             'show_hidden' => $show_hidden,
01113                             'ignore_array' => $ignore_array,
01114                             'ctrl' => $ctrl
01115                         );
01116                         foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_page.php']['addEnableColumns'] as $_funcRef) {
01117                             $query .= t3lib_div::callUserFunction($_funcRef, $_params, $this);
01118                         }
01119                     }
01120                 }
01121             }
01122         } else {
01123             throw new InvalidArgumentException(
01124                 'There is no entry in the $TCA array for the table "' . $table .
01125                 '". This means that the function enableFields() is ' .
01126                 'called with an invalid table name as argument.',
01127                 1283790586
01128             );
01129         }
01130 
01131         return $query;
01132     }
01133 
01134     /**
01135      * Creating where-clause for checking group access to elements in enableFields function
01136      *
01137      * @param   string      Field with group list
01138      * @param   string      Table name
01139      * @return  string      AND sql-clause
01140      * @see enableFields()
01141      */
01142     function getMultipleGroupsWhereClause($field, $table) {
01143         $memberGroups = t3lib_div::intExplode(',', $GLOBALS['TSFE']->gr_list);
01144         $orChecks = array();
01145         $orChecks[] = $field . '=\'\''; // If the field is empty, then OK
01146         $orChecks[] = $field . ' IS NULL'; // If the field is NULL, then OK
01147         $orChecks[] = $field . '=\'0\''; // If the field contsains zero, then OK
01148 
01149         foreach ($memberGroups as $value) {
01150             $orChecks[] = $GLOBALS['TYPO3_DB']->listQuery($field, $value, $table);
01151         }
01152 
01153         return ' AND (' . implode(' OR ', $orChecks) . ')';
01154     }
01155 
01156 
01157     /*********************************
01158      *
01159      * Versioning Preview
01160      *
01161      **********************************/
01162 
01163     /**
01164      * Finding online PID for offline version record
01165      * ONLY active when backend user is previewing records. MUST NEVER affect a site served which is not previewed by backend users!!!
01166      * Will look if the "pid" value of the input record is -1 (it is an offline version) and if the table supports versioning; if so, it will translate the -1 PID into the PID of the original record
01167      * Used whenever you are tracking something back, like making the root line.
01168      * Principle; Record offline! => Find online?
01169      *
01170      * @param   string      Table name
01171      * @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.
01172      * @return  void        (Passed by ref).
01173      * @see t3lib_BEfunc::fixVersioningPid(), versionOL(), getRootLine()
01174      */
01175     function fixVersioningPid($table, &$rr) {
01176         global $TCA;
01177 
01178         if ($this->versioningPreview && is_array($rr) && $rr['pid'] == -1 && ($table == 'pages' || $TCA[$table]['ctrl']['versioningWS'])) { // Have to hardcode it for "pages" table since TCA is not loaded at this moment!
01179 
01180                 // Check values for t3ver_oid and t3ver_wsid:
01181             if (isset($rr['t3ver_oid']) && isset($rr['t3ver_wsid'])) { // If "t3ver_oid" is already a field, just set this:
01182                 $oid = $rr['t3ver_oid'];
01183                 $wsid = $rr['t3ver_wsid'];
01184             } else { // Otherwise we have to expect "uid" to be in the record and look up based on this:
01185                 $newPidRec = $this->getRawRecord($table, $rr['uid'], 't3ver_oid,t3ver_wsid', TRUE);
01186                 if (is_array($newPidRec)) {
01187                     $oid = $newPidRec['t3ver_oid'];
01188                     $wsid = $newPidRec['t3ver_wsid'];
01189                 }
01190             }
01191 
01192                 // If workspace ids matches and ID of current online version is found, look up the PID value of that:
01193             if ($oid && (($this->versioningWorkspaceId == 0 && $this->checkWorkspaceAccess($wsid)) || !strcmp((int) $wsid, $this->versioningWorkspaceId))) {
01194                 $oidRec = $this->getRawRecord($table, $oid, 'pid', TRUE);
01195 
01196                 if (is_array($oidRec)) {
01197                     # SWAP uid as well? Well no, because when fixing a versioning PID happens it is assumed that this is a "branch" type page and therefore the uid should be kept (like in versionOL()). However if the page is NOT a branch version it should not happen - but then again, direct access to that uid should not happen!
01198                     $rr['_ORIG_pid'] = $rr['pid'];
01199                     $rr['pid'] = $oidRec['pid'];
01200                 }
01201             }
01202         }
01203 
01204             // changing PID in case of moving pointer:
01205         if ($movePlhRec = $this->getMovePlaceholder($table, $rr['uid'], 'pid')) {
01206             $rr['pid'] = $movePlhRec['pid'];
01207         }
01208     }
01209 
01210     /**
01211      * Versioning Preview Overlay
01212      * ONLY active when backend user is previewing records. MUST NEVER affect a site served which is not previewed by backend users!!!
01213      * 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.
01214      * Principle; Record online! => Find offline?
01215      *
01216      * @param   string      Table name
01217      * @param   array       Record array passed by reference. As minimum, the "uid", "pid" and "t3ver_state" fields must exist! The record MAY be set to FALSE in which case the calling function should act as if the record is forbidden to access!
01218      * @param   boolean     If set, the $row is cleared in case it is a move-pointer. This is only for preview of moved records (to remove the record from the original location so it appears only in the new location)
01219      * @param   boolean     Unless this option is TRUE, the $row is unset if enablefields for BOTH the version AND the online record deselects it. This is because when versionOL() is called it is assumed that the online record is already selected with no regards to it's enablefields. However, after looking for a new version the online record enablefields must ALSO be evaluated of course. This is done all by this function!
01220      * @return  void        (Passed by ref).
01221      * @see fixVersioningPid(), t3lib_BEfunc::workspaceOL()
01222      */
01223     function versionOL($table, &$row, $unsetMovePointers = FALSE, $bypassEnableFieldsCheck = FALSE) {
01224         global $TCA;
01225 
01226         if ($this->versioningPreview && is_array($row)) {
01227             $movePldSwap = $this->movePlhOL($table, $row); // will overlay any movePlhOL found with the real record, which in turn will be overlaid with its workspace version if any.
01228             if ($wsAlt = $this->getWorkspaceVersionOfRecord($this->versioningWorkspaceId, $table, $row['uid'], implode(',', array_keys($row)), $bypassEnableFieldsCheck)) { // implode(',',array_keys($row)) = Using fields from original record to make sure no additional fields are selected. This is best for eg. getPageOverlay()
01229                 if (is_array($wsAlt)) {
01230                         // Always fix PID (like in fixVersioningPid() above). [This is usually not the important factor for versioning OL]
01231                     $wsAlt['_ORIG_pid'] = $wsAlt['pid']; // Keep the old (-1) - indicates it was a version...
01232                     $wsAlt['pid'] = $row['pid']; // Set in the online versions PID.
01233 
01234                         // "element" and "page" type versions:
01235                         // For versions of single elements or page+content, preserve online UID and PID (this will produce true "overlay" of element _content_, not any references)
01236                         // For page+content the "_ORIG_uid" should actually be used as PID for selection of tables with "versioning_followPages" enabled.
01237                     if ($table !== 'pages' || $wsAlt['t3ver_swapmode'] <= 0) {
01238                         $wsAlt['_ORIG_uid'] = $wsAlt['uid'];
01239                         $wsAlt['uid'] = $row['uid'];
01240 
01241                             // Translate page alias as well so links are pointing to the _online_ page:
01242                         if ($table === 'pages') {
01243                             $wsAlt['alias'] = $row['alias'];
01244                         }
01245                     } else {
01246                             // "branch" versions:
01247                             // Keeping overlay uid and pid so references are changed. This is only for page-versions with BRANCH below!
01248                         $wsAlt['_ONLINE_uid'] = $row['uid']; // The UID of the versionized record is kept and the uid of the online version is stored
01249                     }
01250 
01251                         // Changing input record to the workspace version alternative:
01252                     $row = $wsAlt;
01253 
01254                         // Check if it is deleted/new
01255                     if ((int) $row['t3ver_state'] === 1 || (int) $row['t3ver_state'] === 2) {
01256                         $row = FALSE; // Unset record if it turned out to be deleted in workspace
01257                     }
01258 
01259                         // Check if move-pointer in workspace (unless if a move-placeholder is the reason why it appears!):
01260                         // You have to specifically set $unsetMovePointers in order to clear these because it is normally a display issue if it should be shown or not.
01261                     if ((int) $row['t3ver_state'] === 4 && !$movePldSwap && $unsetMovePointers) {
01262                         $row = FALSE; // Unset record if it turned out to be deleted in workspace
01263                     }
01264                 } else {
01265                         // No version found, then check if t3ver_state =1 (online version is dummy-representation)
01266                         // Notice, that unless $bypassEnableFieldsCheck is TRUE, the $row is unset if enablefields for BOTH the version AND the online record deselects it. See note for $bypassEnableFieldsCheck
01267                     if ($wsAlt <= -1 || (int) $row['t3ver_state'] > 0) {
01268                         $row = FALSE; // Unset record if it turned out to be "hidden"
01269                     }
01270                 }
01271             }
01272         }
01273     }
01274 
01275     /**
01276      * 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)
01277      * Used from versionOL
01278      *
01279      * @param   string      Table name
01280      * @param   array       Row (passed by reference) - only online records...
01281      * @return  boolean     True if overlay is made.
01282      * @see t3lib_BEfunc::movePlhOl()
01283      */
01284     function movePlhOL($table, &$row) {
01285         global $TCA;
01286 
01287         if (($table == 'pages' || (int) $TCA[$table]['ctrl']['versioningWS'] >= 2) && (int) $row['t3ver_state'] === 3) { // Only for WS ver 2... (moving)
01288 
01289                 // If t3ver_move_id is not found, then find it... (but we like best if it is here...)
01290             if (!isset($row['t3ver_move_id'])) {
01291                 $moveIDRec = $this->getRawRecord($table, $row['uid'], 't3ver_move_id', TRUE);
01292                 $moveID = $moveIDRec['t3ver_move_id'];
01293             } else {
01294                 $moveID = $row['t3ver_move_id'];
01295             }
01296 
01297                 // Find pointed-to record.
01298             if ($moveID) {
01299                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(implode(',', array_keys($row)), $table, 'uid=' . intval($moveID) . $this->enableFields($table));
01300                 $origRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
01301                 $GLOBALS['TYPO3_DB']->sql_free_result($res);
01302                 if ($origRow) {
01303                     $row = $origRow;
01304                     return TRUE;
01305                 }
01306             }
01307         }
01308         return FALSE;
01309     }
01310 
01311     /**
01312      * Returns move placeholder of online (live) version
01313      *
01314      * @param   string      Table name
01315      * @param   integer     Record UID of online version
01316      * @param   string      Field list, default is *
01317      * @return  array       If found, the record, otherwise nothing.
01318      * @see t3lib_BEfunc::getMovePlaceholder()
01319      */
01320     function getMovePlaceholder($table, $uid, $fields = '*') {
01321         global $TCA;
01322 
01323         if ($this->versioningPreview) {
01324             $workspace = (int) $this->versioningWorkspaceId;
01325             if (($table == 'pages' || (int) $TCA[$table]['ctrl']['versioningWS'] >= 2) && $workspace !== 0) {
01326 
01327                     // Select workspace version of record:
01328                 $row = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
01329                     $fields,
01330                     $table,
01331                     'pid!=-1 AND
01332                      t3ver_state=3 AND
01333                      t3ver_move_id=' . intval($uid) . ' AND
01334                      t3ver_wsid=' . intval($workspace) .
01335                     $this->deleteClause($table)
01336                 );
01337 
01338                 if (is_array($row)) {
01339                     return $row;
01340                 }
01341             }
01342         }
01343         return FALSE;
01344     }
01345 
01346     /**
01347      * Select the version of a record for a workspace
01348      *
01349      * @param   integer     Workspace ID
01350      * @param   string      Table name to select from
01351      * @param   integer     Record uid for which to find workspace version.
01352      * @param   string      Field list to select
01353      * @param   boolean     If true, enablefields are not checked for.
01354      * @return  mixed       If found, return record, otherwise other value: Returns 1 if version was sought for but not found, returns -1/-2 if record (offline/online) existed but had enableFields that would disable it. Returns FALSE if not in workspace or no versioning for record. Notice, that the enablefields of the online record is also tested.
01355      * @see t3lib_befunc::getWorkspaceVersionOfRecord()
01356      */
01357     function getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields = '*', $bypassEnableFieldsCheck = FALSE) {
01358         global $TCA;
01359 
01360         if ($workspace !== 0 && ($table == 'pages' || $TCA[$table]['ctrl']['versioningWS'])) { // Have to hardcode it for "pages" table since TCA is not loaded at this moment!
01361 
01362                 // Setting up enableFields for version record:
01363             if ($table == 'pages') {
01364                 $enFields = $this->versioningPreview_where_hid_del;
01365             } else {
01366                 $enFields = $this->enableFields($table, -1, array(), TRUE);
01367             }
01368 
01369                 // Select workspace version of record, only testing for deleted.
01370             $newrow = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
01371                 $fields,
01372                 $table,
01373                 'pid=-1 AND
01374                  t3ver_oid=' . intval($uid) . ' AND
01375                  t3ver_wsid=' . intval($workspace) .
01376                 $this->deleteClause($table)
01377             );
01378 
01379                 // If version found, check if it could have been selected with enableFields on as well:
01380             if (is_array($newrow)) {
01381                 if ($bypassEnableFieldsCheck || $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
01382                     'uid',
01383                     $table,
01384                     'pid=-1 AND
01385                         t3ver_oid=' . intval($uid) . ' AND
01386                         t3ver_wsid=' . intval($workspace) .
01387                     $enFields
01388                 )) {
01389                     return $newrow; // Return offline version, tested for its enableFields.
01390                 } else {
01391                     return -1; // Return -1 because offline version was de-selected due to its enableFields.
01392                 }
01393             } else {
01394                     // OK, so no workspace version was found. Then check if online version can be selected with full enable fields and if so, return 1:
01395                 if ($bypassEnableFieldsCheck || $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
01396                     'uid',
01397                     $table,
01398                     'uid=' . intval($uid) . $enFields
01399                 )) {
01400                     return 1; // Means search was done, but no version found.
01401                 } else {
01402                     return -2; // Return -2 because the online record was de-selected due to its enableFields.
01403                 }
01404             }
01405         }
01406 
01407         return FALSE; // No look up in database because versioning not enabled / or workspace not offline
01408     }
01409 
01410     /**
01411      * Checks if user has access to workspace.
01412      *
01413      * @param   int $wsid   Workspace ID
01414      * @return  boolean <code>true</code> if has access
01415      */
01416     function checkWorkspaceAccess($wsid) {
01417         if (!$GLOBALS['BE_USER'] || !t3lib_extMgm::isLoaded('workspaces')) {
01418             return FALSE;
01419         }
01420         if (isset($this->workspaceCache[$wsid])) {
01421             $ws = $this->workspaceCache[$wsid];
01422         }
01423         else {
01424             if ($wsid > 0) {
01425                 $ws = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', 'sys_workspace', 'uid=' . intval($wsid) . ' AND deleted=0'); // No $TCA yet!
01426                 if (!is_array($ws)) {
01427                     return FALSE;
01428                 }
01429             }
01430             else {
01431                 $ws = $wsid;
01432             }
01433             $ws = $GLOBALS['BE_USER']->checkWorkspace($ws);
01434             $this->workspaceCache[$wsid] = $ws;
01435         }
01436         return ($ws['_ACCESS'] != '');
01437     }
01438 }
01439 
01440 
01441 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_page.php'])) {
01442     include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_page.php']);
01443 }
01444 
01445 ?>