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 ***************************************************************/
00203 // *******************************
00204 // Including necessary libraries
00205 // *******************************
00206 require_once (PATH_t3lib.'class.t3lib_loaddbgroup.php');
00207 require_once (PATH_t3lib.'class.t3lib_parsehtml_proc.php');
00208 require_once (PATH_t3lib.'class.t3lib_stdgraphic.php');
00209 require_once (PATH_t3lib.'class.t3lib_basicfilefunc.php');
00210 require_once (PATH_t3lib.'class.t3lib_refindex.php');
00211 require_once (PATH_t3lib.'class.t3lib_flexformtools.php');
00212 
00213 
00214 
00215 
00216 
00217 
00218 
00219 
00220 
00221 
00222 
00237 class t3lib_TCEmain     {
00238 
00239 
00240                 // *********************
00241                 // Public variables you can configure before using the class:
00242                 // *********************
00243 
00244         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.
00245         var $enableLogging = TRUE;                              // Boolean: If true, actions are logged to sys_log.
00246         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.
00247         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.
00248         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!
00249         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
00250         var $checkStoredRecords_loose = TRUE;   // Boolean: If set, values '' and 0 will equal each other when the stored records are checked.
00251         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
00252         var $neverHideAtCopy = FALSE;                   // Boolean. If set, then the 'hideAtCopy' flag for tables will be ignored.
00253         var $dontProcessTransformations = FALSE;        // Boolean: If set, then transformations are NOT performed on the input.
00254         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!
00255         var $bypassFileHandling = FALSE;                        // Boolean: If true, file handling of attached files (addition, deletion etc) is bypassed - the value is saved straight away. YOU MUST KNOW what you are doing with this feature!
00256         var $bypassAccessCheckForRecords = FALSE;       // Boolean: If true, access check, check for deleted etc. for records is bypassed. YOU MUST KNOW what you are doing if you use this feature!
00257 
00258         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)
00259         var $generalComment = '';                               // General comment, eg. for staging in workspaces.
00260 
00261         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
00262 
00263         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)
00264         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!
00265         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.
00266         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.
00267         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)
00268 
00269         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.
00270 
00271 
00272 
00273 
00274                 // *********************
00275                 // Internal variables (mapping arrays) which can be used (read-only) from outside
00276                 // *********************
00277         var $autoVersionIdMap = Array();                        // Contains mapping of auto-versionized records.
00278         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
00279         var $substNEWwithIDs_table = Array();           // Like $substNEWwithIDs, but where each old "NEW..." id is mapped to the table it was from.
00280         var $newRelatedIDs = Array();                           // Holds the tables and there the ids of newly created child records from IRRE
00281         var $copyMappingArray_merged = Array();         // This array is the sum of all copying operations in this class. May be READ from outside, thus partly public.
00282         var $copiedFileMap = Array();                           // A map between input file name and final destination for files being attached to records.
00283         var     $errorLog = Array();                                    // Errors are collected in this variable.
00284 
00285 
00286 
00287                 // *********************
00288                 // Internal Variables, do not touch.
00289                 // *********************
00290 
00291                 // Variables set in init() function:
00292         var $BE_USER;           // The user-object the script uses. If not set from outside, this is set to the current global $BE_USER.
00293         var $userid;            // will be set to uid of be_user executing this script
00294         var $username;          // will be set to username of be_user executing this script
00295         var $admin;                     // will be set if user is admin
00296 
00297         var $defaultPermissions = array(                // Can be overridden from $TYPO3_CONF_VARS
00298                 'user' => 'show,edit,delete,new,editcontent',
00299                 'group' => 'show,edit,new,editcontent',
00300                 'everybody' => ''
00301         );
00302 
00303         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.
00304         var $datamap = Array();         // Set with incoming data array
00305         var $cmdmap = Array();          // Set with incoming cmd array
00306 
00307                 // Internal static:
00308         var $pMap = Array(              // Permission mapping
00309                 'show' => 1,                    // 1st bit
00310                 'edit' => 2,                    // 2nd bit
00311                 'delete' => 4,                  // 3rd bit
00312                 'new' => 8,                             // 4th bit
00313                 'editcontent' => 16             // 5th bit
00314         );
00315         var $sortIntervals = 256;                                       // Integer: The interval between sorting numbers used with tables with a 'sorting' field defined. Min 1
00316 
00317                 // Internal caching arrays
00318         var $recUpdateAccessCache = Array();            // Used by function checkRecordUpdateAccess() to store whether a record is updateable or not.
00319         var $recInsertAccessCache = Array();            // User by function checkRecordInsertAccess() to store whether a record can be inserted on a page id
00320         var $isRecordInWebMount_Cache=array();          // Caching array for check of whether records are in a webmount
00321         var $isInWebMount_Cache=array();                        // Caching array for page ids in webmounts
00322         var $cachedTSconfig = array();                          // Caching for collecting TSconfig for page ids
00323         var $pageCache = Array();                                       // Used for caching page records in pageInfo()
00324         var $checkWorkspaceCache = Array();                     // Array caching workspace access for BE_USER
00325 
00326                 // Other arrays:
00327         var $dbAnalysisStore=array();                           // For accumulation of MM relations that must be written after new records are created.
00328         var $removeFilesStore=array();                          // For accumulation of files which must be deleted after processing of all input content
00329         var $uploadedFileArray = array();                       // Uploaded files, set by process_uploads()
00330         var $registerDBList=array();                            // Used for tracking references that might need correction after operations
00331         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.
00332         var $remapStack = array();                                      // array used for remapping uids and values at the end of process_datamap
00333         var $updateRefIndexStack = array();                     // array used for additional calls to $this->updateRefIndex
00334         var $callFromImpExp = false;                            // tells, that this TCEmain was called from tx_impext - this variable is set by tx_impexp
00335 
00336                 // Various
00337         var $fileFunc;                                                          // For "singleTon" file-manipulation object
00338         var $checkValue_currentRecord=array();          // Set to "currentRecord" during checking of values.
00339         var $autoVersioningUpdate = FALSE;                      // A signal flag used to tell file processing that autoversioning has happend and hence certain action should be applied.
00340 
00341 
00342 
00343 
00344 
00345 
00346 
00347 
00348 
00349 
00350 
00351 
00362         function start($data,$cmd,$altUserObject='')    {
00363 
00364                         // Initializing BE_USER
00365                 $this->BE_USER = is_object($altUserObject) ? $altUserObject : $GLOBALS['BE_USER'];
00366                 $this->userid = $this->BE_USER->user['uid'];
00367                 $this->username = $this->BE_USER->user['username'];
00368                 $this->admin = $this->BE_USER->user['admin'];
00369 
00370                 if ($GLOBALS['BE_USER']->uc['recursiveDelete'])    {
00371                         $this->deleteTree = 1;
00372                 }
00373 
00374                         // Initializing default permissions for pages
00375                 $defaultPermissions = $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPermissions'];
00376                 if (isset($defaultPermissions['user']))         {$this->defaultPermissions['user'] = $defaultPermissions['user'];}
00377                 if (isset($defaultPermissions['group']))                {$this->defaultPermissions['group'] = $defaultPermissions['group'];}
00378                 if (isset($defaultPermissions['everybody']))            {$this->defaultPermissions['everybody'] = $defaultPermissions['everybody'];}
00379 
00380                         // generates the excludelist, based on TCA/exclude-flag and non_exclude_fields for the user:
00381                 $this->exclude_array = $this->admin ? array() : $this->getExcludeListArray();
00382 
00383                         // Setting the data and cmd arrays
00384                 if (is_array($data)) {
00385                         reset($data);
00386                         $this->datamap = $data;
00387                 }
00388                 if (is_array($cmd))     {
00389                         reset($cmd);
00390                         $this->cmdmap = $cmd;
00391                 }
00392         }
00393 
00401         function setMirror($mirror)     {
00402                 if (is_array($mirror))  {
00403                         reset($mirror);
00404                         while(list($table,$uid_array)=each($mirror))    {
00405                                 if (isset($this->datamap[$table]))      {
00406                                         reset($uid_array);
00407                                         while (list($id,$uidList) = each($uid_array))   {
00408                                                 if (isset($this->datamap[$table][$id])) {
00409                                                         $theIdsInArray = t3lib_div::trimExplode(',',$uidList,1);
00410                                                         while(list(,$copyToUid)=each($theIdsInArray))   {
00411                                                                 $this->datamap[$table][$copyToUid] = $this->datamap[$table][$id];
00412                                                         }
00413                                                 }
00414                                         }
00415                                 }
00416                         }
00417                 }
00418         }
00419 
00426         function setDefaultsFromUserTS($userTS) {
00427                 global $TCA;
00428                 if (is_array($userTS))  {
00429                         foreach($userTS as $k => $v)    {
00430                                 $k = substr($k,0,-1);
00431                                 if ($k && is_array($v) && isset($TCA[$k]))      {
00432                                         if (is_array($this->defaultValues[$k])) {
00433                                                 $this->defaultValues[$k] = array_merge($this->defaultValues[$k],$v);
00434                                         } else {
00435                                                 $this->defaultValues[$k] = $v;
00436                                         }
00437                                 }
00438                         }
00439                 }
00440         }
00441 
00449         function process_uploads($postFiles)    {
00450 
00451                 if (is_array($postFiles))       {
00452 
00453                                 // Editing frozen:
00454                         if ($this->BE_USER->workspace!==0 && $this->BE_USER->workspaceRec['freeze'])    {
00455                                 $this->newlog('All editing in this workspace has been frozen!',1);
00456                                 return FALSE;
00457                         }
00458 
00459                         reset($postFiles);
00460                         $subA = current($postFiles);
00461                         if (is_array($subA))    {
00462                                 if (is_array($subA['name']) && is_array($subA['type']) && is_array($subA['tmp_name']) && is_array($subA['size']))       {
00463                                                 // Initialize the uploadedFilesArray:
00464                                         $this->uploadedFileArray=array();
00465 
00466                                                 // For each entry:
00467                                         foreach($subA as $key => $values)       {
00468                                                 $this->process_uploads_traverseArray($this->uploadedFileArray,$values,$key);
00469                                         }
00470                                 } else {
00471                                         $this->uploadedFileArray=$subA;
00472                                 }
00473                         }
00474                 }
00475         }
00476 
00487         function process_uploads_traverseArray(&$outputArr,$inputArr,$keyToSet) {
00488                 if (is_array($inputArr))        {
00489                         foreach($inputArr as $key => $value)    {
00490                                 $this->process_uploads_traverseArray($outputArr[$key],$inputArr[$key],$keyToSet);
00491                         }
00492                 } else {
00493                         $outputArr[$keyToSet]=$inputArr;
00494                 }
00495         }
00496 
00497 
00498 
00499 
00500 
00501 
00502 
00503 
00504 
00505 
00506 
00507 
00508 
00509 
00510 
00511         /*********************************************
00512          *
00513          * PROCESSING DATA
00514          *
00515          *********************************************/
00516 
00523         function process_datamap() {
00524                 global $TCA, $TYPO3_CONF_VARS;
00525 
00526                         // Editing frozen:
00527                 if ($this->BE_USER->workspace!==0 && $this->BE_USER->workspaceRec['freeze'])    {
00528                         $this->newlog('All editing in this workspace has been frozen!',1);
00529                         return FALSE;
00530                 }
00531 
00532                         // First prepare user defined objects (if any) for hooks which extend this function:
00533                 $hookObjectsArr = array();
00534                 if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'])) {
00535                         foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'] as $classRef) {
00536                                 $hookObjectsArr[] = &t3lib_div::getUserObj($classRef);
00537                         }
00538                 }
00539 
00540                         // 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.
00541                 $orderOfTables = Array();
00542                 if (isset($this->datamap['pages']))     {               // Set pages first.
00543                         $orderOfTables[]='pages';
00544                 }
00545                 reset($this->datamap);
00546                 while (list($table,) = each($this->datamap))    {
00547                         if ($table!='pages')    {
00548                                 $orderOfTables[]=$table;
00549                         }
00550                 }
00551 
00552                         // Process the tables...
00553                 foreach($orderOfTables as $table)       {
00554                                 /* Check if
00555                                         - table is set in $TCA,
00556                                         - table is NOT readOnly
00557                                         - the table is set with content in the data-array (if not, there's nothing to process...)
00558                                         - permissions for tableaccess OK
00559                                 */
00560                         $modifyAccessList = $this->checkModifyAccessList($table);
00561                         if (!$modifyAccessList) {
00562                                 $id = 0;
00563                                 $this->log($table,$id,2,0,1,"Attempt to modify table '%s' without permission",1,array($table));
00564                         }
00565                         if (isset($TCA[$table]) && !$this->tableReadOnly($table) && is_array($this->datamap[$table]) && $modifyAccessList)      {
00566                                 if ($this->reverseOrder)        {
00567                                         $this->datamap[$table] = array_reverse($this->datamap[$table], 1);
00568                                 }
00569 
00570                                         // For each record from the table, do:
00571                                         // $id is the record uid, may be a string if new records...
00572                                         // $incomingFieldArray is the array of fields
00573                                 foreach($this->datamap[$table] as $id => $incomingFieldArray)   {
00574                                         if (is_array($incomingFieldArray))      {
00575 
00576                                                         // Hook: processDatamap_preProcessIncomingFieldArray
00577                                                 foreach($hookObjectsArr as $hookObj)    {
00578                                                         if (method_exists($hookObj, 'processDatamap_preProcessFieldArray')) {
00579                                                                 $hookObj->processDatamap_preProcessFieldArray($incomingFieldArray, $table, $id, $this);
00580                                                         }
00581                                                 }
00582 
00583                                                         // ******************************
00584                                                         // Checking access to the record
00585                                                         // ******************************
00586                                                 $createNewVersion = FALSE;
00587                                                 $recordAccess = FALSE;
00588                                                 $old_pid_value = '';
00589                                                 $resetRejected = FALSE;
00590                                                 $this->autoVersioningUpdate = FALSE;
00591 
00592                                                 if (!t3lib_div::testInt($id)) {               // Is it a new record? (Then Id is a string)
00593                                                         $fieldArray = $this->newFieldArray($table);     // Get a fieldArray with default values
00594                                                         if (isset($incomingFieldArray['pid']))  {       // A pid must be set for new records.
00595                                                                         // $value = the pid
00596                                                                 $pid_value = $incomingFieldArray['pid'];
00597 
00598                                                                         // Checking and finding numerical pid, it may be a string-reference to another value
00599                                                                 $OK = 1;
00600                                                                 if (strstr($pid_value,'NEW'))   {       // If a NEW... id
00601                                                                         if (substr($pid_value,0,1)=='-') {$negFlag=-1;$pid_value=substr($pid_value,1);} else {$negFlag=1;}
00602                                                                         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.
00603                                                                                 $old_pid_value = $pid_value;
00604                                                                                 $pid_value=intval($negFlag*$this->substNEWwithIDs[$pid_value]);
00605                                                                         } else {$OK = 0;}       // If not found in the substArray we must stop the process...
00606                                                                 } 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.
00607                                                                         if ($WSdestPage = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, 'pages', $pid_value, 'uid,t3ver_swapmode'))      {       // Looks for workspace version of page.
00608                                                                                 if ($WSdestPage['t3ver_swapmode']==0)   {       // if swapmode is zero, then change pid value.
00609                                                                                         $pid_value = $WSdestPage['uid'];
00610                                                                                 }
00611                                                                         }
00612                                                                 }
00613                                                                 $pid_value = intval($pid_value);
00614 
00615                                                                         // The $pid_value is now the numerical pid at this point
00616                                                                 if ($OK)        {
00617                                                                         $sortRow = $TCA[$table]['ctrl']['sortby'];
00618                                                                         if ($pid_value>=0)      {       // Points to a page on which to insert the element, possibly in the top of the page
00619                                                                                 if ($sortRow)   {       // If this table is sorted we better find the top sorting number
00620                                                                                         $fieldArray[$sortRow] = $this->getSortNumber($table,0,$pid_value);
00621                                                                                 }
00622                                                                                 $fieldArray['pid'] = $pid_value;        // The numerical pid is inserted in the data array
00623                                                                         } else {        // points to another record before ifself
00624                                                                                 if ($sortRow)   {       // If this table is sorted we better find the top sorting number
00625                                                                                         $tempArray=$this->getSortNumber($table,0,$pid_value);   // Because $pid_value is < 0, getSortNumber returns an array
00626                                                                                         $fieldArray['pid'] = $tempArray['pid'];
00627                                                                                         $fieldArray[$sortRow] = $tempArray['sortNumber'];
00628                                                                                 } else {        // Here we fetch the PID of the record that we point to...
00629                                                                                         $tempdata = $this->recordInfo($table,abs($pid_value),'pid');
00630                                                                                         $fieldArray['pid']=$tempdata['pid'];
00631                                                                                 }
00632                                                                         }
00633                                                                 }
00634                                                         }
00635                                                         $theRealPid = $fieldArray['pid'];
00636 
00637                                                                 // Now, check if we may insert records on this pid.
00638                                                         if ($theRealPid>=0)     {
00639                                                                 $recordAccess = $this->checkRecordInsertAccess($table,$theRealPid);             // Checks if records can be inserted on this $pid.
00640                                                                 if ($recordAccess)      {
00641                                                                         $this->addDefaultPermittedLanguageIfNotSet($table,$incomingFieldArray);
00642                                                                         $recordAccess = $this->BE_USER->recordEditAccessInternals($table,$incomingFieldArray,TRUE);
00643                                                                         if (!$recordAccess)             {
00644                                                                                 $this->newlog("recordEditAccessInternals() check failed. [".$this->BE_USER->errorMsg."]",1);
00645                                                                         } elseif(!$this->bypassWorkspaceRestrictions)   {
00646                                                                                         // Workspace related processing:
00647                                                                                 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
00648                                                                                         if ($res<0)     {
00649                                                                                                 $recordAccess = FALSE;
00650                                                                                                 $this->newlog('Stage for versioning root point and users access level did not allow for editing',1);
00651                                                                                         }
00652                                                                                 } else {        // So, if no live records were allowed, we have to create a new version of this record:
00653                                                                                         if ($TCA[$table]['ctrl']['versioningWS'])       {
00654                                                                                                 $createNewVersion = TRUE;
00655                                                                                         } else {
00656                                                                                                 $recordAccess = FALSE;
00657                                                                                                 $this->newlog('Record could not be created in this workspace in this branch',1);
00658                                                                                         }
00659                                                                                 }
00660                                                                         }
00661                                                                 }
00662                                                         } else {
00663                                                                 debug('Internal ERROR: pid should not be less than zero!');
00664                                                         }
00665                                                         $status = 'new';                                                // Yes new record, change $record_status to 'insert'
00666                                                 } else {        // Nope... $id is a number
00667                                                         $fieldArray = array();
00668                                                         $recordAccess = $this->checkRecordUpdateAccess($table,$id);
00669                                                         if (!$recordAccess)             {
00670                                                                 $propArr = $this->getRecordProperties($table,$id);
00671                                                                 $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']);
00672                                                         } else {        // Next check of the record permissions (internals)
00673                                                                 $recordAccess = $this->BE_USER->recordEditAccessInternals($table,$id);
00674                                                                 if (!$recordAccess)             {
00675                                                                         $propArr = $this->getRecordProperties($table,$id);
00676                                                                         $this->newlog("recordEditAccessInternals() check failed. [".$this->BE_USER->errorMsg."]",1);
00677                                                                 } else {        // Here we fetch the PID of the record that we point to...
00678                                                                         $tempdata = $this->recordInfo($table,$id,'pid'.($TCA[$table]['ctrl']['versioningWS']?',t3ver_wsid,t3ver_stage':''));
00679                                                                         $theRealPid = $tempdata['pid'];
00680 
00681                                                                                 // Prepare the reset of the rejected flag if set:
00682                                                                         if ($TCA[$table]['ctrl']['versioningWS'] && $tempdata['t3ver_stage']<0) {
00683                                                                                 $resetRejected = TRUE;
00684                                                                         }
00685 
00686                                                                                 // Checking access in case of offline workspace:
00687                                                                         if (!$this->bypassWorkspaceRestrictions && $errorCode = $this->BE_USER->workspaceCannotEditRecord($table,$tempdata))    {
00688                                                                                 $recordAccess = FALSE;          // Versioning is required and it must be offline version!
00689 
00690                                                                                         // 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.
00691                                                                                 if ($this->BE_USER->workspaceAllowAutoCreation($table,$id,$theRealPid)) {
00692                                                                                         $tce = t3lib_div::makeInstance('t3lib_TCEmain');
00693                                                                                         $tce->stripslashes_values = 0;
00694 
00695                                                                                                 // Setting up command for creating a new version of the record:
00696                                                                                         $cmd = array();
00697                                                                                         $cmd[$table][$id]['version'] = array(
00698                                                                                                 'action' => 'new',
00699                                                                                                 'treeLevels' => -1,     // Default is to create a version of the individual records...
00700                                                                                                 'label' => 'Auto-created for WS #'.$this->BE_USER->workspace
00701                                                                                         );
00702                                                                                         $tce->start(array(),$cmd);
00703                                                                                         $tce->process_cmdmap();
00704                                                                                         $this->errorLog = array_merge($this->errorLog,$tce->errorLog);
00705 
00706                                                                                         if ($tce->copyMappingArray[$table][$id])        {
00707                                                                                                 $this->uploadedFileArray[$table][$tce->copyMappingArray[$table][$id]] = $this->uploadedFileArray[$table][$id];
00708                                                                                                 $id = $this->autoVersionIdMap[$table][$id] = $tce->copyMappingArray[$table][$id];
00709                                                                                                 $recordAccess = TRUE;
00710                                                                                                 $this->autoVersioningUpdate = TRUE;
00711                                                                                         } else $this->newlog("Could not be edited in offline workspace in the branch where found (failure state: '".$errorCode."'). Auto-creation of version failed!",1);
00712                                                                                 } 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);
00713                                                                         }
00714                                                                 }
00715                                                         }
00716                                                         $status = 'update';     // the default is 'update'
00717                                                 }
00718 
00719                                                         // If access was granted above, proceed to create or update record:
00720                                                 if ($recordAccess)      {
00721 
00722                                                         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.
00723                                                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
00724                                                         if ($status=='new' && $table=='pages' && is_array($TSConfig['permissions.']))   {
00725                                                                 $fieldArray = $this->setTSconfigPermissions($fieldArray,$TSConfig['permissions.']);
00726                                                         }
00727                                                         if ($createNewVersion)  {
00728                                                                 $newVersion_placeholderFieldArray = $fieldArray;
00729                                                         }
00730 
00731                                                                 // Processing of all fields in incomingFieldArray and setting them in $fieldArray
00732                                                         $fieldArray = $this->fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$theRealPid,$status,$tscPID);
00733 
00734                                                                 // NOTICE! All manipulation beyond this point bypasses both "excludeFields" AND possible "MM" relations / file uploads to field!
00735 
00736                                                                 // Forcing some values unto field array:
00737                                                         $fieldArray = $this->overrideFieldArray($table,$fieldArray);    // NOTICE: This overriding is potentially dangerous; permissions per field is not checked!!!
00738                                                         if ($createNewVersion)  {
00739                                                                 $newVersion_placeholderFieldArray = $this->overrideFieldArray($table,$newVersion_placeholderFieldArray);
00740                                                         }
00741 
00742                                                                 // Setting system fields
00743                                                         if ($status=='new')     {
00744                                                                 if ($TCA[$table]['ctrl']['crdate'])     {
00745                                                                         $fieldArray[$TCA[$table]['ctrl']['crdate']]=time();
00746                                                                         if ($createNewVersion)  $newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['crdate']]=time();
00747                                                                 }
00748                                                                 if ($TCA[$table]['ctrl']['cruser_id'])  {
00749                                                                         $fieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid;
00750                                                                         if ($createNewVersion)  $newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid;
00751                                                                 }
00752                                                         } elseif ($this->checkSimilar) {        // Removing fields which are equal to the current value:
00753                                                                 $fieldArray = $this->compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray);
00754                                                         }
00755                                                         if ($TCA[$table]['ctrl']['tstamp'] && count($fieldArray))       {
00756                                                                 $fieldArray[$TCA[$table]['ctrl']['tstamp']]=time();
00757                                                                 if ($createNewVersion)  $newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['tstamp']]=time();
00758                                                         }
00759                                                         if ($resetRejected)     {
00760                                                                 $fieldArray['t3ver_stage'] = 0;
00761                                                         }
00762 
00763                                                                 // Hook: processDatamap_postProcessFieldArray
00764                                                         foreach($hookObjectsArr as $hookObj)    {
00765                                                                 if (method_exists($hookObj, 'processDatamap_postProcessFieldArray')) {
00766                                                                         $hookObj->processDatamap_postProcessFieldArray($status, $table, $id, $fieldArray, $this);
00767                                                                 }
00768                                                         }
00769 
00770                                                                 // Performing insert/update. If fieldArray has been unset by some userfunction (see hook above), don't do anything
00771                                                                 // Kasper: Unsetting the fieldArray is dangerous; MM relations might be saved already and files could have been uploaded that are now "lost"
00772                                                         if (is_array($fieldArray)) {
00773                                                                 if ($status=='new')     {
00774                                                                         if ($createNewVersion)  {       // This creates a new version of the record with online placeholder and offline version
00775                                                                                 $versioningType = $table==='pages' ? $this->BE_USER->workspaceVersioningTypeGetClosest(t3lib_div::intInRange($TYPO3_CONF_VARS['BE']['newPagesVersioningType'],-1,1)) : -1;
00776                                                                                 if ($this->BE_USER->workspaceVersioningTypeAccess($versioningType))     {
00777                                                                                         $newVersion_placeholderFieldArray['t3ver_label'] = 'INITIAL PLACEHOLDER';
00778                                                                                         $newVersion_placeholderFieldArray['t3ver_state'] = 1;   // Setting placeholder state value for temporary record
00779                                                                                         $newVersion_placeholderFieldArray['t3ver_wsid'] = $this->BE_USER->workspace;    // Setting workspace - only so display of place holders can filter out those from other workspaces.
00780                                                                                         $newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['label']] = '[PLACEHOLDER, WS#'.$this->BE_USER->workspace.']';
00781                                                                                         $this->insertDB($table,$id,$newVersion_placeholderFieldArray,FALSE);    // Saving placeholder as 'original'
00782 
00783                                                                                                 // For the actual new offline version, set versioning values to point to placeholder:
00784                                                                                         $fieldArray['pid'] = -1;
00785                                                                                         $fieldArray['t3ver_oid'] = $this->substNEWwithIDs[$id];
00786                                                                                         $fieldArray['t3ver_id'] = 1;
00787                                                                                         $fieldArray['t3ver_state'] = -1;        // Setting placeholder state value for version (so it can know it is currently a new version...)
00788                                                                                         $fieldArray['t3ver_label'] = 'First draft version';
00789                                                                                         $fieldArray['t3ver_wsid'] = $this->BE_USER->workspace;
00790                                                                                         if ($table==='pages') {         // Swap mode set to "branch" so we can build branches for pages.
00791                                                                                                 $fieldArray['t3ver_swapmode'] = $versioningType;
00792                                                                                         }
00793                                                                                         $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!
00794                                                                                         if ($phShadowId)        {
00795                                                                                                 $this->placeholderShadowing($table,$phShadowId);
00796                                                                                         }
00797                                                                                 } else $this->newlog('Versioning type "'.$versioningType.'" was not allowed, so could not create new record.',1);
00798                                                                         } else {
00799                                                                                 $this->insertDB($table,$id,$fieldArray,FALSE,$incomingFieldArray['uid']);
00800                                                                         }
00801                                                                 } else {
00802                                                                         $this->updateDB($table,$id,$fieldArray);
00803                                                                         $this->placeholderShadowing($table,$id);
00804                                                                 }
00805                                                         }
00806 
00807                                                                 /*
00808                                                                  * Hook: processDatamap_afterDatabaseOperations
00809                                                                  *
00810                                                                  * Note: When using the hook after INSERT operations, you will only get the temporary NEW... id passed to your hook as $id,
00811                                                                  *               but you can easily translate it to the real uid of the inserted record using the $this->substNEWwithIDs array.
00812                                                                  */
00813                                                         foreach($hookObjectsArr as $hookObj)    {
00814                                                                 if (method_exists($hookObj, 'processDatamap_afterDatabaseOperations')) {
00815                                                                         $hookObj->processDatamap_afterDatabaseOperations($status, $table, $id, $fieldArray, $this);
00816                                                                 }
00817                                                         }
00818                                                 }       // if ($recordAccess)   {
00819                                         }       // if (is_array($incomingFieldArray))   {
00820                                 }
00821                         }
00822                 }
00823 
00824                 // call_user_func_array
00825 
00826                         // Process the stack of relations to remap/correct
00827                 if(is_array($this->remapStack)) {
00828                         foreach($this->remapStack as $remapAction) {
00829                                         // if no position index for the arguments was set, skip this remap action
00830                                 if (!is_array($remapAction['pos'])) continue;
00831 
00832                                         // load values from the argument array in remapAction
00833                                 $field = $remapAction['field'];
00834                                 $id = $remapAction['args'][$remapAction['pos']['id']];
00835                                 $table = $remapAction['args'][$remapAction['pos']['table']];
00836                                 $valueArray = $remapAction['args'][$remapAction['pos']['valueArray']];
00837                                 $tcaFieldConf = $remapAction['args'][$remapAction['pos']['tcaFieldConf']];
00838 
00839                                         // Replace NEW... IDs with real uids.
00840                                 if(strpos($id, 'NEW') !== false) {
00841                                         $id = $this->substNEWwithIDs[$id];
00842                                         $remapAction['args'][$remapAction['pos']['id']] = $id;
00843                                 }
00844 
00845                                         // Replace relations to NEW...-IDs in values
00846                                 if(is_array($valueArray)) {
00847                                         foreach($valueArray as $key => $value) {
00848                                                 if(strpos($value, 'NEW') !== false) {
00849                                                                 // fetch the proper uid as integer for the NEW...-ID
00850                                                         $valueArray[$key] = $this->substNEWwithIDs[$value];
00851                                                                 // set a hint that this was a new child record
00852                                                         $this->newRelatedIDs[$table][] = $valueArray[$key];
00853                                                 }
00854                                         }
00855                                         $remapAction['args'][$remapAction['pos']['valueArray']] = $valueArray;
00856                                 }
00857 
00858                                         // process the arguments with the defined function
00859                                 $remapAction['args'][$remapAction['pos']['valueArray']] = call_user_func_array(
00860                                         array($this, $remapAction['func']),
00861                                         $remapAction['args']
00862                                 );
00863 
00864                                         // @TODO: Add option to disable count-field
00865                                 $newVal = $this->checkValue_checkMax($tcaFieldConf, $remapAction['args'][$remapAction['pos']['valueArray']]);
00866                                 $this->updateDB($table,$id,array($field => implode(',', $newVal)));
00867                         }
00868                 }
00869 
00870                 $this->dbAnalysisStoreExec();
00871                 $this->removeRegisteredFiles();
00872         }
00873 
00881         function placeholderShadowing($table,$id)       {
00882                 global $TCA;
00883 
00884                 t3lib_div::loadTCA($table);
00885                 if ($liveRec = t3lib_BEfunc::getLiveVersionOfRecord($table,$id,'*'))    {
00886                         if ((int)$liveRec['t3ver_state']===1)   {
00887                                 $justStoredRecord = t3lib_BEfunc::getRecord($table,$id);
00888                                 $newRecord = array();
00889 
00890                                 $shadowCols = $TCA[$table]['ctrl']['shadowColumnsForNewPlaceholders'];
00891                                 $shadowCols.= ','.$TCA[$table]['ctrl']['languageField'];
00892                                 $shadowCols.= ','.$TCA[$table]['ctrl']['transOrigPointerField'];
00893                                 $shadowCols.= ','.$TCA[$table]['ctrl']['type'];
00894                                 $shadowCols.= ','.$TCA[$table]['ctrl']['label'];
00895 
00896                                 $shadowColumns = array_unique(t3lib_div::trimExplode(',', $shadowCols,1));
00897                                 foreach($shadowColumns as $fieldName)   {
00898                                         if (strcmp($justStoredRecord[$fieldName],$liveRec[$fieldName]) && isset($TCA[$table]['columns'][$fieldName]) && $fieldName!=='uid' && $fieldName!=='pid')       {
00899                                                 $newRecord[$fieldName] = $justStoredRecord[$fieldName];
00900                                         }
00901                                 }
00902 
00903                                 if (count($newRecord))  {
00904                                         $this->newlog('Shadowing done on fields '.implode(',',array_keys($newRecord)).' in Placeholder record '.$table.':'.$liveRec['uid'].' (offline version UID='.$id.')');
00905                                         $this->updateDB($table,$liveRec['uid'],$newRecord);
00906                                 }
00907                         }
00908                 }
00909         }
00910 
00924         function fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$realPid,$status,$tscPID)  {
00925                 global $TCA;
00926 
00927                         // Initialize:
00928                 t3lib_div::loadTCA($table);
00929                 $originalLanguageRecord = NULL;
00930                 $originalLanguage_diffStorage = NULL;
00931                 $diffStorageFlag = FALSE;
00932 
00933                         // Setting 'currentRecord' and 'checkValueRecord':
00934                 if (strstr($id,'NEW'))  {
00935                         $currentRecord = $checkValueRecord = $fieldArray;       // must have the 'current' array - not the values after processing below...
00936 
00937                                 // IF $incomingFieldArray is an array, overlay it.
00938                                 // 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...
00939                         if (is_array($incomingFieldArray) && is_array($checkValueRecord))       {
00940                                 $checkValueRecord = t3lib_div::array_merge_recursive_overrule($checkValueRecord, $incomingFieldArray);
00941                         }
00942                 } else {
00943                         $currentRecord = $checkValueRecord = $this->recordInfo($table,$id,'*'); // We must use the current values as basis for this!
00944 
00945                         t3lib_BEfunc::fixVersioningPid($table,$currentRecord);  // This is done to make the pid positive for offline versions; Necessary to have diff-view for pages_language_overlay in workspaces.
00946 
00947                                 // Get original language record if available:
00948                         if (is_array($currentRecord)
00949                                         && $TCA[$table]['ctrl']['transOrigDiffSourceField']
00950                                         && $TCA[$table]['ctrl']['languageField']
00951                                         && $currentRecord[$TCA[$table]['ctrl']['languageField']] > 0
00952                                         && $TCA[$table]['ctrl']['transOrigPointerField']
00953                                         && intval($currentRecord[$TCA[$table]['ctrl']['transOrigPointerField']]) > 0)   {
00954 
00955                                 $lookUpTable = $TCA[$table]['ctrl']['transOrigPointerTable'] ? $TCA[$table]['ctrl']['transOrigPointerTable'] : $table;
00956                                 $originalLanguageRecord = $this->recordInfo($lookUpTable,$currentRecord[$TCA[$table]['ctrl']['transOrigPointerField']],'*');
00957                                 t3lib_BEfunc::workspaceOL($lookUpTable,$originalLanguageRecord);
00958                                 $originalLanguage_diffStorage = unserialize($currentRecord[$TCA[$table]['ctrl']['transOrigDiffSourceField']]);
00959                         }
00960                 }
00961                 $this->checkValue_currentRecord = $checkValueRecord;
00962 
00963                         /*
00964                                 In the following all incoming value-fields are tested:
00965                                 - Are the user allowed to change the field?
00966                                 - Is the field uid/pid (which are already set)
00967                                 - perms-fields for pages-table, then do special things...
00968                                 - If the field is nothing of the above and the field is configured in TCA, the fieldvalues are evaluated by ->checkValue
00969 
00970                                 If everything is OK, the field is entered into $fieldArray[]
00971                         */
00972                 foreach($incomingFieldArray as $field => $fieldValue)   {
00973                         if (!in_array($table.'-'.$field, $this->exclude_array) && !$this->data_disableFields[$table][$id][$field])      {       // The field must be editable.
00974 
00975                                         // Checking if a value for language can be changed:
00976                                 $languageDeny = $TCA[$table]['ctrl']['languageField'] && !strcmp($TCA[$table]['ctrl']['languageField'], $field) && !$this->BE_USER->checkLanguageAccess($fieldValue);
00977 
00978                                 if (!$languageDeny)     {
00979                                                 // Stripping slashes - will probably be removed the day $this->stripslashes_values is removed as an option...
00980                                         if ($this->stripslashes_values) {
00981                                                 if (is_array($fieldValue))      {
00982                                                         t3lib_div::stripSlashesOnArray($fieldValue);
00983                                                 } else $fieldValue = stripslashes($fieldValue);
00984                                         }
00985 
00986                                         switch ($field) {
00987                                                 case 'uid':
00988                                                 case 'pid':
00989                                                         // Nothing happens, already set
00990                                                 break;
00991                                                 case 'perms_userid':
00992                                                 case 'perms_groupid':
00993                                                 case 'perms_user':
00994                                                 case 'perms_group':
00995                                                 case 'perms_everybody':
00996                                                                 // Permissions can be edited by the owner or the administrator
00997                                                         if ($table=='pages' && ($this->admin || $status=='new' || $this->pageInfo($id,'perms_userid')==$this->userid) ) {
00998                                                                 $value=intval($fieldValue);
00999                                                                 switch($field)  {
01000                                                                         case 'perms_userid':
01001                                                                                 $fieldArray[$field]=$value;
01002                                                                         break;
01003                                                                         case 'perms_groupid':
01004                                                                                 $fieldArray[$field]=$value;
01005                                                                         break;
01006                                                                         default:
01007                                                                                 if ($value>=0 && $value<pow(2,5))       {
01008                                                                                         $fieldArray[$field]=$value;
01009                                                                                 }
01010                                                                         break;
01011                                                                 }
01012                                                         }
01013                                                 break;
01014                                                 case 't3ver_oid':
01015                                                 case 't3ver_id':
01016                                                 case 't3ver_wsid':
01017                                                 case 't3ver_state':
01018                                                 case 't3ver_swapmode':
01019                                                 case 't3ver_count':
01020                                                 case 't3ver_stage':
01021                                                 case 't3ver_tstamp':
01022                                                         // t3ver_label is not here because it CAN be edited as a regular field!
01023                                                 break;
01024                                                 default:
01025                                                         if (isset($TCA[$table]['columns'][$field]))     {
01026                                                                         // Evaluating the value.
01027                                                                 $res = $this->checkValue($table,$field,$fieldValue,$id,$status,$realPid,$tscPID);
01028                                                                 if (isset($res['value']))       {
01029                                                                         $fieldArray[$field]=$res['value'];
01030 
01031                                                                                 // Add the value of the original record to the diff-storage content:
01032                                                                         if ($TCA[$table]['ctrl']['transOrigDiffSourceField'])   {
01033                                                                                 $originalLanguage_diffStorage[$field] = $originalLanguageRecord[$field];
01034                                                                                 $diffStorageFlag = TRUE;
01035                                                                         }
01036                                                                 }
01037                                                         } elseif ($TCA[$table]['ctrl']['origUid']===$field) {   // Allow value for original UID to pass by...
01038                                                                 $fieldArray[$field] = $fieldValue;
01039                                                         }
01040                                                 break;
01041                                         }
01042                                 }       // Checking language.
01043                         }       // Check exclude fields / disabled fields...
01044                 }
01045 
01046                         // Add diff-storage information:
01047                 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...
01048                          $fieldArray[$TCA[$table]['ctrl']['transOrigDiffSourceField']] = serialize($originalLanguage_diffStorage);
01049                 }
01050 
01051                         // Checking for RTE-transformations of fields:
01052                 $types_fieldConfig = t3lib_BEfunc::getTCAtypes($table,$currentRecord);
01053                 $theTypeString = t3lib_BEfunc::getTCAtypeValue($table,$currentRecord);
01054                 if (is_array($types_fieldConfig))       {
01055                         reset($types_fieldConfig);
01056                         while(list(,$vconf) = each($types_fieldConfig)) {
01057                                         // Write file configuration:
01058                                 $eFile = t3lib_parsehtml_proc::evalWriteFile($vconf['spec']['static_write'],array_merge($currentRecord,$fieldArray));   // inserted array_merge($currentRecord,$fieldArray) 170502
01059 
01060                                         // RTE transformations:
01061                                 if (!$this->dontProcessTransformations) {
01062                                         if (isset($fieldArray[$vconf['field']]))        {
01063                                                         // Look for transformation flag:
01064                                                 switch((string)$incomingFieldArray['_TRANSFORM_'.$vconf['field']])      {
01065                                                         case 'RTE':
01066                                                                 $RTEsetup = $this->BE_USER->getTSConfig('RTE',t3lib_BEfunc::getPagesTSconfig($tscPID));
01067                                                                 $thisConfig = t3lib_BEfunc::RTEsetup($RTEsetup['properties'],$table,$vconf['field'],$theTypeString);
01068 
01069                                                                         // Set alternative relative path for RTE images/links:
01070                                                                 $RTErelPath = is_array($eFile) ? dirname($eFile['relEditFile']) : '';
01071 
01072                                                                         // Get RTE object, draw form and set flag:
01073                                                                 $RTEobj = &t3lib_BEfunc::RTEgetObj();
01074                                                                 if (is_object($RTEobj)) {
01075                                                                         $fieldArray[$vconf['field']] = $RTEobj->transformContent('db',$fieldArray[$vconf['field']],$table,$vconf['field'],$currentRecord,$vconf['spec'],$thisConfig,$RTErelPath,$currentRecord['pid']);
01076                                                                 } else {
01077                                                                         debug('NO RTE OBJECT FOUND!');
01078                                                                 }
01079                                                         break;
01080                                                 }
01081                                         }
01082                                 }
01083 
01084                                         // Write file configuration:
01085                                 if (is_array($eFile))   {
01086                                         $mixedRec = array_merge($currentRecord,$fieldArray);
01087                                         $SW_fileContent = t3lib_div::getUrl($eFile['editFile']);
01088                                         $parseHTML = t3lib_div::makeInstance('t3lib_parsehtml_proc');
01089                                         $parseHTML->init('','');
01090 
01091                                         $eFileMarker = $eFile['markerField']&&trim($mixedRec[$eFile['markerField']]) ? trim($mixedRec[$eFile['markerField']]) : '###TYPO3_STATICFILE_EDIT###';
01092                                         $insertContent = str_replace($eFileMarker,'',$mixedRec[$eFile['contentField']]);        // must replace the marker if present in content!
01093 
01094                                         $SW_fileNewContent = $parseHTML->substituteSubpart($SW_fileContent, $eFileMarker, chr(10).$insertContent.chr(10), 1, 1);
01095                                         t3lib_div::writeFile($eFile['editFile'],$SW_fileNewContent);
01096 
01097                                                 // Write status:
01098                                         if (!strstr($id,'NEW') && $eFile['statusField'])        {
01099                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
01100                                                         $table,
01101                                                         'uid='.intval($id),
01102                                                         array(
01103                                                                 $eFile['statusField'] => $eFile['relEditFile'].' updated '.date('d-m-Y H:i:s').', bytes '.strlen($mixedRec[$eFile['contentField']])
01104                                                         )
01105                                                 );
01106                                         }
01107                                 } elseif ($eFile && is_string($eFile))  {
01108                                         $this->log($table,$id,2,0,1,"Write-file error: '%s'",13,array($eFile),$realPid);
01109                                 }
01110                         }
01111                 }
01112                         // Return fieldArray
01113                 return $fieldArray;
01114         }
01115 
01116 
01117 
01118 
01119 
01120 
01121 
01122 
01123 
01124 
01125 
01126 
01127         /*********************************************
01128          *
01129          * Evaluation of input values
01130          *
01131          ********************************************/
01132 
01147         function checkValue($table,$field,$value,$id,$status,$realPid,$tscPID)  {
01148                 global $TCA, $PAGES_TYPES;
01149                 t3lib_div::loadTCA($table);
01150 
01151                 $res = Array(); // result array
01152                 $recFID = $table.':'.$id.':'.$field;
01153 
01154                         // Processing special case of field pages.doktype
01155                 if ($table=='pages' && $field=='doktype')       {
01156                                 // If the user may not use this specific doktype, we issue a warning
01157                         if (! ($this->admin || t3lib_div::inList($this->BE_USER->groupData['pagetypes_select'],$value)))        {
01158                                 $propArr = $this->getRecordProperties($table,$id);
01159                                 $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']);
01160                                 return $res;
01161                         };
01162                         if ($status=='update')  {
01163                                         // This checks 1) if we should check for disallowed tables and 2) if there are records from disallowed tables on the current page
01164                                 $onlyAllowedTables = isset($PAGES_TYPES[$value]['onlyAllowedTables']) ? $PAGES_TYPES[$value]['onlyAllowedTables'] : $PAGES_TYPES['default']['onlyAllowedTables'];
01165                                 if ($onlyAllowedTables) {
01166                                         $theWrongTables = $this->doesPageHaveUnallowedTables($id,$value);
01167                                         if ($theWrongTables)    {
01168                                                 $propArr = $this->getRecordProperties($table,$id);
01169                                                 $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']);
01170                                                 return $res;
01171                                         }
01172                                 }
01173                         }
01174                 }
01175 
01176                         // Get current value:
01177                 $curValueRec = $this->recordInfo($table,$id,$field);
01178                 $curValue = $curValueRec[$field];
01179 
01180                         // Getting config for the field
01181                 $tcaFieldConf = $TCA[$table]['columns'][$field]['config'];
01182 
01183                         // Preform processing:
01184                 $res = $this->checkValue_SW($res,$value,$tcaFieldConf,$table,$id,$curValue,$status,$realPid,$recFID,$field,$this->uploadedFileArray[$table][$id][$field],$tscPID);
01185 
01186                 return $res;
01187         }
01188 
01207         function checkValue_SW($res,$value,$tcaFieldConf,$table,$id,$curValue,$status,$realPid,$recFID,$field,$uploadedFiles,$tscPID)   {
01208 
01209                 $PP = array($table,$id,$curValue,$status,$realPid,$recFID,$tscPID);
01210 
01211                 switch ($tcaFieldConf['type']) {
01212                         case 'text':
01213                         case 'passthrough':
01214                         case 'user':
01215                                 $res['value'] = $value;
01216                         break;
01217                         case 'input':
01218                                 $res = $this->checkValue_input($res,$value,$tcaFieldConf,$PP,$field);
01219                         break;
01220                         case 'check':
01221                                 $res = $this->checkValue_check($res,$value,$tcaFieldConf,$PP);
01222                         break;
01223                         case 'radio':
01224                                 $res = $this->checkValue_radio($res,$value,$tcaFieldConf,$PP);
01225                         break;
01226                         case 'group':
01227                         case 'select':
01228                                 $res = $this->checkValue_group_select($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field);
01229                         break;
01230                         case 'inline':
01231                                 $res = $this->checkValue_inline($res,$value,$tcaFieldConf,$PP,$field);
01232                         break;
01233                         case 'flex':
01234                                 if ($field)     {       // FlexForms are only allowed for real fields.
01235                                         $res = $this->checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field);
01236                                 }
01237                         break;
01238                         default:
01239                                 #debug(array($tcaFieldConf,$res,$value),'NON existing field type:');
01240                         break;
01241                 }
01242 
01243                 return $res;
01244         }
01245 
01256         function checkValue_input($res,$value,$tcaFieldConf,$PP,$field='')      {
01257                 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
01258 
01259                         // Secures the string-length to be less than max. Will probably make problems with multi-byte strings!
01260                 if (intval($tcaFieldConf['max'])>0)     {$value = substr($value,0,intval($tcaFieldConf['max']));}
01261 
01262                         // Checking range of value:
01263                 if ($tcaFieldConf['range'] && $value!=$tcaFieldConf['checkbox'])        {       // If value is not set to the allowed checkbox-value then it is checked against the ranges
01264                         if (isset($tcaFieldConf['range']['upper'])&&$value>$tcaFieldConf['range']['upper'])     {$value=$tcaFieldConf['range']['upper'];}
01265                         if (isset($tcaFieldConf['range']['lower'])&&$value<$tcaFieldConf['range']['lower'])     {$value=$tcaFieldConf['range']['lower'];}
01266                 }
01267 
01268                         // Process evaluation settings:
01269                 $evalCodesArray = t3lib_div::trimExplode(',',$tcaFieldConf['eval'],1);
01270                 $res = $this->checkValue_input_Eval($value,$evalCodesArray,$tcaFieldConf['is_in']);
01271 
01272                         // Process UNIQUE settings:
01273                 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...
01274                         if ($res['value'] && in_array('uniqueInPid',$evalCodesArray))   {
01275                                 $res['value'] = $this->getUnique($table,$field,$res['value'],$id,$realPid);
01276                         }
01277                         if ($res['value'] && in_array('unique',$evalCodesArray))        {
01278                                 $res['value'] = $this->getUnique($table,$field,$res['value'],$id);
01279                         }
01280                 }
01281 
01282                 return $res;
01283         }
01284 
01294         function checkValue_check($res,$value,$tcaFieldConf,$PP)        {
01295                 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
01296 
01297                 $itemC = count($tcaFieldConf['items']);
01298                 if (!$itemC)    {$itemC=1;}
01299                 $maxV = pow(2,$itemC);
01300 
01301                 if ($value<0)   {$value=0;}
01302                 if ($value>$maxV)       {$value=$maxV;}
01303                 $res['value'] = $value;
01304 
01305                 return $res;
01306         }
01307 
01317         function checkValue_radio($res,$value,$tcaFieldConf,$PP)        {
01318                 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
01319 
01320                 if (is_array($tcaFieldConf['items']))   {
01321                         foreach($tcaFieldConf['items'] as $set) {
01322                                 if (!strcmp($set[1],$value))    {
01323                                         $res['value'] = $value;
01324                                         break;
01325                                 }
01326                         }
01327                 }
01328 
01329                 return $res;
01330         }
01331 
01343         function checkValue_group_select($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field)   {
01344 
01345                 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
01346 
01347                         // Detecting if value sent is an array and if so, implode it around a comma:
01348                 if (is_array($value))   {
01349                         $value = implode(',',$value);
01350                 }
01351 
01352                         // 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.
01353                         // Anyways, this should NOT disturb anything else:
01354                 $value = $this->convNumEntityToByteValue($value);
01355 
01356                         // When values are sent as group or select they come as comma-separated values which are exploded by this function:
01357                 $valueArray = $this->checkValue_group_select_explodeSelectGroupValue($value);
01358 
01359                         // If not multiple is set, then remove duplicates:
01360                 if (!$tcaFieldConf['multiple']) {
01361                         $valueArray = array_unique($valueArray);
01362                 }
01363 
01364                         // If an exclusive key is found, discard all others:
01365                 if ($tcaFieldConf['type']=='select' && $tcaFieldConf['exclusiveKeys'])  {
01366                         $exclusiveKeys = t3lib_div::trimExplode(',', $tcaFieldConf['exclusiveKeys']);
01367                         foreach($valueArray as $kk => $vv)      {
01368                                 if (in_array($vv, $exclusiveKeys))      {       // $vv is the item key!
01369                                         $valueArray = Array($kk => $vv);
01370                                         break;
01371                                 }
01372                         }
01373                 }
01374 
01375                 // This could be a good spot for parsing the array through a validation-function which checks if the values are alright (except that database references are not in their final form - but that is the point, isn't it?)
01376                 // NOTE!!! Must check max-items of files before the later check because that check would just leave out filenames if there are too many!!
01377 
01378                         // Checking for select / authMode, removing elements from $valueArray if any of them is not allowed!
01379                 if ($tcaFieldConf['type']=='select' && $tcaFieldConf['authMode'])       {
01380                         $preCount = count($valueArray);
01381                         foreach($valueArray as $kk => $vv)      {
01382                                 if (!$this->BE_USER->checkAuthMode($table,$field,$vv,$tcaFieldConf['authMode']))        {
01383                                         unset($valueArray[$kk]);
01384                                 }
01385                         }
01386 
01387                                 // 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.
01388                         if ($preCount && !count($valueArray))   {
01389                                 return array();
01390                         }
01391                 }
01392 
01393                         // For group types:
01394                 if ($tcaFieldConf['type']=='group')     {
01395                         switch($tcaFieldConf['internal_type'])  {
01396                                 case 'file':
01397                                         $valueArray = $this->checkValue_group_select_file(
01398                                                 $valueArray,
01399                                                 $tcaFieldConf,
01400                                                 $curValue,
01401                                                 $uploadedFiles,
01402                                                 $status,
01403                                                 $table,
01404                                                 $id,
01405                                                 $recFID
01406                                         );
01407                                 break;
01408                                 case 'db':
01409                                         $valueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'group', $table);
01410                                 break;
01411                         }
01412                 }
01413                         // For select types which has a foreign table attached:
01414                 if ($tcaFieldConf['type']=='select' && $tcaFieldConf['foreign_table'])  {
01415                                 // check, if there is a NEW... id in the value, that should be substituded later
01416                         if (strpos($value, 'NEW') !== false) {
01417                                 $this->remapStack[] = array(
01418                                         'func' => 'checkValue_group_select_processDBdata',
01419                                         'args' => array($valueArray,$tcaFieldConf,$id,$status,'select',$table),
01420                                         'pos' => array('valueArray' => 0, 'tcaFieldConf' => 1, 'id' => 2, 'table' => 5),
01421                                         'field' => $field
01422                                 );
01423                                 $unsetResult = true;
01424                         } else {
01425                                 $valueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'select', $table);
01426                         }
01427                 }
01428 
01429                 if (!$unsetResult) {
01430                         $newVal=$this->checkValue_checkMax($tcaFieldConf, $valueArray);
01431                         $res['value'] = implode(',',$newVal);
01432                 } else {
01433                         unset($res['value']);
01434                 }
01435 
01436                 return $res;
01437         }
01438 
01453         function checkValue_group_select_file($valueArray,$tcaFieldConf,$curValue,$uploadedFileArray,$status,$table,$id,$recFID)        {
01454 
01455                 if (!$this->bypassFileHandling) {       // If filehandling should NOT be bypassed, do processing:
01456 
01457                                 // If any files are uploaded, add them to value array
01458                         if (is_array($uploadedFileArray) &&
01459                                 $uploadedFileArray['name'] &&
01460                                 strcmp($uploadedFileArray['tmp_name'],'none'))  {
01461                                         $valueArray[]=$uploadedFileArray['tmp_name'];
01462                                         $this->alternativeFileName[$uploadedFileArray['tmp_name']] = $uploadedFileArray['name'];
01463                         }
01464 
01465                                 // Creating fileFunc object.
01466                         if (!$this->fileFunc)   {
01467                                 $this->fileFunc = t3lib_div::makeInstance('t3lib_basicFileFunctions');
01468                                 $this->include_filefunctions=1;
01469                         }
01470                                 // Setting permitted extensions.
01471                         $all_files = Array();
01472                         $all_files['webspace']['allow'] = $tcaFieldConf['allowed'];
01473                         $all_files['webspace']['deny'] = $tcaFieldConf['disallowed'] ? $tcaFieldConf['disallowed'] : '*';
01474                         $all_files['ftpspace'] = $all_files['webspace'];
01475                         $this->fileFunc->init('', $all_files);
01476                 }
01477 
01478                         // If there is an upload folder defined:
01479                 if ($tcaFieldConf['uploadfolder'])      {
01480                         if (!$this->bypassFileHandling) {       // If filehandling should NOT be bypassed, do processing:
01481                                         // For logging..
01482                                 $propArr = $this->getRecordProperties($table,$id);
01483 
01484                                         // Get destrination path:
01485                                 $dest = $this->destPathFromUploadFolder($tcaFieldConf['uploadfolder']);
01486 
01487                                         // If we are updating:
01488                                 if ($status=='update')  {
01489 
01490                                                 // Traverse the input values and convert to absolute filenames in case the update happens to an autoVersionized record.
01491                                                 // 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!
01492                                                 // 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_.
01493                                                 // 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.
01494                                                 // Illustration of the problem comes here:
01495                                                 // 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.
01496                                                 // 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.
01497                                                 // 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.
01498                                                 // 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.
01499                                         if ($this->autoVersioningUpdate===TRUE) {
01500                                                 foreach($valueArray as $key => $theFile)        {
01501                                                         if ($theFile===basename($theFile))      {       // If it is an already attached file...
01502                                                                 $valueArray[$key] = PATH_site.$tcaFieldConf['uploadfolder'].'/'.$theFile;
01503                                                         }
01504                                                 }
01505                                         }
01506 
01507                                                 // Finding the CURRENT files listed, either from MM or from the current record.
01508                                         $theFileValues=array();
01509                                         if ($tcaFieldConf['MM'])        {       // If MM relations for the files also!
01510                                                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
01511                                                 $dbAnalysis->start('','files',$tcaFieldConf['MM'],$id);
01512                                                 reset($dbAnalysis->itemArray);
01513                                                 while (list($somekey,$someval)=each($dbAnalysis->itemArray))    {
01514                                                         if ($someval['id'])     {
01515                                                                 $theFileValues[]=$someval['id'];
01516                                                         }
01517                                                 }
01518                                         } else {
01519                                                 $theFileValues=t3lib_div::trimExplode(',',$curValue,1);
01520                                         }
01521 
01522                                                 // DELETE files: If existing files were found, traverse those and register files for deletion which has been removed:
01523                                         if (count($theFileValues))      {
01524                                                         // 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!)
01525                                                 foreach($valueArray as $key => $theFile)        {
01526                                                         if ($theFile && !strstr(t3lib_div::fixWindowsFilePath($theFile),'/'))   {
01527                                                                 $theFileValues = t3lib_div::removeArrayEntryByValue($theFileValues,$theFile);
01528                                                         }
01529                                                 }
01530 
01531                                                         // This array contains the filenames in the uploadfolder that should be deleted:
01532                                                 foreach($theFileValues as $key => $theFile)     {
01533                                                         $theFile = trim($theFile);
01534                                                         if (@is_file($dest.'/'.$theFile))       {
01535                                                                 $this->removeFilesStore[]=$dest.'/'.$theFile;
01536                                                         } elseif ($theFile) {
01537                                                                 $this->log($table,$id,5,0,1,"Could not delete file '%s' (does not exist). (%s)",10,array($dest.'/'.$theFile, $recFID),$propArr['event_pid']);
01538                                                         }
01539                                                 }
01540                                         }
01541                                 }
01542 
01543                                         // Traverse the submitted values:
01544                                 foreach($valueArray as $key => $theFile)        {
01545                                                 // 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)
01546                                         if (strstr(t3lib_div::fixWindowsFilePath($theFile),'/'))        {
01547                                                         // Init:
01548                                                 $maxSize = intval($tcaFieldConf['max_size']);
01549                                                 $cmd='';
01550                                                 $theDestFile='';                // Must be cleared. Else a faulty fileref may be inserted if the below code returns an error!
01551 
01552                                                         // Check various things before copying file:
01553                                                 if (@is_dir($dest) && (@is_file($theFile) || @is_uploaded_file($theFile)))      {               // File and destination must exist
01554 
01555                                                                 // Finding size. For safe_mode we have to rely on the size in the upload array if the file is uploaded.
01556                                                         if (is_uploaded_file($theFile) && $theFile==$uploadedFileArray['tmp_name'])     {
01557                                                                 $fileSize = $uploadedFileArray['size'];
01558                                                         } else {
01559                                                                 $fileSize = filesize($theFile);
01560                                                         }
01561 
01562                                                         if (!$maxSize || $fileSize<=($maxSize*1024))    {       // Check file size:
01563                                                                         // Prepare filename:
01564                                                                 $theEndFileName = isset($this->alternativeFileName[$theFile]) ? $this->alternativeFileName[$theFile] : $theFile;
01565                                                                 $fI = t3lib_div::split_fileref($theEndFileName);
01566 
01567                                                                         // Check for allowed extension:
01568                                                                 if ($this->fileFunc->checkIfAllowed($fI['fileext'], $dest, $theEndFileName)) {
01569                                                                         $theDestFile = $this->fileFunc->getUniqueName($this->fileFunc->cleanFileName($fI['file']), $dest);
01570 
01571                                                                                 // If we have a unique destination filename, then write the file:
01572                                                                         if ($theDestFile)       {
01573                                                                                 t3lib_div::upload_copy_move($theFile,$theDestFile);
01574                                                                                 $this->copiedFileMap[$theFile] = $theDestFile;
01575                                                                                 clearstatcache();
01576                                                                                 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']);
01577                                                                         } 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']);
01578                                                                 } else $this->log($table,$id,5,0,1,"Fileextension '%s' not allowed. (%s)",12,array($fI['fileext'], $recFID),$propArr['event_pid']);
01579                                                         } 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']);
01580                                                 } 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']);
01581 
01582                                                         // If the destination file was created, we will set the new filename in the value array, otherwise unset the entry in the value array!
01583                                                 if (@is_file($theDestFile))     {
01584                                                         $info = t3lib_div::split_fileref($theDestFile);
01585                                                         $valueArray[$key]=$info['file']; // The value is set to the new filename
01586                                                 } else {
01587                                                         unset($valueArray[$key]);       // The value is set to the new filename
01588                                                 }
01589                                         }
01590                                 }
01591                         }
01592 
01593                                 // 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!
01594                         if ($tcaFieldConf['MM'])        {
01595                                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
01596                                 $dbAnalysis->tableArray['files']=array();       // dummy
01597 
01598                                 reset($valueArray);
01599                                 while (list($key,$theFile)=each($valueArray))   {
01600                                                 // explode files
01601                                                 $dbAnalysis->itemArray[]['id']=$theFile;
01602                                 }
01603                                 if ($status=='update')  {
01604                                         $dbAnalysis->writeMM($tcaFieldConf['MM'],$id,0);
01605                                 } else {
01606                                         $this->dbAnalysisStore[] = array($dbAnalysis, $tcaFieldConf['MM'], $id, 0);     // This will be traversed later to execute the actions
01607                                 }
01608                                 $valueArray = $dbAnalysis->countItems();
01609                         }
01610                 }
01611 
01612                 return $valueArray;
01613         }
01614 
01627         function checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field)   {
01628                 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
01629 
01630                 if (is_array($value))   {
01631 
01632                                 // This value is necessary for flex form processing to happen on flexform fields in page records when they are copied.
01633                                 // The problem is, that when copying a page, flexfrom XML comes along in the array for the new record - but since $this->checkValue_currentRecord does not have a uid or pid for that sake, the t3lib_BEfunc::getFlexFormDS() function returns no good DS. For new records we do know the expected PID so therefore we send that with this special parameter. Only active when larger than zero.
01634                         $newRecordPidValue = $status=='new' ? $realPid : 0;
01635 
01636                                 // Get current value array:
01637                         $dataStructArray = t3lib_BEfunc::getFlexFormDS($tcaFieldConf,$this->checkValue_currentRecord,$table,'',TRUE,$newRecordPidValue);
01638 
01639                         $currentValueArray = t3lib_div::xml2array($curValue);
01640                         if (!is_array($currentValueArray))      $currentValueArray = array();
01641                         if (is_array($currentValueArray['meta']['currentLangId']))              unset($currentValueArray['meta']['currentLangId']);     // Remove all old meta for languages...
01642 
01643                                 // Evaluation of input values:
01644                         $value['data'] = $this->checkValue_flex_procInData($value['data'],$currentValueArray['data'],$uploadedFiles['data'],$dataStructArray,$PP);
01645 
01646                                 // Create XML and convert charsets from input value:
01647                         $xmlValue = $this->checkValue_flexArray2Xml($value,TRUE);
01648 
01649                                 // If we wanted to set UTF fixed:
01650                         // $storeInCharset='utf-8';
01651                         // $currentCharset=$GLOBALS['LANG']->charSet;
01652                         // $xmlValue = $GLOBALS['LANG']->csConvObj->conv($xmlValue,$currentCharset,$storeInCharset,1);
01653                         $storeInCharset=$GLOBALS['LANG']->charSet;
01654 
01655                                 // Merge them together IF they are both arrays:
01656                                 // 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).
01657                         if (is_array($currentValueArray))       {
01658                                 $arrValue = t3lib_div::xml2array($xmlValue);
01659                                 $arrValue = t3lib_div::array_merge_recursive_overrule($currentValueArray,$arrValue);
01660                                 $xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
01661                         }
01662 
01663                                 // Temporary fix to delete flex form elements:
01664                         $deleteCMDs = t3lib_div::_GP('_DELETE_FLEX_FORMdata');
01665                         if (is_array($deleteCMDs[$table][$id][$field]['data'])) {
01666                                 $arrValue = t3lib_div::xml2array($xmlValue);
01667                                 $this->_DELETE_FLEX_FORMdata($arrValue['data'],$deleteCMDs[$table][$id][$field]['data']);
01668                                 $xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
01669                         }
01670 
01671                                 // Temporary fix to move flex form elements up:
01672                         $moveCMDs = t3lib_div::_GP('_MOVEUP_FLEX_FORMdata');
01673                         if (is_array($moveCMDs[$table][$id][$field]['data']))   {
01674                                 $arrValue = t3lib_div::xml2array($xmlValue);
01675                                 $this->_MOVE_FLEX_FORMdata($arrValue['data'],$moveCMDs[$table][$id][$field]['data'], 'up');
01676                                 $xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
01677                         }
01678 
01679                                 // Temporary fix to move flex form elements down:
01680                         $moveCMDs = t3lib_div::_GP('_MOVEDOWN_FLEX_FORMdata');
01681                         if (is_array($moveCMDs[$table][$id][$field]['data']))   {
01682                                 $arrValue = t3lib_div::xml2array($xmlValue);
01683                                 $this->_MOVE_FLEX_FORMdata($arrValue['data'],$moveCMDs[$table][$id][$field]['data'], 'down');
01684                                 $xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
01685                         }
01686 
01687                                 // Create the value XML:
01688                         $res['value']='';
01689                         $res['value'].=$xmlValue;
01690                 } else {        // Passthrough...:
01691                         $res['value']=$value;
01692                 }
01693 
01694                 return $res;
01695         }
01696 
01704         function checkValue_flexArray2Xml($array, $addPrologue=FALSE)   {
01705                 $flexObj = t3lib_div::makeInstance('t3lib_flexformtools');
01706                 return $flexObj->flexArray2Xml($array, $addPrologue);
01707         }
01708 
01716         function _DELETE_FLEX_FORMdata(&$valueArrayToRemoveFrom,$deleteCMDS)    {
01717                 if (is_array($valueArrayToRemoveFrom) && is_array($deleteCMDS)) {
01718                         foreach($deleteCMDS as $key => $value)  {
01719                                 if (is_array($deleteCMDS[$key]))        {
01720                                         $this->_DELETE_FLEX_FORMdata($valueArrayToRemoveFrom[$key],$deleteCMDS[$key]);
01721                                 } else {
01722                                         unset($valueArrayToRemoveFrom[$key]);
01723                                 }
01724                         }
01725                 }
01726         }
01727 
01738         function _MOVE_FLEX_FORMdata(&$valueArrayToMoveIn, $moveCMDS, $direction)       {
01739                 if (is_array($valueArrayToMoveIn) && is_array($moveCMDS))       {
01740 
01741                                 // Only execute the first move command:
01742                         list ($key, $value) = each ($moveCMDS);
01743 
01744                         if (is_array($moveCMDS[$key]))  {
01745                                 $this->_MOVE_FLEX_FORMdata($valueArrayToMoveIn[$key],$moveCMDS[$key], $direction);
01746                         } else {
01747                                 switch ($direction) {
01748                                         case 'up':
01749                                                 if ($key > 1) {
01750                                                         $tmpArr = $valueArrayToMoveIn[$key];
01751                                                         $valueArrayToMoveIn[$key] = $valueArrayToMoveIn[$key-1];
01752                                                         $valueArrayToMoveIn[$key-1] = $tmpArr;
01753                                                 }
01754                                         break;
01755                                         case 'down':
01756                                                 if ($key < count($valueArrayToMoveIn)) {
01757                                                         $tmpArr = $valueArrayToMoveIn[$key];
01758                                                         $valueArrayToMoveIn[$key] = $valueArrayToMoveIn[$key+1];
01759                                                         $valueArrayToMoveIn[$key+1] = $tmpArr;
01760                                                 }
01761                                         break;
01762                                 }
01763                         }
01764                 }
01765         }
01766 
01778         function checkValue_inline($res,$value,$tcaFieldConf,$PP,$field)        {
01779                 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
01780 
01781                 if (!$tcaFieldConf['foreign_table'])    {
01782                         return false;   // Fatal error, inline fields should always have a foreign_table defined
01783                 }
01784 
01785                         // When values are sent they come as comma-separated values which are exploded by this function:
01786                 $valueArray = t3lib_div::trimExplode(',', $value);
01787 
01788                         // Remove duplicates: (should not be needed)
01789                 $valueArray = array_unique($valueArray);
01790 
01791                         // Example for received data:
01792                         // $value = 45,NEW4555fdf59d154,12,123
01793                         // We need to decide whether we use the stack or can save the relation directly.
01794                 if(strpos($value, 'NEW') !== false || !t3lib_div::testInt($id)) {
01795                         $this->remapStack[] = array(
01796                                 'func' => 'checkValue_group_select_processDBdata',
01797                                 'args' => array($valueArray,$tcaFieldConf,$id,$status,'inline',$table),
01798                                 'pos' => array('valueArray' => 0, 'tcaFieldConf' => 1, 'id' => 2, 'table' => 5),
01799                                 'field' => $field
01800                         );
01801                         unset($res['value']);
01802                 } elseif($value || t3lib_div::testInt($id)) {
01803                         $newValueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'inline', $table);
01804 
01805                                 // Checking that the number of items is correct
01806                         $newVal = $this->checkValue_checkMax($tcaFieldConf, $newValueArray);
01807                         $res['value'] = implode(',',$newVal);
01808                 }
01809 
01810                 return $res;
01811         }
01812 
01821         function checkValue_checkMax($tcaFieldConf, $valueArray) {
01822                 // 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...
01823 
01824                 $valueArrayC = count($valueArray);
01825 
01826                         // 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.
01827                 $maxI = isset($tcaFieldConf['maxitems']) ? intval($tcaFieldConf['maxitems']):1;
01828                 if ($valueArrayC > $maxI)       {$valueArrayC=$maxI;}   // Checking for not too many elements
01829 
01830                         // Dumping array to list
01831                 $newVal=array();
01832                 foreach($valueArray as $nextVal)        {
01833                         if ($valueArrayC==0)    {break;}
01834                         $valueArrayC--;
01835                         $newVal[]=$nextVal;
01836                 }
01837 
01838                 return $newVal;
01839         }
01840 
01841 
01842 
01843 
01844 
01845 
01846 
01847 
01848 
01849 
01850 
01851 
01852 
01853 
01854 
01855 
01856 
01857         /*********************************************
01858          *
01859          * Helper functions for evaluation functions.
01860          *
01861          ********************************************/
01862 
01873         function getUnique($table,$field,$value,$id,$newPid=0)  {
01874                 global $TCA;
01875 
01876                         // Initialize:
01877                 t3lib_div::loadTCA($table);
01878                 $whereAdd='';
01879                 $newValue='';
01880                 if (intval($newPid))    { $whereAdd.=' AND pid='.intval($newPid); } else { $whereAdd.=' AND pid>=0'; }  // "AND pid>=0" for versioning
01881                 $whereAdd.=$this->deleteClause($table);
01882 
01883                         // If the field is configured in TCA, proceed:
01884                 if (is_array($TCA[$table]) && is_array($TCA[$table]['columns'][$field]))        {
01885 
01886                                 // Look for a record which might already have the value:
01887                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, $field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($value, $table).' AND uid!='.intval($id).$whereAdd);
01888                         $counter = 0;
01889 
01890                                 // For as long as records with the test-value existing, try again (with incremented numbers appended).
01891                         while ($GLOBALS['TYPO3_DB']->sql_num_rows($res))        {
01892                                 $newValue = $value.$counter;
01893                                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, $field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($newValue, $table).' AND uid!='.intval($id).$whereAdd);
01894                                 $counter++;
01895                                 if ($counter>100)       { break; }      // At "100" it will give up and accept a duplicate - should probably be fixed to a small hash string instead...!
01896                         }
01897                                 // If the new value is there:
01898                         $value = strlen($newValue) ? $newValue : $value;
01899                 }
01900                 return $value;
01901         }
01902 
01911         function checkValue_input_Eval($value,$evalArray,$is_in)        {
01912                 $res = Array();
01913                 $newValue = $value;
01914                 $set = true;
01915 
01916                 foreach($evalArray as $func)    {
01917                         switch($func)   {
01918                                 case 'int':
01919                                 case 'year':
01920                                 case 'date':
01921                                 case 'datetime':
01922                                 case 'time':
01923                                 case 'timesec':
01924                                         $value = intval($value);
01925                                 break;
01926                                 case 'double2':
01927                                         $theDec = 0;
01928                                         for ($a=strlen($value); $a>0; $a--)     {
01929                                                 if (substr($value,$a-1,1)=='.' || substr($value,$a-1,1)==',')   {
01930                                                         $theDec = substr($value,$a);
01931                                                         $value = substr($value,0,$a-1);
01932                                                         break;
01933                                                 }
01934                                         }
01935                                         $theDec = ereg_replace('[^0-9]','',$theDec).'00';
01936                                         $value = intval(str_replace(' ','',$value)).'.'.substr($theDec,0,2);
01937                                 break;
01938                                 case 'md5':
01939                                         if (strlen($value)!=32){$set=false;}
01940                                 break;
01941                                 case 'trim':
01942                                         $value = trim($value);
01943                                 break;
01944                                 case 'upper':
01945                                         $value = strtoupper($value);
01946 #                                       $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.
01947                                 break;
01948                                 case 'lower':
01949                                         $value = strtolower($value);
01950 #                                       $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.
01951                                 break;
01952                                 case 'required':
01953                                         if (!$value)    {$set=0;}
01954                                 break;
01955                                 case 'is_in':
01956                                         $c=strlen($value);
01957                                         if ($c) {
01958                                                 $newVal = '';
01959                                                 for ($a=0;$a<$c;$a++)   {
01960                                                         $char = substr($value,$a,1);
01961                                                         if (strstr($is_in,$char))       {
01962                                                                 $newVal.=$char;
01963                                                         }
01964                                                 }
01965                                                 $value = $newVal;
01966                                         }
01967                                 break;
01968                                 case 'nospace':
01969                                         $value = str_replace(' ','',$value);
01970                                 break;
01971                                 case 'alpha':
01972                                         $value = ereg_replace('[^a-zA-Z]','',$value);
01973                                 break;
01974                                 case 'num':
01975                                         $value = ereg_replace('[^0-9]','',$value);
01976                                 break;
01977                                 case 'alphanum':
01978                                         $value = ereg_replace('[^a-zA-Z0-9]','',$value);
01979                                 break;
01980                                 case 'alphanum_x':
01981                                         $value = ereg_replace('[^a-zA-Z0-9_-]','',$value);
01982                                 break;
01983                                 default:
01984                                         if (substr($func, 0, 3) == 'tx_')       {
01985                                                 $evalObj = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func].':&'.$func);
01986                                                 if (is_object($evalObj) && method_exists($evalObj, 'evaluateFieldValue'))       {
01987                                                         $value = $evalObj->evaluateFieldValue($value, $is_in, $set);
01988                                                 }
01989                                         }
01990                                 break;
01991                         }
01992                 }
01993                 if ($set)       {$res['value'] = $value;}
01994                 return $res;
01995         }
01996 
02008         function checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,$type,$currentTable)       {
02009                 $tables = $type=='group'?$tcaFieldConf['allowed']:$tcaFieldConf['foreign_table'].','.$tcaFieldConf['neg_foreign_table'];
02010                 $prep = $type=='group'?$tcaFieldConf['prepend_tname']:$tcaFieldConf['neg_foreign_table'];
02011 
02012                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
02013                 $dbAnalysis->registerNonTableValues=$tcaFieldConf['allowNonIdValues'] ? 1 : 0;
02014                 $dbAnalysis->start(implode(',',$valueArray),$tables, '', 0, $currentTable, $tcaFieldConf);
02015 
02016                 if ($tcaFieldConf['MM'])        {
02017                         if ($status=='update')  {
02018                                 $dbAnalysis->writeMM($tcaFieldConf['MM'],$id,$prep);
02019                         } else {
02020                                 $this->dbAnalysisStore[] = array($dbAnalysis,$tcaFieldConf['MM'],$id,$prep);    // This will be traversed later to execute the actions
02021                         }
02022                         $valueArray = $dbAnalysis->countItems();
02023                 } elseif ($type == 'inline') {
02024                         if ($tcaFieldConf['foreign_field']) {
02025                                         // if the record was imported, sorting was also imported, so skip this
02026                                 $skipSorting = $this->callFromImpExp ? true : false;
02027                                         // update record in intermediate table (sorting & pointer uid to parent record)
02028                                 $dbAnalysis->writeForeignField($tcaFieldConf, $id, 0, $skipSorting);
02029                                 $valueArray = $dbAnalysis->countItems();
02030                         } else {
02031                                 $valueArray = $dbAnalysis->getValueArray($prep);
02032                                 if ($prep) {
02033                                                 // @TODO: Do we want to support relations to multiple tables in Comma Separated Lists?
02034                                         $valueArray = $dbAnalysis->convertPosNeg($valueArray,$tcaFieldConf['foreign_table'],$tcaFieldConf['neg_foreign_table']);
02035                                 }
02036                         }
02037                 } else {
02038                         $valueArray = $dbAnalysis->getValueArray($prep);
02039                         if ($type=='select' && $prep)   {
02040                                 $valueArray = $dbAnalysis->convertPosNeg($valueArray,$tcaFieldConf['foreign_table'],$tcaFieldConf['neg_foreign_table']);
02041                         }
02042                 }
02043 
02044                         // Here we should see if 1) the records exist anymore, 2) which are new and check if the BE_USER has read-access to the new ones.
02045                 return $valueArray;
02046         }
02047 
02054         function checkValue_group_select_explodeSelectGroupValue($value)        {
02055                 $valueArray = t3lib_div::trimExplode(',',$value,1);
02056                 reset($valueArray);
02057                 while(list($key,$newVal)=each($valueArray))     {
02058                         $temp=explode('|',$newVal,2);
02059                         $valueArray[$key] = str_replace(',','',str_replace('|','',rawurldecode($temp[0])));
02060                 }
02061                 return $valueArray;
02062         }
02063 
02078         function checkValue_flex_procInData($dataPart,$dataPart_current,$uploadedFiles,$dataStructArray,$pParams,$callBackFunc='')      {
02079 #debug(array($dataPart,$dataPart_current,$dataStructArray));
02080                 if (is_array($dataPart))        {
02081                         foreach($dataPart as $sKey => $sheetDef)        {
02082                                 list ($dataStruct,$actualSheet) = t3lib_div::resolveSheetDefInDS($dataStructArray,$sKey);
02083 #debug(array($dataStruct,$actualSheet,$sheetDef,$actualSheet,$sKey));
02084                                 if (is_array($dataStruct) && $actualSheet==$sKey && is_array($sheetDef))        {
02085                                         foreach($sheetDef as $lKey => $lData)   {
02086                                                 $this->checkValue_flex_procInData_travDS(
02087                                                         $dataPart[$sKey][$lKey],
02088                                                         $dataPart_current[$sKey][$lKey],
02089                                                         $uploadedFiles[$sKey][$lKey],
02090                                                         $dataStruct['ROOT']['el'],
02091                                                         $pParams,
02092                                                         $callBackFunc,
02093                                                         $sKey.'/'.$lKey.'/'
02094                                                 );
02095                                         }
02096                                 }
02097                         }
02098                 }
02099 
02100                 return $dataPart;
02101         }
02102 
02117         function checkValue_flex_procInData_travDS(&$dataValues,$dataValues_current,$uploadedFiles,$DSelements,$pParams,$callBackFunc,$structurePath)   {
02118                 if (is_array($DSelements))      {
02119 
02120                                 // For each DS element:
02121                         foreach($DSelements as $key => $dsConf) {
02122 
02123                                                 // Array/Section:
02124                                 if ($DSelements[$key]['type']=='array') {
02125                                         if (is_array($dataValues[$key]['el']))  {
02126                                                 if ($DSelements[$key]['section'])       {
02127                                                         foreach($dataValues[$key]['el'] as $ik => $el)  {
02128                                                                 $theKey = key($el);
02129                                                                 if (is_array($dataValues[$key]['el'][$ik][$theKey]['el']))      {
02130                                                                         $this->checkValue_flex_procInData_travDS(
02131                                                                                         $dataValues[$key]['el'][$ik][$theKey]['el'],
02132                                                                                         $dataValues_current[$key]['el'][$ik][$theKey]['el'],
02133                                                                                         $uploadedFiles[$key]['el'][$ik][$theKey]['el'],
02134                                                                                         $DSelements[$key]['el'][$theKey]['el'],
02135                                                                                         $pParams,
02136                                                                                         $callBackFunc,
02137                                                                                         $structurePath.$key.'/el/'.$ik.'/'.$theKey.'/el/'
02138                                                                                 );
02139                                                                 }
02140                                                         }
02141                                                 } else {
02142                                                         if (!isset($dataValues[$key]['el']))    $dataValues[$key]['el']=array();
02143                                                         $this->checkValue_flex_procInData_travDS(
02144                                                                         $dataValues[$key]['el'],
02145                                                                         $dataValues_current[$key]['el'],
02146                                                                         $uploadedFiles[$key]['el'],
02147                                                                         $DSelements[$key]['el'],
02148                                                                         $pParams,
02149                                                                         $callBackFunc,
02150                                                                         $structurePath.$key.'/el/'
02151                                                                 );
02152                                                 }
02153                                         }
02154                                 } else {
02155                                         if (is_array($dsConf['TCEforms']['config']) && is_array($dataValues[$key]))     {
02156                                                 foreach($dataValues[$key] as $vKey => $data)    {
02157 
02158                                                         if ($callBackFunc)      {
02159                                                                 if (is_object($this->callBackObj))      {
02160                                                                         $res = $this->callBackObj->$callBackFunc(
02161                                                                                                 $pParams,
02162                                                                                                 $dsConf['TCEforms']['config'],
02163                                                                                                 $dataValues[$key][$vKey],
02164                                                                                                 $dataValues_current[$key][$vKey],
02165                                                                                                 $uploadedFiles[$key][$vKey],
02166                                                                                                 $structurePath.$key.'/'.$vKey.'/'
02167                                                                                         );
02168                                                                 } else {
02169                                                                         $res = $this->$callBackFunc(
02170                                                                                                 $pParams,
02171                                                                                                 $dsConf['TCEforms']['config'],
02172                                                                                                 $dataValues[$key][$vKey],
02173                                                                                                 $dataValues_current[$key][$vKey],
02174                                                                                                 $uploadedFiles[$key][$vKey]
02175                                                                                         );
02176                                                                 }
02177                                                         } else {        // Default
02178                                                                 list($CVtable,$CVid,$CVcurValue,$CVstatus,$CVrealPid,$CVrecFID,$CVtscPID) = $pParams;
02179 
02180                                                                 $res = $this->checkValue_SW(
02181                                                                                         array(),
02182                                                                                         $dataValues[$key][$vKey],
02183                                                                                         $dsConf['TCEforms']['config'],
02184                                                                                         $CVtable,
02185                                                                                         $CVid,
02186                                                                                         $dataValues_current[$key][$vKey],
02187                                                                                         $CVstatus,
02188                                                                                         $CVrealPid,
02189                                                                                         $CVrecFID,
02190                                                                                         '',
02191                                                                                         $uploadedFiles[$key][$vKey],
02192                                                                                         array(),
02193                                                                                         $CVtscPID
02194                                                                                 );
02195 
02196                                                                         // Look for RTE transformation of field:
02197                                                                 if ($dataValues[$key]['_TRANSFORM_'.$vKey] == 'RTE' && !$this->dontProcessTransformations)      {
02198 
02199                                                                                 // Unsetting trigger field - we absolutely don't want that into the data storage!
02200                                                                         unset($dataValues[$key]['_TRANSFORM_'.$vKey]);
02201 
02202                                                                         if (isset($res['value']))       {
02203 
02204                                                                                         // Calculating/Retrieving some values here:
02205                                                                                 list(,,$recFieldName) = explode(':', $CVrecFID);
02206                                                                                 $theTypeString = t3lib_BEfunc::getTCAtypeValue($CVtable,$this->checkValue_currentRecord);
02207                                                                                 $specConf = t3lib_BEfunc::getSpecConfParts('',$dsConf['TCEforms']['defaultExtras']);
02208 
02209                                                                                         // Find, thisConfig:
02210                                                                                 $RTEsetup = $this->BE_USER->getTSConfig('RTE',t3lib_BEfunc::getPagesTSconfig($CVtscPID));
02211                                                                                 $thisConfig = t3lib_BEfunc::RTEsetup($RTEsetup['properties'],$CVtable,$recFieldName,$theTypeString);
02212 
02213                                                                                         // Get RTE object, draw form and set flag:
02214                                                                                 $RTEobj = &t3lib_BEfunc::RTEgetObj();
02215                                                                                 if (is_object($RTEobj)) {
02216                                                                                         $res['value'] = $RTEobj->transformContent('db',$res['value'],$CVtable,$recFieldName,$this->checkValue_currentRecord,$specConf,$thisConfig,'',$CVrealPid);
02217                                                                                 } else {
02218                                                                                         debug('NO RTE OBJECT FOUND!');
02219                                                                                 }
02220                                                                         }
02221                                                                 }
02222                                                         }
02223 
02224                                                                 // Adding the value:
02225                                                         if (isset($res['value']))       {
02226                                                                 $dataValues[$key][$vKey] = $res['value'];
02227                                                         }
02228                                                 }
02229                                         }
02230                                 }
02231                         }
02232                 }
02233         }
02234 
02235 
02236 
02237 
02238 
02239 
02240 
02241 
02242 
02243 
02244 
02245 
02246 
02247 
02248 
02249 
02250 
02251         /*********************************************
02252          *
02253          * PROCESSING COMMANDS
02254          *
02255          ********************************************/
02256 
02263         function process_cmdmap() {
02264                 global $TCA, $TYPO3_CONF_VARS;
02265 
02266                         // Editing frozen:
02267                 if ($this->BE_USER->workspace!==0 && $this->BE_USER->workspaceRec['freeze'])    {
02268                         $this->newlog('All editing in this workspace has been frozen!',1);
02269                         return FALSE;
02270                 }
02271 
02272                         // Hook initialization:
02273                 $hookObjectsArr = array();
02274                 if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'])) {
02275                         foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'] as $classRef) {
02276                                 $hookObjectsArr[] = &t3lib_div::getUserObj($classRef);
02277                         }
02278                 }
02279 
02280                         // Traverse command map:
02281                 reset($this->cmdmap);
02282                 while(list($table,) = each($this->cmdmap))      {
02283 
02284                                 // Check if the table may be modified!
02285                         $modifyAccessList = $this->checkModifyAccessList($table);
02286                         if (!$modifyAccessList) {
02287                                 $id = 0;
02288                                 $this->log($table,$id,2,0,1,"Attempt to modify table '%s' without permission",1,array($table));
02289                         }       // FIXME: $id not set here (Comment added by Sebastian Kurfuerst)
02290 
02291                                 // Check basic permissions and circumstances:
02292                         if (isset($TCA[$table]) && !$this->tableReadOnly($table) && is_array($this->cmdmap[$table]) && $modifyAccessList)       {
02293 
02294                                         // Traverse the command map:
02295                                 foreach($this->cmdmap[$table] as $id => $incomingCmdArray)      {
02296                                         if (is_array($incomingCmdArray))        {       // have found a command.
02297 
02298                                                         // Get command and value (notice, only one command is observed at a time!):
02299                                                 reset($incomingCmdArray);
02300                                                 $command = key($incomingCmdArray);
02301                                                 $value = current($incomingCmdArray);
02302 
02303                                                 foreach($hookObjectsArr as $hookObj) {
02304                                                         if (method_exists($hookObj, 'processCmdmap_preProcess')) {
02305                                                                 $hookObj->processCmdmap_preProcess($command, $table, $id, $value, $this);
02306                                                         }
02307                                                 }
02308 
02309                                                         // Init copyMapping array:
02310                                                 $this->copyMappingArray = Array();              // Must clear this array before call from here to those functions: Contains mapping information between new and old id numbers.
02311 
02312                                                         // Branch, based on command
02313                                                 switch ($command)       {
02314                                                         case 'move':
02315                                                                 $this->moveRecord($table,$id,$value);
02316                                                         break;
02317                                                         case 'copy':
02318                                                                 if ($table === 'pages') {
02319                                                                         $this->copyPages($id,$value);
02320                                                                 } else {
02321                                                                         $this->copyRecord($table,$id,$value,1);
02322                                                                 }
02323                                                         break;
02324                                                         case 'localize':
02325                                                                 $this->localize($table,$id,$value);
02326                                                         break;
02327                                                         case 'version':
02328                                                                 switch ((string)$value['action'])       {
02329                                                                         case 'new':
02330                                                                                 $versionizeTree = t3lib_div::intInRange(!isset($value['treeLevels'])?-1:$value['treeLevels'],-1,100);
02331                                                                                 if ($table == 'pages' && $versionizeTree>=0)    {
02332                                                                                         $this->versionizePages($id,$value['label'],$versionizeTree);
02333                                                                                 } else {
02334                                                                                         $this->versionizeRecord($table,$id,$value['label']);
02335                                                                                 }
02336                                                                         break;
02337                                                                         case 'swap':
02338                                                                                 $this->version_swap($table,$id,$value['swapWith'],$value['swapIntoWS']);
02339                                                                         break;
02340                                                                         case 'clearWSID':
02341                                                                                 $this->version_clearWSID($table,$id);
02342                                                                         break;
02343                                                                         case 'setStage':
02344                                                                                 $idList = t3lib_div::trimExplode(',',$id,1);
02345                                                                                 foreach($idList as $id) {
02346                                                                                         $this->version_setStage($table,$id,$value['stageId'],$value['comment']?$value['comment']:$this->generalComment);
02347                                                                                 }
02348                                                                         break;
02349                                                                 }
02350                                                         break;
02351                                                         case 'delete':
02352                                                                 $this->deleteAction($table, $id);
02353                                                         break;
02354                                                         case 'undelete':
02355                                                                 $this->undeleteRecord($table, $id);
02356                                                         break;
02357                                                 }
02358 
02359                                                 foreach($hookObjectsArr as $hookObj) {
02360                                                         if (method_exists($hookObj, 'processCmdmap_postProcess')) {
02361                                                                 $hookObj->processCmdmap_postProcess($command, $table, $id, $value, $this);
02362                                                         }
02363                                                 }
02364 
02365                                                         // Merging the copy-array info together for remapping purposes.
02366                                                 $this->copyMappingArray_merged= t3lib_div::array_merge_recursive_overrule($this->copyMappingArray_merged,$this->copyMappingArray);
02367                                         }
02368                                 }
02369                         }
02370                 }
02371 
02372                         // Finally, before exit, check if there are ID references to remap. This might be the case if versioning or copying has taken place!
02373                 $this->remapListedDBRecords();
02374         }
02375 
02376 
02377 
02378 
02379 
02380 
02381 
02382 
02383 
02384 
02385 
02386         /*********************************************
02387          *
02388          * Cmd: Copying
02389          *
02390          ********************************************/
02391 
02403         function copyRecord($table,$uid,$destPid,$first=0,$overrideValues=array(),$excludeFields='')    {
02404                 global $TCA;
02405 
02406                 $uid = $origUid = intval($uid);
02407                 if ($TCA[$table] && $uid)       {
02408                         t3lib_div::loadTCA($table);
02409 /*
02410                                 // 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)
02411                         if ($lookForLiveVersion = t3lib_BEfunc::getLiveVersionOfRecord($table,$uid,'uid'))      {
02412                                 $uid = $lookForLiveVersion['uid'];
02413                         }
02414                                 // Get workspace version of the source record, if any: Then we will copy workspace version instead:
02415                         if ($WSversion = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, $table, $uid, 'uid,t3ver_oid'))   {
02416                                 $uid = $WSversion['uid'];
02417                         }
02418                                 // 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.
02419 */
02420                         if ($this->doesRecordExist($table,$uid,'show')) {               // This checks if the record can be selected which is all that a copy action requires.
02421                                 $data = Array();
02422 
02423                                 $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));
02424 
02425                                 // $row = $this->recordInfo($table,$uid,'*');
02426                                 $row = t3lib_BEfunc::getRecordWSOL($table,$uid);        // So it copies (and localized) content from workspace...
02427                                 if (is_array($row))     {
02428 
02429                                                 // Initializing:
02430                                         $theNewID = uniqid('NEW');
02431                                         $enableField = isset($TCA[$table]['ctrl']['enablecolumns']) ? $TCA[$table]['ctrl']['enablecolumns']['disabled'] : '';
02432                                         $headerField = $TCA[$table]['ctrl']['label'];
02433 
02434                                                 // Getting default data:
02435                                         $defaultData = $this->newFieldArray($table);
02436 
02437                                                 // Getting "copy-after" fields if applicable:
02438                                                 // 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.
02439                                         $copyAfterFields = $destPid<0 ? $this->fixCopyAfterDuplFields($table,$uid,abs($destPid),0) : array();
02440 
02441                                                 // Page TSconfig related:
02442                                         $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...
02443                                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
02444                                         $tE = $this->getTableEntries($table,$TSConfig);
02445 
02446                                                 // Traverse ALL fields of the selected record:
02447                                         foreach($row as $field => $value)       {
02448                                                 if (!in_array($field,$nonFields))       {
02449 
02450                                                                 // Get TCA configuration for the field:
02451                                                         $conf = $TCA[$table]['columns'][$field]['config'];
02452 
02453                                                                 // Preparation/Processing of the value:
02454                                                         if ($field=='pid')      {       // "pid" is hardcoded of course:
02455                                                                 $value = $destPid;
02456                                                         } elseif (isset($overrideValues[$field]))       {       // Override value...
02457                                                                 $value = $overrideValues[$field];
02458                                                         } elseif (isset($copyAfterFields[$field]))      {       // Copy-after value if available:
02459                                                                 $value = $copyAfterFields[$field];
02460                                                         } elseif ($TCA[$table]['ctrl']['setToDefaultOnCopy'] && t3lib_div::inList($TCA[$table]['ctrl']['setToDefaultOnCopy'],$field))   {       // Revert to default for some fields:
02461                                                                 $value = $defaultData[$field];
02462                                                         } else {
02463                                                                         // Hide at copy may override:
02464                                                                 if ($first && $field==$enableField && $TCA[$table]['ctrl']['hideAtCopy'] && !$this->neverHideAtCopy && !$tE['disableHideAtCopy'])       {
02465                                                                         $value=1;
02466                                                                 }
02467                                                                         // Prepend label on copy:
02468                                                                 if ($first && $field==$headerField && $TCA[$table]['ctrl']['prependAtCopy'] && !$tE['disablePrependAtCopy'])    {
02469                                                                         $value = $this->getCopyHeader($table,$this->resolvePid($table,$destPid),$field,$this->clearPrefixFromValue($table,$value),0);
02470                                                                 }
02471                                                                         // Processing based on the TCA config field type (files, references, flexforms...)
02472                                                                 $value = $this->copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf,$tscPID);
02473                                                         }
02474 
02475                                                                 // Add value to array.
02476                                                         $data[$table][$theNewID][$field] = $value;
02477                                                 }
02478                                         }
02479 
02480                                                 // Overriding values:
02481                                         if ($TCA[$table]['ctrl']['editlock'])   {
02482                                                 $data[$table][$theNewID][$TCA[$table]['ctrl']['editlock']] = 0;
02483                                         }
02484 
02485                                                 // Setting original UID:
02486                                         if ($TCA[$table]['ctrl']['origUid'])    {
02487                                                 $data[$table][$theNewID][$TCA[$table]['ctrl']['origUid']] = $uid;
02488                                         }
02489 
02490                                                 // Do the copy by simply submitting the array through TCEmain:
02491                                         $copyTCE = t3lib_div::makeInstance('t3lib_TCEmain');
02492                                         $copyTCE->stripslashes_values = 0;
02493                                         $copyTCE->copyTree = $this->copyTree;
02494                                         $copyTCE->cachedTSconfig = $this->cachedTSconfig;       // Copy forth the cached TSconfig
02495                                         $copyTCE->dontProcessTransformations=1;         // Transformations should NOT be carried out during copy
02496 
02497                                         $copyTCE->start($data,'',$this->BE_USER);
02498                                         $copyTCE->process_datamap();
02499 
02500                                                 // Getting the new UID:
02501                                         $theNewSQLID = $copyTCE->substNEWwithIDs[$theNewID];
02502                                         if ($theNewSQLID)       {
02503                                                 $this->copyMappingArray[$table][$origUid] = $theNewSQLID;
02504                                         }
02505 
02506                                                 // Copy back the cached TSconfig
02507                                         $this->cachedTSconfig = $copyTCE->cachedTSconfig;
02508                                         $this->errorLog = array_merge($this->errorLog,$copyTCE->errorLog);
02509                                         unset($copyTCE);
02510 
02511                                         return $theNewSQLID;
02512                                 } else $this->log($table,$uid,3,0,1,'Attempt to copy record that did not exist!');
02513                         } else $this->log($table,$uid,3,0,1,'Attempt to copy record without permission');
02514                 }
02515         }
02516 
02525         function copyPages($uid,$destPid)       {
02526 
02527                         // Initialize:
02528                 $uid = intval($uid);
02529                 $destPid = intval($destPid);
02530 
02531                         // Finding list of tables to copy.
02532                 $copyTablesArray = $this->admin ? $this->compileAdminTables() : explode(',',$this->BE_USER->groupData['tables_modify']);        // These are the tables, the user may modify
02533                 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
02534                         foreach($copyTablesArray as $k => $table)       {
02535                                 if (!$table || !t3lib_div::inList($this->copyWhichTables.',pages',$table))      {       // pages are always going...
02536                                         unset($copyTablesArray[$k]);
02537                                 }
02538                         }
02539                 }
02540                 $copyTablesArray = array_unique($copyTablesArray);
02541 
02542                         // Begin to copy pages if we're allowed to:
02543                 if ($this->admin || in_array('pages',$copyTablesArray)) {
02544 
02545                                 // Copy this page we're on. And set first-flag (this will trigger that the record is hidden if that is configured)!
02546                         $theNewRootID = $this->copySpecificPage($uid,$destPid,$copyTablesArray,1);
02547 
02548                                 // If we're going to copy recursively...:
02549                         if ($theNewRootID && $this->copyTree)   {
02550 
02551                                         // Get ALL subpages to copy (read-permissions are respected!):
02552                                 $CPtable = $this->int_pageTreeInfo(Array(), $uid, intval($this->copyTree), $theNewRootID);
02553 
02554                                         // Now copying the subpages:
02555                                 foreach($CPtable as $thePageUid => $thePagePid) {
02556                                         $newPid = $this->copyMappingArray['pages'][$thePagePid];
02557                                         if (isset($newPid))     {
02558                                                 $this->copySpecificPage($thePageUid,$newPid,$copyTablesArray);
02559                                         } else {
02560                                                 $this->log('pages',$uid,5,0,1,'Something went wrong during copying branch');
02561                                                 break;
02562                                         }
02563                                 }
02564                         }       // else the page was not copied. Too bad...
02565                 } else {
02566                         $this->log('pages',$uid,5,0,1,'Attempt to copy page without permission to this table');
02567                 }
02568         }
02569 
02579         function copySpecificPage($uid,$destPid,$copyTablesArray,$first=0)      {
02580                 global $TCA;
02581 
02582                         // Copy the page itself:
02583                 $theNewRootID = $this->copyRecord('pages',$uid,$destPid,$first);
02584 
02585                         // If a new page was created upon the copy operation we will proceed with all the tables ON that page:
02586                 if ($theNewRootID)      {
02587                         foreach($copyTablesArray as $table)     {
02588                                 if ($table && is_array($TCA[$table]) && $table!='pages')        {       // all records under the page is copied.
02589                                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($uid).$this->deleteClause($table), '', ($TCA[$table]['ctrl']['sortby'] ? $TCA[$table]['ctrl']['sortby'].' DESC' : ''));
02590                                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))     {
02591                                                 $this->copyRecord($table,$row['uid'], $theNewRootID);   // Copying each of the underlying records...
02592                                         }
02593                                 }
02594                         }
02595                         return $theNewRootID;
02596                 }
02597         }
02598 
02613         function copyRecord_raw($table,$uid,$pid,$overrideArray=array())        {
02614                 global $TCA;
02615 
02616                 $uid = intval($uid);
02617                 if ($TCA[$table] && $uid)       {
02618                         t3lib_div::loadTCA($table);
02619                         if ($this->doesRecordExist($table,$uid,'show')) {
02620 
02621                                         // Set up fields which should not be processed. They are still written - just passed through no-questions-asked!
02622                                 $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');
02623 
02624                                         // Select main record:
02625                                 $row = $this->recordInfo($table,$uid,'*');
02626                                 if (is_array($row))     {
02627 
02628                                                 // Merge in override array.
02629                                         $row = array_merge($row,$overrideArray);
02630 
02631                                                 // Traverse ALL fields of the selected record:
02632                                         foreach($row as $field => $value)       {
02633                                                 if (!in_array($field,$nonFields))       {
02634 
02635                                                                 // Get TCA configuration for the field:
02636                                                         $conf = $TCA[$table]['columns'][$field]['config'];
02637                                                         if (is_array($conf))    {
02638                                                                         // Processing based on the TCA config field type (files, references, flexforms...)
02639                                                                 $value = $this->copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf,$pid);
02640                                                         }
02641 
02642                                                                 // Add value to array.
02643                                                         $row[$field] = $value;
02644                                                 }
02645                                         }
02646 
02647                                                 // Force versioning related fields:
02648                                         $row['pid'] = $pid;
02649 
02650                                                 // Setting original UID:
02651                                         if ($TCA[$table]['ctrl']['origUid'])    {
02652                                                 $row[$TCA[$table]['ctrl']['origUid']] = $uid;
02653                                         }
02654 
02655                                                 // Do the copy by internal function
02656                                         $theNewSQLID = $this->insertNewCopyVersion($table,$row,$pid);
02657                                         if ($theNewSQLID)       {
02658                                                 $this->dbAnalysisStoreExec();
02659                                                 $this->dbAnalysisStore = array();
02660                                                 return $this->copyMappingArray[$table][$uid] = $theNewSQLID;
02661                                         }
02662                                 } else $this->log($table,$uid,3,0,1,'Attempt to rawcopy/versionize record that did not exist!');
02663                         } else $this->log($table,$uid,3,0,1,'Attempt to rawcopy/versionize record without copy permission');
02664                 }
02665         }
02666 
02677         function rawCopyPageContent($old_pid,$new_pid,$copyTablesArray) {
02678                 global $TCA;
02679 
02680                 if ($new_pid)   {
02681                         foreach($copyTablesArray as $table)     {
02682                                 if ($table && is_array($TCA[$table]) && $table!='pages')        {       // all records under the page is copied.
02683                                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($old_pid).$this->deleteClause($table));
02684                                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))     {
02685                                                 $this->copyRecord_raw($table,$row['uid'],$new_pid);     // Copying each of the underlying records (method RAW)
02686                                         }
02687                                 }
02688                         }
02689                 }
02690         }
02691 
02701         function insertNewCopyVersion($table,$fieldArray,$realPid)      {
02702                 global $TCA;
02703 
02704                 $id = uniqid('NEW');
02705 
02706                         // $fieldArray is set as current record.
02707                         // 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...
02708                 $this->checkValue_currentRecord = $fieldArray;
02709 
02710                         // Traverse record and input-process each value:
02711                 foreach($fieldArray as $field => $fieldValue)   {
02712                         if (isset($TCA[$table]['columns'][$field]))     {
02713                                         // Evaluating the value.
02714                                 $res = $this->checkValue($table,$field,$fieldValue,$id,'new',$realPid,0);
02715                                 if (isset($res['value']))       {
02716                                         $fieldArray[$field] = $res['value'];
02717                                 }
02718                         }
02719                 }
02720 
02721                         // System fields being set:
02722                 if ($TCA[$table]['ctrl']['crdate'])     {
02723                         $fieldArray[$TCA[$table]['ctrl']['crdate']]=time();
02724                 }
02725                 if ($TCA[$table]['ctrl']['cruser_id'])  {
02726                         $fieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid;
02727                 }
02728                 if ($TCA[$table]['ctrl']['tstamp'])     {
02729                         $fieldArray[$TCA[$table]['ctrl']['tstamp']]=time();
02730                 }
02731 
02732                         // Finally, insert record:
02733                 $this->insertDB($table,$id,$fieldArray, TRUE);
02734 
02735                         // Return new id:
02736                 return $this->substNEWwithIDs[$id];
02737         }
02738 
02753         function copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf,$realDestPid)     {
02754                 global $TCA;
02755 
02756                         // 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)
02757                 $value = $this->copyRecord_procFilesRefs($conf, $uid, $value);
02758                 $inlineSubType = $this->getInlineFieldType($conf);
02759 
02760                         // Register if there are references to take care of or MM is used on an inline field (no change to value):
02761                 if ($this->isReferenceField($conf) || $inlineSubType == 'mm')   {
02762                         $allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table'];
02763                         $prependName = $conf['type']=='group' ? $conf['prepend_tname'] : $conf['neg_foreign_table'];
02764                         if ($conf['MM'])        {
02765                                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
02766                                 $dbAnalysis->start('', $allowedTables, $conf['MM'], $uid, $table, $conf);
02767                                 $value = implode(',',$dbAnalysis->getValueArray($prependName));
02768                         }
02769                         if ($value)     {       // Setting the value in this array will notify the remapListedDBRecords() function that this field MAY need references to be corrected
02770                                 $this->registerDBList[$table][$uid][$field] = $value;
02771                         }
02772 
02773                         // if another inline subtype is used (foreign_field, mm with attributes or simply item list)
02774                 } elseif ($inlineSubType !== false) {
02775                         $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
02776                         $dbAnalysis->start($value, $conf['foreign_table'], $conf['MM'], $uid, $table, $conf);
02777 
02778                                 // walk through the items, copy them and remember the new id
02779                         foreach ($dbAnalysis->itemArray as $k => $v) {
02780                                         // Take the real positive integer if available:
02781                                 if (t3lib_div::testInt($realDestPid) && $realDestPid >= 0) {
02782                                         $childDestPid = $realDestPid;
02783                                         // If the $realDestPid is not a valid integer or negative (e.g. workspaces):
02784                                         // @TODO: Check again concerning workspaces
02785                                 } else {
02786                                         $childDestPid = -$v['id'];
02787                                 }
02788                                 $newId = $this->copyRecord($v['table'], $v['id'], $childDestPid);
02789                                 $dbAnalysis->itemArray[$k]['id'] = $newId;
02790                         }
02791 
02792                                 // store the new values, we will set up the uids for the subtype later on
02793                         $value = implode(',',$dbAnalysis->getValueArray());
02794                         $this->registerDBList[$table][$uid][$field] = $value;
02795                 }
02796 
02797                         // 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())
02798                 if ($conf['type']=='flex')      {
02799 
02800                                 // Get current value array:
02801                         $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $row, $table);
02802                         $currentValueArray = t3lib_div::xml2array($value);
02803 
02804                                 // Traversing the XML structure, processing files:
02805                         if (is_array($currentValueArray))       {
02806                                 $currentValueArray['data'] = $this->checkValue_flex_procInData(
02807                                                         $currentValueArray['data'],
02808                                                         array(),        // Not used.
02809                                                         array(),        // Not used.
02810                                                         $dataStructArray,
02811                                                         array($table,$uid,$field),      // Parameters.
02812                                                         'copyRecord_flexFormCallBack'
02813                                                 );
02814                                 $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.
02815                         }
02816                 }
02817 
02818                 return $value;
02819         }
02820 
02832         function copyRecord_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2)   {
02833 
02834                         // Extract parameters:
02835                 list($table, $uid, $field) = $pParams;
02836 
02837                         // Process references and files, currently that means only the files, prepending absolute paths:
02838                 $dataValue = $this->copyRecord_procFilesRefs($dsConf, $uid, $dataValue);
02839 
02840                         // If references are set for this field, set flag so they can be corrected later (in ->remapListedDBRecords())
02841                 if ($this->isReferenceField($dsConf) && strlen($dataValue)) {
02842                         $this->registerDBList[$table][$uid][$field] = 'FlexForm_reference';
02843                 }
02844 
02845                         // Return
02846                 return array('value' => $dataValue);
02847         }
02848 
02860         function copyRecord_procFilesRefs($conf, $uid, $value)  {
02861 
02862                         // Prepend absolute paths to files:
02863                 if ($conf['type']=='group' && $conf['internal_type']=='file')   {
02864 
02865                                 // Get an array with files as values:
02866                         if ($conf['MM'])        {
02867                                 $theFileValues = array();
02868 
02869                                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
02870                                 $dbAnalysis->start('', 'files', $conf['MM'], $uid);
02871 
02872                                 foreach($dbAnalysis->itemArray as $somekey => $someval) {
02873                                         if ($someval['id'])     {
02874                                                 $theFileValues[] = $someval['id'];
02875                                         }
02876                                 }
02877                         } else {
02878                                 $theFileValues = t3lib_div::trimExplode(',',$value,1);
02879                         }
02880 
02881                                 // Traverse this array of files:
02882                         $uploadFolder = $conf['uploadfolder'];
02883                         $dest = $this->destPathFromUploadFolder($uploadFolder);
02884                         $newValue = array();
02885 
02886                         foreach($theFileValues as $file)        {
02887                                 if (trim($file))        {
02888                                         $realFile = $dest.'/'.trim($file);
02889                                         if (@is_file($realFile))        {
02890                                                 $newValue[] = $realFile;
02891                                         }
02892                                 }
02893                         }
02894 
02895                                 // 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...)
02896                         $value = implode(',',$newValue);
02897                 }
02898 
02899                         // Return the new value:
02900                 return $value;
02901         }
02902 
02903 
02904 
02905 
02906 
02907 
02908 
02909 
02910 
02911 
02912 
02913 
02914 
02915         /*********************************************
02916          *
02917          * Cmd: Moving, Localizing
02918          *
02919          ********************************************/
02920 
02929         function moveRecord($table,$uid,$destPid)       {
02930                 global $TCA, $TYPO3_CONF_VARS;
02931 
02932                 if ($TCA[$table])       {
02933 
02934                                 // Prepare user defined objects (if any) for hooks which extend this function:
02935                         $hookObjectsArr = array();
02936                         if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['moveRecordClass'])) {
02937                                 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['moveRecordClass'] as $classRef) {
02938                                         $hookObjectsArr[] = &t3lib_div::getUserObj($classRef);
02939                                 }
02940                         }
02941 
02942                                 // 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)
02943                         if ($lookForLiveVersion = t3lib_BEfunc::getLiveVersionOfRecord($table,$uid,'uid'))      {
02944                                 $uid = $lookForLiveVersion['uid'];
02945                         }
02946 
02947                                 // Get workspace version of the source record, if any:
02948                         $WSversion = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, $table, $uid, 'uid,t3ver_oid');
02949 
02950                                 // Initialize:
02951                         $sortRow = $TCA[$table]['ctrl']['sortby'];
02952                         $destPid = intval($destPid);
02953                         $origDestPid = $destPid;
02954 
02955                         $propArr = $this->getRecordProperties($table,$uid);     // Get this before we change the pid (for logging)
02956                         $moveRec = $this->getRecordProperties($table,$uid,TRUE);
02957                         $resolvedPid = $this->resolvePid($table,$destPid);      // This is the actual pid of the moving to destination
02958 
02959                                 // 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.
02960                                 // 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.
02961                         if ($table!='pages' || $resolvedPid==$moveRec['pid'])   {
02962                                 $mayMoveAccess = $this->checkRecordUpdateAccess($table,$uid);   // Edit rights for the record...
02963                         } else {
02964                                 $mayMoveAccess = $this->doesRecordExist($table,$uid,'delete');
02965                         }
02966 
02967                                 // 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
02968                         if ($table!='pages' || $resolvedPid!=$moveRec['pid'])   {
02969                                 $mayInsertAccess = $this->checkRecordInsertAccess($table,$resolvedPid,4);       // Insert rights for the record...
02970                         } else {
02971                                 $mayInsertAccess = $this->checkRecordUpdateAccess($table,$uid);
02972                         }
02973 
02974                                 // Check workspace permissions:
02975                         $workspaceAccessBlocked = array();
02976                         $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...
02977                         $destRes = $this->BE_USER->workspaceAllowLiveRecordsInPID($resolvedPid,$table);
02978                                 // Workspace source check:
02979                         if ($errorCode = $this->BE_USER->workspaceCannotEditRecord($table, $WSversion['uid'] ? $WSversion['uid'] : $uid))       {
02980                                 $workspaceAccessBlocked['src1']='Record could not be edited in workspace: '.$errorCode.' ';
02981                         } else {
02982                                 if (!$recIsNewVersion && $this->BE_USER->workspaceAllowLiveRecordsInPID($moveRec['pid'],$table)<=0)     {
02983                                         $workspaceAccessBlocked['src2']='Could not remove record from table "'.$table.'" from its page "'.$moveRec['pid'].'" ';
02984                                 }
02985                         }
02986                                 // Workspace destination check:
02987                         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.
02988                                 $workspaceAccessBlocked['dest1']='Could not insert record from table "'.$table.'" in destination PID "'.$resolvedPid.'" ';
02989                         } elseif ($destRes==1 && $WSversion['uid'])     {
02990                                 $workspaceAccessBlocked['dest2']='Could not insert other versions in destination PID ';
02991                         }
02992 
02993                                 // 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...)
02994                         if (($destPid<0 && !$sortRow) || $destPid>=0)   {       // $destPid>=0 because we must correct pid in case of versioning "page" types.
02995                                 $destPid = $resolvedPid;
02996                         }
02997 
02998                                 // Timestamp field:
02999                         $updateFields = array();
03000                         if ($TCA[$table]['ctrl']['tstamp'])     {
03001                                 $updateFields[$TCA[$table]['ctrl']['tstamp']] = time();
03002                         }
03003 
03004                                         // If moving is allowed, begin the processing:
03005                         if (!count($workspaceAccessBlocked))    {
03006                                 if ($mayMoveAccess)     {
03007                                         if ($destPid>=0)        {       // insert as first element on page (where uid = $destPid)
03008                                                 if ($mayInsertAccess)   {
03009                                                         if ($table!='pages' || $this->destNotInsideSelf($destPid,$uid)) {
03010                                                                 $this->clear_cache($table,$uid);        // clear cache before moving
03011 
03012                                                                 $updateFields['pid'] = $destPid;        // Setting PID
03013 
03014                                                                         // table is sorted by 'sortby'
03015                                                                 if ($sortRow)   {
03016                                                                         $sortNumber = $this->getSortNumber($table,$uid,$destPid);
03017                                                                         $updateFields[$sortRow] = $sortNumber;
03018                                                                 }
03019 
03020                                                                         // check for child records that have also to be moved
03021                                                                 $this->moveRecord_procFields($table,$uid,$destPid);
03022                                                                         // Create query for update:
03023                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields);
03024 
03025                                                                         // Call post processing hooks:
03026                                                                 foreach($hookObjectsArr as $hookObj) {
03027                                                                         if (method_exists($hookObj, 'moveRecord_firstElementPostProcess')) {
03028                                                                                 $hookObj->moveRecord_firstElementPostProcess($table, $uid, $destPid, $moveRec, $updateFields, $this);
03029                                                                         }
03030                                                                 }
03031 
03032                                                                         // Logging...
03033                                                                 $newPropArr = $this->getRecordProperties($table,$uid);
03034                                                                 $oldpagePropArr = $this->getRecordProperties('pages',$propArr['pid']);
03035                                                                 $newpagePropArr = $this->getRecordProperties('pages',$destPid);
03036 
03037                                                                 if ($destPid!=$propArr['pid'])  {
03038                                                                         $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
03039                                                                         $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
03040                                                                 } else {
03041                                                                         $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
03042                                                                 }
03043                                                                 $this->clear_cache($table,$uid);        // clear cache after moving
03044                                                                 $this->fixUniqueInPid($table,$uid);
03045                                                                         // fixCopyAfterDuplFields
03046                                                                 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.
03047                                                         } else {
03048                                                                 $destPropArr = $this->getRecordProperties('pages',$destPid);
03049                                                                 $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']);
03050                                                         }
03051                                                 }
03052                                         } else {        // Put after another record
03053                                                 if ($sortRow)   {       // table is being sorted
03054                                                         $sortInfo = $this->getSortNumber($table,$uid,$destPid);
03055                                                         $destPid = $sortInfo['pid'];    // Setting the destPid to the new pid of the record.
03056                                                         if (is_array($sortInfo))        {       // If not an array, there was an error (which is already logged)
03057                                                                 if ($mayInsertAccess)   {
03058                                                                         if ($table!='pages' || $this->destNotInsideSelf($destPid,$uid)) {
03059                                                                                 $this->clear_cache($table,$uid);        // clear cache before moving
03060 
03061                                                                                         // We now update the pid and sortnumber
03062                                                                                 $updateFields['pid'] = $destPid;
03063                                                                                 $updateFields[$sortRow] = $sortInfo['sortNumber'];
03064 
03065                                                                                         // check for child records that have also to be moved
03066                                                                                 $this->moveRecord_procFields($table,$uid,$destPid);
03067                                                                                         // Create query for update:
03068                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields);
03069 
03070                                                                                         // Call post processing hooks:
03071                                                                                 foreach($hookObjectsArr as $hookObj) {
03072                                                                                         if (method_exists($hookObj, 'moveRecord_afterAnotherElementPostProcess')) {
03073                                                                                                 $hookObj->moveRecord_afterAnotherElementPostProcess($table, $uid, $destPid, $origDestPid, $moveRec, $updateFields, $this);
03074                                                                                         }
03075                                                                                 }
03076 
03077                                                                                         // Logging...
03078                                                                                 $newPropArr = $this->getRecordProperties($table,$uid);
03079                                                                                 $oldpagePropArr = $this->getRecordProperties('pages',$propArr['pid']);
03080                                                                                 if ($destPid!=$propArr['pid'])  {
03081                                                                                         $newpagePropArr = $this->getRecordProperties('pages',$destPid);
03082                                                                                         $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
03083                                                                                         $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
03084                                                                                 } else {
03085                                                                                         $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
03086                                                                                 }
03087 
03088                                                                                         // clear cache after moving
03089                                                                                 $this->clear_cache($table,$uid);
03090 
03091                                                                                         // fixUniqueInPid
03092                                                                                 $this->fixUniqueInPid($table,$uid);
03093 
03094                                                                                         // fixCopyAfterDuplFields
03095                                                                                 if ($origDestPid<0)     {$this->fixCopyAfterDuplFields($table,$uid,abs($origDestPid),1);}
03096                                                                         } else {
03097                                                                                 $destPropArr = $this->getRecordProperties('pages',$destPid);
03098                                                                                 $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']);
03099                                                                         }
03100                                                                 }
03101                                                         }
03102                                                 } else {
03103                                                         $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']);
03104                                                 }
03105                                         }
03106                                 } else {
03107                                         $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']);
03108                                 }
03109                         } else {
03110                                 $this->newlog("Move attempt failed due to workspace restrictions: ".implode(' ',$workspaceAccessBlocked),1);
03111                         }
03112                 }
03113         }
03114 
03124         function moveRecord_procFields($table,$uid,$destPid) {
03125                 t3lib_div::loadTCA($table);
03126                 $conf = $GLOBALS['TCA'][$table]['columns'];
03127                 $row = t3lib_BEfunc::getRecordWSOL($table,$uid);
03128                 foreach ($row as $field => $value) {
03129                         $this->moveRecord_procBasedOnFieldType($table,$uid,$destPid,$field,$value,$conf[$field]['config']);
03130                 }
03131         }
03132 
03144         function moveRecord_procBasedOnFieldType($table,$uid,$destPid,$field,$value,$conf) {
03145                 $moveTable = '';
03146                 $moveIds = array();
03147 
03148                 if ($conf['type'] == 'inline')  {
03149                         $foreign_table = $conf['foreign_table'];
03150 
03151                         if ($foreign_table) {
03152                                 $inlineType = $this->getInlineFieldType($conf);
03153                                 if ($inlineType == 'list' || $inlineType == 'field') {
03154                                         $moveTable = $foreign_table;
03155                                         $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
03156                                         $dbAnalysis->start($value, $conf['foreign_table'], '', $uid, $table, $conf);
03157                                 }
03158                         }
03159                 }
03160 
03161                         // move the records
03162                 if (isset($dbAnalysis)) {
03163                         foreach ($dbAnalysis->itemArray as $v) {
03164                                 $this->moveRecord($v['table'],$v['id'],$destPid);
03165                         }
03166                 }
03167         }
03168 
03178         function localize($table,$uid,$language)        {
03179                 global $TCA;
03180 
03181                 $uid = intval($uid);
03182 
03183                 if ($TCA[$table] && $uid)       {
03184                         t3lib_div::loadTCA($table);
03185 
03186                         if (($TCA[$table]['ctrl']['languageField'] && $TCA[$table]['ctrl']['transOrigPointerField'] && !$TCA[$table]['ctrl']['transOrigPointerTable']) || $table==='pages')     {
03187                                 if ($langRec = t3lib_BEfunc::getRecord('sys_language',intval($language),'uid,title'))   {
03188                                         if ($this->doesRecordExist($table,$uid,'show')) {
03189 
03190                                                 $row = t3lib_BEfunc::getRecordWSOL($table,$uid);        // Getting workspace overlay if possible - this will localize versions in workspace if any
03191                                                 if (is_array($row))     {
03192                                                         if ($row[$TCA[$table]['ctrl']['languageField']] <= 0 || $table==='pages')       {
03193                                                                 if ($row[$TCA[$table]['ctrl']['transOrigPointerField']] == 0 || $table==='pages')       {
03194                                                                         if ($table==='pages')   {
03195                                                                                 $pass = $TCA[$table]['ctrl']['transForeignTable']==='pages_language_overlay' && !t3lib_BEfunc::getRecordsByField('pages_language_overlay','pid',$uid,' AND '.$TCA['pages_language_overlay']['ctrl']['languageField'].'='.intval($langRec['uid']));
03196                                                                                 $Ttable = 'pages_language_overlay';
03197                                                                                 t3lib_div::loadTCA($Ttable);
03198                                                                         } else {
03199                                                                                 $pass = !t3lib_BEfunc::getRecordsByField($table,$TCA[$table]['ctrl']['transOrigPointerField'],$uid,'AND pid='.intval($row['pid']).' AND '.$TCA[$table]['ctrl']['languageField'].'='.intval($langRec['uid']));
03200                                                                                 $Ttable = $table;
03201                                                                         }
03202 
03203                                                                         if ($pass)      {
03204 
03205                                                                                         // Initialize:
03206                                                                                 $overrideValues = array();
03207                                                                                 $excludeFields = array();
03208 
03209                                                                                         // Set override values:
03210                                                                                 $overrideValues[$TCA[$Ttable]['ctrl']['languageField']] = $langRec['uid'];
03211                                                                                 $overrideValues[$TCA[$Ttable]['ctrl']['transOrigPointerField']] = $uid;
03212 
03213                                                                                         // Set exclude Fields:
03214                                                                                 foreach($TCA[$Ttable]['columns'] as $fN => $fCfg)       {
03215                                                                                         if ($fCfg['l10n_mode']=='prefixLangTitle')      {       // Check if we are just prefixing:
03216                                                                                                 if (($fCfg['config']['type']=='text' || $fCfg['config']['type']=='input') && strlen($row[$fN])) {
03217                                                                                                         list($tscPID) = t3lib_BEfunc::getTSCpid($table,$uid,'');
03218                                                                                                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
03219 
03220                                                                                                         if (isset($TSConfig['translateToMessage']) && strlen($TSConfig['translateToMessage']))  {
03221                                                                                                                 $translateToMsg = @sprintf($TSConfig['translateToMessage'], $langRec['title']);
03222                                                                                                         }
03223                                                                                                         if (!strlen($translateToMsg))   {
03224                                                                                                                 $translateToMsg = 'Translate to '.$langRec['title'].':';
03225                                                                                                         }
03226 
03227                                                                                                         $overrideValues[$fN] = '['.$translateToMsg.'] '.$row[$fN];
03228                                                                                                 }
03229                                                                                         } elseif (t3lib_div::inList('exclude,noCopy,mergeIfNotBlank',$fCfg['l10n_mode']) && $fN!=$TCA[$Ttable]['ctrl']['languageField'] && $fN!=$TCA[$Ttable]['ctrl']['transOrigPointerField']) {        // Otherwise, do not copy field (unless it is the language field or pointer to the original language)
03230                                                                                                 $excludeFields[] = $fN;
03231                                                                                         }
03232                                                                                 }
03233 
03234                                                                                 if ($Ttable === $table) {
03235 
03236                                                                                                 // Execute the copy:
03237                                                                                         $this->copyRecord($table,$uid,-$uid,1,$overrideValues,implode(',',$excludeFields));
03238                                                                                 } else {
03239 
03240                                                                                                 // Create new record:
03241                                                                                         $copyTCE = t3lib_div::makeInstance('t3lib_TCEmain');
03242                                                                                         $copyTCE->stripslashes_values = 0;
03243                                                                                         $copyTCE->cachedTSconfig = $this->cachedTSconfig;       // Copy forth the cached TSconfig
03244                                                                                         $copyTCE->dontProcessTransformations=1;         // Transformations should NOT be carried out during copy
03245 
03246                                                                                         $copyTCE->start(array($Ttable=>array('NEW'=>$overrideValues)),'',$this->BE_USER);
03247                                                                                         $copyTCE->process_datamap();
03248 
03249                                                                                                 // Getting the new UID as if it had been copied:
03250                                                                                         $theNewSQLID = $copyTCE->substNEWwithIDs['NEW'];
03251                                                                                         if ($theNewSQLID)       {
03252                                                                                                         // If is by design that $Ttable is used and not $table! See "l10nmgr" extension. Could be debated, but this is what I chose for this "pseudo case"
03253                                                                                                 $this->copyMappingArray[$Ttable][$uid] = $theNewSQLID;
03254                                                                                         }
03255                                                                                 }
03256                                                                         } else $this->newlog('Localization failed; There already was a localization for this language of the record!',1);
03257                                                                 } else $this->newlog('Localization failed; Source record contained a reference to an original default record (which is strange)!',1);
03258                                                         } else $this->newlog('Localization failed; Source record had another language than "Default" or "All" defined!',1);
03259                                                 } else $this->newlog('Attempt to localize record that did not exist!',1);
03260                                         } else $this->newlog('Attempt to localize record without permission',1);
03261                                 } else $this->newlog('Sys language UID "'.$language.'" not found valid!',1);
03262                         } else $this->newlog('Localization failed; "languageField" and "transOrigPointerField" must be defined for the table!',1);
03263                 }
03264         }
03265 
03266 
03267 
03268 
03269 
03270 
03271 
03272 
03273 
03274 
03275 
03276 
03277 
03278 
03279         /*********************************************
03280          *
03281          * Cmd: Deleting
03282          *
03283          ********************************************/
03284 
03292         function deleteAction($table, $id)      {
03293                 global $TCA;
03294 
03295                 $delRec = t3lib_BEfunc::getRecord($table, $id);
03296 
03297                 if (is_array($delRec))  {       // Record asked to be deleted was found:
03298 
03299                                 // For Live version, try if there is a workspace version because if so, rather "delete" that instead
03300                         if ($delRec['pid']!=-1) {       // Look, if record is an offline version, then delete directly:
03301                                 if ($wsVersion = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, $table, $id))     {
03302                                         $delRec = $wsVersion;
03303                                         $id = $delRec['uid'];
03304                                 }
03305                         }
03306 
03307                         if ($delRec['pid']==-1) {       // Look, if record is an offline version, then delete directly:
03308                                 if ($TCA[$table]['ctrl']['versioningWS'])       {
03309                                         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.
03310                                                 $liveRec = t3lib_BEfunc::getLiveVersionOfRecord($table,$id,'uid,t3ver_state');
03311 
03312                                                 if ($delRec['t3ver_wsid']==0 || (int)$liveRec['t3ver_state']!==1)       {       // Delete those in WS 0 + if their live records state was not "Placeholder".
03313                                                         $this->deleteEl($table, $id);
03314                                                 } else {        // If live record was placeholder, rather clear it from workspace (because it clears both version and placeholder).
03315                                                         $this->version_clearWSID($table,$id);
03316                                                 }
03317                                         } else $this->newlog('Tried to delete record from another workspace',1);
03318                                 } else $this->newlog('Versioning not enabled for record with PID = -1!',2);
03319                         } elseif ($res = $this->BE_USER->workspaceAllowLiveRecordsInPID($delRec['pid'], $table))        {       // Look, if record is "online" or in a versionized branch, then delete directly.
03320                                 if ($res>0)     {
03321                                         $this->deleteEl($table, $id);
03322                                 } else $this->newlog('Stage of root point did not allow for deletion',1);
03323                         } else {
03324                                 // Otherwise, try to delete by versionization:
03325                                 $this->versionizeRecord($table,$id,'DELETED!',TRUE);
03326                         }
03327                 }
03328         }
03329 
03339         function deleteEl($table, $uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE)   {
03340                 if ($table == 'pages')  {
03341                         $this->deletePages($uid, $noRecordCheck, $forceHardDelete);
03342                 } else {
03343                         $this->deleteVersionsForRecord($table,$uid,$forceHardDelete);
03344                         $this->deleteRecord($table, $uid, $noRecordCheck, $forceHardDelete);
03345                 }
03346         }
03347 
03356         function deleteVersionsForRecord($table, $uid, $forceHardDelete)        {
03357                 $versions = t3lib_BEfunc::selectVersionsOfRecord($table, $uid, 'uid,pid');
03358                 if (is_array($versions))        {
03359                         foreach($versions as $verRec)   {
03360                                 if (!$verRec['_CURRENT_VERSION'])       {
03361                                         if ($table == 'pages')  {
03362                                                 $this->deletePages($verRec['uid'], TRUE, $forceHardDelete);
03363                                         } else {
03364                                                 $this->deleteRecord($table, $verRec['uid'], TRUE, $forceHardDelete);
03365                                         }
03366                                 }
03367                         }
03368                 }
03369         }
03370 
03378         function undeleteRecord($table,$uid)    {
03379                 $this->deleteRecord($table,$uid,TRUE,FALSE,TRUE);
03380         }
03381 
03395         function deleteRecord($table,$uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE,$undeleteRecord=FALSE)  {
03396                 global $TCA;
03397 
03398                 $uid = intval($uid);
03399                 if ($TCA[$table] && $uid)       {
03400                         if ($noRecordCheck || $this->doesRecordExist($table,$uid,'delete'))     {
03401                                 $this->clear_cache($table,$uid);        // clear cache before deleting the record, else the correct page cannot be identified by clear_cache
03402 
03403                                 $propArr = $this->getRecordProperties($table, $uid);
03404                                 $pagePropArr = $this->getRecordProperties('pages', $propArr['pid']);
03405 
03406                                 $deleteRow = $TCA[$table]['ctrl']['delete'];
03407                                 if ($deleteRow && !$forceHardDelete)    {
03408                                         $value = $undeleteRecord ? 0 : 1;
03409                                         $updateFields = array(
03410                                                 $deleteRow => $value
03411                                         );
03412 
03413                                         if ($TCA[$table]['ctrl']['tstamp']) {
03414                                                 $updateFields[$TCA[$table]['ctrl']['tstamp']] = time();
03415                                         }
03416 
03417                                                 // If the table is sorted, then the sorting number is set very high
03418                                         if ($TCA[$table]['ctrl']['sortby'] && !$undeleteRecord) {
03419                                                 $updateFields[$TCA[$table]['ctrl']['sortby']] = 1000000000;
03420                                         }
03421 
03422                                                 // before (un-)deleting this record, check for child records or references
03423                                         $this->deleteRecord_procFields($table, $uid, $undeleteRecord);
03424                                         $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields);
03425                                 } else {
03426 
03427                                                 // Fetches all fields with flexforms and look for files to delete:
03428                                         t3lib_div::loadTCA($table);
03429                                         foreach($TCA[$table]['columns'] as $fieldName => $cfg)  {
03430                                                 $conf = $cfg['config'];
03431 
03432                                                 switch($conf['type'])   {
03433                                                         case 'flex':
03434                                                                 $flexObj = t3lib_div::makeInstance('t3lib_flexformtools');
03435                                                                 $flexObj->traverseFlexFormXMLData($table,$fieldName,t3lib_BEfunc::getRecordRaw($table,'uid='.intval($uid)),$this,'deleteRecord_flexFormCallBack');
03436                                                         break;
03437                                                 }
03438                                         }
03439 
03440                                                 // Fetches all fields that holds references to files
03441                                         $fileFieldArr = $this->extFileFields($table);
03442                                         if (count($fileFieldArr))       {
03443                                                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(implode(',',$fileFieldArr), $table, 'uid='.intval($uid));
03444                                                 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))        {
03445                                                         $fArray = $fileFieldArr;
03446                                                         foreach($fArray as $theField)   {       // MISSING: Support for MM file relations!
03447                                                                 $this->extFileFunctions($table,$theField,$row[$theField],'deleteAll');          // This deletes files that belonged to this record.
03448                                                         }
03449                                                 } else {
03450                                                         $this->log($table,$uid,3,0,100,'Delete: Zero rows in result when trying to read filenames from record which should be deleted');
03451                                                 }
03452                                         }
03453 
03454                                                 // Delete the hard way...:
03455                                         $GLOBALS['TYPO3_DB']->exec_DELETEquery($table, 'uid='.intval($uid));
03456                                 }
03457 
03458                                 $state = $undeleteRecord ? 1 : 3;       // 1 means insert, 3 means delete
03459                                 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
03460                                         if ($forceHardDelete) {
03461                                                 $message = "Record '%s' (%s) was deleted unrecoverable from page '%s' (%s)";
03462                                         }
03463                                         else {
03464                                                 $message = $state == 1 ?
03465                                                         "Record '%s' (%s) was restored on page '%s' (%s)" :
03466                                                         "Record '%s' (%s) was deleted from page '%s' (%s)";
03467                                         }
03468                                         $this->log($table, $uid, $state, 0, 0,
03469                                                                 $message, 0,
03470                                                                 array(
03471                                                                         $propArr['header'],
03472                                                                         $table.':'.$uid,
03473                                                                         $pagePropArr['header'],
03474                                                                         $propArr['pid']
03475                                                                         ),
03476                                                                 $propArr['pid']);
03477 
03478                                 } else {
03479                                         $this->log($table,$uid,$state,0,100,$GLOBALS['TYPO3_DB']->sql_error());
03480                                 }
03481 
03482                                         // Update reference index:
03483                                 $this->updateRefIndex($table,$uid);
03484 
03485                                         // if there are entries in the updateRefIndexStack
03486                                 if (is_array($this->updateRefIndexStack[$table]) && is_array($this->updateRefIndexStack[$table][$uid])) {
03487                                         while ($args = array_pop($this->updateRefIndexStack[$table][$uid])) {
03488                                                         // $args[0]: table, $args[1]: uid
03489                                                 $this->updateRefIndex($args[0], $args[1]);
03490                                         }
03491                                         unset($this->updateRefIndexStack[$table][$uid]);
03492                                 }
03493 
03494                         } else $this->log($table,$uid,3,0,1,'Attempt to delete record without delete-permissions');
03495                 }
03496         }
03497 
03501         function deleteRecord_flexFormCallBack($dsArr, $dataValue, $PA, $structurePath, &$pObj) {
03502 
03503                         // Use reference index object to find files in fields:
03504                 $refIndexObj = t3lib_div::makeInstance('t3lib_refindex');
03505                 $files = $refIndexObj->getRelations_procFiles($dataValue, $dsArr['TCEforms']['config'], $PA['uid']);
03506 
03507                         // Traverse files and delete them:
03508                 if (is_array($files))   {
03509                         foreach($files as $dat) {
03510                                 if (@is_file($dat['ID_absFile']))       {
03511                                         unlink ($dat['ID_absFile']);
03512 #echo 'DELETE FlexFormFile:'.$dat['ID_absFile'].chr(10);
03513                                 } else {
03514                                         $this->log($table,0,3,0,100,"Delete: Referenced file '".$dat['ID_absFile']."' that was supposed to be deleted together with it's record didn't exist");
03515                                 }
03516                         }
03517                 }
03518         }
03519 
03528         function deletePages($uid,$force=FALSE,$forceHardDelete=FALSE)  {
03529                         // Getting list of pages to delete:
03530                 if ($force)     {
03531                         $brExist = $this->doesBranchExist('',$uid,0,1);         // returns the branch WITHOUT permission checks (0 secures that)
03532                         $res = t3lib_div::trimExplode(',',$brExist.$uid,1);
03533                 } else {
03534                         $res = $this->canDeletePage($uid);
03535                 }
03536 
03537                         // Perform deletion if not error:
03538                 if (is_array($res))     {
03539                         foreach($res as $deleteId)      {
03540                                 $this->deleteSpecificPage($deleteId,$forceHardDelete);
03541                         }
03542                 } else {
03543                         $this->newlog($res,1);
03544                 }
03545         }
03546 
03556         function deleteSpecificPage($uid,$forceHardDelete=FALSE)        {
03557                 global $TCA;
03558                 reset ($TCA);
03559                 $uid = intval($uid);
03560                 if ($uid)       {
03561                         while (list($table)=each($TCA)) {
03562                                 if ($table!='pages')    {
03563                                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($uid).$this->deleteClause($table));
03564                                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))     {
03565                                                 $this->deleteVersionsForRecord($table,$row['uid'],$forceHardDelete);
03566                                                 $this->deleteRecord($table,$row['uid'], TRUE, $forceHardDelete);
03567                                         }
03568                                 }
03569                         }
03570                         $this->deleteVersionsForRecord('pages',$uid,$forceHardDelete);
03571                         $this->deleteRecord('pages',$uid, TRUE, $forceHardDelete);
03572                 }
03573         }
03574 
03581         function canDeletePage($uid)    {
03582                 if ($this->doesRecordExist('pages',$uid,'delete'))      {       // If we may at all delete this page
03583                         if ($this->deleteTree)  {
03584                                 $brExist = $this->doesBranchExist('',$uid,$this->pMap['delete'],1);     // returns the branch
03585                                 if ($brExist != -1)     {       // Checks if we had permissions
03586                                         if ($this->noRecordsFromUnallowedTables($brExist.$uid)) {
03587                                                 return t3lib_div::trimExplode(',',$brExist.$uid,1);
03588                                         } else return 'Attempt to delete records from disallowed tables';
03589                                 } else return 'Attempt to delete pages in branch without permissions';
03590                         } else {
03591                                 $brExist = $this->doesBranchExist('',$uid,$this->pMap['delete'],1);     // returns the branch
03592                                 if ($brExist == '')     {       // Checks if branch exists
03593                                         if ($this->noRecordsFromUnallowedTables($uid))  {
03594                                                 return array($uid);
03595                                         } else return 'Attempt to delete records from disallowed tables';
03596                                 } else return 'Attempt to delete page which has subpages';
03597                         }
03598                 } else return 'Attempt to delete page without permissions';
03599         }
03600 
03608         function cannotDeleteRecord($table,$id) {
03609                 if ($table==='pages')   {
03610                         $res = $this->canDeletePage($id);
03611                         return is_array($res) ? FALSE : $res;
03612                 } else {
03613                         return $this->doesRecordExist($table,$id,'delete') ? FALSE : 'No permission to delete record';
03614                 }
03615         }
03616 
03627         function deleteRecord_procFields($table, $uid, $undeleteRecord = false) {
03628                 t3lib_div::loadTCA($table);
03629                 $conf = $GLOBALS['TCA'][$table]['columns'];
03630                 $row = t3lib_BEfunc::getRecord($table, $uid, '*', '', false);
03631 
03632                 foreach ($row as $field => $value) {
03633                         $this->deleteRecord_procBasedOnFieldType($table, $uid, $field, $value, $conf[$field]['config'], $undeleteRecord);
03634                 }
03635         }
03636 
03650         function deleteRecord_procBasedOnFieldType($table, $uid, $field, $value, $conf, $undeleteRecord = false) {
03651                 if ($conf['type'] == 'inline')  {
03652                         $foreign_table = $conf['foreign_table'];
03653 
03654                         if ($foreign_table) {
03655                                 $inlineType = $this->getInlineFieldType($conf);
03656                                 if ($inlineType == 'list' || $inlineType == 'field') {
03657                                         $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
03658                                         $dbAnalysis->start($value, $conf['foreign_table'], '', $uid, $table, $conf);
03659                                         $dbAnalysis->undeleteRecord = true;
03660 
03661                                                 // walk through the items and remove them
03662                                         foreach ($dbAnalysis->itemArray as $v) {
03663                                                 if (!$undeleteRecord)   {
03664                                                         $this->deleteAction($v['table'], $v['id']);
03665                                                 } else {
03666                                                         $this->undeleteRecord($v['table'], $v['id']);
03667                                                 }
03668                                         }
03669                                 }
03670                         }
03671 
03672                         // no delete action but calls to updateRefIndex *AFTER* this record was deleted
03673                 } elseif ($this->isReferenceField($conf)) {
03674                         $allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table'];
03675                         $prependName = $conf['type']=='group' ? $conf['prepend_tname'] : $conf['neg_foreign_table'];
03676 
03677                         $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
03678                         $dbAnalysis->start($value, $allowedTables, $conf['MM'], $uid, $table, $conf);
03679 
03680                         foreach ($dbAnalysis->itemArray as $v) {
03681                                 $this->updateRefIndexStack[$table][$uid][] = array($v['table'], $v['id']);
03682                         }
03683                 }
03684         }
03685 
03686 
03687 
03688 
03689 
03690 
03691 
03692 
03693         /*********************************************
03694          *
03695          * Cmd: Versioning
03696          *
03697          ********************************************/
03698 
03711         function versionizeRecord($table,$id,$label,$delete=FALSE,$versionizeTree=-1)   {
03712                 global $TCA;
03713 
03714                 $id = intval($id);
03715 
03716                 if ($TCA[$table] && $TCA[$table]['ctrl']['versioningWS'] && $id>0)      {
03717                         if ($this->doesRecordExist($table,$id,'show'))  {
03718                                 if ($this->BE_USER->workspaceVersioningTypeAccess($versionizeTree))     {
03719 
03720                                                 // Select main record:
03721                                         $row = $this->recordInfo($table,$id,'pid,t3ver_id');
03722                                         if (is_array($row))     {
03723                                                 if ($row['pid']>=0)     {       // record must be online record
03724                                                         if (!$delete || !$this->cannotDeleteRecord($table,$id)) {
03725 
03726                                                                         // Look for next version number:
03727                                                                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
03728                                                                         't3ver_id',
03729                                                                         $table,
03730                                                                         '(t3ver_oid='.$id.' OR uid='.$id.')'.$this->deleteClause($table),
03731                                                                         '',
03732                                                                         't3ver_id DESC',
03733                                                                         '1'
03734                                                                 );
03735                                                                 list($highestVerNumber) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
03736 
03737                                                                         // Look for version number of the current:
03738                                                                 $subVer = $row['t3ver_id'].'.'.($highestVerNumber+1);
03739 
03740                                                                         // Set up the values to override when making a raw-copy:
03741                                                                 $overrideArray = array(
03742                                                                         't3ver_id' => $highestVerNumber+1,
03743                                                                         't3ver_oid' => $id,
03744                                                                         't3ver_label' => ($label ? $label : $subVer.' / '.date('d-m-Y H:m:s')),
03745                                                                         't3ver_wsid' => $this->BE_USER->workspace,
03746                                                                         't3ver_state' => $delete ? 2 : 0,
03747                                                                         't3ver_count' => 0,
03748                                                                         't3ver_stage' => 0,
03749                                                                         't3ver_tstamp' => 0
03750                                                                 );
03751                                                                 if ($TCA[$table]['ctrl']['editlock'])   {
03752                                                                         $overrideArray[$TCA[$table]['ctrl']['editlock']] = 0;
03753                                                                 }
03754                                                                 if ($table==='pages')   {
03755                                                                         $overrideArray['t3ver_swapmode'] = $versionizeTree;
03756                                                                 }
03757 
03758                                                                         // Checking if the record already has a version in the current workspace of the backend user
03759                                                                 $workspaceCheck = TRUE;
03760                                                                 if ($this->BE_USER->workspace!==0)      {
03761                                                                                 // Look for version already in workspace:
03762                                                                         $workspaceCheck = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace,$table,$id,'uid') ? FALSE : TRUE;
03763                                                                 }
03764 
03765                                                                 if ($workspaceCheck)    {
03766 
03767                                                                                 // Create raw-copy and return result:
03768                                                                         return $this->copyRecord_raw($table,$id,-1,$overrideArray);
03769                                                                 } else $this->newlog('Record you wanted to versionize was already a version in the workspace (wsid='.$this->BE_USER->workspace.')!',1);
03770                                                         } else $this->newlog('Record cannot be deleted: '.$this->cannotDeleteRecord($table,$id),1);
03771                                                 } else $this->newlog('Record you wanted to versionize was already a version in archive (pid=-1)!',1);
03772                                         } else $this->newlog('Record you wanted to versionize did not exist!',1);
03773                                 } else $this->newlog('The versioning type '.$versionizeTree.' mode you requested was not allowed',1);
03774                         } else $this->newlog('You didnt have correct permissions to make a new version (copy) of this record "'.$table.'" / '.$id,1);
03775                 } else $this->newlog('Versioning is not supported for this table "'.$table.'" / '.$id,1);
03776         }
03777 
03787         function versionizePages($uid,$label,$versionizeTree)   {
03788                 global $TCA;
03789 
03790                 $uid = intval($uid);
03791                 $brExist = $this->doesBranchExist('',$uid,$this->pMap['show'],1);       // returns the branch
03792 
03793                 if ($brExist != -1)     {       // Checks if we had permissions
03794 
03795                                 // Finding list of tables ALLOWED to be copied
03796                         $allowedTablesArray = $this->admin ? $this->compileAdminTables() : explode(',',$this->BE_USER->groupData['tables_modify']);     // These are the tables, the user may modify
03797                         $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.
03798 
03799                                 // Make list of tables that should come along with a new version of the page:
03800                         $verTablesArray = array();
03801                         $allTables = array_keys($TCA);
03802                         foreach($allTables as $tN)      {
03803                                 if ($tN!='pages' && ($versionizeTree>0 || $TCA[$tN]['ctrl']['versioning_followPages']) && ($this->admin || in_array($tN, $allowedTablesArray))) {
03804                                         $verTablesArray[] = $tN;
03805                                 }
03806                         }
03807 
03808                                 // Begin to copy pages if we're allowed to:
03809                         if ($this->admin || in_array('pages',$allowedTablesArray))      {
03810                                 if ($this->BE_USER->workspaceVersioningTypeAccess($versionizeTree))     {
03811                                                 // Versionize this page:
03812                                         $theNewRootID = $this->versionizeRecord('pages',$uid,$label,FALSE,$versionizeTree);
03813                                         if ($theNewRootID)      {
03814                                                 $this->rawCopyPageContent($uid,$theNewRootID,$verTablesArray);
03815 
03816                                                         // If we're going to copy recursively...:
03817                                                 if ($versionizeTree>0)  {
03818 
03819                                                                 // Get ALL subpages to copy (read permissions respected - they should NOT be...):
03820                                                         $CPtable = $this->int_pageTreeInfo(Array(), $uid, intval($versionizeTree), $theNewRootID);
03821 
03822                                                                 // Now copying the subpages:
03823                                                         foreach($CPtable as $thePageUid => $thePagePid) {
03824                                                                 $newPid = $this->copyMappingArray['pages'][$thePagePid];
03825                                                                 if (isset($newPid))     {
03826                                                                         $theNewRootID = $this->copyRecord_raw('pages',$thePageUid,$newPid);
03827                                                                         $this->rawCopyPageContent($thePageUid,$theNewRootID,$verTablesArray);
03828                                                                 } else {
03829                                                                         $this->newlog('Something went wrong during copying branch (for versioning)',1);
03830                                                                         break;
03831                                                                 }
03832                                                         }
03833                                                 }       // else the page was not copied. Too bad...
03834                                         } else $this->newlog('The root version could not be created!',1);
03835                                 } else $this->newlog('Versioning type "'.$versionizeTree.'" was not allowed in workspace',1);
03836                         } else $this->newlog('Attempt to versionize page without permission to this table',1);
03837                 } else $this->newlog('Could not read all subpages to versionize.',1);
03838         }
03839 
03850         function version_swap($table,$id,$swapWith,$swapIntoWS=0)       {
03851                 global $TCA;
03852 
03853                 /*
03854                 Version ID swapping principles:
03855                         - 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
03856 
03857                         uid             pid                     uid             t3ver_oid       pid
03858                 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)
03859                 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))
03860                 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.)
03861 
03862                         13 is online UID,
03863                         247 is specific versions UID
03864                         123 is the PID of the original record
03865                         -1 is the versioning repository PID
03866 
03867                         Recovery Process:
03868                                 Search for negative UID (here "-13"):
03869                                         YES: Step 1 completed, but at least step 3 didn't.
03870                                                 Search for the negativ UIDs positive (here: "13")
03871                                                         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)
03872                                                         NO: Only Step 1 completed! Rollback: Just change uid "-13" to "13" and "t3ver_oid" to "13" (not important)
03873                                         NO: No problems.
03874                 */
03875 
03876                         // First, check if we may actually edit the online record
03877                 if ($this->checkRecordUpdateAccess($table,$id)) {
03878 
03879                                 // Select the two versions:
03880                         $curVersion = t3lib_BEfunc::getRecord($table,$id,'*');
03881                         $swapVersion = t3lib_BEfunc::getRecord($table,$swapWith,'*');
03882 
03883                         if (is_array($curVersion) && is_array($swapVersion))    {
03884                                 if ($this->BE_USER->workspacePublishAccess($swapVersion['t3ver_wsid'])) {
03885                                         $wsAccess = $this->BE_USER->checkWorkspace($swapVersion['t3ver_wsid']);
03886                                         if ($swapVersion['t3ver_wsid']<=0 || !($wsAccess['publish_access']&1) || (int)$swapVersion['t3ver_stage']===10) {
03887                                                 if ($this->doesRecordExist($table,$swapWith,'show') && $this->checkRecordUpdateAccess($table,$swapWith)) {
03888                                                         if (!$swapIntoWS || $this->BE_USER->workspaceSwapAccess())      {
03889 
03890                                                                         // Check if the swapWith record really IS a version of the original!
03891                                                                 if ((int)$swapVersion['pid']==-1 && (int)$curVersion['pid']>=0 && !strcmp($swapVersion['t3ver_oid'],$id))       {
03892 
03893                                                                                 // Lock file name:
03894                                                                         $lockFileName = PATH_site.'typo3temp/swap_locking/'.$table.':'.$id.'.ser';
03895 
03896                                                                         if (!@is_file($lockFileName))   {
03897 
03898                                                                                         // Write lock-file:
03899                                                                                 t3lib_div::writeFileToTypo3tempDir($lockFileName,serialize(array(
03900                                                                                         'tstamp'=>time(),
03901                                                                                         'user'=>$GLOBALS['BE_USER']->user['username'],
03902                                                                                         'curVersion'=>$curVersion,
03903                                                                                         'swapVersion'=>$swapVersion
03904                                                                                 )));
03905 
03906                                                                                         // Find fields to keep
03907                                                                                 $keepFields = $this->getUniqueFields($table);
03908                                                                                 if ($TCA[$table]['ctrl']['sortby'])     {
03909                                                                                         $keepFields[] = $TCA[$table]['ctrl']['sortby'];
03910                                                                                 }
03911 
03912                                                                                         // Swap "keepfields"
03913                                                                                 foreach($keepFields as $fN)     {
03914                                                                                         $tmp = $swapVersion[$fN];
03915                                                                                         $swapVersion[$fN] = $curVersion[$fN];
03916                                                                                         $curVersion[$fN] = $tmp;
03917                                                                                 }
03918 
03919                                                                                         // Preserve states:
03920                                                                                 $t3ver_state = array();
03921                                                                                 $t3ver_state['swapVersion'] = $swapVersion['t3ver_state'];
03922                                                                                 $t3ver_state['curVersion'] = $curVersion['t3ver_state'];
03923 
03924                                                                                         // Modify offline version to become online:
03925                                                                                 $tmp_wsid = $swapVersion['t3ver_wsid'];
03926                                                                                 unset($swapVersion['uid']);
03927                                                                                 $swapVersion['pid'] = intval($curVersion['pid']);       // Set pid for ONLINE
03928                                                                                 $swapVersion['t3ver_oid'] = intval($id);
03929                                                                                 $swapVersion['t3ver_wsid'] = $swapIntoWS ? intval($curVersion['t3ver_wsid']) : 0;
03930                                                                                 $swapVersion['t3ver_tstamp'] = time();
03931                                                                                 $swapVersion['t3ver_stage'] = $swapVersion['t3ver_state'] = 0;
03932 
03933                                                                                         // Modify online version to become offline:
03934                                                                                 unset($curVersion['uid']);
03935                                                                                 $curVersion['pid'] = -1;        // Set pid for OFFLINE
03936                                                                                 $curVersion['t3ver_oid'] = intval($id);
03937                                                                                 $curVersion['t3ver_wsid'] = $swapIntoWS ? intval($tmp_wsid) : 0;
03938                                                                                 $curVersion['t3ver_tstamp'] = time();
03939                                                                                 $curVersion['t3ver_count'] = $curVersion['t3ver_count']+1;      // Increment lifecycle counter
03940                                                                                 $curVersion['t3ver_stage'] = $curVersion['t3ver_state'] = 0;
03941 
03942                                                                                 if ($table==='pages') {         // Keeping the swapmode state
03943                                                                                                 $curVersion['t3ver_swapmode'] = $swapVersion['t3ver_swapmode'];
03944                                                                                 }
03945 
03946                                                                                         // Execute swapping:
03947                                                                                 $sqlErrors = array();
03948                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($id),$swapVersion);
03949                                                                                 if ($GLOBALS['TYPO3_DB']->sql_error())          {
03950                                                                                         $sqlErrors[] = $GLOBALS['TYPO3_DB']->sql_error();
03951                                                                                 } else {
03952                                                                                         $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($swapWith),$curVersion);
03953                                                                                         if ($GLOBALS['TYPO3_DB']->sql_error())  {
03954                                                                                                 $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
03955                                                                                         } else {
03956                                                                                                 unlink($lockFileName);
03957                                                                                         }
03958                                                                                 }
03959 
03960                                                                                 if (!count($sqlErrors)) {
03961 
03962                                                                                                 // Checking for delete:
03963                                                                                         if ($t3ver_state['swapVersion']==2)     {
03964                                                                                                 $this->deleteEl($table,$id,TRUE);       // Force delete
03965                                                                                         }
03966 
03967                                                                                         $this->newlog('Swapping successful for table "'.$table.'" uid '.$id.'=>'.$swapWith);
03968 
03969                                                                                                 // Update reference index:
03970                                                                                         $this->updateRefIndex($table,$id);
03971                                                                                         $this->updateRefIndex($table,$swapWith);
03972 
03973                                                                                                 // SWAPPING pids for subrecords:
03974                                                                                         if ($table=='pages' && $swapVersion['t3ver_swapmode']>=0)       {
03975 
03976                                                                                                         // Collect table names that should be copied along with the tables:
03977                                                                                                 foreach($TCA as $tN => $tCfg)   {
03978                                                                                                         if ($swapVersion['t3ver_swapmode']>0 || $TCA[$tN]['ctrl']['versioning_followPages'])    {       // For "Branch" publishing swap ALL, otherwise for "page" publishing, swap only "versioning_followPages" tables
03979                                                                                                                 $temporaryPid = -($id+1000000);
03980 
03981                                                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($id),array('pid'=>$temporaryPid));
03982                                                                                                                 if ($GLOBALS['TYPO3_DB']->sql_error())  $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
03983 
03984                                                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($swapWith),array('pid'=>$id));
03985                                                                                                                 if ($GLOBALS['TYPO3_DB']->sql_error())  $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
03986 
03987                                                                                                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($temporaryPid),array('pid'=>$swapWith));
03988                                                                                                                 if ($GLOBALS['TYPO3_DB']->sql_error())  $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
03989 
03990                                                                                                                 if (count($sqlErrors))  {
03991                                                                                                                         $this->newlog('During Swapping: SQL errors happend: '.implode('; ',$sqlErrors),2);
03992                                                                                                                 }
03993                                                                                                         }
03994                                                                                                 }
03995                                                                                         }
03996                                                                                                 // Clear cache:
03997                                                                                         $this->clear_cache($table,$id);
03998 
03999                                                                                                 // Checking for "new-placeholder" and if found, delete it (BUT FIRST after swapping!):
04000                                                                                         if ($t3ver_state['curVersion']==1)      {
04001                                                                                                 $this->deleteEl($table, $swapWith, TRUE, TRUE);         // For delete + completely delete!
04002                                                                                         }
04003                                                                                 } else $this->newlog('During Swapping: SQL errors happend: '.implode('; ',$sqlErrors),2);
04004                                                                         } 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);
04005                                                                 } 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);
04006                                                         } else $this->newlog('Workspace #'.$swapVersion['t3ver_wsid'].' does not support swapping.',1);
04007                                                 } else $this->newlog('You cannot publish a record you do not have edit and show permissions for',1);
04008                                         } else $this->newlog('Records in workspace #'.$swapVersion['t3ver_wsid'].' can only be published when in "Publish" stage.',1);
04009                                 } else $this->newlog('User could not publish records from workspace #'.$swapVersion['t3ver_wsid'],1);
04010                         } else $this->newlog('Error: Either online or swap version could not be selected!',2);
04011                 } else $this->newlog('Error: You cannot swap versions for a record you do not have access to edit!',1);
04012         }
04013 
04021         function version_clearWSID($table,$id)  {
04022                 if ($errorCode = $this->BE_USER->workspaceCannotEditOfflineVersion($table, $id))        {
04023                         $this->newlog('Attempt to reset workspace for record failed: '.$errorCode,1);
04024                 } elseif ($this->checkRecordUpdateAccess($table,$id)) {
04025                         if ($liveRec = t3lib_BEfunc::getLiveVersionOfRecord($table,$id,'uid,t3ver_state'))      {
04026                                         // Clear workspace ID:
04027                                 $sArray = array();
04028                                 $sArray['t3ver_wsid'] = 0;
04029                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($id),$sArray);
04030 
04031                                         // Clear workspace ID for live version AND DELETE IT as well because it is a new record!
04032                                 if ((int)$liveRec['t3ver_state']===1)   {
04033                                         $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($liveRec['uid']),$sArray);
04034                                         $this->deleteEl($table, $liveRec['uid'], TRUE); // THIS assumes that the record was placeholder ONLY for ONE record (namely $id)
04035                                 }
04036 
04037                                         // 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.
04038                                 $wsRec = t3lib_BEfunc::getRecord($table,$id);
04039                                 if ((int)$wsRec['t3ver_state']===2)     {
04040                                         $this->deleteEl($table, $id, TRUE, TRUE);
04041                                 }
04042                         }
04043                 } else $this->newlog('Attempt to reset workspace for record failed because you do not have edit access',1);
04044         }
04045 
04055         function version_setStage($table,$id,$stageId,$comment='')      {
04056                 if ($errorCode = $this->BE_USER->workspaceCannotEditOfflineVersion($table, $id))        {
04057                         $this->newlog('Attempt to set stage for record failed: '.$errorCode,1);
04058                 } elseif ($this->checkRecordUpdateAccess($table,$id)) {
04059                         $stat = $this->BE_USER->checkWorkspaceCurrent();
04060                         if (t3lib_div::inList('admin,online,offline,reviewer,owner', $stat['_ACCESS']) || ($stageId<=1 && $stat['_ACCESS']==='member')) {
04061 
04062                                         // Set stage of record:
04063                                 $sArray = array();
04064                                 $sArray['t3ver_stage'] = $stageId;
04065                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($id), $sArray);
04066                                 $this->newlog('Stage for record was changed to '.$stageId.'. Comment was: "'.substr($comment,0,100).'"');
04067 // TEMPORARY, except 6-30 as action/detail number which is observed elsewhere!
04068 $this->log($table,$id,6,0,0,'Stage raised...',30,array('comment'=>$comment,'stage'=>$stageId));
04069 
04070                                 if ((int)$stat['stagechg_notification']>0)      {
04071                                         $this->notifyStageChange($stat,$stageId,$table,$id,$comment);
04072                                 }
04073                         } else $this->newlog('The member user tried to set a stage value "'.$stageId.'" that was not allowed',1);
04074                 } else $this->newlog('Attempt to set stage for record failed because you do not have edit access',1);
04075         }
04076 
04077 
04078 
04079 
04080 
04081 
04082 
04083 
04084 
04085 
04086 
04087 
04088 
04089         /*********************************************
04090          *
04091          * Cmd: Helper functions
04092          *
04093          ********************************************/
04094 
04100         function remapListedDBRecords() {
04101                 global $TCA;
04102 
04103                 if (count($this->registerDBList))       {
04104                         reset($this->registerDBList);
04105                         while(list($table,$records)=each($this->registerDBList))        {
04106                                 t3lib_div::loadTCA($table);
04107                                 reset($records);
04108                                 while(list($uid,$fields)=each($records))        {
04109                                         $newData = array();
04110                                         $theUidToUpdate = $this->copyMappingArray_merged[$table][$uid];
04111                                         $theUidToUpdate_saveTo = t3lib_BEfunc::wsMapId($table,$theUidToUpdate);
04112 
04113                                         foreach($fields as $fieldName => $value)        {
04114                                                 $conf = $TCA[$table]['columns'][$fieldName]['config'];
04115 
04116                                                 switch($conf['type'])   {
04117                                                         case 'group':
04118                                                         case 'select':
04119                                                                 $vArray = $this->remapListedDBRecords_procDBRefs($conf, $value, $theUidToUpdate, $table);
04120                                                                 if (is_array($vArray))  {
04121                                                                         $newData[$fieldName] = implode(',',$vArray);
04122                                                                 }
04123                                                         break;
04124                                                         case 'flex':
04125                                                                 if ($value=='FlexForm_reference')       {
04126                                                                         $origRecordRow = $this->recordInfo($table,$theUidToUpdate,'*'); // This will fetch the new row for the element
04127 
04128                                                                         if (is_array($origRecordRow))   {
04129                                                                                 t3lib_BEfunc::workspaceOL($table,$origRecordRow);
04130 
04131                                                                                         // Get current data structure and value array:
04132                                                                                 $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $origRecordRow, $table);
04133                                                                                 $currentValueArray = t3lib_div::xml2array($origRecordRow[$fieldName]);
04134 
04135                                                                                         // Do recursive processing of the XML data:
04136                                                                                 $currentValueArray['data'] = $this->checkValue_flex_procInData(
04137                                                                                                         $currentValueArray['data'],
04138                                                                                                         array(),        // Not used.
04139                                                                                                         array(),        // Not used.
04140                                                                                                         $dataStructArray,
04141                                                                                                         array($table,$theUidToUpdate,$fieldName),       // Parameters.
04142                                                                                                         'remapListedDBRecords_flexFormCallBack'
04143                                                                                                 );
04144 
04145                                                                                         // The return value should be compiled back into XML, ready to insert directly in the field (as we call updateDB() directly later):
04146                                                                                 if (is_array($currentValueArray['data']))       {
04147                                                                                         $newData[$fieldName] =
04148                                                                                                 $this->checkValue_flexArray2Xml($currentValueArray,TRUE);
04149                                                                                 }
04150                                                                         }
04151                                                                 }
04152                                                         break;
04153                                                         case 'inline':
04154                                                                 $this->remapListedDBRecords_procInline($conf, $value, $uid, $table);
04155                                                         break;
04156                                                         default:
04157                                                                 debug('Field type should not appear here: '. $conf['type']);
04158                                                         break;
04159                                                 }
04160                                         }
04161 
04162                                         if (count($newData))    {       // If any fields were changed, those fields are updated!
04163                                                 $this->updateDB($table,$theUidToUpdate_saveTo,$newData);
04164                                         }
04165                                 }
04166                         }
04167                 }
04168         }
04169 
04181         function remapListedDBRecords_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2) {
04182 
04183                         // Extract parameters:
04184                 list($table,$uid,$field)        = $pParams;
04185 
04186                         // If references are set for this field, set flag so they can be corrected later:
04187                 if ($this->isReferenceField($dsConf) && strlen($dataValue)) {
04188                         $vArray = $this->remapListedDBRecords_procDBRefs($dsConf, $dataValue, $uid, $table);
04189                         if (is_array($vArray))  {
04190                                 $dataValue = implode(',',$vArray);
04191                         }
04192                 }
04193 
04194                         // Return
04195                 return array('value' => $dataValue);
04196         }
04197 
04208         function remapListedDBRecords_procDBRefs($conf, $value, $MM_localUid, $table)   {
04209 
04210                         // Initialize variables
04211                 $set = FALSE;   // Will be set true if an upgrade should be done...
04212                 $allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table'];             // Allowed tables for references.
04213                 $prependName = $conf['type']=='group' ? $conf['prepend_tname'] : '';    // Table name to prepend the UID
04214                 $dontRemapTables = t3lib_div::trimExplode(',',$conf['dontRemapTablesOnCopy'],1);        // Which tables that should possibly not be remapped
04215 
04216                         // Convert value to list of references:
04217                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
04218                 $dbAnalysis->registerNonTableValues = ($conf['type']=='select' && $conf['allowNonIdValues']) ? 1 : 0;
04219                 $dbAnalysis->start($value, $allowedTables, $conf['MM'], $MM_localUid, $table, $conf);
04220 
04221                         // Traverse those references and map IDs:
04222                 foreach($dbAnalysis->itemArray as $k => $v)     {
04223                         $mapID = $this->copyMappingArray_merged[$v['table']][$v['id']];
04224                         if ($mapID && !in_array($v['table'],$dontRemapTables))  {
04225                                 $dbAnalysis->itemArray[$k]['id'] = $mapID;
04226                                 $set = TRUE;
04227                         }
04228                 }
04229 
04230                         // If a change has been done, set the new value(s)
04231                 if ($set)       {
04232                         if ($conf['MM'])        {
04233 // FIXME $theUidToUpdate is undefined
04234                                 $dbAnalysis->writeMM($conf['MM'], $theUidToUpdate, $prependName);
04235                         } else {
04236                                 $vArray = $dbAnalysis->getValueArray($prependName);
04237                                 if ($conf['type']=='select')    {
04238                                         $vArray = $dbAnalysis->convertPosNeg($vArray, $conf['foreign_table'], $conf['neg_foreign_table']);
04239                                 }
04240                                 return $vArray;
04241                         }
04242                 }
04243         }
04244 
04254         function remapListedDBRecords_procInline($conf, $value, $uid, $table) {
04255                 $theUidToUpdate = $this->copyMappingArray_merged[$table][$uid];
04256 
04257                 if ($conf['foreign_table']) {
04258                         $inlineType = $this->getInlineFieldType($conf);
04259 
04260                         if ($inlineType == 'field') {
04261                                 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
04262                                 $dbAnalysis->start($value, $conf['foreign_table'], $conf['MM'], 0, $table, $conf);
04263 
04264                                 $dbAnalysis->writeForeignField($conf, $uid, $theUidToUpdate);
04265                         } elseif ($inlineType == 'mm') {
04266                                 $vArray = $this->remapListedDBRecords_procDBRefs($conf, $value, $theUidToUpdate, $table);
04267                         }
04268                 }
04269         }
04270 
04271 
04272 
04273 
04274 
04275 
04276 
04277 
04278 
04279 
04280 
04281 
04282 
04283 
04284 
04285         /*****************************
04286          *
04287          * Access control / Checking functions
04288          *
04289          *****************************/
04290 
04297         function checkModifyAccessList($table)  {
04298                 $res = ($this->admin || (!$this->tableAdminOnly($table) && t3lib_div::inList($this->BE_USER->groupData['tables_modify'],$table)));
04299                 return $res;
04300         }
04301 
04309         function isRecordInWebMount($table,$id) {
04310                 if (!isset($this->isRecordInWebMount_Cache[$table.':'.$id]))    {
04311                         $recP=$this->getRecordProperties($table,$id);
04312                         $this->isRecordInWebMount_Cache[$table.':'.$id]=$this->isInWebMount($recP['event_pid']);
04313                 }
04314                 return $this->isRecordInWebMount_Cache[$table.':'.$id];
04315         }
04316 
04323         function isInWebMount($pid)     {
04324                 if (!isset($this->isInWebMount_Cache[$pid]))    {
04325                         $this->isInWebMount_Cache[$pid]=$this->BE_USER->isInWebMount($pid);
04326                 }
04327                 return $this->isInWebMount_Cache[$pid];
04328         }
04329 
04337         function checkRecordUpdateAccess($table,$id)    {
04338                 global $TCA;
04339                 $res = 0;
04340                 if ($TCA[$table] && intval($id)>0)      {
04341                         if (isset($this->recUpdateAccessCache[$table][$id]))    {       // If information is cached, return it
04342                                 return $this->recUpdateAccessCache[$table][$id];
04343                                 // Check if record exists and 1) if 'pages' the page may be edited, 2) if page-content the page allows for editing
04344                         } elseif ($this->doesRecordExist($table,$id,'edit'))    {
04345                                 $res = 1;
04346                         }
04347                         $this->recUpdateAccessCache[$table][$id]=$res;  // Cache the result
04348                 }
04349                 return $res;
04350         }
04351 
04361         function checkRecordInsertAccess($insertTable,$pid,$action=1)   {
04362                 global $TCA;
04363 
04364                 $res = 0;
04365                 $pid = intval($pid);
04366                 if ($pid>=0)    {
04367                         if (isset($this->recInsertAccessCache[$insertTable][$pid]))     {       // If information is cached, return it
04368                                 return $this->recInsertAccessCache[$insertTable][$pid];
04369                         } else {
04370                                         // 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
04371                                 if ( (!$pid && $this->admin) || $this->doesRecordExist('pages',$pid,($insertTable=='pages'?$this->pMap['new']:$this->pMap['editcontent'])) )    {               // Check permissions
04372                                         if ($this->isTableAllowedForThisPage($pid, $insertTable))       {
04373                                                 $res = 1;
04374                                                 $this->recInsertAccessCache[$insertTable][$pid]=$res;   // Cache the result
04375                                         } else {
04376                                                 $propArr = $this->getRecordProperties('pages',$pid);
04377                                                 $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']);
04378                                         }
04379                                 } else {
04380                                         $propArr = $this->getRecordProperties('pages',$pid);
04381                                         $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']);
04382                                 }
04383                         }
04384                 }
04385                 return $res;
04386         }
04387 
04395         function isTableAllowedForThisPage($page_uid, $checkTable)      {
04396                 global $TCA, $PAGES_TYPES;
04397                 $page_uid = intval($page_uid);
04398 
04399                         // 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.
04400                 if (($TCA[$checkTable]['ctrl']['rootLevel'] xor !$page_uid) && $TCA[$checkTable]['ctrl']['rootLevel']!=-1 && $checkTable!='pages')      {
04401                         return false;
04402                 }
04403 
04404                         // Check root-level
04405                 if (!$page_uid) {
04406                         if ($this->admin)       {
04407                                 return true;
04408                         }
04409                 } else {
04410                                 // Check non-root-level
04411                         $doktype = $this->pageInfo($page_uid,'doktype');
04412                         $allowedTableList = isset($PAGES_TYPES[$doktype]['allowedTables']) ? $PAGES_TYPES[$doktype]['allowedTables'] : $PAGES_TYPES['default']['allowedTables'];
04413                         $allowedArray = t3lib_div::trimExplode(',',$allowedTableList,1);
04414                         if (strstr($allowedTableList,'*') || in_array($checkTable,$allowedArray))       {               // If all tables or the table is listed as a allowed type, return true
04415                                 return true;
04416                         }
04417                 }
04418         }
04419 
04428         function doesRecordExist($table,$id,$perms)     {
04429                 global $TCA;
04430 
04431                 if ($this->bypassAccessCheckForRecords) {
04432                         return is_array(t3lib_BEfunc::getRecordRaw($table,'uid='.intval($id),'uid'));
04433                 }
04434 
04435                 $res = 0;
04436                 $id = intval($id);
04437 
04438                         // Processing the incoming $perms (from possible string to integer that can be AND'ed)
04439                 if (!t3lib_div::testInt($perms))        {
04440                         if ($table!='pages')    {
04441                                 switch($perms)  {
04442                                         case 'edit':
04443                                         case 'delete':
04444                                         case 'new':
04445                                                 $perms = 'editcontent';         // This holds it all in case the record is not page!!
04446                                         break;
04447                                 }
04448                         }
04449                         $perms = intval($this->pMap[$perms]);
04450                 } else {
04451                         $perms = intval($perms);
04452                 }
04453 
04454                 if (!$perms)    {die('Internal ERROR: no permissions to check for non-admin user.');}
04455 
04456                         // For all tables: Check if record exists:
04457                 if (is_array($TCA[$table]) && $id>0 && ($this->isRecordInWebMount($table,$id) || $this->admin)) {
04458                         if ($table != 'pages')  {
04459 
04460                                         // Find record without checking page:
04461                                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid', $table, 'uid='.intval($id).$this->deleteClause($table));      // THIS SHOULD CHECK FOR editlock I think!
04462                                 $output = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres);
04463                                 t3lib_BEfunc::fixVersioningPid($table,$output,TRUE);
04464 
04465                                         // If record found, check page as well:
04466                                 if (is_array($output))  {
04467 
04468                                                 // Looking up the page for record:
04469                                         $mres = $this->doesRecordExist_pageLookUp($output['pid'], $perms);
04470                                         $pageRec = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres);
04471                                                 // 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):
04472                                         if (is_array($pageRec) || (!$output['pid'] && $this->admin))    {
04473                                                 return TRUE;
04474                                         }
04475                                 }
04476                                 return FALSE;
04477                         } else {
04478                                 $mres = $this->doesRecordExist_pageLookUp($id, $perms);
04479                                 return $GLOBALS['TYPO3_DB']->sql_num_rows($mres);
04480                         }
04481                 }
04482         }
04483 
04493         function doesRecordExist_pageLookUp($id, $perms)        {
04494                 global $TCA;
04495 
04496                 return $GLOBALS['TYPO3_DB']->exec_SELECTquery(
04497                         'uid',
04498                         'pages',
04499                         'uid='.intval($id).
04500                                 $this->deleteClause('pages').
04501                                 ($perms && !$this->admin ? ' AND '.$this->BE_USER->getPagePermsClause($perms) : '').
04502                                 (!$this->admin && $TCA['pages']['ctrl']['editlock'] && ($perms & (2+4+16)) ? ' AND '.$TCA['pages']['ctrl']['editlock'].'=0':'') // admin users don't need check
04503                 );
04504         }
04505 
04519         function doesBranchExist($inList,$pid,$perms,$recurse)  {
04520                 global $TCA;
04521                 $pid = intval($pid);
04522                 $perms = intval($perms);
04523 
04524                 if ($pid>=0)    {
04525                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
04526                                 'uid, perms_userid, perms_groupid, perms_user, perms_group, perms_everybody',
04527                                 'pages',
04528                                 'pid='.intval($pid).$this->deleteClause('pages'),
04529                                 '',
04530                                 'sorting'
04531                         );
04532                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))     {
04533                                 if ($this->admin || $this->BE_USER->doesUserHaveAccess($row,$perms))    {       // IF admin, then it's OK
04534                                         $inList.=$row['uid'].',';
04535                                         if ($recurse)   {       // Follow the subpages recursively...
04536                                                 $inList = $this->doesBranchExist($inList, $row['uid'], $perms, $recurse);
04537                                                 if ($inList == -1)      {return -1;}            // No permissions somewhere in the branch
04538                                         }
04539                                 } else {
04540                                         return -1;              // No permissions
04541                                 }
04542                         }
04543                 }
04544                 return $inList;
04545         }
04546 
04553         function tableReadOnly($table)  {
04554                         // returns true if table is readonly
04555                 global $TCA;
04556                 return ($TCA[$table]['ctrl']['readOnly'] ? 1 : 0);
04557         }
04558 
04565         function tableAdminOnly($table) {
04566                         // returns true if table is admin-only
04567                 global $TCA;
04568                 return ($TCA[$table]['ctrl']['adminOnly'] ? 1 : 0);
04569         }
04570 
04579         function destNotInsideSelf($dest,$id)   {
04580                 $loopCheck = 100;
04581                 $dest = intval($dest);
04582                 $id = intval($id);
04583 
04584                 if ($dest==$id) {
04585                         return FALSE;
04586                 }
04587 
04588                 while ($dest!=0 && $loopCheck>0)        {
04589                         $loopCheck--;
04590                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('pid, uid, t3ver_oid,t3ver_wsid', 'pages', 'uid='.intval($dest).$this->deleteClause('pages'));
04591                         if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
04592                                 t3lib_BEfunc::fixVersioningPid('pages',$row);
04593                                 if ($row['pid']==$id)   {
04594                                         return FALSE;
04595                                 } else {
04596                                         $dest = $row['pid'];
04597                                 }
04598                         } else {
04599                                 return FALSE;
04600                         }
04601                 }
04602                 return TRUE;
04603         }
04604 
04611         function getExcludeListArray()  {
04612                 global $TCA;
04613 
04614                 $list = array();
04615                 reset($TCA);
04616                 while (list($table)=each($TCA)) {
04617                         t3lib_div::loadTCA($table);
04618                         while (list($field,$config)=each($TCA[$table]['columns']))      {
04619                                 if ($config['exclude'] && !t3lib_div::inList($this->BE_USER->groupData['non_exclude_fields'],$table.':'.$field))        {
04620                                         $list[]=$table.'-'.$field;
04621                                 }
04622                         }
04623                 }
04624                 return $list;
04625         }
04626 
04634         function doesPageHaveUnallowedTables($page_uid,$doktype)        {
04635                 global $TCA, $PAGES_TYPES;
04636 
04637                 $page_uid = intval($page_uid);
04638                 if (!$page_uid) {
04639                         return FALSE;   // Not a number. Probably a new page
04640                 }
04641 
04642                 $allowedTableList = isset($PAGES_TYPES[$doktype]['allowedTables']) ? $PAGES_TYPES[$doktype]['allowedTables'] : $PAGES_TYPES['default']['allowedTables'];
04643                 $allowedArray = t3lib_div::trimExplode(',',$allowedTableList,1);
04644                 if (strstr($allowedTableList,'*'))      {       // If all tables is OK the return true
04645                         return FALSE;   // OK...
04646                 }
04647 
04648                 reset ($TCA);
04649                 $tableList = array();
04650                 while (list($table)=each($TCA)) {
04651                         if (!in_array($table,$allowedArray))    {       // If the table is not in the allowed list, check if there are records...
04652                                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', $table, 'pid='.intval($page_uid));
04653                                 $count = $GLOBALS['TYPO3_DB']->sql_fetch_row($mres);
04654                                 if ($count[0])  {
04655                                         $tableList[]=$table;
04656                                 }
04657                         }
04658                 }
04659                 return implode(',',$tableList);
04660         }
04661 
04662 
04663 
04664 
04665 
04666 
04667 
04668 
04669         /*****************************
04670          *
04671          * Information lookup
04672          *
04673          *****************************/
04674 
04683         function pageInfo($id,$field)   {
04684                 if (!isset($this->pageCache[$id]))      {
04685                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'uid='.intval($id));
04686                         if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
04687                                 $this->pageCache[$id] = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
04688                         }
04689                         $GLOBALS['TYPO3_DB']->sql_free_result($res);
04690                 }
04691                 return $this->pageCache[$id][$field];
04692         }
04693 
04703         function recordInfo($table,$id,$fieldList)      {
04704                 global $TCA;
04705                 if (is_array($TCA[$table]))     {
04706                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fieldList, $table, 'uid='.intval($id));
04707                         if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
04708                                 return $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
04709                         }
04710                 }
04711         }
04712 
04724         function getRecordProperties($table,$id,$noWSOL=FALSE)  {
04725                 $row = ($table=='pages' && !$id) ? array('title'=>'[root-level]', 'uid' => 0, 'pid' => 0) :$this->recordInfo($table,$id,'*');
04726                 if (!$noWSOL)   {
04727                         t3lib_BEfunc::workspaceOL($table,$row);
04728                 }
04729                 t3lib_BEfunc::fixVersioningPid($table,$row);
04730                 return $this->getRecordPropertiesFromRow($table,$row);
04731         }
04732 
04740         function getRecordPropertiesFromRow($table,$row)        {
04741                 global $TCA;
04742                 if ($TCA[$table])       {
04743                         $out = array(
04744                                 'header' => $row[$TCA[$table]['ctrl']['label']],
04745                                 'pid' => $row['pid'],
04746                                 'event_pid' => ($table=='pages'?$row['uid']:$row['pid']),
04747                                 't3ver_state' => $TCA[$table]['ctrl']['versioningWS'] ? $row['t3ver_state'] : '',
04748                                 '_ORIG_pid' => $row['_ORIG_pid']
04749                         );
04750                         return $out;
04751                 }
04752         }
04753 
04754 
04755 
04756 
04757 
04758 
04759 
04760 
04761 
04762 
04763 
04764 
04765 
04766 
04767 
04768         /*********************************************
04769          *
04770          * Storing data to Database Layer
04771          *
04772          ********************************************/
04773 
04783         function updateDB($table,$id,$fieldArray)       {
04784                 global $TCA;
04785 
04786                 if (is_array($fieldArray) && is_array($TCA[$table]) && intval($id))     {
04787                         unset($fieldArray['uid']);      // Do NOT update the UID field, ever!
04788 
04789                         if (count($fieldArray)) {
04790 
04791                                         // Execute the UPDATE query:
04792                                 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($id), $fieldArray);
04793 
04794                                         // If succees, do...:
04795                                 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
04796 
04797                                         if ($this->checkStoredRecords)  {
04798                                                 $newRow = $this->checkStoredRecord($table,$id,$fieldArray,2);
04799                                         }
04800 
04801                                                 // Update reference index:
04802                                         $this->updateRefIndex($table,$id);
04803 
04804                                                 // Set log entry:
04805                                         $propArr = $this->getRecordPropertiesFromRow($table,$newRow);
04806                                         $theLogId = $this->log($table,$id,2,$propArr['pid'],0,"Record '%s' (%s) was updated.",10,array($propArr['header'],$table.':'.$id),$propArr['event_pid']);
04807 
04808                                                 // Set History data:
04809                                         $this->setHistory($table,$id,$theLogId);
04810 
04811                                                 // Clear cache for relevant pages:
04812                                         $this->clear_cache($table,$id);
04813 
04814                                                 // Unset the pageCache for the id if table was page.
04815                                         if ($table=='pages')    unset($this->pageCache[$id]);
04816                                 } else {
04817                                         $this->log($table,$id,2,0,2,"SQL error: '%s' (%s)",12,array($GLOBALS['TYPO3_DB']->sql_error(),$table.':'.$id));
04818                                 }
04819                         }
04820                 }
04821         }
04822 
04835         function insertDB($table,$id,$fieldArray,$newVersion=FALSE,$suggestedUid=0,$dontSetNewIdIndex=FALSE)    {
04836                 global $TCA;
04837 
04838                 if (is_array($fieldArray) && is_array($TCA[$table]) && isset($fieldArray['pid']))       {
04839                         unset($fieldArray['uid']);      // Do NOT insert the UID field, ever!
04840 
04841                         if (count($fieldArray)) {
04842 
04843                                         // Check for "suggestedUid".
04844                                         // This feature is used by the import functionality to force a new record to have a certain UID value.
04845                                         // This is only recommended for use when the destination server is a passive mirrow of another server.
04846                                         // As a security measure this feature is available only for Admin Users (for now)
04847                                 $suggestedUid = intval($suggestedUid);
04848                                 if ($this->BE_USER->isAdmin() && $suggestedUid && $this->suggestedInsertUids[$table.':'.$suggestedUid]) {
04849                                                 // When the value of ->suggestedInsertUids[...] is "DELETE" it will try to remove the previous record
04850                                         if ($this->suggestedInsertUids[$table.':'.$suggestedUid]==='DELETE')    {
04851                                                         // DELETE:
04852                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery($table, 'uid='.intval($suggestedUid));
04853                                         }
04854                                         $fieldArray['uid'] = $suggestedUid;
04855                                 }
04856 
04857                                         // Execute the INSERT query:
04858                                 $GLOBALS['TYPO3_DB']->exec_INSERTquery($table, $fieldArray);
04859 
04860                                         // If succees, do...:
04861                                 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
04862 
04863                                                 // Set mapping for NEW... -> real uid:
04864                                         $NEW_id = $id;          // the NEW_id now holds the 'NEW....' -id
04865                                         $id = $GLOBALS['TYPO3_DB']->sql_insert_id();
04866                                         if (!$dontSetNewIdIndex)        {
04867                                                 $this->substNEWwithIDs[$NEW_id] = $id;
04868                                                 $this->substNEWwithIDs_table[$NEW_id] = $table;
04869                                         }
04870 
04871                                                 // Checking the record is properly saved and writing to log
04872                                         if ($this->checkStoredRecords)  {
04873                                                 $newRow = $this->checkStoredRecord($table,$id,$fieldArray,1);
04874                                         }
04875 
04876                                                 // Update reference index:
04877                                         $this->updateRefIndex($table,$id);
04878 
04879                                         if ($newVersion)        {
04880                                                 $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);
04881                                         } else {
04882                                                 $propArr = $this->getRecordPropertiesFromRow($table,$newRow);
04883                                                 $page_propArr = $this->getRecordProperties('pages',$propArr['pid']);
04884                                                 $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);
04885 
04886                                                         // Clear cache for relavant pages:
04887                                                 $this->clear_cache($table,$id);
04888                                         }
04889 
04890                                         return $id;
04891                                 } else {
04892                                         $this->log($table,$id,1,0,2,"SQL error: '%s' (%s)",12,array($GLOBALS['TYPO3_DB']->sql_error(),$table.':'.$id));
04893                                 }
04894                         }
04895                 }
04896         }
04897 
04908         function checkStoredRecord($table,$id,$fieldArray,$action)      {
04909                 global $TCA;
04910 
04911                 $id = intval($id);
04912                 if (is_array($TCA[$table]) && $id)      {
04913                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($id));
04914                         if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
04915                                         // Traverse array of values that was inserted into the database and compare with the actually stored value:
04916                                 $errorString = array();
04917                                 foreach($fieldArray as $key => $value)  {
04918                                         if ($this->checkStoredRecords_loose && !$value && !$row[$key])  {
04919                                                 // Nothing...
04920                                         } elseif (strcmp($value,$row[$key]))    {
04921                                                 $errorString[] = $key;
04922                                         }
04923                                 }
04924 
04925                                         // Set log message if there were fields with unmatching values:
04926                                 if (count($errorString))        {
04927                                         $this->log($table,$id,$action,0,102,'These fields are not properly updated in database: ('.implode(',',$errorString).') Probably value mismatch with fieldtype.');
04928                                 }
04929 
04930                                         // Return selected rows:
04931                                 return $row;
04932                         }
04933                         $GLOBALS['TYPO3_DB']->sql_free_result($res);
04934                 }
04935         }
04936 
04945         function setHistory($table,$id,$logId)          {
04946                 if (isset($this->historyRecords[$table.':'.$id]))       {
04947 
04948                                 // Initialize settings:
04949                         list($tscPID) = t3lib_BEfunc::getTSCpid($table,$id,'');
04950                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
04951 
04952                         $tE = $this->getTableEntries($table,$TSConfig);
04953                         $maxAgeSeconds = 60*60*24*(strcmp($tE['history.']['maxAgeDays'],'') ? t3lib_div::intInRange($tE['history.']['maxAgeDays'],0,365) : 30); // one month
04954 
04955                                 // Garbage collect old entries:
04956                         $this->clearHistory($maxAgeSeconds, $table);
04957 
04958                                 // Set history data:
04959                                 $fields_values = array();
04960                                 $fields_values['history_data'] = serialize($this->historyRecords[$table.':'.$id]);
04961                                 $fields_values['fieldlist'] = implode(',',array_keys($this->historyRecords[$table.':'.$id]['newRecord']));
04962                                 $fields_values['tstamp'] = time();
04963                                 $fields_values['tablename'] = $table;
04964                                 $fields_values['recuid'] = $id;
04965                                 $fields_values['sys_log_uid'] = $logId;
04966 
04967                                 $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_history', $fields_values);
04968                         }
04969                 }
04970 
04978         function clearHistory($maxAgeSeconds=604800,$table)     {
04979                 $tstampLimit = $maxAgeSeconds ? time()-$maxAgeSeconds : 0;
04980 
04981                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_history', 'tstamp<'.intval($tstampLimit).' AND tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_history'));
04982                 }
04983 
04992         function updateRefIndex($table,$id)     {
04993                 $refIndexObj = t3lib_div::makeInstance('t3lib_refindex');
04994                 $result = $refIndexObj->updateRefIndexTable($table,$id);
04995         }
04996 
04997 
04998 
04999 
05000 
05001 
05002 
05003 
05004 
05005 
05006 
05007 
05008 
05009         /*********************************************
05010          *
05011          * Misc functions
05012          *
05013          ********************************************/
05014 
05024         function getSortNumber($table,$uid,$pid)        {
05025                 global $TCA;
05026                 if ($TCA[$table] && $TCA[$table]['ctrl']['sortby'])     {
05027                         $sortRow = $TCA[$table]['ctrl']['sortby'];
05028                         if ($pid>=0)    {       // Sorting number is in the top
05029                                 $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
05030                                 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {       // There was an element
05031                                         if ($row['uid']==$uid)  {       // The top record was the record it self, so we return its current sortnumber
05032                                                 return $row[$sortRow];
05033                                         }
05034                                         if ($row[$sortRow] < 1) {       // If the pages sortingnumber < 1 we must resort the records under this pid
05035                                                 $this->resorting($table,$pid,$sortRow,0);
05036                                                 return $this->sortIntervals;    // First sorting number after resorting
05037                                         } else {
05038                                                 return floor($row[$sortRow]/2); // Sorting number between current top element and zero
05039                                         }
05040                                 } else {        // No pages, so we choose the default value as sorting-number
05041                                         return $this->sortIntervals;    // First sorting number if no elements.
05042                                 }
05043                         } else {        // Sorting number is inside the list
05044                                 $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
05045                                 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {       // There was a record
05046 
05047                                                 // 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.
05048                                         if ($lookForLiveVersion = t3lib_BEfunc::getLiveVersionOfRecord($table,$row['uid'],$sortRow.',pid,uid')) {
05049                                                 $row =  $lookForLiveVersion;
05050                                         }
05051 
05052                                                 // If the record happends to be it self
05053                                         if ($row['uid']==$uid)  {
05054                                                 $sortNumber = $row[$sortRow];
05055                                         } else {
05056                                                 $subres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
05057                                                                                 $sortRow.',pid,uid',
05058                                                                                 $table,
05059                                                                                 'pid='.intval($row['pid']).' AND '.$sortRow.'>='.intval($row[$sortRow]).$this->deleteClause($table),
05060                                                                                 '',
05061                                                                                 $sortRow.' ASC',
05062                                                                                 '2'
05063                                                                         );              // Fetches the next record in order to calculate the in between sortNumber
05064                                                 if ($GLOBALS['TYPO3_DB']->sql_num_rows($subres)==2)     {       // There was a record afterwards
05065                                                         $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres);                         // Forward to the second result...
05066                                                         $subrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres);       // There was a record afterwards
05067                                                         $sortNumber = $row[$sortRow]+ floor(($subrow[$sortRow]-$row[$sortRow])/2);      // The sortNumber is found in between these values
05068                                                         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
05069                                                                 $sortNumber = $this->resorting($table,$row['pid'],$sortRow,  $row['uid']);      // By this special param, resorting reserves and returns the sortnumber after the uid
05070                                                         }
05071                                                 } else {        // If after the last record in the list, we just add the sortInterval to the last sortvalue
05072                                                         $sortNumber = $row[$sortRow]+$this->sortIntervals;
05073                                                 }
05074                                         }
05075                                         return Array('pid' => $row['pid'], 'sortNumber' => $sortNumber);
05076                                 } else {
05077                                         $propArr = $this->getRecordProperties($table,$uid);
05078                                         $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...
05079                                         return false;   // There MUST be a page or else this cannot work
05080                                 }
05081                         }
05082                 }
05083         }
05084 
05097         function resorting($table,$pid,$sortRow, $return_SortNumber_After_This_Uid) {
05098                 global $TCA;
05099                 if ($TCA[$table] && $sortRow && $TCA[$table]['ctrl']['sortby']==$sortRow)       {
05100                         $returnVal = 0;
05101                         $intervals = $this->sortIntervals;
05102                         $i = $intervals*2;
05103 
05104                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($pid).$this->deleteClause($table), '', $sortRow.' ASC');
05105                         while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
05106                                 $uid=intval($row['uid']);
05107                                 if ($uid)       {
05108                                         $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), array($sortRow=>$i));
05109                                         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
05110                                                 $i = $i+$intervals;
05111                                                 $returnVal=$i;
05112                                         }
05113                                 } else {die ('Fatal ERROR!! No Uid at resorting.');}
05114                                 $i = $i+$intervals;
05115                         }
05116                         return $returnVal;
05117                 }
05118         }
05119 
05128         function setTSconfigPermissions($fieldArray,$TSConfig_p)        {
05129                 if (strcmp($TSConfig_p['userid'],''))   $fieldArray['perms_userid']=intval($TSConfig_p['userid']);
05130                 if (strcmp($TSConfig_p['groupid'],''))  $fieldArray['perms_groupid']=intval($TSConfig_p['groupid']);
05131                 if (strcmp($TSConfig_p['user'],''))                     $fieldArray['perms_user']=t3lib_div::testInt($TSConfig_p['user']) ? $TSConfig_p['user'] : $this->assemblePermissions($TSConfig_p['user']);
05132                 if (strcmp($TSConfig_p['group'],''))            $fieldArray['perms_group']=t3lib_div::testInt($TSConfig_p['group']) ? $TSConfig_p['group'] : $this->assemblePermissions($TSConfig_p['group']);
05133                 if (strcmp($TSConfig_p['everybody'],''))        $fieldArray['perms_everybody']=t3lib_div::testInt($TSConfig_p['everybody']) ? $TSConfig_p['everybody'] : $this->assemblePermissions($TSConfig_p['everybody']);
05134 
05135                 return $fieldArray;
05136         }
05137 
05145         function newFieldArray($table)  {
05146                 global $TCA;
05147 
05148                 t3lib_div::loadTCA($table);
05149                 $fieldArray=Array();
05150                 if (is_array($TCA[$table]['columns']))  {
05151                         reset ($TCA[$table]['columns']);
05152                         while (list($field,$content)=each($TCA[$table]['columns']))     {
05153                                 if (isset($this->defaultValues[$table][$field]))        {
05154                                         $fieldArray[$field] = $this->defaultValues[$table][$field];
05155                                 } elseif (isset($content['config']['default'])) {
05156                                         $fieldArray[$field] = $content['config']['default'];
05157                                 }
05158                         }
05159                 }
05160                 if ($table==='pages')   {               // Set default permissions for a page.
05161                         $fieldArray['perms_userid'] = $this->userid;
05162                         $fieldArray['perms_groupid'] = intval($this->BE_USER->firstMainGroup);
05163                         $fieldArray['perms_user'] = $this->assemblePermissions($this->defaultPermissions['user']);
05164                         $fieldArray['perms_group'] = $this->assemblePermissions($this->defaultPermissions['group']);
05165                         $fieldArray['perms_everybody'] = $this->assemblePermissions($this->defaultPermissions['everybody']);
05166                 }
05167                 return $fieldArray;
05168         }
05169 
05177         function addDefaultPermittedLanguageIfNotSet($table,&$incomingFieldArray)       {
05178                 global $TCA;
05179 
05180                         // Checking languages:
05181                 if ($TCA[$table]['ctrl']['languageField'])      {
05182                         if (!isset($incomingFieldArray[$TCA[$table]['ctrl']['languageField']])) {       // Language field must be found in input row - otherwise it does not make sense.
05183                                 $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)));
05184                                 foreach($rows as $r)    {
05185                                         if ($this->BE_USER->checkLanguageAccess($r['uid']))             {
05186                                                 $incomingFieldArray[$TCA[$table]['ctrl']['languageField']] = $r['uid'];
05187                                                 break;
05188                                         }
05189                                 }
05190                         }
05191                 }
05192         }
05193 
05201         function overrideFieldArray($table,$data)       {
05202                 if (is_array($this->overrideValues[$table]))    {
05203                         $data = array_merge($data,$this->overrideValues[$table]);
05204                 }
05205                 return $data;
05206         }
05207 
05217         function compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray)   {
05218 
05219                         // Fetch the original record:
05220                 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($id));
05221                 $currentRecord = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
05222 
05223                         // If the current record exists (which it should...), begin comparison:
05224                 if (is_array($currentRecord))   {
05225 
05226                                 // Read all field types:
05227                         $c = 0;
05228                         $cRecTypes = array();
05229                         foreach($currentRecord as $col => $val) {
05230                                 $cRecTypes[$col] = $GLOBALS['TYPO3_DB']->sql_field_type($res,$c);
05231                                 $c++;
05232                         }
05233 
05234                                 // Free result:
05235                         $GLOBALS['TYPO3_DB']->sql_free_result($res);
05236 
05237                                 // Unset the fields which are similar:
05238                         foreach($fieldArray as $col => $val)    {
05239                                 if (
05240                                                 !strcmp($val,$currentRecord[$col]) ||   // Unset fields which matched exactly.
05241                                                 ($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.
05242                                         )       {
05243                                         unset($fieldArray[$col]);
05244                                 } else {
05245                                         $this->historyRecords[$table.':'.$id]['oldRecord'][$col] = $currentRecord[$col];
05246                                         $this->historyRecords[$table.':'.$id]['newRecord'][$col] = $fieldArray[$col];
05247                                 }
05248                         }
05249                 } else {        // If the current record does not exist this is an error anyways and we just return an empty array here.
05250                         $fieldArray = array();
05251                 }
05252 
05253                 return $fieldArray;
05254         }
05255 
05263         function assemblePermissions($string)   {
05264                 $keyArr = t3lib_div::trimExplode(',',$string,1);
05265                 $value=0;
05266                 while(list(,$key)=each($keyArr))        {
05267                         if ($key && isset($this->pMap[$key]))   {
05268                                 $value |= $this->pMap[$key];
05269                         }
05270                 }
05271                 return $value;
05272         }
05273 
05280         function rmComma($input)        {
05281                 return ereg_replace(',$','',$input);
05282         }
05283 
05290         function convNumEntityToByteValue($input)       {
05291                 $token = md5(microtime());
05292                 $parts = explode($token,ereg_replace('(&#([0-9]+);)',$token.'\2'.$token,$input));
05293 
05294                 foreach($parts as $k => $v)     {
05295                         if ($k%2)       {
05296                                 $v = intval($v);
05297                                 if ($v > 32)    {       // Just to make sure that control bytes are not converted.
05298                                         $parts[$k] =chr(intval($v));
05299                                 }
05300                         }
05301                 }
05302 
05303                 return implode('',$parts);
05304         }
05305 
05312         function destPathFromUploadFolder($folder)      {
05313                 return PATH_site.$folder;
05314         }
05315 
05322         function deleteClause($table)   {
05323                         // Returns the proper delete-clause if any for a table from TCA
05324                 global $TCA;
05325                 if ($TCA[$table]['ctrl']['delete'])     {
05326                         return ' AND '.$table.'.'.$TCA[$table]['ctrl']['delete'].'=0';
05327                 } else {
05328                         return '';
05329                 }
05330         }
05331 
05338         function getTCEMAIN_TSconfig($tscPID)   {
05339                 if (!isset($this->cachedTSconfig[$tscPID]))     {
05340                         $this->cachedTSconfig[$tscPID] = $this->BE_USER->getTSConfig('TCEMAIN',t3lib_BEfunc::getPagesTSconfig($tscPID));
05341                 }
05342                 return $this->cachedTSconfig[$tscPID]['properties'];
05343         }
05344 
05353         function getTableEntries($table,$TSconfig)      {
05354                 $tA = is_array($TSconfig['table.'][$table.'.']) ? $TSconfig['table.'][$table.'.'] : array();;
05355                 $dA = is_array($TSconfig['default.']) ? $TSconfig['default.'] : array();
05356                 return t3lib_div::array_merge_recursive_overrule($dA,$tA);
05357         }
05358 
05366         function getPID($table,$uid)    {
05367                 $res_tmp = $GLOBALS['TYPO3_DB']->exec_SELECTquery('pid', $table, 'uid='.intval($uid));
05368                 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp))     {
05369                         return $row['pid'];
05370                 }
05371         }
05372 
05379         function dbAnalysisStoreExec()  {
05380                 reset($this->dbAnalysisStore);
05381                 while(list($k,$v)=each($this->dbAnalysisStore)) {
05382                         $id = $this->substNEWwithIDs[$v[2]];
05383                         if ($id)        {
05384                                 $v[2] = $id;
05385                                 $v[0]->writeMM($v[1],$v[2],$v[3]);
05386                         }
05387                 }
05388         }
05389 
05395         function removeRegisteredFiles()        {
05396                 reset($this->removeFilesStore);
05397                 while(list($k,$v)=each($this->removeFilesStore))        {
05398                         unlink($v);
05399                 }
05400         }
05401 
05407         function removeCacheFiles()     {
05408                 return t3lib_extMgm::removeCacheFiles();
05409         }
05410 
05421         function int_pageTreeInfo($CPtable,$pid,$counter, $rootID)      {
05422                 if ($counter)   {
05423                         $addW =  !$this->admin ? ' AND '.$this->BE_USER->getPagePermsClause($this->pMap['show']) : '';
05424                         $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'pid='.intval($pid).$this->deleteClause('pages').$addW, '', 'sorting DESC');
05425                         while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))      {
05426                                 if ($row['uid']!=$rootID)       {
05427                                         $CPtable[$row['uid']] = $pid;
05428                                         if ($counter-1) {       // If the uid is NOT the rootID of the copyaction and if we are supposed to walk further down
05429                                                 $CPtable = $this->int_pageTreeInfo($CPtable,$row['uid'],$counter-1, $rootID);
05430                                         }
05431                                 }
05432                         }
05433                 }
05434                 return $CPtable;
05435         }
05436 
05442         function compileAdminTables()   {
05443                 global $TCA;
05444                 reset ($TCA);
05445                 $listArr = array();
05446                 while (list($table)=each($TCA)) {
05447                         $listArr[]=$table;
05448                 }
05449                 return $listArr;
05450         }
05451 
05459         function fixUniqueInPid($table,$uid)    {
05460                 global $TCA;
05461                 if ($TCA[$table])       {
05462                         t3lib_div::loadTCA($table);
05463                         reset ($TCA[$table]['columns']);
05464                         $curData=$this->recordInfo($table,$uid,'*');
05465                         $newData=array();
05466                         while (list($field,$conf)=each($TCA[$table]['columns']))        {
05467                                 if ($conf['config']['type']=='input')   {
05468                                         $evalCodesArray = t3lib_div::trimExplode(',',$conf['config']['eval'],1);
05469                                         if (in_array('uniqueInPid',$evalCodesArray))    {
05470                                                 $newV = $this->getUnique($table,$field,$curData[$field],$uid,$curData['pid']);
05471                                                 if (strcmp($newV,$curData[$field]))     {
05472                                                         $newData[$field]=$newV;
05473                                                 }
05474                                         }
05475                                 }
05476                         }
05477                                 // IF there are changed fields, then update the database
05478                         if (count($newData))    {
05479                                 $this->updateDB($table,$uid,$newData);
05480                         }
05481                 }
05482         }
05483 
05495         function fixCopyAfterDuplFields($table,$uid,$prevUid,$update, $newData=array()) {
05496                 global $TCA;
05497                 if ($TCA[$table] && $TCA[$table]['ctrl']['copyAfterDuplFields'])        {
05498                         t3lib_div::loadTCA($table);
05499                         $prevData=$this->recordInfo($table,$prevUid,'*');
05500                         $theFields = t3lib_div::trimExplode(',',$TCA[$table]['ctrl']['copyAfterDuplFields'],1);
05501                         reset($theFields);
05502                         while(list(,$field)=each($theFields))   {
05503                                 if ($TCA[$table]['columns'][$field] && ($update || !isset($newData[$field])))   {
05504                                         $newData[$field]=$prevData[$field];
05505                                 }
05506                         }
05507                         if ($update && count($newData)) {
05508                                 $this->updateDB($table,$uid,$newData);
05509                         }
05510                 }
05511                 return $newData;
05512         }
05513 
05520         function extFileFields($table)  {
05521                 global $TCA;
05522                 $listArr=array();
05523                 t3lib_div::loadTCA($table);
05524                 if ($TCA[$table]['columns'])    {
05525                         reset($TCA[$table]['columns']);
05526                         while (list($field,$configArr)=each($TCA[$table]['columns']))   {
05527                                 if ($configArr['config']['type']=='group' && $configArr['config']['internal_type']=='file')     {
05528                                         $listArr[]=$field;
05529                                 }
05530                         }
05531                 }
05532                 return $listArr;
05533         }
05534 
05541         function getUniqueFields($table)        {
05542                 global $TCA;
05543 
05544                 $listArr=array();
05545                 t3lib_div::loadTCA($table);
05546                 if ($TCA[$table]['columns'])    {
05547                         reset($TCA[$table]['columns']);
05548                         while (list($field,$configArr)=each($TCA[$table]['columns']))   {
05549                                 if ($configArr['config']['type']==='input')     {
05550                                         $evalCodesArray = t3lib_div::trimExplode(',',$configArr['config']['eval'],1);
05551                                         if (in_array('uniqueInPid',$evalCodesArray) || in_array('unique',$evalCodesArray))      {
05552                                                 $listArr[]=$field;
05553                                         }
05554                                 }
05555                         }
05556                 }
05557                 return $listArr;
05558         }
05559 
05566         function isReferenceField($conf)        {
05567                 return ($conf['type']=='group' && $conf['internal_type']=='db') ||      ($conf['type']=='select' && $conf['foreign_table']);
05568         }
05569 
05577         function getInlineFieldType($conf) {
05578                 if ($conf['type'] == 'inline' && $conf['foreign_table']) {
05579                         if ($conf['foreign_field'])
05580                                 return 'field';         // the reference to the parent is stored in a pointer field in the child record
05581                         elseif ($conf['MM'])
05582                                 return 'mm';            // regular MM intermediate table is used to store data
05583                         else
05584                                 return 'list';          // an item list (separated by comma) is stored (like select type is doing)
05585                 }
05586                 return false;
05587         }
05588 
05600         function getCopyHeader($table,$pid,$field,$value,$count,$prevTitle='')  {
05601                 global $TCA;
05602 
05603                         // Set title value to check for:
05604                 if ($count)     {
05605                         $checkTitle = $value.rtrim(' '.sprintf($this->prependLabel($table),$count));
05606                 }       else {
05607                         $checkTitle = $value;
05608                 }
05609 
05610                         // Do check:
05611                 if ($prevTitle != $checkTitle || $count<100)    {
05612                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($pid).' AND '.$field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($checkTitle, $table).$this->deleteClause($table), '', '', '1');
05613                         if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
05614                                 return $this->getCopyHeader($table,$pid,$field,$value,$count+1,$checkTitle);
05615                         }
05616                 }
05617 
05618                         // Default is to just return the current input title if no other was returned before:
05619                 return $checkTitle;
05620         }
05621 
05629         function prependLabel($table)   {
05630                 global $TCA;
05631                 if (is_object($GLOBALS['LANG']))        {
05632                         $label = $GLOBALS['LANG']->sL($TCA[$table]['ctrl']['prependAtCopy']);
05633                 } else {
05634                         list($label) = explode('|',$TCA[$table]['ctrl']['prependAtCopy']);
05635                 }
05636                 return $label;
05637         }
05638 
05646         function resolvePid($table,$pid)        {
05647                 global $TCA;
05648                 $pid = intval($pid);
05649                 if ($pid < 0)   {
05650                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('pid', $table, 'uid='.abs($pid));
05651                         $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
05652 
05653                                 // 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.
05654                         if ($lookForLiveVersion = t3lib_BEfunc::getLiveVersionOfRecord($table,abs($pid),'pid')) {
05655                                 $row = $lookForLiveVersion;
05656                         }
05657 
05658                         $pid = intval($row['pid']);
05659                 } 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.
05660                         if ($WSdestPage = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, 'pages', $pid, 'uid,t3ver_swapmode'))    {       // Looks for workspace version of page.
05661                                 if ($WSdestPage['t3ver_swapmode']==0)   {       // if swapmode is zero, then change pid value.
05662                                         $pid = $WSdestPage['uid'];
05663                                 }
05664                         }
05665                 }
05666                 return $pid;
05667         }
05668 
05676         function clearPrefixFromValue($table,$value)    {
05677                 global $TCA;
05678                 $regex = sprintf(quotemeta($this->prependLabel($table)),'[0-9]*').'$';
05679                 return @ereg_replace($regex,'',$value);
05680         }
05681 
05691         function extFileFunctions($table,$field,$filelist,$func)        {
05692                 global $TCA;
05693                 t3lib_div::loadTCA($table);
05694                 $uploadFolder = $TCA[$table]['columns'][$field]['config']['uploadfolder'];
05695                 if ($uploadFolder && trim($filelist))   {
05696                         $uploadPath = $this->destPathFromUploadFolder($uploadFolder);
05697                         $fileArray = explode(',',$filelist);
05698                         while (list(,$theFile)=each($fileArray))        {
05699                                 $theFile=trim($theFile);
05700                                 if ($theFile)   {
05701                                         switch($func)   {
05702                                                 case 'deleteAll':
05703                                                         if (@is_file($uploadPath.'/'.$theFile)) {
05704                                                                 unlink ($uploadPath.'/'.$theFile);
05705                                                         } else {
05706                                                                 $this->log($table,0,3,0,100,"Delete: Referenced file that was supposed to be deleted together with it's record didn't exist");
05707                                                         }
05708                                                 break;
05709                                         }
05710                                 }
05711                         }
05712                 }
05713         }
05714 
05721         function noRecordsFromUnallowedTables($inList)  {
05722                 global $TCA;
05723                 reset ($TCA);
05724                 $inList = trim($this->rmComma(trim($inList)));
05725                 if ($inList && !$this->admin)   {
05726                         while (list($table) = each($TCA))       {
05727                                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', $table, 'pid IN ('.$inList.')'.t3lib_BEfunc::deleteClause($table));
05728                                 $count = $GLOBALS['TYPO3_DB']->sql_fetch_row($mres);
05729                                 if ($count[0] && ($this->tableReadOnly($table) || !$this->checkModifyAccessList($table)))       {
05730                                         return FALSE;
05731                                 }
05732                         }
05733                 }
05734                 return TRUE;
05735         }
05736 
05747         function notifyStageChange($stat,$stageId,$table,$id,$comment)  {
05748                 $workspaceRec = t3lib_BEfunc::getRecord('sys_workspace', $stat['uid']);
05749 
05750                 if (is_array($workspaceRec))    {
05751 
05752                                 // Compile label:
05753                         switch((int)$stageId)   {
05754                                 case 1:
05755                                         $newStage = 'Ready for review';
05756                                 break;
05757                                 case 10:
05758                                         $newStage = 'Ready for publishing';
05759                                 break;
05760                                 case -1:
05761                                         $newStage = 'Element was rejected!';
05762                                 break;
05763                                 case 0:
05764                                         $newStage = 'Rejected element was noticed and edited';
05765                                 break;
05766                                 default:
05767                                         $newStage = 'Unknown state change!?';
05768                                 break;
05769                         }
05770 
05771                                 // Compile list of recipients:
05772                         $emails = array();
05773                         switch((int)$stat['stagechg_notification'])     {
05774                                 case 1:
05775                                         switch((int)$stageId)   {
05776                                                 case 1:
05777                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['reviewers']);
05778                                                 break;
05779                                                 case 10:
05780                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['adminusers'], TRUE);
05781                                                 break;
05782                                                 case -1:
05783                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['reviewers']);
05784                                                         $emails = array_merge($emails,$this->notifyStageChange_getEmails($workspaceRec['members']));
05785                                                 break;
05786                                                 case 0:
05787                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['members']);
05788                                                 break;
05789                                                 default:
05790                                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['adminusers'], TRUE);
05791                                                 break;
05792                                         }
05793                                 break;
05794                                 case 10:
05795                                         $emails = $this->notifyStageChange_getEmails($workspaceRec['adminusers'], TRUE);
05796                                         $emails = array_merge($emails,$this->notifyStageChange_getEmails($workspaceRec['reviewers']));
05797                                         $emails = array_merge($emails,$this->notifyStageChange_getEmails($workspaceRec['members']));
05798                                 break;
05799                         }
05800                         $emails = array_unique($emails);
05801 
05802                                 // Send email:
05803                         if (count($emails))     {
05804                                 $message = sprintf('
05805 At the TYPO3 site "%s" (%s)
05806 in workspace "%s" (#%s)
05807 the stage has changed for the element "%s":
05808 
05809 ==> %s
05810 
05811 User Comment:
05812 "%s"
05813 
05814 State was change by %s (username: %s)
05815                                 ',
05816                                 $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'],
05817                                 t3lib_div::getIndpEnv('TYPO3_SITE_URL').TYPO3_mainDir,
05818                                 $workspaceRec['title'],
05819                                 $workspaceRec['uid'],
05820                                 $table.':'.$id,
05821                                 $newStage,
05822                                 $comment,
05823                                 $this->BE_USER->user['realName'],
05824                                 $this->BE_USER->user['username']);
05825 
05826                                 t3lib_div::plainMailEncoded(
05827                                         implode(',',$emails),
05828                                         'TYPO3 Workspace Note: Stage Change for '.$table.':'.$id,
05829                                         trim($message)
05830                                 );
05831                         }
05832                 }
05833         }
05834 
05842         function notifyStageChange_getEmails($listOfUsers,$noTablePrefix=FALSE) {
05843                 $users = t3lib_div::trimExplode(',',$listOfUsers,1);
05844                 $emails = array();
05845                 foreach($users as $userIdent)   {
05846                         if ($noTablePrefix)     {
05847                                 $id = intval($userIdent);
05848                         } else {
05849                                 list($table,$id) = t3lib_div::revExplode('_',$userIdent,2);
05850                         }
05851                         if ($table==='be_users' || $noTablePrefix)      {
05852                                 if ($userRecord = t3lib_BEfunc::getRecord('be_users', $id, 'email'))    {
05853                                         if (strlen(trim($userRecord['email']))) {
05854                                                 $emails[$id] = $userRecord['email'];
05855                                         }
05856                                 }
05857                         }
05858                 }
05859                 return $emails;
05860         }
05861 
05862 
05863 
05864 
05865 
05866 
05867 
05868 
05869 
05870 
05871 
05872 
05873         /******************************
05874          *
05875          * Clearing cache
05876          *
05877          ******************************/
05878 
05888         function clear_cache($table,$uid) {
05889                 global $TCA, $TYPO3_CONF_VARS;
05890 
05891                 $uid = intval($uid);
05892                 if (is_array($TCA[$table]) && $uid > 0) {
05893 
05894                                 // Get Page TSconfig relavant:
05895                         list($tscPID) = t3lib_BEfunc::getTSCpid($table,$uid,'');
05896                         $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
05897 
05898                         if (!$TSConfig['clearCache_disable'])   {
05899 
05900                                         // If table is "pages":
05901                                 if (t3lib_extMgm::isLoaded('cms'))      {
05902                                         $list_cache = array();
05903                                         if ($table=='pages')    {
05904 
05905                                                         // Builds list of pages on the SAME level as this page (siblings)
05906                                                 $res_tmp = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
05907                                                                                 'A.pid AS pid, B.uid AS uid',
05908                                                                                 'pages A, pages B',
05909                                                                                 'A.uid='.intval($uid).' AND B.pid=A.pid AND B.deleted=0'
05910                                                                         );
05911 
05912                                                 $pid_tmp = 0;
05913                                                 while ($row_tmp = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp)) {
05914                                                         $list_cache[] = $row_tmp['uid'];
05915                                                         $pid_tmp = $row_tmp['pid'];
05916 
05917                                                                 // Add children as well:
05918                                                         if ($TSConfig['clearCache_pageSiblingChildren'])        {
05919                                                                 $res_tmp2 = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
05920                                                                                                 'uid',
05921                                                                                                 'pages',
05922                                                                                                 'pid='.intval($row_tmp['uid']).' AND deleted=0'
05923                                                                                         );
05924                                                                 while ($row_tmp2 = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp2))    {
05925                                                                         $list_cache[] = $row_tmp2['uid'];
05926                                                                 }
05927                                                         }
05928                                                 }
05929 
05930                                                         // Finally, add the parent page as well:
05931                                                 $list_cache[] = $pid_tmp;
05932 
05933                                                         // Add grand-parent as well:
05934                                                 if ($TSConfig['clearCache_pageGrandParent'])    {
05935                                                         $res_tmp = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
05936                                                                                         'pid',
05937                                                                                         'pages',
05938                                                                                         'uid='.intval($pid_tmp)
05939                                                                                 );
05940                                                         if ($row_tmp = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp)) {
05941                                                                 $list_cache[] = $row_tmp['pid'];
05942                                                         }
05943                                                 }
05944                                         } else {        // For other tables than "pages", delete cache for the records "parent page".
05945                                                 $list_cache[] = intval($this->getPID($table,$uid));
05946                                         }
05947 
05948                                                 // Call pre-processing function for clearing of cache for page ids:
05949                                         if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval']))    {
05950                                                 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval'] as $funcName)     {
05951                                                         $_params = array('pageIdArray' => &$list_cache, 'table' => $table, 'uid' => $uid, 'functionID' => 'clear_cache()');
05952                                                                 // Returns the array of ids to clear, false if nothing should be cleared! Never an empty array!
05953                                                         t3lib_div::callUserFunction($funcName,$_params,$this);
05954                                                 }
05955                                         }
05956 
05957                                                 // Delete cache for selected pages:
05958                                         if (is_array($list_cache))      {
05959                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')');
05960                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection', 'page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')');
05961                                         }
05962                                 }
05963                         }
05964 
05965                                 // Clear cache for pages entered in TSconfig:
05966                         if ($TSConfig['clearCacheCmd']) {
05967                                 $Commands = t3lib_div::trimExplode(',',strtolower($TSConfig['clearCacheCmd']),1);
05968                                 $Commands = array_unique($Commands);
05969                                 foreach($Commands as $cmdPart)  {
05970                                         $this->clear_cacheCmd($cmdPart);
05971                                 }
05972                         }
05973 
05974                                 // Call post processing function for clear-cache:
05975                         global $TYPO3_CONF_VARS;
05976                         if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc']))    {
05977 // FIXME $uid_page is undefined
05978                                 $_params = array('table' => $table,'uid' => $uid,'uid_page' => $uid_page,'TSConfig' => $TSConfig);
05979                                 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'] as $_funcRef)     {
05980                                         t3lib_div::callUserFunction($_funcRef,$_params,$this);
05981                                 }
05982                         }
05983                 }
05984         }
05985 
05998         function clear_cacheCmd($cacheCmd)      {
05999                 global $TYPO3_CONF_VARS;
06000 
06001                         // Clear cache for either ALL pages or ALL tables!
06002                 switch($cacheCmd)       {
06003                         case 'pages':
06004                                 if ($this->admin || $this->BE_USER->getTSConfigVal('options.clearCache.pages')) {
06005                                         if (t3lib_extMgm::isLoaded('cms'))      {
06006                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','');
06007                                         }
06008                                 }
06009                         break;
06010                         case 'all':
06011                                 if ($this->admin || $this->BE_USER->getTSConfigVal('options.clearCache.all'))   {
06012                                         if (t3lib_extMgm::isLoaded('cms'))      {
06013                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','');
06014                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection','');
06015                                         }
06016                                         $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_hash','');
06017 
06018                                                 // Clearing additional cache tables:
06019                                         if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearAllCache_additionalTables']))        {
06020                                                 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearAllCache_additionalTables'] as $tableName)        {
06021                                                         if (!ereg('[^[:alnum:]_]',$tableName) && substr($tableName,-5)=='cache')        {
06022                                                                 $GLOBALS['TYPO3_DB']->exec_DELETEquery($tableName,'');
06023                                                         } else {
06024                                                                 die('Fatal Error: Trying to flush table "'.$tableName.'" with "Clear All Cache"');
06025                                                         }
06026                                                 }
06027                                         }
06028                                 }
06029                         break;
06030                         case 'temp_CACHED':
06031                                 if ($this->admin && $TYPO3_CONF_VARS['EXT']['extCache'])        {
06032                                         $this->removeCacheFiles();
06033                                 }
06034                         break;
06035                 }
06036 
06037                         // Clear cache for a page ID!
06038                 if (t3lib_div::testInt($cacheCmd))      {
06039                         if (t3lib_extMgm::isLoaded('cms'))      {
06040 
06041                                 $list_cache = array($cacheCmd);
06042 
06043                                         // Call pre-processing function for clearing of cache for page ids:
06044                                 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval']))    {
06045                                         foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval'] as $funcName)     {
06046                                                 $_params = array('pageIdArray' => &$list_cache, 'cacheCmd' => $cacheCmd, 'functionID' => 'clear_cacheCmd()');
06047                                                         // Returns the array of ids to clear, false if nothing should be cleared! Never an empty array!
06048                                                 t3lib_div::callUserFunction($funcName,$_params,$this);
06049                                         }
06050                                 }
06051 
06052                                         // Delete cache for selected pages:
06053                                 if (is_array($list_cache))      {
06054                                         $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')');
06055                                         $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!
06056                                 }
06057                         }
06058                 }
06059 
06060                         // Call post processing function for clear-cache:
06061                 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc']))    {
06062                         $_params = array('cacheCmd'=>$cacheCmd);
06063                         foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'] as $_funcRef)     {
06064                                 t3lib_div::callUserFunction($_funcRef,$_params,$this);
06065                         }
06066                 }
06067         }
06068 
06069 
06070 
06071 
06072 
06073 
06074 
06075 
06076 
06077 
06078 
06079 
06080 
06081 
06082         /*****************************
06083          *
06084          * Logging
06085          *
06086          *****************************/
06087 
06104         function log($table,$recuid,$action,$recpid,$error,$details,$details_nr=-1,$data=array(),$event_pid=-1,$NEWid='') {
06105                 if ($this->enableLogging)       {
06106                         $type=1;        // Type value for tce_db.php
06107                         if (!$this->storeLogMessages)   {$details='';}
06108                         if ($error>0)   $this->errorLog[] = '['.$type.'.'.$action.'.'.$details_nr.']: '.$details;
06109                         return $this->BE_USER->writelog($type,$action,$error,$details_nr,$details,$data,$table,$recuid,$recpid,$event_pid,$NEWid);
06110                 }
06111         }
06112 
06121         function newlog($message, $error=0)     {
06122                 return $this->log('',0,0,0,$error,$message,-1);
06123         }
06124 
06131         function printLogErrorMessages($redirect)       {
06132 
06133                 $res_log = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
06134                                         '*',
06135                                         'sys_log',
06136                                         'type=1 AND userid='.intval($this->BE_USER->user['uid']).' AND tstamp='.intval($GLOBALS['EXEC_TIME']).' AND error!=0'
06137                                 );
06138                 $errorJS = array();
06139                 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_log)) {
06140                         $log_data = unserialize($row['log_data']);
06141                         $errorJS[] = $row['error'].': '.sprintf($row['details'], $log_data[0],$log_data[1],$log_data[2],$log_data[3],$log_data[4]);
06142                 }
06143 
06144                 if (count($errorJS))    {
06145                         $error_doc = t3lib_div::makeInstance('template');
06146                         $error_doc->backPath = $GLOBALS['BACK_PATH'];
06147 
06148                         $content.= $error_doc->startPage('tce_db.php Error output');
06149 
06150                         $lines[] = '
06151                                         <tr class="bgColor5">
06152                                                 <td colspan="2" align="center"><strong>Errors:</strong></td>
06153                                         </tr>';
06154 
06155                         foreach($errorJS as $line)      {
06156                                 $lines[] = '
06157                                         <tr class="bgColor4">
06158                                                 <td valign="top"><img'.t3lib_iconWorks::skinImg($error_doc->backPath,'gfx/icon_fatalerror.gif','width="18" height="16"').' alt="" /></td>
06159                                                 <td>'.htmlspecialchars($line).'</td>
06160                                         </tr>';
06161                         }
06162 
06163                         $lines[] = '
06164                                         <tr>
06165                                                 <td colspan="2" align="center"><br />'.
06166                                                 '<form action=""><input type="submit" value="Continue" onclick="'.htmlspecialchars('window.location.href=\''.$redirect.'\';return false;').'"></form>'.
06167                                                 '</td>
06168                                         </tr>';
06169 
06170                         $content.= '
06171                                 <br/><br/>
06172                                 <table border="0" cellpadding="1" cellspacing="1" width="300" align="center">
06173                                         '.implode('',$lines).'
06174                                 </table>';
06175 
06176                         $content.= $error_doc->endPage();
06177                         echo $content;
06178                         exit;
06179                 }
06180         }
06181 }
06182 
06183 
06184 
06185 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tcemain.php'])   {
06186         include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tcemain.php']);
06187 }
06188 ?>


Généré par L'expert TYPO3 avec  doxygen 1.4.6