"TYPO3 4.0.1: typo3_src-4.0.1/t3lib/class.t3lib_tcemain.php Source File", "datetime" => "Sat Dec 2 19:22:19 2006", "date" => "2 Dec 2006", "doxygenversion" => "1.4.6", "projectname" => "TYPO3 4.0.1", "projectnumber" => "4.0.1" ); get_header($doxygen_vars); ?>

class.t3lib_tcemain.php

00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 1999-2006 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 ***************************************************************/
00195 // *******************************
00196 // Including necessary libraries
00197 // *******************************
00198 require_once (PATH_t3lib.'class.t3lib_loaddbgroup.php');
00199 require_once (PATH_t3lib.'class.t3lib_parsehtml_proc.php');
00200 require_once (PATH_t3lib.'class.t3lib_stdgraphic.php');
00201 require_once (PATH_t3lib.'class.t3lib_basicfilefunc.php');
00202 require_once (PATH_t3lib.'class.t3lib_refindex.php');
00203 require_once (PATH_t3lib.'class.t3lib_flexformtools.php');
00204 
00205 
00206 
00207 
00208 
00209 
00210 
00211 
00212 
00213 
00214 
00229 class t3lib_TCEmain     {
00230 
00231 
00232                 // *********************
00233                 // Public variables you can configure before using the class:
00234                 // *********************
00235 
00236         var $storeLogMessages = TRUE;                   // Boolean: If true, the default log-messages will be stored. This should not be necessary if the locallang-file for the log-display is properly configured. So disabling this will just save some database-space as the default messages are not saved.
00237         var $enableLogging = TRUE;                              // Boolean: If true, actions are logged to sys_log.
00238         var $reverseOrder = FALSE;                              // Boolean: If true, the datamap array is reversed in the order, which is a nice thing if you're creating a whole new bunch of records.
00239         var $checkSimilar = TRUE;                               // Boolean: If true, only fields which are different from the database values are saved! In fact, if a whole input array is similar, it's not saved then.
00240         var $stripslashes_values = TRUE;                // Boolean: If true, incoming values in the data-array have their slashes stripped. ALWAYS SET THIS TO ZERO and supply an unescaped data array instead. This switch may totally disappear in future versions of this class!
00241         var $checkStoredRecords = TRUE;                 // Boolean: This will read the record after having updated or inserted it. If anything is not properly submitted an error is written to the log. This feature consumes extra time by selecting records
00242         var $checkStoredRecords_loose = TRUE;   // Boolean: If set, values '' and 0 will equal each other when the stored records are checked.
00243         var $deleteTree = FALSE;                                // Boolean. If this is set, then a page is deleted by deleting the whole branch under it (user must have deletepermissions to it all). If not set, then the page is deleted ONLY if it has no branch
00244         var $neverHideAtCopy = FALSE;                   // Boolean. If set, then the 'hideAtCopy' flag for tables will be ignored.
00245         var $dontProcessTransformations = FALSE;        // Boolean: If set, then transformations are NOT performed on the input.
00246         var $bypassWorkspaceRestrictions = FALSE;       // Boolean: If true, workspace restrictions are bypassed on edit an create actions (process_datamap()). YOU MUST KNOW what you do if you use this feature!
00247 
00248         var $copyWhichTables = '*';                             // String. Comma-list. This list of tables decides which tables will be copied. If empty then none will. If '*' then all will (that the user has permission to of course)
00249         var $generalComment = '';                               // General comment, eg. for staging in workspaces.
00250 
00251         var $copyTree = 0;                                              // Integer. If 0 then branch is NOT copied. If 1 then pages on the 1st level is copied. If 2 then pages on the second level is copied ... and so on
00252 
00253         var $defaultValues = array();                   // Array [table][fields]=value: New records are created with default values and you can set this array on the form $defaultValues[$table][$field] = $value to override the default values fetched from TCA. If ->setDefaultsFromUserTS is called UserTSconfig default values will overrule existing values in this array (thus UserTSconfig overrules externally set defaults which overrules TCA defaults)
00254         var $overrideValues = array();                  // Array [table][fields]=value: You can set this array on the form $overrideValues[$table][$field] = $value to override the incoming data. You must set this externally. You must make sure the fields in this array are also found in the table, because it's not checked. All columns can be set by this array!
00255         var $alternativeFileName = array();             // Array [filename]=alternative_filename: Use this array to force another name onto a file. Eg. if you set ['/tmp/blablabal'] = 'my_file.txt' and '/tmp/blablabal' is set for a certain file-field, then 'my_file.txt' will be used as the name instead.
00256         var $data_disableFields=array();                // If entries are set in this array corresponding to fields for update, they are ignored and thus NOT updated. You could set this array from a series of checkboxes with value=0 and hidden fields before the checkbox with 1. Then an empty checkbox will disable the field.
00257         var $suggestedInsertUids=array();               // Use this array to validate suggested uids for tables by setting [table]:[uid]. This is a dangerous option since it will force the inserted record to have a certain UID. The value just have to be true, but if you set it to "DELETE" it will make sure any record with that UID will be deleted first (raw delete). The option is used for import of T3D files when synchronizing between two mirrored servers. As a security measure this feature is available only for Admin Users (for now)
00258 
00259         var $callBackObj;                                               // Object. Call back object for flex form traversation. Useful when external classes wants to use the iteration functions inside tcemain for traversing a FlexForm structure.
00260 
00261 
00262 
00263 
00264                 // *********************
00265                 // Internal variables (mapping arrays) which can be used (read-only) from outside
00266                 // *********************
00267         var $autoVersionIdMap = Array();                        // Contains mapping of auto-versionized records.
00268         var $substNEWwithIDs = Array();                         // When new elements are created, this array contains a map between their "NEW..." string IDs and the eventual UID they got when stored in database
00269         var $substNEWwithIDs_table = Array();           // Like $substNEWwithIDs, but where each old "NEW..." id is mapped to the table it was from.
00270         var $copyMappingArray_merged = Array();         // This array is the sum of all copying operations in this class. May be READ from outside, thus partly public.
00271         var $copiedFileMap = Array();                           // A map between input file name and final destination for files being attached to records.
00272         var     $errorLog = Array();                                    // Errors are collected in this variable.
00273 
00274 
00275 
00276                 // *********************
00277                 // Internal Variables, do not touch.
00278                 // *********************
00279 
00280                 // Variables set in init() function:
00281         var $BE_USER;           // The user-object the script uses. If not set from outside, this is set to the current global $BE_USER.
00282         var $userid;            // will be set to uid of be_user executing this script
00283         var $username;          // will be set to username of be_user executing this script
00284         var $admin;                     // will be set if user is admin
00285 
00286         var $defaultPermissions = array(                // Can be overridden from $TYPO3_CONF_VARS
00287                 'user' => 'show,edit,delete,new,editcontent',
00288                 'group' => 'show,edit,new,editcontent',
00289                 'everybody' => ''
00290         );
00291 
00292         var $exclude_array;                     // The list of <table>-<fields> that cannot be edited by user. This is compiled from TCA/exclude-flag combined with non_exclude_fields for the user.
00293         var $datamap = Array();         // Set with incoming data array
00294         var $cmdmap = Array();          // Set with incoming cmd array
00295 
00296                 // Internal static:
00297         var $pMap = Array(              // Permission mapping
00298                 'show' => 1,                    // 1st bit
00299                 'edit' => 2,                    // 2nd bit
00300                 'delete' => 4,                  // 3rd bit
00301                 'new' => 8,                             // 4th bit
00302                 'editcontent' => 16             // 5th bit
00303         );
00304         var $sortIntervals = 256;                                       // Integer: The interval between sorting numbers used with tables with a 'sorting' field defined. Min 1
00305 
00306                 // Internal caching arrays
00307         var $recUpdateAccessCache = Array();            // Used by function checkRecordUpdateAccess() to store whether a record is updateable or not.
00308         var $recInsertAccessCache = Array();            // User by function checkRecordInsertAccess() to store whether a record can be inserted on a page id
00309         var $isRecordInWebMount_Cache=array();          // Caching array for check of whether records are in a webmount
00310         var $isInWebMount_Cache=array();                        // Caching array for page ids in webmounts
00311         var $cachedTSconfig = array();                          // Caching for collecting TSconfig for page ids
00312         var $pageCache = Array();                                       // Used for caching page records in pageInfo()
00313         var $checkWorkspaceCache = Array();                     // Array caching workspace access for BE_USER
00314 
00315                 // Other arrays:
00316         var $dbAnalysisStore=array();                           // For accumulation of MM relations that must be written after new records are created.
00317         var $removeFilesStore=array();                          // For accumulation of files which must be deleted after processing of all input content
00318         var $uploadedFileArray = array();                       // Uploaded files, set by process_uploads()
00319         var $registerDBList=array();                            // Used for tracking references that might need correction after operations
00320         var $copyMappingArray = Array();                        // Used by the copy action to track the ids of new pages so subpages are correctly inserted! THIS is internally cleared for each executed copy operation! DO NOT USE THIS FROM OUTSIDE! Read from copyMappingArray_merged instead which is accumulating this information.
00321 
00322                 // Various
00323         var $fileFunc;                                                          // For "singleTon" file-manipulation object
00324         var $checkValue_currentRecord=array();          // Set to "currentRecord" during checking of values.
00325         var $autoVersioningUpdate = FALSE;                      // A signal flag used to tell file processing that autoversioning has happend and hence certain action should be applied.
00326 
00327 
00328 
00329 
00330 
00331 
00332 
00333 
00334 
00335 
00336 
00337 
00348         function start($data,$cmd,$altUserObject='')    {
00349 
00350                         // Initializing BE_USER
00351                 $this->BE_USER = is_object($altUserObject) ? $altUserObject : $GLOBALS['BE_USER'];
00352                 $this->userid = $this->BE_USER->user['uid'];
00353                 $this->username = $this->BE_USER->user['username'];
00354                 $this->admin = $this->BE_USER->user['admin'];
00355 
00356                 if ($GLOBALS['BE_USER']->uc['recursiveDelete'])    {
00357                         $this->deleteTree = 1;
00358                 }
00359 
00360                         // Initializing default permissions for pages
00361                 $defaultPermissions = $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPermissions'];
00362                 if (isset($defaultPermissions['user']))         {$this->defaultPermissions['user'] = $defaultPermissions['user'];}
00363                 if (isset($defaultPermissions['group']))                {$this->defaultPermissions['group'] = $defaultPermissions['group'];}
00364                 if (isset($defaultPermissions['everybody']))            {$this->defaultPermissions['everybody'] = $defaultPermissions['everybody'];}
00365 
00366                         // generates the excludelist, based on TCA/exclude-flag and non_exclude_fields for the user:
00367                 $this->exclude_array = $this->admin ? array() : $this->getExcludeListArray();
00368 
00369                         // Setting the data and cmd arrays
00370                 if (is_array($data)) {
00371                         reset($data);
00372                         $this->datamap = $data;
00373                 }
00374                 if (is_array($cmd))     {
00375                         reset($cmd);
00376                         $this->cmdmap = $cmd;
00377                 }
00378         }
00379 
00387         function setMirror($mirror)     {
00388                 if (is_array($mirror))  {
00389                         reset($mirror);
00390                         while(list($table,$uid_array)=each($mirror))    {
00391                                 if (isset($this->datamap[$table]))      {
00392                                         reset($uid_array);
00393                                         while (list($id,$uidList) = each($uid_array))   {
00394                                                 if (isset($this->datamap[$table][$id])) {
00395                                                         $theIdsInArray = t3lib_div::trimExplode(',',$uidList,1);
00396                                                         while(list(,$copyToUid)=each($theIdsInArray))   {
00397                                                                 $this->datamap[$table][$copyToUid] = $this->datamap[$table][$id];
00398                                                         }
00399                                                 }
00400                                         }
00401                                 }
00402                         }
00403                 }
00404         }
00405 
00412         function setDefaultsFromUserTS($userTS) {
00413                 global $TCA;
00414                 if (is_array($userTS))  {
00415                         foreach($userTS as $k => $v)    {
00416                                 $k = substr($k,0,-1);
00417                                 if ($k && is_array($v) && isset($TCA[$k]))      {
00418                                         if (is_array($this->defaultValues[$k])) {
00419                                                 $this->defaultValues[$k] = array_merge($this->defaultValues[$k],$v);
00420                                         } else {
00421                                                 $this->defaultValues[$k] = $v;
00422                                         }
00423                                 }
00424                         }
00425                 }
00426         }
00427 
00435         function process_uploads($postFiles)    {
00436 
00437                 if (is_array($postFiles))       {
00438 
00439                                 // Editing frozen:
00440                         if ($this->BE_USER->workspace!==0 && $this->BE_USER->workspaceRec['freeze'])    {
00441                                 $this->newlog('All editing in this workspace has been frozen!',1);
00442                                 return FALSE;
00443                         }
00444 
00445                         reset($postFiles);
00446                         $subA = current($postFiles);
00447                         if (is_array($subA))    {
00448                                 if (is_array($subA['name']) && is_array($subA['type']) && is_array($subA['tmp_name']) && is_array($subA['size']))       {
00449                                                 // Initialize the uploadedFilesArray:
00450                                         $this->uploadedFileArray=array();
00451 
00452                                                 // For each entry:
00453                                         foreach($subA as $key => $values)       {
00454                                                 $this->process_uploads_traverseArray($this->uploadedFileArray,$values,$key);
00455                                         }
00456                                 } else {
00457                                         $this->uploadedFileArray=$subA;
00458                                 }
00459                         }
00460                 }
00461         }
00462 
00473         function process_uploads_traverseArray(&$outputArr,$inputArr,$keyToSet) {
00474                 if (is_array($inputArr))        {
00475                         foreach($inputArr as $key => $value)    {
00476                                 $this->process_uploads_traverseArray($outputArr[$key],$inputArr[$key],$keyToSet);
00477                         }
00478                 } else {
00479                         $outputArr[$keyToSet]=$inputArr;
00480                 }
00481         }
00482 
00483 
00484 
00485 
00486 
00487 
00488 
00489 
00490 
00491 
00492 
00493 
00494 
00495 
00496 
00497         /*********************************************
00498          *
00499          * PROCESSING DATA
00500          *
00501          *********************************************/
00502 
00509         function process_datamap() {
00510                 global $TCA, $TYPO3_CONF_VARS;
00511 
00512                         // Editing frozen:
00513                 if ($this->BE_USER->workspace!==0 && $this->BE_USER->workspaceRec['freeze'])    {
00514                         $this->newlog('All editing in this workspace has been frozen!',1);
00515                         return FALSE;
00516                 }
00517 
00518                         // First prepare user defined objects (if any) for hooks which extend this function:
00519                 $hookObjectsArr = array();
00520                 if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'])) {
00521                         foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'] as $classRef) {
00522                                 $hookObjectsArr[] = &t3lib_div::getUserObj($classRef);
00523                         }
00524                 }
00525 
00526                         // Organize tables so that the pages-table is always processed first. This is required if you want to make sure that content pointing to a new page will be created.
00527                 $orderOfTables = Array();
00528                 if (isset($this->datamap['pages']))     {               // Set pages first.
00529                         $orderOfTables[]='pages';
00530                 }
00531                 reset($this->datamap);
00532                 while (list($table,) = each($this->datamap))    {
00533                         if ($table!='pages')    {
00534                                 $orderOfTables[]=$table;
00535                         }
00536                 }
00537 
00538                         // Process the tables...
00539                 foreach($orderOfTables as $table)       {
00540                                 /* Check if
00541                                         - table is set in $TCA,
00542                                         - table is NOT readOnly
00543                                         - the table is set with content in the data-array (if not, there's nothing to process...)
00544                                         - permissions for tableaccess OK
00545                                 */
00546                         $modifyAccessList = $this->checkModifyAccessList($table);
00547                         if (!$modifyAccessList) {
00548                                 $id = 0;
00549                                 $this->log($table,$id,2,0,1,"Attempt to modify table '%s' without permission",1,array($table));
00550                         }
00551                         if (isset($TCA[$table]) && !$this->tableReadOnly($table) && is_array($this->datamap[$table]) && $modifyAccessList)      {
00552                                 if ($this->reverseOrder)        {
00553                                         $this->datamap[$table] = array_reverse($this->datamap[$table], 1);
00554                                 }
00555 
00556                                         // For each record from the table, do:
00557                                         // $id is the record uid, may be a string if new records...
00558                                         // $incomingFieldArray is the array of fields
00559                                 foreach($this->datamap[$table] as $id => $incomingFieldArray)   {
00560                                         if (is_array($incomingFieldArray))      {
00561 
00562                                                         // Hook: processDatamap_preProcessIncomingFieldArray
00563                                                 foreach($hookObjectsArr as $hookObj)    {
00564                                                         if (method_exists($hookObj, 'processDatamap_preProcessFieldArray')) {
00565                                                                 $hookObj->processDatamap_preProcessFieldArray($incomingFieldArray, $table, $id, $this);
00566                                                         }
00567                                                 }
00568 
00569                                                         // ******************************
00570                                                         // Checking access to the record
00571                                                         // ******************************
00572                                                 $createNewVersion = FALSE;
00573                                                 $recordAccess = FALSE;
00574                                                 $old_pid_value = '';
00575                                                 $resetRejected = FALSE;
00576                                                 $this->autoVersioningUpdate = FALSE;
00577 
00578                                                 if (!t3lib_div::testInt($id)) {               // Is it a new record? (Then Id is a string)
00579                                                         $fieldArray = $this->newFieldArray($table);     // Get a fieldArray with default values
00580                                                         if (isset($incomingFieldArray['pid']))  {       // A pid must be set for new records.
00581                                                                         // $value = the pid
00582                                                                 $pid_value = $incomingFieldArray['pid'];
00583 
00584                                                                         // Checking and finding numerical pid, it may be a string-reference to another value
00585                                                                 $OK = 1;
00586                                                                 if (strstr($pid_value,'NEW'))   {       // If a NEW... id
00587                                                                         if (substr($pid_value,0,1)=='-') {$negFlag=-1;$pid_value=substr($pid_value,1);} else {$negFlag=1;}
00588                                                                         if (isset($this->substNEWwithIDs[$pid_value]))  {       // Trying to find the correct numerical value as it should be mapped by earlier processing of another new record.
00589                                                                                 $old_pid_value = $pid_value;
00590                                                                                 $pid_value=intval($negFlag*$this->substNEWwithIDs[$pid_value]);
00591                                                                         } else {$OK = 0;}       // If not found in the substArray we must stop the process...
00592                                                                 } elseif ($pid_value>=0 && $this->BE_USER->workspace!==0 && $TCA[$table]['ctrl']['versioning_followPages'])     {       // PID points to page, the workspace is an offline space and the table follows page during versioning: This means we must check if the PID page has a version in the workspace with swapmode set to 0 (zero = page+content) and if so, change the pid to the uid of that version.
00593                                                                         if ($WSdestPage = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, 'pages', $pid_value, 'uid,t3ver_swapmode'))      {       // Looks for workspace version of page.
00594                                                                                 if ($WSdestPage['t3ver_swapmode']==0)   {       // if swapmode is zero, then change pid value.
00595                                                                                         $pid_value = $WSdestPage['uid'];
00596                                                                                 }
00597                                                                         }
00598                                                                 }
00599                                                                 $pid_value = intval($pid_value);
00600 
00601                                                                         // The $pid_value is now the numerical pid at this point
00602                                                                 if ($OK)        {
00603                                                                         $sortRow = $TCA[$table]['ctrl']['sortby'];
00604                                                                         if ($pid_value>=0)      {       // Points to a page on which to insert the element, possibly in the top of the page
00605                                                                                 if ($sortRow)   {       // If this table is sorted we better find the top sorting number
00606                                                                                         $fieldArray[$sortRow] = $this->getSortNumber($table,0,$pid_value);
00607                                                                                 }
00608                                                                                 $fieldArray['pid'] = $pid_value;        // The numerical pid is inserted in the data array
00609                                                                         } else {        // points to another record before ifself
00610                                                                                 if ($sortRow)   {       // If this table is sorted we better find the top sorting number
00611                                                                                         $tempArray=$this->getSortNumber($table,0,$pid_value);   // Because $pid_value is < 0, getSortNumber returns an array
00612                                                                                         $fieldArray['pid'] = $tempArray['pid'];
00613                                                                                         $fieldArray[$sortRow] = $tempArray['sortNumber'];
00614                                                                                 } else {        // Here we fetch the PID of the record that we point to...
00615                                                                                         $tempdata = $this->recordInfo($table,abs($pid_value),'pid');
00616                                                                                         $fieldArray['pid']=$tempdata['pid'];
00617                                                                                 }
00618                                                                         }
00619                                                                 }
00620                                                         }
00621                                                         $theRealPid = $fieldArray['pid'];
00622 
00623                                                                 // Now, check if we may insert records on this pid.
00624                                                         if ($theRealPid>=0)     {
00625                                                                 $recordAccess = $this->checkRecordInsertAccess($table,$theRealPid);             // Checks if records can be inserted on this $pid.
00626                                                                 if ($recordAccess)      {
00627                                                                         $this->addDefaultPermittedLanguageIfNotSet($table,$incomingFieldArray);
00628                                                                         $recordAccess = $this->BE_USER->recordEditAccessInternals($table,$incomingFieldArray,TRUE);
00629                                                                         if (!$recordAccess)             {
00630                                                                                 $this->newlog("recordEditAccessInternals() check failed. [".$this->BE_USER->errorMsg."]",1);
00631                                                                         } elseif(!$this->bypassWorkspaceRestrictions)   {
00632                                                                                         // Workspace related processing:
00633                                                                                 if ($res = $this->BE_USER->workspaceAllowLiveRecordsInPID($theRealPid,$table))  {       // If LIVE records cannot be created in the current PID due to workspace restrictions, prepare creation of placeholder-record
00634                                                                                         if ($res<0)     {
00635                                                                                                 $recordAccess = FALSE;
00636                                                                                                 $this->newlog('Stage for versioning root point and users access level did not allow for editing',1);
00637                                                                                         }
00638                                                                                 } else {        // So, if no live records were allowed, we have to create a new version of this record:
00639                                                                                         if ($TCA[$table]['ctrl']['versioningWS'])       {
00640                                                                                                 $createNewVersion = TRUE;
00641                                                                                         } else {
00642                                                                                                 $recordAccess = FALSE;
00643                                                                                                 $this->newlog('Record could not be created in this workspace in this branch',1);
00644                                                                                         }
00645                                                                                 }
00646                                                                         }
00647                                                                 }
00648                                                         } else {
00649                                                                 debug('Internal ERROR: pid should not be less than zero!');
00650                                                         }
00651                                                         $status = 'new';                                                // Yes new record, change $record_status to 'insert'
00652                                                 } else {        // Nope... $id is a number
00653                                                         $fieldArray = array();
00654                                                         $recordAccess = $this->checkRecordUpdateAccess($table,$id);
00655                                                         if (!$recordAccess)             {
00656                                                                 $propArr = $this->getRecordProperties($table,$id);
00657                                                                 $this->log($table,$id,2,0,1,"Attempt to modify record '%s' (%s) without permission. Or non-existing page.",2,array($propArr['header'],$table.':'.$id),$propArr['event_pid']);
00658                                                         } else {        // Next check of the record permissions (internals)
00659                                                                 $recordAccess = $this->BE_USER->recordEditAccessInternals($table,$id);
00660                                                                 if (!$recordAccess)             {
00661                                                                         $propArr = $this->getRecordProperties($table,$id);
00662                                                                         $this->newlog("recordEditAccessInternals() check failed. [".$this->BE_USER->errorMsg."]",1);
00663                                                                 } else {        // Here we fetch the PID of the record that we point to...
00664                                                                         $tempdata = $this->recordInfo($table,$id,'pid'.($TCA[$table]['ctrl']['versioningWS']?',t3ver_wsid,t3ver_stage':''));
00665                                                                         $theRealPid = $tempdata['pid'];
00666 
00667                                                                                 // Prepare the reset of the rejected flag if set:
00668                                                                         if ($TCA[$table]['ctrl']['versioningWS'] && $tempdata['t3ver_stage']<0) {
00669                                                                                 $resetRejected = TRUE;
00670                                                                         }
00671 
00672                                                                                 // Checking access in case of offline workspace:
00673                                                                         if (!$this->bypassWorkspaceRestrictions && $errorCode = $this->BE_USER->workspaceCannotEditRecord($table,$tempdata))    {
00674                                                                                 $recordAccess = FALSE;          // Versioning is required and it must be offline version!
00675 
00676                                                                                         // Auto-creation of version: In offline workspace, test if versioning is enabled and look for workspace version of input record. If there is no versionized record found we will create one and save to that.
00677                                                                                 if ($this->BE_USER->workspaceAllowAutoCreation($table,$id,$theRealPid)) {
00678                                                                                         $tce = t3lib_div::makeInstance('t3lib_TCEmain');
00679                                                                                         $tce->stripslashes_values = 0;
00680 
00681                                                                                                 // Setting up command for creating a new version of the record:
00682                                                                                         $cmd = array();
00683                                                                                         $cmd[$table][$id]['version'] = array(
00684                                                                                                 'action' => 'new',
00685                                                                                                 'treeLevels' => -1,     // Default is to create a version of the individual records...
00686                                                                                                 'label' => 'Auto-created for WS #'.$this->BE_USER->workspace
00687                                                                                         );
00688                                                                                         $tce->start(array(),$cmd);
00689                                                                                         $tce->process_cmdmap();
00690                                                                                         $this->errorLog = array_merge($this->errorLog,$tce->errorLog);
00691 
00692                                                                                         if ($tce->copyMappingArray[$table][$id])        {
00693                                                                                                 $this->uploadedFileArray[$table][$tce->copyMappingArray[$table][$id]] = $this->uploadedFileArray[$table][$id];
00694                                                                                                 $id = $this->autoVersionIdMap[$table][$id] = $tce->copyMappingArray[$table][$id];
00695                                                                                                 $recordAccess = TRUE;
00696                                                                                                 $this->autoVersioningUpdate = TRUE;
00697                                                                                         } else $this->newlog("Could not be edited in offline workspace in the branch where found (failure state: '".$errorCode."'). Auto-creation of version failed!",1);
00698                                                                                 } else $this->newlog("Could not be edited in offline workspace in the branch where found (failure state: '".$errorCode."'). Auto-creation of version not allowed in workspace!",1);
00699                                                                         }
00700                                                                 }
00701                                                         }
00702                                                         $status = 'update';     // the default is 'update'
00703                                                 }
00704 
00705                                                         // If access was granted above, proceed to create or update record:
00706                                                 if ($recordAccess)      {
00707 
00708                                                         list($tscPID) = t3lib_BEfunc::getTSCpid($table,$id,$old_pid_value ? $old_pid_value : $fieldArray['pid']);       // Here the "pid" is set IF NOT the old pid was a string pointing to a place in the subst-id array.
00709                                                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
00710                                                         if ($status=='new' && $table=='pages' && is_array($TSConfig['permissions.']))   {
00711                                                                 $fieldArray = $this->setTSconfigPermissions($fieldArray,$TSConfig['permissions.']);
00712                                                         }
00713                                                         if ($createNewVersion)  {
00714                                                                 $newVersion_placeholderFieldArray = $fieldArray;
00715                                                         }
00716 
00717                                                                 // Processing of all fields in incomingFieldArray and setting them in $fieldArray
00718                                                         $fieldArray = $this->fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$theRealPid,$status,$tscPID);
00719 
00720                                                                 // NOTICE! All manipulation beyond this point bypasses both "excludeFields" AND possible "MM" relations / file uploads to field!
00721 
00722                                                                 // Forcing some values unto field array:
00723                                                         $fieldArray = $this->overrideFieldArray($table,$fieldArray);    // NOTICE: This overriding is potentially dangerous; permissions per field is not checked!!!
00724                                                         if ($createNewVersion)  {
00725                                                                 $newVersion_placeholderFieldArray = $this->overrideFieldArray($table,$newVersion_placeholderFieldArray);
00726                                                         }
00727 
00728                                                                 // Setting system fields
00729                                                         if ($status=='new')     {
00730                                                                 if ($TCA[$table]['ctrl']['crdate'])     {
00731                                                                         $fieldArray[$TCA[$table]['ctrl']['crdate']]=time();
00732                                                                         if ($createNewVersion)  $newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['crdate']]=time();
00733                                                                 }
00734                                                                 if ($TCA[$table]['ctrl']['cruser_id'])  {
00735                                                                         $fieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid;
00736                                                                         if ($createNewVersion)  $newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid;
00737                                                                 }
00738                                                         } elseif ($this->checkSimilar) {        // Removing fields which are equal to the current value:
00739                                                                 $fieldArray = $this->compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray);
00740                                                         }
00741                                                         if ($TCA[$table]['ctrl']['tstamp'] && count($fieldArray))       {
00742                                                                 $fieldArray[$TCA[$table]['ctrl']['tstamp']]=time();
00743                                                                 if ($createNewVersion)  $newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['tstamp']]=time();
00744                                                         }
00745                                                         if ($resetRejected)     {
00746                                                                 $fieldArray['t3ver_stage'] = 0;
00747                                                         }
00748 
00749                                                                 // Hook: processDatamap_postProcessFieldArray
00750                                                         foreach($hookObjectsArr as $hookObj)    {
00751                                                                 if (method_exists($hookObj, 'processDatamap_postProcessFieldArray')) {
00752                                                                         $hookObj->processDatamap_postProcessFieldArray($status, $table, $id, $fieldArray, $this);
00753                                                                 }
00754                                                         }
00755 
00756                                                                 // Performing insert/update. If fieldArray has been unset by some userfunction (see hook above), don't do anything
00757                                                                 // Kasper: Unsetting the fieldArray is dangerous; MM relations might be saved already and files could have been uploaded that are now "lost"
00758                                                         if (is_array($fieldArray)) {
00759                                                                 if ($status=='new')     {
00760                                                                         if ($createNewVersion)  {       // This creates a new version of the record with online placeholder and offline version
00761                                                                                 $versioningType = $table==='pages' ? $this->BE_USER->workspaceVersioningTypeGetClosest(t3lib_div::intInRange($TYPO3_CONF_VARS['BE']['newPagesVersioningType'],-1,1)) : -1;
00762                                                                                 if ($this->BE_USER->workspaceVersioningTypeAccess($versioningType))     {
00763                                                                                         $newVersion_placeholderFieldArray['t3ver_label'] = 'INITIAL PLACEHOLDER';
00764                                                                                         $newVersion_placeholderFieldArray['t3ver_state'] = 1;   // Setting placeholder state value for temporary record
00765                                                                                         $newVersion_placeholderFieldArray['t3ver_wsid'] = $this->BE_USER->workspace;    // Setting workspace - only so display of place holders can filter out those from other workspaces.
00766                                                                                         $newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['label']] = '[PLACEHOLDER, WS#'.$this->BE_USER->workspace.']';
00767                                                                                         $this->insertDB($table,$id,$newVersion_placeholderFieldArray,FALSE);    // Saving placeholder as 'original'
00768 
00769                                                                                                 // For the actual new offline version, set versioning values to point to placeholder:
00770                                                                                         $fieldArray['pid'] = -1;
00771                                                                                         $fieldArray['t3ver_oid'] = $this->substNEWwithIDs[$id];
00772                                                                                         $fieldArray['t3ver_id'] = 1;
00773                                                                                         $fieldArray['t3ver_state'] = -1;        // Setting placeholder state value for version (so it can know it is currently a new version...)
00774                                                                                         $fieldArray['t3ver_label'] = 'First draft version';
00775                                                                                         $fieldArray['t3ver_wsid'] = $this->BE_USER->workspace;
00776                                                                                         if ($table==='pages') {         // Swap mode set to "branch" so we can build branches for pages.
00777                                                                                                 $fieldArray['t3ver_swapmode'] = $versioningType;
00778                                                                                         }
00779                                                                                         $phShadowId = $this->insertDB($table,$id,$fieldArray,TRUE,0,TRUE);      // When inserted, $this->substNEWwithIDs[$id] will be changed to the uid of THIS version and so the interface will pick it up just nice!
00780                                                                                         if ($phShadowId)        {
00781                                                                                                 $this->placeholderShadowing($table,$phShadowId);
00782                                                                                         }
00783                                                                                 } else $this->newlog('Versioning type "'.$versioningType.'" was not allowed, so could not create new record.',1);
00784                                                                         } else {
00785                                                                                 $this->insertDB($table,$id,$fieldArray,FALSE,$incomingFieldArray['uid']);
00786                                                                         }
00787                                                                 } else {
00788                                                                         $this->updateDB($table,$id,$fieldArray);
00789                                                                         $this->placeholderShadowing($table,$id);
00790                                                                 }
00791                                                         }
00792 
00793                                                                 // Hook: processDatamap_afterDatabaseOperations
00794                                                         foreach($hookObjectsArr as $hookObj)    {
00795                                                                 if (method_exists($hookObj, 'processDatamap_afterDatabaseOperations')) {
00796                                                                         $hookObj->processDatamap_afterDatabaseOperations($status, $table, $id, $fieldArray, $this);
00797                                                                 }
00798                                                         }
00799                                                 }       // if ($recordAccess)   {
00800                                         }       // if (is_array($incomingFieldArray))   {
00801                                 }
00802                         }
00803                 }
00804                 $this->dbAnalysisStoreExec();
00805                 $this->removeRegisteredFiles();
00806         }
00807 
00815         function placeholderShadowing($table,$id)       {
00816                 global $TCA;
00817 
00818                 if ($liveRec = t3lib_BEfunc::getLiveVersionOfRecord($table,$id,'*'))    {
00819                         if ((int)$liveRec['t3ver_state']===1)   {
00820                                 $justStoredRecord = t3lib_BEfunc::getRecord($table,$id);
00821                                 $newRecord = array();
00822 
00823                                 $shadowColumns = t3lib_div::trimExplode(',', $TCA[$table]['ctrl']['shadowColumnsForNewPlaceholders'],1);
00824                                 foreach($shadowColumns as $fieldName)   {
00825                                         if (strcmp($justStoredRecord[$fieldName],$liveRec[$fieldName])) {
00826                                                 $newRecord[$fieldName] = $justStoredRecord[$fieldName];
00827                                         }
00828                                 }
00829 
00830                                 if (count($newRecord))  {
00831                                         $this->newlog('Shadowing done on fields '.implode(',',array_keys($newRecord)).' in Placeholder record '.$table.':'.$liveRec['uid'].' (offline version UID='.$id.')');
00832                                         $this->updateDB($table,$liveRec['uid'],$newRecord);
00833                                 }
00834                         }
00835                 }
00836         }
00837 
00851         function fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$realPid,$status,$tscPID)  {
00852                 global $TCA;
00853 
00854                         // Initialize:
00855                 t3lib_div::loadTCA($table);
00856                 $originalLanguageRecord = NULL;
00857                 $originalLanguage_diffStorage = NULL;
00858                 $diffStorageFlag = FALSE;
00859 
00860                         // Setting 'currentRecord' and 'checkValueRecord':
00861                 if (strstr($id,'NEW'))  {
00862                         $currentRecord = $checkValueRecord = $fieldArray;       // must have the 'current' array - not the values after processing below...
00863 
00864                                 // IF $incomingFieldArray is an array, overlay it.
00865                                 // The point is that when new records are created as copies with flex type fields there might be a field containing information about which DataStructure to use and without that information the flexforms cannot be correctly processed.... This should be OK since the $checkValueRecord is used by the flexform evaluation only anyways...
00866                         if (is_array($incomingFieldArray) && is_array($checkValueRecord))       {
00867                                 $checkValueRecord = t3lib_div::array_merge_recursive_overrule($checkValueRecord, $incomingFieldArray);
00868                         }
00869                 } else {
00870                         $currentRecord = $checkValueRecord = $this->recordInfo($table,$id,'*'); // We must use the current values as basis for this!
00871 
00872                                 // Get original language record if available:
00873                         if (is_array($currentRecord)
00874                                         && $TCA[$table]['ctrl']['transOrigDiffSourceField']
00875                                         && $TCA[$table]['ctrl']['languageField']
00876                                         && $currentRecord[$TCA[$table]['ctrl']['languageField']] > 0
00877                                         && $TCA[$table]['ctrl']['transOrigPointerField']
00878                                         && intval($currentRecord[$TCA[$table]['ctrl']['transOrigPointerField']]) > 0)   {
00879 
00880                                 $lookUpTable = $TCA[$table]['ctrl']['transOrigPointerTable'] ? $TCA[$table]['ctrl']['transOrigPointerTable'] : $table;
00881                                 $originalLanguageRecord = $this->recordInfo($lookUpTable,$currentRecord[$TCA[$table]['ctrl']['transOrigPointerField']],'*');
00882                                 t3lib_BEfunc::workspaceOL($lookUpTable,$originalLanguageRecord);
00883                                 $originalLanguage_diffStorage = unserialize($currentRecord[$TCA[$table]['ctrl']['transOrigDiffSourceField']]);
00884                         }
00885                 }
00886                 $this->checkValue_currentRecord = $checkValueRecord;
00887 
00888                         /*
00889                                 In the following all incoming value-fields are tested:
00890                                 - Are the user allowed to change the field?
00891                                 - Is the field uid/pid (which are already set)
00892                                 - perms-fields for pages-table, then do special things...
00893                                 - If the field is nothing of the above and the field is configured in TCA, the fieldvalues are evaluated by ->checkValue
00894 
00895                                 If everything is OK, the field is entered into $fieldArray[]
00896                         */
00897                 foreach($incomingFieldArray as $field => $fieldValue)   {
00898                         if (!in_array($table.'-'.$field, $this->exclude_array) && !$this->data_disableFields[$table][$id][$field])      {       // The field must be editable.
00899 
00900                                         // Checking if a value for language can be changed:
00901                                 $languageDeny = $TCA[$table]['ctrl']['languageField'] && !strcmp($TCA[$table]['ctrl']['languageField'], $field) && !$this->BE_USER->checkLanguageAccess($fieldValue);
00902 
00903                                 if (!$languageDeny)     {
00904                                                 // Stripping slashes - will probably be removed the day $this->stripslashes_values is removed as an option...
00905                                         if ($this->stripslashes_values) {
00906                                                 if (is_array($fieldValue))      {
00907                                                         t3lib_div::stripSlashesOnArray($fieldValue);
00908                                                 } else $fieldValue = stripslashes($fieldValue);
00909                                         }
00910 
00911                                         switch ($field) {
00912                                                 case 'uid':
00913                                                 case 'pid':
00914                                                         // Nothing happens, already set
00915                                                 break;
00916                                                 case 'perms_userid':
00917                                                 case 'perms_groupid':
00918                                                 case 'perms_user':
00919                                                 case 'perms_group':
00920                                                 case 'perms_everybody':
00921                                                                 // Permissions can be edited by the owner or the administrator
00922                                                         if ($table=='pages' && ($this->admin || $status=='new' || $this->pageInfo($id,'perms_userid')==$this->userid) ) {
00923                                                                 $value=intval($fieldValue);
00924                                                                 switch($field)  {
00925                                                                         case 'perms_userid':
00926                                                                                 $fieldArray[$field]=$value;
00927                                                                         break;
00928                                                                         case 'perms_groupid':
00929                                                                                 $fieldArray[$field]=$value;
00930                                                                         break;
00931                                                                         default:
00932                                                                                 if ($value>=0 && $value<pow(2,5))       {
00933                                                                                         $fieldArray[$field]=$value;
00934                                                                                 }
00935                                                                         break;
00936                                                                 }
00937                                                         }
00938                                                 break;
00939                                                 case 't3ver_oid':
00940                                                 case 't3ver_id':
00941                                                 case 't3ver_wsid':
00942                                                 case 't3ver_state':
00943                                                 case 't3ver_swapmode':
00944                                                 case 't3ver_count':
00945                                                 case 't3ver_stage':
00946                                                 case 't3ver_tstamp':
00947                                                         // t3ver_label is not here because it CAN be edited as a regular field!
00948                                                 break;
00949                                                 default:
00950                                                         if (isset($TCA[$table]['columns'][$field]))     {
00951                                                                         // Evaluating the value.
00952                                                                 $res = $this->checkValue($table,$field,$fieldValue,$id,$status,$realPid,$tscPID);
00953                                                                 if (isset($res['value']))       {
00954                                                                         $fieldArray[$field]=$res['value'];
00955 
00956                                                                                 // Add the value of the original record to the diff-storage content:
00957                                                                         if ($TCA[$table]['ctrl']['transOrigDiffSourceField'])   {
00958                                                                                 $originalLanguage_diffStorage[$field] = $originalLanguageRecord[$field];
00959                                                                                 $diffStorageFlag = TRUE;
00960                                                                         }
00961                                                                 }
00962                                                         } elseif ($TCA[$table]['ctrl']['origUid']===$field) {   // Allow value for original UID to pass by...
00963                                                                 $fieldArray[$field] = $fieldValue;
00964                                                         }
00965                                                 break;
00966                                         }
00967                                 }       // Checking language.
00968                         }       // Check exclude fields / disabled fields...
00969                 }
00970 
00971                         // Add diff-storage information:
00972                 if ($diffStorageFlag && !isset($fieldArray[$TCA[$table]['ctrl']['transOrigDiffSourceField']]))  {       // If the field is set it would probably be because of an undo-operation - in which case we should not update the field of course...
00973                          $fieldArray[$TCA[$table]['ctrl']['transOrigDiffSourceField']] = serialize($originalLanguage_diffStorage);
00974                 }
00975 
00976                         // Checking for RTE-transformations of fields:
00977                 $types_fieldConfig = t3lib_BEfunc::getTCAtypes($table,$currentRecord);
00978                 $theTypeString = t3lib_BEfunc::getTCAtypeValue($table,$currentRecord);
00979                 if (is_array($types_fieldConfig))       {
00980                         reset($types_fieldConfig);
00981                         while(list(,$vconf) = each($types_fieldConfig)) {
00982                                         // Write file configuration:
00983                                 $eFile = t3lib_parsehtml_proc::evalWriteFile($vconf['spec']['static_write'],array_merge($currentRecord,$fieldArray));   // inserted array_merge($currentRecord,$fieldArray) 170502
00984 
00985                                         // RTE transformations:
00986                                 if (!$this->dontProcessTransformations) {
00987                                         if (isset($fieldArray[$vconf['field']]))        {
00988                                                         // Look for transformation flag:
00989                                                 switch((string)$incomingFieldArray['_TRANSFORM_'.$vconf['field']])      {
00990                                                         case 'RTE':
00991                                                                 $RTEsetup = $this->BE_USER->getTSConfig('RTE',t3lib_BEfunc::getPagesTSconfig($tscPID));
00992                                                                 $thisConfig = t3lib_BEfunc::RTEsetup($RTEsetup['properties'],$table,$vconf['field'],$theTypeString);
00993 
00994                                                                         // Set alternative relative path for RTE images/links:
00995                                                                 $RTErelPath = is_array($eFile) ? dirname($eFile['relEditFile']) : '';
00996 
00997                                                                         // Get RTE object, draw form and set flag:
00998                                                                 $RTEobj = &t3lib_BEfunc::RTEgetObj();
00999                                                                 if (is_object($RTEobj)) {
01000                                                                         $fieldArray[$vconf['field']] = $RTEobj->transformContent('db',$fieldArray[$vconf['field']],$table,$vconf['field'],$currentRecord,$vconf['spec'],$thisConfig,$RTErelPath,$currentRecord['pid']);
01001                                                                 } else {
01002                                                                         debug('NO RTE OBJECT FOUND!');
01003                                                                 }
01004                                                         break;
01005                                                 }
01006                                         }
01007                                 }
01008 
01009                                         // Write file configuration:
01010                                 if (is_array($eFile))   {
01011                                         $mixedRec = array_merge($currentRecord,$fieldArray);
01012                                         $SW_fileContent = t3lib_div::getUrl($eFile['editFile']);
01013                                         $parseHTML = t3lib_div::makeInstance('t3lib_parsehtml_proc');
01014                                         $parseHTML->init('','');
01015 
01016                                         $eFileMarker = $eFile['markerField']&&trim($mixedRec[$eFile['markerField']]) ? trim($mixedRec[$eFile['markerField']]) : '###TYPO3_STATICFILE_EDIT###';
01017                                         $insertContent = str_replace($eFileMarker,'',$mixedRec[$eFile['contentField']]);        // must replace the marker if present in content!
01018 
01019                                         $SW_fileNewContent = $parseHTML->substituteSubpart($SW_fileContent, $eFileMarker, chr(10).$insertContent.chr(10), 1, 1);
01020                                         t3lib_div::writeFile($eFile['editFile'],$SW_fileNewContent);
01021 
01022                                                 // Write status:
01023                                         if (!strstr($id,'NEW') && $eFile['statusField'])        {
01024                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
01025                                                         $table,
01026                                                         'uid='.intval($id),
01027                                                         array(
01028                                                                 $eFile['statusField'] => $eFile['relEditFile'].' updated '.date('d-m-Y H:i:s').', bytes '.strlen($mixedRec[$eFile['contentField']])
01029                                                         )
01030                                                 );
01031                                         }
01032                                 } elseif ($eFile && is_string($eFile))  {
01033                                         $this->log($table,$id,2,0,1,"Write-file error: '%s'",13,array($eFile),$realPid);
01034                                 }
01035                         }
01036                 }
01037                         // Return fieldArray
01038                 return $fieldArray;
01039         }
01040 
01041 
01042 
01043 
01044 
01045 
01046 
01047 
01048 
01049 
01050 
01051 
01052         /*********************************************
01053          *
01054          * Evaluation of input values
01055          *
01056          ********************************************/
01057 
01072         function checkValue($table,$field,$value,$id,$status,$realPid,$tscPID)  {
01073                 global $TCA, $PAGES_TYPES;
01074                 t3lib_div::loadTCA($table);
01075 
01076                 $res = Array(); // result array
01077                 $recFID = $table.':'.$id.':'.$field;
01078 
01079                         // Processing special case of field pages.doktype
01080                 if ($table=='pages' && $field=='doktype')       {
01081                                 // If the user may not use this specific doktype, we issue a warning
01082                         if (! ($this->admin || t3lib_div::inList($this->BE_USER->groupData['pagetypes_select'],$value)))        {
01083                                 $propArr = $this->getRecordProperties($table,$id);
01084                                 $this->log($table,$id,5,0,1,"You cannot change the 'doktype' of page '%s' to the desired value.",1,array($propArr['header']),$propArr['event_pid']);
01085                                 return $res;
01086                         };
01087                         if ($status=='update')  {
01088                                         // This checks 1) if we should check for disallowed tables and 2) if there are records from disallowed tables on the current page
01089                                 $onlyAllowedTables = isset($PAGES_TYPES[$value]['onlyAllowedTables']) ? $PAGES_TYPES[$value]['onlyAllowedTables'] : $PAGES_TYPES['default']['onlyAllowedTables'];
01090                                 if ($onlyAllowedTables) {
01091                                         $theWrongTables = $this->doesPageHaveUnallowedTables($id,$value);
01092                                         if ($theWrongTables)    {
01093                                                 $propArr = $this->getRecordProperties($table,$id);
01094                                                 $this->log($table,$id,5,0,1,"'doktype' of page '%s' could not be changed because the page contains records from disallowed tables; %s",2,array($propArr['header'],$theWrongTables),$propArr['event_pid']);
01095                                                 return $res;
01096                                         }
01097                                 }
01098                         }
01099                 }
01100 
01101                         // Get current value:
01102                 $curValueRec = $this->recordInfo($table,$id,$field);
01103                 $curValue = $curValueRec[$field];
01104 
01105                         // Getting config for the field
01106                 $tcaFieldConf = $TCA[$table]['columns'][$field]['config'];
01107 
01108                         // Preform processing:
01109                 $res = $this->checkValue_SW($res,$value,$tcaFieldConf,$table,$id,$curValue,$status,$realPid,$recFID,$field,$this->uploadedFileArray[$table][$id][$field],$tscPID);
01110 
01111                 return $res;
01112         }
01113 
01132         function checkValue_SW($res,$value,$tcaFieldConf,$table,$id,$curValue,$status,$realPid,$recFID,$field,$uploadedFiles,$tscPID)   {
01133 
01134                 $PP = array($table,$id,$curValue,$status,$realPid,$recFID,$tscPID);
01135 
01136                 switch ($tcaFieldConf['type']) {
01137                         case 'text':
01138                         case 'passthrough':
01139                         case 'user':
01140                                 $res['value'] = $value;
01141                         break;
01142                         case 'input':
01143                                 $res = $this->checkValue_input($res,$value,$tcaFieldConf,$PP,$field);
01144                         break;
01145                         case 'check':
01146                                 $res = $this->checkValue_check($res,$value,$tcaFieldConf,$PP);
01147                         break;
01148                         case 'radio':
01149                                 $res = $this->checkValue_radio($res,$value,$tcaFieldConf,$PP);
01150                         break;
01151                         case 'group':
01152                         case 'select':
01153                                 $res = $this->checkValue_group_select($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field);
01154                         break;
01155                         case 'flex':
01156                                 if ($field)     {       // FlexForms are only allowed for real fields.
01157                                         $res = $this->checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field);
01158                                 }
01159                         break;
01160                         default:
01161                                 #debug(array($tcaFieldConf,$res,$value),'NON existing field type:');
01162                         break;
01163                 }
01164 
01165                 return $res;
01166         }
01167 
01178         function checkValue_input($res,$value,$tcaFieldConf,$PP,$field='')      {
01179                 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
01180 
01181                         // Secures the string-length to be less than max. Will probably make problems with multi-byte strings!
01182                 if (intval($tcaFieldConf['max'])>0)     {$value = substr($value,0,intval($tcaFieldConf['max']));}
01183 
01184                         // Checking range of value:
01185                 if ($tcaFieldConf['range'] && $value!=$tcaFieldConf['checkbox'])        {       // If value is not set to the allowed checkbox-value then it is checked against the ranges
01186                         if (isset($tcaFieldConf['range']['upper'])&&$value>$tcaFieldConf['range']['upper'])     {$value=$tcaFieldConf['range']['upper'];}
01187                         if (isset($tcaFieldConf['range']['lower'])&&$value<$tcaFieldConf['range']['lower'])     {$value=$tcaFieldConf['range']['lower'];}
01188                 }
01189 
01190                         // Process evaluation settings:
01191                 $evalCodesArray = t3lib_div::trimExplode(',',$tcaFieldConf['eval'],1);
01192                 $res = $this->checkValue_input_Eval($value,$evalCodesArray,$tcaFieldConf['is_in']);
01193 
01194                         // Process UNIQUE settings:
01195                 if ($field && $realPid>=0)      {       // Field is NOT set for flexForms - which also means that uniqueInPid and unique is NOT available for flexForm fields! Also getUnique should not be done for versioning and if PID is -1 ($realPid<0) then versioning is happening...
01196                         if ($res['value'] && in_array('uniqueInPid',$evalCodesArray))   {
01197                                 $res['value'] = $this->getUnique($table,$field,$res['value'],$id,$realPid);
01198                         }
01199                         if ($res['value'] && in_array('unique',$evalCodesArray))        {
01200                                 $res['value'] = $this->getUnique($table,$field,$res['value'],$id);
01201                         }
01202                 }
01203 
01204                 return $res;
01205         }
01206 
01216         function checkValue_check($res,$value,$tcaFieldConf,$PP)        {
01217                 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
01218 
01219                 $itemC = count($tcaFieldConf['items']);
01220                 if (!$itemC)    {$itemC=1;}
01221                 $maxV = pow(2,$itemC);
01222 
01223                 if ($value<0)   {$value=0;}
01224                 if ($value>$maxV)       {$value=$maxV;}
01225                 $res['value'] = $value;
01226 
01227                 return $res;
01228         }
01229 
01239         function checkValue_radio($res,$value,$tcaFieldConf,$PP)        {
01240                 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
01241 
01242                 if (is_array($tcaFieldConf['items']))   {
01243                         foreach($tcaFieldConf['items'] as $set) {
01244                                 if (!strcmp($set[1],$value))    {
01245                                         $res['value'] = $value;
01246                                         break;
01247                                 }
01248                         }
01249                 }
01250 
01251                 return $res;
01252         }
01253 
01265         function checkValue_group_select($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field)   {
01266 
01267                 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
01268 
01269                         // Detecting if value sent is an array and if so, implode it around a comma:
01270                 if (is_array($value))   {
01271                         $value = implode(',',$value);
01272                 }
01273 
01274                         // This converts all occurencies of '&#123;' to the byte 123 in the string - this is needed in very rare cases where filenames with special characters (like ???, umlaud etc) gets sent to the server as HTML entities instead of bytes. The error is done only by MSIE, not Mozilla and Opera.
01275                         // Anyways, this should NOT disturb anything else:
01276                 $value = $this->convNumEntityToByteValue($value);
01277 
01278                         // When values are sent as group or select they come as comma-separated values which are exploded by this function:
01279                 $valueArray = $this->checkValue_group_select_explodeSelectGroupValue($value);
01280 
01281                         // If not multiple is set, then remove duplicates:
01282                 if (!$tcaFieldConf['multiple']) {
01283                         $valueArray = array_unique($valueArray);
01284                 }
01285 
01286                         // If an exclusive key is found, discard all others:
01287                 if ($tcaFieldConf['type']=='select' && $tcaFieldConf['exclusiveKeys'])  {
01288                         $exclusiveKeys = t3lib_div::trimExplode(',', $tcaFieldConf['exclusiveKeys']);
01289                         foreach($valueArray as $kk => $vv)      {
01290                                 if (in_array($vv, $exclusiveKeys))      {       // $vv is the item key!
01291                                         $valueArray = Array($kk => $vv);
01292                                         break;
01293                                 }
01294                         }
01295                 }
01296 
01297                 // This could be a good spot for parsing the array through a validation-function which checks if the values are alright (except that database references are not in their final form - but that is the point, isn't it?)
01298                 // NOTE!!! Must check max-items of files before the later check because that check would just leave out filenames if there are too many!!
01299 
01300                         // Checking for select / authMode, removing elements from $valueArray if any of them is not allowed!
01301                 if ($tcaFieldConf['type']=='select' && $tcaFieldConf['authMode'])       {
01302                         $preCount = count($valueArray);
01303                         foreach($valueArray as $kk => $vv)      {
01304                                 if (!$this->BE_USER->checkAuthMode($table,$field,$vv,$tcaFieldConf['authMode']))        {
01305                                         unset($valueArray[$kk]);
01306                                 }
01307                         }
01308 
01309                                 // During the check it turns out that the value / all values were removed - we respond by simply returning an empty array so nothing is written to DB for this field.
01310                         if ($preCount && !count($valueArray))   {
01311                                 return array();
01312                         }
01313                 }
01314 
01315                         // For group types:
01316                 if ($tcaFieldConf['type']=='group')     {
01317                         switch($tcaFieldConf['internal_type'])  {
01318                                 case 'file':
01319                                         $valueArray = $this->checkValue_group_select_file(
01320                                                 $valueArray,
01321                                                 $tcaFieldConf,
01322                                                 $curValue,
01323                                                 $uploadedFiles,
01324                                                 $status,
01325                                                 $table,
01326                                                 $id,
01327                                                 $recFID
01328                                         );
01329                                 break;
01330                                 case 'db':
01331                                         $valueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'group');
01332                                 break;
01333                         }
01334                 }
01335                         // For select types which has a foreign table attached:
01336                 if ($tcaFieldConf['type']=='select' && $tcaFieldConf['foreign_table'])  {
01337                         $valueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'select');
01338                 }
01339 
01340 // BTW, checking for min and max items here does NOT make any sense when MM is used because the above function calls will just return an array with a single item (the count) if MM is used... Why didn't I perform the check before? Probably because we could not evaluate the validity of record uids etc... Hmm...
01341 
01342                         // Checking the number of items, that it is correct.
01343                         // If files, there MUST NOT be too many files in the list at this point, so check that prior to this code.
01344                 $valueArrayC = count($valueArray);
01345                 $minI = isset($tcaFieldConf['minitems']) ? intval($tcaFieldConf['minitems']):0;
01346 
01347                         // NOTE to the comment: It's not really possible to check for too few items, because you must then determine first, if the field is actual used regarding the CType.
01348                 $maxI = isset($tcaFieldConf['maxitems']) ? intval($tcaFieldConf['maxitems']):1;
01349                 if ($valueArrayC > $maxI)       {$valueArrayC=$maxI;}   // Checking for not too many elements
01350 
01351                         // Dumping array to list
01352                 $newVal=array();
01353                 foreach($valueArray as $nextVal)        {
01354                         if ($valueArrayC==0)    {break;}
01355                         $valueArrayC--;
01356                         $newVal[]=$nextVal;
01357                 }
01358                 $res['value'] = implode(',',$newVal);
01359 
01360                 return $res;
01361         }
01362 
01377         function checkValue_group_select_file($valueArray,$tcaFieldConf,$curValue,$uploadedFileArray,$status,$table,$id,$recFID)        {
01378 
01379                         // If any files are uploaded:
01380                 if (is_array($uploadedFileArray) &&
01381                         $uploadedFileArray['name'] &&
01382                         strcmp($uploadedFileArray['tmp_name'],'none'))  {
01383                                 $valueArray[]=$uploadedFileArray['tmp_name'];
01384                                 $this->alternativeFileName[$uploadedFileArray['tmp_name']] = $uploadedFileArray['name'];
01385                 }
01386 
01387                         // Creating fileFunc object.
01388                 if (!$this->fileFunc)   {
01389                         $this->fileFunc = t3lib_div::makeInstance('t3lib_basicFileFunctions');
01390                         $this->include_filefunctions=1;
01391                 }
01392                         // Setting permitted extensions.
01393                 $all_files = Array();
01394                 $all_files['webspace']['allow'] = $tcaFieldConf['allowed'];
01395                 $all_files['webspace']['deny'] = $tcaFieldConf['disallowed'] ? $tcaFieldConf['disallowed'] : '*';
01396                 $all_files['ftpspace'] = $all_files['webspace'];
01397                 $this->fileFunc->init('', $all_files);
01398 
01399                         // If there is an upload folder defined:
01400                 if ($tcaFieldConf['uploadfolder'])      {
01401                                 // For logging..
01402                         $propArr = $this->getRecordProperties($table,$id);
01403 
01404                                 // Get destrination path:
01405                         $dest = $this->destPathFromUploadFolder($tcaFieldConf['uploadfolder']);
01406 
01407                                 // If we are updating:
01408                         if ($status=='update')  {
01409 
01410                                         // Traverse the input values and convert to absolute filenames in case the update happens to an autoVersionized record.
01411                                         // Background: This is a horrible workaround! The problem is that when a record is auto-versionized the files of the record get copied and therefore get new names which is overridden with the names from the original record in the incoming data meaning both lost files and double-references!
01412                                         // The only solution I could come up with (except removing support for managing files when autoversioning) was to convert all relative files to absolute names so they are copied again (and existing files deleted). This should keep references intact but means that some files are copied, then deleted after being copied _again_.
01413                                         // Actually, the same problem applies to database references in case auto-versioning would include sub-records since in such a case references are remapped - and they would be overridden due to the same principle then.
01414                                         // Illustration of the problem comes here:
01415                                         // We have a record 123 with a file logo.gif. We open and edit the files header in a workspace. So a new version is automatically made.
01416                                         // The versions uid is 456 and the file is copied to "logo_01.gif". But the form data that we sents was based on uid 123 and hence contains the filename "logo.gif" from the original.
01417                                         // The file management code below will do two things: First it will blindly accept "logo.gif" as a file attached to the record (thus creating a double reference) and secondly it will find that "logo_01.gif" was not in the incoming filelist and therefore should be deleted.
01418                                         // If we prefix the incoming file "logo.gif" with its absolute path it will be seen as a new file added. Thus it will be copied to "logo_02.gif". "logo_01.gif" will still be deleted but since the files are the same the difference is zero - only more processing and file copying for no reason. But it will work.
01419                                 if ($this->autoVersioningUpdate===TRUE) {
01420                                         foreach($valueArray as $key => $theFile)        {
01421                                                 if ($theFile===basename($theFile))      {
01422                                                         $valueArray[$key] = PATH_site.$tcaFieldConf['uploadfolder'].'/'.$theFile;
01423                                                 }
01424                                         }
01425                                 }
01426 
01427                                         // Finding the CURRENT files listed, either from MM or from the current record.
01428                                 $theFileValues=array();
01429                                 if ($tcaFieldConf['MM'])        {       // If MM relations for the files also!
01430                                         $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
01431                                         $dbAnalysis->start('','files',$tcaFieldConf['MM'],$id);
01432                                         reset($dbAnalysis->itemArray);
01433                                         while (list($somekey,$someval)=each($dbAnalysis->itemArray))    {
01434                                                 if ($someval['id'])     {
01435                                                         $theFileValues[]=$someval['id'];
01436                                                 }
01437                                         }
01438                                 } else {
01439                                         $theFileValues=t3lib_div::trimExplode(',',$curValue,1);
01440                                 }
01441 
01442                                         // DELETE files: If existing files were found, traverse those and register files for deletion which has been removed:
01443                                 if (count($theFileValues))      {
01444                                                 // Traverse the input values and for all input values which match an EXISTING value, remove the existing from $theFileValues array (this will result in an array of all the existing files which should be deleted!)
01445                                         foreach($valueArray as $key => $theFile)        {
01446                                                 if ($theFile && !strstr(t3lib_div::fixWindowsFilePath($theFile),'/'))   {
01447                                                         $theFileValues = t3lib_div::removeArrayEntryByValue($theFileValues,$theFile);
01448                                                 }
01449                                         }
01450 
01451                                                 // This array contains the filenames in the uploadfolder that should be deleted:
01452                                         foreach($theFileValues as $key => $theFile)     {
01453                                                 $theFile = trim($theFile);
01454                                                 if (@is_file($dest.'/'.$theFile))       {
01455                                                         $this->removeFilesStore[]=$dest.'/'.$theFile;
01456                                                 } elseif ($theFile) {
01457                                                         $this->log($table,$id,5,0,1,"Could not delete file '%s' (does not exist). (%s)",10,array($dest.'/'.$theFile, $recFID),$propArr['event_pid']);
01458                                                 }
01459                                         }
01460                                 }
01461                         }
01462 
01463                                 // Traverse the submitted values:
01464                         foreach($valueArray as $key => $theFile)        {
01465                                         // NEW FILES? If the value contains '/' it indicates, that the file is new and should be added to the uploadsdir (whether its absolute or relative does not matter here)
01466                                 if (strstr(t3lib_div::fixWindowsFilePath($theFile),'/'))        {
01467                                                 // Init:
01468                                         $maxSize = intval($tcaFieldConf['max_size']);
01469                                         $cmd='';
01470                                         $theDestFile='';                // Must be cleared. Else a faulty fileref may be inserted if the below code returns an error!! (Change: 22/12/2000)
01471 
01472                                                 // Check various things before copying file:
01473                                         if (@is_dir($dest) && (@is_file($theFile) || @is_uploaded_file($theFile)))      {               // File and destination must exist
01474 
01475                                                         // Finding size. For safe_mode we have to rely on the size in the upload array if the file is uploaded.
01476                                                 if (is_uploaded_file($theFile) && $theFile==$uploadedFileArray['tmp_name'])     {
01477                                                         $fileSize = $uploadedFileArray['size'];
01478                                                 } else {
01479                                                         $fileSize = filesize($theFile);
01480                                                 }
01481 
01482                                                 if (!$maxSize || $fileSize<=($maxSize*1024))    {       // Check file size:
01483                                                                 // Prepare filename:
01484                                                         $theEndFileName = isset($this->alternativeFileName[$theFile]) ? $this->alternativeFileName[$theFile] : $theFile;
01485                                                         $fI = t3lib_div::split_fileref($theEndFileName);
01486 
01487                                                                 // Check for allowed extension:
01488                                                         if ($this->fileFunc->checkIfAllowed($fI['fileext'], $dest, $theEndFileName)) {
01489                                                                 $theDestFile = $this->fileFunc->getUniqueName($this->fileFunc->cleanFileName($fI['file']), $dest);
01490 
01491                                                                         // If we have a unique destination filename, then write the file:
01492                                                                 if ($theDestFile)       {
01493                                                                         t3lib_div::upload_copy_move($theFile,$theDestFile);
01494                                                                         $this->copiedFileMap[$theFile] = $theDestFile;
01495                                                                         clearstatcache();
01496                                                                         if (!@is_file($theDestFile))    $this->log($table,$id,5,0,1,"Copying file '%s' failed!: The destination path (%s) may be write protected. Please make it write enabled!. (%s)",16,array($theFile, dirname($theDestFile), $recFID),$propArr['event_pid']);
01497                                                                 } else $this->log($table,$id,5,0,1,"Copying file '%s' failed!: No destination file (%s) possible!. (%s)",11,array($theFile, $theDestFile, $recFID),$propArr['event_pid']);
01498                                                         } else $this->log($table,$id,5,0,1,"Fileextension '%s' not allowed. (%s)",12,array($fI['fileext'], $recFID),$propArr['event_pid']);
01499                                                 } else $this->log($table,$id,5,0,1,"Filesize (%s) of file '%s' exceeds limit (%s). (%s)",13,array(t3lib_div::formatSize($fileSize),$theFile,t3lib_div::formatSize($maxSize*1024),$recFID),$propArr['event_pid']);
01500                                         } else $this->log($table,$id,5,0,1,'The destination (%s) or the source file (%s) does not exist. (%s)',14,array($dest, $theFile, $recFID),$propArr['event_pid']);
01501 
01502                                                 // If the destination file was created, we will set the new filename in the value array, otherwise unset the entry in the value array!
01503                                         if (@is_file($theDestFile))     {
01504                                                 $info = t3lib_div::split_fileref($theDestFile);
01505                                                 $valueArray[$key]=$info['file']; // The value is set to the new filename
01506                                         } else {
01507                                                 unset($valueArray[$key]);       // The value is set to the new filename
01508                                         }
01509                                 }
01510                         }
01511 
01512                                 // If MM relations for the files, we will set the relations as MM records and change the valuearray to contain a single entry with a count of the number of files!
01513                         if ($tcaFieldConf['MM'])        {
01514                                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
01515                                 $dbAnalysis->tableArray['files']=array();       // dummy
01516 
01517                                 reset($valueArray);
01518                                 while (list($key,$theFile)=each($valueArray))   {
01519                                                 // explode files
01520                                                 $dbAnalysis->itemArray[]['id']=$theFile;
01521                                 }
01522                                 if ($status=='update')  {
01523                                         $dbAnalysis->writeMM($tcaFieldConf['MM'],$id,0);
01524                                 } else {
01525                                         $this->dbAnalysisStore[] = array($dbAnalysis, $tcaFieldConf['MM'], $id, 0);     // This will be traversed later to execute the actions
01526                                 }
01527                                 $cc=count($dbAnalysis->itemArray);
01528                                 $valueArray = array($cc);
01529                         }
01530                 }
01531 
01532                 return $valueArray;
01533         }
01534 
01547         function checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field)   {
01548                 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
01549 
01550                 if (is_array($value))   {
01551 
01552                                 // Get current value array:
01553                         $dataStructArray = t3lib_BEfunc::getFlexFormDS($tcaFieldConf,$this->checkValue_currentRecord,$table);
01554 #debug($this->checkValue_currentRecord);
01555                         $currentValueArray = t3lib_div::xml2array($curValue);
01556                         if (!is_array($currentValueArray))      $currentValueArray = array();
01557                         if (is_array($currentValueArray['meta']['currentLangId']))              unset($currentValueArray['meta']['currentLangId']);     // Remove all old meta for languages...
01558 
01559                                 // Evaluation of input values:
01560                         $value['data'] = $this->checkValue_flex_procInData($value['data'],$currentValueArray['data'],$uploadedFiles['data'],$dataStructArray,$PP);
01561 
01562                                 // Create XML and convert charsets from input value:
01563                         $xmlValue = $this->checkValue_flexArray2Xml($value,TRUE);
01564 
01565                                 // If we wanted to set UTF fixed:
01566                         // $storeInCharset='utf-8';
01567                         // $currentCharset=$GLOBALS['LANG']->charSet;
01568                         // $xmlValue = $GLOBALS['LANG']->csConvObj->conv($xmlValue,$currentCharset,$storeInCharset,1);
01569                         $storeInCharset=$GLOBALS['LANG']->charSet;
01570 
01571                                 // Merge them together IF they are both arrays:
01572                                 // Here we convert the currently submitted values BACK to an array, then merge the two and then BACK to XML again. This is needed to ensure the charsets are the same (provided that the current value was already stored IN the charset that the new value is converted to).
01573                         if (is_array($currentValueArray))       {
01574                                 $arrValue = t3lib_div::xml2array($xmlValue);
01575                                 $arrValue = t3lib_div::array_merge_recursive_overrule($currentValueArray,$arrValue);
01576                                 $xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
01577                         }
01578 
01579                                 // Temporary fix to delete flex form elements:
01580                         $deleteCMDs = t3lib_div::_GP('_DELETE_FLEX_FORMdata');
01581                         if (is_array($deleteCMDs[$table][$id][$field]['data'])) {
01582                                 $arrValue = t3lib_div::xml2array($xmlValue);
01583                                 $this->_DELETE_FLEX_FORMdata($arrValue['data'],$deleteCMDs[$table][$id][$field]['data']);
01584                                 $xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
01585                         }
01586 
01587                                 // Temporary fix to move flex form elements up:
01588                         $moveCMDs = t3lib_div::_GP('_MOVEUP_FLEX_FORMdata');
01589                         if (is_array($moveCMDs[$table][$id][$field]['data']))   {
01590                                 $arrValue = t3lib_div::xml2array($xmlValue);
01591                                 $this->_MOVE_FLEX_FORMdata($arrValue['data'],$moveCMDs[$table][$id][$field]['data'], 'up');
01592                                 $xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
01593                         }
01594 
01595                                 // Temporary fix to move flex form elements down:
01596                         $moveCMDs = t3lib_div::_GP('_MOVEDOWN_FLEX_FORMdata');
01597                         if (is_array($moveCMDs[$table][$id][$field]['data']))   {
01598                                 $arrValue = t3lib_div::xml2array($xmlValue);
01599                                 $this->_MOVE_FLEX_FORMdata($arrValue['data'],$moveCMDs[$table][$id][$field]['data'], 'down');
01600                                 $xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
01601                         }
01602 
01603                                 // Create the value XML:
01604                         $res['value']='';
01605                         $res['value'].=$xmlValue;
01606                 } else {        // Passthrough...:
01607                         $res['value']=$value;
01608                 }
01609 
01610                 return $res;
01611         }
01612 
01620         function checkValue_flexArray2Xml($array, $addPrologue=FALSE)   {
01621                 $flexObj = t3lib_div::makeInstance('t3lib_flexformtools');
01622                 return $flexObj->flexArray2Xml($array, $addPrologue);
01623         }
01624 
01632         function _DELETE_FLEX_FORMdata(&$valueArrayToRemoveFrom,$deleteCMDS)    {
01633                 if (is_array($valueArrayToRemoveFrom) && is_array($deleteCMDS)) {
01634                         foreach($deleteCMDS as $key => $value)  {
01635                                 if (is_array($deleteCMDS[$key]))        {
01636                                         $this->_DELETE_FLEX_FORMdata($valueArrayToRemoveFrom[$key],$deleteCMDS[$key]);
01637                                 } else {
01638                                         unset($valueArrayToRemoveFrom[$key]);
01639                                 }
01640                         }
01641                 }
01642         }
01643 
01654         function _MOVE_FLEX_FORMdata(&$valueArrayToMoveIn, $moveCMDS, $direction)       {
01655                 if (is_array($valueArrayToMoveIn) && is_array($moveCMDS))       {
01656 
01657                                 // Only execute the first move command:
01658                         list ($key, $value) = each ($moveCMDS);
01659 
01660                         if (is_array($moveCMDS[$key]))  {
01661                                 $this->_MOVE_FLEX_FORMdata($valueArrayToMoveIn[$key],$moveCMDS[$key], $direction);
01662                         } else {
01663                                 switch ($direction) {
01664                                         case 'up':
01665                                                 if ($key > 1) {
01666                                                         $tmpArr = $valueArrayToMoveIn[$key];
01667                                                         $valueArrayToMoveIn[$key] = $valueArrayToMoveIn[$key-1];
01668                                                         $valueArrayToMoveIn[$key-1] = $tmpArr;
01669                                                 }
01670                                         break;
01671                                         case 'down':
01672                                                 if ($key < count($valueArrayToMoveIn)) {
01673                                                         $tmpArr = $valueArrayToMoveIn[$key];
01674                                                         $valueArrayToMoveIn[$key] = $valueArrayToMoveIn[$key+1];
01675                                                         $valueArrayToMoveIn[$key+1] = $tmpArr;
01676                                                 }
01677                                         break;
01678                                 }
01679                         }
01680                 }
01681         }
01682 
01683 
01684 
01685 
01686 
01687 
01688 
01689 
01690 
01691 
01692 
01693 
01694 
01695 
01696 
01697 
01698 
01699 
01700         /*********************************************
01701          *
01702          * Helper functions for evaluation functions.
01703          *
01704          ********************************************/
01705 
01716         function getUnique($table,$field,$value,$id,$newPid=0)  {
01717                 global $TCA;
01718 
01719                         // Initialize:
01720                 t3lib_div::loadTCA($table);
01721                 $whereAdd='';
01722                 $newValue='';
01723                 if (intval($newPid))    { $whereAdd.=' AND pid='.intval($newPid); } else { $whereAdd.=' AND pid>=0'; }  // "AND pid>=0" for versioning
01724                 $whereAdd.=$this->deleteClause($table);
01725 
01726                         // If the field is configured in TCA, proceed:
01727                 if (is_array($TCA[$table]) && is_array($TCA[$table]['columns'][$field]))        {
01728 
01729                                 // Look for a record which might already have the value:
01730                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, $field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($value, $table).' AND uid!='.intval($id).$whereAdd);
01731                         $counter = 0;
01732 
01733                                 // For as long as records with the test-value existing, try again (with incremented numbers appended).
01734                         while ($GLOBALS['TYPO3_DB']->sql_num_rows($res))        {
01735                                 $newValue = $value.$counter;
01736                                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, $field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($newValue, $table).' AND uid!='.intval($id).$whereAdd);
01737                                 $counter++;
01738                                 if ($counter>100)       { break; }      // At "100" it will give up and accept a duplicate - should probably be fixed to a small hash string instead...!
01739                         }
01740                                 // If the new value is there:
01741                         $value = strlen($newValue) ? $newValue : $value;
01742                 }
01743                 return $value;
01744         }
01745 
01754         function checkValue_input_Eval($value,$evalArray,$is_in)        {
01755                 $res = Array();
01756                 $newValue = $value;
01757                 $set = true;
01758 
01759                 foreach($evalArray as $func)    {
01760                         switch($func)   {
01761                                 case 'int':
01762                                 case 'year':
01763                                 case 'date':
01764                                 case 'datetime':
01765                                 case 'time':
01766                                 case 'timesec':
01767                                         $value = intval($value);
01768                                 break;
01769                                 case 'double2':
01770                                         $theDec = 0;
01771                                         for ($a=strlen($value); $a>0; $a--)     {
01772                                                 if (substr($value,$a-1,1)=='.' || substr($value,$a-1,1)==',')   {
01773                                                         $theDec = substr($value,$a);
01774                                                         $value = substr($value,0,$a-1);
01775                                                         break;
01776                                                 }
01777                                         }
01778                                         $theDec = ereg_replace('[^0-9]','',$theDec).'00';
01779                                         $value = intval(str_replace(' ','',$value)).'.'.substr($theDec,0,2);
01780                                 break;
01781                                 case 'md5':
01782                                         if (strlen($value)!=32){$set=false;}
01783                                 break;
01784                                 case 'trim':
01785                                         $value = trim($value);
01786                                 break;
01787                                 case 'upper':
01788                                         $value = strtoupper($value);
01789 #                                       $value = strtr($value, 'áéúíâêûôîæøåäöü', 'ÁÉÚÍÂÊÛÔÎÆØÅÄÖÜ');   // WILL make trouble with other charsets than ISO-8859-1, so what do we do here? PHP-function which can handle this for other charsets? Currently the browsers JavaScript will fix it.
01790                                 break;
01791                                 case 'lower':
01792                                         $value = strtolower($value);
01793 #                                       $value = strtr($value, 'ÁÉÚÍÂÊÛÔÎÆØÅÄÖÜ', 'áéúíâêûôîæøåäöü');   // WILL make trouble with other charsets than ISO-8859-1, so what do we do here? PHP-function which can handle this for other charsets? Currently the browsers JavaScript will fix it.
01794                                 break;
01795                                 case 'required':
01796                                         if (!$value)    {$set=0;}
01797                                 break;
01798                                 case 'is_in':
01799                                         $c=strlen($value);
01800                                         if ($c) {
01801                                                 $newVal = '';
01802                                                 for ($a=0;$a<$c;$a++)   {
01803                                                         $char = substr($value,$a,1);
01804                                                         if (strstr($is_in,$char))       {
01805                                                                 $newVal.=$char;
01806                                                         }
01807                                                 }
01808                                                 $value = $newVal;
01809                                         }
01810                                 break;
01811                                 case 'nospace':
01812                                         $value = str_replace(' ','',$value);
01813                                 break;
01814                                 case 'alpha':
01815                                         $value = ereg_replace('[^a-zA-Z]','',$value);
01816                                 break;
01817                                 case 'num':
01818                                         $value = ereg_replace('[^0-9]','',$value);
01819                                 break;
01820                                 case 'alphanum':
01821                                         $value = ereg_replace('[^a-zA-Z0-9]','',$value);
01822                                 break;
01823                                 case 'alphanum_x':
01824                                         $value = ereg_replace('[^a-zA-Z0-9_-]','',$value);
01825                                 break;
01826                                 default:
01827                                         if (substr($func, 0, 3) == 'tx_')       {
01828                                                 $evalObj = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func].':&'.$func);
01829                                                 if(is_object($evalObj) && method_exists($evalObj, 'evaluateFieldValue'))        {
01830                                                         $value = $evalObj->evaluateFieldValue($value, $is_in, $set);
01831                                                 }
01832                                         }
01833                                 break;
01834                         }
01835                 }
01836                 if ($set)       {$res['value'] = $value;}
01837                 return $res;
01838         }
01839 
01850         function checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,$type)     {
01851                 $tables = $type=='group'?$tcaFieldConf['allowed']:$tcaFieldConf['foreign_table'].','.$tcaFieldConf['neg_foreign_table'];
01852                 $prep = $type=='group'?$tcaFieldConf['prepend_tname']:$tcaFieldConf['neg_foreign_table'];
01853 
01854                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
01855                 $dbAnalysis->registerNonTableValues=$tcaFieldConf['allowNonIdValues'] ? 1 : 0;
01856                 $dbAnalysis->start(implode(',',$valueArray),$tables);
01857 
01858                 if ($tcaFieldConf['MM'])        {
01859                         if ($status=='update')  {
01860                                 $dbAnalysis->writeMM($tcaFieldConf['MM'],$id,$prep);
01861                         } else {
01862                                 $this->dbAnalysisStore[] = array($dbAnalysis,$tcaFieldConf['MM'],$id,$prep);    // This will be traversed later to execute the actions
01863                         }
01864                         $cc=count($dbAnalysis->itemArray);
01865                         $valueArray = array($cc);
01866                 } else {
01867                         $valueArray = $dbAnalysis->getValueArray($prep);
01868                         if ($type=='select' && $prep)   {
01869                                 $valueArray = $dbAnalysis->convertPosNeg($valueArray,$tcaFieldConf['foreign_table'],$tcaFieldConf['neg_foreign_table']);
01870                         }
01871                 }
01872 
01873                         // Here we should se if 1) the records exist anymore, 2) which are new and check if the BE_USER has read-access to the new ones.
01874                 return $valueArray;
01875         }
01876 
01883         function checkValue_group_select_explodeSelectGroupValue($value)        {
01884                 $valueArray = t3lib_div::trimExplode(',',$value,1);
01885                 reset($valueArray);
01886                 while(list($key,$newVal)=each($valueArray))     {
01887                         $temp=explode('|',$newVal,2);
01888                         $valueArray[$key] = str_replace(',','',str_replace('|','',rawurldecode($temp[0])));
01889                 }
01890                 return $valueArray;
01891         }
01892 
01907         function checkValue_flex_procInData($dataPart,$dataPart_current,$uploadedFiles,$dataStructArray,$pParams,$callBackFunc='')      {
01908 #debug(array($dataPart,$dataPart_current,$dataStructArray));
01909                 if (is_array($dataPart))        {
01910                         foreach($dataPart as $sKey => $sheetDef)        {
01911                                 list ($dataStruct,$actualSheet) = t3lib_div::resolveSheetDefInDS($dataStructArray,$sKey);
01912 #debug(array($dataStruct,$actualSheet,$sheetDef,$actualSheet,$sKey));
01913                                 if (is_array($dataStruct) && $actualSheet==$sKey && is_array($sheetDef))        {
01914                                         foreach($sheetDef as $lKey => $lData)   {
01915                                                 $this->checkValue_flex_procInData_travDS(
01916                                                         $dataPart[$sKey][$lKey],
01917                                                         $dataPart_current[$sKey][$lKey],
01918                                                         $uploadedFiles[$sKey][$lKey],
01919                                                         $dataStruct['ROOT']['el'],
01920                                                         $pParams,
01921                                                         $callBackFunc,
01922                                                         $sKey.'/'.$lKey.'/'
01923                                                 );
01924                                         }
01925                                 }
01926                         }
01927                 }
01928 
01929                 return $dataPart;
01930         }
01931 
01946         function checkValue_flex_procInData_travDS(&$dataValues,$dataValues_current,$uploadedFiles,$DSelements,$pParams,$callBackFunc,$structurePath)   {
01947                 if (is_array($DSelements))      {
01948 
01949                                 // For each DS element:
01950                         foreach($DSelements as $key => $dsConf) {
01951 
01952                                                 // Array/Section:
01953                                 if ($DSelements[$key]['type']=='array') {
01954                                         if (is_array($dataValues[$key]['el']))  {
01955                                                 if ($DSelements[$key]['section'])       {
01956                                                         foreach($dataValues[$key]['el'] as $ik => $el)  {
01957                                                                 $theKey = key($el);
01958                                                                 if (is_array($dataValues[$key]['el'][$ik][$theKey]['el']))      {
01959                                                                         $this->checkValue_flex_procInData_travDS(
01960                                                                                         $dataValues[$key]['el'][$ik][$theKey]['el'],
01961                                                                                         $dataValues_current[$key]['el'][$ik][$theKey]['el'],
01962                                                                                         $uploadedFiles[$key]['el'][$ik][$theKey]['el'],
01963                                                                                         $DSelements[$key]['el'][$theKey]['el'],
01964                                                                                         $pParams,
01965                                                                                         $callBackFunc,
01966                                                                                         $structurePath.$key.'/el/'.$ik.'/'.$theKey.'/el/'
01967                                                                                 );
01968                                                                 }
01969                                                         }
01970                                                 } else {
01971                                                         if (!isset($dataValues[$key]['el']))    $dataValues[$key]['el']=array();
01972                                                         $this->checkValue_flex_procInData_travDS(
01973                                                                         $dataValues[$key]['el'],
01974                                                                         $dataValues_current[$key]['el'],
01975                                                                         $uploadedFiles[$key]['el'],
01976                                                                         $DSelements[$key]['el'],
01977                                                                         $pParams,
01978                                                                         $callBackFunc,
01979                                                                         $structurePath.$key.'/el/'
01980                                                                 );
01981                                                 }
01982                                         }
01983                                 } else {
01984                                         if (is_array($dsConf['TCEforms']['config']) && is_array($dataValues[$key]))     {
01985                                                 foreach($dataValues[$key] as $vKey => $data)    {
01986 
01987                                                         if ($callBackFunc)      {
01988                                                                 if (is_object($this->callBackObj))      {
01989                                                                         $res = $this->callBackObj->$callBackFunc(
01990                                                                                                 $pParams,
01991                                                                                                 $dsConf['TCEforms']['config'],
01992                                                                                                 $dataValues[$key][$vKey],
01993                                                                                                 $dataValues_current[$key][$vKey],
01994                                                                                                 $uploadedFiles[$key][$vKey],
01995                                                                                                 $structurePath.$key.'/'.$vKey.'/'
01996                                                                                         );
01997                                                                 } else {
01998                                                                         $res = $this->$callBackFunc(
01999                                                                                                 $pParams,
02000                                                                                                 $dsConf['TCEforms']['config'],
02001                                                                                                 $dataValues[$key][$vKey],
02002                                                                                                 $dataValues_current[$key][$vKey],
02003                                                                                                 $uploadedFiles[$key][$vKey]
02004                                                                                         );
02005                                                                 }
02006                                                         } else {        // Default
02007                                                                 list($CVtable,$CVid,$CVcurValue,$CVstatus,$CVrealPid,$CVrecFID,$CVtscPID) = $pParams;
02008 
02009                                                                 $res = $this->checkValue_SW(
02010                                                                                         array(),
02011                                                                                         $dataValues[$key][$vKey],
02012                                                                                         $dsConf['TCEforms']['config'],
02013                                                                                         $CVtable,
02014                                                                                         $CVid,
02015                                                                                         $dataValues_current[$key][$vKey],
02016                                                                                         $CVstatus,
02017                                                                                         $CVrealPid,
02018                                                                                         $CVrecFID,
02019                                                                                         '',
02020                                                                                         $uploadedFiles[$key][$vKey],
02021                                                                                         array(),
02022                                                                                         $CVtscPID
02023                                                                                 );
02024 
02025                                                                         // Look for RTE transformation of field:
02026                                                                 if ($dataValues[$key]['_TRANSFORM_'.$vKey] == 'RTE' && !$this->dontProcessTransformations)      {
02027 
02028                                                                                 // Unsetting trigger field - we absolutely don't want that into the data storage!
02029                                                                         unset($dataValues[$key]['_TRANSFORM_'.$vKey]);
02030 
02031                                                                         if (isset($res['value']))       {
02032 
02033                                                                                         // Calculating/Retrieving some values here:
02034                                                                                 list(,,$recFieldName) = explode(':', $CVrecFID);
02035                                                                                 $theTypeString = t3lib_BEfunc::getTCAtypeValue($CVtable,$this->checkValue_currentRecord);
02036                                                                                 $specConf = t3lib_BEfunc::getSpecConfParts('',$dsConf['TCEforms']['defaultExtras']);
02037 
02038                                                                                         // Find, thisConfig:
02039                                                                                 $RTEsetup = $this->BE_USER->getTSConfig('RTE',t3lib_BEfunc::getPagesTSconfig($CVtscPID));
02040                                                                                 $thisConfig = t3lib_BEfunc::RTEsetup($RTEsetup['properties'],$CVtable,$recFieldName,$theTypeString);
02041 
02042                                                                                         // Get RTE object, draw form and set flag:
02043                                                                                 $RTEobj = &t3lib_BEfunc::RTEgetObj();
02044                                                                                 if (is_object($RTEobj)) {
02045                                                                                         $res['value'] = $RTEobj->transformContent('db',$res['value'],$CVtable,$recFieldName,$this->checkValue_currentRecord,$specConf,$thisConfig,'',$CVrealPid);
02046                                                                                 } else {
02047                                                                                         debug('NO RTE OBJECT FOUND!');
02048                                                                                 }
02049                                                                         }
02050                                                                 }
02051                                                         }
02052 
02053                                                                 // Adding the value:
02054                                                         if (isset($res['value']))       {
02055                                                                 $dataValues[$key][$vKey] = $res['value'];
02056                                                         }
02057                                                 }
02058                                         }
02059                                 }
02060                         }
02061                 }
02062         }
02063 
02064 
02065 
02066 
02067 
02068 
02069 
02070 
02071 
02072 
02073 
02074 
02075 
02076 
02077 
02078 
02079 
02080         /*********************************************
02081          *
02082          * PROCESSING COMMANDS
02083          *
02084          ********************************************/
02085 
02092         function process_cmdmap() {
02093                 global $TCA, $TYPO3_CONF_VARS;
02094 
02095                         // Editing frozen:
02096                 if ($this->BE_USER->workspace!==0 && $this->BE_USER->workspaceRec['freeze'])    {
02097                         $this->newlog('All editing in this workspace has been frozen!',1);
02098                         return FALSE;
02099                 }
02100 
02101                         // Hook initialization:
02102                 $hookObjectsArr = array();
02103                 if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'])) {
02104                         foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'] as $classRef) {
02105                                 $hookObjectsArr[] = &t3lib_div::getUserObj($classRef);
02106                         }
02107                 }
02108 
02109                         // Traverse command map:
02110                 reset($this->cmdmap);
02111                 while(list($table,) = each($this->cmdmap))      {
02112 
02113                                 // Check if the table may be modified!
02114                         $modifyAccessList = $this->checkModifyAccessList($table);
02115                         if (!$modifyAccessList) {
02116                                 $id = 0;
02117                                 $this->log($table,$id,2,0,1,"Attempt to modify table '%s' without permission",1,array($table));
02118                         }       // FIXME: $id not set here (Comment added by Sebastian Kurfuerst)
02119 
02120                                 // Check basic permissions and circumstances:
02121                         if (isset($TCA[$table]) && !$this->tableReadOnly($table) && is_array($this->cmdmap[$table]) && $modifyAccessList)       {
02122 
02123                                         // Traverse the command map:
02124                                 foreach($this->cmdmap[$table] as $id => $incomingCmdArray)      {
02125                                         if (is_array($incomingCmdArray))        {       // have found a command.
02126 
02127                                                         // Get command and value (notice, only one command is observed at a time!):
02128                                                 reset($incomingCmdArray);
02129                                                 $command = key($incomingCmdArray);
02130                                                 $value = current($incomingCmdArray);
02131 
02132                                                 foreach($hookObjectsArr as $hookObj) {
02133                                                         if (method_exists($hookObj, 'processCmdmap_preProcess')) {
02134                                                                 $hookObj->processCmdmap_preProcess($command, $table, $id, $value, $this);
02135                                                         }
02136                                                 }
02137 
02138                                                         // Init copyMapping array:
02139                                                 $this->copyMappingArray = Array();              // Must clear this array before call from here to those functions: Contains mapping information between new and old id numbers.
02140 
02141                                                         // Branch, based on command
02142                                                 switch ($command)       {
02143                                                         case 'move':
02144                                                                 $this->moveRecord($table,$id,$value);
02145                                                         break;
02146                                                         case 'copy':
02147                                                                 if ($table === 'pages') {
02148                                                                         $this->copyPages($id,$value);
02149                                                                 } else {
02150                                                                         $this->copyRecord($table,$id,$value,1);
02151                                                                 }
02152                                                         break;
02153                                                         case 'localize':
02154                                                                 $this->localize($table,$id,$value);
02155                                                         break;
02156                                                         case 'version':
02157                                                                 switch ((string)$value['action'])       {
02158                                                                         case 'new':
02159                                                                                 $versionizeTree = t3lib_div::intInRange(!isset($value['treeLevels'])?-1:$value['treeLevels'],-1,100);
02160                                                                                 if ($table == 'pages' && $versionizeTree>=0)    {
02161                                                                                         $this->versionizePages($id,$value['label'],$versionizeTree);
02162                                                                                 } else {
02163                                                                                         $this->versionizeRecord($table,$id,$value['label']);
02164                                                                                 }
02165                                                                         break;
02166                                                                         case 'swap':
02167                                                                                 $this->version_swap($table,$id,$value['swapWith'],$value['swapIntoWS']);
02168                                                                         break;
02169                                                                         case 'clearWSID':
02170                                                                                 $this->version_clearWSID($table,$id);
02171                                                                         break;
02172                                                                         case 'setStage':
02173                                                                                 $idList = t3lib_div::trimExplode(',',$id,1);
02174                                                                                 foreach($idList as $id) {
02175                                                                                         $this->version_setStage($table,$id,$value['stageId'],$value['comment']?$value['comment']:$this->generalComment);
02176                                                                                 }
02177                                                                         break;
02178                                                                 }
02179                                                         break;
02180                                                         case 'delete':
02181                                                                 $this->deleteAction($table, $id);
02182                                                         break;
02183                                                         case 'undelete':
02184                                                                 $this->undeleteRecord($table, $id);
02185                                                         break;
02186                                                 }
02187 
02188                                                 foreach($hookObjectsArr as $hookObj) {
02189                                                         if (method_exists($hookObj, 'processCmdmap_postProcess')) {
02190                                                                 $hookObj->processCmdmap_postProcess($command, $table, $id, $value, $this);
02191                                                         }
02192                                                 }
02193 
02194                                                         // Merging the copy-array info together for remapping purposes.
02195                                                 $this->copyMappingArray_merged= t3lib_div::array_merge_recursive_overrule($this->copyMappingArray_merged,$this->copyMappingArray);
02196                                         }
02197                                 }
02198                         }
02199                 }
02200 
02201                         // Finally, before exit, check if there are ID references to remap. This might be the case if versioning or copying has taken place!
02202                 $this->remapListedDBRecords();
02203         }
02204 
02205 
02206 
02207 
02208 
02209 
02210 
02211 
02212 
02213 
02214 
02215         /*********************************************
02216          *
02217          * Cmd: Copying
02218          *
02219          ********************************************/
02220 
02232         function copyRecord($table,$uid,$destPid,$first=0,$overrideValues=array(),$excludeFields='')    {
02233                 global $TCA;
02234 
02235                 $uid = $origUid = intval($uid);
02236                 if ($TCA[$table] && $uid)       {
02237                         t3lib_div::loadTCA($table);
02238 /*
02239                                 // In case the record to be moved turns out to be an offline version, we have to find the live version and work on that one (this case happens for pages with "branch" versioning type)
02240                         if ($lookForLiveVersion = t3lib_BEfunc::getLiveVersionOfRecord($table,$uid,'uid'))      {
02241                                 $uid = $lookForLiveVersion['uid'];
02242                         }
02243                                 // Get workspace version of the source record, if any: Then we will copy workspace version instead:
02244                         if ($WSversion = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, $table, $uid, 'uid,t3ver_oid'))   {
02245                                 $uid = $WSversion['uid'];
02246                         }
02247                                 // Now, the $uid is the actual record we will copy while $origUid is the record we asked to get copied - but that could be a live version.
02248 */
02249                         if ($this->doesRecordExist($table,$uid,'show')) {               // This checks if the record can be selected which is all that a copy action requires.
02250                                 $data = Array();
02251 
02252                                 $nonFields = array_unique(t3lib_div::trimExplode(',','uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,t3ver_oid,t3ver_wsid,t3ver_id,t3ver_label,t3ver_state,t3ver_swapmode,t3ver_count,t3ver_stage,t3ver_tstamp,'.$excludeFields,1));
02253 
02254                                 // $row = $this->recordInfo($table,$uid,'*');
02255                                 $row = t3lib_BEfunc::getRecordWSOL($table,$uid);        // So it copies (and localized) content from workspace...
02256                                 if (is_array($row))     {
02257 
02258                                                 // Initializing:
02259                                         $theNewID = uniqid('NEW');
02260                                         $enableField = isset($TCA[$table]['ctrl']['enablecolumns']) ? $TCA[$table]['ctrl']['enablecolumns']['disabled'] : '';
02261                                         $headerField = $TCA[$table]['ctrl']['label'];
02262 
02263                                                 // Getting default data:
02264                                         $defaultData = $this->newFieldArray($table);
02265 
02266                                                 // Getting "copy-after" fields if applicable:
02267                                                 // origDestPid is retrieve before it may possibly be converted to resolvePid if the table is not sorted anyway. In this way, copying records to after another records which are not sorted still lets you use this function in order to copy fields from the one before.
02268                                         $copyAfterFields = $destPid<0 ? $this->fixCopyAfterDuplFields($table,$uid,abs($destPid),0) : array();
02269 
02270                                                 // Page TSconfig related:
02271                                         $tscPID = t3lib_BEfunc::getTSconfig_pidValue($table,$uid,$destPid);     // NOT using t3lib_BEfunc::getTSCpid() because we need the real pid - not the ID of a page, if the input is a page...
02272                                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
02273                                         $tE = $this->getTableEntries($table,$TSConfig);
02274 
02275                                                 // Traverse ALL fields of the selected record:
02276                                         foreach($row as $field => $value)       {
02277                                                 if (!in_array($field,$nonFields))       {
02278 
02279                                                                 // Get TCA configuration for the field:
02280                                                         $conf = $TCA[$table]['columns'][$field]['config'];
02281 
02282                                                                 // Preparation/Processing of the value:
02283                                                         if ($field=='pid')      {       // "pid" is hardcoded of course:
02284                                                                 $value = $destPid;
02285                                                         } elseif (isset($overrideValues[$field]))       {       // Override value...
02286                                                                 $value = $overrideValues[$field];
02287                                                         } elseif (isset($copyAfterFields[$field]))      {       // Copy-after value if available:
02288                                                                 $value = $copyAfterFields[$field];
02289                                                         } elseif ($TCA[$table]['ctrl']['setToDefaultOnCopy'] && t3lib_div::inList($TCA[$table]['ctrl']['setToDefaultOnCopy'],$field))   {       // Revert to default for some fields:
02290                                                                 $value = $defaultData[$field];
02291                                                         } else {
02292                                                                         // Hide at copy may override:
02293                                                                 if ($first && $field==$enableField && $TCA[$table]['ctrl']['hideAtCopy'] && !$this->neverHideAtCopy && !$tE['disableHideAtCopy'])       {
02294                                                                         $value=1;
02295                                                                 }
02296                                                                         // Prepend label on copy:
02297                                                                 if ($first && $field==$headerField && $TCA[$table]['ctrl']['prependAtCopy'] && !$tE['disablePrependAtCopy'])    {
02298                                                                         $value = $this->getCopyHeader($table,$this->resolvePid($table,$destPid),$field,$this->clearPrefixFromValue($table,$value),0);
02299                                                                 }
02300                                                                         // Processing based on the TCA config field type (files, references, flexforms...)
02301                                                                 $value = $this->copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf);
02302                                                         }
02303 
02304                                                                 // Add value to array.
02305                                                         $data[$table][$theNewID][$field] = $value;
02306                                                 }
02307                                         }
02308 
02309                                                 // Overriding values:
02310                                         if ($TCA[$table]['ctrl']['editlock'])   {
02311                                                 $data[$table][$theNewID][$TCA[$table]['ctrl']['editlock']] = 0;
02312                                         }
02313 
02314                                                 // Setting original UID:
02315                                         if ($TCA[$table]['ctrl']['origUid'])    {
02316                                                 $data[$table][$theNewID][$TCA[$table]['ctrl']['origUid']] = $uid;
02317                                         }
02318 
02319                                                 // Do the copy by simply submitting the array through TCEmain:
02320                                         $copyTCE = t3lib_div::makeInstance('t3lib_TCEmain');
02321                                         $copyTCE->stripslashes_values = 0;
02322                                         $copyTCE->copyTree = $this->copyTree;
02323                                         $copyTCE->cachedTSconfig = $this->cachedTSconfig;       // Copy forth the cached TSconfig
02324                                         $copyTCE->dontProcessTransformations=1;         // Transformations should NOT be carried out during copy
02325 
02326                                         $copyTCE->start($data,'',$this->BE_USER);
02327                                         $copyTCE->process_datamap();
02328 
02329                                                 // Getting the new UID:
02330                                         $theNewSQLID = $copyTCE->substNEWwithIDs[$theNewID];
02331                                         if ($theNewSQLID)       {
02332                                                 $this->copyMappingArray[$table][$origUid] = $theNewSQLID;
02333                                         }
02334 
02335                                                 // Copy back the cached TSconfig
02336                                         $this->cachedTSconfig = $copyTCE->cachedTSconfig;
02337                                         $this->errorLog = array_merge($this->errorLog,$copyTCE->errorLog);
02338                                         unset($copyTCE);
02339 
02340                                         return $theNewSQLID;
02341                                 } else $this->log($table,$uid,3,0,1,'Attempt to copy record that did not exist!');
02342                         } else $this->log($table,$uid,3,0,1,'Attempt to copy record without permission');
02343                 }
02344         }
02345 
02354         function copyPages($uid,$destPid)       {
02355 
02356                         // Initialize:
02357                 $uid = intval($uid);
02358                 $destPid = intval($destPid);
02359 
02360                         // Finding list of tables to copy.
02361                 $copyTablesArray = $this->admin ? $this->compileAdminTables() : explode(',',$this->BE_USER->groupData['tables_modify']);        // These are the tables, the user may modify
02362                 if (!strstr($this->copyWhichTables,'*'))        {               // If not all tables are allowed then make a list of allowed tables: That is the tables that figure in both allowed tables AND the copyTable-list
02363                         foreach($copyTablesArray as $k => $table)       {
02364                                 if (!$table || !t3lib_div::inList($this->copyWhichTables.',pages',$table))      {       // pages are always going...
02365                                         unset($copyTablesArray[$k]);
02366                                 }
02367                         }
02368                 }
02369                 $copyTablesArray = array_unique($copyTablesArray);
02370 
02371                         // Begin to copy pages if we're allowed to:
02372                 if ($this->admin || in_array('pages',$copyTablesArray)) {
02373 
02374                                 // Copy this page we're on. And set first-flag (this will trigger that the record is hidden if that is configured)!
02375                         $theNewRootID = $this->copySpecificPage($uid,$destPid,$copyTablesArray,1);
02376 
02377                                 // If we're going to copy recursively...:
02378                         if ($theNewRootID && $this->copyTree)   {
02379 
02380                                         // Get ALL subpages to copy (read-permissions are respected!):
02381                                 $CPtable = $this->int_pageTreeInfo(Array(), $uid, intval($this->copyTree), $theNewRootID);
02382 
02383                                         // Now copying the subpages:
02384                                 foreach($CPtable as $thePageUid => $thePagePid) {
02385                                         $newPid = $this->copyMappingArray['pages'][$thePagePid];
02386                                         if (isset($newPid))     {
02387                                                 $this->copySpecificPage($thePageUid,$newPid,$copyTablesArray);
02388                                         } else {
02389                                                 $this->log('pages',$uid,5,0,1,'Something went wrong during copying branch');
02390                                                 break;
02391                                         }
02392                                 }
02393                         }       // else the page was not copied. Too bad...
02394                 } else {
02395                         $this->log('pages',$uid,5,0,1,'Attempt to copy page without permission to this table');
02396                 }
02397         }
02398 
02408         function copySpecificPage($uid,$destPid,$copyTablesArray,$first=0)      {
02409                 global $TCA;
02410 
02411                         // Copy the page itself:
02412                 $theNewRootID = $this->copyRecord('pages',$uid,$destPid,$first);
02413 
02414                         // If a new page was created upon the copy operation we will proceed with all the tables ON that page:
02415                 if ($theNewRootID)      {
02416                         foreach($copyTablesArray as $table)     {
02417                                 if ($table && is_array($TCA[$table]) && $table!='pages')        {       // all records under the page is copied.
02418                                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($uid).$this->deleteClause($table), '', ($TCA[$table]['ctrl']['sortby'] ? $TCA[$table]['ctrl']['sortby'].' DESC' : ''));
02419                                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))     {
02420                                                 $this->copyRecord($table,$row['uid'], $theNewRootID);   // Copying each of the underlying records...
02421                                         }
02422                                 }
02423                         }
02424                         return $theNewRootID;
02425                 }
02426         }
02427 
02442         function copyRecord_raw($table,$uid,$pid,$overrideArray=array())        {
02443                 global $TCA;
02444 
02445                 $uid = intval($uid);
02446                 if ($TCA[$table] && $uid)       {
02447                         t3lib_div::loadTCA($table);
02448                         if ($this->doesRecordExist($table,$uid,'show')) {
02449 
02450                                         // Set up fields which should not be processed. They are still written - just passed through no-questions-asked!
02451                                 $nonFields = array('uid','pid','t3ver_id','t3ver_oid','t3ver_wsid','t3ver_label','t3ver_state','t3ver_swapmode','t3ver_count','t3ver_stage','t3ver_tstamp','perms_userid','perms_groupid','perms_user','perms_group','perms_everybody');
02452 
02453                                         // Select main record:
02454                                 $row = $this->recordInfo($table,$uid,'*');
02455                                 if (is_array($row))     {
02456 
02457                                                 // Merge in override array.
02458                                         $row = array_merge($row,$overrideArray);
02459 
02460                                                 // Traverse ALL fields of the selected record:
02461                                         foreach($row as $field => $value)       {
02462                                                 if (!in_array($field,$nonFields))       {
02463 
02464                                                                 // Get TCA configuration for the field:
02465                                                         $conf = $TCA[$table]['columns'][$field]['config'];
02466                                                         if (is_array($conf))    {
02467                                                                         // Processing based on the TCA config field type (files, references, flexforms...)
02468                                                                 $value = $this->copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf);
02469                                                         }
02470 
02471                                                                 // Add value to array.
02472                                                         $row[$field] = $value;
02473                                                 }
02474                                         }
02475 
02476                                                 // Force versioning related fields:
02477                                         $row['pid'] = $pid;
02478 
02479                                                 // Setting original UID:
02480                                         if ($TCA[$table]['ctrl']['origUid'])    {
02481                                                 $row[$TCA[$table]['ctrl']['origUid']] = $uid;
02482                                         }
02483 
02484                                                 // Do the copy by internal function
02485                                         $theNewSQLID = $this->insertNewCopyVersion($table,$row,$pid);
02486                                         if ($theNewSQLID)       {
02487                                                 $this->dbAnalysisStoreExec();
02488                                                 $this->dbAnalysisStore = array();
02489                                                 return $this->copyMappingArray[$table][$uid] = $theNewSQLID;
02490                                         }
02491                                 } else $this->log($table,$uid,3,0,1,'Attempt to rawcopy/versionize record that did not exist!');
02492                         } else $this->log($table,$uid,3,0,1,'Attempt to rawcopy/versionize record without copy permission');
02493                 }
02494         }
02495 
02506         function rawCopyPageContent($old_pid,$new_pid,$copyTablesArray) {
02507                 global $TCA;
02508 
02509                 if ($new_pid)   {
02510                         foreach($copyTablesArray as $table)     {
02511                                 if ($table && is_array($TCA[$table]) && $table!='pages')        {       // all records under the page is copied.
02512                                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($old_pid).$this->deleteClause($table));
02513                                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))     {
02514                                                 $this->copyRecord_raw($table,$row['uid'],$new_pid);     // Copying each of the underlying records (method RAW)
02515                                         }
02516                                 }
02517                         }
02518                 }
02519         }
02520 
02530         function insertNewCopyVersion($table,$fieldArray,$realPid)      {
02531                 global $TCA;
02532 
02533                 $id = uniqid('NEW');
02534 
02535                         // $fieldArray is set as current record.
02536                         // The point is that when new records are created as copies with flex type fields there might be a field containing information about which DataStructure to use and without that information the flexforms cannot be correctly processed.... This should be OK since the $checkValueRecord is used by the flexform evaluation only anyways...
02537                 $this->checkValue_currentRecord = $fieldArray;
02538 
02539                         // Traverse record and input-process each value:
02540                 foreach($fieldArray as $field => $fieldValue)   {
02541                         if (isset($TCA[$table]['columns'][$field]))     {
02542                                         // Evaluating the value.
02543                                 $res = $this->checkValue($table,$field,$fieldValue,$id,'new',$realPid,0);
02544                                 if (isset($res['value']))       {
02545                                         $fieldArray[$field] = $res['value'];
02546                                 }
02547                         }
02548                 }
02549 
02550                         // System fields being set:
02551                 if ($TCA[$table]['ctrl']['crdate'])     {
02552                         $fieldArray[$TCA[$table]['ctrl']['crdate']]=time();
02553                 }
02554                 if ($TCA[$table]['ctrl']['cruser_id'])  {
02555                         $fieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid;
02556                 }
02557                 if ($TCA[$table]['ctrl']['tstamp'])     {
02558                         $fieldArray[$TCA[$table]['ctrl']['tstamp']]=time();
02559                 }
02560 
02561                         // Finally, insert record:
02562                 $this->insertDB($table,$id,$fieldArray, TRUE);
02563 
02564                         // Return new id:
02565                 return $this->substNEWwithIDs[$id];
02566         }
02567 
02581         function copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf)  {
02582                 global $TCA;
02583 
02584                         // Process references and files, currently that means only the files, prepending absolute paths (so the TCEmain engine will detect the file as new and one that should be made into a copy)
02585                 $value = $this->copyRecord_procFilesRefs($conf, $uid, $value);
02586 
02587 
02588                         // Register if there are references to take care of (no change to value):
02589                 if ($this->isReferenceField($conf))     {
02590                         $allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table'];
02591                         $prependName = $conf['type']=='group' ? $conf['prepend_tname'] : $conf['neg_foreign_table'];
02592                         if ($conf['MM'])        {
02593                                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
02594                                 $dbAnalysis->start('',$allowedTables,$conf['MM'],$uid);
02595                                 $value = implode(',',$dbAnalysis->getValueArray($prependName));
02596                         }
02597                         if ($value)     {       // Setting the value in this array will notify the remapListedDBRecords() function that this field MAY need references to be corrected
02598                                 $this->registerDBList[$table][$uid][$field] = $value;
02599                         }
02600                 }
02601 
02602                         // For "flex" fieldtypes we need to traverse the structure for two reasons: If there are file references they have to be prepended with absolute paths and if there are database reference they MIGHT need to be remapped (still done in remapListedDBRecords())
02603                 if ($conf['type']=='flex')      {
02604 
02605                                 // Get current value array:
02606                         $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $row, $table);
02607                         $currentValueArray = t3lib_div::xml2array($value);
02608 
02609                                 // Traversing the XML structure, processing files:
02610                         if (is_array($currentValueArray))       {
02611                                 $currentValueArray['data'] = $this->checkValue_flex_procInData(
02612                                                         $currentValueArray['data'],
02613                                                         array(),        // Not used.
02614                                                         array(),        // Not used.
02615                                                         $dataStructArray,
02616                                                         array($table,$uid,$field),      // Parameters.
02617                                                         'copyRecord_flexFormCallBack'
02618                                                 );
02619                                 $value = $currentValueArray;    // Setting value as an array! -> which means the input will be processed according to the 'flex' type when the new copy is created.
02620                         }
02621                 }
02622 
02623                 return $value;
02624         }
02625 
02637         function copyRecord_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2)   {
02638 
02639                         // Extract parameters:
02640                 list($table, $uid, $field) = $pParams;
02641 
02642                         // Process references and files, currently that means only the files, prepending absolute paths:
02643                 $dataValue = $this->copyRecord_procFilesRefs($dsConf, $uid, $dataValue);
02644 
02645                         // If references are set for this field, set flag so they can be corrected later (in ->remapListedDBRecords())
02646                 if ($this->isReferenceField($dsConf) && strlen($dataValue)) {
02647                         $this->registerDBList[$table][$uid][$field] = 'FlexForm_reference';
02648                 }
02649 
02650                         // Return
02651                 return array('value' => $dataValue);
02652         }
02653 
02665         function copyRecord_procFilesRefs($conf, $uid, $value)  {
02666 
02667                         // Prepend absolute paths to files:
02668                 if ($conf['type']=='group' && $conf['internal_type']=='file')   {
02669 
02670                                 // Get an array with files as values:
02671                         if ($conf['MM'])        {
02672                                 $theFileValues = array();
02673 
02674                                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
02675                                 $dbAnalysis->start('', 'files', $conf['MM'], $uid);
02676 
02677                                 foreach($dbAnalysis->itemArray as $somekey => $someval) {
02678                                         if ($someval['id'])     {
02679                                                 $theFileValues[] = $someval['id'];
02680                                         }
02681                                 }
02682                         } else {
02683                                 $theFileValues = t3lib_div::trimExplode(',',$value,1);
02684                         }
02685 
02686                                 // Traverse this array of files:
02687                         $uploadFolder = $conf['uploadfolder'];
02688                         $dest = $this->destPathFromUploadFolder($uploadFolder);
02689                         $newValue = array();
02690 
02691                         foreach($theFileValues as $file)        {
02692                                 if (trim($file))        {
02693                                         $realFile = $dest.'/'.trim($file);
02694                                         if (@is_file($realFile))        {
02695                                                 $newValue[] = $realFile;
02696                                         }
02697                                 }
02698                         }
02699 
02700                                 // Implode the new filelist into the new value (all files have absolute paths now which means they will get copied when entering TCEmain as new values...)
02701                         $value = implode(',',$newValue);
02702                 }
02703 
02704                         // Return the new value:
02705                 return $value;
02706         }
02707 
02708 
02709 
02710 
02711 
02712 
02713 
02714 
02715 
02716 
02717 
02718 
02719 
02720         /*********************************************
02721          *
02722          * Cmd: Moving, Localizing
02723          *
02724          ********************************************/
02725 
02734         function moveRecord($table,$uid,$destPid)       {
02735                 global $TCA, $TYPO3_CONF_VARS;
02736 
02737                 if ($TCA[$table])       {
02738 
02739                                 // Prepare user defined objects (if any) for hooks which extend this function:
02740                         $hookObjectsArr = array();
02741                         if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['moveRecordClass'])) {
02742                                 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['moveRecordClass'] as $classRef) {
02743                                         $hookObjectsArr[] = &t3lib_div::getUserObj($classRef);
02744                                 }
02745                         }
02746 
02747                                 // In case the record to be moved turns out to be an offline version, we have to find the live version and work on that one (this case happens for pages with "branch" versioning type)
02748                         if ($lookForLiveVersion = t3lib_BEfunc::getLiveVersionOfRecord($table,$uid,'uid'))      {
02749                                 $uid = $lookForLiveVersion['uid'];
02750                         }
02751 
02752                                 // Get workspace version of the source record, if any:
02753                         $WSversion = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, $table, $uid, 'uid,t3ver_oid');
02754 
02755                                 // Initialize:
02756                         $sortRow = $TCA[$table]['ctrl']['sortby'];
02757                         $destPid = intval($destPid);
02758                         $origDestPid = $destPid;
02759 
02760                         $propArr = $this->getRecordProperties($table,$uid);     // Get this before we change the pid (for logging)
02761                         $moveRec = $this->getRecordProperties($table,$uid,TRUE);
02762                         $resolvedPid = $this->resolvePid($table,$destPid);      // This is the actual pid of the moving to destination
02763 
02764                                 // Finding out, if the record may be moved from where it is. If the record is a non-page, then it depends on edit-permissions.
02765                                 // If the record is a page, then there are two options: If the page is moved within itself, (same pid) it's edit-perms of the pid. If moved to another place then its both delete-perms of the pid and new-page perms on the destination.
02766                         if ($table!='pages' || $resolvedPid==$moveRec['pid'])   {
02767                                 $mayMoveAccess = $this->checkRecordUpdateAccess($table,$uid);   // Edit rights for the record...
02768                         } else {
02769                                 $mayMoveAccess = $this->doesRecordExist($table,$uid,'delete');
02770                         }
02771 
02772                                 // Finding out, if the record may be moved TO another place. Here we check insert-rights (non-pages = edit, pages = new), unless the pages are moved on the same pid, then edit-rights are checked
02773                         if ($table!='pages' || $resolvedPid!=$moveRec['pid'])   {
02774                                 $mayInsertAccess = $this->checkRecordInsertAccess($table,$resolvedPid,4);       // Insert rights for the record...
02775                         } else {
02776                                 $mayInsertAccess = $this->checkRecordUpdateAccess($table,$uid);
02777                         }
02778 
02779                                 // Check workspace permissions:
02780                         $workspaceAccessBlocked = array();
02781                         $recIsNewVersion = !strcmp($moveRec['_ORIG_pid'],'') && (int)$moveRec['t3ver_state']==1;        // Element was an online version AND it was in "New state" so it can be moved...
02782                         $destRes = $this->BE_USER->workspaceAllowLiveRecordsInPID($resolvedPid,$table);
02783                                 // Workspace source check:
02784                         if ($errorCode = $this->BE_USER->workspaceCannotEditRecord($table, $WSversion['uid'] ? $WSversion['uid'] : $uid))       {
02785                                 $workspaceAccessBlocked['src1']='Record could not be edited in workspace: '.$errorCode.' ';
02786                         } else {
02787                                 if (!$recIsNewVersion && $this->BE_USER->workspaceAllowLiveRecordsInPID($moveRec['pid'],$table)<=0)     {
02788                                         $workspaceAccessBlocked['src2']='Could not remove record from table "'.$table.'" from its page "'.$moveRec['pid'].'" ';
02789                                 }
02790                         }
02791                                 // Workspace destination check:
02792                         if (!($destRes>0 || ($recIsNewVersion && !$destRes)))   {       // All records can be inserted if $destRes is greater than zero. Only new versions can be inserted if $destRes is false. NO RECORDS can be inserted if $destRes is negative which indicates a stage not allowed for use.
02793                                 $workspaceAccessBlocked['dest1']='Could not insert record from table "'.$table.'" in destination PID "'.$resolvedPid.'" ';
02794                         } elseif ($destRes==1 && $WSversion['uid'])     {
02795                                 $workspaceAccessBlocked['dest2']='Could not insert other versions in destination PID ';
02796                         }
02797 
02798                                 // Checking if the pid is negative, but no sorting row is defined. In that case, find the correct pid. Basically this check make the error message 4-13 meaning less... But you can always remove this check if you prefer the error instead of a no-good action (which is to move the record to its own page...)
02799                         if (($destPid<0 && !$sortRow) || $destPid>=0)   {       // $destPid>=0 because we must correct pid in case of versioning "page" types.
02800                                 $destPid = $resolvedPid;
02801                         }
02802 
02803                                 // Timestamp field:
02804                         $updateFields = array();
02805                         if ($TCA[$table]['ctrl']['tstamp'])     {
02806                                 $updateFields[$TCA[$table]['ctrl']['tstamp']] = time();
02807                         }
02808 
02809                                         // If moving is allowed, begin the processing:
02810                         if (!count($workspaceAccessBlocked))    {
02811                                 if ($mayMoveAccess)     {
02812                                         if ($destPid>=0)        {       // insert as first element on page (where uid = $destPid)
02813                                                 if ($mayInsertAccess)   {
02814                                                         if ($table!='pages' || $this->destNotInsideSelf($destPid,$uid)) {
02815                                                                 $this->clear_cache($table,$uid);        // clear cache before moving
02816 
02817                                                                 $updateFields['pid'] = $destPid;        // Setting PID
02818 
02819                                                                         // table is sorted by 'sortby'
02820                                                                 if ($sortRow)   {
02821                                                                         $sortNumber = $this->getSortNumber($table,$uid,$destPid);
02822                                                                         $updateFields[$sortRow] = $sortNumber;
02823                                                                 }
02824                                                                         // Create query for update:
02825                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields);
02826 
02827                                                                         // Call post processing hooks:
02828                                                                 foreach($hookObjectsArr as $hookObj) {
02829                                                                         if (method_exists($hookObj, 'moveRecord_firstElementPostProcess')) {
02830                                                                                 $hookObj->moveRecord_firstElementPostProcess($table, $uid, $destPid, $moveRec, $updateFields, $this);
02831                                                                         }
02832                                                                 }
02833 
02834                                                                         // Logging...
02835                                                                 $newPropArr = $this->getRecordProperties($table,$uid);
02836                                                                 $oldpagePropArr = $this->getRecordProperties('pages',$propArr['pid']);
02837                                                                 $newpagePropArr = $this->getRecordProperties('pages',$destPid);
02838 
02839                                                                 if ($destPid!=$propArr['pid'])  {
02840                                                                         $this->log($table,$uid,4,$destPid,0,"Moved record '%s' (%s) to page '%s' (%s)",2,array($propArr['header'],$table.':'.$uid, $newpagePropArr['header'], $newPropArr['pid']),$propArr['pid']);     // Logged to old page
02841                                                                         $this->log($table,$uid,4,$destPid,0,"Moved record '%s' (%s) from page '%s' (%s)",3,array($propArr['header'],$table.':'.$uid, $oldpagePropArr['header'], $propArr['pid']),$destPid);     // Logged to new page
02842                                                                 } else {
02843                                                                         $this->log($table,$uid,4,$destPid,0,"Moved record '%s' (%s) on page '%s' (%s)",4,array($propArr['header'],$table.':'.$uid, $oldpagePropArr['header'], $propArr['pid']),$destPid);       // Logged to new page
02844                                                                 }
02845                                                                 $this->clear_cache($table,$uid);        // clear cache after moving
02846                                                                 $this->fixUniqueInPid($table,$uid);
02847                                                                         // fixCopyAfterDuplFields
02848                                                                 if ($origDestPid<0)     {$this->fixCopyAfterDuplFields($table,$uid,abs($origDestPid),1);}       // origDestPid is retrieve before it may possibly be converted to resolvePid if the table is not sorted anyway. In this way, copying records to after another records which are not sorted still lets you use this function in order to copy fields from the one before.
02849                                                         } else {
02850                                                                 $destPropArr = $this->getRecordProperties('pages',$destPid);
02851                                                                 $this->log($table,$uid,4,0,1,"Attempt to move page '%s' (%s) to inside of its own rootline (at page '%s' (%s))",10,array($propArr['header'],$uid, $destPropArr['header'], $destPid),$propArr['pid']);
02852                                                         }
02853                                                 }
02854                                         } else {        // Put after another record
02855                                                 if ($sortRow)   {       // table is being sorted
02856                                                         $sortInfo = $this->getSortNumber($table,$uid,$destPid);
02857                                                         $destPid = $sortInfo['pid'];    // Setting the destPid to the new pid of the record.
02858                                                         if (is_array($sortInfo))        {       // If not an array, there was an error (which is already logged)
02859                                                                 if ($mayInsertAccess)   {
02860                                                                         if ($table!='pages' || $this->destNotInsideSelf($destPid,$uid)) {
02861                                                                                 $this->clear_cache($table,$uid);        // clear cache before moving
02862 
02863                                                                                         // We now update the pid and sortnumber
02864                                                                                 $updateFields['pid'] = $destPid;
02865                                                                                 $updateFields[$sortRow] = $sortInfo['sortNumber'];
02866                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields);
02867 
02868                                                                                         // Call post processing hooks:
02869                                                                                 foreach($hookObjectsArr as $hookObj) {
02870                                                                                         if (method_exists($hookObj, 'moveRecord_afterAnotherElementPostProcess')) {
02871                                                                                                 $hookObj->moveRecord_afterAnotherElementPostProcess($table, $uid, $destPid, $origDestPid, $moveRec, $updateFields, $this);
02872                                                                                         }
02873                                                                                 }
02874 
02875                                                                                         // Logging...
02876                                                                                 $newPropArr = $this->getRecordProperties($table,$uid);
02877                                                                                 $oldpagePropArr = $this->getRecordProperties('pages',$propArr['pid']);
02878                                                                                 if ($destPid!=$propArr['pid'])  {
02879                                                                                         $newpagePropArr = $this->getRecordProperties('pages',$destPid);
02880                                                                                         $this->log($table,$uid,4,0,0,"Moved record '%s' (%s) to page '%s' (%s)",2,array($propArr['header'],$table.':'.$uid, $newpagePropArr['header'], $newPropArr['pid']),$propArr['pid']);    // Logged to old page
02881                                                                                         $this->log($table,$uid,4,0,0,"Moved record '%s' (%s) from page '%s' (%s)",3,array($propArr['header'],$table.':'.$uid, $oldpagePropArr['header'], $propArr['pid']),$destPid);    // Logged to new page
02882                                                                                 } else {
02883                                                                                         $this->log($table,$uid,4,0,0,"Moved record '%s' (%s) on page '%s' (%s)",4,array($propArr['header'],$table.':'.$uid, $oldpagePropArr['header'], $propArr['pid']),$destPid);      // Logged to new page
02884                                                                                 }
02885 
02886                                                                                         // clear cache after moving
02887                                                                                 $this->clear_cache($table,$uid);
02888 
02889                                                                                         // fixUniqueInPid
02890                                                                                 $this->fixUniqueInPid($table,$uid);
02891 
02892                                                                                         // fixCopyAfterDuplFields
02893                                                                                 if ($origDestPid<0)     {$this->fixCopyAfterDuplFields($table,$uid,abs($origDestPid),1);}
02894                                                                         } else {
02895                                                                                 $destPropArr = $this->getRecordProperties('pages',$destPid);
02896                                                                                 $this->log($table,$uid,4,0,1,"Attempt to move page '%s' (%s) to inside of its own rootline (at page '%s' (%s))",10,array($propArr['header'],$uid, $destPropArr['header'], $destPid),$propArr['pid']);
02897                                                                         }
02898                                                                 }
02899                                                         }
02900                                                 } else {
02901                                                         $this->log($table,$uid,4,0,1,"Attempt to move record '%s' (%s) to after another record, although the table has no sorting row.",13,array($propArr['header'],$table.':'.$uid),$propArr['event_pid']);
02902                                                 }
02903                                         }
02904                                 } else {
02905                                         $this->log($table,$uid,4,0,1,"Attempt to move record '%s' (%s) without having permissions to do so",14,array($propArr['header'],$table.':'.$uid),$propArr['event_pid']);
02906                                 }
02907                         } else {
02908                                 $this->newlog("Move attempt failed due to workspace restrictions: ".implode(' ',$workspaceAccessBlocked),1);
02909                         }
02910                 }
02911         }
02912 
02921         function localize($table,$uid,$language)        {
02922                 global $TCA;
02923 
02924                 $uid = intval($uid);
02925 
02926                 if ($TCA[$table] && $uid)       {
02927                         t3lib_div::loadTCA($table);
02928 
02929                         if ($TCA[$table]['ctrl']['languageField'] && $TCA[$table]['ctrl']['transOrigPointerField'])     {
02930                                 if ($langRec = t3lib_BEfunc::getRecord('sys_language',intval($language),'uid,title'))   {
02931                                         if ($this->doesRecordExist($table,$uid,'show')) {
02932 
02933                                                 $row = t3lib_BEfunc::getRecordWSOL($table,$uid);        // Getting workspace overlay if possible - this will localize versions in workspace if any
02934                                                 if (is_array($row))     {
02935                                                         if ($row[$TCA[$table]['ctrl']['languageField']] <= 0)   {
02936                                                                 if ($row[$TCA[$table]['ctrl']['transOrigPointerField']] == 0)   {
02937                                                                         if (!t3lib_BEfunc::getRecordsByField($table,$TCA[$table]['ctrl']['transOrigPointerField'],$uid,'AND pid='.intval($row['pid']).' AND '.$TCA[$table]['ctrl']['languageField'].'='.intval($langRec['uid'])))       {
02938 
02939                                                                                         // Initialize:
02940                                                                                 $overrideValues = array();
02941                                                                                 $excludeFields = array();
02942 
02943                                                                                         // Set override values:
02944                                                                                 $overrideValues[$TCA[$table]['ctrl']['languageField']] = $langRec['uid'];
02945                                                                                 $overrideValues[$TCA[$table]['ctrl']['transOrigPointerField']] = $uid;
02946 
02947                                                                                         // Set exclude Fields:
02948                                                                                 foreach($TCA[$table]['columns'] as $fN => $fCfg)        {
02949                                                                                         if ($fCfg['l10n_mode']=='prefixLangTitle')      {       // Check if we are just prefixing:
02950                                                                                                 if (($fCfg['config']['type']=='text' || $fCfg['config']['type']=='input') && strlen($row[$fN])) {
02951                                                                                                         list($tscPID) = t3lib_BEfunc::getTSCpid($table,$uid,'');
02952                                                                                                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
02953 
02954                                                                                                         if (isset($TSConfig['translateToMessage']) && strlen($TSConfig['translateToMessage']))  {
02955                                                                                                                 $translateToMsg = @sprintf($TSConfig['translateToMessage'], $langRec['title']);
02956                                                                                                         }
02957                                                                                                         if (!strlen($translateToMsg))   {
02958                                                                                                                 $translateToMsg = 'Translate to '.$langRec['title'].':';
02959                                                                                                         }
02960 
02961                                                                                                         $overrideValues[$fN] = '['.$translateToMsg.'] '.$row[$fN];
02962                                                                                                 }
02963                                                                                         } elseif (t3lib_div::inList('exclude,noCopy,mergeIfNotBlank',$fCfg['l10n_mode']) && $fN!=$TCA[$table]['ctrl']['languageField'] && $fN!=$TCA[$table]['ctrl']['transOrigPointerField']) {  // Otherwise, do not copy field (unless it is the language field or pointer to the original language)
02964                                                                                                 $excludeFields[] = $fN;
02965                                                                                         }
02966                                                                                 }
02967                                                                                         // Execute the copy:
02968                                                                                 $this->copyRecord($table,$uid,-$uid,1,$overrideValues,implode(',',$excludeFields));
02969                                                                         } else $this->newlog('Localization failed; There already was a localization for this language of the record!',1);
02970                                                                 } else $this->newlog('Localization failed; Source record contained a reference to an original default record (which is strange)!',1);
02971                                                         } else $this->newlog('Localization failed; Source record had another language than "Default" or "All" defined!',1);
02972                                                 } else $this->newlog('Attempt to localize record that did not exist!',1);
02973                                         } else $this->newlog('Attempt to localize record without permission',1);
02974                                 } else $this->newlog('Sys language UID "'.$language.'" not found valid!',1);
02975                         } else $this->newlog('Localization failed; "languageField" and "transOrigPointerField" must be defined for the table!',1);
02976                 }
02977         }
02978 
02979 
02980 
02981 
02982 
02983 
02984 
02985 
02986 
02987 
02988 
02989 
02990 
02991 
02992         /*********************************************
02993          *
02994          * Cmd: Deleting
02995          *
02996          ********************************************/
02997 
03005         function deleteAction($table, $id)      {
03006                 global $TCA;
03007 
03008                 $delRec = t3lib_BEfunc::getRecord($table, $id);
03009 
03010                 if (is_array($delRec))  {       // Record asked to be deleted was found:
03011 
03012                                 // For Live version, try if there is a workspace version because if so, rather "delete" that instead
03013                         if ($delRec['pid']!=-1) {       // Look, if record is an offline version, then delete directly:
03014                                 if ($wsVersion = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, $table, $id))     {
03015                                         $delRec = $wsVersion;
03016                                         $id = $delRec['uid'];
03017                                 }
03018                         }
03019 
03020                         if ($delRec['pid']==-1) {       // Look, if record is an offline version, then delete directly:
03021                                 if ($TCA[$table]['ctrl']['versioningWS'])       {
03022                                         if ($this->BE_USER->workspace==0 || (int)$delRec['t3ver_wsid']==$this->BE_USER->workspace)      {       // In Live workspace, delete any. In other workspaces there must be match.
03023                                                 $liveRec = t3lib_BEfunc::getLiveVersionOfRecord($table,$id,'uid,t3ver_state');
03024 
03025                                                 if ($delRec['t3ver_wsid']==0 || (int)$liveRec['t3ver_state']!==1)       {       // Delete those in WS 0 + if their live records state was not "Placeholder".
03026                                                         $this->deleteEl($table, $id);
03027                                                 } else {        // If live record was placeholder, rather clear it from workspace (because it clears both version and placeholder).
03028                                                         $this->version_clearWSID($table,$id);
03029                                                 }
03030                                         } else $this->newlog('Tried to delete record from another workspace',1);
03031                                 } else $this->newlog('Versioning not enabled for record with PID = -1!',2);
03032                         } elseif ($res = $this->BE_USER->workspaceAllowLiveRecordsInPID($delRec['pid'], $table))        {       // Look, if record is "online" or in a versionized branch, then delete directly.
03033                                 if ($res>0)     {
03034                                         $this->deleteEl($table, $id);
03035                                 } else $this->newlog('Stage of root point did not allow for deletion',1);
03036                         } else {
03037                                 // Otherwise, try to delete by versionization:
03038                                 $this->versionizeRecord($table,$id,'DELETED!',TRUE);
03039                         }
03040                 }
03041         }
03042 
03052         function deleteEl($table, $uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE)   {
03053                 if ($table == 'pages')  {
03054                         $this->deletePages($uid, $noRecordCheck, $forceHardDelete);
03055                 } else {
03056                         $this->deleteRecord($table, $uid, $noRecordCheck, $forceHardDelete);
03057                 }
03058         }
03059 
03067         function undeleteRecord($table,$uid)    {
03068                 $this->deleteRecord($table,$uid,TRUE,FALSE,TRUE);
03069         }
03070 
03084         function deleteRecord($table,$uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE,$undeleteRecord=FALSE)  {
03085                 global $TCA;
03086 
03087                 $uid = intval($uid);
03088                 if ($TCA[$table] && $uid)       {
03089                         if ($noRecordCheck || $this->doesRecordExist($table,$uid,'delete'))     {
03090                                 $this->clear_cache($table,$uid);        // clear cache before deleting the record, else the correct page cannot be identified by clear_cache
03091 
03092                                 $propArr = $this->getRecordProperties($table, $uid);
03093                                 $pagePropArr = $this->getRecordProperties('pages', $propArr['pid']);
03094 
03095                                 $deleteRow = $TCA[$table]['ctrl']['delete'];
03096                                 if ($deleteRow && !$forceHardDelete)    {
03097                                         $value = $undeleteRecord ? 0 : 1;
03098                                         $updateFields = array(
03099                                                 $deleteRow => $value
03100                                         );
03101 
03102                                         if ($TCA[$table]['ctrl']['tstamp']) {
03103                                                 $updateFields[$TCA[$table]['ctrl']['tstamp']] = time();
03104                                         }
03105 
03106                                                 // If the table is sorted, then the sorting number is set very high
03107                                         if ($TCA[$table]['ctrl']['sortby'] && !$undeleteRecord) {
03108                                                 $updateFields[$TCA[$table]['ctrl']['sortby']] = 1000000000;
03109                                         }
03110 
03111                                         $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields);
03112                                 } else {
03113 
03114                                                 // Fetches all fields that holds references to files
03115                                         $fileFieldArr = $this->extFileFields($table);
03116                                         if (count($fileFieldArr))       {
03117                                                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(implode(',',$fileFieldArr), $table, 'uid='.intval($uid));
03118                                                 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))        {
03119                                                         $fArray = $fileFieldArr;
03120                                                         foreach($fArray as $theField)   {       // MISSING: Support for MM file relations!
03121                                                                 $this->extFileFunctions($table,$theField,$row[$theField],'deleteAll');          // This deletes files that belonged to this record.
03122                                                         }
03123                                                 } else {
03124                                                         $this->log($table,$uid,3,0,100,'Delete: Zero rows in result when trying to read filenames from record which should be deleted');
03125                                                 }
03126                                         }
03127 
03128                                         $GLOBALS['TYPO3_DB']->exec_DELETEquery($table, 'uid='.intval($uid));
03129                                 }
03130 
03131                                 $state = $undeleteRecord ? 1 : 3;       // 1 means insert, 3 means delete
03132                                 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
03133                                         if ($forceHardDelete) {
03134                                                 $message = "Record '%s' (%s) was deleted unrecoverable from page '%s' (%s)";
03135                                         }
03136                                         else {
03137                                                 $message = $state == 1 ?
03138                                                         "Record '%s' (%s) was restored on page '%s' (%s)" :
03139                                                         "Record '%s' (%s) was deleted from page '%s' (%s)";
03140                                         }
03141                                         $this->log($table, $uid, $state, 0, 0,
03142                                                                 $message, 0,
03143                                                                 array(
03144                                                                         $propArr['header'],
03145                                                                         $table.':'.$uid,
03146                                                                         $pagePropArr['header'],
03147                                                                         $propArr['pid']
03148                                                                         ),
03149                                                                 $propArr['pid']);
03150 
03151                                 } else {
03152                                         $this->log($table,$uid,$state,0,100,$GLOBALS['TYPO3_DB']->sql_error());
03153                                 }
03154 
03155                                         // Update reference index:
03156                                 $this->updateRefIndex($table,$uid);
03157 
03158                         } else $this->log($table,$uid,3,0,1,'Attempt to delete record without delete-permissions');
03159                 }
03160         }
03161 
03170         function deletePages($uid,$force=FALSE,$forceHardDelete=FALSE)  {
03171                         // Getting list of pages to delete:
03172                 if ($force)     {
03173                         $brExist = $this->doesBranchExist('',$uid,0,1);         // returns the branch WITHOUT permission checks (0 secures that)
03174                         $res = t3lib_div::trimExplode(',',$brExist.$uid,1);
03175                 } else {
03176                         $res = $this->canDeletePage($uid);
03177                 }
03178 
03179                         // Perform deletion if not error:
03180                 if (is_array($res))     {
03181                         foreach($res as $deleteId)      {
03182                                 $this->deleteSpecificPage($deleteId,$forceHardDelete);
03183                         }
03184                 } else {
03185                         $this->newlog($res,1);
03186                 }
03187         }
03188 
03198         function deleteSpecificPage($uid,$forceHardDelete=FALSE)        {
03199                 global $TCA;
03200                 reset ($TCA);
03201                 $uid = intval($uid);
03202                 if ($uid)       {
03203                         while (list($table)=each($TCA)) {
03204                                 if ($table!='pages')    {
03205                                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($uid).$this->deleteClause($table));
03206                                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))     {
03207                                                 $this->deleteRecord($table,$row['uid'], TRUE, $forceHardDelete);
03208                                         }
03209                                 }
03210                         }
03211                         $this->deleteRecord('pages',$uid, TRUE, $forceHardDelete);
03212                 }
03213         }
03214 
03221         function canDeletePage($uid)    {
03222                 if ($this->doesRecordExist('pages',$uid,'delete'))      {       // If we may at all delete this page
03223                         if ($this->deleteTree)  {
03224                                 $brExist = $this->doesBranchExist('',$uid,$this->pMap['delete'],1);     // returns the branch
03225                                 if ($brExist != -1)     {       // Checks if we had permissions
03226                                         if ($this->noRecordsFromUnallowedTables($brExist.$uid)) {
03227                                                 return t3lib_div::trimExplode(',',$brExist.$uid,1);
03228                                         } else return 'Attempt to delete records from disallowed tables';
03229                                 } else return 'Attempt to delete pages in branch without permissions';
03230                         } else {
03231                                 $brExist = $this->doesBranchExist('',$uid,$this->pMap['delete'],1);     // returns the branch
03232                                 if ($brExist == '')     {       // Checks if branch exists
03233                                         if ($this->noRecordsFromUnallowedTables($uid))  {
03234                                                 return array($uid);
03235                                         } else return 'Attempt to delete records from disallowed tables';
03236                                 } else return 'Attempt to delete page which has subpages';
03237                         }
03238                 } else return 'Attempt to delete page without permissions';
03239         }
03240 
03248         function cannotDeleteRecord($table,$id) {
03249                 if ($table==='pages')   {
03250                         $res = $this->canDeletePage($id);
03251                         return is_array($res) ? FALSE : $res;
03252                 } else {
03253                         return $this->doesRecordExist($table,$id,'delete') ? FALSE : 'No permission to delete record';
03254                 }
03255         }
03256 
03257 
03258 
03259 
03260 
03261 
03262 
03263 
03264 
03265 
03266 
03267 
03268         /*********************************************
03269          *
03270          * Cmd: Versioning
03271          *
03272          ********************************************/
03273 
03286         function versionizeRecord($table,$id,$label,$delete=FALSE,$versionizeTree=-1)   {
03287                 global $TCA;
03288 
03289                 $id = intval($id);
03290 
03291                 if ($TCA[$table] && $TCA[$table]['ctrl']['versioningWS'] && $id>0)      {
03292                         if ($this->doesRecordExist($table,$id,'show'))  {
03293                                 if ($this->BE_USER->workspaceVersioningTypeAccess($versionizeTree))     {
03294 
03295                                                 // Select main record:
03296                                         $row = $this->recordInfo($table,$id,'pid,t3ver_id');
03297                                         if (is_array($row))     {
03298                                                 if ($row['pid']>=0)     {       // record must be online record
03299                                                         if (!$delete || !$this->cannotDeleteRecord($table,$id)) {
03300 
03301                                                                         // Look for next version number:
03302                                                                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
03303                                                                         't3ver_id',
03304                                                                         $table,
03305                                                                         '(t3ver_oid='.$id.' OR uid='.$id.')'.$this->deleteClause($table),
03306                                                                         '',
03307                                                                         't3ver_id DESC',
03308                                                                         '1'
03309                                                                 );
03310                                                                 list($highestVerNumber) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
03311 
03312                                                                         // Look for version number of the current:
03313                                                                 $subVer = $row['t3ver_id'].'.'.($highestVerNumber+1);
03314 
03315                                                                         // Set up the values to override when making a raw-copy:
03316                                                                 $overrideArray = array(
03317                                                                         't3ver_id' => $highestVerNumber+1,
03318                                                                         't3ver_oid' => $id,
03319                                                                         't3ver_label' => ($label ? $label : $subVer.' / '.date('d-m-Y H:m:s')),
03320                                                                         't3ver_wsid' => $this->BE_USER->workspace,
03321                                                                         't3ver_state' => $delete ? 2 : 0,
03322                                                                         't3ver_count' => 0,
03323                                                                         't3ver_stage' => 0,
03324                                                                         't3ver_tstamp' => 0
03325                                                                 );
03326                                                                 if ($TCA[$table]['ctrl']['editlock'])   {
03327                                                                         $overrideArray[$TCA[$table]['ctrl']['editlock']] = 0;
03328                                                                 }
03329                                                                 if ($table==='pages')   {
03330                                                                         $overrideArray['t3ver_swapmode'] = $versionizeTree;
03331                                                                 }
03332 
03333                                                                         // Checking if the record already has a version in the current workspace of the backend user
03334                                                                 $workspaceCheck = TRUE;
03335                                                                 if ($this->BE_USER->workspace!==0)      {
03336                                                                                 // Look for version already in workspace:
03337                                                                         $workspaceCheck = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace,$table,$id,'uid') ? FALSE : TRUE;
03338                                                                 }
03339 
03340                                                                 if ($workspaceCheck)    {
03341 
03342                                                                                 // Create raw-copy and return result:
03343                                                                         return $this->copyRecord_raw($table,$id,-1,$overrideArray);
03344                                                                 } else $this->newlog('Record you wanted to versionize was already a version in the workspace (wsid='.$this->BE_USER->workspace.')!',1);
03345                                                         } else $this->newlog('Record cannot be deleted: '.$this->cannotDeleteRecord($table,$id),1);
03346                                                 } else $this->newlog('Record you wanted to versionize was already a version in archive (pid=-1)!',1);
03347                                         } else $this->newlog('Record you wanted to versionize did not exist!',1);
03348                                 } else $this->newlog('The versioning type '.$versionizeTree.' mode you requested was not allowed',1);
03349                         } else $this->newlog('You didnt have correct permissions to make a new version (copy) of this record "'.$table.'" / '.$id,1);
03350                 } else $this->newlog('Versioning is not supported for this table "'.$table.'" / '.$id,1);
03351         }
03352 
03362         function versionizePages($uid,$label,$versionizeTree)   {
03363                 global $TCA;
03364 
03365                 $uid = intval($uid);
03366                 $brExist = $this->doesBranchExist('',$uid,$this->pMap['show'],1);       // returns the branch
03367 
03368                 if ($brExist != -1)     {       // Checks if we had permissions
03369 
03370                                 // Finding list of tables ALLOWED to be copied
03371                         $allowedTablesArray = $this->admin ? $this->compileAdminTables() : explode(',',$this->BE_USER->groupData['tables_modify']);     // These are the tables, the user may modify
03372                         $allowedTablesArray = $this->compileAdminTables();      // These are ALL tables because a new version should be ALL of them regardless of permission of the user executing the request.
03373 
03374                                 // Make list of tables that should come along with a new version of the page:
03375                         $verTablesArray = array();
03376                         $allTables = array_keys($TCA);
03377                         foreach($allTables as $tN)      {
03378                                 if ($tN!='pages' && ($versionizeTree>0 || $TCA[$tN]['ctrl']['versioning_followPages']) && ($this->admin || in_array($tN, $allowedTablesArray))) {
03379                                         $verTablesArray[] = $tN;
03380                                 }
03381                         }
03382 
03383                                 // Begin to copy pages if we're allowed to:
03384                         if ($this->admin || in_array('pages',$allowedTablesArray))      {
03385                                 if ($this->BE_USER->workspaceVersioningTypeAccess($versionizeTree))     {
03386                                                 // Versionize this page:
03387                                         $theNewRootID = $this->versionizeRecord('pages',$uid,$label,FALSE,$versionizeTree);
03388                                         if ($theNewRootID)      {
03389                                                 $this->rawCopyPageContent($uid,$theNewRootID,$verTablesArray);
03390 
03391                                                         // If we're going to copy recursively...:
03392                                                 if ($versionizeTree>0)  {
03393 
03394                                                                 // Get ALL subpages to copy (read permissions respected - they should NOT be...):
03395                                                         $CPtable = $this->int_pageTreeInfo(Array(), $uid, intval($versionizeTree), $theNewRootID);
03396 
03397                                                                 // Now copying the subpages:
03398                                                         foreach($CPtable as $thePageUid => $thePagePid) {
03399                                                                 $newPid = $this->copyMappingArray['pages'][$thePagePid];
03400                                                                 if (isset($newPid))     {
03401                                                                         $theNewRootID = $this->copyRecord_raw('pages',$thePageUid,$newPid);
03402                                                                         $this->rawCopyPageContent($thePageUid,$theNewRootID,$verTablesArray);
03403                                                                 } else {
03404                                                                         $this->newlog('Something went wrong during copying branch (for versioning)',1);
03405                                                                         break;
03406                                                                 }
03407                                                         }
03408                                                 }       // else the page was not copied. Too bad...
03409                                         } else $this->newlog('The root version could not be created!',1);
03410                                 } else $this->newlog('Versioning type "'.$versionizeTree.'" was not allowed in workspace',1);
03411                         } else $this->newlog('Attempt to versionize page without permission to this table',1);
03412                 } else $this->newlog('Could not read all subpages to versionize.',1);
03413         }
03414 
03425         function version_swap($table,$id,$swapWith,$swapIntoWS=0)       {
03426                 global $TCA;
03427 
03428                 /*
03429                 Version ID swapping principles:
03430                   - Version from archive (future/past, called "swap version") will get the uid of the "t3ver_oid", the official element with uid = "t3ver_oid" will get the new versions old uid. PIDs are swapped also
03431 
03432                         uid             pid                     uid             t3ver_oid       pid
03433                 1:      13              123      -->    -13             247                     123             (Original has negated UID, and sets t3ver_oid to the final UID (which is nice to know for recovery). PID is unchanged at this point)
03434                 2:      247             -1       -->    13              13                      123             (Swap version gets original UID, correct t3ver_oid (not required for online version) and is moved to the final PID (123))
03435                 3:      -13             123      -->    247             13                      -1              (Original gets the swap versions old UID, has t3ver_oid set correctly (important) and the ver. repository PID set right.)
03436 
03437                         13 is online UID,
03438                         247 is specific versions UID
03439                         123 is the PID of the original record
03440                         -1 is the versioning repository PID
03441 
03442                         Recovery Process:
03443                                 Search for negative UID (here "-13"):
03444                                         YES: Step 1 completed, but at least step 3 didn't.
03445                                                 Search for the negativ UIDs positive (here: "13")
03446                                                         YES: Step 2 completed: Rollback: "t3ver_oid" of the -uid record shows the original UID of the swap record. Use that to change back UID and pid to -1. After that, proceed with recovery for step 1 (see below)
03447                                                         NO: Only Step 1 completed! Rollback: Just change uid "-13" to "13" and "t3ver_oid" to "13" (not important)
03448                                         NO: No problems.
03449                 */
03450 
03451                         // First, check if we may actually edit the online record
03452                 if ($this->checkRecordUpdateAccess($table,$id)) {
03453 
03454                                 // Select the two versions:
03455                         $curVersion = t3lib_BEfunc::getRecord($table,$id,'*');
03456                         $swapVersion = t3lib_BEfunc::getRecord($table,$swapWith,'*');
03457 
03458                         if (is_array($curVersion) && is_array($swapVersion))    {
03459                                 if ($this->BE_USER->workspacePublishAccess($swapVersion['t3ver_wsid'])) {
03460                                         $wsAccess = $this->BE_USER->checkWorkspace($swapVersion['t3ver_wsid']);
03461                                         if ($swapVersion['t3ver_wsid']<=0 || !($wsAccess['publish_access']&1) || (int)$swapVersion['t3ver_stage']===10) {
03462                                                 if ($this->doesRecordExist($table,$swapWith,'show') && $this->checkRecordUpdateAccess($table,$swapWith)) {
03463                                                         if (!$swapIntoWS || $this->BE_USER->workspaceSwapAccess())      {
03464 
03465                                                                         // Check if the swapWith record really IS a version of the original!
03466                                                                 if ((int)$swapVersion['pid']==-1 && (int)$curVersion['pid']>=0 && !strcmp($swapVersion['t3ver_oid'],$id))       {
03467 
03468                                                                                 // Lock file name:
03469                                                                         $lockFileName = PATH_site.'typo3temp/swap_locking/'.$table.':'.$id.'.ser';
03470 
03471                                                                         if (!@is_file($lockFileName))   {
03472 
03473                                                                                         // Write lock-file:
03474                                                                                 t3lib_div::writeFileToTypo3tempDir($lockFileName,serialize(array(
03475                                                                                         'tstamp'=>time(),
03476                                                                                         'user'=>$GLOBALS['BE_USER']->user['username'],
03477                                                                                         'curVersion'=>$curVersion,
03478                                                                                         'swapVersion'=>$swapVersion
03479                                                                                 )));
03480 
03481                                                                                         // Find fields to keep
03482                                                                                 $keepFields = $this->getUniqueFields($table);
03483                                                                                 if ($TCA[$table]['ctrl']['sortby'])     {
03484                                                                                         $keepFields[] = $TCA[$table]['ctrl']['sortby'];
03485                                                                                 }
03486 
03487                                                                                         // Swap "keepfields"
03488                                                                                 foreach($keepFields as $fN)     {
03489                                                                                         $tmp = $swapVersion[$fN];
03490                                                                                         $swapVersion[$fN] = $curVersion[$fN];
03491                                                                                         $curVersion[$fN] = $tmp;
03492                                                                                 }
03493 
03494                                                                                         // Preserve states:
03495                                                                                 $t3ver_state = array();
03496                                                                                 $t3ver_state['swapVersion'] = $swapVersion['t3ver_state'];
03497                                                                                 $t3ver_state['curVersion'] = $curVersion['t3ver_state'];
03498 
03499                                                                                         // Modify offline version to become online:
03500                                                                                 $tmp_wsid = $swapVersion['t3ver_wsid'];
03501                                                                                 unset($swapVersion['uid']);
03502                                                                                 $swapVersion['pid'] = intval($curVersion['pid']);       // Set pid for ONLINE
03503                                                                                 $swapVersion['t3ver_oid'] = intval($id);
03504                                                                                 $swapVersion['t3ver_wsid'] = $swapIntoWS ? intval($curVersion['t3ver_wsid']) : 0;
03505                                                                                 $swapVersion['t3ver_tstamp'] = time();
03506                                                                                 $swapVersion['t3ver_stage'] = $swapVersion['t3ver_state'] = 0;
03507 
03508                                                                                         // Modify online version to become offline:
03509                                                                                 unset($curVersion['uid']);
03510                                                                                 $curVersion['pid'] = -1;        // Set pid for OFFLINE
03511                                                                                 $curVersion['t3ver_oid'] = intval($id);
03512                                                                                 $curVersion['t3ver_wsid'] = $swapIntoWS ? intval($tmp_wsid) : 0;
03513                                                                                 $curVersion['t3ver_tstamp'] = time();
03514                                                                                 $curVersion['t3ver_count'] = $curVersion['t3ver_count']+1;      // Increment lifecycle counter
03515                                                                                 $curVersion['t3ver_stage'] = $curVersion['t3ver_state'] = 0;
03516 
03517                                                                                 if ($table==='pages') {         // Keeping the swapmode state
03518                                                                                                 $curVersion['t3ver_swapmode'] = $swapVersion['t3ver_swapmode'];
03519                                                                                 }
03520 
03521                                                                                         // Execute swapping:
03522                                                                                 $sqlErrors = array();
03523                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($id),$swapVersion);
03524                                                                                 if ($GLOBALS['TYPO3_DB']->sql_error())          {
03525                                                                                         $sqlErrors[] = $GLOBALS['TYPO3_DB']->sql_error();
03526                                                                                 } else {
03527                                                                                         $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($swapWith),$curVersion);
03528                                                                                         if ($GLOBALS['TYPO3_DB']->sql_error())  {
03529                                                                                                 $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
03530                                                                                         } else {
03531                                                                                                 unlink($lockFileName);
03532                                                                                         }
03533                                                                                 }
03534 
03535                                                                                 if (!count($sqlErrors)) {
03536 
03537                                                                                                 // Checking for delete:
03538                                                                                         if ($t3ver_state['swapVersion']==2)     {
03539                                                                                                 $this->deleteEl($table,$id,TRUE);       // Force delete
03540                                                                                         }
03541 
03542                                                                                         $this->newlog('Swapping successful for table "'.$table.'" uid '.$id.'=>'.$swapWith);
03543 
03544                                                                                                 // Update reference index:
03545                                                                                         $this->updateRefIndex($table,$id);
03546                                                                                         $this->updateRefIndex($table,$swapWith);
03547 
03548                                                                                                 // SWAPPING pids for subrecords:
03549                                                                                         if ($table=='pages' && $swapVersion['t3ver_swapmode']>=0)       {
03550 
03551                                                                                                         // Collect table names that should be copied along with the tables:
03552                                                                                                 foreach($TCA as $tN => $tCfg)   {
03553                                                                                                         if ($swapVersion['t3ver_swapmode']>0 || $TCA[$tN]['ctrl']['versioning_followPages'])    {       // For "Branch" publishing swap ALL, otherwise for "page" publishing, swap only "versioning_followPages" tables
03554                                                                                                                 $temporaryPid = -($id+1000000);
03555 
03556                                                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($id),array('pid'=>$temporaryPid));
03557                                                                                                                 if ($GLOBALS['TYPO3_DB']->sql_error())  $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
03558 
03559                                                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($swapWith),array('pid'=>$id));
03560                                                                                                                 if ($GLOBALS['TYPO3_DB']->sql_error())  $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
03561 
03562                                                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($temporaryPid),array('pid'=>$swapWith));
03563                                                                                                                 if ($GLOBALS['TYPO3_DB']->sql_error())  $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
03564 
03565                                                                                                                 if (count($sqlErrors))  {
03566                                                                                                                         $this->newlog('During Swapping: SQL errors happend: '.implode('; ',$sqlErrors),2);
03567                                                                                                                 }
03568                                                                                                         }
03569                                                                                                 }
03570                                                                                         }
03571                                                                                                 // Clear cache:
03572                                                                                         $this->clear_cache($table,$id);
03573 
03574                                                                                                 // Checking for "new-placeholder" and if found, delete it (BUT FIRST after swapping!):
03575                                                                                         if ($t3ver_state['curVersion']==1)      {
03576                                                                                                 $this->deleteEl($table, $swapWith, TRUE, TRUE);         // For delete + completely delete!
03577                                                                                         }
03578                                                                                 } else $this->newlog('During Swapping: SQL errors happend: '.implode('; ',$sqlErrors),2);
03579                                                                         } else $this->newlog('A swapping lock file was present. Either another swap process is already running or a previous swap process failed. Ask your administrator to handle the situation.',2);
03580                                                                 } else $this->newlog('In swap version, either pid was not -1 or the t3ver_oid didn\'t match the id of the online version as it must!',2);
03581                                                         } else $this->newlog('Workspace #'.$swapVersion['t3ver_wsid'].' does not support swapping.',1);
03582                                                 } else $this->newlog('You cannot publish a record you do not have edit and show permissions for',1);
03583                                         } else $this->newlog('Records in workspace #'.$swapVersion['t3ver_wsid'].' can only be published when in "Publish" stage.',1);
03584                                 } else $this->newlog('User could not publish records from workspace #'.$swapVersion['t3ver_wsid'],1);
03585                         } else $this->newlog('Error: Either online or swap version could not be selected!',2);
03586                 } else $this->newlog('Error: You cannot swap versions for a record you do not have access to edit!',1);
03587         }
03588 
03596         function version_clearWSID($table,$id)  {
03597                 if ($errorCode = $this->BE_USER->workspaceCannotEditOfflineVersion($table, $id))        {
03598                         $this->newlog('Attempt to reset workspace for record failed: '.$errorCode,1);
03599                 } elseif ($this->checkRecordUpdateAccess($table,$id)) {
03600                         if ($liveRec = t3lib_BEfunc::getLiveVersionOfRecord($table,$id,'uid,t3ver_state'))      {
03601                                         // Clear workspace ID:
03602                                 $sArray = array();
03603                                 $sArray['t3ver_wsid'] = 0;
03604                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($id),$sArray);
03605 
03606                                         // Clear workspace ID for live version AND DELETE IT as well because it is a new record!
03607                                 if ((int)$liveRec['t3ver_state']===1)   {
03608                                         $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($liveRec['uid']),$sArray);
03609                                         $this->deleteEl($table, $liveRec['uid'], TRUE); // THIS assumes that the record was placeholder ONLY for ONE record (namely $id)
03610                                 }
03611 
03612                                         // If "deleted" flag is set for the version that got released it doesn't make sense to keep that "placeholder" anymore and we delete it completly.
03613                                 $wsRec = t3lib_BEfunc::getRecord($table,$id);
03614                                 if ((int)$wsRec['t3ver_state']===2)     {
03615                                         $this->deleteEl($table, $id, TRUE, TRUE);
03616                                 }
03617                         }
03618                 } else $this->newlog('Attempt to reset workspace for record failed because you do not have edit access',1);
03619         }
03620 
03630         function version_setStage($table,$id,$stageId,$comment='')      {
03631                 if ($errorCode = $this->BE_USER->workspaceCannotEditOfflineVersion($table, $id))        {
03632                         $this->newlog('Attempt to set stage for record failed: '.$errorCode,1);
03633                 } elseif ($this->checkRecordUpdateAccess($table,$id)) {
03634                         $stat = $this->BE_USER->checkWorkspaceCurrent();
03635                         if (t3lib_div::inList('admin,online,offline,reviewer,owner', $stat['_ACCESS']) || ($stageId<=1 && $stat['_ACCESS']==='member')) {
03636 
03637                                         // Set stage of record:
03638                                 $sArray = array();
03639                                 $sArray['t3ver_stage'] = $stageId;
03640                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($id), $sArray);
03641                                 $this->newlog('Stage for record was changed to '.$stageId.'. Comment was: "'.substr($comment,0,100).'"');
03642 // TEMPORARY, except 6-30 as action/detail number which is observed elsewhere!
03643 $this->log($table,$id,6,0,0,'Stage raised...',30,array('comment'=>$comment,'stage'=>$stageId));
03644 
03645                                 if ((int)$stat['stagechg_notification']>0)      {
03646                                         $this->notifyStageChange($stat,$stageId,$table,$id,$comment);
03647                                 }
03648                         } else $this->newlog('The member user tried to set a stage value "'.$stageId.'" that was not allowed',1);
03649                 } else $this->newlog('Attempt to set stage for record failed because you do not have edit access',1);
03650         }
03651 
03652 
03653 
03654 
03655 
03656 
03657 
03658 
03659 
03660 
03661 
03662 
03663 
03664         /*********************************************
03665          *
03666          * Cmd: Helper functions
03667          *
03668          ********************************************/
03669 
03675         function remapListedDBRecords() {
03676                 global $TCA;
03677 
03678                 if (count($this->registerDBList))       {
03679                         reset($this->registerDBList);
03680                         while(list($table,$records)=each($this->registerDBList))        {
03681                                 t3lib_div::loadTCA($table);
03682                                 reset($records);
03683                                 while(list($uid,$fields)=each($records))        {
03684                                         $newData = array();
03685                                         $theUidToUpdate = $this->copyMappingArray_merged[$table][$uid];
03686                                         $theUidToUpdate_saveTo = t3lib_BEfunc::wsMapId($table,$theUidToUpdate);
03687 
03688                                         foreach($fields as $fieldName => $value)        {
03689                                                 $conf = $TCA[$table]['columns'][$fieldName]['config'];
03690 
03691                                                 switch($conf['type'])   {
03692                                                         case 'group':
03693                                                         case 'select':
03694                                                                 $vArray = $this->remapListedDBRecords_procDBRefs($conf, $value, $theUidToUpdate);
03695                                                                 if (is_array($vArray))  {
03696                                                                         $newData[$fieldName] = implode(',',$vArray);
03697                                                                 }
03698                                                         break;
03699                                                         case 'flex':
03700                                                                 if ($value=='FlexForm_reference')       {
03701                                                                         $origRecordRow = $this->recordInfo($table,$theUidToUpdate,'*'); // This will fetch the new row for the element
03702 
03703                                                                         if (is_array($origRecordRow))   {
03704                                                                                 t3lib_BEfunc::workspaceOL($table,$origRecordRow);
03705 
03706                                                                                         // Get current data structure and value array:
03707                                                                                 $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $origRecordRow, $table);
03708                                                                                 $currentValueArray = t3lib_div::xml2array($origRecordRow[$fieldName]);
03709 
03710                                                                                         // Do recursive processing of the XML data:
03711                                                                                 $currentValueArray['data'] = $this->checkValue_flex_procInData(
03712                                                                                                         $currentValueArray['data'],
03713                                                                                                         array(),        // Not used.
03714                                                                                                         array(),        // Not used.
03715                                                                                                         $dataStructArray,
03716                                                                                                         array($table,$theUidToUpdate,$fieldName),       // Parameters.
03717                                                                                                         'remapListedDBRecords_flexFormCallBack'
03718                                                                                                 );
03719 
03720                                                                                         // The return value should be compiled back into XML, ready to insert directly in the field (as we call updateDB() directly later):
03721                                                                                 if (is_array($currentValueArray['data']))       {
03722                                                                                         $newData[$fieldName] =
03723                                                                                                 $this->checkValue_flexArray2Xml($currentValueArray,TRUE);
03724                                                                                 }
03725                                                                         }
03726                                                                 }
03727                                                         break;
03728                                                         default:
03729                                                                 debug('Field type should not appear here: '. $conf['type']);
03730                                                         break;
03731                                                 }
03732                                         }
03733 
03734                                         if (count($newData))    {       // If any fields were changed, those fields are updated!
03735                                                 $this->updateDB($table,$theUidToUpdate_saveTo,$newData);
03736                                         }
03737                                 }
03738                         }
03739                 }
03740         }
03741 
03753         function remapListedDBRecords_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2) {
03754 
03755                         // Extract parameters:
03756                 list($table,$uid,$field)        = $pParams;
03757 
03758                         // If references are set for this field, set flag so they can be corrected later:
03759                 if ($this->isReferenceField($dsConf) && strlen($dataValue)) {
03760                         $vArray = $this->remapListedDBRecords_procDBRefs($dsConf, $dataValue, $uid);
03761                         if (is_array($vArray))  {
03762                                 $dataValue = implode(',',$vArray);
03763                         }
03764                 }
03765 
03766                         // Return
03767                 return array('value' => $dataValue);
03768         }
03769 
03779         function remapListedDBRecords_procDBRefs($conf, $value, $MM_localUid)   {
03780 
03781                         // Initialize variables
03782                 $set = FALSE;   // Will be set true if an upgrade should be done...
03783                 $allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table'];             // Allowed tables for references.
03784                 $prependName = $conf['type']=='group' ? $conf['prepend_tname'] : '';    // Table name to prepend the UID
03785                 $dontRemapTables = t3lib_div::trimExplode(',',$conf['dontRemapTablesOnCopy'],1);        // Which tables that should possibly not be remapped
03786 
03787                         // Convert value to list of references:
03788                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
03789                 $dbAnalysis->registerNonTableValues = ($conf['type']=='select' && $conf['allowNonIdValues']) ? 1 : 0;
03790                 $dbAnalysis->start($value, $allowedTables, $conf['MM'], $MM_localUid);
03791 
03792                         // Traverse those references and map IDs:
03793                 foreach($dbAnalysis->itemArray as $k => $v)     {
03794                         $mapID = $this->copyMappingArray_merged[$v['table']][$v['id']];
03795                         if ($mapID && !in_array($v['table'],$dontRemapTables))  {
03796                                 $dbAnalysis->itemArray[$k]['id'] = $mapID;
03797                                 $set = TRUE;
03798                         }
03799                 }
03800 
03801                         // If a change has been done, set the new value(s)
03802                 if ($set)       {
03803                         if ($conf['MM'])        {
03804 // FIXME $theUidToUpdate is undefined
03805                                 $dbAnalysis->writeMM($conf['MM'], $theUidToUpdate, $prependName);
03806                         } else {
03807                                 $vArray = $dbAnalysis->getValueArray($prependName);
03808                                 if ($conf['type']=='select')    {
03809                                         $vArray = $dbAnalysis->convertPosNeg($vArray, $conf['foreign_table'], $conf['neg_foreign_table']);
03810                                 }
03811                                 return $vArray;
03812                         }
03813                 }
03814         }
03815 
03816 
03817 
03818 
03819 
03820 
03821 
03822 
03823 
03824 
03825 
03826 
03827 
03828 
03829 
03830 
03831 
03832         /*****************************
03833          *
03834          * Access control / Checking functions
03835          *
03836          *****************************/
03837 
03844         function checkModifyAccessList($table)  {
03845                 $res = ($this->admin || (!$this->tableAdminOnly($table) && t3lib_div::inList($this->BE_USER->groupData['tables_modify'],$table)));
03846                 return $res;
03847         }
03848 
03856         function isRecordInWebMount($table,$id) {
03857                 if (!isset($this->isRecordInWebMount_Cache[$table.':'.$id]))    {
03858                         $recP=$this->getRecordProperties($table,$id);
03859                         $this->isRecordInWebMount_Cache[$table.':'.$id]=$this->isInWebMount($recP['event_pid']);
03860                 }
03861                 return $this->isRecordInWebMount_Cache[$table.':'.$id];
03862         }
03863 
03870         function isInWebMount($pid)     {
03871                 if (!isset($this->isInWebMount_Cache[$pid]))    {
03872                         $this->isInWebMount_Cache[$pid]=$this->BE_USER->isInWebMount($pid);
03873                 }
03874                 return $this->isInWebMount_Cache[$pid];
03875         }
03876 
03884         function checkRecordUpdateAccess($table,$id)    {
03885                 global $TCA;
03886                 $res = 0;
03887                 if ($TCA[$table] && intval($id)>0)      {
03888                         if (isset($this->recUpdateAccessCache[$table][$id]))    {       // If information is cached, return it
03889                                 return $this->recUpdateAccessCache[$table][$id];
03890                                 // Check if record exists and 1) if 'pages' the page may be edited, 2) if page-content the page allows for editing
03891                         } elseif ($this->doesRecordExist($table,$id,'edit'))    {
03892                                 $res = 1;
03893                         }
03894                         $this->recUpdateAccessCache[$table][$id]=$res;  // Cache the result
03895                 }
03896                 return $res;
03897         }
03898 
03908         function checkRecordInsertAccess($insertTable,$pid,$action=1)   {
03909                 global $TCA;
03910 
03911                 $res = 0;
03912                 $pid = intval($pid);
03913                 if ($pid>=0)    {
03914                         if (isset($this->recInsertAccessCache[$insertTable][$pid]))     {       // If information is cached, return it
03915                                 return $this->recInsertAccessCache[$insertTable][$pid];
03916                         } else {
03917                                         // If either admin and root-level or if page record exists and 1) if 'pages' you may create new ones 2) if page-content, new content items may be inserted on the $pid page
03918                                 if ( (!$pid && $this->admin) || $this->doesRecordExist('pages',$pid,($insertTable=='pages'?$this->pMap['new']:$this->pMap['editcontent'])) )    {               // Check permissions
03919                                         if ($this->isTableAllowedForThisPage($pid, $insertTable))       {
03920                                                 $res = 1;
03921                                                 $this->recInsertAccessCache[$insertTable][$pid]=$res;   // Cache the result
03922                                         } else {
03923                                                 $propArr = $this->getRecordProperties('pages',$pid);
03924                                                 $this->log($insertTable,$pid,$action,0,1,"Attempt to insert record on page '%s' (%s) where this table, %s, is not allowed",11,array($propArr['header'],$pid,$insertTable),$propArr['event_pid']);
03925                                         }
03926                                 } else {
03927                                         $propArr = $this->getRecordProperties('pages',$pid);
03928                                         $this->log($insertTable,$pid,$action,0,1,"Attempt to insert a record on page '%s' (%s) from table '%s' without permissions. Or non-existing page.",12,array($propArr['header'],$pid,$insertTable),$propArr['event_pid']);
03929                                 }
03930                         }
03931                 }
03932                 return $res;
03933         }
03934 
03942         function isTableAllowedForThisPage($page_uid, $checkTable)      {
03943                 global $TCA, $PAGES_TYPES;
03944                 $page_uid = intval($page_uid);
03945 
03946                         // Check if rootLevel flag is set and we're trying to insert on rootLevel - and reversed - and that the table is not "pages" which are allowed anywhere.
03947                 if (($TCA[$checkTable]['ctrl']['rootLevel'] xor !$page_uid) && $TCA[$checkTable]['ctrl']['rootLevel']!=-1 && $checkTable!='pages')      {
03948                         return false;
03949                 }
03950 
03951                         // Check root-level
03952                 if (!$page_uid) {
03953                         if ($this->admin)       {
03954                                 return true;
03955                         }
03956                 } else {
03957                                 // Check non-root-level
03958                         $doktype = $this->pageInfo($page_uid,'doktype');
03959                         $allowedTableList = isset($PAGES_TYPES[$doktype]['allowedTables']) ? $PAGES_TYPES[$doktype]['allowedTables'] : $PAGES_TYPES['default']['allowedTables'];
03960                         $allowedArray = t3lib_div::trimExplode(',',$allowedTableList,1);
03961                         if (strstr($allowedTableList,'*') || in_array($checkTable,$allowedArray))       {               // If all tables or the table is listed as a allowed type, return true
03962                                 return true;
03963                         }
03964                 }
03965         }
03966 
03975         function doesRecordExist($table,$id,$perms)     {
03976                 global $TCA;
03977 
03978                 $res = 0;
03979                 $id = intval($id);
03980 
03981                         // Processing the incoming $perms (from possible string to integer that can be AND'ed)
03982                 if (!t3lib_div::testInt($perms))        {
03983                         if ($table!='pages')    {
03984                                 switch($perms)  {
03985                                         case 'edit':
03986                                         case 'delete':
03987                                         case 'new':
03988                                                 $perms = 'editcontent';         // This holds it all in case the record is not page!!
03989                                         break;
03990                                 }
03991                         }
03992                         $perms = intval($this->pMap[$perms]);
03993                 } else {
03994                         $perms = intval($perms);
03995                 }
03996 
03997                 if (!$perms)    {die('Internal ERROR: no permissions to check for non-admin user.');}
03998 
03999                         // For all tables: Check if record exists:
04000                 if (is_array($TCA[$table]) && $id>0 && ($this->isRecordInWebMount($table,$id) || $this->admin)) {
04001                         if ($table != 'pages')  {
04002 
04003                                         // Find record without checking page:
04004                                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid', $table, 'uid='.intval($id).$this->deleteClause($table));      // THIS SHOULD CHECK FOR editlock I think!
04005                                 $output = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres);
04006                                 t3lib_BEfunc::fixVersioningPid($table,$output,TRUE);
04007 
04008                                         // If record found, check page as well:
04009                                 if (is_array($output))  {
04010 
04011                                                 // Looking up the page for record:
04012                                         $mres = $this->doesRecordExist_pageLookUp($output['pid'], $perms);
04013                                         $pageRec = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres);
04014                                                 // Return true if either a page was found OR if the PID is zero AND the user is ADMIN (in which case the record is at root-level):
04015                                         if (is_array($pageRec) || (!$output['pid'] && $this->admin))    {
04016                                                 return TRUE;
04017                                         }
04018                                 }
04019                                 return FALSE;
04020                         } else {
04021                                 $mres = $this->doesRecordExist_pageLookUp($id, $perms);
04022                                 return $GLOBALS['TYPO3_DB']->sql_num_rows($mres);
04023                         }
04024                 }
04025         }
04026 
04036         function doesRecordExist_pageLookUp($id, $perms)        {
04037                 global $TCA;
04038 
04039                 return $GLOBALS['TYPO3_DB']->exec_SELECTquery(
04040                         'uid',
04041                         'pages',
04042                         'uid='.intval($id).
04043                                 $this->deleteClause('pages').
04044                                 ($perms && !$this->admin ? ' AND '.$this->BE_USER->getPagePermsClause($perms) : '').
04045                                 (!$this->admin && $TCA['pages']['ctrl']['editlock'] && ($perms & (2+4+16)) ? ' AND '.$TCA['pages']['ctrl']['editlock'].'=0':'') // admin users don't need check
04046                 );
04047         }
04048 
04062         function doesBranchExist($inList,$pid,$perms,$recurse)  {
04063                 global $TCA;
04064                 $pid = intval($pid);
04065                 $perms = intval($perms);
04066 
04067                 if ($pid>=0)    {
04068                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
04069                                 'uid, perms_userid, perms_groupid, perms_user, perms_group, perms_everybody',
04070                                 'pages',
04071                                 'pid='.intval($pid).$this->deleteClause('pages'),
04072                                 '',
04073                                 'sorting'
04074                         );
04075                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))     {
04076                                 if ($this->admin || $this->BE_USER->doesUserHaveAccess($row,$perms))    {       // IF admin, then it's OK
04077                                         $inList.=$row['uid'].',';
04078                                         if ($recurse)   {       // Follow the subpages recursively...
04079                                                 $inList = $this->doesBranchExist($inList, $row['uid'], $perms, $recurse);
04080                                                 if ($inList == -1)      {return -1;}            // No permissions somewhere in the branch
04081                                         }
04082                                 } else {
04083                                         return -1;              // No permissions
04084                                 }
04085                         }
04086                 }
04087                 return $inList;
04088         }
04089 
04096         function tableReadOnly($table)  {
04097                         // returns true if table is readonly
04098                 global $TCA;
04099                 return ($TCA[$table]['ctrl']['readOnly'] ? 1 : 0);
04100         }
04101 
04108         function tableAdminOnly($table) {
04109                         // returns true if table is admin-only
04110                 global $TCA;
04111                 return ($TCA[$table]['ctrl']['adminOnly'] ? 1 : 0);
04112         }
04113 
04122         function destNotInsideSelf($dest,$id)   {
04123                 $loopCheck = 100;
04124                 $dest = intval($dest);
04125                 $id = intval($id);
04126 
04127                 if ($dest==$id) {
04128                         return FALSE;
04129                 }
04130 
04131                 while ($dest!=0 && $loopCheck>0)        {
04132                         $loopCheck--;
04133                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('pid, uid, t3ver_oid,t3ver_wsid', 'pages', 'uid='.intval($dest).$this->deleteClause('pages'));
04134                         if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
04135                                 t3lib_BEfunc::fixVersioningPid('pages',$row);
04136                                 if ($row['pid']==$id)   {
04137                                         return FALSE;
04138                                 } else {
04139                                         $dest = $row['pid'];
04140                                 }
04141                         } else {
04142                                 return FALSE;
04143                         }
04144                 }
04145                 return TRUE;
04146         }
04147 
04154         function getExcludeListArray()  {
04155                 global $TCA;
04156 
04157                 $list = array();
04158                 reset($TCA);
04159                 while (list($table)=each($TCA)) {
04160                         t3lib_div::loadTCA($table);
04161                         while (list($field,$config)=each($TCA[$table]['columns']))      {
04162                                 if ($config['exclude'] && !t3lib_div::inList($this->BE_USER->groupData['non_exclude_fields'],$table.':'.$field))        {
04163                                         $list[]=$table.'-'.$field;
04164                                 }
04165                         }
04166                 }
04167                 return $list;
04168         }
04169 
04177         function doesPageHaveUnallowedTables($page_uid,$doktype)        {
04178                 global $TCA, $PAGES_TYPES;
04179 
04180                 $page_uid = intval($page_uid);
04181                 if (!$page_uid) {
04182                         return FALSE;   // Not a number. Probably a new page
04183                 }
04184 
04185                 $allowedTableList = isset($PAGES_TYPES[$doktype]['allowedTables']) ? $PAGES_TYPES[$doktype]['allowedTables'] : $PAGES_TYPES['default']['allowedTables'];
04186                 $allowedArray = t3lib_div::trimExplode(',',$allowedTableList,1);
04187                 if (strstr($allowedTableList,'*'))      {       // If all tables is OK the return true
04188                         return FALSE;   // OK...
04189                 }
04190 
04191                 reset ($TCA);
04192                 $tableList = array();
04193                 while (list($table)=each($TCA)) {
04194                         if (!in_array($table,$allowedArray))    {       // If the table is not in the allowed list, check if there are records...
04195                                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', $table, 'pid='.intval($page_uid));
04196                                 $count = $GLOBALS['TYPO3_DB']->sql_fetch_row($mres);
04197                                 if ($count[0])  {
04198                                         $tableList[]=$table;
04199                                 }
04200                         }
04201                 }
04202                 return implode(',',$tableList);
04203         }
04204 
04205 
04206 
04207 
04208 
04209 
04210 
04211 
04212         /*****************************
04213          *
04214          * Information lookup
04215          *
04216          *****************************/
04217 
04226         function pageInfo($id,$field)   {
04227                 if (!isset($this->pageCache[$id]))      {
04228                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'uid='.intval($id));
04229                         if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
04230                                 $this->pageCache[$id] = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
04231                         }
04232                         $GLOBALS['TYPO3_DB']->sql_free_result($res);
04233                 }
04234                 return $this->pageCache[$id][$field];
04235         }
04236 
04246         function recordInfo($table,$id,$fieldList)      {
04247                 global $TCA;
04248                 if (is_array($TCA[$table]))     {
04249                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fieldList, $table, 'uid='.intval($id));
04250                         if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
04251                                 return $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
04252                         }
04253                 }
04254         }
04255 
04267         function getRecordProperties($table,$id,$noWSOL=FALSE)  {
04268                 $row = ($table=='pages' && !$id) ? array('title'=>'[root-level]', 'uid' => 0, 'pid' => 0) :$this->recordInfo($table,$id,'*');
04269                 if (!$noWSOL)   {
04270                         t3lib_BEfunc::workspaceOL($table,$row);
04271                 }
04272                 t3lib_BEfunc::fixVersioningPid($table,$row);
04273                 return $this->getRecordPropertiesFromRow($table,$row);
04274         }
04275 
04283         function getRecordPropertiesFromRow($table,$row)        {
04284                 global $TCA;
04285                 if ($TCA[$table])       {
04286                         $out = array(
04287                                 'header' => $row[$TCA[$table]['ctrl']['label']],
04288                                 'pid' => $row['pid'],
04289                                 'event_pid' => ($table=='pages'?$row['uid']:$row['pid']),
04290                                 't3ver_state' => $TCA[$table]['ctrl']['versioningWS'] ? $row['t3ver_state'] : '',
04291                                 '_ORIG_pid' => $row['_ORIG_pid']
04292                         );
04293                         return $out;
04294                 }
04295         }
04296 
04297 
04298 
04299 
04300 
04301 
04302 
04303 
04304 
04305 
04306 
04307 
04308 
04309 
04310 
04311         /*********************************************
04312          *
04313          * Storing data to Database Layer
04314          *
04315          ********************************************/
04316 
04326         function updateDB($table,$id,$fieldArray)       {
04327                 global $TCA;
04328 
04329                 if (is_array($fieldArray) && is_array($TCA[$table]) && intval($id))     {
04330                         unset($fieldArray['uid']);      // Do NOT update the UID field, ever!
04331 
04332                         if (count($fieldArray)) {
04333 
04334                                         // Execute the UPDATE query:
04335                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($id), $fieldArray);
04336 
04337                                         // If succees, do...:
04338                                 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
04339 
04340                                         if ($this->checkStoredRecords)  {
04341                                                 $newRow = $this->checkStoredRecord($table,$id,$fieldArray,2);
04342                                         }
04343 
04344                                                 // Update reference index:
04345                                         $this->updateRefIndex($table,$id);
04346 
04347                                                 // Set log entry:
04348                                         $propArr = $this->getRecordPropertiesFromRow($table,$newRow);
04349                                         $theLogId = $this->log($table,$id,2,$propArr['pid'],0,"Record '%s' (%s) was updated.",10,array($propArr['header'],$table.':'.$id),$propArr['event_pid']);
04350 
04351                                                 // Set History data:
04352                                         $this->setHistory($table,$id,$theLogId);
04353 
04354                                                 // Clear cache for relevant pages:
04355                                         $this->clear_cache($table,$id);
04356 
04357                                                 // Unset the pageCache for the id if table was page.
04358                                         if ($table=='pages')    unset($this->pageCache[$id]);
04359                                 } else {
04360                                         $this->log($table,$id,2,0,2,"SQL error: '%s' (%s)",12,array($GLOBALS['TYPO3_DB']->sql_error(),$table.':'.$id));
04361                                 }
04362                         }
04363                 }
04364         }
04365 
04378         function insertDB($table,$id,$fieldArray,$newVersion=FALSE,$suggestedUid=0,$dontSetNewIdIndex=FALSE)    {
04379                 global $TCA;
04380 
04381                 if (is_array($fieldArray) && is_array($TCA[$table]) && isset($fieldArray['pid']))       {
04382                         unset($fieldArray['uid']);      // Do NOT insert the UID field, ever!
04383 
04384                         if (count($fieldArray)) {
04385 
04386                                         // Check for "suggestedUid".
04387                                         // This feature is used by the import functionality to force a new record to have a certain UID value.
04388                                         // This is only recommended for use when the destination server is a passive mirrow of another server.
04389                                         // As a security measure this feature is available only for Admin Users (for now)
04390                                 $suggestedUid = intval($suggestedUid);
04391                                 if ($this->BE_USER->isAdmin() && $suggestedUid && $this->suggestedInsertUids[$table.':'.$suggestedUid]) {
04392                                                 // When the value of ->suggestedInsertUids[...] is "DELETE" it will try to remove the previous record
04393                                         if ($this->suggestedInsertUids[$table.':'.$suggestedUid]==='DELETE')    {
04394                                                         // DELETE:
04395                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery($table, 'uid='.intval($suggestedUid));
04396                                         }
04397                                         $fieldArray['uid'] = $suggestedUid;
04398                                 }
04399 
04400                                         // Execute the INSERT query:
04401                                 $GLOBALS['TYPO3_DB']->exec_INSERTquery($table, $fieldArray);
04402 
04403                                         // If succees, do...:
04404                                 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
04405 
04406                                                 // Set mapping for NEW... -> real uid:
04407                                         $NEW_id = $id;          // the NEW_id now holds the 'NEW....' -id
04408                                         $id = $GLOBALS['TYPO3_DB']->sql_insert_id();
04409                                         if (!$dontSetNewIdIndex)        {
04410                                                 $this->substNEWwithIDs[$NEW_id] = $id;
04411                                                 $this->substNEWwithIDs_table[$NEW_id] = $table;
04412                                         }
04413 
04414                                                 // Checking the record is properly saved and writing to log
04415                                         if ($this->checkStoredRecords)  {
04416                                                 $newRow = $this->checkStoredRecord($table,$id,$fieldArray,1);
04417                                         }
04418 
04419                                                 // Update reference index:
04420                                         $this->updateRefIndex($table,$id);
04421 
04422                                         if ($newVersion)        {
04423                                                 $this->log($table,$id,1,0,0,"New version created of table '%s', uid '%s'",10,array($table,$fieldArray['t3ver_oid']),$newRow['pid'],$NEW_id);
04424                                         } else {
04425                                                 $propArr = $this->getRecordPropertiesFromRow($table,$newRow);
04426                                                 $page_propArr = $this->getRecordProperties('pages',$propArr['pid']);
04427                                                 $this->log($table,$id,1,0,0,"Record '%s' (%s) was inserted on page '%s' (%s)",10,array($propArr['header'],$table.':'.$id,$page_propArr['header'],$newRow['pid']),$newRow['pid'],$NEW_id);
04428 
04429                                                         // Clear cache for relavant pages:
04430                                                 $this->clear_cache($table,$id);
04431                                         }
04432 
04433                                         return $id;
04434                                 } else {
04435                                         $this->log($table,$id,1,0,2,"SQL error: '%s' (%s)",12,array($GLOBALS['TYPO3_DB']->sql_error(),$table.':'.$id));
04436                                 }
04437                         }
04438                 }
04439         }
04440 
04451         function checkStoredRecord($table,$id,$fieldArray,$action)      {
04452                 global $TCA;
04453 
04454                 $id = intval($id);
04455                 if (is_array($TCA[$table]) && $id)      {
04456                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($id));
04457                         if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
04458                                         // Traverse array of values that was inserted into the database and compare with the actually stored value:
04459                                 $errorString = array();
04460                                 foreach($fieldArray as $key => $value)  {
04461                                         if ($this->checkStoredRecords_loose && !$value && !$row[$key])  {
04462                                                 // Nothing...
04463                                         } elseif (strcmp($value,$row[$key]))    {
04464                                                 $errorString[] = $key;
04465                                         }
04466                                 }
04467 
04468                                         // Set log message if there were fields with unmatching values:
04469                                 if (count($errorString))        {
04470                                         $this->log($table,$id,$action,0,102,'These fields are not properly updated in database: ('.implode(',',$errorString).') Probably value mismatch with fieldtype.');
04471                                 }
04472 
04473                                         // Return selected rows:
04474                                 return $row;
04475                         }
04476                         $GLOBALS['TYPO3_DB']->sql_free_result($res);
04477                 }
04478         }
04479 
04488         function setHistory($table,$id,$logId)          {
04489                 if (isset($this->historyRecords[$table.':'.$id]))       {
04490 
04491                                 // Initialize settings:
04492                         list($tscPID) = t3lib_BEfunc::getTSCpid($table,$id,'');
04493                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
04494 
04495                         $tE = $this->getTableEntries($table,$TSConfig);
04496                         $maxAgeSeconds = 60*60*24*(strcmp($tE['history.']['maxAgeDays'],'') ? t3lib_div::intInRange($tE['history.']['maxAgeDays'],0,365) : 30); // one month
04497 
04498                                 // Garbage collect old entries:
04499                         $this->clearHistory($maxAgeSeconds, $table);
04500 
04501                                 // Set history data:
04502                                 $fields_values = array();
04503                                 $fields_values['history_data'] = serialize($this->historyRecords[$table.':'.$id]);
04504                                 $fields_values['fieldlist'] = implode(',',array_keys($this->historyRecords[$table.':'.$id]['newRecord']));
04505                                 $fields_values['tstamp'] = time();
04506                                 $fields_values['tablename'] = $table;
04507                                 $fields_values['recuid'] = $id;
04508                                 $fields_values['sys_log_uid'] = $logId;
04509 
04510                                 $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_history', $fields_values);
04511                         }
04512                 }
04513 
04521         function clearHistory($maxAgeSeconds=604800,$table)     {
04522                 $tstampLimit = $maxAgeSeconds ? time()-$maxAgeSeconds : 0;
04523 
04524                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_history', 'tstamp<'.intval($tstampLimit).' AND tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_history'));
04525                 }
04526 
04535         function updateRefIndex($table,$id)     {
04536                 $refIndexObj = t3lib_div::makeInstance('t3lib_refindex');
04537                 $result = $refIndexObj->updateRefIndexTable($table,$id);
04538         }
04539 
04540 
04541 
04542 
04543 
04544 
04545 
04546 
04547 
04548 
04549 
04550 
04551 
04552         /*********************************************
04553          *
04554          * Misc functions
04555          *
04556          ********************************************/
04557 
04567         function getSortNumber($table,$uid,$pid)        {
04568                 global $TCA;
04569                 if ($TCA[$table] && $TCA[$table]['ctrl']['sortby'])     {
04570                         $sortRow = $TCA[$table]['ctrl']['sortby'];
04571                         if ($pid>=0)    {       // Sorting number is in the top
04572                                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($sortRow.',pid,uid', $table, 'pid='.intval($pid).$this->deleteClause($table), '', $sortRow.' ASC', '1');          // Fetches the first record under this pid
04573                                 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {       // There was an element
04574                                         if ($row['uid']==$uid)  {       // The top record was the record it self, so we return its current sortnumber
04575                                                 return $row[$sortRow];
04576                                         }
04577                                         if ($row[$sortRow] < 1) {       // If the pages sortingnumber < 1 we must resort the records under this pid
04578                                                 $this->resorting($table,$pid,$sortRow,0);
04579                                                 return $this->sortIntervals;    // First sorting number after resorting
04580                                         } else {
04581                                                 return floor($row[$sortRow]/2); // Sorting number between current top element and zero
04582                                         }
04583                                 } else {        // No pages, so we choose the default value as sorting-number
04584                                         return $this->sortIntervals;    // First sorting number if no elements.
04585                                 }
04586                         } else {        // Sorting number is inside the list
04587                                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($sortRow.',pid,uid', $table, 'uid='.abs($pid).$this->deleteClause($table));               // Fetches the record which is supposed to be the prev record
04588                                 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {       // There was a record
04589 
04590                                                 // Look, if the record UID happens to be an offline record. If so, find its live version. Offline uids will be used when a page is versionized as "branch" so this is when we must correct - otherwise a pid of "-1" and a wrong sort-row number is returned which we don't want.
04591                                         if ($lookForLiveVersion = t3lib_BEfunc::getLiveVersionOfRecord($table,$row['uid'],$sortRow.',pid,uid')) {
04592                                                 $row =  $lookForLiveVersion;
04593                                         }
04594 
04595                                                 // If the record happends to be it self
04596                                         if ($row['uid']==$uid)  {
04597                                                 $sortNumber = $row[$sortRow];
04598                                         } else {
04599                                                 $subres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
04600                                                                                 $sortRow.',pid,uid',
04601                                                                                 $table,
04602                                                                                 'pid='.intval($row['pid']).' AND '.$sortRow.'>='.intval($row[$sortRow]).$this->deleteClause($table),
04603                                                                                 '',
04604                                                                                 $sortRow.' ASC',
04605                                                                                 '2'
04606                                                                         );              // Fetches the next record in order to calculate the in between sortNumber
04607                                                 if ($GLOBALS['TYPO3_DB']->sql_num_rows($subres)==2)     {       // There was a record afterwards
04608                                                         $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres);                         // Forward to the second result...
04609                                                         $subrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres);       // There was a record afterwards
04610                                                         $sortNumber = $row[$sortRow]+ floor(($subrow[$sortRow]-$row[$sortRow])/2);      // The sortNumber is found in between these values
04611                                                         if ($sortNumber<=$row[$sortRow] || $sortNumber>=$subrow[$sortRow])      {       // The sortNumber happend NOT to be between the two surrounding numbers, so we'll have to resort the list
04612                                                                 $sortNumber = $this->resorting($table,$row['pid'],$sortRow,  $row['uid']);      // By this special param, resorting reserves and returns the sortnumber after the uid
04613                                                         }
04614                                                 } else {        // If after the last record in the list, we just add the sortInterval to the last sortvalue
04615                                                         $sortNumber = $row[$sortRow]+$this->sortIntervals;
04616                                                 }
04617                                         }
04618                                         return Array('pid' => $row['pid'], 'sortNumber' => $sortNumber);
04619                                 } else {
04620                                         $propArr = $this->getRecordProperties($table,$uid);
04621                                         $this->log($table,$uid,4,0,1,"Attempt to move record '%s' (%s) to after a non-existing record (uid=%s)",1,array($propArr['header'],$table.':'.$uid,abs($pid)),$propArr['pid']); // OK, dont insert $propArr['event_pid'] here...
04622                                         return false;   // There MUST be a page or else this cannot work
04623                                 }
04624                         }
04625                 }
04626         }
04627 
04640         function resorting($table,$pid,$sortRow, $return_SortNumber_After_This_Uid) {
04641                 global $TCA;
04642                 if ($TCA[$table] && $sortRow && $TCA[$table]['ctrl']['sortby']==$sortRow)       {
04643                         $returnVal = 0;
04644                         $intervals = $this->sortIntervals;
04645                         $i = $intervals*2;
04646 
04647                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($pid).$this->deleteClause($table), '', $sortRow.' ASC');
04648                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
04649                                 $uid=intval($row['uid']);
04650                                 if ($uid)       {
04651                                         $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), array($sortRow=>$i));
04652                                         if ($uid==$return_SortNumber_After_This_Uid)    {               // This is used to return a sortingValue if the list is resorted because of inserting records inside the list and not in the top
04653                                                 $i = $i+$intervals;
04654                                                 $returnVal=$i;
04655                                         }
04656                                 } else {die ('Fatal ERROR!! No Uid at resorting.');}
04657                                 $i = $i+$intervals;
04658                         }
04659                         return $returnVal;
04660                 }
04661         }
04662 
04671         function setTSconfigPermissions($fieldArray,$TSConfig_p)        {
04672                 if (strcmp($TSConfig_p['userid'],''))   $fieldArray['perms_userid']=intval($TSConfig_p['userid']);
04673                 if (strcmp($TSConfig_p['groupid'],''))  $fieldArray['perms_groupid']=intval($TSConfig_p['groupid']);
04674                 if (strcmp($TSConfig_p['user'],''))                     $fieldArray['perms_user']=t3lib_div::testInt($TSConfig_p['user']) ? $TSConfig_p['user'] : $this->assemblePermissions($TSConfig_p['user']);
04675                 if (strcmp($TSConfig_p['group'],''))            $fieldArray['perms_group']=t3lib_div::testInt($TSConfig_p['group']) ? $TSConfig_p['group'] : $this->assemblePermissions($TSConfig_p['group']);
04676                 if (strcmp($TSConfig_p['everybody'],''))        $fieldArray['perms_everybody']=t3lib_div::testInt($TSConfig_p['everybody']) ? $TSConfig_p['everybody'] : $this->assemblePermissions($TSConfig_p['everybody']);
04677 
04678                 return $fieldArray;
04679         }
04680 
04688         function newFieldArray($table)  {
04689                 global $TCA;
04690 
04691                 t3lib_div::loadTCA($table);
04692                 $fieldArray=Array();
04693                 if (is_array($TCA[$table]['columns']))  {
04694                         reset ($TCA[$table]['columns']);
04695                         while (list($field,$content)=each($TCA[$table]['columns']))     {
04696                                 if (isset($this->defaultValues[$table][$field]))        {
04697                                         $fieldArray[$field] = $this->defaultValues[$table][$field];
04698                                 } elseif (isset($content['config']['default'])) {
04699                                         $fieldArray[$field] = $content['config']['default'];
04700                                 }
04701                         }
04702                 }
04703                 if ($table==='pages')   {               // Set default permissions for a page.
04704                         $fieldArray['perms_userid'] = $this->userid;
04705                         $fieldArray['perms_groupid'] = intval($this->BE_USER->firstMainGroup);
04706                         $fieldArray['perms_user'] = $this->assemblePermissions($this->defaultPermissions['user']);
04707                         $fieldArray['perms_group'] = $this->assemblePermissions($this->defaultPermissions['group']);
04708                         $fieldArray['perms_everybody'] = $this->assemblePermissions($this->defaultPermissions['everybody']);
04709                 }
04710                 return $fieldArray;
04711         }
04712 
04720         function addDefaultPermittedLanguageIfNotSet($table,&$incomingFieldArray)       {
04721                 global $TCA;
04722 
04723                         // Checking languages:
04724                 if ($TCA[$table]['ctrl']['languageField'])      {
04725                         if (!isset($incomingFieldArray[$TCA[$table]['ctrl']['languageField']])) {       // Language field must be found in input row - otherwise it does not make sense.
04726                                 $rows = array_merge(array(array('uid'=>0)),$GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid','sys_language','pid=0'.t3lib_BEfunc::deleteClause('sys_language')),array(array('uid'=>-1)));
04727                                 foreach($rows as $r)    {
04728                                         if ($this->BE_USER->checkLanguageAccess($r['uid']))             {
04729                                                 $incomingFieldArray[$TCA[$table]['ctrl']['languageField']] = $r['uid'];
04730                                                 break;
04731                                         }
04732                                 }
04733                         }
04734                 }
04735         }
04736 
04744         function overrideFieldArray($table,$data)       {
04745                 if (is_array($this->overrideValues[$table]))    {
04746                         $data = array_merge($data,$this->overrideValues[$table]);
04747                 }
04748                 return $data;
04749         }
04750 
04760         function compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray)   {
04761 
04762                         // Fetch the original record:
04763                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($id));
04764                 $currentRecord = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
04765 
04766                         // If the current record exists (which it should...), begin comparison:
04767                 if (is_array($currentRecord))   {
04768 
04769                                 // Read all field types:
04770                         $c = 0;
04771                         $cRecTypes = array();
04772                         foreach($currentRecord as $col => $val) {
04773                                 $cRecTypes[$col] = $GLOBALS['TYPO3_DB']->sql_field_type($res,$c);
04774                                 $c++;
04775                         }
04776 
04777                                 // Free result:
04778                         $GLOBALS['TYPO3_DB']->sql_free_result($res);
04779 
04780                                 // Unset the fields which are similar:
04781                         foreach($fieldArray as $col => $val)    {
04782                                 if (
04783                                                 !strcmp($val,$currentRecord[$col]) ||   // Unset fields which matched exactly.
04784                                                 ($cRecTypes[$col]=='int' && $currentRecord[$col]==0 && !strcmp($val,''))        // Now, a situation where TYPO3 tries to put an empty string into an integer field, we should not strcmp the integer-zero and '', but rather accept them to be similar.
04785                                         )       {
04786                                         unset($fieldArray[$col]);
04787                                 } else {
04788                                         $this->historyRecords[$table.':'.$id]['oldRecord'][$col] = $currentRecord[$col];
04789                                         $this->historyRecords[$table.':'.$id]['newRecord'][$col] = $fieldArray[$col];
04790                                 }
04791                         }
04792                 } else {        // If the current record does not exist this is an error anyways and we just return an empty array here.
04793                         $fieldArray = array();
04794                 }
04795 
04796                 return $fieldArray;
04797         }
04798 
04806         function assemblePermissions($string)   {
04807                 $keyArr = t3lib_div::trimExplode(',',$string,1);
04808                 $value=0;
04809                 while(list(,$key)=each($keyArr))        {
04810                         if ($key && isset($this->pMap[$key]))   {
04811                                 $value |= $this->pMap[$key];
04812                         }
04813                 }
04814                 return $value;
04815         }
04816 
04823         function rmComma($input)        {
04824                 return ereg_replace(',$','',$input);
04825         }
04826 
04833         function convNumEntityToByteValue($input)       {
04834                 $token = md5(microtime());
04835                 $parts = explode($token,ereg_replace('(&#([0-9]+);)',$token.'\2'.$token,$input));
04836 
04837                 foreach($parts as $k => $v)     {
04838                         if ($k%2)       {
04839                                 $v = intval($v);
04840                                 if ($v > 32)    {       // Just to make sure that control bytes are not converted.
04841                                         $parts[$k] =chr(intval($v));
04842                                 }
04843                         }
04844                 }
04845 
04846                 return implode('',$parts);
04847         }
04848 
04855         function destPathFromUploadFolder($folder)      {
04856                 return PATH_site.$folder;
04857         }
04858 
04865         function deleteClause($table)   {
04866                         // Returns the proper delete-clause if any for a table from TCA
04867                 global $TCA;
04868                 if ($TCA[$table]['ctrl']['delete'])     {
04869                         return ' AND '.$table.'.'.$TCA[$table]['ctrl']['delete'].'=0';
04870                 } else {
04871                         return '';
04872                 }
04873         }
04874 
04881         function getTCEMAIN_TSconfig($tscPID)   {
04882                 if (!isset($this->cachedTSconfig[$tscPID]))     {
04883                         $this->cachedTSconfig[$tscPID] = $this->BE_USER->getTSConfig('TCEMAIN',t3lib_BEfunc::getPagesTSconfig($tscPID));
04884                 }
04885                 return $this->cachedTSconfig[$tscPID]['properties'];
04886         }
04887 
04896         function getTableEntries($table,$TSconfig)      {
04897                 $tA = is_array($TSconfig['table.'][$table.'.']) ? $TSconfig['table.'][$table.'.'] : array();;
04898                 $dA = is_array($TSconfig['default.']) ? $TSconfig['default.'] : array();
04899                 return t3lib_div::array_merge_recursive_overrule($dA,$tA);
04900         }
04901 
04909         function getPID($table,$uid)    {
04910                 $res_tmp = $GLOBALS['TYPO3_DB']->exec_SELECTquery('pid', $table, 'uid='.intval($uid));
04911                 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp))     {
04912                         return $row['pid'];
04913                 }
04914         }
04915 
04922         function dbAnalysisStoreExec()  {
04923                 reset($this->dbAnalysisStore);
04924                 while(list($k,$v)=each($this->dbAnalysisStore)) {
04925                         $id = $this->substNEWwithIDs[$v[2]];
04926                         if ($id)        {
04927                                 $v[2] = $id;
04928                                 $v[0]->writeMM($v[1],$v[2],$v[3]);
04929                         }
04930                 }
04931         }
04932 
04938         function removeRegisteredFiles()        {
04939                 reset($this->removeFilesStore);
04940                 while(list($k,$v)=each($this->removeFilesStore))        {
04941                         unlink($v);
04942                 }
04943         }
04944 
04950         function removeCacheFiles()     {
04951                 return t3lib_extMgm::removeCacheFiles();
04952         }
04953 
04964         function int_pageTreeInfo($CPtable,$pid,$counter, $rootID)      {
04965                 if ($counter)   {
04966                         $addW =  !$this->admin ? ' AND '.$this->BE_USER->getPagePermsClause($this->pMap['show']) : '';
04967                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'pid='.intval($pid).$this->deleteClause('pages').$addW, '', 'sorting DESC');
04968                         while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))      {
04969                                 if ($row['uid']!=$rootID)       {
04970                                         $CPtable[$row['uid']] = $pid;
04971                                         if ($counter-1) {       // If the uid is NOT the rootID of the copyaction and if we are supposed to walk further down
04972                                                 $CPtable = $this->int_pageTreeInfo($CPtable,$row['uid'],$counter-1, $rootID);
04973                                         }
04974                                 }
04975                         }
04976                 }
04977                 return $CPtable;
04978         }
04979 
04985         function compileAdminTables()   {
04986                 global $TCA;
04987                 reset ($TCA);
04988                 $listArr = array();
04989                 while (list($table)=each($TCA)) {
04990                         $listArr[]=$table;
04991                 }
04992                 return $listArr;
04993         }
04994 
05002         function fixUniqueInPid($table,$uid)    {
05003                 global $TCA;
05004                 if ($TCA[$table])       {
05005                         t3lib_div::loadTCA($table);
05006                         reset ($TCA[$table]['columns']);
05007                         $curData=$this->recordInfo($table,$uid,'*');
05008                         $newData=array();
05009                         while (list($field,$conf)=each($TCA[$table]['columns']))        {
05010                                 if ($conf['config']['type']=='input')   {
05011                                         $evalCodesArray = t3lib_div::trimExplode(',',$conf['config']['eval'],1);
05012                                         if (in_array('uniqueInPid',$evalCodesArray))    {
05013                                                 $newV = $this->getUnique($table,$field,$curData[$field],$uid,$curData['pid']);
05014                                                 if (strcmp($newV,$curData[$field]))     {
05015                                                         $newData[$field]=$newV;
05016                                                 }
05017                                         }
05018                                 }
05019                         }
05020                                 // IF there are changed fields, then update the database
05021                         if (count($newData))    {
05022                                 $this->updateDB($table,$uid,$newData);
05023                         }
05024                 }
05025         }
05026 
05038         function fixCopyAfterDuplFields($table,$uid,$prevUid,$update, $newData=array()) {
05039                 global $TCA;
05040                 if ($TCA[$table] && $TCA[$table]['ctrl']['copyAfterDuplFields'])        {
05041                         t3lib_div::loadTCA($table);
05042                         $prevData=$this->recordInfo($table,$prevUid,'*');
05043                         $theFields = t3lib_div::trimExplode(',',$TCA[$table]['ctrl']['copyAfterDuplFields'],1);
05044                         reset($theFields);
05045                         while(list(,$field)=each($theFields))   {
05046                                 if ($TCA[$table]['columns'][$field] && ($update || !isset($newData[$field])))   {
05047                                         $newData[$field]=$prevData[$field];
05048                                 }
05049                         }
05050                         if ($update && count($newData)) {
05051                                 $this->updateDB($table,$uid,$newData);
05052                         }
05053                 }
05054                 return $newData;
05055         }
05056 
05063         function extFileFields($table)  {
05064                 global $TCA;
05065                 $listArr=array();
05066                 t3lib_div::loadTCA($table);
05067                 if ($TCA[$table]['columns'])    {
05068                         reset($TCA[$table]['columns']);
05069                         while (list($field,$configArr)=each($TCA[$table]['columns']))   {
05070                                 if ($configArr['config']['type']=='group' && $configArr['config']['internal_type']=='file')     {
05071                                         $listArr[]=$field;
05072                                 }
05073                         }
05074                 }
05075                 return $listArr;
05076         }
05077 
05084         function getUniqueFields($table)        {
05085                 global $TCA;
05086 
05087                 $listArr=array();
05088                 t3lib_div::loadTCA($table);
05089                 if ($TCA[$table]['columns'])    {
05090                         reset($TCA[$table]['columns']);
05091                         while (list($field,$configArr)=each($TCA[$table]['columns']))   {
05092                                 if ($configArr['config']['type']==='input')     {
05093                                         $evalCodesArray = t3lib_div::trimExplode(',',$configArr['config']['eval'],1);
05094                                         if (in_array('uniqueInPid',$evalCodesArray) || in_array('unique',$evalCodesArray))      {
05095                                                 $listArr[]=$field;
05096                                         }
05097                                 }
05098                         }
05099                 }
05100                 return $listArr;
05101         }
05102 
05109         function isReferenceField($conf)        {
05110                 return ($conf['type']=='group' && $conf['internal_type']=='db') ||      ($conf['type']=='select' && $conf['foreign_table']);
05111         }
05112 
05124         function getCopyHeader($table,$pid,$field,$value,$count,$prevTitle='')  {
05125                 global $TCA;
05126 
05127                         // Set title value to check for:
05128                 if ($count)     {
05129                         $checkTitle = $value.rtrim(' '.sprintf($this->prependLabel($table),$count));
05130                 }       else {
05131                         $checkTitle = $value;
05132                 }
05133 
05134                         // Do check:
05135                 if ($prevTitle != $checkTitle || $count<100)    {
05136                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($pid).' AND '.$field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($checkTitle, $table).$this->deleteClause($table), '', '', '1');
05137                         if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
05138                                 return $this->getCopyHeader($table,$pid,$field,$value,$count+1,$checkTitle);
05139                         }
05140                 }
05141 
05142                         // Default is to just return the current input title if no other was returned before:
05143                 return $checkTitle;
05144         }
05145 
05153         function prependLabel($table)   {
05154                 global $TCA;
05155                 if (is_object($GLOBALS['LANG']))        {
05156                         $label = $GLOBALS['LANG']->sL($TCA[$table]['ctrl']['prependAtCopy']);
05157                 } else {
05158                         list($label) = explode('|',$TCA[$table]['ctrl']['prependAtCopy']);
05159                 }
05160                 return $label;
05161         }
05162 
05170         function resolvePid($table,$pid)        {
05171                 global $TCA;
05172                 $pid = intval($pid);
05173                 if ($pid < 0)   {
05174                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('pid', $table, 'uid='.abs($pid));
05175                         $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
05176 
05177                                 // Look, if the record UID happens to be an offline record. If so, find its live version. Offline uids will be used when a page is versionized as "branch" so this is when we must correct - otherwise a pid of "-1" and a wrong sort-row number is returned which we don't want.
05178                         if ($lookForLiveVersion = t3lib_BEfunc::getLiveVersionOfRecord($table,abs($pid),'pid')) {
05179                                 $row = $lookForLiveVersion;
05180                         }
05181 
05182                         $pid = intval($row['pid']);
05183                 } elseif ($this->BE_USER->workspace!==0 && $TCA[$table]['ctrl']['versioning_followPages']) { // PID points to page, the workspace is an offline space and the table follows page during versioning: This means we must check if the PID page has a version in the workspace with swapmode set to 0 (zero = page+content) and if so, change the pid to the uid of that version.
05184                         if ($WSdestPage = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, 'pages', $pid, 'uid,t3ver_swapmode'))    {       // Looks for workspace version of page.
05185                                 if ($WSdestPage['t3ver_swapmode']==0)   {       // if swapmode is zero, then change pid value.
05186                                         $pid = $WSdestPage['uid'];
05187                                 }
05188                         }
05189                 }
05190                 return $pid;
05191         }
05192 
05200         function clearPrefixFromValue($table,$value)    {
05201                 global $TCA;
05202                 $regex = sprintf(quotemeta($this->prependLabel($table)),'[0-9]*').'$';
05203                 return @ereg_replace($regex,'',$value);
05204         }
05205 
05215         function extFileFunctions($table,$field,$filelist,$func)        {
05216                 global $TCA;
05217                 t3lib_div::loadTCA($table);
05218                 $uploadFolder = $TCA[$table]['columns'][$field]['config']['uploadfolder'];
05219                 if ($uploadFolder && trim($filelist))   {
05220                         $uploadPath = $this->destPathFromUploadFolder($uploadFolder);
05221                         $fileArray = explode(',',$filelist);
05222                         while (list(,$theFile)=each($fileArray))        {
05223                                 $theFile=trim($theFile);
05224                                 if ($theFile)   {
05225                                         switch($func)   {
05226                                                 case 'deleteAll':
05227                                                         if (@is_file($uploadPath.'/'.$theFile)) {
05228                                                                 unlink ($uploadPath.'/'.$theFile);
05229                                                         } else {
05230                                                                 $this->log($table,0,3,0,100,"Delete: Referenced file that was supposed to be deleted together with it's record didn't exist");
05231                                                         }
05232                                                 break;
05233                                         }
05234                                 }
05235                         }
05236                 }
05237         }
05238 
05245         function noRecordsFromUnallowedTables($inList)  {
05246                 global $TCA;
05247                 reset ($TCA);
05248                 $inList = trim($this->rmComma(trim($inList)));
05249                 if ($inList && !$this->admin)   {
05250                         while (list($table) = each($TCA))       {
05251                                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', $table, 'pid IN ('.$inList.')'.t3lib_BEfunc::deleteClause($table));
05252                                 $count = $GLOBALS['TYPO3_DB']->sql_fetch_row($mres);
05253                                 if ($count[0] && ($this->tableReadOnly($table) || !$this->checkModifyAccessList($table)))       {
05254                                         return FALSE;
05255                                 }
05256                         }
05257                 }
05258                 return TRUE;
05259         }
05260 
05271         function notifyStageChange($stat,$stageId,$table,$id,$comment)  {
05272                 $workspaceRec = t3lib_BEfunc::getRecord('sys_workspace', $stat['uid']);
05273 
05274                 if (is_array($workspaceRec))    {
05275 
05276                                 // Compile label:
05277                         switch((int)$stageId)   {
05278                                 case 1:
05279                                         $newStage = 'Ready for review';
05280                                 break;
05281                                 case 10:
05282                                         $newStage = 'Ready for publishing';
05283                                 break;
05284                                 case -1:
05285                                         $newStage = 'Element was rejected!';
05286                                 break;
05287                                 case 0:
05288                                         $newStage = 'Rejected element was noticed and edited';
05289                                 break;
05290                                 default:
05291                                         $newStage = 'Unknown state change!?';
05292                                 break;
05293                         }
05294 
05295                                 // Compile list of recipients:
05296                         $emails = array();
05297                         switch((int)$stat['stagechg_notification'])     {
05298                                 case 1:
05299                                         switch((int)$stageId)   {
05300                                                 case 1:
05301                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['reviewers']);
05302                                                 break;
05303                                                 case 10:
05304                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['adminusers'], TRUE);
05305                                                 break;
05306                                                 case -1:
05307                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['reviewers']);
05308                                                         $emails = array_merge($emails,$this->notifyStageChange_getEmails($workspaceRec['members']));
05309                                                 break;
05310                                                 case 0:
05311                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['members']);
05312                                                 break;
05313                                                 default:
05314                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['adminusers'], TRUE);
05315                                                 break;
05316                                         }
05317                                 break;
05318                                 case 10:
05319                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['adminusers'], TRUE);
05320                                         $emails = array_merge($emails,$this->notifyStageChange_getEmails($workspaceRec['reviewers']));
05321                                         $emails = array_merge($emails,$this->notifyStageChange_getEmails($workspaceRec['members']));
05322                                 break;
05323                         }
05324                         $emails = array_unique($emails);
05325 
05326                                 // Send email:
05327                         if (count($emails))     {
05328                                 $message = sprintf('
05329 At the TYPO3 site "%s" (%s)
05330 in workspace "%s" (#%s)
05331 the stage has changed for the element "%s":
05332 
05333 ==> %s
05334 
05335 User Comment:
05336 "%s"
05337 
05338 State was change by %s (username: %s)
05339                                 ',
05340                                 $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'],
05341                                 t3lib_div::getIndpEnv('TYPO3_SITE_URL').TYPO3_mainDir,
05342                                 $workspaceRec['title'],
05343                                 $workspaceRec['uid'],
05344                                 $table.':'.$id,
05345                                 $newStage,
05346                                 $comment,
05347                                 $this->BE_USER->user['realName'],
05348                                 $this->BE_USER->user['username']);
05349 
05350                                 t3lib_div::plainMailEncoded(
05351                                         implode(',',$emails),
05352                                         'TYPO3 Workspace Note: Stage Change for '.$table.':'.$id,
05353                                         trim($message)
05354                                 );
05355                         }
05356                 }
05357         }
05358 
05366         function notifyStageChange_getEmails($listOfUsers,$noTablePrefix=FALSE) {
05367                 $users = t3lib_div::trimExplode(',',$listOfUsers,1);
05368                 $emails = array();
05369                 foreach($users as $userIdent)   {
05370                         if ($noTablePrefix)     {
05371                                 $id = intval($userIdent);
05372                         } else {
05373                                 list($table,$id) = t3lib_div::revExplode('_',$userIdent,2);
05374                         }
05375                         if ($table==='be_users' || $noTablePrefix)      {
05376                                 if ($userRecord = t3lib_BEfunc::getRecord('be_users', $id, 'email'))    {
05377                                         if (strlen(trim($userRecord['email']))) {
05378                                                 $emails[$id] = $userRecord['email'];
05379                                         }
05380                                 }
05381                         }
05382                 }
05383                 return $emails;
05384         }
05385 
05386 
05387 
05388 
05389 
05390 
05391 
05392 
05393 
05394 
05395 
05396 
05397         /******************************
05398          *
05399          * Clearing cache
05400          *
05401          ******************************/
05402 
05412         function clear_cache($table,$uid) {
05413                 global $TCA, $TYPO3_CONF_VARS;
05414 
05415                 $uid = intval($uid);
05416                 if (is_array($TCA[$table]) && $uid > 0) {
05417 
05418                                 // Get Page TSconfig relavant:
05419                         list($tscPID) = t3lib_BEfunc::getTSCpid($table,$uid,'');
05420                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
05421 
05422                         if (!$TSConfig['clearCache_disable'])   {
05423 
05424                                         // If table is "pages":
05425                                 if (t3lib_extMgm::isLoaded('cms'))      {
05426                                         $list_cache = array();
05427                                         if ($table=='pages')    {
05428 
05429                                                         // Builds list of pages on the SAME level as this page (siblings)
05430                                                 $res_tmp = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
05431                                                                                 'A.pid AS pid, B.uid AS uid',
05432                                                                                 'pages A, pages B',
05433                                                                                 'A.uid='.intval($uid).' AND B.pid=A.pid AND B.deleted=0'
05434                                                                         );
05435 
05436                                                 $pid_tmp = 0;
05437                                                 while ($row_tmp = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp)) {
05438                                                         $list_cache[] = $row_tmp['uid'];
05439                                                         $pid_tmp = $row_tmp['pid'];
05440 
05441                                                                 // Add children as well:
05442                                                         if ($TSConfig['clearCache_pageSiblingChildren'])        {
05443                                                                 $res_tmp2 = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
05444                                                                                                 'uid',
05445                                                                                                 'pages',
05446                                                                                                 'pid='.intval($row_tmp['uid']).' AND deleted=0'
05447                                                                                         );
05448                                                                 while ($row_tmp2 = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp2))    {
05449                                                                         $list_cache[] = $row_tmp2['uid'];
05450                                                                 }
05451                                                         }
05452                                                 }
05453 
05454                                                         // Finally, add the parent page as well:
05455                                                 $list_cache[] = $pid_tmp;
05456 
05457                                                         // Add grand-parent as well:
05458                                                 if ($TSConfig['clearCache_pageGrandParent'])    {
05459                                                         $res_tmp = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
05460                                                                                         'pid',
05461                                                                                         'pages',
05462                                                                                         'uid='.intval($pid_tmp)
05463                                                                                 );
05464                                                         if ($row_tmp = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp)) {
05465                                                                 $list_cache[] = $row_tmp['pid'];
05466                                                         }
05467                                                 }
05468                                         } else {        // For other tables than "pages", delete cache for the records "parent page".
05469                                                 $list_cache[] = intval($this->getPID($table,$uid));
05470                                         }
05471 
05472                                                 // Call pre-processing function for clearing of cache for page ids:
05473                                         if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval']))    {
05474                                                 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval'] as $funcName)     {
05475                                                         $_params = array('pageIdArray' => &$list_cache, 'table' => $table, 'uid' => $uid, 'functionID' => 'clear_cache()');
05476                                                                 // Returns the array of ids to clear, false if nothing should be cleared! Never an empty array!
05477                                                         t3lib_div::callUserFunction($funcName,$_params,$this);
05478                                                 }
05479                                         }
05480 
05481                                                 // Delete cache for selected pages:
05482                                         if (is_array($list_cache))      {
05483                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')');
05484                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection', 'page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')');
05485                                         }
05486                                 }
05487                         }
05488 
05489                                 // Clear cache for pages entered in TSconfig:
05490                         if ($TSConfig['clearCacheCmd']) {
05491                                 $Commands = t3lib_div::trimExplode(',',strtolower($TSConfig['clearCacheCmd']),1);
05492                                 $Commands = array_unique($Commands);
05493                                 foreach($Commands as $cmdPart)  {
05494                                         $this->clear_cacheCmd($cmdPart);
05495                                 }
05496                         }
05497 
05498                                 // Call post processing function for clear-cache:
05499                         global $TYPO3_CONF_VARS;
05500                         if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc']))    {
05501 // FIXME $uid_page is undefined
05502                                 $_params = array('table' => $table,'uid' => $uid,'uid_page' => $uid_page,'TSConfig' => $TSConfig);
05503                                 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'] as $_funcRef)     {
05504                                         t3lib_div::callUserFunction($_funcRef,$_params,$this);
05505                                 }
05506                         }
05507                 }
05508         }
05509 
05522         function clear_cacheCmd($cacheCmd)      {
05523                 global $TYPO3_CONF_VARS;
05524 
05525                         // Clear cache for either ALL pages or ALL tables!
05526                 switch($cacheCmd)       {
05527                         case 'pages':
05528                                 if ($this->admin || $this->BE_USER->getTSConfigVal('options.clearCache.pages')) {
05529                                         if (t3lib_extMgm::isLoaded('cms'))      {
05530                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','');
05531                                         }
05532                                 }
05533                         break;
05534                         case 'all':
05535                                 if ($this->admin || $this->BE_USER->getTSConfigVal('options.clearCache.all'))   {
05536                                         if (t3lib_extMgm::isLoaded('cms'))      {
05537                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','');
05538                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection','');
05539                                         }
05540                                         $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_hash','');
05541 
05542                                                 // Clearing additional cache tables:
05543                                         if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearAllCache_additionalTables']))        {
05544                                                 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearAllCache_additionalTables'] as $tableName)        {
05545                                                         if (!ereg('[^[:alnum:]_]',$tableName) && substr($tableName,-5)=='cache')        {
05546                                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery($tableName,'');
05547                                                         } else {
05548                                                                 die('Fatal Error: Trying to flush table "'.$tableName.'" with "Clear All Cache"');
05549                                                         }
05550                                                 }
05551                                         }
05552                                 }
05553                         break;
05554                         case 'temp_CACHED':
05555                                 if ($this->admin && $TYPO3_CONF_VARS['EXT']['extCache'])        {
05556                                         $this->removeCacheFiles();
05557                                 }
05558                         break;
05559                 }
05560 
05561                         // Clear cache for a page ID!
05562                 if (t3lib_div::testInt($cacheCmd))      {
05563                         if (t3lib_extMgm::isLoaded('cms'))      {
05564 
05565                                 $list_cache = array($cacheCmd);
05566 
05567                                         // Call pre-processing function for clearing of cache for page ids:
05568                                 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval']))    {
05569                                         foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval'] as $funcName)     {
05570                                                 $_params = array('pageIdArray' => &$list_cache, 'cacheCmd' => $cacheCmd, 'functionID' => 'clear_cacheCmd()');
05571                                                         // Returns the array of ids to clear, false if nothing should be cleared! Never an empty array!
05572                                                 t3lib_div::callUserFunction($funcName,$_params,$this);
05573                                         }
05574                                 }
05575 
05576                                         // Delete cache for selected pages:
05577                                 if (is_array($list_cache))      {
05578                                         $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')');
05579                                         $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection', 'page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')');  // Originally, cache_pagesection was not cleared with cache_pages!
05580                                 }
05581                         }
05582                 }
05583 
05584                         // Call post processing function for clear-cache:
05585                 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc']))    {
05586                         $_params = array('cacheCmd'=>$cacheCmd);
05587                         foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'] as $_funcRef)     {
05588                                 t3lib_div::callUserFunction($_funcRef,$_params,$this);
05589                         }
05590                 }
05591         }
05592 
05593 
05594 
05595 
05596 
05597 
05598 
05599 
05600 
05601 
05602 
05603 
05604 
05605 
05606         /*****************************
05607          *
05608          * Logging
05609          *
05610          *****************************/
05611 
05628         function log($table,$recuid,$action,$recpid,$error,$details,$details_nr=-1,$data=array(),$event_pid=-1,$NEWid='') {
05629                 if ($this->enableLogging)       {
05630                         $type=1;        // Type value for tce_db.php
05631                         if (!$this->storeLogMessages)   {$details='';}
05632                         if ($error>0)   $this->errorLog[] = '['.$type.'.'.$action.'.'.$details_nr.']: '.$details;
05633                         return $this->BE_USER->writelog($type,$action,$error,$details_nr,$details,$data,$table,$recuid,$recpid,$event_pid,$NEWid);
05634                 }
05635         }
05636 
05645         function newlog($message, $error=0)     {
05646                 return $this->log('',0,0,0,$error,$message,-1);
05647         }
05648 
05655         function printLogErrorMessages($redirect)       {
05656 
05657                 $res_log = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
05658                                         '*',
05659                                         'sys_log',
05660                                         'type=1 AND userid='.intval($this->BE_USER->user['uid']).' AND tstamp='.intval($GLOBALS['EXEC_TIME']).' AND error!=0'
05661                                 );
05662                 $errorJS = array();
05663                 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_log)) {
05664                         $log_data = unserialize($row['log_data']);
05665                         $errorJS[] = $row['error'].': '.sprintf($row['details'], $log_data[0],$log_data[1],$log_data[2],$log_data[3],$log_data[4]);
05666                 }
05667 
05668                 if (count($errorJS))    {
05669                         $error_doc = t3lib_div::makeInstance('template');
05670                         $error_doc->backPath = $GLOBALS['BACK_PATH'];
05671 
05672                         $content.= $error_doc->startPage('tce_db.php Error output');
05673 
05674                         $lines[] = '
05675                                         <tr class="bgColor5">
05676                                                 <td colspan="2" align="center"><strong>Errors:</strong></td>
05677                                         </tr>';
05678 
05679                         foreach($errorJS as $line)      {
05680                                 $lines[] = '
05681                                         <tr class="bgColor4">
05682                                                 <td valign="top"><img'.t3lib_iconWorks::skinImg($error_doc->backPath,'gfx/icon_fatalerror.gif','width="18" height="16"').' alt="" /></td>
05683                                                 <td>'.htmlspecialchars($line).'</td>
05684                                         </tr>';
05685                         }
05686 
05687                         $lines[] = '
05688                                         <tr>
05689                                                 <td colspan="2" align="center"><br />'.
05690                                                 '<form action=""><input type="submit" value="Continue" onclick="'.htmlspecialchars('window.location.href=\''.$redirect.'\';return false;').'"></form>'.
05691                                                 '</td>
05692                                         </tr>';
05693 
05694                         $content.= '
05695                                 <br/><br/>
05696                                 <table border="0" cellpadding="1" cellspacing="1" width="300" align="center">
05697                                         '.implode('',$lines).'
05698                                 </table>';
05699 
05700                         $content.= $error_doc->endPage();
05701                         echo $content;
05702                         exit;
05703                 }
05704         }
05705 }
05706 
05707 
05708 
05709 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tcemain.php'])   {
05710         include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tcemain.php']);
05711 }
05712 ?>