Documentation TYPO3 par Ameos

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 send 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 send 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                 // This could be a good spot for parsing the array through a validation-function which checks if the values are allright (except that database references are not in their final form - but that is the point, isn't it?)
01287                 // NOTE!!! Must check max-items of files before the later check because that check would just leave out filenames if there are too many!!
01288 
01289                         // Checking for select / authMode, removing elements from $valueArray if any of them is not allowed!
01290                 if ($tcaFieldConf['type']=='select' && $tcaFieldConf['authMode'])       {
01291                         $preCount = count($valueArray);
01292                         foreach($valueArray as $kk => $vv)      {
01293                                 if (!$this->BE_USER->checkAuthMode($table,$field,$vv,$tcaFieldConf['authMode']))        {
01294                                         unset($valueArray[$kk]);
01295                                 }
01296                         }
01297 
01298                                 // 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.
01299                         if ($preCount && !count($valueArray))   {
01300                                 return array();
01301                         }
01302                 }
01303 
01304                         // For group types:
01305                 if ($tcaFieldConf['type']=='group')     {
01306                         switch($tcaFieldConf['internal_type'])  {
01307                                 case 'file':
01308                                         $valueArray = $this->checkValue_group_select_file(
01309                                                 $valueArray,
01310                                                 $tcaFieldConf,
01311                                                 $curValue,
01312                                                 $uploadedFiles,
01313                                                 $status,
01314                                                 $table,
01315                                                 $id,
01316                                                 $recFID
01317                                         );
01318                                 break;
01319                                 case 'db':
01320                                         $valueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'group');
01321                                 break;
01322                         }
01323                 }
01324                         // For select types which has a foreign table attached:
01325                 if ($tcaFieldConf['type']=='select' && $tcaFieldConf['foreign_table'])  {
01326                         $valueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'select');
01327                 }
01328 
01329 // 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...
01330 
01331                         // Checking the number of items, that it is correct.
01332                         // If files, there MUST NOT be too many files in the list at this point, so check that prior to this code.
01333                 $valueArrayC = count($valueArray);
01334                 $minI = isset($tcaFieldConf['minitems']) ? intval($tcaFieldConf['minitems']):0;
01335 
01336                         // 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.
01337                 $maxI = isset($tcaFieldConf['maxitems']) ? intval($tcaFieldConf['maxitems']):1;
01338                 if ($valueArrayC > $maxI)       {$valueArrayC=$maxI;}   // Checking for not too many elements
01339 
01340                         // Dumping array to list
01341                 $newVal=array();
01342                 foreach($valueArray as $nextVal)        {
01343                         if ($valueArrayC==0)    {break;}
01344                         $valueArrayC--;
01345                         $newVal[]=$nextVal;
01346                 }
01347                 $res['value'] = implode(',',$newVal);
01348 
01349                 return $res;
01350         }
01351 
01366         function checkValue_group_select_file($valueArray,$tcaFieldConf,$curValue,$uploadedFileArray,$status,$table,$id,$recFID)        {
01367 
01368                         // If any files are uploaded:
01369                 if (is_array($uploadedFileArray) &&
01370                         $uploadedFileArray['name'] &&
01371                         strcmp($uploadedFileArray['tmp_name'],'none'))  {
01372                                 $valueArray[]=$uploadedFileArray['tmp_name'];
01373                                 $this->alternativeFileName[$uploadedFileArray['tmp_name']] = $uploadedFileArray['name'];
01374                 }
01375 
01376                         // Creating fileFunc object.
01377                 if (!$this->fileFunc)   {
01378                         $this->fileFunc = t3lib_div::makeInstance('t3lib_basicFileFunctions');
01379                         $this->include_filefunctions=1;
01380                 }
01381                         // Setting permitted extensions.
01382                 $all_files = Array();
01383                 $all_files['webspace']['allow'] = $tcaFieldConf['allowed'];
01384                 $all_files['webspace']['deny'] = $tcaFieldConf['disallowed'] ? $tcaFieldConf['disallowed'] : '*';
01385                 $all_files['ftpspace'] = $all_files['webspace'];
01386                 $this->fileFunc->init('', $all_files);
01387 
01388                         // If there is an upload folder defined:
01389                 if ($tcaFieldConf['uploadfolder'])      {
01390                                 // For logging..
01391                         $propArr = $this->getRecordProperties($table,$id);
01392 
01393                                 // Get destrination path:
01394                         $dest = $this->destPathFromUploadFolder($tcaFieldConf['uploadfolder']);
01395 
01396                                 // If we are updating:
01397                         if ($status=='update')  {
01398 
01399                                         // Traverse the input values and convert to absolute filenames in case the update happens to an autoVersionized record.
01400                                         // 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!
01401                                         // 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_.
01402                                         // 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.
01403                                         // Illustration of the problem comes here:
01404                                         // 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.
01405                                         // 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.
01406                                         // 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.
01407                                         // 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.
01408                                 if ($this->autoVersioningUpdate===TRUE) {
01409                                         foreach($valueArray as $key => $theFile)        {
01410                                                 if ($theFile===basename($theFile))      {
01411                                                         $valueArray[$key] = PATH_site.$tcaFieldConf['uploadfolder'].'/'.$theFile;
01412                                                 }
01413                                         }
01414                                 }
01415 
01416                                         // Finding the CURRENT files listed, either from MM or from the current record.
01417                                 $theFileValues=array();
01418                                 if ($tcaFieldConf['MM'])        {       // If MM relations for the files also!
01419                                         $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
01420                                         $dbAnalysis->start('','files',$tcaFieldConf['MM'],$id);
01421                                         reset($dbAnalysis->itemArray);
01422                                         while (list($somekey,$someval)=each($dbAnalysis->itemArray))    {
01423                                                 if ($someval['id'])     {
01424                                                         $theFileValues[]=$someval['id'];
01425                                                 }
01426                                         }
01427                                 } else {
01428                                         $theFileValues=t3lib_div::trimExplode(',',$curValue,1);
01429                                 }
01430 
01431                                         // DELETE files: If existing files were found, traverse those and register files for deletion which has been removed:
01432                                 if (count($theFileValues))      {
01433                                                 // 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!)
01434                                         foreach($valueArray as $key => $theFile)        {
01435                                                 if ($theFile && !strstr(t3lib_div::fixWindowsFilePath($theFile),'/'))   {
01436                                                         $theFileValues = t3lib_div::removeArrayEntryByValue($theFileValues,$theFile);
01437                                                 }
01438                                         }
01439 
01440                                                 // This array contains the filenames in the uploadfolder that should be deleted:
01441                                         foreach($theFileValues as $key => $theFile)     {
01442                                                 $theFile = trim($theFile);
01443                                                 if (@is_file($dest.'/'.$theFile))       {
01444                                                         $this->removeFilesStore[]=$dest.'/'.$theFile;
01445                                                 } elseif ($theFile) {
01446                                                         $this->log($table,$id,5,0,1,"Could not delete file '%s' (does not exist). (%s)",10,array($dest.'/'.$theFile, $recFID),$propArr['event_pid']);
01447                                                 }
01448                                         }
01449                                 }
01450                         }
01451 
01452                                 // Traverse the submitted values:
01453                         foreach($valueArray as $key => $theFile)        {
01454                                         // 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)
01455                                 if (strstr(t3lib_div::fixWindowsFilePath($theFile),'/'))        {
01456                                                 // Init:
01457                                         $maxSize = intval($tcaFieldConf['max_size']);
01458                                         $cmd='';
01459                                         $theDestFile='';                // Must be cleared. Else a faulty fileref may be inserted if the below code returns an error!! (Change: 22/12/2000)
01460 
01461                                                 // Check various things before copying file:
01462                                         if (@is_dir($dest) && (@is_file($theFile) || @is_uploaded_file($theFile)))      {               // File and destination must exist
01463 
01464                                                         // Finding size. For safe_mode we have to rely on the size in the upload array if the file is uploaded.
01465                                                 if (is_uploaded_file($theFile) && $theFile==$uploadedFileArray['tmp_name'])     {
01466                                                         $fileSize = $uploadedFileArray['size'];
01467                                                 } else {
01468                                                         $fileSize = filesize($theFile);
01469                                                 }
01470 
01471                                                 if (!$maxSize || $fileSize<=($maxSize*1024))    {       // Check file size:
01472                                                                 // Prepare filename:
01473                                                         $theEndFileName = isset($this->alternativeFileName[$theFile]) ? $this->alternativeFileName[$theFile] : $theFile;
01474                                                         $fI = t3lib_div::split_fileref($theEndFileName);
01475 
01476                                                                 // Check for allowed extension:
01477                                                         if ($this->fileFunc->checkIfAllowed($fI['fileext'], $dest, $theEndFileName)) {
01478                                                                 $theDestFile = $this->fileFunc->getUniqueName($this->fileFunc->cleanFileName($fI['file']), $dest);
01479 
01480                                                                         // If we have a unique destination filename, then write the file:
01481                                                                 if ($theDestFile)       {
01482                                                                         t3lib_div::upload_copy_move($theFile,$theDestFile);
01483                                                                         $this->copiedFileMap[$theFile] = $theDestFile;
01484                                                                         clearstatcache();
01485                                                                         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']);
01486                                                                 } 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']);
01487                                                         } else $this->log($table,$id,5,0,1,"Fileextension '%s' not allowed. (%s)",12,array($fI['fileext'], $recFID),$propArr['event_pid']);
01488                                                 } 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']);
01489                                         } 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']);
01490 
01491                                                 // If the destination file was created, we will set the new filename in the value array, otherwise unset the entry in the value array!
01492                                         if (@is_file($theDestFile))     {
01493                                                 $info = t3lib_div::split_fileref($theDestFile);
01494                                                 $valueArray[$key]=$info['file']; // The value is set to the new filename
01495                                         } else {
01496                                                 unset($valueArray[$key]);       // The value is set to the new filename
01497                                         }
01498                                 }
01499                         }
01500 
01501                                 // 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!
01502                         if ($tcaFieldConf['MM'])        {
01503                                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
01504                                 $dbAnalysis->tableArray['files']=array();       // dummy
01505 
01506                                 reset($valueArray);
01507                                 while (list($key,$theFile)=each($valueArray))   {
01508                                                 // explode files
01509                                                 $dbAnalysis->itemArray[]['id']=$theFile;
01510                                 }
01511                                 if ($status=='update')  {
01512                                         $dbAnalysis->writeMM($tcaFieldConf['MM'],$id,0);
01513                                 } else {
01514                                         $this->dbAnalysisStore[] = array($dbAnalysis, $tcaFieldConf['MM'], $id, 0);     // This will be traversed later to execute the actions
01515                                 }
01516                                 $cc=count($dbAnalysis->itemArray);
01517                                 $valueArray = array($cc);
01518                         }
01519                 }
01520 
01521                 return $valueArray;
01522         }
01523 
01536         function checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field)   {
01537                 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
01538 
01539                 if (is_array($value))   {
01540 
01541                                 // Get current value array:
01542                         $dataStructArray = t3lib_BEfunc::getFlexFormDS($tcaFieldConf,$this->checkValue_currentRecord,$table);
01543 #debug($this->checkValue_currentRecord);
01544                         $currentValueArray = t3lib_div::xml2array($curValue);
01545                         if (!is_array($currentValueArray))      $currentValueArray = array();
01546                         if (is_array($currentValueArray['meta']['currentLangId']))              unset($currentValueArray['meta']['currentLangId']);     // Remove all old meta for languages...
01547 
01548                                 // Evaluation of input values:
01549                         $value['data'] = $this->checkValue_flex_procInData($value['data'],$currentValueArray['data'],$uploadedFiles['data'],$dataStructArray,$PP);
01550 
01551                                 // Create XML and convert charsets from input value:
01552                         $xmlValue = $this->checkValue_flexArray2Xml($value,TRUE);
01553 
01554                                 // If we wanted to set UTF fixed:
01555                         // $storeInCharset='utf-8';
01556                         // $currentCharset=$GLOBALS['LANG']->charSet;
01557                         // $xmlValue = $GLOBALS['LANG']->csConvObj->conv($xmlValue,$currentCharset,$storeInCharset,1);
01558                         $storeInCharset=$GLOBALS['LANG']->charSet;
01559 
01560                                 // Merge them together IF they are both arrays:
01561                                 // 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).
01562                         if (is_array($currentValueArray))       {
01563                                 $arrValue = t3lib_div::xml2array($xmlValue);
01564                                 $arrValue = t3lib_div::array_merge_recursive_overrule($currentValueArray,$arrValue);
01565                                 $xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
01566                         }
01567 
01568                                 // Temporary fix to delete flex form elements:
01569                         $deleteCMDs = t3lib_div::_GP('_DELETE_FLEX_FORMdata');
01570                         if (is_array($deleteCMDs[$table][$id][$field]['data'])) {
01571                                 $arrValue = t3lib_div::xml2array($xmlValue);
01572                                 $this->_DELETE_FLEX_FORMdata($arrValue['data'],$deleteCMDs[$table][$id][$field]['data']);
01573                                 $xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
01574                         }
01575 
01576                                 // Temporary fix to move flex form elements up:
01577                         $moveCMDs = t3lib_div::_GP('_MOVEUP_FLEX_FORMdata');
01578                         if (is_array($moveCMDs[$table][$id][$field]['data']))   {
01579                                 $arrValue = t3lib_div::xml2array($xmlValue);
01580                                 $this->_MOVE_FLEX_FORMdata($arrValue['data'],$moveCMDs[$table][$id][$field]['data'], 'up');
01581                                 $xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
01582                         }
01583 
01584                                 // Temporary fix to move flex form elements down:
01585                         $moveCMDs = t3lib_div::_GP('_MOVEDOWN_FLEX_FORMdata');
01586                         if (is_array($moveCMDs[$table][$id][$field]['data']))   {
01587                                 $arrValue = t3lib_div::xml2array($xmlValue);
01588                                 $this->_MOVE_FLEX_FORMdata($arrValue['data'],$moveCMDs[$table][$id][$field]['data'], 'down');
01589                                 $xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
01590                         }
01591 
01592                                 // Create the value XML:
01593                         $res['value']='';
01594                         $res['value'].=$xmlValue;
01595                 } else {        // Passthrough...:
01596                         $res['value']=$value;
01597                 }
01598 
01599                 return $res;
01600         }
01601 
01609         function checkValue_flexArray2Xml($array, $addPrologue=FALSE)   {
01610                 $flexObj = t3lib_div::makeInstance('t3lib_flexformtools');
01611                 return $flexObj->flexArray2Xml($array, $addPrologue);
01612         }
01613 
01621         function _DELETE_FLEX_FORMdata(&$valueArrayToRemoveFrom,$deleteCMDS)    {
01622                 if (is_array($valueArrayToRemoveFrom) && is_array($deleteCMDS)) {
01623                         foreach($deleteCMDS as $key => $value)  {
01624                                 if (is_array($deleteCMDS[$key]))        {
01625                                         $this->_DELETE_FLEX_FORMdata($valueArrayToRemoveFrom[$key],$deleteCMDS[$key]);
01626                                 } else {
01627                                         unset($valueArrayToRemoveFrom[$key]);
01628                                 }
01629                         }
01630                 }
01631         }
01632 
01643         function _MOVE_FLEX_FORMdata(&$valueArrayToMoveIn, $moveCMDS, $direction)       {
01644                 if (is_array($valueArrayToMoveIn) && is_array($moveCMDS))       {
01645 
01646                                 // Only execute the first move command:
01647                         list ($key, $value) = each ($moveCMDS);
01648 
01649                         if (is_array($moveCMDS[$key]))  {
01650                                 $this->_MOVE_FLEX_FORMdata($valueArrayToMoveIn[$key],$moveCMDS[$key], $direction);
01651                         } else {
01652                                 switch ($direction) {
01653                                         case 'up':
01654                                                 if ($key > 1) {
01655                                                         $tmpArr = $valueArrayToMoveIn[$key];
01656                                                         $valueArrayToMoveIn[$key] = $valueArrayToMoveIn[$key-1];
01657                                                         $valueArrayToMoveIn[$key-1] = $tmpArr;
01658                                                 }
01659                                         break;
01660                                         case 'down':
01661                                                 if ($key < count($valueArrayToMoveIn)) {
01662                                                         $tmpArr = $valueArrayToMoveIn[$key];
01663                                                         $valueArrayToMoveIn[$key] = $valueArrayToMoveIn[$key+1];
01664                                                         $valueArrayToMoveIn[$key+1] = $tmpArr;
01665                                                 }
01666                                         break;
01667                                 }
01668                         }
01669                 }
01670         }
01671 
01672 
01673 
01674 
01675 
01676 
01677 
01678 
01679 
01680 
01681 
01682 
01683 
01684 
01685 
01686 
01687 
01688 
01689         /*********************************************
01690          *
01691          * Helper functions for evaluation functions.
01692          *
01693          ********************************************/
01694 
01705         function getUnique($table,$field,$value,$id,$newPid=0)  {
01706                 global $TCA;
01707 
01708                         // Initialize:
01709                 t3lib_div::loadTCA($table);
01710                 $whereAdd='';
01711                 $newValue='';
01712                 if (intval($newPid))    { $whereAdd.=' AND pid='.intval($newPid); } else { $whereAdd.=' AND pid>=0'; }  // "AND pid>=0" for versioning
01713                 $whereAdd.=$this->deleteClause($table);
01714 
01715                         // If the field is configured in TCA, proceed:
01716                 if (is_array($TCA[$table]) && is_array($TCA[$table]['columns'][$field]))        {
01717 
01718                                 // Look for a record which might already have the value:
01719                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, $field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($value, $table).' AND uid!='.intval($id).$whereAdd);
01720                         $counter = 0;
01721 
01722                                 // For as long as records with the test-value existing, try again (with incremented numbers appended).
01723                         while ($GLOBALS['TYPO3_DB']->sql_num_rows($res))        {
01724                                 $newValue = $value.$counter;
01725                                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, $field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($newValue, $table).' AND uid!='.intval($id).$whereAdd);
01726                                 $counter++;
01727                                 if ($counter>100)       { break; }      // At "100" it will give up and accept a duplicate - should probably be fixed to a small hash string instead...!
01728                         }
01729                                 // If the new value is there:
01730                         $value = strlen($newValue) ? $newValue : $value;
01731                 }
01732                 return $value;
01733         }
01734 
01743         function checkValue_input_Eval($value,$evalArray,$is_in)        {
01744                 $res = Array();
01745                 $newValue = $value;
01746                 $set = true;
01747 
01748                 foreach($evalArray as $func)    {
01749                         switch($func)   {
01750                                 case 'int':
01751                                 case 'year':
01752                                 case 'date':
01753                                 case 'datetime':
01754                                 case 'time':
01755                                 case 'timesec':
01756                                         $value = intval($value);
01757                                 break;
01758                                 case 'double2':
01759                                         $theDec = 0;
01760                                         for ($a=strlen($value); $a>0; $a--)     {
01761                                                 if (substr($value,$a-1,1)=='.' || substr($value,$a-1,1)==',')   {
01762                                                         $theDec = substr($value,$a);
01763                                                         $value = substr($value,0,$a-1);
01764                                                         break;
01765                                                 }
01766                                         }
01767                                         $theDec = ereg_replace('[^0-9]','',$theDec).'00';
01768                                         $value = intval(str_replace(' ','',$value)).'.'.substr($theDec,0,2);
01769                                 break;
01770                                 case 'md5':
01771                                         if (strlen($value)!=32){$set=false;}
01772                                 break;
01773                                 case 'trim':
01774                                         $value = trim($value);
01775                                 break;
01776                                 case 'upper':
01777                                         $value = strtoupper($value);
01778 #                                       $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.
01779                                 break;
01780                                 case 'lower':
01781                                         $value = strtolower($value);
01782 #                                       $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.
01783                                 break;
01784                                 case 'required':
01785                                         if (!$value)    {$set=0;}
01786                                 break;
01787                                 case 'is_in':
01788                                         $c=strlen($value);
01789                                         if ($c) {
01790                                                 $newVal = '';
01791                                                 for ($a=0;$a<$c;$a++)   {
01792                                                         $char = substr($value,$a,1);
01793                                                         if (strstr($is_in,$char))       {
01794                                                                 $newVal.=$char;
01795                                                         }
01796                                                 }
01797                                                 $value = $newVal;
01798                                         }
01799                                 break;
01800                                 case 'nospace':
01801                                         $value = str_replace(' ','',$value);
01802                                 break;
01803                                 case 'alpha':
01804                                         $value = ereg_replace('[^a-zA-Z]','',$value);
01805                                 break;
01806                                 case 'num':
01807                                         $value = ereg_replace('[^0-9]','',$value);
01808                                 break;
01809                                 case 'alphanum':
01810                                         $value = ereg_replace('[^a-zA-Z0-9]','',$value);
01811                                 break;
01812                                 case 'alphanum_x':
01813                                         $value = ereg_replace('[^a-zA-Z0-9_-]','',$value);
01814                                 break;
01815                                 default:
01816                                         if (substr($func, 0, 3) == 'tx_')       {
01817                                                 $evalObj = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func].':&'.$func);
01818                                                 if(is_object($evalObj) && method_exists($evalObj, 'evaluateFieldValue'))        {
01819                                                         $value = $evalObj->evaluateFieldValue($value, $is_in, $set);
01820                                                 }
01821                                         }
01822                                 break;
01823                         }
01824                 }
01825                 if ($set)       {$res['value'] = $value;}
01826                 return $res;
01827         }
01828 
01839         function checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,$type)     {
01840                 $tables = $type=='group'?$tcaFieldConf['allowed']:$tcaFieldConf['foreign_table'].','.$tcaFieldConf['neg_foreign_table'];
01841                 $prep = $type=='group'?$tcaFieldConf['prepend_tname']:$tcaFieldConf['neg_foreign_table'];
01842 
01843                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
01844                 $dbAnalysis->registerNonTableValues=$tcaFieldConf['allowNonIdValues'] ? 1 : 0;
01845                 $dbAnalysis->start(implode(',',$valueArray),$tables);
01846 
01847                 if ($tcaFieldConf['MM'])        {
01848                         if ($status=='update')  {
01849                                 $dbAnalysis->writeMM($tcaFieldConf['MM'],$id,$prep);
01850                         } else {
01851                                 $this->dbAnalysisStore[] = array($dbAnalysis,$tcaFieldConf['MM'],$id,$prep);    // This will be traversed later to execute the actions
01852                         }
01853                         $cc=count($dbAnalysis->itemArray);
01854                         $valueArray = array($cc);
01855                 } else {
01856                         $valueArray = $dbAnalysis->getValueArray($prep);
01857                         if ($type=='select' && $prep)   {
01858                                 $valueArray = $dbAnalysis->convertPosNeg($valueArray,$tcaFieldConf['foreign_table'],$tcaFieldConf['neg_foreign_table']);
01859                         }
01860                 }
01861 
01862                         // 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.
01863                 return $valueArray;
01864         }
01865 
01872         function checkValue_group_select_explodeSelectGroupValue($value)        {
01873                 $valueArray = t3lib_div::trimExplode(',',$value,1);
01874                 reset($valueArray);
01875                 while(list($key,$newVal)=each($valueArray))     {
01876                         $temp=explode('|',$newVal,2);
01877                         $valueArray[$key] = str_replace(',','',str_replace('|','',rawurldecode($temp[0])));
01878                 }
01879                 return $valueArray;
01880         }
01881 
01896         function checkValue_flex_procInData($dataPart,$dataPart_current,$uploadedFiles,$dataStructArray,$pParams,$callBackFunc='')      {
01897 #debug(array($dataPart,$dataPart_current,$dataStructArray));
01898                 if (is_array($dataPart))        {
01899                         foreach($dataPart as $sKey => $sheetDef)        {
01900                                 list ($dataStruct,$actualSheet) = t3lib_div::resolveSheetDefInDS($dataStructArray,$sKey);
01901 #debug(array($dataStruct,$actualSheet,$sheetDef,$actualSheet,$sKey));
01902                                 if (is_array($dataStruct) && $actualSheet==$sKey && is_array($sheetDef))        {
01903                                         foreach($sheetDef as $lKey => $lData)   {
01904                                                 $this->checkValue_flex_procInData_travDS(
01905                                                         $dataPart[$sKey][$lKey],
01906                                                         $dataPart_current[$sKey][$lKey],
01907                                                         $uploadedFiles[$sKey][$lKey],
01908                                                         $dataStruct['ROOT']['el'],
01909                                                         $pParams,
01910                                                         $callBackFunc,
01911                                                         $sKey.'/'.$lKey.'/'
01912                                                 );
01913                                         }
01914                                 }
01915                         }
01916                 }
01917 
01918                 return $dataPart;
01919         }
01920 
01935         function checkValue_flex_procInData_travDS(&$dataValues,$dataValues_current,$uploadedFiles,$DSelements,$pParams,$callBackFunc,$structurePath)   {
01936                 if (is_array($DSelements))      {
01937 
01938                                 // For each DS element:
01939                         foreach($DSelements as $key => $dsConf) {
01940 
01941                                                 // Array/Section:
01942                                 if ($DSelements[$key]['type']=='array') {
01943                                         if (is_array($dataValues[$key]['el']))  {
01944                                                 if ($DSelements[$key]['section'])       {
01945                                                         foreach($dataValues[$key]['el'] as $ik => $el)  {
01946                                                                 $theKey = key($el);
01947                                                                 if (is_array($dataValues[$key]['el'][$ik][$theKey]['el']))      {
01948                                                                         $this->checkValue_flex_procInData_travDS(
01949                                                                                         $dataValues[$key]['el'][$ik][$theKey]['el'],
01950                                                                                         $dataValues_current[$key]['el'][$ik][$theKey]['el'],
01951                                                                                         $uploadedFiles[$key]['el'][$ik][$theKey]['el'],
01952                                                                                         $DSelements[$key]['el'][$theKey]['el'],
01953                                                                                         $pParams,
01954                                                                                         $callBackFunc,
01955                                                                                         $structurePath.$key.'/el/'.$ik.'/'.$theKey.'/el/'
01956                                                                                 );
01957                                                                 }
01958                                                         }
01959                                                 } else {
01960                                                         if (!isset($dataValues[$key]['el']))    $dataValues[$key]['el']=array();
01961                                                         $this->checkValue_flex_procInData_travDS(
01962                                                                         $dataValues[$key]['el'],
01963                                                                         $dataValues_current[$key]['el'],
01964                                                                         $uploadedFiles[$key]['el'],
01965                                                                         $DSelements[$key]['el'],
01966                                                                         $pParams,
01967                                                                         $callBackFunc,
01968                                                                         $structurePath.$key.'/el/'
01969                                                                 );
01970                                                 }
01971                                         }
01972                                 } else {
01973                                         if (is_array($dsConf['TCEforms']['config']) && is_array($dataValues[$key]))     {
01974                                                 foreach($dataValues[$key] as $vKey => $data)    {
01975 
01976                                                         if ($callBackFunc)      {
01977                                                                 if (is_object($this->callBackObj))      {
01978                                                                         $res = $this->callBackObj->$callBackFunc(
01979                                                                                                 $pParams,
01980                                                                                                 $dsConf['TCEforms']['config'],
01981                                                                                                 $dataValues[$key][$vKey],
01982                                                                                                 $dataValues_current[$key][$vKey],
01983                                                                                                 $uploadedFiles[$key][$vKey],
01984                                                                                                 $structurePath.$key.'/'.$vKey.'/'
01985                                                                                         );
01986                                                                 } else {
01987                                                                         $res = $this->$callBackFunc(
01988                                                                                                 $pParams,
01989                                                                                                 $dsConf['TCEforms']['config'],
01990                                                                                                 $dataValues[$key][$vKey],
01991                                                                                                 $dataValues_current[$key][$vKey],
01992                                                                                                 $uploadedFiles[$key][$vKey]
01993                                                                                         );
01994                                                                 }
01995                                                         } else {        // Default
01996                                                                 list($CVtable,$CVid,$CVcurValue,$CVstatus,$CVrealPid,$CVrecFID,$CVtscPID) = $pParams;
01997 
01998                                                                 $res = $this->checkValue_SW(
01999                                                                                         array(),
02000                                                                                         $dataValues[$key][$vKey],
02001                                                                                         $dsConf['TCEforms']['config'],
02002                                                                                         $CVtable,
02003                                                                                         $CVid,
02004                                                                                         $dataValues_current[$key][$vKey],
02005                                                                                         $CVstatus,
02006                                                                                         $CVrealPid,
02007                                                                                         $CVrecFID,
02008                                                                                         '',
02009                                                                                         $uploadedFiles[$key][$vKey],
02010                                                                                         array(),
02011                                                                                         $CVtscPID
02012                                                                                 );
02013 
02014                                                                         // Look for RTE transformation of field:
02015                                                                 if ($dataValues[$key]['_TRANSFORM_'.$vKey] == 'RTE' && !$this->dontProcessTransformations)      {
02016 
02017                                                                                 // Unsetting trigger field - we absolutely don't want that into the data storage!
02018                                                                         unset($dataValues[$key]['_TRANSFORM_'.$vKey]);
02019 
02020                                                                         if (isset($res['value']))       {
02021 
02022                                                                                         // Calculating/Retrieving some values here:
02023                                                                                 list(,,$recFieldName) = explode(':', $CVrecFID);
02024                                                                                 $theTypeString = t3lib_BEfunc::getTCAtypeValue($CVtable,$this->checkValue_currentRecord);
02025                                                                                 $specConf = t3lib_BEfunc::getSpecConfParts('',$dsConf['TCEforms']['defaultExtras']);
02026 
02027                                                                                         // Find, thisConfig:
02028                                                                                 $RTEsetup = $this->BE_USER->getTSConfig('RTE',t3lib_BEfunc::getPagesTSconfig($CVtscPID));
02029                                                                                 $thisConfig = t3lib_BEfunc::RTEsetup($RTEsetup['properties'],$CVtable,$recFieldName,$theTypeString);
02030 
02031                                                                                         // Get RTE object, draw form and set flag:
02032                                                                                 $RTEobj = &t3lib_BEfunc::RTEgetObj();
02033                                                                                 if (is_object($RTEobj)) {
02034                                                                                         $res['value'] = $RTEobj->transformContent('db',$res['value'],$CVtable,$recFieldName,$this->checkValue_currentRecord,$specConf,$thisConfig,'',$CVrealPid);
02035                                                                                 } else {
02036                                                                                         debug('NO RTE OBJECT FOUND!');
02037                                                                                 }
02038                                                                         }
02039                                                                 }
02040                                                         }
02041 
02042                                                                 // Adding the value:
02043                                                         if (isset($res['value']))       {
02044                                                                 $dataValues[$key][$vKey] = $res['value'];
02045                                                         }
02046                                                 }
02047                                         }
02048                                 }
02049                         }
02050                 }
02051         }
02052 
02053 
02054 
02055 
02056 
02057 
02058 
02059 
02060 
02061 
02062 
02063 
02064 
02065 
02066 
02067 
02068 
02069         /*********************************************
02070          *
02071          * PROCESSING COMMANDS
02072          *
02073          ********************************************/
02074 
02081         function process_cmdmap() {
02082                 global $TCA, $TYPO3_CONF_VARS;
02083 
02084                         // Editing frozen:
02085                 if ($this->BE_USER->workspace!==0 && $this->BE_USER->workspaceRec['freeze'])    {
02086                         $this->newlog('All editing in this workspace has been frozen!',1);
02087                         return FALSE;
02088                 }
02089 
02090                         // Hook initialization:
02091                 $hookObjectsArr = array();
02092                 if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'])) {
02093                         foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'] as $classRef) {
02094                                 $hookObjectsArr[] = &t3lib_div::getUserObj($classRef);
02095                         }
02096                 }
02097 
02098                         // Traverse command map:
02099                 reset($this->cmdmap);
02100                 while(list($table,) = each($this->cmdmap))      {
02101 
02102                                 // Check if the table may be modified!
02103                         $modifyAccessList = $this->checkModifyAccessList($table);
02104                         if (!$modifyAccessList) {
02105                                 $id = 0;
02106                                 $this->log($table,$id,2,0,1,"Attempt to modify table '%s' without permission",1,array($table));
02107                         }       // FIXME: $id not set here (Comment added by Sebastian Kurfuerst)
02108 
02109                                 // Check basic permissions and circumstances:
02110                         if (isset($TCA[$table]) && !$this->tableReadOnly($table) && is_array($this->cmdmap[$table]) && $modifyAccessList)       {
02111 
02112                                         // Traverse the command map:
02113                                 foreach($this->cmdmap[$table] as $id => $incomingCmdArray)      {
02114                                         if (is_array($incomingCmdArray))        {       // have found a command.
02115 
02116                                                         // Get command and value (notice, only one command is observed at a time!):
02117                                                 reset($incomingCmdArray);
02118                                                 $command = key($incomingCmdArray);
02119                                                 $value = current($incomingCmdArray);
02120 
02121                                                 foreach($hookObjectsArr as $hookObj) {
02122                                                         if (method_exists($hookObj, 'processCmdmap_preProcess')) {
02123                                                                 $hookObj->processCmdmap_preProcess($command, $table, $id, $value, $this);
02124                                                         }
02125                                                 }
02126 
02127                                                         // Init copyMapping array:
02128                                                 $this->copyMappingArray = Array();              // Must clear this array before call from here to those functions: Contains mapping information between new and old id numbers.
02129 
02130                                                         // Branch, based on command
02131                                                 switch ($command)       {
02132                                                         case 'move':
02133                                                                 $this->moveRecord($table,$id,$value);
02134                                                         break;
02135                                                         case 'copy':
02136                                                                 if ($table === 'pages') {
02137                                                                         $this->copyPages($id,$value);
02138                                                                 } else {
02139                                                                         $this->copyRecord($table,$id,$value,1);
02140                                                                 }
02141                                                         break;
02142                                                         case 'localize':
02143                                                                 $this->localize($table,$id,$value);
02144                                                         break;
02145                                                         case 'version':
02146                                                                 switch ((string)$value['action'])       {
02147                                                                         case 'new':
02148                                                                                 $versionizeTree = t3lib_div::intInRange(!isset($value['treeLevels'])?-1:$value['treeLevels'],-1,100);
02149                                                                                 if ($table == 'pages' && $versionizeTree>=0)    {
02150                                                                                         $this->versionizePages($id,$value['label'],$versionizeTree);
02151                                                                                 } else {
02152                                                                                         $this->versionizeRecord($table,$id,$value['label']);
02153                                                                                 }
02154                                                                         break;
02155                                                                         case 'swap':
02156                                                                                 $this->version_swap($table,$id,$value['swapWith'],$value['swapIntoWS']);
02157                                                                         break;
02158                                                                         case 'clearWSID':
02159                                                                                 $this->version_clearWSID($table,$id);
02160                                                                         break;
02161                                                                         case 'setStage':
02162                                                                                 $idList = t3lib_div::trimExplode(',',$id,1);
02163                                                                                 foreach($idList as $id) {
02164                                                                                         $this->version_setStage($table,$id,$value['stageId'],$value['comment']?$value['comment']:$this->generalComment);
02165                                                                                 }
02166                                                                         break;
02167                                                                 }
02168                                                         break;
02169                                                         case 'delete':
02170                                                                 $this->deleteAction($table, $id);
02171                                                         break;
02172                                                         case 'undelete':
02173                                                                 $this->undeleteRecord($table, $id);
02174                                                         break;
02175                                                 }
02176 
02177                                                 foreach($hookObjectsArr as $hookObj) {
02178                                                         if (method_exists($hookObj, 'processCmdmap_postProcess')) {
02179                                                                 $hookObj->processCmdmap_postProcess($command, $table, $id, $value, $this);
02180                                                         }
02181                                                 }
02182 
02183                                                         // Merging the copy-array info together for remapping purposes.
02184                                                 $this->copyMappingArray_merged= t3lib_div::array_merge_recursive_overrule($this->copyMappingArray_merged,$this->copyMappingArray);
02185                                         }
02186                                 }
02187                         }
02188                 }
02189 
02190                         // Finally, before exit, check if there are ID references to remap. This might be the case if versioning or copying has taken place!
02191                 $this->remapListedDBRecords();
02192         }
02193 
02194 
02195 
02196 
02197 
02198 
02199 
02200 
02201 
02202 
02203 
02204         /*********************************************
02205          *
02206          * Cmd: Copying
02207          *
02208          ********************************************/
02209 
02221         function copyRecord($table,$uid,$destPid,$first=0,$overrideValues=array(),$excludeFields='')    {
02222                 global $TCA;
02223 
02224                 $uid = $origUid = intval($uid);
02225                 if ($TCA[$table] && $uid)       {
02226                         t3lib_div::loadTCA($table);
02227 /*
02228                                 // 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)
02229                         if ($lookForLiveVersion = t3lib_BEfunc::getLiveVersionOfRecord($table,$uid,'uid'))      {
02230                                 $uid = $lookForLiveVersion['uid'];
02231                         }
02232                                 // Get workspace version of the source record, if any: Then we will copy workspace version instead:
02233                         if ($WSversion = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, $table, $uid, 'uid,t3ver_oid'))   {
02234                                 $uid = $WSversion['uid'];
02235                         }
02236                                 // 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.
02237 */
02238                         if ($this->doesRecordExist($table,$uid,'show')) {               // This checks if the record can be selected which is all that a copy action requires.
02239                                 $data = Array();
02240 
02241                                 $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));
02242 
02243                                 #$row = $this->recordInfo($table,$uid,'*');
02244                                 $row = t3lib_BEfunc::getRecordWSOL($table,$uid);        // So it copies (and localized) content from workspace...
02245                                 if (is_array($row))     {
02246 
02247                                                 // Initializing:
02248                                         $theNewID = uniqid('NEW');
02249                                         $enableField = isset($TCA[$table]['ctrl']['enablecolumns']) ? $TCA[$table]['ctrl']['enablecolumns']['disabled'] : '';
02250                                         $headerField = $TCA[$table]['ctrl']['label'];
02251 
02252                                                 // Getting default data:
02253                                         $defaultData = $this->newFieldArray($table);
02254 
02255                                                 // Getting "copy-after" fields if applicable:
02256                                                 // 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.
02257                                         $copyAfterFields = $destPid<0 ? $this->fixCopyAfterDuplFields($table,$uid,abs($destPid),0) : array();
02258 
02259                                                 // Page TSconfig related:
02260                                         $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...
02261                                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
02262                                         $tE = $this->getTableEntries($table,$TSConfig);
02263 
02264                                                 // Traverse ALL fields of the selected record:
02265                                         foreach($row as $field => $value)       {
02266                                                 if (!in_array($field,$nonFields))       {
02267 
02268                                                                 // Get TCA configuration for the field:
02269                                                         $conf = $TCA[$table]['columns'][$field]['config'];
02270 
02271                                                                 // Preparation/Processing of the value:
02272                                                         if ($field=='pid')      {       // "pid" is hardcoded of course:
02273                                                                 $value = $destPid;
02274                                                         } elseif (isset($overrideValues[$field]))       {       // Override value...
02275                                                                 $value = $overrideValues[$field];
02276                                                         } elseif (isset($copyAfterFields[$field]))      {       // Copy-after value if available:
02277                                                                 $value = $copyAfterFields[$field];
02278                                                         } elseif ($TCA[$table]['ctrl']['setToDefaultOnCopy'] && t3lib_div::inList($TCA[$table]['ctrl']['setToDefaultOnCopy'],$field))   {       // Revert to default for some fields:
02279                                                                 $value = $defaultData[$field];
02280                                                         } else {
02281                                                                         // Hide at copy may override:
02282                                                                 if ($first && $field==$enableField && $TCA[$table]['ctrl']['hideAtCopy'] && !$this->neverHideAtCopy && !$tE['disableHideAtCopy'])       {
02283                                                                         $value=1;
02284                                                                 }
02285                                                                         // Prepend label on copy:
02286                                                                 if ($first && $field==$headerField && $TCA[$table]['ctrl']['prependAtCopy'] && !$tE['disablePrependAtCopy'])    {
02287                                                                         $value = $this->getCopyHeader($table,$this->resolvePid($table,$destPid),$field,$this->clearPrefixFromValue($table,$value),0);
02288                                                                 }
02289                                                                         // Processing based on the TCA config field type (files, references, flexforms...)
02290                                                                 $value = $this->copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf);
02291                                                         }
02292 
02293                                                                 // Add value to array.
02294                                                         $data[$table][$theNewID][$field] = $value;
02295                                                 }
02296                                         }
02297 
02298                                                 // Overriding values:
02299                                         if ($TCA[$table]['ctrl']['editlock'])   {
02300                                                 $data[$table][$theNewID][$TCA[$table]['ctrl']['editlock']] = 0;
02301                                         }
02302 
02303                                                 // Setting original UID:
02304                                         if ($TCA[$table]['ctrl']['origUid'])    {
02305                                                 $data[$table][$theNewID][$TCA[$table]['ctrl']['origUid']] = $uid;
02306                                         }
02307 
02308                                                 // Do the copy by simply submitting the array through TCEmain:
02309                                         $copyTCE = t3lib_div::makeInstance('t3lib_TCEmain');
02310                                         $copyTCE->stripslashes_values = 0;
02311                                         $copyTCE->copyTree = $this->copyTree;
02312                                         $copyTCE->cachedTSconfig = $this->cachedTSconfig;       // Copy forth the cached TSconfig
02313                                         $copyTCE->dontProcessTransformations=1;         // Transformations should NOT be carried out during copy
02314 
02315                                         $copyTCE->start($data,'',$this->BE_USER);
02316                                         $copyTCE->process_datamap();
02317 
02318                                                 // Getting the new UID:
02319                                         $theNewSQLID = $copyTCE->substNEWwithIDs[$theNewID];
02320                                         if ($theNewSQLID)       {
02321                                                 $this->copyMappingArray[$table][$origUid] = $theNewSQLID;
02322                                         }
02323 
02324                                                 // Copy back the cached TSconfig
02325                                         $this->cachedTSconfig = $copyTCE->cachedTSconfig;
02326                                         $this->errorLog = array_merge($this->errorLog,$copyTCE->errorLog);
02327                                         unset($copyTCE);
02328 
02329                                         return $theNewSQLID;
02330                                 } else $this->log($table,$uid,3,0,1,'Attempt to copy record that did not exist!');
02331                         } else $this->log($table,$uid,3,0,1,'Attempt to copy record without permission');
02332                 }
02333         }
02334 
02343         function copyPages($uid,$destPid)       {
02344 
02345                         // Initialize:
02346                 $uid = intval($uid);
02347                 $destPid = intval($destPid);
02348 
02349                         // Finding list of tables to copy.
02350                 $copyTablesArray = $this->admin ? $this->compileAdminTables() : explode(',',$this->BE_USER->groupData['tables_modify']);        // These are the tables, the user may modify
02351                 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
02352                         foreach($copyTablesArray as $k => $table)       {
02353                                 if (!$table || !t3lib_div::inList($this->copyWhichTables.',pages',$table))      {       // pages are always going...
02354                                         unset($copyTablesArray[$k]);
02355                                 }
02356                         }
02357                 }
02358                 $copyTablesArray = array_unique($copyTablesArray);
02359 
02360                         // Begin to copy pages if we're allowed to:
02361                 if ($this->admin || in_array('pages',$copyTablesArray)) {
02362 
02363                                 // Copy this page we're on. And set first-flag (this will trigger that the record is hidden if that is configured)!
02364                         $theNewRootID = $this->copySpecificPage($uid,$destPid,$copyTablesArray,1);
02365 
02366                                 // If we're going to copy recursively...:
02367                         if ($theNewRootID && $this->copyTree)   {
02368 
02369                                         // Get ALL subpages to copy (read-permissions are respected!):
02370                                 $CPtable = $this->int_pageTreeInfo(Array(), $uid, intval($this->copyTree), $theNewRootID);
02371 
02372                                         // Now copying the subpages:
02373                                 foreach($CPtable as $thePageUid => $thePagePid) {
02374                                         $newPid = $this->copyMappingArray['pages'][$thePagePid];
02375                                         if (isset($newPid))     {
02376                                                 $this->copySpecificPage($thePageUid,$newPid,$copyTablesArray);
02377                                         } else {
02378                                                 $this->log('pages',$uid,5,0,1,'Something went wrong during copying branch');
02379                                                 break;
02380                                         }
02381                                 }
02382                         }       // else the page was not copied. Too bad...
02383                 } else {
02384                         $this->log('pages',$uid,5,0,1,'Attempt to copy page without permission to this table');
02385                 }
02386         }
02387 
02397         function copySpecificPage($uid,$destPid,$copyTablesArray,$first=0)      {
02398                 global $TCA;
02399 
02400                         // Copy the page itself:
02401                 $theNewRootID = $this->copyRecord('pages',$uid,$destPid,$first);
02402 
02403                         // If a new page was created upon the copy operation we will proceed with all the tables ON that page:
02404                 if ($theNewRootID)      {
02405                         foreach($copyTablesArray as $table)     {
02406                                 if ($table && is_array($TCA[$table]) && $table!='pages')        {       // all records under the page is copied.
02407                                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($uid).$this->deleteClause($table), '', ($TCA[$table]['ctrl']['sortby'] ? $TCA[$table]['ctrl']['sortby'].' DESC' : ''));
02408                                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))     {
02409                                                 $this->copyRecord($table,$row['uid'], $theNewRootID);   // Copying each of the underlying records...
02410                                         }
02411                                 }
02412                         }
02413                         return $theNewRootID;
02414                 }
02415         }
02416 
02431         function copyRecord_raw($table,$uid,$pid,$overrideArray=array())        {
02432                 global $TCA;
02433 
02434                 $uid = intval($uid);
02435                 if ($TCA[$table] && $uid)       {
02436                         t3lib_div::loadTCA($table);
02437                         if ($this->doesRecordExist($table,$uid,'show')) {
02438 
02439                                         // Set up fields which should not be processed. They are still written - just passed through no-questions-asked!
02440                                 $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');
02441 
02442                                         // Select main record:
02443                                 $row = $this->recordInfo($table,$uid,'*');
02444                                 if (is_array($row))     {
02445 
02446                                                 // Merge in override array.
02447                                         $row = array_merge($row,$overrideArray);
02448 
02449                                                 // Traverse ALL fields of the selected record:
02450                                         foreach($row as $field => $value)       {
02451                                                 if (!in_array($field,$nonFields))       {
02452 
02453                                                                 // Get TCA configuration for the field:
02454                                                         $conf = $TCA[$table]['columns'][$field]['config'];
02455                                                         if (is_array($conf))    {
02456                                                                         // Processing based on the TCA config field type (files, references, flexforms...)
02457                                                                 $value = $this->copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf);
02458                                                         }
02459 
02460                                                                 // Add value to array.
02461                                                         $row[$field] = $value;
02462                                                 }
02463                                         }
02464 
02465                                                 // Force versioning related fields:
02466                                         $row['pid'] = $pid;
02467 
02468                                                 // Setting original UID:
02469                                         if ($TCA[$table]['ctrl']['origUid'])    {
02470                                                 $row[$TCA[$table]['ctrl']['origUid']] = $uid;
02471                                         }
02472 
02473                                                 // Do the copy by internal function
02474                                         $theNewSQLID = $this->insertNewCopyVersion($table,$row,$pid);
02475                                         if ($theNewSQLID)       {
02476                                                 $this->dbAnalysisStoreExec();
02477                                                 $this->dbAnalysisStore = array();
02478                                                 return $this->copyMappingArray[$table][$uid] = $theNewSQLID;
02479                                         }
02480                                 } else $this->log($table,$uid,3,0,1,'Attempt to rawcopy/versionize record that did not exist!');
02481                         } else $this->log($table,$uid,3,0,1,'Attempt to rawcopy/versionize record without copy permission');
02482                 }
02483         }
02484 
02495         function rawCopyPageContent($old_pid,$new_pid,$copyTablesArray) {
02496                 global $TCA;
02497 
02498                 if ($new_pid)   {
02499                         foreach($copyTablesArray as $table)     {
02500                                 if ($table && is_array($TCA[$table]) && $table!='pages')        {       // all records under the page is copied.
02501                                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($old_pid).$this->deleteClause($table));
02502                                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))     {
02503                                                 $this->copyRecord_raw($table,$row['uid'],$new_pid);     // Copying each of the underlying records (method RAW)
02504                                         }
02505                                 }
02506                         }
02507                 }
02508         }
02509 
02519         function insertNewCopyVersion($table,$fieldArray,$realPid)      {
02520                 global $TCA;
02521 
02522                 $id = uniqid('NEW');
02523 
02524                         // $fieldArray is set as current record.
02525                         // 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...
02526                 $this->checkValue_currentRecord = $fieldArray;
02527 
02528                         // Traverse record and input-process each value:
02529                 foreach($fieldArray as $field => $fieldValue)   {
02530                         if (isset($TCA[$table]['columns'][$field]))     {
02531                                         // Evaluating the value.
02532                                 $res = $this->checkValue($table,$field,$fieldValue,$id,'new',$realPid,0);
02533                                 if (isset($res['value']))       {
02534                                         $fieldArray[$field] = $res['value'];
02535                                 }
02536                         }
02537                 }
02538 
02539                         // System fields being set:
02540                 if ($TCA[$table]['ctrl']['crdate'])     {
02541                         $fieldArray[$TCA[$table]['ctrl']['crdate']]=time();
02542                 }
02543                 if ($TCA[$table]['ctrl']['cruser_id'])  {
02544                         $fieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid;
02545                 }
02546                 if ($TCA[$table]['ctrl']['tstamp'])     {
02547                         $fieldArray[$TCA[$table]['ctrl']['tstamp']]=time();
02548                 }
02549 
02550                         // Finally, insert record:
02551                 $this->insertDB($table,$id,$fieldArray, TRUE);
02552 
02553                         // Return new id:
02554                 return $this->substNEWwithIDs[$id];
02555         }
02556 
02570         function copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf)  {
02571                 global $TCA;
02572 
02573                         // 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)
02574                 $value = $this->copyRecord_procFilesRefs($conf, $uid, $value);
02575 
02576 
02577                         // Register if there are references to take care of (no change to value):
02578                 if ($this->isReferenceField($conf))     {
02579                         $allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table'];
02580                         $prependName = $conf['type']=='group' ? $conf['prepend_tname'] : $conf['neg_foreign_table'];
02581                         if ($conf['MM'])        {
02582                                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
02583                                 $dbAnalysis->start('',$allowedTables,$conf['MM'],$uid);
02584                                 $value = implode(',',$dbAnalysis->getValueArray($prependName));
02585                         }
02586                         if ($value)     {       // Setting the value in this array will notify the remapListedDBRecords() function that this field MAY need references to be corrected
02587                                 $this->registerDBList[$table][$uid][$field] = $value;
02588                         }
02589                 }
02590 
02591                         // 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())
02592                 if ($conf['type']=='flex')      {
02593 
02594                                 // Get current value array:
02595                         $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $row, $table);
02596                         $currentValueArray = t3lib_div::xml2array($value);
02597 
02598                                 // Traversing the XML structure, processing files:
02599                         if (is_array($currentValueArray))       {
02600                                 $currentValueArray['data'] = $this->checkValue_flex_procInData(
02601                                                         $currentValueArray['data'],
02602                                                         array(),        // Not used.
02603                                                         array(),        // Not used.
02604                                                         $dataStructArray,
02605                                                         array($table,$uid,$field),      // Parameters.
02606                                                         'copyRecord_flexFormCallBack'
02607                                                 );
02608                                 $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.
02609                         }
02610                 }
02611 
02612                 return $value;
02613         }
02614 
02626         function copyRecord_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2)   {
02627 
02628                         // Extract parameters:
02629                 list($table, $uid, $field) = $pParams;
02630 
02631                         // Process references and files, currently that means only the files, prepending absolute paths:
02632                 $dataValue = $this->copyRecord_procFilesRefs($dsConf, $uid, $dataValue);
02633 
02634                         // If references are set for this field, set flag so they can be corrected later (in ->remapListedDBRecords())
02635                 if ($this->isReferenceField($dsConf) && strlen($dataValue)) {
02636                         $this->registerDBList[$table][$uid][$field] = 'FlexForm_reference';
02637                 }
02638 
02639                         // Return
02640                 return array('value' => $dataValue);
02641         }
02642 
02654         function copyRecord_procFilesRefs($conf, $uid, $value)  {
02655 
02656                         // Prepend absolute paths to files:
02657                 if ($conf['type']=='group' && $conf['internal_type']=='file')   {
02658 
02659                                 // Get an array with files as values:
02660                         if ($conf['MM'])        {
02661                                 $theFileValues = array();
02662 
02663                                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
02664                                 $dbAnalysis->start('', 'files', $conf['MM'], $uid);
02665 
02666                                 foreach($dbAnalysis->itemArray as $somekey => $someval) {
02667                                         if ($someval['id'])     {
02668                                                 $theFileValues[] = $someval['id'];
02669                                         }
02670                                 }
02671                         } else {
02672                                 $theFileValues = t3lib_div::trimExplode(',',$value,1);
02673                         }
02674 
02675                                 // Traverse this array of files:
02676                         $uploadFolder = $conf['uploadfolder'];
02677                         $dest = $this->destPathFromUploadFolder($uploadFolder);
02678                         $newValue = array();
02679 
02680                         foreach($theFileValues as $file)        {
02681                                 if (trim($file))        {
02682                                         $realFile = $dest.'/'.trim($file);
02683                                         if (@is_file($realFile))        {
02684                                                 $newValue[] = $realFile;
02685                                         }
02686                                 }
02687                         }
02688 
02689                                 // 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...)
02690                         $value = implode(',',$newValue);
02691                 }
02692 
02693                         // Return the new value:
02694                 return $value;
02695         }
02696 
02697 
02698 
02699 
02700 
02701 
02702 
02703 
02704 
02705 
02706 
02707 
02708 
02709         /*********************************************
02710          *
02711          * Cmd: Moving, Localizing
02712          *
02713          ********************************************/
02714 
02723         function moveRecord($table,$uid,$destPid)       {
02724                 global $TCA, $TYPO3_CONF_VARS;
02725 
02726                 if ($TCA[$table])       {
02727 
02728                                 // Prepare user defined objects (if any) for hooks which extend this function:
02729                         $hookObjectsArr = array();
02730                         if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['moveRecordClass'])) {
02731                                 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['moveRecordClass'] as $classRef) {
02732                                         $hookObjectsArr[] = &t3lib_div::getUserObj($classRef);
02733                                 }
02734                         }
02735 
02736                                 // 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)
02737                         if ($lookForLiveVersion = t3lib_BEfunc::getLiveVersionOfRecord($table,$uid,'uid'))      {
02738                                 $uid = $lookForLiveVersion['uid'];
02739                         }
02740 
02741                                 // Get workspace version of the source record, if any:
02742                         $WSversion = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, $table, $uid, 'uid,t3ver_oid');
02743 
02744                                 // Initialize:
02745                         $sortRow = $TCA[$table]['ctrl']['sortby'];
02746                         $destPid = intval($destPid);
02747                         $origDestPid = $destPid;
02748 
02749                         $propArr = $this->getRecordProperties($table,$uid);     // Get this before we change the pid (for logging)
02750                         $moveRec = $this->getRecordProperties($table,$uid,TRUE);
02751                         $resolvedPid = $this->resolvePid($table,$destPid);      // This is the actual pid of the moving to destination
02752 
02753                                 // 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.
02754                                 // 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.
02755                         if ($table!='pages' || $resolvedPid==$moveRec['pid'])   {
02756                                 $mayMoveAccess = $this->checkRecordUpdateAccess($table,$uid);   // Edit rights for the record...
02757                         } else {
02758                                 $mayMoveAccess = $this->doesRecordExist($table,$uid,'delete');
02759                         }
02760 
02761                                 // 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
02762                         if ($table!='pages' || $resolvedPid!=$moveRec['pid'])   {
02763                                 $mayInsertAccess = $this->checkRecordInsertAccess($table,$resolvedPid,4);       // Insert rights for the record...
02764                         } else {
02765                                 $mayInsertAccess = $this->checkRecordUpdateAccess($table,$uid);
02766                         }
02767 
02768                                 // Check workspace permissions:
02769                         $workspaceAccessBlocked = array();
02770                         $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...
02771                         $destRes = $this->BE_USER->workspaceAllowLiveRecordsInPID($resolvedPid,$table);
02772                                 // Workspace source check:
02773                         if ($errorCode = $this->BE_USER->workspaceCannotEditRecord($table, $WSversion['uid'] ? $WSversion['uid'] : $uid))       {
02774                                 $workspaceAccessBlocked['src1']='Record could not be edited in workspace: '.$errorCode.' ';
02775                         } else {
02776                                 if (!$recIsNewVersion && $this->BE_USER->workspaceAllowLiveRecordsInPID($moveRec['pid'],$table)<=0)     {
02777                                         $workspaceAccessBlocked['src2']='Could not remove record from table "'.$table.'" from its page "'.$moveRec['pid'].'" ';
02778                                 }
02779                         }
02780                                 // Workspace destination check:
02781                         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.
02782                                 $workspaceAccessBlocked['dest1']='Could not insert record from table "'.$table.'" in destination PID "'.$resolvedPid.'" ';
02783                         } elseif ($destRes==1 && $WSversion['uid'])     {
02784                                 $workspaceAccessBlocked['dest2']='Could not insert other versions in destination PID ';
02785                         }
02786 
02787                                 // 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...)
02788                         if (($destPid<0 && !$sortRow) || $destPid>=0)   {       // $destPid>=0 because we must correct pid in case of versioning "page" types.
02789                                 $destPid = $resolvedPid;
02790                         }
02791 
02792                                 // Timestamp field:
02793                         $updateFields = array();
02794                         if ($TCA[$table]['ctrl']['tstamp'])     {
02795                                 $updateFields[$TCA[$table]['ctrl']['tstamp']] = time();
02796                         }
02797 
02798                                         // If moving is allowed, begin the processing:
02799                         if (!count($workspaceAccessBlocked))    {
02800                                 if ($mayMoveAccess)     {
02801                                         if ($destPid>=0)        {       // insert as first element on page (where uid = $destPid)
02802                                                 if ($mayInsertAccess)   {
02803                                                         if ($table!='pages' || $this->destNotInsideSelf($destPid,$uid)) {
02804                                                                 $this->clear_cache($table,$uid);        // clear cache before moving
02805 
02806                                                                 $updateFields['pid'] = $destPid;        // Setting PID
02807 
02808                                                                         // table is sorted by 'sortby'
02809                                                                 if ($sortRow)   {
02810                                                                         $sortNumber = $this->getSortNumber($table,$uid,$destPid);
02811                                                                         $updateFields[$sortRow] = $sortNumber;
02812                                                                 }
02813                                                                         // Create query for update:
02814                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields);
02815 
02816                                                                         // Call post processing hooks:
02817                                                                 foreach($hookObjectsArr as $hookObj) {
02818                                                                         if (method_exists($hookObj, 'moveRecord_firstElementPostProcess')) {
02819                                                                                 $hookObj->moveRecord_firstElementPostProcess($table, $uid, $destPid, $moveRec, $updateFields, $this);
02820                                                                         }
02821                                                                 }
02822 
02823                                                                         // Logging...
02824                                                                 $newPropArr = $this->getRecordProperties($table,$uid);
02825                                                                 $oldpagePropArr = $this->getRecordProperties('pages',$propArr['pid']);
02826                                                                 $newpagePropArr = $this->getRecordProperties('pages',$destPid);
02827 
02828                                                                 if ($destPid!=$propArr['pid'])  {
02829                                                                         $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
02830                                                                         $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
02831                                                                 } else {
02832                                                                         $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
02833                                                                 }
02834                                                                 $this->clear_cache($table,$uid);        // clear cache after moving
02835                                                                 $this->fixUniqueInPid($table,$uid);
02836                                                                         // fixCopyAfterDuplFields
02837                                                                 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.
02838                                                         } else {
02839                                                                 $destPropArr = $this->getRecordProperties('pages',$destPid);
02840                                                                 $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']);
02841                                                         }
02842                                                 }
02843                                         } else {        // Put after another record
02844                                                 if ($sortRow)   {       // table is being sorted
02845                                                         $sortInfo = $this->getSortNumber($table,$uid,$destPid);
02846                                                         $destPid = $sortInfo['pid'];    // Setting the destPid to the new pid of the record.
02847                                                         if (is_array($sortInfo))        {       // If not an array, there was an error (which is already logged)
02848                                                                 if ($mayInsertAccess)   {
02849                                                                         if ($table!='pages' || $this->destNotInsideSelf($destPid,$uid)) {
02850                                                                                 $this->clear_cache($table,$uid);        // clear cache before moving
02851 
02852                                                                                         // We now update the pid and sortnumber
02853                                                                                 $updateFields['pid'] = $destPid;
02854                                                                                 $updateFields[$sortRow] = $sortInfo['sortNumber'];
02855                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields);
02856 
02857                                                                                         // Call post processing hooks:
02858                                                                                 foreach($hookObjectsArr as $hookObj) {
02859                                                                                         if (method_exists($hookObj, 'moveRecord_afterAnotherElementPostProcess')) {
02860                                                                                                 $hookObj->moveRecord_afterAnotherElementPostProcess($table, $uid, $destPid, $origDestPid, $moveRec, $updateFields, $this);
02861                                                                                         }
02862                                                                                 }
02863 
02864                                                                                         // Logging...
02865                                                                                 $newPropArr = $this->getRecordProperties($table,$uid);
02866                                                                                 $oldpagePropArr = $this->getRecordProperties('pages',$propArr['pid']);
02867                                                                                 if ($destPid!=$propArr['pid'])  {
02868                                                                                         $newpagePropArr = $this->getRecordProperties('pages',$destPid);
02869                                                                                         $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
02870                                                                                         $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
02871                                                                                 } else {
02872                                                                                         $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
02873                                                                                 }
02874 
02875                                                                                         // clear cache after moving
02876                                                                                 $this->clear_cache($table,$uid);
02877 
02878                                                                                         // fixUniqueInPid
02879                                                                                 $this->fixUniqueInPid($table,$uid);
02880 
02881                                                                                         // fixCopyAfterDuplFields
02882                                                                                 if ($origDestPid<0)     {$this->fixCopyAfterDuplFields($table,$uid,abs($origDestPid),1);}
02883                                                                         } else {
02884                                                                                 $destPropArr = $this->getRecordProperties('pages',$destPid);
02885                                                                                 $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']);
02886                                                                         }
02887                                                                 }
02888                                                         }
02889                                                 } else {
02890                                                         $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']);
02891                                                 }
02892                                         }
02893                                 } else {
02894                                         $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']);
02895                                 }
02896                         } else {
02897                                 $this->newlog("Move attempt failed due to workspace restrictions: ".implode(' ',$workspaceAccessBlocked),1);
02898                         }
02899                 }
02900         }
02901 
02910         function localize($table,$uid,$language)        {
02911                 global $TCA;
02912 
02913                 $uid = intval($uid);
02914 
02915                 if ($TCA[$table] && $uid)       {
02916                         t3lib_div::loadTCA($table);
02917 
02918                         if ($TCA[$table]['ctrl']['languageField'] && $TCA[$table]['ctrl']['transOrigPointerField'])     {
02919                                 if ($langRec = t3lib_BEfunc::getRecord('sys_language',intval($language),'uid,title'))   {
02920                                         if ($this->doesRecordExist($table,$uid,'show')) {
02921 
02922                                                 $row = t3lib_BEfunc::getRecordWSOL($table,$uid);        // Getting workspace overlay if possible - this will localize versions in workspace if any
02923                                                 if (is_array($row))     {
02924                                                         if ($row[$TCA[$table]['ctrl']['languageField']] <= 0)   {
02925                                                                 if ($row[$TCA[$table]['ctrl']['transOrigPointerField']] == 0)   {
02926                                                                         if (!t3lib_BEfunc::getRecordsByField($table,$TCA[$table]['ctrl']['transOrigPointerField'],$uid,'AND pid='.intval($row['pid']).' AND '.$TCA[$table]['ctrl']['languageField'].'='.intval($langRec['uid'])))       {
02927 
02928                                                                                         // Initialize:
02929                                                                                 $overrideValues = array();
02930                                                                                 $excludeFields = array();
02931 
02932                                                                                         // Set override values:
02933                                                                                 $overrideValues[$TCA[$table]['ctrl']['languageField']] = $langRec['uid'];
02934                                                                                 $overrideValues[$TCA[$table]['ctrl']['transOrigPointerField']] = $uid;
02935 
02936                                                                                         // Set exclude Fields:
02937                                                                                 foreach($TCA[$table]['columns'] as $fN => $fCfg)        {
02938                                                                                         if ($fCfg['l10n_mode']=='prefixLangTitle')      {       // Check if we are just prefixing:
02939                                                                                                 if (($fCfg['config']['type']=='text' || $fCfg['config']['type']=='input') && strlen($row[$fN])) {
02940                                                                                                         list($tscPID) = t3lib_BEfunc::getTSCpid($table,$uid,'');
02941                                                                                                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
02942 
02943                                                                                                         if (isset($TSConfig['translateToMessage']) && strlen($TSConfig['translateToMessage']))  {
02944                                                                                                                 $translateToMsg = @sprintf($TSConfig['translateToMessage'], $langRec['title']);
02945                                                                                                         }
02946                                                                                                         if (!strlen($translateToMsg))   {
02947                                                                                                                 $translateToMsg = 'Translate to '.$langRec['title'].':';
02948                                                                                                         }
02949 
02950                                                                                                         $overrideValues[$fN] = '['.$translateToMsg.'] '.$row[$fN];
02951                                                                                                 }
02952                                                                                         } 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)
02953                                                                                                 $excludeFields[] = $fN;
02954                                                                                         }
02955                                                                                 }
02956                                                                                         // Execute the copy:
02957                                                                                 $this->copyRecord($table,$uid,-$uid,1,$overrideValues,implode(',',$excludeFields));
02958                                                                         } else $this->newlog('Localization failed; There already was a localization for this language of the record!',1);
02959                                                                 } else $this->newlog('Localization failed; Source record contained a reference to an original default record (which is strange)!',1);
02960                                                         } else $this->newlog('Localization failed; Source record had another language than "Default" or "All" defined!',1);
02961                                                 } else $this->newlog('Attempt to localize record that did not exist!',1);
02962                                         } else $this->newlog('Attempt to localize record without permission',1);
02963                                 } else $this->newlog('Sys language UID "'.$language.'" not found valid!',1);
02964                         } else $this->newlog('Localization failed; "languageField" and "transOrigPointerField" must be defined for the table!',1);
02965                 }
02966         }
02967 
02968 
02969 
02970 
02971 
02972 
02973 
02974 
02975 
02976 
02977 
02978 
02979 
02980 
02981         /*********************************************
02982          *
02983          * Cmd: Deleting
02984          *
02985          ********************************************/
02986 
02994         function deleteAction($table, $id)      {
02995                 global $TCA;
02996 
02997                 $delRec = t3lib_BEfunc::getRecord($table, $id);
02998 
02999                 if (is_array($delRec))  {       // Record asked to be deleted was found:
03000 
03001                                 // For Live version, try if there is a workspace version because if so, rather "delete" that instead
03002                         if ($delRec['pid']!=-1) {       // Look, if record is an offline version, then delete directly:
03003                                 if ($wsVersion = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, $table, $id))     {
03004                                         $delRec = $wsVersion;
03005                                         $id = $delRec['uid'];
03006                                 }
03007                         }
03008 
03009                         if ($delRec['pid']==-1) {       // Look, if record is an offline version, then delete directly:
03010                                 if ($TCA[$table]['ctrl']['versioningWS'])       {
03011                                         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.
03012                                                 $liveRec = t3lib_BEfunc::getLiveVersionOfRecord($table,$id,'uid,t3ver_state');
03013 
03014                                                 if ($delRec['t3ver_wsid']==0 || (int)$liveRec['t3ver_state']!==1)       {       // Delete those in WS 0 + if their live records state was not "Placeholder".
03015                                                         $this->deleteEl($table, $id);
03016                                                 } else {        // If live record was placeholder, rather clear it from workspace (because it clears both version and placeholder).
03017                                                         $this->version_clearWSID($table,$id);
03018                                                 }
03019                                         } else $this->newlog('Tried to delete record from another workspace',1);
03020                                 } else $this->newlog('Versioning not enabled for record with PID = -1!',2);
03021                         } elseif ($res = $this->BE_USER->workspaceAllowLiveRecordsInPID($delRec['pid'], $table))        {       // Look, if record is "online" or in a versionized branch, then delete directly.
03022                                 if ($res>0)     {
03023                                         $this->deleteEl($table, $id);
03024                                 } else $this->newlog('Stage of root point did not allow for deletion',1);
03025                         } else {
03026                                 // Otherwise, try to delete by versionization:
03027                                 $this->versionizeRecord($table,$id,'DELETED!',TRUE);
03028                         }
03029                 }
03030         }
03031 
03041         function deleteEl($table, $uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE)   {
03042                 if ($table == 'pages')  {
03043                         $this->deletePages($uid, $noRecordCheck, $forceHardDelete);
03044                 } else {
03045                         $this->deleteRecord($table, $uid, $noRecordCheck, $forceHardDelete);
03046                 }
03047         }
03048 
03056         function undeleteRecord($table,$uid)    {
03057                 $this->deleteRecord($table,$uid,TRUE,FALSE,TRUE);
03058         }
03059 
03073         function deleteRecord($table,$uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE,$undeleteRecord=FALSE)  {
03074                 global $TCA;
03075 
03076                 $uid = intval($uid);
03077                 if ($TCA[$table] && $uid)       {
03078                         if ($noRecordCheck || $this->doesRecordExist($table,$uid,'delete'))     {
03079                                 $this->clear_cache($table,$uid);        // clear cache before deleting the record, else the correct page cannot be identified by clear_cache
03080 
03081                                 $propArr = $this->getRecordProperties($table, $uid);
03082                                 $pagePropArr = $this->getRecordProperties('pages', $propArr['pid']);
03083 
03084                                 $deleteRow = $TCA[$table]['ctrl']['delete'];
03085                                 if ($deleteRow && !$forceHardDelete)    {
03086                                         $value = $undeleteRecord ? 0 : 1;
03087                                         $updateFields = array(
03088                                                 $deleteRow => $value
03089                                         );
03090 
03091                                         if ($TCA[$table]['ctrl']['tstamp']) {
03092                                                 $updateFields[$TCA[$table]['ctrl']['tstamp']] = time();
03093                                         }
03094 
03095                                                 // If the table is sorted, then the sorting number is set very high
03096                                         if ($TCA[$table]['ctrl']['sortby'] && !$undeleteRecord) {
03097                                                 $updateFields[$TCA[$table]['ctrl']['sortby']] = 1000000000;
03098                                         }
03099 
03100                                         $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields);
03101                                 } else {
03102 
03103                                                 // Fetches all fields that holds references to files
03104                                         $fileFieldArr = $this->extFileFields($table);
03105                                         if (count($fileFieldArr))       {
03106                                                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(implode(',',$fileFieldArr), $table, 'uid='.intval($uid));
03107                                                 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))        {
03108                                                         $fArray = $fileFieldArr;
03109                                                         foreach($fArray as $theField)   {       // MISSING: Support for MM file relations!
03110                                                                 $this->extFileFunctions($table,$theField,$row[$theField],'deleteAll');          // This deletes files that belonged to this record.
03111                                                         }
03112                                                 } else {
03113                                                         $this->log($table,$uid,3,0,100,'Delete: Zero rows in result when trying to read filenames from record which should be deleted');
03114                                                 }
03115                                         }
03116 
03117                                         $GLOBALS['TYPO3_DB']->exec_DELETEquery($table, 'uid='.intval($uid));
03118                                 }
03119 
03120                                 $state = $undeleteRecord ? 1 : 3;       // 1 means insert, 3 means delete
03121                                 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
03122                                         if ($forceHardDelete) {
03123                                                 $message = "Record '%s' (%s) was deleted unrecoverable from page '%s' (%s)";
03124                                         }
03125                                         else {
03126                                                 $message = $state == 1 ?
03127                                                         "Record '%s' (%s) was restored on page '%s' (%s)" :
03128                                                         "Record '%s' (%s) was deleted from page '%s' (%s)";
03129                                         }
03130                                         $this->log($table, $uid, $state, 0, 0,
03131                                                                 $message, 0,
03132                                                                 array(
03133                                                                         $propArr['header'],
03134                                                                         $table.':'.$uid,
03135                                                                         $pagePropArr['header'],
03136                                                                         $propArr['pid']
03137                                                                         ),
03138                                                                 $propArr['pid']);
03139 
03140                                 } else {
03141                                         $this->log($table,$uid,$state,0,100,$GLOBALS['TYPO3_DB']->sql_error());
03142                                 }
03143 
03144                                         // Update reference index:
03145                                 $this->updateRefIndex($table,$uid);
03146 
03147                         } else $this->log($table,$uid,3,0,1,'Attempt to delete record without delete-permissions');
03148                 }
03149         }
03150 
03159         function deletePages($uid,$force=FALSE,$forceHardDelete=FALSE)  {
03160                         // Getting list of pages to delete:
03161                 if ($force)     {
03162                         $brExist = $this->doesBranchExist('',$uid,0,1);         // returns the branch WITHOUT permission checks (0 secures that)
03163                         $res = t3lib_div::trimExplode(',',$brExist.$uid,1);
03164                 } else {
03165                         $res = $this->canDeletePage($uid);
03166                 }
03167 
03168                         // Perform deletion if not error:
03169                 if (is_array($res))     {
03170                         foreach($res as $deleteId)      {
03171                                 $this->deleteSpecificPage($deleteId,$forceHardDelete);
03172                         }
03173                 } else {
03174                         $this->newlog($res,1);
03175                 }
03176         }
03177 
03187         function deleteSpecificPage($uid,$forceHardDelete=FALSE)        {
03188                 global $TCA;
03189                 reset ($TCA);
03190                 $uid = intval($uid);
03191                 if ($uid)       {
03192                         while (list($table)=each($TCA)) {
03193                                 if ($table!='pages')    {
03194                                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($uid).$this->deleteClause($table));
03195                                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))     {
03196                                                 $this->deleteRecord($table,$row['uid'], TRUE, $forceHardDelete);
03197                                         }
03198                                 }
03199                         }
03200                         $this->deleteRecord('pages',$uid, TRUE, $forceHardDelete);
03201                 }
03202         }
03203 
03210         function canDeletePage($uid)    {
03211                 if ($this->doesRecordExist('pages',$uid,'delete'))      {       // If we may at all delete this page
03212                         if ($this->deleteTree)  {
03213                                 $brExist = $this->doesBranchExist('',$uid,$this->pMap['delete'],1);     // returns the branch
03214                                 if ($brExist != -1)     {       // Checks if we had permissions
03215                                         if ($this->noRecordsFromUnallowedTables($brExist.$uid)) {
03216                                                 return t3lib_div::trimExplode(',',$brExist.$uid,1);
03217                                         } else return 'Attempt to delete records from disallowed tables';
03218                                 } else return 'Attempt to delete pages in branch without permissions';
03219                         } else {
03220                                 $brExist = $this->doesBranchExist('',$uid,$this->pMap['delete'],1);     // returns the branch
03221                                 if ($brExist == '')     {       // Checks if branch exists
03222                                         if ($this->noRecordsFromUnallowedTables($uid))  {
03223                                                 return array($uid);
03224                                         } else return 'Attempt to delete records from disallowed tables';
03225                                 } else return 'Attempt to delete page which has subpages';
03226                         }
03227                 } else return 'Attempt to delete page without permissions';
03228         }
03229 
03237         function cannotDeleteRecord($table,$id) {
03238                 if ($table==='pages')   {
03239                         $res = $this->canDeletePage($id);
03240                         return is_array($res) ? FALSE : $res;
03241                 } else {
03242                         return $this->doesRecordExist($table,$id,'delete') ? FALSE : 'No permission to delete record';
03243                 }
03244         }
03245 
03246 
03247 
03248 
03249 
03250 
03251 
03252 
03253 
03254 
03255 
03256 
03257         /*********************************************
03258          *
03259          * Cmd: Versioning
03260          *
03261          ********************************************/
03262 
03275         function versionizeRecord($table,$id,$label,$delete=FALSE,$versionizeTree=-1)   {
03276                 global $TCA;
03277 
03278                 $id = intval($id);
03279 
03280                 if ($TCA[$table] && $TCA[$table]['ctrl']['versioningWS'] && $id>0)      {
03281                         if ($this->doesRecordExist($table,$id,'show'))  {
03282                                 if ($this->BE_USER->workspaceVersioningTypeAccess($versionizeTree))     {
03283 
03284                                                 // Select main record:
03285                                         $row = $this->recordInfo($table,$id,'pid,t3ver_id');
03286                                         if (is_array($row))     {
03287                                                 if ($row['pid']>=0)     {       // record must be online record
03288                                                         if (!$delete || !$this->cannotDeleteRecord($table,$id)) {
03289 
03290                                                                         // Look for next version number:
03291                                                                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
03292                                                                         't3ver_id',
03293                                                                         $table,
03294                                                                         '(t3ver_oid='.$id.' || uid='.$id.')'.$this->deleteClause($table),
03295                                                                         '',
03296                                                                         't3ver_id DESC',
03297                                                                         '1'
03298                                                                 );
03299                                                                 list($highestVerNumber) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
03300 
03301                                                                         // Look for version number of the current:
03302                                                                 $subVer = $row['t3ver_id'].'.'.($highestVerNumber+1);
03303 
03304                                                                         // Set up the values to override when making a raw-copy:
03305                                                                 $overrideArray = array(
03306                                                                         't3ver_id' => $highestVerNumber+1,
03307                                                                         't3ver_oid' => $id,
03308                                                                         't3ver_label' => ($label ? $label : $subVer.' / '.date('d-m-Y H:m:s')),
03309                                                                         't3ver_wsid' => $this->BE_USER->workspace,
03310                                                                         't3ver_state' => $delete ? 2 : 0,
03311                                                                         't3ver_count' => 0,
03312                                                                         't3ver_stage' => 0,
03313                                                                         't3ver_tstamp' => 0
03314                                                                 );
03315                                                                 if ($TCA[$table]['ctrl']['editlock'])   {
03316                                                                         $overrideArray[$TCA[$table]['ctrl']['editlock']] = 0;
03317                                                                 }
03318                                                                 if ($table==='pages')   {
03319                                                                         $overrideArray['t3ver_swapmode'] = $versionizeTree;
03320                                                                 }
03321 
03322                                                                         // Checking if the record already has a version in the current workspace of the backend user
03323                                                                 $workspaceCheck = TRUE;
03324                                                                 if ($this->BE_USER->workspace!==0)      {
03325                                                                                 // Look for version already in workspace:
03326                                                                         $workspaceCheck = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace,$table,$id,'uid') ? FALSE : TRUE;
03327                                                                 }
03328 
03329                                                                 if ($workspaceCheck)    {
03330 
03331                                                                                 // Create raw-copy and return result:
03332                                                                         return $this->copyRecord_raw($table,$id,-1,$overrideArray);
03333                                                                 } else $this->newlog('Record you wanted to versionize was already a version in the workspace (wsid='.$this->BE_USER->workspace.')!',1);
03334                                                         } else $this->newlog('Record cannot be deleted: '.$this->cannotDeleteRecord($table,$id),1);
03335                                                 } else $this->newlog('Record you wanted to versionize was already a version in archive (pid=-1)!',1);
03336                                         } else $this->newlog('Record you wanted to versionize did not exist!',1);
03337                                 } else $this->newlog('The versioning type '.$versionizeTree.' mode you requested was not allowed',1);
03338                         } else $this->newlog('You didnt have correct permissions to make a new version (copy) of this record "'.$table.'" / '.$id,1);
03339                 } else $this->newlog('Versioning is not supported for this table "'.$table.'" / '.$id,1);
03340         }
03341 
03351         function versionizePages($uid,$label,$versionizeTree)   {
03352                 global $TCA;
03353 
03354                 $uid = intval($uid);
03355                 $brExist = $this->doesBranchExist('',$uid,$this->pMap['show'],1);       // returns the branch
03356 
03357                 if ($brExist != -1)     {       // Checks if we had permissions
03358 
03359                                 // Finding list of tables ALLOWED to be copied
03360                         $allowedTablesArray = $this->admin ? $this->compileAdminTables() : explode(',',$this->BE_USER->groupData['tables_modify']);     // These are the tables, the user may modify
03361                         $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.
03362 
03363                                 // Make list of tables that should come along with a new version of the page:
03364                         $verTablesArray = array();
03365                         $allTables = array_keys($TCA);
03366                         foreach($allTables as $tN)      {
03367                                 if ($tN!='pages' && ($versionizeTree>0 || $TCA[$tN]['ctrl']['versioning_followPages']) && ($this->admin || in_array($tN, $allowedTablesArray))) {
03368                                         $verTablesArray[] = $tN;
03369                                 }
03370                         }
03371 
03372                                 // Begin to copy pages if we're allowed to:
03373                         if ($this->admin || in_array('pages',$allowedTablesArray))      {
03374                                 if ($this->BE_USER->workspaceVersioningTypeAccess($versionizeTree))     {
03375                                                 // Versionize this page:
03376                                         $theNewRootID = $this->versionizeRecord('pages',$uid,$label,FALSE,$versionizeTree);
03377                                         if ($theNewRootID)      {
03378                                                 $this->rawCopyPageContent($uid,$theNewRootID,$verTablesArray);
03379 
03380                                                         // If we're going to copy recursively...:
03381                                                 if ($versionizeTree>0)  {
03382 
03383                                                                 // Get ALL subpages to copy (read permissions respected - they should NOT be...):
03384                                                         $CPtable = $this->int_pageTreeInfo(Array(), $uid, intval($versionizeTree), $theNewRootID);
03385 
03386                                                                 // Now copying the subpages:
03387                                                         foreach($CPtable as $thePageUid => $thePagePid) {
03388                                                                 $newPid = $this->copyMappingArray['pages'][$thePagePid];
03389                                                                 if (isset($newPid))     {
03390                                                                         $theNewRootID = $this->copyRecord_raw('pages',$thePageUid,$newPid);
03391                                                                         $this->rawCopyPageContent($thePageUid,$theNewRootID,$verTablesArray);
03392                                                                 } else {
03393                                                                         $this->newlog('Something went wrong during copying branch (for versioning)',1);
03394                                                                         break;
03395                                                                 }
03396                                                         }
03397                                                 }       // else the page was not copied. Too bad...
03398                                         } else $this->newlog('The root version could not be created!',1);
03399                                 } else $this->newlog('Versioning type "'.$versionizeTree.'" was not allowed in workspace',1);
03400                         } else $this->newlog('Attempt to versionize page without permission to this table',1);
03401                 } else $this->newlog('Could not read all subpages to versionize.',1);
03402         }
03403 
03414         function version_swap($table,$id,$swapWith,$swapIntoWS=0)       {
03415                 global $TCA;
03416 
03417                 /*
03418                 Version ID swapping principles:
03419                   - 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
03420 
03421                         uid             pid                     uid             t3ver_oid       pid
03422                 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)
03423                 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))
03424                 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.)
03425 
03426                         13 is online UID,
03427                         247 is specific versions UID
03428                         123 is the PID of the original record
03429                         -1 is the versioning repository PID
03430 
03431                         Recovery Process:
03432                                 Search for negative UID (here "-13"):
03433                                         YES: Step 1 completed, but at least step 3 didn't.
03434                                                 Search for the negativ UIDs positive (here: "13")
03435                                                         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)
03436                                                         NO: Only Step 1 completed! Rollback: Just change uid "-13" to "13" and "t3ver_oid" to "13" (not important)
03437                                         NO: No problems.
03438                 */
03439 
03440                         // First, check if we may actually edit the online record
03441                 if ($this->checkRecordUpdateAccess($table,$id)) {
03442 
03443                                 // Select the two versions:
03444                         $curVersion = t3lib_BEfunc::getRecord($table,$id,'*');
03445                         $swapVersion = t3lib_BEfunc::getRecord($table,$swapWith,'*');
03446 
03447                         if (is_array($curVersion) && is_array($swapVersion))    {
03448                                 if ($this->BE_USER->workspacePublishAccess($swapVersion['t3ver_wsid'])) {
03449                                         $wsAccess = $this->BE_USER->checkWorkspace($swapVersion['t3ver_wsid']);
03450                                         if ($swapVersion['t3ver_wsid']<=0 || !($wsAccess['publish_access']&1) || (int)$swapVersion['t3ver_stage']===10) {
03451                                                 if ($this->doesRecordExist($table,$swapWith,'show') && $this->checkRecordUpdateAccess($table,$swapWith)) {
03452                                                         if (!$swapIntoWS || $this->BE_USER->workspaceSwapAccess())      {
03453 
03454                                                                         // Check if the swapWith record really IS a version of the original!
03455                                                                 if ((int)$swapVersion['pid']==-1 && (int)$curVersion['pid']>=0 && !strcmp($swapVersion['t3ver_oid'],$id))       {
03456 
03457                                                                                 // Lock file name:
03458                                                                         $lockFileName = PATH_site.'typo3temp/swap_locking/'.$table.':'.$id.'.ser';
03459 
03460                                                                         if (!@is_file($lockFileName))   {
03461 
03462                                                                                         // Write lock-file:
03463                                                                                 t3lib_div::writeFileToTypo3tempDir($lockFileName,serialize(array(
03464                                                                                         'tstamp'=>time(),
03465                                                                                         'user'=>$GLOBALS['BE_USER']->user['username'],
03466                                                                                         'curVersion'=>$curVersion,
03467                                                                                         'swapVersion'=>$swapVersion
03468                                                                                 )));
03469 
03470                                                                                         // Find fields to keep
03471                                                                                 $keepFields = $this->getUniqueFields($table);
03472                                                                                 if ($TCA[$table]['ctrl']['sortby'])     {
03473                                                                                         $keepFields[] = $TCA[$table]['ctrl']['sortby'];
03474                                                                                 }
03475 
03476                                                                                         // Swap "keepfields"
03477                                                                                 foreach($keepFields as $fN)     {
03478                                                                                         $tmp = $swapVersion[$fN];
03479                                                                                         $swapVersion[$fN] = $curVersion[$fN];
03480                                                                                         $curVersion[$fN] = $tmp;
03481                                                                                 }
03482 
03483                                                                                         // Preserve states:
03484                                                                                 $t3ver_state = array();
03485                                                                                 $t3ver_state['swapVersion'] = $swapVersion['t3ver_state'];
03486                                                                                 $t3ver_state['curVersion'] = $curVersion['t3ver_state'];
03487 
03488                                                                                         // Modify offline version to become online:
03489                                                                                 $tmp_wsid = $swapVersion['t3ver_wsid'];
03490                                                                                 unset($swapVersion['uid']);
03491                                                                                 $swapVersion['pid'] = intval($curVersion['pid']);       // Set pid for ONLINE
03492                                                                                 $swapVersion['t3ver_oid'] = intval($id);
03493                                                                                 $swapVersion['t3ver_wsid'] = $swapIntoWS ? intval($curVersion['t3ver_wsid']) : 0;
03494                                                                                 $swapVersion['t3ver_tstamp'] = time();
03495                                                                                 $swapVersion['t3ver_stage'] = $swapVersion['t3ver_state'] = 0;
03496 
03497                                                                                         // Modify online version to become offline:
03498                                                                                 unset($curVersion['uid']);
03499                                                                                 $curVersion['pid'] = -1;        // Set pid for OFFLINE
03500                                                                                 $curVersion['t3ver_oid'] = intval($id);
03501                                                                                 $curVersion['t3ver_wsid'] = $swapIntoWS ? intval($tmp_wsid) : 0;
03502                                                                                 $curVersion['t3ver_tstamp'] = time();
03503                                                                                 $curVersion['t3ver_count'] = $curVersion['t3ver_count']+1;      // Increment lifecycle counter
03504                                                                                 $curVersion['t3ver_stage'] = $curVersion['t3ver_state'] = 0;
03505 
03506                                                                                 if ($table==='pages') {         // Keeping the swapmode state
03507                                                                                                 $curVersion['t3ver_swapmode'] = $swapVersion['t3ver_swapmode'];
03508                                                                                 }
03509 
03510                                                                                         // Execute swapping:
03511                                                                                 $sqlErrors = array();
03512                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($id),$swapVersion);
03513                                                                                 if ($GLOBALS['TYPO3_DB']->sql_error())          {
03514                                                                                         $sqlErrors[] = $GLOBALS['TYPO3_DB']->sql_error();
03515                                                                                 } else {
03516                                                                                         $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($swapWith),$curVersion);
03517                                                                                         if ($GLOBALS['TYPO3_DB']->sql_error())  {
03518                                                                                                 $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
03519                                                                                         } else {
03520                                                                                                 unlink($lockFileName);
03521                                                                                         }
03522                                                                                 }
03523 
03524                                                                                 if (!count($sqlErrors)) {
03525 
03526                                                                                                 // Checking for delete:
03527                                                                                         if ($t3ver_state['swapVersion']==2)     {
03528                                                                                                 $this->deleteEl($table,$id,TRUE);       // Force delete
03529                                                                                         }
03530 
03531                                                                                         $this->newlog('Swapping successful for table "'.$table.'" uid '.$id.'=>'.$swapWith);
03532 
03533                                                                                                 // Update reference index:
03534                                                                                         $this->updateRefIndex($table,$id);
03535                                                                                         $this->updateRefIndex($table,$swapWith);
03536 
03537                                                                                                 // SWAPPING pids for subrecords:
03538                                                                                         if ($table=='pages' && $swapVersion['t3ver_swapmode']>=0)       {
03539 
03540                                                                                                         // Collect table names that should be copied along with the tables:
03541                                                                                                 foreach($TCA as $tN => $tCfg)   {
03542                                                                                                         if ($swapVersion['t3ver_swapmode']>0 || $TCA[$tN]['ctrl']['versioning_followPages'])    {       // For "Branch" publishing swap ALL, otherwise for "page" publishing, swap only "versioning_followPages" tables
03543                                                                                                                 $temporaryPid = -($id+1000000);
03544 
03545                                                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($id),array('pid'=>$temporaryPid));
03546                                                                                                                 if ($GLOBALS['TYPO3_DB']->sql_error())  $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
03547 
03548                                                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($swapWith),array('pid'=>$id));
03549                                                                                                                 if ($GLOBALS['TYPO3_DB']->sql_error())  $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
03550 
03551                                                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($temporaryPid),array('pid'=>$swapWith));
03552                                                                                                                 if ($GLOBALS['TYPO3_DB']->sql_error())  $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
03553 
03554                                                                                                                 if (count($sqlErrors))  {
03555                                                                                                                         $this->newlog('During Swapping: SQL errors happend: '.implode('; ',$sqlErrors),2);
03556                                                                                                                 }
03557                                                                                                         }
03558                                                                                                 }
03559                                                                                         }
03560                                                                                                 // Clear cache:
03561                                                                                         $this->clear_cache($table,$id);
03562 
03563                                                                                                 // Checking for "new-placeholder" and if found, delete it (BUT FIRST after swapping!):
03564                                                                                         if ($t3ver_state['curVersion']==1)      {
03565                                                                                                 $this->deleteEl($table, $swapWith, TRUE, TRUE);         // For delete + completely delete!
03566                                                                                         }
03567                                                                                 } else $this->newlog('During Swapping: SQL errors happend: '.implode('; ',$sqlErrors),2);
03568                                                                         } 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);
03569                                                                 } 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);
03570                                                         } else $this->newlog('Workspace #'.$swapVersion['t3ver_wsid'].' does not support swapping.',1);
03571                                                 } else $this->newlog('You cannot publish a record you do not have edit and show permissions for',1);
03572                                         } else $this->newlog('Records in workspace #'.$swapVersion['t3ver_wsid'].' can only be published when in "Publish" stage.',1);
03573                                 } else $this->newlog('User could not publish records from workspace #'.$swapVersion['t3ver_wsid'],1);
03574                         } else $this->newlog('Error: Either online or swap version could not be selected!',2);
03575                 } else $this->newlog('Error: You cannot swap versions for a record you do not have access to edit!',1);
03576         }
03577 
03585         function version_clearWSID($table,$id)  {
03586                 if ($errorCode = $this->BE_USER->workspaceCannotEditOfflineVersion($table, $id))        {
03587                         $this->newlog('Attempt to reset workspace for record failed: '.$errorCode,1);
03588                 } elseif ($this->checkRecordUpdateAccess($table,$id)) {
03589                         if ($liveRec = t3lib_BEfunc::getLiveVersionOfRecord($table,$id,'uid,t3ver_state'))      {
03590                                         // Clear workspace ID:
03591                                 $sArray = array();
03592                                 $sArray['t3ver_wsid'] = 0;
03593                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($id),$sArray);
03594 
03595                                         // Clear workspace ID for live version AND DELETE IT as well because it is a new record!
03596                                 if ((int)$liveRec['t3ver_state']===1)   {
03597                                         $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($liveRec['uid']),$sArray);
03598                                         $this->deleteEl($table, $liveRec['uid'], TRUE); // THIS assumes that the record was placeholder ONLY for ONE record (namely $id)
03599                                 }
03600 
03601                                         // 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.
03602                                 $wsRec = t3lib_BEfunc::getRecord($table,$id);
03603                                 if ((int)$wsRec['t3ver_state']===2)     {
03604                                         $this->deleteEl($table, $id, TRUE, TRUE);
03605                                 }
03606                         }
03607                 } else $this->newlog('Attempt to reset workspace for record failed because you do not have edit access',1);
03608         }
03609 
03619         function version_setStage($table,$id,$stageId,$comment='')      {
03620                 if ($errorCode = $this->BE_USER->workspaceCannotEditOfflineVersion($table, $id))        {
03621                         $this->newlog('Attempt to set stage for record failed: '.$errorCode,1);
03622                 } elseif ($this->checkRecordUpdateAccess($table,$id)) {
03623                         $stat = $this->BE_USER->checkWorkspaceCurrent();
03624                         if (t3lib_div::inList('admin,online,offline,reviewer,owner', $stat['_ACCESS']) || ($stageId<=1 && $stat['_ACCESS']==='member')) {
03625 
03626                                         // Set stage of record:
03627                                 $sArray = array();
03628                                 $sArray['t3ver_stage'] = $stageId;
03629                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($id), $sArray);
03630                                 $this->newlog('Stage for record was changed to '.$stageId.'. Comment was: "'.substr($comment,0,100).'"');
03631 // TEMPORARY, except 6-30 as action/detail number which is observed elsewhere!
03632 $this->log($table,$id,6,0,0,'Stage raised...',30,array('comment'=>$comment,'stage'=>$stageId));
03633 
03634                                 if ((int)$stat['stagechg_notification']>0)      {
03635                                         $this->notifyStageChange($stat,$stageId,$table,$id,$comment);
03636                                 }
03637                         } else $this->newlog('The member user tried to set a stage value "'.$stageId.'" that was not allowed',1);
03638                 } else $this->newlog('Attempt to set stage for record failed because you do not have edit access',1);
03639         }
03640 
03641 
03642 
03643 
03644 
03645 
03646 
03647 
03648 
03649 
03650 
03651 
03652 
03653         /*********************************************
03654          *
03655          * Cmd: Helper functions
03656          *
03657          ********************************************/
03658 
03664         function remapListedDBRecords() {
03665                 global $TCA;
03666 
03667                 if (count($this->registerDBList))       {
03668                         reset($this->registerDBList);
03669                         while(list($table,$records)=each($this->registerDBList))        {
03670                                 t3lib_div::loadTCA($table);
03671                                 reset($records);
03672                                 while(list($uid,$fields)=each($records))        {
03673                                         $newData = array();
03674                                         $theUidToUpdate = $this->copyMappingArray_merged[$table][$uid];
03675                                         $theUidToUpdate_saveTo = t3lib_BEfunc::wsMapId($table,$theUidToUpdate);
03676 
03677                                         foreach($fields as $fieldName => $value)        {
03678                                                 $conf = $TCA[$table]['columns'][$fieldName]['config'];
03679 
03680                                                 switch($conf['type'])   {
03681                                                         case 'group':
03682                                                         case 'select':
03683                                                                 $vArray = $this->remapListedDBRecords_procDBRefs($conf, $value, $theUidToUpdate);
03684                                                                 if (is_array($vArray))  {
03685                                                                         $newData[$fieldName] = implode(',',$vArray);
03686                                                                 }
03687                                                         break;
03688                                                         case 'flex':
03689                                                                 if ($value=='FlexForm_reference')       {
03690                                                                         $origRecordRow = $this->recordInfo($table,$theUidToUpdate,'*'); // This will fetch the new row for the element
03691 
03692                                                                         if (is_array($origRecordRow))   {
03693                                                                                 t3lib_BEfunc::workspaceOL($table,$origRecordRow);
03694 
03695                                                                                         // Get current data structure and value array:
03696                                                                                 $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $origRecordRow, $table);
03697                                                                                 $currentValueArray = t3lib_div::xml2array($origRecordRow[$fieldName]);
03698 
03699                                                                                         // Do recursive processing of the XML data:
03700                                                                                 $currentValueArray['data'] = $this->checkValue_flex_procInData(
03701                                                                                                         $currentValueArray['data'],
03702                                                                                                         array(),        // Not used.
03703                                                                                                         array(),        // Not used.
03704                                                                                                         $dataStructArray,
03705                                                                                                         array($table,$theUidToUpdate,$fieldName),       // Parameters.
03706                                                                                                         'remapListedDBRecords_flexFormCallBack'
03707                                                                                                 );
03708 
03709                                                                                         // The return value should be compiled back into XML, ready to insert directly in the field (as we call updateDB() directly later):
03710                                                                                 if (is_array($currentValueArray['data']))       {
03711                                                                                         $newData[$fieldName] =
03712                                                                                                 $this->checkValue_flexArray2Xml($currentValueArray,TRUE);
03713                                                                                 }
03714                                                                         }
03715                                                                 }
03716                                                         break;
03717                                                         default:
03718                                                                 debug('Field type should not appear here: '. $conf['type']);
03719                                                         break;
03720                                                 }
03721                                         }
03722 
03723                                         if (count($newData))    {       // If any fields were changed, those fields are updated!
03724                                                 $this->updateDB($table,$theUidToUpdate_saveTo,$newData);
03725                                         }
03726                                 }
03727                         }
03728                 }
03729         }
03730 
03742         function remapListedDBRecords_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2) {
03743 
03744                         // Extract parameters:
03745                 list($table,$uid,$field)        = $pParams;
03746 
03747                         // If references are set for this field, set flag so they can be corrected later:
03748                 if ($this->isReferenceField($dsConf) && strlen($dataValue)) {
03749                         $vArray = $this->remapListedDBRecords_procDBRefs($dsConf, $dataValue, $uid);
03750                         if (is_array($vArray))  {
03751                                 $dataValue = implode(',',$vArray);
03752                         }
03753                 }
03754 
03755                         // Return
03756                 return array('value' => $dataValue);
03757         }
03758 
03768         function remapListedDBRecords_procDBRefs($conf, $value, $MM_localUid)   {
03769 
03770                         // Initialize variables
03771                 $set = FALSE;   // Will be set true if an upgrade should be done...
03772                 $allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table'];             // Allowed tables for references.
03773                 $prependName = $conf['type']=='group' ? $conf['prepend_tname'] : '';    // Table name to prepend the UID
03774                 $dontRemapTables = t3lib_div::trimExplode(',',$conf['dontRemapTablesOnCopy'],1);        // Which tables that should possibly not be remapped
03775 
03776                         // Convert value to list of references:
03777                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
03778                 $dbAnalysis->registerNonTableValues = ($conf['type']=='select' && $conf['allowNonIdValues']) ? 1 : 0;
03779                 $dbAnalysis->start($value, $allowedTables, $conf['MM'], $MM_localUid);
03780 
03781                         // Traverse those references and map IDs:
03782                 foreach($dbAnalysis->itemArray as $k => $v)     {
03783                         $mapID = $this->copyMappingArray_merged[$v['table']][$v['id']];
03784                         if ($mapID && !in_array($v['table'],$dontRemapTables))  {
03785                                 $dbAnalysis->itemArray[$k]['id'] = $mapID;
03786                                 $set = TRUE;
03787                         }
03788                 }
03789 
03790                         // If a change has been done, set the new value(s)
03791                 if ($set)       {
03792                         if ($conf['MM'])        {
03793 // FIXME $theUidToUpdate is undefined
03794                                 $dbAnalysis->writeMM($conf['MM'], $theUidToUpdate, $prependName);
03795                         } else {
03796                                 $vArray = $dbAnalysis->getValueArray($prependName);
03797                                 if ($conf['type']=='select')    {
03798                                         $vArray = $dbAnalysis->convertPosNeg($vArray, $conf['foreign_table'], $conf['neg_foreign_table']);
03799                                 }
03800                                 return $vArray;
03801                         }
03802                 }
03803         }
03804 
03805 
03806 
03807 
03808 
03809 
03810 
03811 
03812 
03813 
03814 
03815 
03816 
03817 
03818 
03819 
03820 
03821         /*****************************
03822          *
03823          * Access control / Checking functions
03824          *
03825          *****************************/
03826 
03833         function checkModifyAccessList($table)  {
03834                 $res = ($this->admin || (!$this->tableAdminOnly($table) && t3lib_div::inList($this->BE_USER->groupData['tables_modify'],$table)));
03835                 return $res;
03836         }
03837 
03845         function isRecordInWebMount($table,$id) {
03846                 if (!isset($this->isRecordInWebMount_Cache[$table.':'.$id]))    {
03847                         $recP=$this->getRecordProperties($table,$id);
03848                         $this->isRecordInWebMount_Cache[$table.':'.$id]=$this->isInWebMount($recP['event_pid']);
03849                 }
03850                 return $this->isRecordInWebMount_Cache[$table.':'.$id];
03851         }
03852 
03859         function isInWebMount($pid)     {
03860                 if (!isset($this->isInWebMount_Cache[$pid]))    {
03861                         $this->isInWebMount_Cache[$pid]=$this->BE_USER->isInWebMount($pid);
03862                 }
03863                 return $this->isInWebMount_Cache[$pid];
03864         }
03865 
03873         function checkRecordUpdateAccess($table,$id)    {
03874                 global $TCA;
03875                 $res = 0;
03876                 if ($TCA[$table] && intval($id)>0)      {
03877                         if (isset($this->recUpdateAccessCache[$table][$id]))    {       // If information is cached, return it
03878                                 return $this->recUpdateAccessCache[$table][$id];
03879                                 // Check if record exists and 1) if 'pages' the page may be edited, 2) if page-content the page allows for editing
03880                         } elseif ($this->doesRecordExist($table,$id,'edit'))    {
03881                                 $res = 1;
03882                         }
03883                         $this->recUpdateAccessCache[$table][$id]=$res;  // Cache the result
03884                 }
03885                 return $res;
03886         }
03887 
03897         function checkRecordInsertAccess($insertTable,$pid,$action=1)   {
03898                 global $TCA;
03899 
03900                 $res = 0;
03901                 $pid = intval($pid);
03902                 if ($pid>=0)    {
03903                         if (isset($this->recInsertAccessCache[$insertTable][$pid]))     {       // If information is cached, return it
03904                                 return $this->recInsertAccessCache[$insertTable][$pid];
03905                         } else {
03906                                         // 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
03907                                 if ( (!$pid && $this->admin) || $this->doesRecordExist('pages',$pid,($insertTable=='pages'?$this->pMap['new']:$this->pMap['editcontent'])) )    {               // Check permissions
03908                                         if ($this->isTableAllowedForThisPage($pid, $insertTable))       {
03909                                                 $res = 1;
03910                                                 $this->recInsertAccessCache[$insertTable][$pid]=$res;   // Cache the result
03911                                         } else {
03912                                                 $propArr = $this->getRecordProperties('pages',$pid);
03913                                                 $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']);
03914                                         }
03915                                 } else {
03916                                         $propArr = $this->getRecordProperties('pages',$pid);
03917                                         $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']);
03918                                 }
03919                         }
03920                 }
03921                 return $res;
03922         }
03923 
03931         function isTableAllowedForThisPage($page_uid, $checkTable)      {
03932                 global $TCA, $PAGES_TYPES;
03933                 $page_uid = intval($page_uid);
03934 
03935                         // 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.
03936                 if (($TCA[$checkTable]['ctrl']['rootLevel'] xor !$page_uid) && $TCA[$checkTable]['ctrl']['rootLevel']!=-1 && $checkTable!='pages')      {
03937                         return false;
03938                 }
03939 
03940                         // Check root-level
03941                 if (!$page_uid) {
03942                         if ($this->admin)       {
03943                                 return true;
03944                         }
03945                 } else {
03946                                 // Check non-root-level
03947                         $doktype = $this->pageInfo($page_uid,'doktype');
03948                         $allowedTableList = isset($PAGES_TYPES[$doktype]['allowedTables']) ? $PAGES_TYPES[$doktype]['allowedTables'] : $PAGES_TYPES['default']['allowedTables'];
03949                         $allowedArray = t3lib_div::trimExplode(',',$allowedTableList,1);
03950                         if (strstr($allowedTableList,'*') || in_array($checkTable,$allowedArray))       {               // If all tables or the table is listed as a allowed type, return true
03951                                 return true;
03952                         }
03953                 }
03954         }
03955 
03964         function doesRecordExist($table,$id,$perms)     {
03965                 global $TCA;
03966 
03967                 $res = 0;
03968                 $id = intval($id);
03969 
03970                         // Processing the incoming $perms (from possible string to integer that can be AND'ed)
03971                 if (!t3lib_div::testInt($perms))        {
03972                         if ($table!='pages')    {
03973                                 switch($perms)  {
03974                                         case 'edit':
03975                                         case 'delete':
03976                                         case 'new':
03977                                                 $perms = 'editcontent';         // This holds it all in case the record is not page!!
03978                                         break;
03979                                 }
03980                         }
03981                         $perms = intval($this->pMap[$perms]);
03982                 } else {
03983                         $perms = intval($perms);
03984                 }
03985 
03986                 if (!$perms)    {die('Internal ERROR: no permissions to check for non-admin user.');}
03987 
03988                         // For all tables: Check if record exists:
03989                 if (is_array($TCA[$table]) && $id>0 && ($this->isRecordInWebMount($table,$id) || $this->admin)) {
03990                         if ($table != 'pages')  {
03991 
03992                                         // Find record without checking page:
03993                                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid', $table, 'uid='.intval($id).$this->deleteClause($table));      // THIS SHOULD CHECK FOR editlock I think!
03994                                 $output = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres);
03995                                 t3lib_BEfunc::fixVersioningPid($table,$output,TRUE);
03996 
03997                                         // If record found, check page as well:
03998                                 if (is_array($output))  {
03999 
04000                                                 // Looking up the page for record:
04001                                         $mres = $this->doesRecordExist_pageLookUp($output['pid'], $perms);
04002                                         $pageRec = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres);
04003                                                 // 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):
04004                                         if (is_array($pageRec) || (!$output['pid'] && $this->admin))    {
04005                                                 return TRUE;
04006                                         }
04007                                 }
04008                                 return FALSE;
04009                         } else {
04010                                 $mres = $this->doesRecordExist_pageLookUp($id, $perms);
04011                                 return $GLOBALS['TYPO3_DB']->sql_num_rows($mres);
04012                         }
04013                 }
04014         }
04015 
04025         function doesRecordExist_pageLookUp($id, $perms)        {
04026                 global $TCA;
04027 
04028                 return $GLOBALS['TYPO3_DB']->exec_SELECTquery(
04029                         'uid',
04030                         'pages',
04031                         'uid='.intval($id).
04032                                 $this->deleteClause('pages').
04033                                 ($perms && !$this->admin ? ' AND '.$this->BE_USER->getPagePermsClause($perms) : '').
04034                                 (!$this->admin && $TCA['pages']['ctrl']['editlock'] && ($perms & (2+4+16)) ? ' AND '.$TCA['pages']['ctrl']['editlock'].'=0':'') // admin users don't need check
04035                 );
04036         }
04037 
04051         function doesBranchExist($inList,$pid,$perms,$recurse)  {
04052                 global $TCA;
04053                 $pid = intval($pid);
04054                 $perms = intval($perms);
04055 
04056                 if ($pid>=0)    {
04057                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
04058                                 'uid, perms_userid, perms_groupid, perms_user, perms_group, perms_everybody',
04059                                 'pages',
04060                                 'pid='.intval($pid).$this->deleteClause('pages'),
04061                                 '',
04062                                 'sorting'
04063                         );
04064                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))     {
04065                                 if ($this->admin || $this->BE_USER->doesUserHaveAccess($row,$perms))    {       // IF admin, then it's OK
04066                                         $inList.=$row['uid'].',';
04067                                         if ($recurse)   {       // Follow the subpages recursively...
04068                                                 $inList = $this->doesBranchExist($inList, $row['uid'], $perms, $recurse);
04069                                                 if ($inList == -1)      {return -1;}            // No permissions somewhere in the branch
04070                                         }
04071                                 } else {
04072                                         return -1;              // No permissions
04073                                 }
04074                         }
04075                 }
04076                 return $inList;
04077         }
04078 
04085         function tableReadOnly($table)  {
04086                         // returns true if table is readonly
04087                 global $TCA;
04088                 return ($TCA[$table]['ctrl']['readOnly'] ? 1 : 0);
04089         }
04090 
04097         function tableAdminOnly($table) {
04098                         // returns true if table is admin-only
04099                 global $TCA;
04100                 return ($TCA[$table]['ctrl']['adminOnly'] ? 1 : 0);
04101         }
04102 
04111         function destNotInsideSelf($dest,$id)   {
04112                 $loopCheck = 100;
04113                 $dest = intval($dest);
04114                 $id = intval($id);
04115 
04116                 if ($dest==$id) {
04117                         return FALSE;
04118                 }
04119 
04120                 while ($dest!=0 && $loopCheck>0)        {
04121                         $loopCheck--;
04122                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('pid, uid, t3ver_oid,t3ver_wsid', 'pages', 'uid='.intval($dest).$this->deleteClause('pages'));
04123                         if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
04124                                 t3lib_BEfunc::fixVersioningPid('pages',$row);
04125                                 if ($row['pid']==$id)   {
04126                                         return FALSE;
04127                                 } else {
04128                                         $dest = $row['pid'];
04129                                 }
04130                         } else {
04131                                 return FALSE;
04132                         }
04133                 }
04134                 return TRUE;
04135         }
04136 
04143         function getExcludeListArray()  {
04144                 global $TCA;
04145 
04146                 $list = array();
04147                 reset($TCA);
04148                 while (list($table)=each($TCA)) {
04149                         t3lib_div::loadTCA($table);
04150                         while (list($field,$config)=each($TCA[$table]['columns']))      {
04151                                 if ($config['exclude'] && !t3lib_div::inList($this->BE_USER->groupData['non_exclude_fields'],$table.':'.$field))        {
04152                                         $list[]=$table.'-'.$field;
04153                                 }
04154                         }
04155                 }
04156                 return $list;
04157         }
04158 
04166         function doesPageHaveUnallowedTables($page_uid,$doktype)        {
04167                 global $TCA, $PAGES_TYPES;
04168 
04169                 $page_uid = intval($page_uid);
04170                 if (!$page_uid) {
04171                         return FALSE;   // Not a number. Probably a new page
04172                 }
04173 
04174                 $allowedTableList = isset($PAGES_TYPES[$doktype]['allowedTables']) ? $PAGES_TYPES[$doktype]['allowedTables'] : $PAGES_TYPES['default']['allowedTables'];
04175                 $allowedArray = t3lib_div::trimExplode(',',$allowedTableList,1);
04176                 if (strstr($allowedTableList,'*'))      {       // If all tables is OK the return true
04177                         return FALSE;   // OK...
04178                 }
04179 
04180                 reset ($TCA);
04181                 $tableList = array();
04182                 while (list($table)=each($TCA)) {
04183                         if (!in_array($table,$allowedArray))    {       // If the table is not in the allowed list, check if there are records...
04184                                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', $table, 'pid='.intval($page_uid));
04185                                 $count = $GLOBALS['TYPO3_DB']->sql_fetch_row($mres);
04186                                 if ($count[0])  {
04187                                         $tableList[]=$table;
04188                                 }
04189                         }
04190                 }
04191                 return implode(',',$tableList);
04192         }
04193 
04194 
04195 
04196 
04197 
04198 
04199 
04200 
04201         /*****************************
04202          *
04203          * Information lookup
04204          *
04205          *****************************/
04206 
04215         function pageInfo($id,$field)   {
04216                 if (!isset($this->pageCache[$id]))      {
04217                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'uid='.intval($id));
04218                         if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
04219                                 $this->pageCache[$id] = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
04220                         }
04221                         $GLOBALS['TYPO3_DB']->sql_free_result($res);
04222                 }
04223                 return $this->pageCache[$id][$field];
04224         }
04225 
04235         function recordInfo($table,$id,$fieldList)      {
04236                 global $TCA;
04237                 if (is_array($TCA[$table]))     {
04238                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fieldList, $table, 'uid='.intval($id));
04239                         if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
04240                                 return $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
04241                         }
04242                 }
04243         }
04244 
04256         function getRecordProperties($table,$id,$noWSOL=FALSE)  {
04257                 $row = ($table=='pages' && !$id) ? array('title'=>'[root-level]', 'uid' => 0, 'pid' => 0) :$this->recordInfo($table,$id,'*');
04258                 if (!$noWSOL)   {
04259                         t3lib_BEfunc::workspaceOL($table,$row);
04260                 }
04261                 t3lib_BEfunc::fixVersioningPid($table,$row);
04262                 return $this->getRecordPropertiesFromRow($table,$row);
04263         }
04264 
04272         function getRecordPropertiesFromRow($table,$row)        {
04273                 global $TCA;
04274                 if ($TCA[$table])       {
04275                         $out = array(
04276                                 'header' => $row[$TCA[$table]['ctrl']['label']],
04277                                 'pid' => $row['pid'],
04278                                 'event_pid' => ($table=='pages'?$row['uid']:$row['pid']),
04279                                 't3ver_state' => $TCA[$table]['ctrl']['versioningWS'] ? $row['t3ver_state'] : '',
04280                                 '_ORIG_pid' => $row['_ORIG_pid']
04281                         );
04282                         return $out;
04283                 }
04284         }
04285 
04286 
04287 
04288 
04289 
04290 
04291 
04292 
04293 
04294 
04295 
04296 
04297 
04298 
04299 
04300         /*********************************************
04301          *
04302          * Storing data to Database Layer
04303          *
04304          ********************************************/
04305 
04315         function updateDB($table,$id,$fieldArray)       {
04316                 global $TCA;
04317 
04318                 if (is_array($fieldArray) && is_array($TCA[$table]) && intval($id))     {
04319                         unset($fieldArray['uid']);      // Do NOT update the UID field, ever!
04320 
04321                         if (count($fieldArray)) {
04322 
04323                                         // Execute the UPDATE query:
04324                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($id), $fieldArray);
04325 
04326                                         // If succees, do...:
04327                                 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
04328 
04329                                         if ($this->checkStoredRecords)  {
04330                                                 $newRow = $this->checkStoredRecord($table,$id,$fieldArray,2);
04331                                         }
04332 
04333                                                 // Update reference index:
04334                                         $this->updateRefIndex($table,$id);
04335 
04336                                                 // Set log entry:
04337                                         $propArr = $this->getRecordPropertiesFromRow($table,$newRow);
04338                                         $theLogId = $this->log($table,$id,2,$propArr['pid'],0,"Record '%s' (%s) was updated.",10,array($propArr['header'],$table.':'.$id),$propArr['event_pid']);
04339 
04340                                                 // Set History data:
04341                                         $this->setHistory($table,$id,$theLogId);
04342 
04343                                                 // Clear cache for relevant pages:
04344                                         $this->clear_cache($table,$id);
04345 
04346                                                 // Unset the pageCache for the id if table was page.
04347                                         if ($table=='pages')    unset($this->pageCache[$id]);
04348                                 } else {
04349                                         $this->log($table,$id,2,0,2,"SQL error: '%s' (%s)",12,array($GLOBALS['TYPO3_DB']->sql_error(),$table.':'.$id));
04350                                 }
04351                         }
04352                 }
04353         }
04354 
04367         function insertDB($table,$id,$fieldArray,$newVersion=FALSE,$suggestedUid=0,$dontSetNewIdIndex=FALSE)    {
04368                 global $TCA;
04369 
04370                 if (is_array($fieldArray) && is_array($TCA[$table]) && isset($fieldArray['pid']))       {
04371                         unset($fieldArray['uid']);      // Do NOT insert the UID field, ever!
04372 
04373                         if (count($fieldArray)) {
04374 
04375                                         // Check for "suggestedUid".
04376                                         // This feature is used by the import functionality to force a new record to have a certain UID value.
04377                                         // This is only recommended for use when the destination server is a passive mirrow of another server.
04378                                         // As a security measure this feature is available only for Admin Users (for now)
04379                                 $suggestedUid = intval($suggestedUid);
04380                                 if ($this->BE_USER->isAdmin() && $suggestedUid && $this->suggestedInsertUids[$table.':'.$suggestedUid]) {
04381                                                 // When the value of ->suggestedInsertUids[...] is "DELETE" it will try to remove the previous record
04382                                         if ($this->suggestedInsertUids[$table.':'.$suggestedUid]==='DELETE')    {
04383                                                         // DELETE:
04384                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery($table, 'uid='.intval($suggestedUid));
04385                                         }
04386                                         $fieldArray['uid'] = $suggestedUid;
04387                                 }
04388 
04389                                         // Execute the INSERT query:
04390                                 $GLOBALS['TYPO3_DB']->exec_INSERTquery($table, $fieldArray);
04391 
04392                                         // If succees, do...:
04393                                 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
04394 
04395                                                 // Set mapping for NEW... -> real uid:
04396                                         $NEW_id = $id;          // the NEW_id now holds the 'NEW....' -id
04397                                         $id = $GLOBALS['TYPO3_DB']->sql_insert_id();
04398                                         if (!$dontSetNewIdIndex)        {
04399                                                 $this->substNEWwithIDs[$NEW_id] = $id;
04400                                                 $this->substNEWwithIDs_table[$NEW_id] = $table;
04401                                         }
04402 
04403                                                 // Checking the record is properly saved and writing to log
04404                                         if ($this->checkStoredRecords)  {
04405                                                 $newRow = $this->checkStoredRecord($table,$id,$fieldArray,1);
04406                                         }
04407 
04408                                                 // Update reference index:
04409                                         $this->updateRefIndex($table,$id);
04410 
04411                                         if ($newVersion)        {
04412                                                 $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);
04413                                         } else {
04414                                                 $propArr = $this->getRecordPropertiesFromRow($table,$newRow);
04415                                                 $page_propArr = $this->getRecordProperties('pages',$propArr['pid']);
04416                                                 $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);
04417 
04418                                                         // Clear cache for relavant pages:
04419                                                 $this->clear_cache($table,$id);
04420                                         }
04421 
04422                                         return $id;
04423                                 } else {
04424                                         $this->log($table,$id,1,0,2,"SQL error: '%s' (%s)",12,array($GLOBALS['TYPO3_DB']->sql_error(),$table.':'.$id));
04425                                 }
04426                         }
04427                 }
04428         }
04429 
04440         function checkStoredRecord($table,$id,$fieldArray,$action)      {
04441                 global $TCA;
04442 
04443                 $id = intval($id);
04444                 if (is_array($TCA[$table]) && $id)      {
04445                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($id));
04446                         if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
04447                                         // Traverse array of values that was inserted into the database and compare with the actually stored value:
04448                                 $errorString = array();
04449                                 foreach($fieldArray as $key => $value)  {
04450                                         if ($this->checkStoredRecords_loose && !$value && !$row[$key])  {
04451                                                 // Nothing...
04452                                         } elseif (strcmp($value,$row[$key]))    {
04453                                                 $errorString[] = $key;
04454                                         }
04455                                 }
04456 
04457                                         // Set log message if there were fields with unmatching values:
04458                                 if (count($errorString))        {
04459                                         $this->log($table,$id,$action,0,102,'These fields are not properly updated in database: ('.implode(',',$errorString).') Probably value mismatch with fieldtype.');
04460                                 }
04461 
04462                                         // Return selected rows:
04463                                 return $row;
04464                         }
04465                         $GLOBALS['TYPO3_DB']->sql_free_result($res);
04466                 }
04467         }
04468 
04477         function setHistory($table,$id,$logId)          {
04478                 if (isset($this->historyRecords[$table.':'.$id]))       {
04479 
04480                                 // Initialize settings:
04481                         list($tscPID) = t3lib_BEfunc::getTSCpid($table,$id,'');
04482                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
04483 
04484                         $tE = $this->getTableEntries($table,$TSConfig);
04485                         $maxAgeSeconds = 60*60*24*(strcmp($tE['history.']['maxAgeDays'],'') ? t3lib_div::intInRange($tE['history.']['maxAgeDays'],0,365) : 30); // one month
04486 
04487                                 // Garbage collect old entries:
04488                         $this->clearHistory($maxAgeSeconds, $table);
04489 
04490                                 // Set history data:
04491                                 $fields_values = array();
04492                                 $fields_values['history_data'] = serialize($this->historyRecords[$table.':'.$id]);
04493                                 $fields_values['fieldlist'] = implode(',',array_keys($this->historyRecords[$table.':'.$id]['newRecord']));
04494                                 $fields_values['tstamp'] = time();
04495                                 $fields_values['tablename'] = $table;
04496                                 $fields_values['recuid'] = $id;
04497                                 $fields_values['sys_log_uid'] = $logId;
04498 
04499                                 $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_history', $fields_values);
04500                         }
04501                 }
04502 
04510         function clearHistory($maxAgeSeconds=604800,$table)     {
04511                 $tstampLimit = $maxAgeSeconds ? time()-$maxAgeSeconds : 0;
04512 
04513                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_history', 'tstamp<'.intval($tstampLimit).' AND tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_history'));
04514                 }
04515 
04524         function updateRefIndex($table,$id)     {
04525                 $refIndexObj = t3lib_div::makeInstance('t3lib_refindex');
04526                 $result = $refIndexObj->updateRefIndexTable($table,$id);
04527         }
04528 
04529 
04530 
04531 
04532 
04533 
04534 
04535 
04536 
04537 
04538 
04539 
04540 
04541         /*********************************************
04542          *
04543          * Misc functions
04544          *
04545          ********************************************/
04546 
04556         function getSortNumber($table,$uid,$pid)        {
04557                 global $TCA;
04558                 if ($TCA[$table] && $TCA[$table]['ctrl']['sortby'])     {
04559                         $sortRow = $TCA[$table]['ctrl']['sortby'];
04560                         if ($pid>=0)    {       // Sorting number is in the top
04561                                 $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
04562                                 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {       // There was an element
04563                                         if ($row['uid']==$uid)  {       // The top record was the record it self, so we return its current sortnumber
04564                                                 return $row[$sortRow];
04565                                         }
04566                                         if ($row[$sortRow] < 1) {       // If the pages sortingnumber < 1 we must resort the records under this pid
04567                                                 $this->resorting($table,$pid,$sortRow,0);
04568                                                 return $this->sortIntervals;    // First sorting number after resorting
04569                                         } else {
04570                                                 return floor($row[$sortRow]/2); // Sorting number between current top element and zero
04571                                         }
04572                                 } else {        // No pages, so we choose the default value as sorting-number
04573                                         return $this->sortIntervals;    // First sorting number if no elements.
04574                                 }
04575                         } else {        // Sorting number is inside the list
04576                                 $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
04577                                 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {       // There was a record
04578 
04579                                                 // 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.
04580                                         if ($lookForLiveVersion = t3lib_BEfunc::getLiveVersionOfRecord($table,$row['uid'],$sortRow.',pid,uid')) {
04581                                                 $row =  $lookForLiveVersion;
04582                                         }
04583 
04584                                                 // If the record happends to be it self
04585                                         if ($row['uid']==$uid)  {
04586                                                 $sortNumber = $row[$sortRow];
04587                                         } else {
04588                                                 $subres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
04589                                                                                 $sortRow.',pid,uid',
04590                                                                                 $table,
04591                                                                                 'pid='.intval($row['pid']).' AND '.$sortRow.'>='.intval($row[$sortRow]).$this->deleteClause($table),
04592                                                                                 '',
04593                                                                                 $sortRow.' ASC',
04594                                                                                 '2'
04595                                                                         );              // Fetches the next record in order to calculate the in between sortNumber
04596                                                 if ($GLOBALS['TYPO3_DB']->sql_num_rows($subres)==2)     {       // There was a record afterwards
04597                                                         $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres);                         // Forward to the second result...
04598                                                         $subrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres);       // There was a record afterwards
04599                                                         $sortNumber = $row[$sortRow]+ floor(($subrow[$sortRow]-$row[$sortRow])/2);      // The sortNumber is found in between these values
04600                                                         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
04601                                                                 $sortNumber = $this->resorting($table,$row['pid'],$sortRow,  $row['uid']);      // By this special param, resorting reserves and returns the sortnumber after the uid
04602                                                         }
04603                                                 } else {        // If after the last record in the list, we just add the sortInterval to the last sortvalue
04604                                                         $sortNumber = $row[$sortRow]+$this->sortIntervals;
04605                                                 }
04606                                         }
04607                                         return Array('pid' => $row['pid'], 'sortNumber' => $sortNumber);
04608                                 } else {
04609                                         $propArr = $this->getRecordProperties($table,$uid);
04610                                         $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...
04611                                         return false;   // There MUST be a page or else this cannot work
04612                                 }
04613                         }
04614                 }
04615         }
04616 
04629         function resorting($table,$pid,$sortRow, $return_SortNumber_After_This_Uid) {
04630                 global $TCA;
04631                 if ($TCA[$table] && $sortRow && $TCA[$table]['ctrl']['sortby']==$sortRow)       {
04632                         $returnVal = 0;
04633                         $intervals = $this->sortIntervals;
04634                         $i = $intervals*2;
04635 
04636                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($pid).$this->deleteClause($table), '', $sortRow.' ASC');
04637                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
04638                                 $uid=intval($row['uid']);
04639                                 if ($uid)       {
04640                                         $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), array($sortRow=>$i));
04641                                         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
04642                                                 $i = $i+$intervals;
04643                                                 $returnVal=$i;
04644                                         }
04645                                 } else {die ('Fatal ERROR!! No Uid at resorting.');}
04646                                 $i = $i+$intervals;
04647                         }
04648                         return $returnVal;
04649                 }
04650         }
04651 
04660         function setTSconfigPermissions($fieldArray,$TSConfig_p)        {
04661                 if (strcmp($TSConfig_p['userid'],''))   $fieldArray['perms_userid']=intval($TSConfig_p['userid']);
04662                 if (strcmp($TSConfig_p['groupid'],''))  $fieldArray['perms_groupid']=intval($TSConfig_p['groupid']);
04663                 if (strcmp($TSConfig_p['user'],''))                     $fieldArray['perms_user']=t3lib_div::testInt($TSConfig_p['user']) ? $TSConfig_p['user'] : $this->assemblePermissions($TSConfig_p['user']);
04664                 if (strcmp($TSConfig_p['group'],''))            $fieldArray['perms_group']=t3lib_div::testInt($TSConfig_p['group']) ? $TSConfig_p['group'] : $this->assemblePermissions($TSConfig_p['group']);
04665                 if (strcmp($TSConfig_p['everybody'],''))        $fieldArray['perms_everybody']=t3lib_div::testInt($TSConfig_p['everybody']) ? $TSConfig_p['everybody'] : $this->assemblePermissions($TSConfig_p['everybody']);
04666 
04667                 return $fieldArray;
04668         }
04669 
04677         function newFieldArray($table)  {
04678                 global $TCA;
04679 
04680                 t3lib_div::loadTCA($table);
04681                 $fieldArray=Array();
04682                 if (is_array($TCA[$table]['columns']))  {
04683                         reset ($TCA[$table]['columns']);
04684                         while (list($field,$content)=each($TCA[$table]['columns']))     {
04685                                 if (isset($this->defaultValues[$table][$field]))        {
04686                                         $fieldArray[$field] = $this->defaultValues[$table][$field];
04687                                 } elseif (isset($content['config']['default'])) {
04688                                         $fieldArray[$field] = $content['config']['default'];
04689                                 }
04690                         }
04691                 }
04692                 if ($table==='pages')   {               // Set default permissions for a page.
04693                         $fieldArray['perms_userid'] = $this->userid;
04694                         $fieldArray['perms_groupid'] = intval($this->BE_USER->firstMainGroup);
04695                         $fieldArray['perms_user'] = $this->assemblePermissions($this->defaultPermissions['user']);
04696                         $fieldArray['perms_group'] = $this->assemblePermissions($this->defaultPermissions['group']);
04697                         $fieldArray['perms_everybody'] = $this->assemblePermissions($this->defaultPermissions['everybody']);
04698                 }
04699                 return $fieldArray;
04700         }
04701 
04709         function addDefaultPermittedLanguageIfNotSet($table,&$incomingFieldArray)       {
04710                 global $TCA;
04711 
04712                         // Checking languages:
04713                 if ($TCA[$table]['ctrl']['languageField'])      {
04714                         if (!isset($incomingFieldArray[$TCA[$table]['ctrl']['languageField']])) {       // Language field must be found in input row - otherwise it does not make sense.
04715                                 $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)));
04716                                 foreach($rows as $r)    {
04717                                         if ($this->BE_USER->checkLanguageAccess($r['uid']))             {
04718                                                 $incomingFieldArray[$TCA[$table]['ctrl']['languageField']] = $r['uid'];
04719                                                 break;
04720                                         }
04721                                 }
04722                         }
04723                 }
04724         }
04725 
04733         function overrideFieldArray($table,$data)       {
04734                 if (is_array($this->overrideValues[$table]))    {
04735                         $data = array_merge($data,$this->overrideValues[$table]);
04736                 }
04737                 return $data;
04738         }
04739 
04749         function compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray)   {
04750 
04751                         // Fetch the original record:
04752                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($id));
04753                 $currentRecord = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
04754 
04755                         // If the current record exists (which it should...), begin comparison:
04756                 if (is_array($currentRecord))   {
04757 
04758                                 // Read all field types:
04759                         $c = 0;
04760                         $cRecTypes = array();
04761                         foreach($currentRecord as $col => $val) {
04762                                 $cRecTypes[$col] = $GLOBALS['TYPO3_DB']->sql_field_type($res,$c);
04763                                 $c++;
04764                         }
04765 
04766                                 // Free result:
04767                         $GLOBALS['TYPO3_DB']->sql_free_result($res);
04768 
04769                                 // Unset the fields which are similar:
04770                         foreach($fieldArray as $col => $val)    {
04771                                 if (
04772                                                 !strcmp($val,$currentRecord[$col]) ||   // Unset fields which matched exactly.
04773                                                 ($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.
04774                                         )       {
04775                                         unset($fieldArray[$col]);
04776                                 } else {
04777                                         $this->historyRecords[$table.':'.$id]['oldRecord'][$col] = $currentRecord[$col];
04778                                         $this->historyRecords[$table.':'.$id]['newRecord'][$col] = $fieldArray[$col];
04779                                 }
04780                         }
04781                 } else {        // If the current record does not exist this is an error anyways and we just return an empty array here.
04782                         $fieldArray = array();
04783                 }
04784 
04785                 return $fieldArray;
04786         }
04787 
04795         function assemblePermissions($string)   {
04796                 $keyArr = t3lib_div::trimExplode(',',$string,1);
04797                 $value=0;
04798                 while(list(,$key)=each($keyArr))        {
04799                         if ($key && isset($this->pMap[$key]))   {
04800                                 $value |= $this->pMap[$key];
04801                         }
04802                 }
04803                 return $value;
04804         }
04805 
04812         function rmComma($input)        {
04813                 return ereg_replace(',$','',$input);
04814         }
04815 
04822         function convNumEntityToByteValue($input)       {
04823                 $token = md5(microtime());
04824                 $parts = explode($token,ereg_replace('(&#([0-9]+);)',$token.'\2'.$token,$input));
04825 
04826                 foreach($parts as $k => $v)     {
04827                         if ($k%2)       {
04828                                 $v = intval($v);
04829                                 if ($v > 32)    {       // Just to make sure that control bytes are not converted.
04830                                         $parts[$k] =chr(intval($v));
04831                                 }
04832                         }
04833                 }
04834 
04835                 return implode('',$parts);
04836         }
04837 
04844         function destPathFromUploadFolder($folder)      {
04845                 return PATH_site.$folder;
04846         }
04847 
04854         function deleteClause($table)   {
04855                         // Returns the proper delete-clause if any for a table from TCA
04856                 global $TCA;
04857                 if ($TCA[$table]['ctrl']['delete'])     {
04858                         return ' AND '.$table.'.'.$TCA[$table]['ctrl']['delete'].'=0';
04859                 } else {
04860                         return '';
04861                 }
04862         }
04863 
04870         function getTCEMAIN_TSconfig($tscPID)   {
04871                 if (!isset($this->cachedTSconfig[$tscPID]))     {
04872                         $this->cachedTSconfig[$tscPID] = $this->BE_USER->getTSConfig('TCEMAIN',t3lib_BEfunc::getPagesTSconfig($tscPID));
04873                 }
04874                 return $this->cachedTSconfig[$tscPID]['properties'];
04875         }
04876 
04885         function getTableEntries($table,$TSconfig)      {
04886                 $tA = is_array($TSconfig['table.'][$table.'.']) ? $TSconfig['table.'][$table.'.'] : array();;
04887                 $dA = is_array($TSconfig['default.']) ? $TSconfig['default.'] : array();
04888                 return t3lib_div::array_merge_recursive_overrule($dA,$tA);
04889         }
04890 
04898         function getPID($table,$uid)    {
04899                 $res_tmp = $GLOBALS['TYPO3_DB']->exec_SELECTquery('pid', $table, 'uid='.intval($uid));
04900                 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp))     {
04901                         return $row['pid'];
04902                 }
04903         }
04904 
04911         function dbAnalysisStoreExec()  {
04912                 reset($this->dbAnalysisStore);
04913                 while(list($k,$v)=each($this->dbAnalysisStore)) {
04914                         $id = $this->substNEWwithIDs[$v[2]];
04915                         if ($id)        {
04916                                 $v[2] = $id;
04917                                 $v[0]->writeMM($v[1],$v[2],$v[3]);
04918                         }
04919                 }
04920         }
04921 
04927         function removeRegisteredFiles()        {
04928                 reset($this->removeFilesStore);
04929                 while(list($k,$v)=each($this->removeFilesStore))        {
04930                         unlink($v);
04931                 }
04932         }
04933 
04939         function removeCacheFiles()     {
04940                 return t3lib_extMgm::removeCacheFiles();
04941         }
04942 
04953         function int_pageTreeInfo($CPtable,$pid,$counter, $rootID)      {
04954                 if ($counter)   {
04955                         $addW =  !$this->admin ? ' AND '.$this->BE_USER->getPagePermsClause($this->pMap['show']) : '';
04956                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'pid='.intval($pid).$this->deleteClause('pages').$addW, '', 'sorting DESC');
04957                         while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))      {
04958                                 if ($row['uid']!=$rootID)       {
04959                                         $CPtable[$row['uid']] = $pid;
04960                                         if ($counter-1) {       // If the uid is NOT the rootID of the copyaction and if we are supposed to walk further down
04961                                                 $CPtable = $this->int_pageTreeInfo($CPtable,$row['uid'],$counter-1, $rootID);
04962                                         }
04963                                 }
04964                         }
04965                 }
04966                 return $CPtable;
04967         }
04968 
04974         function compileAdminTables()   {
04975                 global $TCA;
04976                 reset ($TCA);
04977                 $listArr = array();
04978                 while (list($table)=each($TCA)) {
04979                         $listArr[]=$table;
04980                 }
04981                 return $listArr;
04982         }
04983 
04991         function fixUniqueInPid($table,$uid)    {
04992                 global $TCA;
04993                 if ($TCA[$table])       {
04994                         t3lib_div::loadTCA($table);
04995                         reset ($TCA[$table]['columns']);
04996                         $curData=$this->recordInfo($table,$uid,'*');
04997                         $newData=array();
04998                         while (list($field,$conf)=each($TCA[$table]['columns']))        {
04999                                 if ($conf['config']['type']=='input')   {
05000                                         $evalCodesArray = t3lib_div::trimExplode(',',$conf['config']['eval'],1);
05001                                         if (in_array('uniqueInPid',$evalCodesArray))    {
05002                                                 $newV = $this->getUnique($table,$field,$curData[$field],$uid,$curData['pid']);
05003                                                 if (strcmp($newV,$curData[$field]))     {
05004                                                         $newData[$field]=$newV;
05005                                                 }
05006                                         }
05007                                 }
05008                         }
05009                                 // IF there are changed fields, then update the database
05010                         if (count($newData))    {
05011                                 $this->updateDB($table,$uid,$newData);
05012                         }
05013                 }
05014         }
05015 
05027         function fixCopyAfterDuplFields($table,$uid,$prevUid,$update, $newData=array()) {
05028                 global $TCA;
05029                 if ($TCA[$table] && $TCA[$table]['ctrl']['copyAfterDuplFields'])        {
05030                         t3lib_div::loadTCA($table);
05031                         $prevData=$this->recordInfo($table,$prevUid,'*');
05032                         $theFields = t3lib_div::trimExplode(',',$TCA[$table]['ctrl']['copyAfterDuplFields'],1);
05033                         reset($theFields);
05034                         while(list(,$field)=each($theFields))   {
05035                                 if ($TCA[$table]['columns'][$field] && ($update || !isset($newData[$field])))   {
05036                                         $newData[$field]=$prevData[$field];
05037                                 }
05038                         }
05039                         if ($update && count($newData)) {
05040                                 $this->updateDB($table,$uid,$newData);
05041                         }
05042                 }
05043                 return $newData;
05044         }
05045 
05052         function extFileFields($table)  {
05053                 global $TCA;
05054                 $listArr=array();
05055                 t3lib_div::loadTCA($table);
05056                 if ($TCA[$table]['columns'])    {
05057                         reset($TCA[$table]['columns']);
05058                         while (list($field,$configArr)=each($TCA[$table]['columns']))   {
05059                                 if ($configArr['config']['type']=='group' && $configArr['config']['internal_type']=='file')     {
05060                                         $listArr[]=$field;
05061                                 }
05062                         }
05063                 }
05064                 return $listArr;
05065         }
05066 
05073         function getUniqueFields($table)        {
05074                 global $TCA;
05075 
05076                 $listArr=array();
05077                 t3lib_div::loadTCA($table);
05078                 if ($TCA[$table]['columns'])    {
05079                         reset($TCA[$table]['columns']);
05080                         while (list($field,$configArr)=each($TCA[$table]['columns']))   {
05081                                 if ($configArr['config']['type']==='input')     {
05082                                         $evalCodesArray = t3lib_div::trimExplode(',',$configArr['config']['eval'],1);
05083                                         if (in_array('uniqueInPid',$evalCodesArray) || in_array('unique',$evalCodesArray))      {
05084                                                 $listArr[]=$field;
05085                                         }
05086                                 }
05087                         }
05088                 }
05089                 return $listArr;
05090         }
05091 
05098         function isReferenceField($conf)        {
05099                 return ($conf['type']=='group' && $conf['internal_type']=='db') ||      ($conf['type']=='select' && $conf['foreign_table']);
05100         }
05101 
05113         function getCopyHeader($table,$pid,$field,$value,$count,$prevTitle='')  {
05114                 global $TCA;
05115 
05116                         // Set title value to check for:
05117                 if ($count)     {
05118                         $checkTitle = $value.rtrim(' '.sprintf($this->prependLabel($table),$count));
05119                 }       else {
05120                         $checkTitle = $value;
05121                 }
05122 
05123                         // Do check:
05124                 if ($prevTitle != $checkTitle || $count<100)    {
05125                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($pid).' AND '.$field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($checkTitle, $table).$this->deleteClause($table), '', '', '1');
05126                         if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
05127                                 return $this->getCopyHeader($table,$pid,$field,$value,$count+1,$checkTitle);
05128                         }
05129                 }
05130 
05131                         // Default is to just return the current input title if no other was returned before:
05132                 return $checkTitle;
05133         }
05134 
05142         function prependLabel($table)   {
05143                 global $TCA;
05144                 if (is_object($GLOBALS['LANG']))        {
05145                         $label = $GLOBALS['LANG']->sL($TCA[$table]['ctrl']['prependAtCopy']);
05146                 } else {
05147                         list($label) = explode('|',$TCA[$table]['ctrl']['prependAtCopy']);
05148                 }
05149                 return $label;
05150         }
05151 
05159         function resolvePid($table,$pid)        {
05160                 global $TCA;
05161                 $pid = intval($pid);
05162                 if ($pid < 0)   {
05163                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('pid', $table, 'uid='.abs($pid));
05164                         $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
05165 
05166                                 // 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.
05167                         if ($lookForLiveVersion = t3lib_BEfunc::getLiveVersionOfRecord($table,abs($pid),'pid')) {
05168                                 $row = $lookForLiveVersion;
05169                         }
05170 
05171                         $pid = intval($row['pid']);
05172                 } 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.
05173                         if ($WSdestPage = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, 'pages', $pid, 'uid,t3ver_swapmode'))    {       // Looks for workspace version of page.
05174                                 if ($WSdestPage['t3ver_swapmode']==0)   {       // if swapmode is zero, then change pid value.
05175                                         $pid = $WSdestPage['uid'];
05176                                 }
05177                         }
05178                 }
05179                 return $pid;
05180         }
05181 
05189         function clearPrefixFromValue($table,$value)    {
05190                 global $TCA;
05191                 $regex = sprintf(quotemeta($this->prependLabel($table)),'[0-9]*').'$';
05192                 return @ereg_replace($regex,'',$value);
05193         }
05194 
05204         function extFileFunctions($table,$field,$filelist,$func)        {
05205                 global $TCA;
05206                 t3lib_div::loadTCA($table);
05207                 $uploadFolder = $TCA[$table]['columns'][$field]['config']['uploadfolder'];
05208                 if ($uploadFolder && trim($filelist))   {
05209                         $uploadPath = $this->destPathFromUploadFolder($uploadFolder);
05210                         $fileArray = explode(',',$filelist);
05211                         while (list(,$theFile)=each($fileArray))        {
05212                                 $theFile=trim($theFile);
05213                                 if ($theFile)   {
05214                                         switch($func)   {
05215                                                 case 'deleteAll':
05216                                                         if (@is_file($uploadPath.'/'.$theFile)) {
05217                                                                 unlink ($uploadPath.'/'.$theFile);
05218                                                         } else {
05219                                                                 $this->log($table,0,3,0,100,"Delete: Referenced file that was supposed to be deleted together with it's record didn't exist");
05220                                                         }
05221                                                 break;
05222                                         }
05223                                 }
05224                         }
05225                 }
05226         }
05227 
05234         function noRecordsFromUnallowedTables($inList)  {
05235                 global $TCA;
05236                 reset ($TCA);
05237                 $inList = trim($this->rmComma(trim($inList)));
05238                 if ($inList && !$this->admin)   {
05239                         while (list($table) = each($TCA))       {
05240                                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', $table, 'pid IN ('.$inList.')'.t3lib_BEfunc::deleteClause($table));
05241                                 $count = $GLOBALS['TYPO3_DB']->sql_fetch_row($mres);
05242                                 if ($count[0] && ($this->tableReadOnly($table) || !$this->checkModifyAccessList($table)))       {
05243                                         return FALSE;
05244                                 }
05245                         }
05246                 }
05247                 return TRUE;
05248         }
05249 
05260         function notifyStageChange($stat,$stageId,$table,$id,$comment)  {
05261                 $workspaceRec = t3lib_BEfunc::getRecord('sys_workspace', $stat['uid']);
05262 
05263                 if (is_array($workspaceRec))    {
05264 
05265                                 // Compile label:
05266                         switch((int)$stageId)   {
05267                                 case 1:
05268                                         $newStage = 'Ready for review';
05269                                 break;
05270                                 case 10:
05271                                         $newStage = 'Ready for publishing';
05272                                 break;
05273                                 case -1:
05274                                         $newStage = 'Element was rejected!';
05275                                 break;
05276                                 case 0:
05277                                         $newStage = 'Rejected element was noticed and edited';
05278                                 break;
05279                                 default:
05280                                         $newStage = 'Unknown state change!?';
05281                                 break;
05282                         }
05283 
05284                                 // Compile list of recipients:
05285                         $emails = array();
05286                         switch((int)$stat['stagechg_notification'])     {
05287                                 case 1:
05288                                         switch((int)$stageId)   {
05289                                                 case 1:
05290                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['reviewers']);
05291                                                 break;
05292                                                 case 10:
05293                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['adminusers'], TRUE);
05294                                                 break;
05295                                                 case -1:
05296                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['reviewers']);
05297                                                         $emails = array_merge($emails,$this->notifyStageChange_getEmails($workspaceRec['members']));
05298                                                 break;
05299                                                 case 0:
05300                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['members']);
05301                                                 break;
05302                                                 default:
05303                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['adminusers'], TRUE);
05304                                                 break;
05305                                         }
05306                                 break;
05307                                 case 10:
05308                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['adminusers'], TRUE);
05309                                         $emails = array_merge($emails,$this->notifyStageChange_getEmails($workspaceRec['reviewers']));
05310                                         $emails = array_merge($emails,$this->notifyStageChange_getEmails($workspaceRec['members']));
05311                                 break;
05312                         }
05313                         $emails = array_unique($emails);
05314 
05315                                 // Send email:
05316                         if (count($emails))     {
05317                                 $message = sprintf('
05318 At the TYPO3 site "%s" (%s)
05319 in workspace "%s" (#%s)
05320 the stage has changed for the element "%s":
05321 
05322 ==> %s
05323 
05324 User Comment:
05325 "%s"
05326 
05327 State was change by %s (username: %s)
05328                                 ',
05329                                 $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'],
05330                                 t3lib_div::getIndpEnv('TYPO3_SITE_URL').TYPO3_mainDir,
05331                                 $workspaceRec['title'],
05332                                 $workspaceRec['uid'],
05333                                 $table.':'.$id,
05334                                 $newStage,
05335                                 $comment,
05336                                 $this->BE_USER->user['realName'],
05337                                 $this->BE_USER->user['username']);
05338 
05339                                 t3lib_div::plainMailEncoded(
05340                                         implode(',',$emails),
05341                                         'TYPO3 Workspace Note: Stage Change for '.$table.':'.$id,
05342                                         trim($message)
05343                                 );
05344                         }
05345                 }
05346         }
05347 
05355         function notifyStageChange_getEmails($listOfUsers,$noTablePrefix=FALSE) {
05356                 $users = t3lib_div::trimExplode(',',$listOfUsers,1);
05357                 $emails = array();
05358                 foreach($users as $userIdent)   {
05359                         if ($noTablePrefix)     {
05360                                 $id = intval($userIdent);
05361                         } else {
05362                                 list($table,$id) = t3lib_div::revExplode('_',$userIdent,2);
05363                         }
05364                         if ($table==='be_users' || $noTablePrefix)      {
05365                                 if ($userRecord = t3lib_BEfunc::getRecord('be_users', $id, 'email'))    {
05366                                         if (strlen(trim($userRecord['email']))) {
05367                                                 $emails[$id] = $userRecord['email'];
05368                                         }
05369                                 }
05370                         }
05371                 }
05372                 return $emails;
05373         }
05374 
05375 
05376 
05377 
05378 
05379 
05380 
05381 
05382 
05383 
05384 
05385 
05386         /******************************
05387          *
05388          * Clearing cache
05389          *
05390          ******************************/
05391 
05401         function clear_cache($table,$uid) {
05402                 global $TCA, $TYPO3_CONF_VARS;
05403 
05404                 $uid = intval($uid);
05405                 if (is_array($TCA[$table]) && $uid > 0) {
05406 
05407                                 // Get Page TSconfig relavant:
05408                         list($tscPID) = t3lib_BEfunc::getTSCpid($table,$uid,'');
05409                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
05410 
05411                         if (!$TSConfig['clearCache_disable'])   {
05412 
05413                                         // If table is "pages":
05414                                 if (t3lib_extMgm::isLoaded('cms'))      {
05415                                         $list_cache = array();
05416                                         if ($table=='pages')    {
05417 
05418                                                         // Builds list of pages on the SAME level as this page (siblings)
05419                                                 $res_tmp = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
05420                                                                                 'A.pid AS pid, B.uid AS uid',
05421                                                                                 'pages A, pages B',
05422                                                                                 'A.uid='.intval($uid).' AND B.pid=A.pid AND B.deleted=0'
05423                                                                         );
05424 
05425                                                 $pid_tmp = 0;
05426                                                 while ($row_tmp = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp)) {
05427                                                         $list_cache[] = $row_tmp['uid'];
05428                                                         $pid_tmp = $row_tmp['pid'];
05429 
05430                                                                 // Add children as well:
05431                                                         if ($TSConfig['clearCache_pageSiblingChildren'])        {
05432                                                                 $res_tmp2 = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
05433                                                                                                 'uid',
05434                                                                                                 'pages',
05435                                                                                                 'pid='.intval($row_tmp['uid']).' AND deleted=0'
05436                                                                                         );
05437                                                                 while ($row_tmp2 = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp2))    {
05438                                                                         $list_cache[] = $row_tmp2['uid'];
05439                                                                 }
05440                                                         }
05441                                                 }
05442 
05443                                                         // Finally, add the parent page as well:
05444                                                 $list_cache[] = $pid_tmp;
05445 
05446                                                         // Add grand-parent as well:
05447                                                 if ($TSConfig['clearCache_pageGrandParent'])    {
05448                                                         $res_tmp = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
05449                                                                                         'pid',
05450                                                                                         'pages',
05451                                                                                         'uid='.intval($pid_tmp)
05452                                                                                 );
05453                                                         if ($row_tmp = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp)) {
05454                                                                 $list_cache[] = $row_tmp['pid'];
05455                                                         }
05456                                                 }
05457                                         } else {        // For other tables than "pages", delete cache for the records "parent page".
05458                                                 $list_cache[] = intval($this->getPID($table,$uid));
05459                                         }
05460 
05461                                                 // Call pre-processing function for clearing of cache for page ids:
05462                                         if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval']))    {
05463                                                 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval'] as $funcName)     {
05464                                                         $_params = array('pageIdArray' => &$list_cache, 'table' => $table, 'uid' => $uid, 'functionID' => 'clear_cache()');
05465                                                                 // Returns the array of ids to clear, false if nothing should be cleared! Never an empty array!
05466                                                         t3lib_div::callUserFunction($funcName,$_params,$this);
05467                                                 }
05468                                         }
05469 
05470                                                 // Delete cache for selected pages:
05471                                         if (is_array($list_cache))      {
05472                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')');
05473                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection', 'page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')');
05474                                         }
05475                                 }
05476                         }
05477 
05478                                 // Clear cache for pages entered in TSconfig:
05479                         if ($TSConfig['clearCacheCmd']) {
05480                                 $Commands = t3lib_div::trimExplode(',',strtolower($TSConfig['clearCacheCmd']),1);
05481                                 $Commands = array_unique($Commands);
05482                                 foreach($Commands as $cmdPart)  {
05483                                         $this->clear_cacheCmd($cmdPart);
05484                                 }
05485                         }
05486 
05487                                 // Call post processing function for clear-cache:
05488                         global $TYPO3_CONF_VARS;
05489                         if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc']))    {
05490 // FIXME $uid_page is undefined
05491                                 $_params = array('table' => $table,'uid' => $uid,'uid_page' => $uid_page,'TSConfig' => $TSConfig);
05492                                 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'] as $_funcRef)     {
05493                                         t3lib_div::callUserFunction($_funcRef,$_params,$this);
05494                                 }
05495                         }
05496                 }
05497         }
05498 
05511         function clear_cacheCmd($cacheCmd)      {
05512                 global $TYPO3_CONF_VARS;
05513 
05514                         // Clear cache for either ALL pages or ALL tables!
05515                 switch($cacheCmd)       {
05516                         case 'pages':
05517                                 if ($this->admin || $this->BE_USER->getTSConfigVal('options.clearCache.pages')) {
05518                                         if (t3lib_extMgm::isLoaded('cms'))      {
05519                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','');
05520                                         }
05521                                 }
05522                         break;
05523                         case 'all':
05524                                 if ($this->admin || $this->BE_USER->getTSConfigVal('options.clearCache.all'))   {
05525                                         if (t3lib_extMgm::isLoaded('cms'))      {
05526                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','');
05527                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection','');
05528                                         }
05529                                         $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_hash','');
05530 
05531                                                 // Clearing additional cache tables:
05532                                         if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearAllCache_additionalTables']))        {
05533                                                 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearAllCache_additionalTables'] as $tableName)        {
05534                                                         if (!ereg('[^[:alnum:]_]',$tableName) && substr($tableName,-5)=='cache')        {
05535                                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery($tableName,'');
05536                                                         } else {
05537                                                                 die('Fatal Error: Trying to flush table "'.$tableName.'" with "Clear All Cache"');
05538                                                         }
05539                                                 }
05540                                         }
05541                                 }
05542                         break;
05543                         case 'temp_CACHED':
05544                                 if ($this->admin && $TYPO3_CONF_VARS['EXT']['extCache'])        {
05545                                         $this->removeCacheFiles();
05546                                 }
05547                         break;
05548                 }
05549 
05550                         // Clear cache for a page ID!
05551                 if (t3lib_div::testInt($cacheCmd))      {
05552                         if (t3lib_extMgm::isLoaded('cms'))      {
05553 
05554                                 $list_cache = array($cacheCmd);
05555 
05556                                         // Call pre-processing function for clearing of cache for page ids:
05557                                 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval']))    {
05558                                         foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval'] as $funcName)     {
05559                                                 $_params = array('pageIdArray' => &$list_cache, 'cacheCmd' => $cacheCmd, 'functionID' => 'clear_cacheCmd()');
05560                                                         // Returns the array of ids to clear, false if nothing should be cleared! Never an empty array!
05561                                                 t3lib_div::callUserFunction($funcName,$_params,$this);
05562                                         }
05563                                 }
05564 
05565                                         // Delete cache for selected pages:
05566                                 if (is_array($list_cache))      {
05567                                         $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')');
05568                                         $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!
05569                                 }
05570                         }
05571                 }
05572 
05573                         // Call post processing function for clear-cache:
05574                 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc']))    {
05575                         $_params = array('cacheCmd'=>$cacheCmd);
05576                         foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'] as $_funcRef)     {
05577                                 t3lib_div::callUserFunction($_funcRef,$_params,$this);
05578                         }
05579                 }
05580         }
05581 
05582 
05583 
05584 
05585 
05586 
05587 
05588 
05589 
05590 
05591 
05592 
05593 
05594 
05595         /*****************************
05596          *
05597          * Logging
05598          *
05599          *****************************/
05600 
05617         function log($table,$recuid,$action,$recpid,$error,$details,$details_nr=-1,$data=array(),$event_pid=-1,$NEWid='') {
05618                 if ($this->enableLogging)       {
05619                         $type=1;        // Type value for tce_db.php
05620                         if (!$this->storeLogMessages)   {$details='';}
05621                         if ($error>0)   $this->errorLog[] = '['.$type.'.'.$action.'.'.$details_nr.']: '.$details;
05622                         return $this->BE_USER->writelog($type,$action,$error,$details_nr,$details,$data,$table,$recuid,$recpid,$event_pid,$NEWid);
05623                 }
05624         }
05625 
05634         function newlog($message, $error=0)     {
05635                 return $this->log('',0,0,0,$error,$message,-1);
05636         }
05637 
05644         function printLogErrorMessages($redirect)       {
05645 
05646                 $res_log = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
05647                                         '*',
05648                                         'sys_log',
05649                                         'type=1 AND userid='.intval($this->BE_USER->user['uid']).' AND tstamp='.intval($GLOBALS['EXEC_TIME']).' AND error!=0'
05650                                 );
05651                 $errorJS = array();
05652                 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_log)) {
05653                         $log_data = unserialize($row['log_data']);
05654                         $errorJS[] = $row['error'].': '.sprintf($row['details'], $log_data[0],$log_data[1],$log_data[2],$log_data[3],$log_data[4]);
05655                 }
05656 
05657                 if (count($errorJS))    {
05658                         $error_doc = t3lib_div::makeInstance('template');
05659                         $error_doc->backPath = $GLOBALS['BACK_PATH'];
05660 
05661                         $content.= $error_doc->startPage('tce_db.php Error output');
05662 
05663                         $lines[] = '
05664                                         <tr class="bgColor5">
05665                                                 <td colspan="2" align="center"><strong>Errors:</strong></td>
05666                                         </tr>';
05667 
05668                         foreach($errorJS as $line)      {
05669                                 $lines[] = '
05670                                         <tr class="bgColor4">
05671                                                 <td valign="top"><img'.t3lib_iconWorks::skinImg($error_doc->backPath,'gfx/icon_fatalerror.gif','width="18" height="16"').' alt="" /></td>
05672                                                 <td>'.htmlspecialchars($line).'</td>
05673                                         </tr>';
05674                         }
05675 
05676                         $lines[] = '
05677                                         <tr>
05678                                                 <td colspan="2" align="center"><br />'.
05679                                                 '<form action=""><input type="submit" value="Continue" onclick="'.htmlspecialchars('window.location.href=\''.$redirect.'\';return false;').'"></form>'.
05680                                                 '</td>
05681                                         </tr>';
05682 
05683                         $content.= '
05684                                 <br/><br/>
05685                                 <table border="0" cellpadding="1" cellspacing="1" width="300" align="center">
05686                                         '.implode('',$lines).'
05687                                 </table>';
05688 
05689                         $content.= $error_doc->endPage();
05690                         echo $content;
05691                         exit;
05692                 }
05693         }
05694 }
05695 
05696 
05697 
05698 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tcemain.php'])   {
05699         include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tcemain.php']);
05700 }
05701 ?>


Généré par Les experts TYPO3 avec  doxygen 1.4.6