Documentation TYPO3 par Ameos |
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2005 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 ***************************************************************/ 00163 // ******************************* 00164 // Including necessary libraries 00165 // ******************************* 00166 require_once (PATH_t3lib.'class.t3lib_loaddbgroup.php'); 00167 require_once (PATH_t3lib.'class.t3lib_parsehtml_proc.php'); 00168 require_once (PATH_t3lib.'class.t3lib_stdgraphic.php'); 00169 require_once (PATH_t3lib.'class.t3lib_basicfilefunc.php'); 00170 00171 00172 00173 00174 00175 00176 00177 00178 00179 00180 00181 00182 00199 class t3lib_TCEmain { 00200 var $log_table = 'sys_log'; 00201 00202 var $checkStoredRecords = 1; // 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 00203 var $checkStoredRecords_loose=1; // If set, values '' and 0 will equal each other when the stored records are checked. 00204 var $sortIntervals = 256; // The interval between sorting numbers used with tables with a 'sorting' field defined. Min 1 00205 00206 var $deleteTree = 0; // 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 delete ONLY if it has no branch 00207 var $copyTree = 0; // int. 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 00208 var $versionizeTree = 0; // int. If 0 then branch is NOT versionized. If 1 then pages on the 1st level is versionized. If 2 then pages on the second level is versionized ... and so on 00209 var $neverHideAtCopy = 0; // Boolean. If set, then the 'hideAtCopy' flag for tables will be ignored. 00210 var $reverseOrder=0; // boolean. If set, the dataarray is reversed in the order, which is a nice thing if you're creating a whole new bunch of records. 00211 var $copyWhichTables = '*'; // 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) 00212 var $stripslashes_values=1; // If set, 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! 00213 var $storeLogMessages=1; // If set, 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. 00214 var $enableLogging=1; // If set, actions are logged. 00215 00216 var $callBackObj; // Call back object for flex form traversation. Useful when external classes wants to use the iteration functions inside tcemain for traversing a FlexForm structure. 00217 00218 // var $history=1; // Bit-array: Bit0: History on/off. DEPENDS on checkSimilar to be set! 00219 var $checkSimilar=1; // Boolean: If set, 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. 00220 var $dontProcessTransformations=0; // Boolean: If set, then transformations are NOT performed on the input. 00221 # var $disableRTE = 0; // Boolean: If set, the RTE is expected to have been disabled in the interface which submitted information. Thus transformations related to the RTE is not done. 00222 00223 var $pMap = Array( // Permission mapping 00224 'show' => 1, // 1st bit 00225 'edit' => 2, // 2nd bit 00226 'delete' => 4, // 3rd bit 00227 'new' => 8, // 4th bit 00228 'editcontent' => 16 // 5th bit 00229 ); 00230 var $defaultPermissions = array( // Can be overridden from $TYPO3_CONF_VARS 00231 'user' => 'show,edit,delete,new,editcontent', 00232 'group' => 'show,edit,new,editcontent', 00233 'everybody' => '' 00234 ); 00235 00236 00237 var $alternativeFileName=array(); // 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. 00238 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. 00239 var $defaultValues=array(); // You can set this array on the form $defaultValues[$table][$field] = $value to override the default values fetched from TCA. You must set this externally. 00240 var $overrideValues=array(); // 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! 00241 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) 00242 00243 // ********* 00244 // internal 00245 // ********* 00246 var $fileFunc; // May contain an object 00247 var $last_log_id; 00248 var $BE_USER; // The user-object the script uses. If not set from outside, this is set to the current global $BE_USER. 00249 var $userid; // will be set to uid of be_user executing this script 00250 var $username; // will be set to username of be_user executing this script 00251 var $admin; // will be set if user is admin 00252 var $exclude_array; // the list of <table>-<fields> that cannot be edited. This is compiled from TCA/exclude-flag combined with non_exclude_fields for the user. 00253 00254 var $data = Array(); 00255 var $datamap = Array(); 00256 var $cmd = Array(); 00257 var $cmdmap = Array(); 00258 var $uploadedFileArray = array(); 00259 00260 var $cachedTSconfig = array(); 00261 var $substNEWwithIDs = Array(); 00262 var $substNEWwithIDs_table = Array(); 00263 var $recUpdateAccessCache = Array(); // Used by function checkRecordUpdateAccess() to store whether a record is updateable or not. 00264 var $recInsertAccessCache = Array(); 00265 var $isRecordInWebMount_Cache=array(); 00266 var $isInWebMount_Cache=array(); 00267 var $pageCache = Array(); // Used for caching page records in pageInfo() 00268 var $copyMappingArray = Array(); // Use by the copy action to track the ids of new pages so subpages are correctly inserted! 00269 var $copyMappingArray_merged = Array(); // This array is the sum of all copying operations in this class. May be READ from outside, thus partly public. 00270 var $registerDBList=array(); 00271 var $dbAnalysisStore=array(); 00272 var $removeFilesStore=array(); 00273 var $copiedFileMap=array(); 00274 00275 var $checkValue_currentRecord=array(); // Set to "currentRecord" during checking of values. 00276 00277 00288 function start($data,$cmd,$altUserObject='') { 00289 // Initializing BE_USER 00290 $this->BE_USER = is_object($altUserObject) ? $altUserObject : $GLOBALS['BE_USER']; 00291 $this->userid = $this->BE_USER->user['uid']; 00292 $this->username = $this->BE_USER->user['username']; 00293 $this->admin = $this->BE_USER->user['admin']; 00294 00295 // Initializing default permissions for pages 00296 $defaultPermissions = $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPermissions']; 00297 if (isset($defaultPermissions['user'])) {$this->defaultPermissions['user'] = $defaultPermissions['user'];} 00298 if (isset($defaultPermissions['group'])) {$this->defaultPermissions['group'] = $defaultPermissions['group'];} 00299 if (isset($defaultPermissions['everybody'])) {$this->defaultPermissions['everybody'] = $defaultPermissions['everybody'];} 00300 00301 // generates the excludelist, based on TCA/exclude-flag and non_exclude_fields for the user: 00302 $this->exclude_array = ($this->admin) ? array() : $this->getExcludeListArray(); 00303 00304 // Setting the data and cmd arrays 00305 if (is_array($data)) { 00306 reset($data); 00307 $this->datamap = $data; 00308 } 00309 if (is_array($cmd)) { 00310 reset($cmd); 00311 $this->cmdmap = $cmd; 00312 } 00313 } 00314 00321 function setMirror($mirror) { 00322 if (is_array($mirror)) { 00323 reset($mirror); 00324 while(list($table,$uid_array)=each($mirror)) { 00325 if (isset($this->datamap[$table])) { 00326 reset($uid_array); 00327 while (list($id,$uidList) = each($uid_array)) { 00328 if (isset($this->datamap[$table][$id])) { 00329 $theIdsInArray = t3lib_div::trimExplode(',',$uidList,1); 00330 while(list(,$copyToUid)=each($theIdsInArray)) { 00331 $this->datamap[$table][$copyToUid] = $this->datamap[$table][$id]; 00332 } 00333 } 00334 } 00335 } 00336 } 00337 } 00338 } 00339 00346 function setDefaultsFromUserTS($userTS) { 00347 global $TCA; 00348 if (is_array($userTS)) { 00349 foreach($userTS as $k => $v) { 00350 $k = substr($k,0,-1); 00351 if ($k && is_array($v) && isset($TCA[$k])) { 00352 if (is_array($this->defaultValues[$k])) { 00353 $this->defaultValues[$k] = array_merge($this->defaultValues[$k],$v); 00354 } else { 00355 $this->defaultValues[$k] = $v; 00356 } 00357 } 00358 } 00359 } 00360 } 00361 00369 function process_uploads($postFiles) { 00370 if (is_array($postFiles)) { 00371 reset($postFiles); 00372 $subA = current($postFiles); 00373 if (is_array($subA)) { 00374 if (is_array($subA['name']) && is_array($subA['type']) && is_array($subA['tmp_name']) && is_array($subA['size'])) { 00375 // Initialize the uploadedFilesArray: 00376 $this->uploadedFileArray=array(); 00377 00378 // For each entry: 00379 foreach($subA as $key => $values) { 00380 $this->process_uploads_traverseArray($this->uploadedFileArray,$values,$key); 00381 } 00382 } else { 00383 $this->uploadedFileArray=$subA; 00384 } 00385 } 00386 } 00387 } 00388 00399 function process_uploads_traverseArray(&$outputArr,$inputArr,$keyToSet) { 00400 if (is_array($inputArr)) { 00401 foreach($inputArr as $key => $value) { 00402 $this->process_uploads_traverseArray($outputArr[$key],$inputArr[$key],$keyToSet); 00403 } 00404 } else { 00405 $outputArr[$keyToSet]=$inputArr; 00406 } 00407 } 00408 00409 00410 00411 00412 00413 00414 00415 00416 00417 00418 00419 00420 00421 00422 00423 /********************************************* 00424 * 00425 * PROCESSING DATA 00426 * 00427 *********************************************/ 00428 00435 function process_datamap() { 00436 global $TCA, $TYPO3_CONF_VARS; 00437 00438 // First prepare user defined objects (if any) for hooks which extend this function: 00439 $hookObjectsArr = array(); 00440 if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'])) { 00441 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'] as $classRef) { 00442 $hookObjectsArr[] = &t3lib_div::getUserObj($classRef); 00443 } 00444 } 00445 00446 // Organize tables so that the pages-table are always processed first. This is required if you want to make sure that content pointing to a new page will be created. 00447 $orderOfTables = Array(); 00448 if (isset($this->datamap['pages'])) { // Set pages first. 00449 $orderOfTables[]='pages'; 00450 } 00451 reset($this->datamap); 00452 while (list($table,) = each($this->datamap)) { 00453 if ($table!='pages') { 00454 $orderOfTables[]=$table; 00455 } 00456 } 00457 00458 // Process the tables... 00459 foreach($orderOfTables as $table) { 00460 /* Check if 00461 - table is set in $TCA, 00462 - table is NOT readOnly, 00463 - the table is set with content in the data-array (if not, there's nothing to process...) 00464 - permissions for tableaccess OK 00465 */ 00466 $modifyAccessList = $this->checkModifyAccessList($table); 00467 if (!$modifyAccessList) { 00468 $this->log($table,$id,2,0,1,"Attempt to modify table '%s' without permission",1,array($table)); 00469 } 00470 if (isset($TCA[$table]) && !$this->tableReadOnly($table) && is_array($this->datamap[$table]) && $modifyAccessList) { 00471 if ($this->reverseOrder) { 00472 $this->datamap[$table] = array_reverse($this->datamap[$table], 1); 00473 } 00474 00475 // For each record from the table, do: 00476 // $id is the record uid, may be a string if new records... 00477 // $incomingFieldArray is the array of fields 00478 foreach($this->datamap[$table] as $id => $incomingFieldArray) { 00479 if (is_array($incomingFieldArray)) { 00480 00481 // Hook: processDatamap_preProcessIncomingFieldArray 00482 foreach($hookObjectsArr as $hookObj) { 00483 if (method_exists($hookObj, 'processDatamap_preProcessFieldArray')) { 00484 $hookObj->processDatamap_preProcessFieldArray($incomingFieldArray, $table, $id, $this); 00485 } 00486 } 00487 00488 // ****************************** 00489 // Checking access to the record 00490 // ****************************** 00491 $recordAccess = 0; 00492 $old_pid_value = ''; 00493 if (!t3lib_div::testInt($id)) { // Is it a new record? (Then Id is a string) 00494 $fieldArray = $this->newFieldArray($table); // Get a fieldArray with default values 00495 if (isset($incomingFieldArray['pid'])) { // A pid must be set for new records. 00496 // $value = the pid 00497 $pid_value = $incomingFieldArray['pid']; 00498 00499 // Checking and finding numerical pid, it may be a string-reference to another value 00500 $OK = 1; 00501 if (strstr($pid_value,'NEW')) { // If a NEW... id 00502 if (substr($pid_value,0,1)=='-') {$negFlag=-1;$pid_value=substr($pid_value,1);} else {$negFlag=1;} 00503 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. 00504 $old_pid_value = $pid_value; 00505 $pid_value=intval($negFlag*$this->substNEWwithIDs[$pid_value]); 00506 } else {$OK = 0;} // If not found in the substArray we must stop the proces... 00507 } 00508 $pid_value = intval($pid_value); 00509 00510 // The $pid_value is now the numerical pid at this point 00511 if ($OK) { 00512 $sortRow = $TCA[$table]['ctrl']['sortby']; 00513 if ($pid_value>=0) { // Points to a page on which to insert the element, possibly in the top of the page 00514 if ($sortRow) { // If this table is sorted we better find the top sorting number 00515 $fieldArray[$sortRow] = $this->getSortNumber($table,0,$pid_value); 00516 } 00517 $fieldArray['pid'] = $pid_value; // The numerical pid is inserted in the data array 00518 } else { // points to another record before ifself 00519 if ($sortRow) { // If this table is sorted we better find the top sorting number 00520 $tempArray=$this->getSortNumber($table,0,$pid_value); // Because $pid_value is < 0, getSortNumber returns an array 00521 $fieldArray['pid'] = $tempArray['pid']; 00522 $fieldArray[$sortRow] = $tempArray['sortNumber']; 00523 } else { // Here we fetch the PID of the record that we point to... 00524 $tempdata = $this->recordInfo($table,abs($pid_value),'pid'); 00525 $fieldArray['pid']=$tempdata['pid']; 00526 } 00527 } 00528 } 00529 } 00530 $theRealPid = $fieldArray['pid']; 00531 // Now, check if we may insert records on this pid. 00532 if ($theRealPid>=0) { 00533 $recordAccess = $this->checkRecordInsertAccess($table,$theRealPid); // Checks if records can be inserted on this $pid. 00534 } else { 00535 debug('Internal ERROR: pid should not be less than zero!'); 00536 } 00537 $status = 'new'; // Yes new record, change $record_status to 'insert' 00538 } else { // Nope... $id is a number 00539 $fieldArray = Array(); 00540 $recordAccess = $this->checkRecordUpdateAccess($table,$id); 00541 if (!$recordAccess) { 00542 $propArr = $this->getRecordProperties($table,$id); 00543 $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']); 00544 } else { // Next check of the record permissions (internals) 00545 $recordAccess = $this->BE_USER->recordEditAccessInternals($table,$id); 00546 if (!$recordAccess) { 00547 $propArr = $this->getRecordProperties($table,$id); 00548 $this->log($table,$id,2,0,1,"recordEditAccessInternals() check failed. [".$this->BE_USER->errorMsg."]",2,array($propArr['header'],$table.':'.$id),$propArr['event_pid']); 00549 } else { // Here we fetch the PID of the record that we point to... 00550 $tempdata = $this->recordInfo($table,$id,'pid'); 00551 $theRealPid = $tempdata['pid']; 00552 } 00553 } 00554 $status = 'update'; // the default is 'update' 00555 } 00556 00557 // ************************************** 00558 // If access was granted above, proceed: 00559 // ************************************** 00560 if ($recordAccess) { 00561 00562 list($tscPID) = t3lib_BEfunc::getTSCpid($table,$id,$old_pid_value ? $old_pid_value : $fieldArray['pid']); // Here the "pid" is sent IF NOT the old pid was a string pointing to a place in the subst-id array. 00563 $TSConfig = $this->getTCEMAIN_TSconfig($tscPID); 00564 if ($status=='new' && $table=='pages' && is_array($TSConfig['permissions.'])) { 00565 $fieldArray = $this->setTSconfigPermissions($fieldArray,$TSConfig['permissions.']); 00566 } 00567 00568 $fieldArray = $this->fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$theRealPid,$status,$tscPID); 00569 00570 // NOTICE! All manipulation beyond this point bypasses both "excludeFields" AND possible "MM" relations / file uploads to field! 00571 00572 $fieldArray = $this->overrideFieldArray($table,$fieldArray); // NOTICE: This overriding is potentially dangerous; permissions per field is not checked!!! 00573 00574 // Setting system fields 00575 if ($status=='new') { 00576 if ($TCA[$table]['ctrl']['crdate']) { 00577 $fieldArray[$TCA[$table]['ctrl']['crdate']]=time(); 00578 } 00579 if ($TCA[$table]['ctrl']['cruser_id']) { 00580 $fieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid; 00581 } 00582 } elseif ($this->checkSimilar) { // Removing fields which are equal to the current value: 00583 $fieldArray = $this->compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray); 00584 } 00585 if ($TCA[$table]['ctrl']['tstamp']) { 00586 $fieldArray[$TCA[$table]['ctrl']['tstamp']]=time(); 00587 } 00588 00589 // Hook: processDatamap_postProcessFieldArray 00590 foreach($hookObjectsArr as $hookObj) { 00591 if (method_exists($hookObj, 'processDatamap_postProcessFieldArray')) { 00592 $hookObj->processDatamap_postProcessFieldArray($status, $table, $id, $fieldArray, $this); 00593 } 00594 } 00595 00596 // Performing insert/update. If fieldArray has been unset by some userfunction (see hook above), don't do anything 00597 // Kasper: Unsetting the fieldArray is dangerous; MM relations might be saved already and files could have been uploaded that are now "lost" 00598 if (is_array($fieldArray)) { 00599 if ($status=='new') { 00600 // if ($pid_value<0) {$fieldArray = $this->fixCopyAfterDuplFields($table,$id,abs($pid_value),0,$fieldArray);} // Out-commented 02-05-02: I couldn't understand WHY this is needed for NEW records. Obviously to proces records being copied? Problem is that the fields are not set anyways and the copying function should basically take care of this! 00601 $this->insertDB($table,$id,$fieldArray,FALSE,$incomingFieldArray['uid']); 00602 } else { 00603 $this->updateDB($table,$id,$fieldArray); 00604 } 00605 } 00606 00607 // Hook: processDatamap_afterDatabaseOperations 00608 foreach($hookObjectsArr as $hookObj) { 00609 if (method_exists($hookObj, 'processDatamap_afterDatabaseOperations')) { 00610 $hookObj->processDatamap_afterDatabaseOperations($status, $table, $id, $fieldArray, $this); 00611 } 00612 } 00613 } // if ($recordAccess) { 00614 } // if (is_array($incomingFieldArray)) { 00615 } 00616 } 00617 } 00618 $this->dbAnalysisStoreExec(); 00619 $this->removeRegisteredFiles(); 00620 } 00621 00635 function fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$realPid,$status,$tscPID) { 00636 global $TCA; 00637 00638 // Initialize: 00639 t3lib_div::loadTCA($table); 00640 unset($originalLanguageRecord); 00641 unset($originalLanguage_diffStorage); 00642 $diffStorageFlag = FALSE; 00643 00644 // Setting 'currentRecord' and 'checkValueRecord': 00645 if (strstr($id,'NEW')) { 00646 $currentRecord = $checkValueRecord = $fieldArray; // must have the 'current' array - not the values after processing below... 00647 00648 // IF $incomingFieldArray is an array, overlay it. 00649 // 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... 00650 if (is_array($incomingFieldArray) && is_array($checkValueRecord)) { 00651 $checkValueRecord = t3lib_div::array_merge_recursive_overrule($checkValueRecord, $incomingFieldArray); 00652 } 00653 } else { 00654 $currentRecord = $checkValueRecord = $this->recordInfo($table,$id,'*'); // We must use the current values as basis for this! 00655 00656 // Get original language record if available: 00657 if (is_array($currentRecord) 00658 && $TCA[$table]['ctrl']['transOrigDiffSourceField'] 00659 && $TCA[$table]['ctrl']['languageField'] 00660 && $currentRecord[$TCA[$table]['ctrl']['languageField']] > 0 00661 && $TCA[$table]['ctrl']['transOrigPointerField'] 00662 && intval($currentRecord[$TCA[$table]['ctrl']['transOrigPointerField']]) > 0) { 00663 00664 $lookUpTable = $TCA[$table]['ctrl']['transOrigPointerTable'] ? $TCA[$table]['ctrl']['transOrigPointerTable'] : $table; 00665 $originalLanguageRecord = $this->recordInfo($lookUpTable,$currentRecord[$TCA[$table]['ctrl']['transOrigPointerField']],'*'); 00666 $originalLanguage_diffStorage = unserialize($currentRecord[$TCA[$table]['ctrl']['transOrigDiffSourceField']]); 00667 } 00668 } 00669 $this->checkValue_currentRecord = $checkValueRecord; 00670 00671 /* 00672 In the following all incoming value-fields are tested: 00673 - Are the user allowed to change the field? 00674 - Is the field uid/pid (which are already set) 00675 - perms-fields for pages-table, then do special things... 00676 - If the field is nothing of the above and the field is configured in TCA, the fieldvalues are evaluated by ->checkValue 00677 00678 If everything is OK, the field is entered into $fieldArray[] 00679 */ 00680 foreach($incomingFieldArray as $field => $fieldValue) { 00681 if (!in_array($table.'-'.$field, $this->exclude_array) && !$this->data_disableFields[$table][$id][$field]) { // The field must be editable. 00682 00683 // Checking language: 00684 $languageDeny = $TCA[$table]['ctrl']['languageField'] && !strcmp($TCA[$table]['ctrl']['languageField'], $field) && !$this->BE_USER->checkLanguageAccess($fieldValue); 00685 00686 if (!$languageDeny) { 00687 // Stripping slashes - will probably be removed the day $this->stripslashes_values is removed as an option... 00688 if ($this->stripslashes_values) { 00689 if (is_array($fieldValue)) { 00690 t3lib_div::stripSlashesOnArray($fieldValue); 00691 } else $fieldValue = stripslashes($fieldValue); 00692 } 00693 00694 switch ($field) { 00695 case 'uid': 00696 case 'pid': 00697 // Nothing happens, already set 00698 break; 00699 case 'perms_userid': 00700 case 'perms_groupid': 00701 case 'perms_user': 00702 case 'perms_group': 00703 case 'perms_everybody': 00704 // Permissions can be edited by the owner or the administrator 00705 if ($table=='pages' && ($this->admin || $status=='new' || $this->pageInfo($id,'perms_userid')==$this->userid) ) { 00706 $value=intval($fieldValue); 00707 switch($field) { 00708 case 'perms_userid': 00709 $fieldArray[$field]=$value; 00710 break; 00711 case 'perms_groupid': 00712 $fieldArray[$field]=$value; 00713 break; 00714 default: 00715 if ($value>=0 && $value<pow(2,5)) { 00716 $fieldArray[$field]=$value; 00717 } 00718 break; 00719 } 00720 } 00721 break; 00722 case 't3ver_oid': 00723 case 't3ver_id': 00724 // t3ver_label is not here because it CAN be edited as a regular field! 00725 break; 00726 default: 00727 if (isset($TCA[$table]['columns'][$field])) { 00728 // Evaluating the value. 00729 $res = $this->checkValue($table,$field,$fieldValue,$id,$status,$realPid,$tscPID); 00730 if (isset($res['value'])) { 00731 $fieldArray[$field]=$res['value']; 00732 00733 // Add the value of the original record to the diff-storage content: 00734 if ($TCA[$table]['ctrl']['transOrigDiffSourceField']) { 00735 $originalLanguage_diffStorage[$field] = $originalLanguageRecord[$field]; 00736 $diffStorageFlag = TRUE; 00737 } 00738 } 00739 } 00740 00741 00742 break; 00743 } 00744 } // Checking language. 00745 } // Check exclude fields / disabled fields... 00746 } 00747 00748 // Add diff-storage information: 00749 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... 00750 $fieldArray[$TCA[$table]['ctrl']['transOrigDiffSourceField']] = serialize($originalLanguage_diffStorage); 00751 } 00752 00753 // Checking for RTE-transformations of fields: 00754 $types_fieldConfig = t3lib_BEfunc::getTCAtypes($table,$currentRecord); 00755 $theTypeString = t3lib_BEfunc::getTCAtypeValue($table,$currentRecord); 00756 if (is_array($types_fieldConfig)) { 00757 reset($types_fieldConfig); 00758 while(list(,$vconf) = each($types_fieldConfig)) { 00759 // Write file configuration: 00760 $eFile = t3lib_parsehtml_proc::evalWriteFile($vconf['spec']['static_write'],array_merge($currentRecord,$fieldArray)); // inserted array_merge($currentRecord,$fieldArray) 170502 00761 00762 // RTE transformations: 00763 if (!$this->dontProcessTransformations) { 00764 if (isset($fieldArray[$vconf['field']])) { 00765 // Look for transformation flag: 00766 switch((string)$incomingFieldArray['_TRANSFORM_'.$vconf['field']]) { 00767 case 'RTE': 00768 $RTEsetup = $this->BE_USER->getTSConfig('RTE',t3lib_BEfunc::getPagesTSconfig($tscPID)); 00769 $thisConfig = t3lib_BEfunc::RTEsetup($RTEsetup['properties'],$table,$vconf['field'],$theTypeString); 00770 00771 // Set alternative relative path for RTE images/links: 00772 $RTErelPath = is_array($eFile) ? dirname($eFile['relEditFile']) : ''; 00773 00774 // Get RTE object, draw form and set flag: 00775 $RTEobj = &t3lib_BEfunc::RTEgetObj(); 00776 if (is_object($RTEobj)) { 00777 $fieldArray[$vconf['field']] = $RTEobj->transformContent('db',$fieldArray[$vconf['field']],$table,$vconf['field'],$currentRecord,$vconf['spec'],$thisConfig,$RTErelPath,$currentRecord['pid']); 00778 } else { 00779 debug('NO RTE OBJECT FOUND!'); 00780 } 00781 break; 00782 } 00783 } 00784 } 00785 00786 // Write file configuration: 00787 if (is_array($eFile)) { 00788 $mixedRec = array_merge($currentRecord,$fieldArray); 00789 $SW_fileContent = t3lib_div::getUrl($eFile['editFile']); 00790 $parseHTML = t3lib_div::makeInstance('t3lib_parsehtml_proc'); 00791 $parseHTML->init('',''); 00792 00793 $eFileMarker = $eFile['markerField']&&trim($mixedRec[$eFile['markerField']]) ? trim($mixedRec[$eFile['markerField']]) : '###TYPO3_STATICFILE_EDIT###'; 00794 $insertContent = str_replace($eFileMarker,'',$mixedRec[$eFile['contentField']]); // must replace the marker if present in content! 00795 00796 $SW_fileNewContent = $parseHTML->substituteSubpart($SW_fileContent, $eFileMarker, chr(10).$insertContent.chr(10), 1, 1); 00797 t3lib_div::writeFile($eFile['editFile'],$SW_fileNewContent); 00798 00799 // Write status: 00800 if (!strstr($id,'NEW') && $eFile['statusField']) { 00801 $GLOBALS['TYPO3_DB']->exec_UPDATEquery( 00802 $table, 00803 'uid='.intval($id), 00804 array( 00805 $eFile['statusField'] => $eFile['relEditFile'].' updated '.date('d-m-Y H:i:s').', bytes '.strlen($mixedRec[$eFile['contentField']]) 00806 ) 00807 ); 00808 } 00809 } elseif ($eFile && is_string($eFile)) { 00810 $this->log($insertTable,$id,2,0,1,"Write-file error: '%s'",13,array($eFile),$realPid); 00811 } 00812 } 00813 } 00814 // Return fieldArray 00815 return $fieldArray; 00816 } 00817 00826 function checkModifyAccessList($table) { 00827 $res = ($this->admin || (!$this->tableAdminOnly($table) && t3lib_div::inList($this->BE_USER->groupData['tables_modify'],$table))); 00828 return $res; 00829 } 00830 00838 function isRecordInWebMount($table,$id) { 00839 if (!isset($this->isRecordInWebMount_Cache[$table.':'.$id])) { 00840 $recP=$this->getRecordProperties($table,$id); 00841 $this->isRecordInWebMount_Cache[$table.':'.$id]=$this->isInWebMount($recP['event_pid']); 00842 } 00843 return $this->isRecordInWebMount_Cache[$table.':'.$id]; 00844 } 00845 00852 function isInWebMount($pid) { 00853 if (!isset($this->isInWebMount_Cache[$pid])) { 00854 $this->isInWebMount_Cache[$pid]=$this->BE_USER->isInWebMount($pid); 00855 } 00856 //debug($this->isInWebMount_Cache); 00857 return $this->isInWebMount_Cache[$pid]; 00858 } 00859 00869 function checkRecordUpdateAccess($table,$id) { 00870 global $TCA; 00871 $res = 0; 00872 if ($TCA[$table] && intval($id)>0) { 00873 if (isset($this->recUpdateAccessCache[$table][$id])) { // If information is cached, return it 00874 return $this->recUpdateAccessCache[$table][$id]; 00875 // Check if record exists and 1) if 'pages' the page may be edited, 2) if page-content the page allows for editing 00876 } elseif ($this->doesRecordExist($table,$id,'edit')) { 00877 $res = 1; 00878 } 00879 $this->recUpdateAccessCache[$table][$id]=$res; // Cache the result 00880 } 00881 return $res; 00882 } 00883 00894 function checkRecordInsertAccess($insertTable,$pid,$action=1) { 00895 global $TCA; 00896 $res = 0; 00897 $pid = intval($pid); 00898 if ($pid>=0) { 00899 if (isset($this->recInsertAccessCache[$insertTable][$pid])) { // If information is cached, return it 00900 return $this->recInsertAccessCache[$insertTable][$pid]; 00901 } else { 00902 // 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 00903 if ( (!$pid && $this->admin) || $this->doesRecordExist('pages',$pid,($insertTable=='pages'?$this->pMap['new']:$this->pMap['editcontent'])) ) { // Check permissions 00904 if ($this->isTableAllowedForThisPage($pid, $insertTable)) { 00905 $res = 1; 00906 $this->recInsertAccessCache[$insertTable][$pid]=$res; // Cache the result 00907 } else { 00908 $propArr = $this->getRecordProperties('pages',$pid); 00909 $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']); 00910 } 00911 } else { 00912 $propArr = $this->getRecordProperties('pages',$pid); 00913 $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']); 00914 } 00915 } 00916 } 00917 return $res; 00918 } 00919 00930 function isTableAllowedForThisPage($page_uid, $checkTable) { 00931 global $TCA, $PAGES_TYPES; 00932 $page_uid = intval($page_uid); 00933 00934 // 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. 00935 if (($TCA[$checkTable]['ctrl']['rootLevel'] xor !$page_uid) && $TCA[$checkTable]['ctrl']['rootLevel']!=-1 && $checkTable!='pages') { 00936 return false; 00937 } 00938 00939 // Check root-level 00940 if (!$page_uid) { 00941 if ($this->admin) { 00942 return true; 00943 } 00944 } else { 00945 // Check non-root-level 00946 $doktype = $this->pageInfo($page_uid,'doktype'); 00947 $allowedTableList = isset($PAGES_TYPES[$doktype]['allowedTables']) ? $PAGES_TYPES[$doktype]['allowedTables'] : $PAGES_TYPES['default']['allowedTables']; 00948 $allowedArray = t3lib_div::trimExplode(',',$allowedTableList,1); 00949 if (strstr($allowedTableList,'*') || in_array($checkTable,$allowedArray)) { // If all tables or the table is listed as a allowed type, return true 00950 return true; 00951 } 00952 } 00953 } 00954 00965 function doesRecordExist($table,$id,$perms) { 00966 global $TCA; 00967 00968 $res = 0; 00969 $id = intval($id); 00970 00971 // Processing the incoming $perms (from possible string to integer that can be AND'ed) 00972 if (!t3lib_div::testInt($perms)) { 00973 if ($table!='pages') { 00974 switch($perms) { 00975 case 'edit': 00976 case 'delete': 00977 case 'new': 00978 $perms = 'editcontent'; // This holds it all in case the record is not page!! 00979 break; 00980 } 00981 } 00982 $perms = intval($this->pMap[$perms]); 00983 } else { 00984 $perms = intval($perms); 00985 } 00986 00987 if (!$perms) {debug('Internal ERROR: no permissions to check for non-admin user.');} 00988 00989 // For all tables: Check if record exists: 00990 // Notice: If $perms are 0 (zero) no perms-clause is added! 00991 if (is_array($TCA[$table]) && $id>0 && ($this->isRecordInWebMount($table,$id) || $this->admin)) { 00992 if ($table != 'pages') { 00993 00994 // Find record without checking page: 00995 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid', $table, 'uid='.intval($id).$this->deleteClause($table)); 00996 $output = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres); 00997 t3lib_BEfunc::fixVersioningPid($table,$output); 00998 00999 // If record found, check page as well: 01000 if (is_array($output)) { 01001 01002 // Looking up the page for record: 01003 $mres = $this->doesRecordExist_pageLookUp($output['pid'], $perms); 01004 $pageRec = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres); 01005 01006 // 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): 01007 if (is_array($pageRec) || (!$output['pid'] && $this->admin)) { 01008 return TRUE; 01009 } 01010 } 01011 return FALSE; 01012 } else { 01013 $mres = $this->doesRecordExist_pageLookUp($id, $perms); 01014 return $GLOBALS['TYPO3_DB']->sql_num_rows($mres); 01015 } 01016 } 01017 } 01018 01028 function doesRecordExist_pageLookUp($id, $perms) { 01029 global $TCA; 01030 01031 return $GLOBALS['TYPO3_DB']->exec_SELECTquery( 01032 'uid', 01033 'pages', 01034 'uid='.intval($id). 01035 $this->deleteClause('pages'). 01036 ($perms && !$this->admin ? ' AND '.$this->BE_USER->getPagePermsClause($perms) : ''). 01037 (!$this->admin && $TCA['pages']['ctrl']['editlock'] && ($perms & (2+4+16)) ? ' AND '.$TCA['pages']['ctrl']['editlock'].'=0':'') // admin users don't need check 01038 ); 01039 } 01040 01054 function doesBranchExist($inList,$pid,$perms, $recurse) { 01055 global $TCA; 01056 $pid = intval($pid); 01057 $perms = intval($perms); 01058 if ($pid>=0) { 01059 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 01060 'uid, perms_userid, perms_groupid, perms_user, perms_group, perms_everybody', 01061 'pages', 01062 'pid='.intval($pid).$this->deleteClause('pages'), 01063 '', 01064 'sorting' 01065 ); 01066 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) { 01067 if ($this->admin || $this->BE_USER->doesUserHaveAccess($row,$perms)) { // IF admin, then it's OK 01068 $inList.=$row['uid'].','; 01069 if ($recurse) { // Follow the subpages recursively... 01070 $inList = $this->doesBranchExist($inList, $row['uid'], $perms, $recurse); 01071 if ($inList == -1) {return -1;} // No permissions somewhere in the branch 01072 } 01073 } else { 01074 return -1; // No permissions 01075 } 01076 } 01077 } 01078 return $inList; 01079 } 01080 01089 function pageInfo($id,$field) { 01090 if (!isset($this->pageCache[$id])) { 01091 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'uid='.intval($id)); 01092 if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) { 01093 $this->pageCache[$id] = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res); 01094 } 01095 $GLOBALS['TYPO3_DB']->sql_free_result($res); 01096 } 01097 return $this->pageCache[$id][$field]; 01098 } 01099 01109 function recordInfo($table,$id,$fieldList) { 01110 global $TCA; 01111 if (is_array($TCA[$table])) { 01112 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fieldList, $table, 'uid='.intval($id)); 01113 if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) { 01114 return $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res); 01115 } 01116 } 01117 } 01118 01126 function getRecordProperties($table,$id) { 01127 $row = ($table=='pages' && !$id) ? array('title'=>'[root-level]', 'uid' => 0, 'pid' => 0) :$this->recordInfo($table,$id,'*'); 01128 t3lib_BEfunc::fixVersioningPid($table,$row); 01129 return $this->getRecordPropertiesFromRow($table,$row); 01130 } 01131 01139 function getRecordPropertiesFromRow($table,$row) { 01140 global $TCA; 01141 if ($TCA[$table]) { 01142 $out = array( 01143 'header' => $row[$TCA[$table]['ctrl']['label']], 01144 'pid' => $row['pid'], 01145 'event_pid' => ($table=='pages'?$row['uid']:$row['pid']) 01146 ); 01147 return $out; 01148 } 01149 } 01150 01158 function setTSconfigPermissions($fieldArray,$TSConfig_p) { 01159 if (strcmp($TSConfig_p['userid'],'')) $fieldArray['perms_userid']=intval($TSConfig_p['userid']); 01160 if (strcmp($TSConfig_p['groupid'],'')) $fieldArray['perms_groupid']=intval($TSConfig_p['groupid']); 01161 if (strcmp($TSConfig_p['user'],'')) $fieldArray['perms_user']=t3lib_div::testInt($TSConfig_p['user']) ? $TSConfig_p['user'] : $this->assemblePermissions($TSConfig_p['user']); 01162 if (strcmp($TSConfig_p['group'],'')) $fieldArray['perms_group']=t3lib_div::testInt($TSConfig_p['group']) ? $TSConfig_p['group'] : $this->assemblePermissions($TSConfig_p['group']); 01163 if (strcmp($TSConfig_p['everybody'],'')) $fieldArray['perms_everybody']=t3lib_div::testInt($TSConfig_p['everybody']) ? $TSConfig_p['everybody'] : $this->assemblePermissions($TSConfig_p['everybody']); 01164 01165 return $fieldArray; 01166 } 01167 01174 function newFieldArray($table) { 01175 global $TCA; 01176 t3lib_div::loadTCA($table); 01177 $fieldArray=Array(); 01178 if (is_array($TCA[$table]['columns'])) { 01179 reset ($TCA[$table]['columns']); 01180 while (list($field,$content)=each($TCA[$table]['columns'])) { 01181 if (isset($this->defaultValues[$table][$field])) { 01182 $fieldArray[$field] = $this->defaultValues[$table][$field]; 01183 } elseif (isset($content['config']['default'])) { 01184 $fieldArray[$field] = $content['config']['default']; 01185 } 01186 } 01187 } 01188 if ($table=='pages') { // Set default permissions for a page. 01189 $fieldArray['perms_userid'] = $this->userid; 01190 $fieldArray['perms_groupid'] = intval($this->BE_USER->firstMainGroup); 01191 $fieldArray['perms_user'] = $this->assemblePermissions($this->defaultPermissions['user']); 01192 $fieldArray['perms_group'] = $this->assemblePermissions($this->defaultPermissions['group']); 01193 $fieldArray['perms_everybody'] = $this->assemblePermissions($this->defaultPermissions['everybody']); 01194 } 01195 return $fieldArray; 01196 } 01197 01205 function overrideFieldArray($table,$data) { 01206 if (is_array($this->overrideValues[$table])) { 01207 $data = array_merge($data,$this->overrideValues[$table]); // Candidate for t3lib_div::array_merge() if integer-keys will some day make trouble... 01208 } 01209 return $data; 01210 } 01211 01218 function assemblePermissions($string) { 01219 $keyArr = t3lib_div::trimExplode(',',$string,1); 01220 $value=0; 01221 while(list(,$key)=each($keyArr)) { 01222 if ($key && isset($this->pMap[$key])) { 01223 $value |= $this->pMap[$key]; 01224 } 01225 } 01226 return $value; 01227 } 01228 01229 01230 01231 01232 01233 01234 01235 01236 01237 01238 01239 01240 01241 01242 01243 01244 01245 01246 01247 01248 /********************************************* 01249 * 01250 * Evaluation of input values 01251 * 01252 ********************************************/ 01253 01268 function checkValue($table,$field,$value,$id,$status,$realPid,$tscPID) { 01269 global $TCA, $PAGES_TYPES; 01270 t3lib_div::loadTCA($table); 01271 01272 $res = Array(); // result array 01273 $recFID = $table.':'.$id.':'.$field; 01274 01275 // Processing special case of field pages.doktype 01276 if ($table=='pages' && $field=='doktype') { 01277 // If the user may not use this specific doktype, we issue a warning 01278 if (! ($this->admin || t3lib_div::inList($this->BE_USER->groupData['pagetypes_select'],$value))) { 01279 $propArr = $this->getRecordProperties($table,$id); 01280 $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']); 01281 return $res; 01282 }; 01283 if ($status=='update') { 01284 // This checks 1) if we should check for disallowed tables and 2) if there are records from disallowed tables on the current page 01285 $onlyAllowedTables = isset($PAGES_TYPES[$value]['onlyAllowedTables']) ? $PAGES_TYPES[$value]['onlyAllowedTables'] : $PAGES_TYPES['default']['onlyAllowedTables']; 01286 if ($onlyAllowedTables) { 01287 $theWrongTables = $this->doesPageHaveUnallowedTables($id,$value); 01288 if ($theWrongTables) { 01289 $propArr = $this->getRecordProperties($table,$id); 01290 $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']); 01291 return $res; 01292 } 01293 } 01294 } 01295 } 01296 01297 // Get current value: 01298 $curValueRec = $this->recordInfo($table,$id,$field); 01299 $curValue = $curValueRec[$field]; 01300 01301 // Getting config for the field 01302 $tcaFieldConf = $TCA[$table]['columns'][$field]['config']; 01303 01304 // Preform processing: 01305 $res = $this->checkValue_SW($res,$value,$tcaFieldConf,$table,$id,$curValue,$status,$realPid,$recFID,$field,$this->uploadedFileArray[$table][$id][$field],$tscPID); 01306 01307 return $res; 01308 } 01309 01328 function checkValue_SW($res,$value,$tcaFieldConf,$table,$id,$curValue,$status,$realPid,$recFID,$field,$uploadedFiles,$tscPID) { 01329 01330 $PP = array($table,$id,$curValue,$status,$realPid,$recFID,$tscPID); 01331 01332 switch ($tcaFieldConf['type']) { 01333 case 'text': 01334 case 'passthrough': 01335 case 'user': 01336 $res['value'] = $value; 01337 break; 01338 case 'input': 01339 $res = $this->checkValue_input($res,$value,$tcaFieldConf,$PP,$field); 01340 break; 01341 case 'check': 01342 $res = $this->checkValue_check($res,$value,$tcaFieldConf,$PP); 01343 break; 01344 case 'radio': 01345 $res = $this->checkValue_radio($res,$value,$tcaFieldConf,$PP); 01346 break; 01347 case 'group': 01348 case 'select': 01349 $res = $this->checkValue_group_select($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field); 01350 break; 01351 case 'flex': 01352 if ($field) { // FlexForms are only allowed for real fields. 01353 $res = $this->checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field); 01354 } 01355 break; 01356 default: 01357 #debug(array($tcaFieldConf,$res,$value),'NON existing field type:'); 01358 break; 01359 } 01360 01361 return $res; 01362 } 01363 01374 function checkValue_input($res,$value,$tcaFieldConf,$PP,$field='') { 01375 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP; 01376 01377 // Secures the string-length to be less than max. Will probably make problems with multi-byte strings! 01378 if (intval($tcaFieldConf['max'])>0) {$value = substr($value,0,intval($tcaFieldConf['max']));} 01379 01380 // Checking range of value: 01381 if ($tcaFieldConf['range'] && $value!=$tcaFieldConf['checkbox']) { // If value is not set to the allowed checkbox-value then it is checked against the ranges 01382 if (isset($tcaFieldConf['range']['upper'])&&$value>$tcaFieldConf['range']['upper']) {$value=$tcaFieldConf['range']['upper'];} 01383 if (isset($tcaFieldConf['range']['lower'])&&$value<$tcaFieldConf['range']['lower']) {$value=$tcaFieldConf['range']['lower'];} 01384 } 01385 01386 // Process evaluation settings: 01387 $evalCodesArray = t3lib_div::trimExplode(',',$tcaFieldConf['eval'],1); 01388 $res = $this->checkValue_input_Eval($value,$evalCodesArray,$tcaFieldConf['is_in']); 01389 01390 // Process UNIQUE settings: 01391 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... 01392 if ($res['value'] && in_array('uniqueInPid',$evalCodesArray)) { 01393 $res['value'] = $this->getUnique($table,$field,$res['value'],$id,$realPid); 01394 } 01395 if ($res['value'] && in_array('unique',$evalCodesArray)) { 01396 $res['value'] = $this->getUnique($table,$field,$res['value'],$id); 01397 } 01398 } 01399 01400 return $res; 01401 } 01402 01412 function checkValue_check($res,$value,$tcaFieldConf,$PP) { 01413 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP; 01414 01415 $itemC = count($tcaFieldConf['items']); 01416 if (!$itemC) {$itemC=1;} 01417 $maxV = pow(2,$itemC); 01418 01419 if ($value<0) {$value=0;} 01420 if ($value>$maxV) {$value=$maxV;} 01421 $res['value'] = $value; 01422 01423 return $res; 01424 } 01425 01435 function checkValue_radio($res,$value,$tcaFieldConf,$PP) { 01436 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP; 01437 01438 if (is_array($tcaFieldConf['items'])) { 01439 foreach($tcaFieldConf['items'] as $set) { 01440 if (!strcmp($set[1],$value)) { 01441 $res['value'] = $value; 01442 break; 01443 } 01444 } 01445 } 01446 01447 return $res; 01448 } 01449 01461 function checkValue_group_select($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field) { 01462 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP; 01463 01464 // Detecting if value send is an array and if so, implode it around a comma: 01465 if (is_array($value)) { 01466 $value = implode(',',$value); 01467 } 01468 01469 // This converts all occurencies of '{' 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. 01470 // Anyways, this should NOT disturb anything else: 01471 $value = $this->convNumEntityToByteValue($value); 01472 01473 // When values are send as group or select they come as comma-separated values which are exploded by this function: 01474 $valueArray = $this->checkValue_group_select_explodeSelectGroupValue($value); 01475 01476 // If not multiple is set, then remove duplicates: 01477 if (!$tcaFieldConf['multiple']) { 01478 $valueArray = array_unique($valueArray); 01479 } 01480 01481 // This could be a good spot for parsing the array through a validation-function which checks if the values are allright (except that database references are not in their final form - but that is the point, isn't it?) 01482 // NOTE!!! Must check max-items of files before the later check because that check would just leave out filenames if there are too many!! 01483 01484 // Checking for select / authMode, removing elements from $valueArray if any of them is not allowed! 01485 if ($tcaFieldConf['type']=='select' && $tcaFieldConf['authMode']) { 01486 $preCount = count($valueArray); 01487 foreach($valueArray as $kk => $vv) { 01488 if (!$this->BE_USER->checkAuthMode($table,$field,$vv,$tcaFieldConf['authMode'])) { 01489 unset($valueArray[$kk]); 01490 } 01491 } 01492 01493 // 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. 01494 if ($preCount && !count($valueArray)) { 01495 return array(); 01496 } 01497 } 01498 01499 // For group types: 01500 if ($tcaFieldConf['type']=='group') { 01501 switch($tcaFieldConf['internal_type']) { 01502 case 'file': 01503 $valueArray = $this->checkValue_group_select_file( 01504 $valueArray, 01505 $tcaFieldConf, 01506 $curValue, 01507 $uploadedFiles, 01508 $status, 01509 $table, 01510 $id, 01511 $recFID 01512 ); 01513 break; 01514 case 'db': 01515 $valueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'group'); 01516 break; 01517 } 01518 } 01519 // For select types which has a foreign table attached: 01520 if ($tcaFieldConf['type']=='select' && $tcaFieldConf['foreign_table']) { 01521 $valueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'select'); 01522 } 01523 01524 // 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... 01525 01526 // Checking the number of items, that it is correct. 01527 // If files, there MUST NOT be too many files in the list at this point, so check that prior to this code. 01528 $valueArrayC = count($valueArray); 01529 $minI = isset($tcaFieldConf['minitems']) ? intval($tcaFieldConf['minitems']):0; 01530 01531 // 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. 01532 $maxI = isset($tcaFieldConf['maxitems']) ? intval($tcaFieldConf['maxitems']):1; 01533 if ($valueArrayC > $maxI) {$valueArrayC=$maxI;} // Checking for not too many elements 01534 01535 // Dumping array to list 01536 $newVal=array(); 01537 foreach($valueArray as $nextVal) { 01538 if ($valueArrayC==0) {break;} 01539 $valueArrayC--; 01540 $newVal[]=$nextVal; 01541 } 01542 $res['value'] = implode(',',$newVal); 01543 01544 return $res; 01545 } 01546 01561 function checkValue_group_select_file($valueArray,$tcaFieldConf,$curValue,$uploadedFileArray,$status,$table,$id,$recFID) { 01562 01563 // If any files are uploaded: 01564 if (is_array($uploadedFileArray) && 01565 $uploadedFileArray['name'] && 01566 strcmp($uploadedFileArray['tmp_name'],'none')) { 01567 $valueArray[]=$uploadedFileArray['tmp_name']; 01568 $this->alternativeFileName[$uploadedFileArray['tmp_name']] = $uploadedFileArray['name']; 01569 } 01570 01571 // Creating fileFunc object. 01572 if (!$this->fileFunc) { 01573 $this->fileFunc = t3lib_div::makeInstance('t3lib_basicFileFunctions'); 01574 $this->include_filefunctions=1; 01575 } 01576 // Setting permitted extensions. 01577 $all_files = Array(); 01578 $all_files['webspace']['allow'] = $tcaFieldConf['allowed']; 01579 $all_files['webspace']['deny'] = $tcaFieldConf['disallowed'] ? $tcaFieldConf['disallowed'] : '*'; 01580 $all_files['ftpspace'] = $all_files['webspace']; 01581 $this->fileFunc->init('', $all_files); 01582 01583 // If there is an upload folder defined: 01584 if ($tcaFieldConf['uploadfolder']) { 01585 // For logging.. 01586 $propArr = $this->getRecordProperties($table,$id); 01587 01588 // Get destrination path: 01589 $dest = $this->destPathFromUploadFolder($tcaFieldConf['uploadfolder']); 01590 01591 // If we are updating: 01592 if ($status=='update') { 01593 01594 // Finding the CURRENT files listed, either from MM or from the current record. 01595 $theFileValues=array(); 01596 if ($tcaFieldConf['MM']) { // If MM relations for the files also! 01597 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup'); 01598 $dbAnalysis->start('','files',$tcaFieldConf['MM'],$id); 01599 reset($dbAnalysis->itemArray); 01600 while (list($somekey,$someval)=each($dbAnalysis->itemArray)) { 01601 if ($someval['id']) { 01602 $theFileValues[]=$someval['id']; 01603 } 01604 } 01605 } else { 01606 $theFileValues=t3lib_div::trimExplode(',',$curValue,1); 01607 } 01608 01609 // DELETE files: If existing files were found, traverse those and register files for deletion which has been removed: 01610 if (count($theFileValues)) { 01611 // 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!) 01612 foreach($valueArray as $key => $theFile) { 01613 if ($theFile && !strstr(t3lib_div::fixWindowsFilePath($theFile),'/')) { 01614 $theFileValues = t3lib_div::removeArrayEntryByValue($theFileValues,$theFile); 01615 } 01616 } 01617 01618 // This array contains the filenames in the uploadfolder that should be deleted: 01619 foreach($theFileValues as $key => $theFile) { 01620 $theFile = trim($theFile); 01621 if (@is_file($dest.'/'.$theFile)) { 01622 $this->removeFilesStore[]=$dest.'/'.$theFile; 01623 } elseif ($theFile) { 01624 $this->log($table,$id,5,0,1,"Could not delete file '%s' (does not exist). (%s)",10,array($dest.'/'.$theFile, $recFID),$propArr['event_pid']); 01625 } 01626 } 01627 } 01628 } 01629 01630 // Traverse the submitted values: 01631 foreach($valueArray as $key => $theFile) { 01632 // 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) 01633 if (strstr(t3lib_div::fixWindowsFilePath($theFile),'/')) { 01634 // Init: 01635 $maxSize = intval($tcaFieldConf['max_size']); 01636 $cmd=''; 01637 $theDestFile=''; // Must be cleared. Else a faulty fileref may be inserted if the below code returns an error!! (Change: 22/12/2000) 01638 01639 // Check various things before copying file: 01640 if (@is_dir($dest) && (@is_file($theFile) || @is_uploaded_file($theFile))) { // File and destination must exist 01641 01642 // Finding size. For safe_mode we have to rely on the size in the upload array if the file is uploaded. 01643 if (is_uploaded_file($theFile) && $theFile==$uploadedFileArray['tmp_name']) { 01644 $fileSize = $uploadedFileArray['size']; 01645 } else { 01646 $fileSize = filesize($theFile); 01647 } 01648 01649 if (!$maxSize || $fileSize<=($maxSize*1024)) { // Check file size: 01650 // Prepare filename: 01651 $theEndFileName = isset($this->alternativeFileName[$theFile]) ? $this->alternativeFileName[$theFile] : $theFile; 01652 $fI = t3lib_div::split_fileref($theEndFileName); 01653 01654 // Check for allowed extension: 01655 if ($this->fileFunc->checkIfAllowed($fI['fileext'], $dest, $theEndFileName)) { 01656 $theDestFile = $this->fileFunc->getUniqueName($this->fileFunc->cleanFileName($fI['file']), $dest); 01657 01658 // If we have a unique destination filename, then write the file: 01659 if ($theDestFile) { 01660 t3lib_div::upload_copy_move($theFile,$theDestFile); 01661 $this->copiedFileMap[$theFile] = $theDestFile; 01662 clearstatcache(); 01663 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']); 01664 } 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']); 01665 } else $this->log($table,$id,5,0,1,"Fileextension '%s' not allowed. (%s)",12,array($fI['fileext'], $recFID),$propArr['event_pid']); 01666 } 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']); 01667 } 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']); 01668 01669 // If the destination file was created, we will set the new filename in the value array, otherwise unset the entry in the value array! 01670 if (@is_file($theDestFile)) { 01671 $info = t3lib_div::split_fileref($theDestFile); 01672 $valueArray[$key]=$info['file']; // The value is set to the new filename 01673 } else { 01674 unset($valueArray[$key]); // The value is set to the new filename 01675 } 01676 } 01677 } 01678 01679 // 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! 01680 if ($tcaFieldConf['MM']) { 01681 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup'); 01682 $dbAnalysis->tableArray['files']=array(); // dummy 01683 01684 reset($valueArray); 01685 while (list($key,$theFile)=each($valueArray)) { 01686 // explode files 01687 $dbAnalysis->itemArray[]['id']=$theFile; 01688 } 01689 if ($status=='update') { 01690 $dbAnalysis->writeMM($tcaFieldConf['MM'],$id,0); 01691 } else { 01692 $this->dbAnalysisStore[] = array($dbAnalysis, $tcaFieldConf['MM'], $id, 0); // This will be traversed later to execute the actions 01693 } 01694 $cc=count($dbAnalysis->itemArray); 01695 $valueArray = array($cc); 01696 } 01697 } 01698 01699 return $valueArray; 01700 } 01701 01714 function checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field) { 01715 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP; 01716 01717 if (is_array($value)) { 01718 01719 // Get current value array: 01720 $dataStructArray = t3lib_BEfunc::getFlexFormDS($tcaFieldConf,$this->checkValue_currentRecord,$table); 01721 #debug($this->checkValue_currentRecord); 01722 $currentValueArray = t3lib_div::xml2array($curValue); 01723 if (!is_array($currentValueArray)) $currentValueArray = array(); 01724 if (is_array($currentValueArray['meta']['currentLangId'])) unset($currentValueArray['meta']['currentLangId']); // Remove all old meta for languages... 01725 01726 // Evaluation of input values: 01727 $value['data'] = $this->checkValue_flex_procInData($value['data'],$currentValueArray['data'],$uploadedFiles['data'],$dataStructArray,$PP); 01728 01729 // Create XML and convert charsets from input value: 01730 $xmlValue = $this->checkValue_flexArray2Xml($value); 01731 01732 // If we wanted to set UTF fixed: 01733 // $storeInCharset='utf-8'; 01734 // $currentCharset=$GLOBALS['LANG']->charSet; 01735 // $xmlValue = $GLOBALS['LANG']->csConvObj->conv($xmlValue,$currentCharset,$storeInCharset,1); 01736 $storeInCharset=$GLOBALS['LANG']->charSet; 01737 01738 // Merge them together IF they are both arrays: 01739 // 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). 01740 if (is_array($currentValueArray)) { 01741 $arrValue = t3lib_div::xml2array($xmlValue); 01742 $arrValue = t3lib_div::array_merge_recursive_overrule($currentValueArray,$arrValue); 01743 $xmlValue = $this->checkValue_flexArray2Xml($arrValue); 01744 } 01745 01746 // Temporary fix to delete flex form elements: 01747 $deleteCMDs = t3lib_div::_GP('_DELETE_FLEX_FORMdata'); 01748 if (is_array($deleteCMDs[$table][$id][$field]['data'])) { 01749 $arrValue = t3lib_div::xml2array($xmlValue); 01750 $this->_DELETE_FLEX_FORMdata($arrValue['data'],$deleteCMDs[$table][$id][$field]['data']); 01751 $xmlValue = $this->checkValue_flexArray2Xml($arrValue); 01752 } 01753 01754 // Temporary fix to move flex form elements up: 01755 $moveCMDs = t3lib_div::_GP('_MOVEUP_FLEX_FORMdata'); 01756 if (is_array($moveCMDs[$table][$id][$field]['data'])) { 01757 $arrValue = t3lib_div::xml2array($xmlValue); 01758 $this->_MOVE_FLEX_FORMdata($arrValue['data'],$moveCMDs[$table][$id][$field]['data'], 'up'); 01759 $xmlValue = $this->checkValue_flexArray2Xml($arrValue); 01760 } 01761 01762 // Temporary fix to move flex form elements down: 01763 $moveCMDs = t3lib_div::_GP('_MOVEDOWN_FLEX_FORMdata'); 01764 if (is_array($moveCMDs[$table][$id][$field]['data'])) { 01765 $arrValue = t3lib_div::xml2array($xmlValue); 01766 $this->_MOVE_FLEX_FORMdata($arrValue['data'],$moveCMDs[$table][$id][$field]['data'], 'down'); 01767 $xmlValue = $this->checkValue_flexArray2Xml($arrValue); 01768 } 01769 01770 // Create the value XML: 01771 $res['value']=''; 01772 $res['value'].='<?xml version="1.0" encoding="'.$storeInCharset.'" standalone="yes" ?>'.chr(10); 01773 $res['value'].=$xmlValue; 01774 } else { // Passthrough...: 01775 $res['value']=$value; 01776 } 01777 01778 return $res; 01779 } 01780 01787 function checkValue_flexArray2Xml($array) { 01788 $output = t3lib_div::array2xml($array,'',0,'T3FlexForms',4,array('parentTagMap' => array( 01789 /* 'data' => 'sheets', 01790 'sheets' => 'language', 01791 'language' => 'fieldname', 01792 'el' => 'fieldname' */ 01793 ))); 01794 return $output; 01795 } 01796 01804 function _DELETE_FLEX_FORMdata(&$valueArrayToRemoveFrom,$deleteCMDS) { 01805 if (is_array($valueArrayToRemoveFrom) && is_array($deleteCMDS)) { 01806 foreach($deleteCMDS as $key => $value) { 01807 if (is_array($deleteCMDS[$key])) { 01808 $this->_DELETE_FLEX_FORMdata($valueArrayToRemoveFrom[$key],$deleteCMDS[$key]); 01809 } else { 01810 unset($valueArrayToRemoveFrom[$key]); 01811 } 01812 } 01813 } 01814 } 01815 01825 function _MOVE_FLEX_FORMdata(&$valueArrayToMoveIn, $moveCMDS, $direction) { 01826 if (is_array($valueArrayToMoveIn) && is_array($moveCMDS)) { 01827 01828 // Only execute the first move command: 01829 list ($key, $value) = each ($moveCMDS); 01830 01831 if (is_array($moveCMDS[$key])) { 01832 $this->_MOVE_FLEX_FORMdata($valueArrayToMoveIn[$key],$moveCMDS[$key], $direction); 01833 } else { 01834 switch ($direction) { 01835 case 'up': 01836 if ($key > 1) { 01837 $tmpArr = $valueArrayToMoveIn[$key]; 01838 $valueArrayToMoveIn[$key] = $valueArrayToMoveIn[$key-1]; 01839 $valueArrayToMoveIn[$key-1] = $tmpArr; 01840 } 01841 break; 01842 case 'down': 01843 if ($key < count($valueArrayToMoveIn)) { 01844 $tmpArr = $valueArrayToMoveIn[$key]; 01845 $valueArrayToMoveIn[$key] = $valueArrayToMoveIn[$key+1]; 01846 $valueArrayToMoveIn[$key+1] = $tmpArr; 01847 } 01848 break; 01849 } 01850 } 01851 } 01852 } 01853 01854 01855 01856 01857 01858 01859 01860 01861 01862 01863 01864 01865 01866 01867 01868 01869 01870 01871 /********************************************* 01872 * 01873 * Helper functions for evaluation functions. 01874 * 01875 ********************************************/ 01876 01877 01888 function getUnique($table,$field,$value,$id,$newPid=0) { 01889 global $TCA; 01890 01891 // Initialize: 01892 t3lib_div::loadTCA($table); 01893 $whereAdd=''; 01894 $newValue=''; 01895 if (intval($newPid)) { $whereAdd.=' AND pid='.intval($newPid); } else { $whereAdd.=' AND pid>=0'; } // "AND pid>=0" for versioning 01896 $whereAdd.=$this->deleteClause($table); 01897 01898 // If the field is configured in TCA, proceed: 01899 if (is_array($TCA[$table]) && is_array($TCA[$table]['columns'][$field])) { 01900 01901 // Look for a record which might already have the value: 01902 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, $field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($value, $table).' AND uid!='.intval($id).$whereAdd); 01903 $counter = 0; 01904 01905 // For as long as records with the test-value existing, try again (with incremented numbers appended). 01906 while ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) { 01907 $newValue = $value.$counter; 01908 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, $field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($newValue, $table).' AND uid!='.intval($id).$whereAdd); 01909 $counter++; 01910 if ($counter>100) { break; } // At "100" it will give up and accept a duplicate - should probably be fixed to a small hash string instead...! 01911 } 01912 // If the new value is there: 01913 $value = strlen($newValue) ? $newValue : $value; 01914 } 01915 return $value; 01916 } 01917 01926 function checkValue_input_Eval($value,$evalArray,$is_in) { 01927 $res = Array(); 01928 $newValue = $value; 01929 $set = true; 01930 01931 foreach($evalArray as $func) { 01932 switch($func) { 01933 case 'int': 01934 case 'year': 01935 case 'date': 01936 case 'datetime': 01937 case 'time': 01938 case 'timesec': 01939 $value = intval($value); 01940 break; 01941 case 'double2': 01942 $theDec = 0; 01943 for ($a=strlen($value); $a>0; $a--) { 01944 if (substr($value,$a-1,1)=='.' || substr($value,$a-1,1)==',') { 01945 $theDec = substr($value,$a); 01946 $value = substr($value,0,$a-1); 01947 break; 01948 } 01949 } 01950 $theDec = ereg_replace('[^0-9]','',$theDec).'00'; 01951 $value = intval(str_replace(' ','',$value)).'.'.substr($theDec,0,2); 01952 break; 01953 case 'md5': 01954 if (strlen($value)!=32){$set=false;} 01955 break; 01956 case 'trim': 01957 $value = trim($value); 01958 break; 01959 case 'upper': 01960 $value = strtoupper($value); 01961 # $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. 01962 break; 01963 case 'lower': 01964 $value = strtolower($value); 01965 # $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. 01966 break; 01967 case 'required': 01968 if (!$value) {$set=0;} 01969 break; 01970 case 'is_in': 01971 $c=strlen($value); 01972 if ($c) { 01973 $newVal = ''; 01974 for ($a=0;$a<$c;$a++) { 01975 $char = substr($value,$a,1); 01976 if (strstr($is_in,$char)) { 01977 $newVal.=$char; 01978 } 01979 } 01980 $value = $newVal; 01981 } 01982 break; 01983 case 'nospace': 01984 $value = str_replace(' ','',$value); 01985 break; 01986 case 'alpha': 01987 $value = ereg_replace('[^a-zA-Z]','',$value); 01988 break; 01989 case 'num': 01990 $value = ereg_replace('[^0-9]','',$value); 01991 break; 01992 case 'alphanum': 01993 $value = ereg_replace('[^a-zA-Z0-9]','',$value); 01994 break; 01995 case 'alphanum_x': 01996 $value = ereg_replace('[^a-zA-Z0-9_-]','',$value); 01997 break; 01998 } 01999 } 02000 if ($set) {$res['value'] = $value;} 02001 return $res; 02002 } 02003 02014 function checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,$type) { 02015 $tables = $type=='group'?$tcaFieldConf['allowed']:$tcaFieldConf['foreign_table'].','.$tcaFieldConf['neg_foreign_table']; 02016 $prep = $type=='group'?$tcaFieldConf['prepend_tname']:$tcaFieldConf['neg_foreign_table']; 02017 02018 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup'); 02019 $dbAnalysis->registerNonTableValues=$tcaFieldConf['allowNonIdValues'] ? 1 : 0; 02020 $dbAnalysis->start(implode(',',$valueArray),$tables); 02021 02022 if ($tcaFieldConf['MM']) { 02023 if ($status=='update') { 02024 $dbAnalysis->writeMM($tcaFieldConf['MM'],$id,$prep); 02025 } else { 02026 $this->dbAnalysisStore[] = array($dbAnalysis,$tcaFieldConf['MM'],$id,$prep); // This will be traversed later to execute the actions 02027 } 02028 $cc=count($dbAnalysis->itemArray); 02029 $valueArray = array($cc); 02030 } else { 02031 $valueArray = $dbAnalysis->getValueArray($prep); 02032 if ($type=='select' && $prep) { 02033 $valueArray = $dbAnalysis->convertPosNeg($valueArray,$tcaFieldConf['foreign_table'],$tcaFieldConf['neg_foreign_table']); 02034 } 02035 } 02036 02037 // Here we should se if 1) the records exist anymore, 2) which are new and check if the BE_USER has read-access to the new ones. 02038 return $valueArray; 02039 } 02040 02047 function checkValue_group_select_explodeSelectGroupValue($value) { 02048 $valueArray = t3lib_div::trimExplode(',',$value,1); 02049 reset($valueArray); 02050 while(list($key,$newVal)=each($valueArray)) { 02051 $temp=explode('|',$newVal,2); 02052 $valueArray[$key] = str_replace(',','',str_replace('|','',rawurldecode($temp[0]))); 02053 } 02054 return $valueArray; 02055 } 02056 02070 function checkValue_flex_procInData($dataPart,$dataPart_current,$uploadedFiles,$dataStructArray,$pParams,$callBackFunc='') { 02071 #debug(array($dataPart,$dataPart_current,$dataStructArray)); 02072 if (is_array($dataPart)) { 02073 foreach($dataPart as $sKey => $sheetDef) { 02074 list ($dataStruct,$actualSheet) = t3lib_div::resolveSheetDefInDS($dataStructArray,$sKey); 02075 #debug(array($dataStruct,$actualSheet,$sheetDef,$actualSheet,$sKey)); 02076 if (is_array($dataStruct) && $actualSheet==$sKey && is_array($sheetDef)) { 02077 foreach($sheetDef as $lKey => $lData) { 02078 $this->checkValue_flex_procInData_travDS( 02079 $dataPart[$sKey][$lKey], 02080 $dataPart_current[$sKey][$lKey], 02081 $uploadedFiles[$sKey][$lKey], 02082 $dataStruct['ROOT']['el'], 02083 $pParams, 02084 $callBackFunc, 02085 $sKey.'/'.$lKey.'/' 02086 ); 02087 } 02088 } 02089 } 02090 } 02091 02092 return $dataPart; 02093 } 02094 02109 function checkValue_flex_procInData_travDS(&$dataValues,$dataValues_current,$uploadedFiles,$DSelements,$pParams,$callBackFunc,$structurePath) { 02110 if (is_array($DSelements)) { 02111 02112 // For each DS element: 02113 foreach($DSelements as $key => $dsConf) { 02114 02115 // Array/Section: 02116 if ($DSelements[$key]['type']=='array') { 02117 if (is_array($dataValues[$key]['el'])) { 02118 if ($DSelements[$key]['section']) { 02119 foreach($dataValues[$key]['el'] as $ik => $el) { 02120 $theKey = key($el); 02121 if (is_array($dataValues[$key]['el'][$ik][$theKey]['el'])) { 02122 $this->checkValue_flex_procInData_travDS( 02123 $dataValues[$key]['el'][$ik][$theKey]['el'], 02124 $dataValues_current[$key]['el'][$ik][$theKey]['el'], 02125 $uploadedFiles[$key]['el'][$ik][$theKey]['el'], 02126 $DSelements[$key]['el'][$theKey]['el'], 02127 $pParams, 02128 $callBackFunc, 02129 $structurePath.$key.'/el/'.$ik.'/'.$theKey.'/el/' 02130 ); 02131 } 02132 } 02133 } else { 02134 if (!isset($dataValues[$key]['el'])) $dataValues[$key]['el']=array(); 02135 $this->checkValue_flex_procInData_travDS( 02136 $dataValues[$key]['el'], 02137 $dataValues_current[$key]['el'], 02138 $uploadedFiles[$key]['el'], 02139 $DSelements[$key]['el'], 02140 $pParams, 02141 $callBackFunc, 02142 $structurePath.$key.'/el/' 02143 ); 02144 } 02145 } 02146 } else { 02147 if (is_array($dsConf['TCEforms']['config']) && is_array($dataValues[$key])) { 02148 foreach($dataValues[$key] as $vKey => $data) { 02149 02150 if ($callBackFunc) { 02151 if (is_object($this->callBackObj)) { 02152 $res = $this->callBackObj->$callBackFunc( 02153 $pParams, 02154 $dsConf['TCEforms']['config'], 02155 $dataValues[$key][$vKey], 02156 $dataValues_current[$key][$vKey], 02157 $uploadedFiles[$key][$vKey], 02158 $structurePath.$key.'/'.$vKey.'/' 02159 ); 02160 } else { 02161 $res = $this->$callBackFunc( 02162 $pParams, 02163 $dsConf['TCEforms']['config'], 02164 $dataValues[$key][$vKey], 02165 $dataValues_current[$key][$vKey], 02166 $uploadedFiles[$key][$vKey] 02167 ); 02168 } 02169 } else { // Default 02170 list($CVtable,$CVid,$CVcurValue,$CVstatus,$CVrealPid,$CVrecFID,$CVtscPID) = $pParams; 02171 02172 $res = $this->checkValue_SW( 02173 array(), 02174 $dataValues[$key][$vKey], 02175 $dsConf['TCEforms']['config'], 02176 $CVtable, 02177 $CVid, 02178 $dataValues_current[$key][$vKey], 02179 $CVstatus, 02180 $CVrealPid, 02181 $CVrecFID, 02182 '', 02183 $uploadedFiles[$key][$vKey], 02184 array(), 02185 $CVtscPID 02186 ); 02187 02188 // Look for RTE transformation of field: 02189 if ($dataValues[$key]['_TRANSFORM_'.$vKey] == 'RTE' && !$this->dontProcessTransformations) { 02190 02191 // Unsetting trigger field - we absolutely don't want that into the data storage! 02192 unset($dataValues[$key]['_TRANSFORM_'.$vKey]); 02193 02194 if (isset($res['value'])) { 02195 02196 // Calculating/Retrieving some values here: 02197 list(,,$recFieldName) = explode(':', $CVrecFID); 02198 $theTypeString = t3lib_BEfunc::getTCAtypeValue($CVtable,$this->checkValue_currentRecord); 02199 $specConf = t3lib_BEfunc::getSpecConfParts('',$dsConf['TCEforms']['defaultExtras']); 02200 02201 // Find, thisConfig: 02202 $RTEsetup = $this->BE_USER->getTSConfig('RTE',t3lib_BEfunc::getPagesTSconfig($CVtscPID)); 02203 $thisConfig = t3lib_BEfunc::RTEsetup($RTEsetup['properties'],$CVtable,$recFieldName,$theTypeString); 02204 02205 // Get RTE object, draw form and set flag: 02206 $RTEobj = &t3lib_BEfunc::RTEgetObj(); 02207 if (is_object($RTEobj)) { 02208 $res['value'] = $RTEobj->transformContent('db',$res['value'],$CVtable,$recFieldName,$this->checkValue_currentRecord,$specConf,$thisConfig,'',$CVrealPid); 02209 } else { 02210 debug('NO RTE OBJECT FOUND!'); 02211 } 02212 } 02213 } 02214 } 02215 02216 // Adding the value: 02217 if (isset($res['value'])) { 02218 $dataValues[$key][$vKey] = $res['value']; 02219 } 02220 } 02221 } 02222 } 02223 } 02224 } 02225 } 02226 02227 02228 02229 02230 02231 02232 02233 02234 02235 02236 02237 02238 02239 02240 02241 02242 02243 02244 02245 02246 /********************************************* 02247 * 02248 * Storing data to Database Layer 02249 * 02250 ********************************************/ 02251 02252 02262 function updateDB($table,$id,$fieldArray) { 02263 global $TCA; 02264 02265 if (is_array($fieldArray) && is_array($TCA[$table]) && intval($id)) { 02266 unset($fieldArray['uid']); // Do NOT update the UID field, ever! 02267 02268 if (count($fieldArray)) { 02269 02270 // Execute the UPDATE query: 02271 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($id), $fieldArray); 02272 02273 // If succees, do...: 02274 if (!$GLOBALS['TYPO3_DB']->sql_error()) { 02275 if ($this->checkStoredRecords) { 02276 $newRow = $this->checkStoredRecord($table,$id,$fieldArray,2); 02277 } 02278 02279 // Set log entry: 02280 $propArr = $this->getRecordPropertiesFromRow($table,$newRow); 02281 $theLogId = $this->log($table,$id,2,$recpid,0,"Record '%s' (%s) was updated.",10,array($propArr['header'],$table.':'.$id),$propArr['event_pid']); 02282 02283 // Set History data: 02284 $this->setHistory($table,$id,$theLogId); 02285 02286 // Clear cache for relavant pages: 02287 $this->clear_cache($table,$id); 02288 02289 // Unset the pageCache for the id if table was page. 02290 if ($table=='pages') unset($this->pageCache[$id]); 02291 } else { 02292 $this->log($table,$id,2,0,2,"SQL error: '%s' (%s)",12,array($GLOBALS['TYPO3_DB']->sql_error(),$table.':'.$id)); 02293 } 02294 } 02295 } 02296 } 02297 02308 function compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray) { 02309 02310 // Fetch the original record: 02311 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($id)); 02312 $currentRecord = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res); 02313 02314 // If the current record exists (which it should...), begin comparison: 02315 if (is_array($currentRecord)) { 02316 02317 // Read all field types: 02318 $c = 0; 02319 $cRecTypes = array(); 02320 foreach($currentRecord as $col => $val) { 02321 // DBAL 02322 # $cRecTypes[$col] = $GLOBALS['TYPO3_DB']->sql_field_type($table,$col); 02323 $cRecTypes[$col] = $GLOBALS['TYPO3_DB']->sql_field_type($res,$c); 02324 $c++; 02325 } 02326 #debug($cRecTypes); 02327 02328 // Free result: 02329 $GLOBALS['TYPO3_DB']->sql_free_result($res); 02330 02331 // Unset the fields which are similar: 02332 foreach($fieldArray as $col => $val) { 02333 if ( 02334 #!isset($currentRecord[$col]) || // Unset fields which were NOT found in the current record! [Uncommented because NULL fields will not return an entry in the array!] 02335 !strcmp($val,$currentRecord[$col]) || // Unset fields which matched exactly. 02336 ($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. 02337 ) { 02338 unset($fieldArray[$col]); 02339 } else { 02340 $this->historyRecords[$table.':'.$id]['oldRecord'][$col] = $currentRecord[$col]; 02341 $this->historyRecords[$table.':'.$id]['newRecord'][$col] = $fieldArray[$col]; 02342 } 02343 } 02344 } else { // If the current record does not exist this is an error anyways and we just return an empty array here. 02345 $fieldArray = array(); 02346 } 02347 02348 return $fieldArray; 02349 } 02350 02362 function insertDB($table,$id,$fieldArray,$newVersion=FALSE,$suggestedUid=0) { 02363 global $TCA; 02364 02365 if (is_array($fieldArray) && is_array($TCA[$table]) && isset($fieldArray['pid'])) { 02366 unset($fieldArray['uid']); // Do NOT insert the UID field, ever! 02367 02368 if (count($fieldArray)) { 02369 02370 // Check for "suggestedUid". 02371 // This feature is used by the import functionality to force a new record to have a certain UID value. 02372 // This is only recommended for use when the destination server is a passive mirrow of another server. 02373 // As a security measure this feature is available only for Admin Users (for now) 02374 $suggestedUid = intval($suggestedUid); 02375 if ($this->BE_USER->isAdmin() && $suggestedUid && $this->suggestedInsertUids[$table.':'.$suggestedUid]) { 02376 // When the value of ->suggestedInsertUids[...] is "DELETE" it will try to remove the previous record 02377 if ($this->suggestedInsertUids[$table.':'.$suggestedUid]==='DELETE') { 02378 // DELETE: 02379 $GLOBALS['TYPO3_DB']->exec_DELETEquery($table, 'uid='.intval($suggestedUid)); 02380 } 02381 $fieldArray['uid'] = $suggestedUid; 02382 } 02383 02384 // Execute the INSERT query: 02385 $GLOBALS['TYPO3_DB']->exec_INSERTquery($table, $fieldArray); 02386 02387 // If succees, do...: 02388 if (!$GLOBALS['TYPO3_DB']->sql_error()) { 02389 02390 // Set mapping for NEW... -> real uid: 02391 $NEW_id = $id; // the NEW_id now holds the 'NEW....' -id 02392 $id = $GLOBALS['TYPO3_DB']->sql_insert_id(); 02393 $this->substNEWwithIDs[$NEW_id] = $id; 02394 $this->substNEWwithIDs_table[$NEW_id] = $table; 02395 02396 // Checking the record is properly saved and writing to log 02397 if ($this->checkStoredRecords) { 02398 $newRow = $this->checkStoredRecord($table,$id,$fieldArray,1); 02399 } 02400 02401 if ($newVersion) { 02402 $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); 02403 } else { 02404 // Set log entry: 02405 if ($table=='pages') { 02406 $thePositionID = $this->getInterfacePagePositionID($id); 02407 } else { 02408 $thePositionID = 0; 02409 } 02410 $propArr = $this->getRecordPropertiesFromRow($table,$newRow); 02411 $page_propArr = $this->getRecordProperties('pages',$propArr['pid']); 02412 $this->log($table,$id,1,$thePositionID,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); 02413 02414 // Clear cache for relavant pages: 02415 $this->clear_cache($table,$id); 02416 } 02417 } else { 02418 $this->log($table,$id,1,0,2,"SQL error: '%s' (%s)",12,array($GLOBALS['TYPO3_DB']->sql_error(),$table.':'.$id)); 02419 } 02420 } 02421 } 02422 } 02423 02434 function checkStoredRecord($table,$id,$fieldArray,$action) { 02435 global $TCA; 02436 02437 $id = intval($id); 02438 if (is_array($TCA[$table]) && $id) { 02439 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($id)); 02440 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { 02441 // Traverse array of values that was inserted into the database and compare with the actually stored value: 02442 $errorString = array(); 02443 foreach($fieldArray as $key => $value) { 02444 if ($this->checkStoredRecords_loose && !$value && !$row[$key]) { 02445 // Nothing... 02446 } elseif (strcmp($value,$row[$key])) { 02447 // DEBUGGING KFISH 02448 // debug(array("$value != ".$row[$key])); 02449 $errorString[] = $key; 02450 } 02451 } 02452 02453 // Set log message if there were fields with unmatching values: 02454 if (count($errorString)) { 02455 $this->log($table,$id,$action,0,102,'These fields are not properly updated in database: ('.implode(',',$errorString).') Probably value mismatch with fieldtype.'); 02456 } 02457 02458 // Return selected rows: 02459 return $row; 02460 } 02461 $GLOBALS['TYPO3_DB']->sql_free_result($res); 02462 } 02463 } 02464 02470 function dbAnalysisStoreExec() { 02471 reset($this->dbAnalysisStore); 02472 while(list($k,$v)=each($this->dbAnalysisStore)) { 02473 $id = $this->substNEWwithIDs[$v[2]]; 02474 if ($id) { 02475 $v[2] = $id; 02476 $v[0]->writeMM($v[1],$v[2],$v[3]); 02477 } 02478 } 02479 } 02480 02486 function removeRegisteredFiles() { 02487 reset($this->removeFilesStore); 02488 while(list($k,$v)=each($this->removeFilesStore)) { 02489 unlink($v); 02490 // debug($v,1); 02491 } 02492 } 02493 02503 function clear_cache($table,$uid) { 02504 global $TCA, $TYPO3_CONF_VARS; 02505 02506 $uid = intval($uid); 02507 if (is_array($TCA[$table]) && $uid > 0) { 02508 02509 // Get Page TSconfig relavant: 02510 list($tscPID) = t3lib_BEfunc::getTSCpid($table,$uid,''); 02511 $TSConfig = $this->getTCEMAIN_TSconfig($tscPID); 02512 02513 if (!$TSConfig['clearCache_disable']) { 02514 02515 // If table is "pages": 02516 if (t3lib_extMgm::isLoaded('cms')) { 02517 $list_cache = array(); 02518 if ($table=='pages') { 02519 02520 // Builds list of pages on the SAME level as this page (siblings) 02521 $res_tmp = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 02522 'A.pid AS pid, B.uid AS uid', 02523 'pages A, pages B', 02524 'A.uid='.intval($uid).' AND B.pid=A.pid AND B.deleted=0' 02525 ); 02526 02527 $pid_tmp = 0; 02528 while ($row_tmp = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp)) { 02529 $list_cache[] = $row_tmp['uid']; 02530 $pid_tmp = $row_tmp['pid']; 02531 02532 // Add children as well: 02533 if ($TSConfig['clearCache_pageSiblingChildren']) { 02534 $res_tmp2 = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 02535 'uid', 02536 'pages', 02537 'pid='.intval($row_tmp['uid']).' AND deleted=0' 02538 ); 02539 while ($row_tmp2 = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp2)) { 02540 $list_cache[] = $row_tmp2['uid']; 02541 } 02542 } 02543 } 02544 02545 // Finally, add the parent page as well: 02546 $list_cache[] = $pid_tmp; 02547 02548 // Add grand-parent as well: 02549 if ($TSConfig['clearCache_pageGrandParent']) { 02550 $res_tmp = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 02551 'pid', 02552 'pages', 02553 'uid='.intval($pid_tmp) 02554 ); 02555 if ($row_tmp = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp)) { 02556 $list_cache[] = $row_tmp['pid']; 02557 } 02558 } 02559 } else { // For other tables than "pages", delete cache for the records "parent page". 02560 $list_cache[] = intval($this->getPID($table,$uid)); 02561 } 02562 02563 // Call pre-processing function for clearing of cache for page ids: 02564 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval'])) { 02565 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval'] as $funcName) { 02566 $_params = array('pageIdArray' => &$list_cache, 'table' => $table, 'uid' => $uid, 'functionID' => 'clear_cache()'); 02567 // Returns the array of ids to clear, false if nothing should be cleared! Never an empty array! 02568 t3lib_div::callUserFunction($funcName,$_params,$this); 02569 } 02570 } 02571 02572 // Delete cache for selected pages: 02573 if (is_array($list_cache)) { 02574 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')'); 02575 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection', 'page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')'); 02576 } 02577 } 02578 } 02579 02580 // Clear cache for pages entered in TSconfig: 02581 if ($TSConfig['clearCacheCmd']) { 02582 $Commands = t3lib_div::trimExplode(',',strtolower($TSConfig['clearCacheCmd']),1); 02583 $Commands = array_unique($Commands); 02584 foreach($Commands as $cmdPart) { 02585 $this->clear_cacheCmd($cmdPart); 02586 } 02587 } 02588 02589 // Call post processing function for clear-cache: 02590 global $TYPO3_CONF_VARS; 02591 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'])) { 02592 $_params = array('table' => $table,'uid' => $uid,'uid_page' => $uid_page,'TSConfig' => $TSConfig); 02593 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'] as $_funcRef) { 02594 t3lib_div::callUserFunction($_funcRef,$_params,$this); 02595 } 02596 } 02597 } 02598 } 02599 02607 function getPID($table,$uid) { 02608 $res_tmp = $GLOBALS['TYPO3_DB']->exec_SELECTquery('pid', $table, 'uid='.intval($uid)); 02609 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_tmp)) { 02610 return $row['pid']; 02611 } 02612 } 02613 02614 02615 02616 02617 02618 02619 02620 02621 02622 02623 02624 02625 02626 02627 02628 02629 02630 02631 02632 02633 02634 02635 02636 02637 02638 /********************************************* 02639 * 02640 * PROCESSING COMMANDS 02641 * 02642 ********************************************/ 02643 02650 function process_cmdmap() { 02651 global $TCA, $TYPO3_CONF_VARS; 02652 02653 $hookObjectsArr = array(); 02654 if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'])) { 02655 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'] as $classRef) { 02656 $hookObjectsArr[] = &t3lib_div::getUserObj($classRef); 02657 } 02658 } 02659 02660 // Traverse command map: 02661 reset ($this->cmdmap); 02662 while (list($table,) = each($this->cmdmap)) { 02663 02664 // Check if the table may be modified! 02665 $modifyAccessList = $this->checkModifyAccessList($table); 02666 if (!$modifyAccessList) { 02667 $this->log($table,$id,2,0,1,"Attempt to modify table '%s' without permission",1,array($table)); 02668 } 02669 02670 // Check basic permissions and circumstances: 02671 if (isset($TCA[$table]) && !$this->tableReadOnly($table) && is_array($this->cmdmap[$table]) && $modifyAccessList) { 02672 02673 // Traverse the command map: 02674 foreach($this->cmdmap[$table] as $id => $incomingCmdArray) { 02675 if (is_array($incomingCmdArray)) { // have found a command. 02676 02677 // Get command and value (notice, only one command is observed at a time!): 02678 reset($incomingCmdArray); 02679 $command = key($incomingCmdArray); 02680 $value = current($incomingCmdArray); 02681 02682 foreach($hookObjectsArr as $hookObj) { 02683 if (method_exists($hookObj, 'processCmdmap_preProcess')) { 02684 $hookObj->processCmdmap_preProcess($command, $table, $id, $value, $this); 02685 } 02686 } 02687 02688 // Init copyMapping array: 02689 $this->copyMappingArray = Array(); // Must clear this array before call from here to those functions: Contains mapping information between new and old id numbers. 02690 02691 // Branch, based on command 02692 switch ($command) { 02693 case 'move': 02694 $this->moveRecord($table,$id,$value); 02695 break; 02696 case 'copy': 02697 if ($table == 'pages') { 02698 $this->copyPages($id,$value); 02699 } else { 02700 $this->copyRecord($table,$id,$value,1); 02701 } 02702 break; 02703 case 'localize': 02704 $this->copyRecord_localize($table,$id,$value); 02705 break; 02706 case 'version': 02707 switch ((string)$value['action']) { 02708 case 'new': 02709 $this->versionizeTree = t3lib_div::intInRange($value['treeLevels'],-1,4); // Max 4 levels of versioning... 02710 if ($table == 'pages' && $this->versionizeTree>=0) { 02711 $this->versionizePages($id,$value['label']); 02712 } else { 02713 $this->versionizeRecord($table,$id,$value['label']); 02714 } 02715 break; 02716 case 'swap': 02717 $this->version_swap($table,$id,$value['swapWith'],$value['swapContent']); 02718 break; 02719 } 02720 break; 02721 case 'delete': 02722 if ($table == 'pages') { 02723 $this->deletePages($id); 02724 } else { 02725 $this->deleteRecord($table,$id, 0); 02726 } 02727 break; 02728 } 02729 02730 foreach($hookObjectsArr as $hookObj) { 02731 if (method_exists($hookObj, 'processCmdmap_postProcess')) { 02732 $hookObj->processCmdmap_postProcess($command, $table, $id, $value, $this); 02733 } 02734 } 02735 02736 // Merging the copy-array info together for remapping purposes. 02737 $this->copyMappingArray_merged= t3lib_div::array_merge_recursive_overrule($this->copyMappingArray_merged,$this->copyMappingArray); 02738 } 02739 } 02740 } 02741 } 02742 02743 #debug($this->copyMappingArray_merged,'$this->copyMappingArray_merged'); 02744 #debug($this->registerDBList,'$this->registerDBList'); 02745 02746 // Finally, before exit, check if there are ID references to remap. This might be the case if versioning or copying has taken place! 02747 $this->remapListedDBRecords(); 02748 } 02749 02758 function moveRecord($table,$uid,$destPid) { 02759 global $TCA; 02760 02761 // Initialize: 02762 $sortRow = $TCA[$table]['ctrl']['sortby']; 02763 $destPid = intval($destPid); 02764 $origDestPid = $destPid; 02765 02766 if ($TCA[$table]) { 02767 $propArr = $this->getRecordProperties($table,$uid); // Get this before we change the pid (for logging) 02768 $resolvedPid = $this->resolvePid($table,$destPid); // This is the actual pid of the moving. 02769 02770 // 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. 02771 // 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. 02772 if ($table!='pages' || $resolvedPid==$propArr['pid']) { 02773 $mayMoveAccess = $this->checkRecordUpdateAccess($table,$uid); // Edit rights for the record... 02774 } else { 02775 $mayMoveAccess = $this->doesRecordExist($table,$uid,'delete'); 02776 } 02777 02778 // Finding out, if the record may be moved TO another place. Here we check insert-rights (non-pages = edit, pages = new), unless the pages is moved on the same pid, then edit-rights are checked 02779 if ($table!='pages' || $resolvedPid!=$propArr['pid']) { 02780 $mayInsertAccess = $this->checkRecordInsertAccess($table,$resolvedPid,4); // Edit rights for the record... 02781 } else { 02782 $mayInsertAccess = $this->checkRecordUpdateAccess($table,$uid); 02783 } 02784 02785 // Checking if the pid is negativ, 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...) 02786 if ($destPid<0 && !$sortRow) { 02787 $destPid = $resolvedPid; 02788 } 02789 02790 // Timestamp field: 02791 $updateFields = array(); 02792 if ($TCA[$table]['ctrl']['tstamp']) { 02793 $updateFields[$TCA[$table]['ctrl']['tstamp']] = time(); 02794 } 02795 02796 // If moving is allowed, begin the processing: 02797 if ($mayMoveAccess) { 02798 if ($destPid>=0) { // insert as first element on page (where uid = $destPid) 02799 if ($mayInsertAccess) { 02800 if ($table!='pages' || $this->destNotInsideSelf ($destPid,$uid)) { 02801 $this->clear_cache($table,$uid); // clear cache before moving 02802 02803 $updateFields['pid'] = $destPid; // Setting PID 02804 02805 // table is sorted by 'sortby' 02806 if ($sortRow) { 02807 $sortNumber = $this->getSortNumber($table,$uid,$destPid); 02808 $updateFields[$sortRow] = $sortNumber; 02809 } 02810 02811 // Create query for update: 02812 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields); 02813 02814 // Logging... 02815 $newPropArr = $this->getRecordProperties($table,$uid); 02816 $oldpagePropArr = $this->getRecordProperties('pages',$propArr['pid']); 02817 $newpagePropArr = $this->getRecordProperties('pages',$destPid); 02818 02819 if ($destPid!=$propArr['pid']) { 02820 $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 02821 $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 02822 } else { 02823 $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 02824 } 02825 $this->clear_cache($table,$uid); // clear cache after moving 02826 $this->fixUniqueInPid($table,$uid); 02827 // fixCopyAfterDuplFields 02828 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. 02829 } else { 02830 $destPropArr = $this->getRecordProperties('pages',$destPid); 02831 $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']); 02832 } 02833 } 02834 } else { // Put after another record 02835 if ($sortRow) { // table is being sorted 02836 $sortInfo = $this->getSortNumber($table,$uid,$destPid); 02837 $destPid = $sortInfo['pid']; // Setting the destPid to the new pid of the record. 02838 if (is_array($sortInfo)) { // If not an array, there was an error (which is already logged) 02839 if ($mayInsertAccess) { 02840 if ($table!='pages' || $this->destNotInsideSelf($destPid,$uid)) { 02841 $this->clear_cache($table,$uid); // clear cache before moving 02842 02843 // We now update the pid and sortnumber 02844 $updateFields['pid'] = $destPid; 02845 $updateFields[$sortRow] = $sortInfo['sortNumber']; 02846 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields); 02847 02848 // Logging... 02849 if ($table=='pages') { 02850 $thePositionID = $this->getInterfacePagePositionID($uid); 02851 } else { 02852 $thePositionID = 0; 02853 } 02854 $this->log($table,$uid,4,$thePositionID,0,''); 02855 02856 // Logging... 02857 $newPropArr = $this->getRecordProperties($table,$uid); 02858 $oldpagePropArr = $this->getRecordProperties('pages',$propArr['pid']); 02859 if ($destPid!=$propArr['pid']) { 02860 $newpagePropArr = $this->getRecordProperties('pages',$destPid); 02861 $this->log($table,$uid,4,$thePositionID,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 02862 $this->log($table,$uid,4,$thePositionID,0,"Moved record '%s' (%s) from page '%s' (%s)",3,array($propArr['header'],$table.':'.$uid, $oldpagePropArr['header'], $propArr['pid']),$destPid); // Logged to new page 02863 } else { 02864 $this->log($table,$uid,4,$thePositionID,0,"Moved record '%s' (%s) on page '%s' (%s)",4,array($propArr['header'],$table.':'.$uid, $oldpagePropArr['header'], $propArr['pid']),$destPid); // Logged to new page 02865 } 02866 02867 // clear cache after moving 02868 $this->clear_cache($table,$uid); 02869 02870 // fixUniqueInPid 02871 $this->fixUniqueInPid($table,$uid); 02872 02873 // fixCopyAfterDuplFields 02874 if ($origDestPid<0) {$this->fixCopyAfterDuplFields($table,$uid,abs($origDestPid),1);} 02875 } else { 02876 $destPropArr = $this->getRecordProperties('pages',$destPid); 02877 $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']); 02878 } 02879 } 02880 } 02881 } else { 02882 $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']); 02883 } 02884 } 02885 } else { 02886 $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']); 02887 } 02888 } 02889 } 02890 02902 function copyRecord($table,$uid,$destPid,$first=0,$overrideValues=array(),$excludeFields='') { 02903 global $TCA; 02904 02905 $uid = intval($uid); 02906 if ($TCA[$table] && $uid) { 02907 t3lib_div::loadTCA($table); 02908 if ($this->doesRecordExist($table,$uid,'show')) { // This checks if the record can be selected which is all that a copy action requires. 02909 $data = Array(); 02910 02911 $nonFields = array_unique(t3lib_div::trimExplode(',','uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,t3ver_oid,t3ver_id,t3ver_label,'.$excludeFields,1)); 02912 02913 $row = $this->recordInfo($table,$uid,'*'); 02914 if (is_array($row)) { 02915 02916 // Initializing: 02917 $theNewID = uniqid('NEW'); 02918 $enableField = isset($TCA[$table]['ctrl']['enablecolumns']) ? $TCA[$table]['ctrl']['enablecolumns']['disabled'] : ''; 02919 $headerField = $TCA[$table]['ctrl']['label']; 02920 02921 // Getting default data: 02922 $defaultData = $this->newFieldArray($table); 02923 02924 // Getting "copy-after" fields if applicable: 02925 // 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. 02926 $copyAfterFields = $destPid<0 ? $this->fixCopyAfterDuplFields($table,$uid,abs($destPid),0) : array(); 02927 02928 // Page TSconfig related: 02929 $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... 02930 $TSConfig = $this->getTCEMAIN_TSconfig($tscPID); 02931 $tE = $this->getTableEntries($table,$TSConfig); 02932 02933 // Traverse ALL fields of the selected record: 02934 foreach($row as $field => $value) { 02935 if (!in_array($field,$nonFields)) { 02936 02937 // Get TCA configuration for the field: 02938 $conf = $TCA[$table]['columns'][$field]['config']; 02939 02940 // Preparation/Processing of the value: 02941 if ($field=='pid') { // "pid" is hardcoded of course: 02942 $value = $destPid; 02943 } elseif (isset($overrideValues[$field])) { // Override value... 02944 $value = $overrideValues[$field]; 02945 } elseif (isset($copyAfterFields[$field])) { // Copy-after value if available: 02946 $value = $copyAfterFields[$field]; 02947 } elseif ($TCA[$table]['ctrl']['setToDefaultOnCopy'] && t3lib_div::inList($TCA[$table]['ctrl']['setToDefaultOnCopy'],$field)) { // Revert to default for some fields: 02948 $value = $defaultData[$field]; 02949 } else { 02950 // Hide at copy may override: 02951 if ($first && $field==$enableField && $TCA[$table]['ctrl']['hideAtCopy'] && !$this->neverHideAtCopy && !$tE['disableHideAtCopy']) { 02952 $value=1; 02953 } 02954 // Prepend label on copy: 02955 if ($first && $field==$headerField && $TCA[$table]['ctrl']['prependAtCopy'] && !$tE['disablePrependAtCopy']) { 02956 $value = $this->getCopyHeader($table,$this->resolvePid($table,$destPid),$field,$this->clearPrefixFromValue($table,$value),0); 02957 } 02958 // Processing based on the TCA config field type (files, references, flexforms...) 02959 $value = $this->copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf); 02960 } 02961 02962 // Add value to array. 02963 $data[$table][$theNewID][$field] = $value; 02964 } 02965 02966 // Overriding values: 02967 if ($TCA[$table]['ctrl']['editlock']) { 02968 $data[$table][$theNewID][$TCA[$table]['ctrl']['editlock']] = 0; 02969 } 02970 } 02971 02972 // Do the copy by simply submitting the array through TCEmain: 02973 $copyTCE = t3lib_div::makeInstance('t3lib_TCEmain'); 02974 $copyTCE->stripslashes_values = 0; 02975 $copyTCE->copyTree = $this->copyTree; 02976 $copyTCE->cachedTSconfig = $this->cachedTSconfig; // Copy forth the cached TSconfig 02977 $copyTCE->dontProcessTransformations=1; // Transformations should NOT be carried out during copy 02978 // $copyTCE->enableLogging = $table=='pages'?1:0; // If enabled the list-view does not update... 02979 02980 $copyTCE->start($data,'',$this->BE_USER); 02981 $copyTCE->process_datamap(); 02982 02983 // Getting the new UID: 02984 $theNewSQLID = $copyTCE->substNEWwithIDs[$theNewID]; 02985 if ($theNewSQLID) { 02986 $this->copyMappingArray[$table][$uid] = $theNewSQLID; 02987 } 02988 02989 // Copy back the cached TSconfig 02990 $this->cachedTSconfig = $copyTCE->cachedTSconfig; 02991 unset($copyTCE); 02992 } else $this->log($table,$uid,3,0,1,'Attempt to copy record that did not exist!'); 02993 } else $this->log($table,$uid,3,0,1,'Attempt to copy record without permission'); 02994 } 02995 } 02996 03011 function copyRecord_raw($table,$uid,$pid,$overrideArray=array()) { 03012 global $TCA; 03013 03014 $uid = intval($uid); 03015 if ($TCA[$table] && $uid) { 03016 t3lib_div::loadTCA($table); 03017 if ($this->doesRecordExist($table,$uid,'show')) { 03018 03019 // Set up fields which should not be processed. They are still written - just passed through no-questions-asked! 03020 $nonFields = array('uid','pid','t3ver_id','t3ver_oid','t3ver_label','perms_userid','perms_groupid','perms_user','perms_group','perms_everybody'); 03021 03022 // Select main record: 03023 $row = $this->recordInfo($table,$uid,'*'); 03024 if (is_array($row)) { 03025 03026 // Merge in override array. 03027 $row = array_merge($row,$overrideArray); 03028 03029 // Traverse ALL fields of the selected record: 03030 foreach($row as $field => $value) { 03031 if (!in_array($field,$nonFields)) { 03032 03033 // Get TCA configuration for the field: 03034 $conf = $TCA[$table]['columns'][$field]['config']; 03035 if (is_array($conf)) { 03036 // Processing based on the TCA config field type (files, references, flexforms...) 03037 $value = $this->copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf); 03038 } 03039 03040 // Add value to array. 03041 $row[$field] = $value; 03042 } 03043 } 03044 03045 // Force versioning related fields: 03046 $row['pid'] = $pid; 03047 03048 // Do the copy by internal function 03049 $theNewSQLID = $this->insertNewCopyVersion($table,$row,$pid); 03050 if ($theNewSQLID) { 03051 return $this->copyMappingArray[$table][$uid] = $theNewSQLID; 03052 } 03053 } else $this->log($table,$uid,3,0,1,'Attempt to rawcopy/versionize record that did not exist!'); 03054 } else $this->log($table,$uid,3,0,1,'Attempt to rawcopy/versionize record without copy permission'); 03055 } 03056 } 03057 03067 function insertNewCopyVersion($table,$fieldArray,$realPid) { 03068 global $TCA; 03069 03070 $id = uniqid('NEW'); 03071 03072 // $fieldArray is set as current record. 03073 // 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... 03074 $this->checkValue_currentRecord = $fieldArray; 03075 03076 // Traverse record and input-process each value: 03077 foreach($fieldArray as $field => $fieldValue) { 03078 if (isset($TCA[$table]['columns'][$field])) { 03079 // Evaluating the value. 03080 $res = $this->checkValue($table,$field,$fieldValue,$id,'new',$realPid,0); 03081 if (isset($res['value'])) { 03082 $fieldArray[$field] = $res['value']; 03083 } 03084 } 03085 } 03086 03087 // System fields being set: 03088 if ($TCA[$table]['ctrl']['crdate']) { 03089 $fieldArray[$TCA[$table]['ctrl']['crdate']]=time(); 03090 } 03091 if ($TCA[$table]['ctrl']['cruser_id']) { 03092 $fieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid; 03093 } 03094 if ($TCA[$table]['ctrl']['tstamp']) { 03095 $fieldArray[$TCA[$table]['ctrl']['tstamp']]=time(); 03096 } 03097 03098 // Finally, insert record: 03099 $this->insertDB($table,$id,$fieldArray, TRUE); 03100 03101 // Return new id: 03102 return $this->substNEWwithIDs[$id]; 03103 } 03104 03118 function copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf) { 03119 global $TCA; 03120 03121 // 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) 03122 $value = $this->copyRecord_procFilesRefs($conf, $uid, $value); 03123 03124 03125 // Register if there are references to take care of (no change to value): 03126 if ($this->isReferenceField($conf)) { 03127 $allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table']; 03128 $prependName = $conf['type']=='group' ? $conf['prepend_tname'] : $conf['neg_foreign_table']; 03129 if ($conf['MM']) { 03130 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup'); 03131 $dbAnalysis->start('',$allowedTables,$conf['MM'],$uid); 03132 $value = implode(',',$dbAnalysis->getValueArray($prependName)); 03133 } 03134 if ($value) { // Setting the value in this array will notify the remapListedDBRecords() function that this field MAY need references to be corrected 03135 $this->registerDBList[$table][$uid][$field] = $value; 03136 } 03137 } 03138 03139 // 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()) 03140 if ($conf['type']=='flex') { 03141 03142 // Get current value array: 03143 $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $row, $table); 03144 $currentValueArray = t3lib_div::xml2array($value); 03145 03146 // Traversing the XML structure, processing files: 03147 if (is_array($currentValueArray)) { 03148 $currentValueArray['data'] = $this->checkValue_flex_procInData( 03149 $currentValueArray['data'], 03150 array(), // Not used. 03151 array(), // Not used. 03152 $dataStructArray, 03153 array($table,$uid,$field), // Parameters. 03154 'copyRecord_flexFormCallBack' 03155 ); 03156 $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. 03157 } 03158 } 03159 03160 return $value; 03161 } 03162 03171 function copyRecord_localize($table,$uid,$language) { 03172 global $TCA; 03173 03174 $uid = intval($uid); 03175 03176 if ($TCA[$table] && $uid) { 03177 t3lib_div::loadTCA($table); 03178 03179 if ($TCA[$table]['ctrl']['languageField'] && $TCA[$table]['ctrl']['transOrigPointerField']) { 03180 if ($langRec = t3lib_BEfunc::getRecord('sys_language',intval($language),'uid,title')) { 03181 if ($this->doesRecordExist($table,$uid,'show')) { 03182 03183 $row = $this->recordInfo($table,$uid,'*'); 03184 if (is_array($row)) { 03185 if ($row[$TCA[$table]['ctrl']['languageField']] <= 0) { 03186 if ($row[$TCA[$table]['ctrl']['transOrigPointerField']] == 0) { 03187 if (!t3lib_BEfunc::getRecordsByField($table,$TCA[$table]['ctrl']['transOrigPointerField'],$uid,'AND pid='.intval($row['pid']).' AND '.$TCA[$table]['ctrl']['languageField'].'='.$langRec['uid'])) { 03188 03189 // Initialize: 03190 $overrideValues = array(); 03191 $excludeFields = array(); 03192 03193 // Set override values: 03194 $overrideValues[$TCA[$table]['ctrl']['languageField']] = $langRec['uid']; 03195 $overrideValues[$TCA[$table]['ctrl']['transOrigPointerField']] = $uid; 03196 03197 // Set exclude Fields: 03198 foreach($TCA[$table]['columns'] as $fN => $fCfg) { 03199 if ($fCfg['l10n_mode']=='prefixLangTitle') { // Check if we are just prefixing: 03200 if ($fCfg['config']['type']=='text' || $fCfg['config']['type']=='input') { 03201 $overrideValues[$fN] = '[Translate to '.$langRec['title'].':] '.$row[$fN]; 03202 } 03203 } elseif (t3lib_div::inList('exclude,noCopy,mergeIfNotBlank',$fCfg['l10n_mode']) && $fN!=$TCA[$table]['ctrl']['languageField'] && $fN!=$TCA[$table]['ctrl']['transOrigPointerField']) { // Otherwise, do not copy field (unless it is the language field or pointer to the original language) 03204 $excludeFields[] = $fN; 03205 } 03206 } 03207 // Execute the copy: 03208 $this->copyRecord($table,$uid,-$uid,1,$overrideValues,implode(',',$excludeFields)); 03209 } else $this->log($table,$uid,3,0,1,'Localization failed; There already was a localization for this language of the record!'); 03210 } else $this->log($table,$uid,3,0,1,'Localization failed; Source record contained a reference to an original default record (which is strange)!'); 03211 } else $this->log($table,$uid,3,0,1,'Localization failed; Source record had another language than "Default" or "All" defined!'); 03212 } else $this->log($table,$uid,3,0,1,'Attempt to localize record that did not exist!'); 03213 } else $this->log($table,$uid,3,0,1,'Attempt to localize record without permission'); 03214 } else $this->log($table,$uid,3,0,1,'Sys language UID "'.$language.'" not found valid!'); 03215 } else $this->log($table,$uid,3,0,1,'Localization failed; "languageField" and "transOrigPointerField" must be defined for the table!'); 03216 } 03217 } 03218 03230 function copyRecord_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2) { 03231 03232 // Extract parameters: 03233 list($table, $uid, $field) = $pParams; 03234 03235 // Process references and files, currently that means only the files, prepending absolute paths: 03236 $dataValue = $this->copyRecord_procFilesRefs($dsConf, $uid, $dataValue); 03237 03238 // If references are set for this field, set flag so they can be corrected later (in ->remapListedDBRecords()) 03239 if ($this->isReferenceField($dsConf) && strlen($dataValue)) { 03240 $this->registerDBList[$table][$uid][$field] = 'FlexForm_reference'; 03241 } 03242 03243 // Return 03244 return array('value' => $dataValue); 03245 } 03246 03258 function copyRecord_procFilesRefs($conf, $uid, $value) { 03259 03260 // Prepend absolute paths to files: 03261 if ($conf['type']=='group' && $conf['internal_type']=='file') { 03262 03263 // Get an array with files as values: 03264 if ($conf['MM']) { 03265 $theFileValues = array(); 03266 03267 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup'); 03268 $dbAnalysis->start('', 'files', $conf['MM'], $uid); 03269 03270 foreach($dbAnalysis->itemArray as $somekey => $someval) { 03271 if ($someval['id']) { 03272 $theFileValues[] = $someval['id']; 03273 } 03274 } 03275 } else { 03276 $theFileValues = t3lib_div::trimExplode(',',$value,1); 03277 } 03278 03279 // Traverse this array of files: 03280 $uploadFolder = $conf['uploadfolder']; 03281 $dest = $this->destPathFromUploadFolder($uploadFolder); 03282 $newValue = array(); 03283 03284 foreach($theFileValues as $file) { 03285 if (trim($file)) { 03286 $realFile = $dest.'/'.trim($file); 03287 if (@is_file($realFile)) { 03288 $newValue[] = $realFile; 03289 } 03290 } 03291 } 03292 03293 // 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...) 03294 $value = implode(',',$newValue); 03295 } 03296 03297 // Return the new value: 03298 return $value; 03299 } 03300 03309 function copyPages($uid,$destPid) { 03310 03311 // Initialize: 03312 $uid = intval($uid); 03313 $destPid = intval($destPid); 03314 03315 // Finding list of tables to copy. 03316 $copyTablesArray = $this->admin ? $this->compileAdminTables() : explode(',',$this->BE_USER->groupData['tables_modify']); // These are the tables, the user may modify 03317 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 03318 foreach($copyTablesArray as $k => $table) { 03319 if (!$table || !t3lib_div::inList($this->copyWhichTables.',pages',$table)) { // pages are always going... 03320 unset($copyTablesArray[$k]); 03321 } 03322 } 03323 } 03324 $copyTablesArray = array_unique($copyTablesArray); 03325 03326 // Begin to copy pages if we're allowed to: 03327 if ($this->admin || in_array('pages',$copyTablesArray)) { 03328 03329 // Copy this page we're on. And set first-flag (this will trigger that the record is hidden if that is configured)! 03330 $this->copySpecificPage($uid,$destPid,$copyTablesArray,1); 03331 $theNewRootID = $this->copyMappingArray['pages'][$uid]; // This is the new ID of the rootpage of the copy-action. This ID is excluded when the list is gathered lateron 03332 03333 // If we're going to copy recursively...: 03334 if ($theNewRootID && $this->copyTree) { 03335 03336 // Get ALL subpages to copy: 03337 $CPtable = $this->int_pageTreeInfo(Array(), $uid, intval($this->copyTree), $theNewRootID); 03338 03339 // Now copying the subpages: 03340 foreach($CPtable as $thePageUid => $thePagePid) { 03341 $newPid = $this->copyMappingArray['pages'][$thePagePid]; 03342 if (isset($newPid)) { 03343 $this->copySpecificPage($thePageUid,$newPid,$copyTablesArray); 03344 } else { 03345 $this->log('pages',$uid,5,0,1,'Something went wrong during copying branch'); 03346 break; 03347 } 03348 } 03349 } // else the page was not copied. Too bad... 03350 } else { 03351 $this->log('pages',$uid,5,0,1,'Attempt to copy page without permission to this table'); 03352 } 03353 } 03354 03364 function copySpecificPage($uid,$destPid,$copyTablesArray,$first=0) { 03365 global $TCA; 03366 03367 // Copy the page itself: 03368 $this->copyRecord('pages',$uid,$destPid,$first); 03369 $theNewRootID = $this->copyMappingArray['pages'][$uid]; // The new uid 03370 03371 // If a new page was created upon the copy operation we will proceed with all the tables ON that page: 03372 if ($theNewRootID) { 03373 foreach($copyTablesArray as $table) { 03374 if ($table && is_array($TCA[$table]) && $table!='pages') { // all records under the page is copied. 03375 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($uid).$this->deleteClause($table), '', ($TCA[$table]['ctrl']['sortby'] ? $TCA[$table]['ctrl']['sortby'].' DESC' : '')); 03376 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) { 03377 $this->copyRecord($table,$row['uid'], $theNewRootID); // Copying each of the underlying records... 03378 } 03379 } 03380 } 03381 } 03382 } 03383 03394 function versionizeRecord($table,$id,$label) { 03395 global $TCA; 03396 03397 $id = intval($id); 03398 03399 if ($TCA[$table] && $TCA[$table]['ctrl']['versioning'] && $id>0) { 03400 if ($this->doesRecordExist($table,$id,'show') && $this->doesRecordExist($table,$id,'edit')) { 03401 03402 // Select main record: 03403 $row = $this->recordInfo($table,$id,'pid,t3ver_id'); 03404 if (is_array($row)) { 03405 if ($row['pid']>=0) { 03406 03407 // Look for next version number: 03408 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 03409 't3ver_id', 03410 $table, 03411 '(t3ver_oid='.$id.' || uid='.$id.')'.$this->deleteClause($table), 03412 '', 03413 't3ver_id DESC', 03414 '1' 03415 ); 03416 list($highestVerNumber) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res); 03417 03418 // Look for version number of the current: 03419 $subVer = $row['t3ver_id'].'.'.($highestVerNumber+1); 03420 03421 // Set up the values to override when making a raw-copy: 03422 $overrideArray = array( 03423 't3ver_id' => $highestVerNumber+1, 03424 't3ver_oid' => $id, 03425 't3ver_label' => ($label ? $label : $subVer.' / '.date('d-m-Y H:m:s')) 03426 ); 03427 if ($TCA[$table]['ctrl']['editlock']) { 03428 $overrideArray[$TCA[$table]['ctrl']['editlock']] = 0; 03429 } 03430 03431 // Create raw-copy and return result: 03432 return $this->copyRecord_raw($table,$id,-1,$overrideArray); 03433 } else $this->log($table,$id,0,0,1,'Record you wanted to versionize was already a version in archive (pid=-1)!'); 03434 } else $this->log($table,$id,0,0,1,'Record you wanted to versionize didnt exist!'); 03435 } else $this->log($table,$id,0,0,1,'You didnt have correct permissions to make a new version (copy) of this record "'.$table.'" / '.$id); 03436 } else $this->log($table,$id,0,0,1,'Versioning is not supported for this table "'.$table.'" / '.$id); 03437 } 03438 03447 function versionizePages($uid,$label) { 03448 global $TCA; 03449 03450 $uid = intval($uid); 03451 03452 // Finding list of tables ALLOWED to be copied 03453 $allowedTablesArray = $this->admin ? $this->compileAdminTables() : explode(',',$this->BE_USER->groupData['tables_modify']); // These are the tables, the user may modify 03454 03455 // Make list of tables that should come along with a new version of the page: 03456 $verTablesArray = array(); 03457 $allTables = array_keys($TCA); 03458 foreach($allTables as $tN) { 03459 if ($tN!='pages' && $TCA[$tN]['ctrl']['versioning_followPages'] && ($this->admin || in_array($tN, $allowedTablesArray))) { 03460 $verTablesArray[] = $tN; 03461 } 03462 } 03463 03464 // Begin to copy pages if we're allowed to: 03465 if ($this->admin || in_array('pages',$allowedTablesArray)) { 03466 03467 // Versionize this page: 03468 $theNewRootID = $this->versionizeRecord('pages',$uid,$label); 03469 $this->rawCopyPageContent($uid,$theNewRootID,$verTablesArray); 03470 03471 // If we're going to copy recursively...: 03472 if ($theNewRootID && $this->versionizeTree > 0) { 03473 03474 // Get ALL subpages to copy: 03475 $CPtable = $this->int_pageTreeInfo(Array(), $uid, intval($this->versionizeTree), $theNewRootID); 03476 03477 // Now copying the subpages: 03478 foreach($CPtable as $thePageUid => $thePagePid) { 03479 $newPid = $this->copyMappingArray['pages'][$thePagePid]; 03480 if (isset($newPid)) { 03481 $theNewRootID = $this->copyRecord_raw('pages',$thePageUid,$newPid); 03482 $this->rawCopyPageContent($thePageUid,$theNewRootID,$verTablesArray); 03483 } else { 03484 $this->log('pages',$uid,0,0,1,'Something went wrong during copying branch (for versioning)'); 03485 break; 03486 } 03487 } 03488 } // else the page was not copied. Too bad... 03489 } else { 03490 $this->log('pages',$uid,0,0,1,'Attempt to versionize page without permission to this table'); 03491 } 03492 } 03493 03504 function rawCopyPageContent($old_pid,$new_pid,$copyTablesArray) { 03505 global $TCA; 03506 03507 if ($new_pid) { 03508 foreach($copyTablesArray as $table) { 03509 if ($table && is_array($TCA[$table]) && $table!='pages') { // all records under the page is copied. 03510 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($old_pid).$this->deleteClause($table)); 03511 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) { 03512 $this->copyRecord_raw($table,$row['uid'],$new_pid); // Copying each of the underlying records (method RAW) 03513 } 03514 } 03515 } 03516 } 03517 } 03518 03529 function version_swap($table,$id,$swapWith,$swapContent) { 03530 global $TCA; 03531 03532 /* 03533 Version ID swapping principles: 03534 - 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 03535 03536 uid pid uid t3ver_oid pid 03537 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) 03538 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)) 03539 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.) 03540 03541 13 is online UID, 03542 247 is specific versions UID 03543 123 is the PID of the original record 03544 -1 is the versioning repository PID 03545 03546 Recovery Process: 03547 Search for negative UID (here "-13"): 03548 YES: Step 1 completed, but at least step 3 didn't. 03549 Search for the negativ UIDs positive (here: "13") 03550 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) 03551 NO: Only Step 1 completed! Rollback: Just change uid "-13" to "13" and "t3ver_oid" to "13" (not important) 03552 NO: No problems. 03553 */ 03554 03555 // First, check if we may actually edit this record: 03556 if ($this->checkRecordUpdateAccess($table,$id)) { 03557 03558 // Find fields to select: 03559 $keepFields = array(); // Keep-fields can be used for other fields than "sortby" if needed in the future... 03560 $selectFields = array('uid','pid','t3ver_oid'); 03561 if ($TCA[$table]['ctrl']['sortby']) { 03562 $selectFields[] = $keepFields[] = $TCA[$table]['ctrl']['sortby']; 03563 } 03564 $selectFields = array_unique($selectFields); 03565 03566 // Select the two versions: 03567 $curVersion = t3lib_BEfunc::getRecord($table,$id,implode(',',$selectFields)); 03568 $swapVersion = t3lib_BEfunc::getRecord($table,$swapWith,implode(',',$selectFields)); 03569 03570 if (is_array($curVersion) && is_array($swapVersion)) { 03571 if (!is_array(t3lib_BEfunc::getRecord($table,-$id,'uid'))) { 03572 03573 // Add "keepfields" 03574 $swapVerBaseArray = array(); 03575 foreach($keepFields as $fN) { 03576 $swapVerBaseArray[$fN] = $curVersion[$fN]; 03577 } 03578 #debug($swapVerBaseArray); 03579 // Check if the swapWith record really IS a version of the original! 03580 if ($swapVersion['pid']==-1 && $swapVersion['t3ver_oid']==$id) { 03581 #debug($curVersion,'$curVersion'); 03582 #debug($swapVersion,'$swapVersion'); 03583 $sqlErrors=array(); 03584 03585 // Step 1: 03586 $sArray = array(); 03587 $sArray['uid'] = -intval($id); 03588 $sArray['t3ver_oid'] = intval($swapWith); 03589 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($id),$sArray); 03590 if ($GLOBALS['TYPO3_DB']->sql_error()) $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error(); 03591 03592 // Step 2: 03593 $sArray = $swapVerBaseArray; 03594 $sArray['uid'] = intval($id); 03595 $sArray['t3ver_oid'] = intval($id); 03596 $sArray['pid'] = intval($curVersion['pid']); 03597 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($swapWith),$sArray); 03598 if ($GLOBALS['TYPO3_DB']->sql_error()) $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error(); 03599 03600 // Step 3: 03601 $sArray = array(); 03602 $sArray['uid'] = intval($swapWith); 03603 $sArray['t3ver_oid'] = intval($id); 03604 $sArray['pid'] = -1; 03605 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid=-'.intval($id),$sArray); 03606 if ($GLOBALS['TYPO3_DB']->sql_error()) $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error(); 03607 03608 if (!count($sqlErrors)) { 03609 $this->log($table,$id,0,0,0,'Swapping successful for table "'.$table.'" uid '.$id.'=>'.$swapWith); 03610 03611 // SWAPPING pids for subrecords: 03612 if ($table=='pages' && $swapContent) { 03613 03614 // Collect table names that should be copied along with the tables: 03615 foreach($TCA as $tN => $tCfg) { 03616 if ($TCA[$tN]['ctrl']['versioning_followPages'] || ($tN=='pages' && $swapContent==='ALL')) { // THIS produces the problem that some records might be left inside a versionized branch. Question is; Should ALL records swap pids, not only the versioning_followPages ones? 03617 $temporaryPid = -($id+1000000); 03618 03619 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($id),array('pid'=>$temporaryPid)); 03620 if ($GLOBALS['TYPO3_DB']->sql_error()) $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error(); 03621 03622 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($swapWith),array('pid'=>$id)); 03623 if ($GLOBALS['TYPO3_DB']->sql_error()) $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error(); 03624 03625 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($temporaryPid),array('pid'=>$swapWith)); 03626 if ($GLOBALS['TYPO3_DB']->sql_error()) $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error(); 03627 03628 if (count($sqlErrors)) { 03629 $this->log($table,$id,0,0,1,'During Swapping: SQL errors happend: '.implode('; ',$sqlErrors)); 03630 } 03631 } 03632 } 03633 } 03634 // Clear cache: 03635 $this->clear_cache($table,$id); 03636 03637 } else $this->log($table,$id,0,0,1,'During Swapping: SQL errors happend: '.implode('; ',$sqlErrors)); 03638 } else $this->log($table,$id,0,0,1,'In swap version, either pid was not -1 or the t3ver_oid didn\'t match the id of the online version as it must!'); 03639 } else $this->log($table,$id,0,0,1,'Error: A record with a negative UID existed - that indicates some inconsistency in the database from prior versioning actions!'); 03640 } else $this->log($table,$id,0,0,1,'Error: Either online or swap version could not be selected!'); 03641 } else $this->log($table,$id,0,0,1,'Error: You cannot swap versions for a record you do not have access to edit!'); 03642 } 03643 03653 function int_pageTreeInfo($CPtable,$pid,$counter, $rootID) { 03654 if ($counter) { 03655 $addW = !$this->admin ? ' AND '.$this->BE_USER->getPagePermsClause($this->pMap['show']) : ''; 03656 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'pid='.intval($pid).$this->deleteClause('pages').$addW, '', 'sorting DESC'); 03657 while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) { 03658 if ($row['uid']!=$rootID) { 03659 $CPtable[$row['uid']] = $pid; 03660 if ($counter-1) { // If the uid is NOT the rootID of the copyaction and if we are supposed to walk further down 03661 $CPtable = $this->int_pageTreeInfo($CPtable,$row['uid'],$counter-1, $rootID); 03662 } 03663 } 03664 } 03665 } 03666 return $CPtable; 03667 } 03668 03674 function compileAdminTables() { 03675 global $TCA; 03676 reset ($TCA); 03677 $listArr = array(); 03678 while (list($table)=each($TCA)) { 03679 $listArr[]=$table; 03680 } 03681 return $listArr; 03682 } 03683 03691 function fixUniqueInPid($table,$uid) { 03692 global $TCA; 03693 if ($TCA[$table]) { 03694 t3lib_div::loadTCA($table); 03695 reset ($TCA[$table]['columns']); 03696 $curData=$this->recordInfo($table,$uid,'*'); 03697 $newData=array(); 03698 while (list($field,$conf)=each($TCA[$table]['columns'])) { 03699 if ($conf['config']['type']=='input') { 03700 $evalCodesArray = t3lib_div::trimExplode(',',$conf['config']['eval'],1); 03701 if (in_array('uniqueInPid',$evalCodesArray)) { 03702 $newV = $this->getUnique($table,$field,$curData[$field],$uid,$curData['pid']); 03703 if (strcmp($newV,$curData[$field])) { 03704 $newData[$field]=$newV; 03705 } 03706 } 03707 } 03708 } 03709 // IF there are changed fields, then update the database 03710 if (count($newData)) { 03711 $this->updateDB($table,$uid,$newData); 03712 } 03713 } 03714 } 03715 03727 function fixCopyAfterDuplFields($table,$uid,$prevUid,$update, $newData=array()) { 03728 global $TCA; 03729 if ($TCA[$table] && $TCA[$table]['ctrl']['copyAfterDuplFields']) { 03730 t3lib_div::loadTCA($table); 03731 $prevData=$this->recordInfo($table,$prevUid,'*'); 03732 $theFields = t3lib_div::trimExplode(',',$TCA[$table]['ctrl']['copyAfterDuplFields'],1); 03733 reset($theFields); 03734 while(list(,$field)=each($theFields)) { 03735 if ($TCA[$table]['columns'][$field] && ($update || !isset($newData[$field]))) { 03736 $newData[$field]=$prevData[$field]; 03737 } 03738 } 03739 if ($update && count($newData)) { 03740 $this->updateDB($table,$uid,$newData); 03741 } 03742 } 03743 return $newData; 03744 } 03745 03752 function extFileFields ($table) { 03753 global $TCA; 03754 $listArr=array(); 03755 t3lib_div::loadTCA($table); 03756 if ($TCA[$table]['columns']) { 03757 reset($TCA[$table]['columns']); 03758 while (list($field,$configArr)=each($TCA[$table]['columns'])) { 03759 if ($configArr['config']['type']=='group' && $configArr['config']['internal_type']=='file') { 03760 $listArr[]=$field; 03761 } 03762 } 03763 } 03764 return $listArr; 03765 } 03766 03778 function getCopyHeader($table,$pid,$field,$value,$count,$prevTitle='') { 03779 global $TCA; 03780 03781 // Set title value to check for: 03782 if ($count) { 03783 $checkTitle = $value.rtrim(' '.sprintf($this->prependLabel($table),$count)); 03784 } else { 03785 $checkTitle = $value; 03786 } 03787 03788 // Do check: 03789 if ($prevTitle != $checkTitle || $count<100) { 03790 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($pid).' AND '.$field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($checkTitle, $table).$this->deleteClause($table), '', '', '1'); 03791 if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) { 03792 return $this->getCopyHeader($table,$pid,$field,$value,$count+1,$checkTitle); 03793 } 03794 } 03795 03796 // Default is to just return the current input title if no other was returned before: 03797 return $checkTitle; 03798 } 03799 03807 function prependLabel($table) { 03808 global $TCA; 03809 if (is_object($GLOBALS['LANG'])) { 03810 $label = $GLOBALS['LANG']->sL($TCA[$table]['ctrl']['prependAtCopy']); 03811 } else { 03812 list($label) = explode('|',$TCA[$table]['ctrl']['prependAtCopy']); 03813 } 03814 return $label; 03815 } 03816 03824 function resolvePid($table,$pid) { 03825 global $TCA; 03826 $pid=intval($pid); 03827 if ($pid < 0) { 03828 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('pid', $table, 'uid='.abs($pid)); 03829 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res); 03830 $pid = intval($row['pid']); 03831 } 03832 return $pid; 03833 } 03834 03842 function clearPrefixFromValue($table,$value) { 03843 global $TCA; 03844 $regex = sprintf(quotemeta($this->prependLabel($table)),'[0-9]*').'$'; 03845 return @ereg_replace($regex,'',$value); 03846 } 03847 03853 function remapListedDBRecords() { 03854 global $TCA; 03855 #debug($this->registerDBList); 03856 #debug($this->copyMappingArray_merged); 03857 if (count($this->registerDBList)) { 03858 reset($this->registerDBList); 03859 while(list($table,$records)=each($this->registerDBList)) { 03860 t3lib_div::loadTCA($table); 03861 reset($records); 03862 while(list($uid,$fields)=each($records)) { 03863 $newData = array(); 03864 $theUidToUpdate = $this->copyMappingArray_merged[$table][$uid]; 03865 03866 foreach($fields as $fieldName => $value) { 03867 $conf = $TCA[$table]['columns'][$fieldName]['config']; 03868 03869 switch($conf['type']) { 03870 case 'group': 03871 case 'select': 03872 $vArray = $this->remapListedDBRecords_procDBRefs($conf, $value, $theUidToUpdate); 03873 if (is_array($vArray)) { 03874 $newData[$fieldName] = implode(',',$vArray); 03875 } 03876 break; 03877 case 'flex': 03878 if ($value=='FlexForm_reference') { 03879 $origRecordRow = $this->recordInfo($table,$theUidToUpdate,'*'); // This will fetch the new row for the element 03880 03881 if (is_array($origRecordRow)) { 03882 03883 // Get current data structure and value array: 03884 $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $origRecordRow, $table); 03885 $currentValueArray = t3lib_div::xml2array($origRecordRow[$fieldName]); 03886 #debug($dataStructArray); 03887 #debug($currentValueArray); 03888 #debug($origRecordRow); 03889 #debug($currentValueArray['data']); 03890 // Do recursive processing of the XML data: 03891 $currentValueArray['data'] = $this->checkValue_flex_procInData( 03892 $currentValueArray['data'], 03893 array(), // Not used. 03894 array(), // Not used. 03895 $dataStructArray, 03896 array($table,$theUidToUpdate,$fieldName), // Parameters. 03897 'remapListedDBRecords_flexFormCallBack' 03898 ); 03899 #debug($currentValueArray['data']); 03900 // The return value should be compiled back into XML, ready to insert directly in the field (as we call updateDB() directly later): 03901 if (is_array($currentValueArray['data'])) { 03902 $newData[$fieldName] = 03903 '<?xml version="1.0" encoding="'.$GLOBALS['LANG']->charSet.'" standalone="yes" ?>'.chr(10). 03904 $this->checkValue_flexArray2Xml($currentValueArray); 03905 } 03906 } 03907 } 03908 break; 03909 default: 03910 debug('Field type should not appear here: '. $conf['type']); 03911 break; 03912 } 03913 } 03914 03915 if (count($newData)) { // If any fields were changed, those fields are updated! 03916 $this->updateDB($table,$theUidToUpdate,$newData); 03917 #debug($this->recordInfo($table,$theUidToUpdate,'*'),'Stored result:'); 03918 // debug($newData); 03919 } 03920 } 03921 } 03922 } 03923 } 03924 03936 function remapListedDBRecords_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2) { 03937 03938 // Extract parameters: 03939 list($table,$uid,$field) = $pParams; 03940 03941 // If references are set for this field, set flag so they can be corrected later: 03942 if ($this->isReferenceField($dsConf) && strlen($dataValue)) { 03943 $vArray = $this->remapListedDBRecords_procDBRefs($dsConf, $dataValue, $uid); 03944 if (is_array($vArray)) { 03945 $dataValue = implode(',',$vArray); 03946 } 03947 } 03948 03949 // Return 03950 return array('value' => $dataValue); 03951 } 03952 03962 function remapListedDBRecords_procDBRefs($conf, $value, $MM_localUid) { 03963 03964 // Initialize variables 03965 $set = FALSE; // Will be set true if an upgrade should be done... 03966 $allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table']; // Allowed tables for references. 03967 $prependName = $conf['type']=='group' ? $conf['prepend_tname'] : ''; // Table name to prepend the UID 03968 $dontRemapTables = t3lib_div::trimExplode(',',$conf['dontRemapTablesOnCopy'],1); // Which tables that should possibly not be remapped 03969 03970 // Convert value to list of references: 03971 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup'); 03972 $dbAnalysis->registerNonTableValues = ($conf['type']=='select' && $conf['allowNonIdValues']) ? 1 : 0; 03973 $dbAnalysis->start($value, $allowedTables, $conf['MM'], $MM_localUid); 03974 03975 // Traverse those references and map IDs: 03976 foreach($dbAnalysis->itemArray as $k => $v) { 03977 $mapID = $this->copyMappingArray_merged[$v['table']][$v['id']]; 03978 if ($mapID && !in_array($v['table'],$dontRemapTables)) { 03979 $dbAnalysis->itemArray[$k]['id'] = $mapID; 03980 $set = TRUE; 03981 } 03982 } 03983 03984 // If a change has been done, set the new value(s) 03985 if ($set) { 03986 if ($conf['MM']) { 03987 $dbAnalysis->writeMM($conf['MM'], $theUidToUpdate, $prependName); 03988 } else { 03989 $vArray = $dbAnalysis->getValueArray($prependName); 03990 if ($conf['type']=='select') { 03991 $vArray = $dbAnalysis->convertPosNeg($vArray, $conf['foreign_table'], $conf['neg_foreign_table']); 03992 } 03993 return $vArray; 03994 } 03995 } 03996 } 03997 04007 function extFileFunctions($table,$field,$filelist,$func) { 04008 global $TCA; 04009 t3lib_div::loadTCA($table); 04010 $uploadFolder = $TCA[$table]['columns'][$field]['config']['uploadfolder']; 04011 if ($uploadFolder && trim($filelist)) { 04012 $uploadPath = $this->destPathFromUploadFolder($uploadFolder); 04013 $fileArray = explode(',',$filelist); 04014 while (list(,$theFile)=each($fileArray)) { 04015 $theFile=trim($theFile); 04016 if ($theFile) { 04017 switch($func) { 04018 case 'deleteAll': 04019 if (@is_file($uploadPath.'/'.$theFile)) { 04020 unlink ($uploadPath.'/'.$theFile); 04021 } else { 04022 $this->log($table,0,3,0,100,"Delete: Referenced file that was supposed to be deleted together with it's record didn't exist"); 04023 } 04024 break; 04025 } 04026 } 04027 } 04028 } 04029 } 04030 04039 function deleteRecord($table,$uid, $noRecordCheck) { 04040 // This function may not be used to delete pages-records unless the underlying records are already deleted 04041 // If $noRecordCheck is set, then the function does not check permissions 04042 global $TCA; 04043 $uid = intval($uid); 04044 if ($TCA[$table] && $uid) { 04045 $deleteRow = $TCA[$table]['ctrl']['delete']; 04046 if ($noRecordCheck || $this->doesRecordExist($table,$uid,'delete')) { 04047 if ($deleteRow) { 04048 $updateFields = array( 04049 $deleteRow => 1 04050 ); 04051 04052 // If the table is sorted, then the sorting number is set very high 04053 if ($TCA[$table]['ctrl']['sortby']) { 04054 $updateFields[$TCA[$table]['ctrl']['sortby']] = 1000000000; 04055 } 04056 04057 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields); 04058 } else { 04059 04060 // Fetches all fields that holds references to files 04061 $fileFieldArr = $this->extFileFields($table); 04062 if (count($fileFieldArr)) { 04063 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(implode(',',$fileFieldArr), $table, 'uid='.intval($uid)); 04064 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) { 04065 $fArray = $fileFieldArr; 04066 04067 foreach($fArray as $theField) { // MISSING: Support for MM file relations! 04068 $this->extFileFunctions($table,$theField,$row[$theField],'deleteAll'); // This deletes files that belonged to this record. 04069 } 04070 } else { 04071 $this->log($table,$uid,3,0,100,'Delete: Zero rows in result when trying to read filenames from record which should be deleted'); 04072 } 04073 } 04074 04075 $GLOBALS['TYPO3_DB']->exec_DELETEquery($table, 'uid='.intval($uid)); 04076 } 04077 04078 if (!$GLOBALS['TYPO3_DB']->sql_error()) { 04079 $this->log($table,$uid,3,0,0,''); 04080 } else { 04081 $this->log($table,$uid,3,0,100,$GLOBALS['TYPO3_DB']->sql_error()); 04082 } 04083 04084 $this->clear_cache($table,$uid); // clear cache 04085 } else { 04086 $this->log($table,$uid,3,0,1,'Attempt to delete record without delete-permissions'); 04087 } 04088 } 04089 } 04090 04097 function deletePages($uid) { 04098 if ($this->doesRecordExist('pages',$uid,'delete')) { // If we may at all delete this page 04099 if ($this->deleteTree) { 04100 $brExist = $this->doesBranchExist('',$uid,$this->pMap['delete'],1); // returns the branch 04101 if ($brExist != -1) { // Checks if we had permissions 04102 if ($this->noRecordsFromUnallowedTables($brExist.$uid)) { 04103 $uidArray = explode(',',$brExist); 04104 while (list(,$listUid)=each($uidArray)) { 04105 if (trim($listUid)) { 04106 $this->deleteSpecificPage($listUid); 04107 } 04108 } 04109 $this->deleteSpecificPage($uid); 04110 } else { 04111 $this->log('pages',$uid,3,0,1,'Attempt to delete records from disallowed tables'); 04112 } 04113 } else { 04114 $this->log('pages',$uid,3,0,1,'Attempt to delete pages in branch without permissions'); 04115 } 04116 } else { 04117 $brExist = $this->doesBranchExist('',$uid,$this->pMap['delete'],1); // returns the branch 04118 if ($brExist == '') { // Checks if branch exists 04119 if ($this->noRecordsFromUnallowedTables($uid)) { 04120 $this->deleteSpecificPage($uid); 04121 } else { 04122 $this->log('pages',$uid,3,0,1,'Attempt to delete records from disallowed tables'); 04123 } 04124 } else { 04125 $this->log('pages',$uid,3,0,1,'Attempt to delete page which has subpages'); 04126 } 04127 } 04128 } else { 04129 $this->log('pages',$uid,3,0,1,'Attempt to delete page without permissions'); 04130 } 04131 } 04132 04139 function deleteSpecificPage($uid) { 04140 // internal function !! 04141 global $TCA; 04142 reset ($TCA); 04143 $uid = intval($uid); 04144 if ($uid) { 04145 while (list($table)=each($TCA)) { 04146 if ($table!='pages') { 04147 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($uid).$this->deleteClause($table)); 04148 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) { 04149 $this->deleteRecord($table,$row['uid'], 1); 04150 } 04151 } 04152 } 04153 $this->deleteRecord('pages',$uid, 1); 04154 } 04155 } 04156 04163 function noRecordsFromUnallowedTables($inList) { 04164 // used by the deleteFunctions to check if there are records from disallowed tables under the pages to be deleted. Return true, if permission granted 04165 global $TCA; 04166 reset ($TCA); 04167 $inList = trim($this->rmComma(trim($inList))); 04168 if ($inList && !$this->admin) { 04169 while (list($table) = each($TCA)) { 04170 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', $table, 'pid IN ('.$inList.')'); 04171 $count = $GLOBALS['TYPO3_DB']->sql_fetch_row($mres); 04172 if ($count[0] && ($this->tableReadOnly($table) || !$this->checkModifyAccessList($table))) { 04173 return false; 04174 } 04175 } 04176 } 04177 return true; 04178 } 04179 04180 04181 04182 04183 04184 04185 04186 04187 04188 04189 04190 04191 04192 04193 04194 04195 04196 04197 04198 04199 04200 04201 04202 04203 04204 04205 /********************************************* 04206 * 04207 * MISC FUNCTIONS 04208 * 04209 ********************************************/ 04210 04225 function getSortNumber($table,$uid,$pid) { 04226 global $TCA; 04227 if ($TCA[$table] && $TCA[$table]['ctrl']['sortby']) { 04228 $sortRow = $TCA[$table]['ctrl']['sortby']; 04229 if ($pid>=0) { // Sorting number is in the top 04230 $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 04231 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { // There was a page 04232 if ($row['uid']==$uid) { // The top record was the record it self, so we return its current sortnumber 04233 return $row[$sortRow]; 04234 } 04235 if ($row[$sortRow] < 1) { // If the pages sortingnumber < 1 we must resort the records under this pid 04236 $this->resorting($table,$pid,$sortRow,0); 04237 return $this->sortIntervals; 04238 } else { 04239 return floor($row[$sortRow]/2); 04240 } 04241 } else { // No pages, so we choose the default value as sorting-number 04242 return $this->sortIntervals; 04243 } 04244 } else { // Sorting number is inside the list 04245 $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 04246 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { // There was a record 04247 if ($row['uid']==$uid) { // If the record happends to be it self 04248 $sortNumber = $row[$sortRow]; 04249 } else { 04250 $subres = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 04251 $sortRow.',pid,uid', 04252 $table, 04253 'pid='.intval($row['pid']).' AND '.$sortRow.'>='.intval($row[$sortRow]).$this->deleteClause($table), 04254 '', 04255 $sortRow.' ASC', 04256 '2' 04257 ); // Fetches the next record in order to calculate the in between sortNumber 04258 if ($GLOBALS['TYPO3_DB']->sql_num_rows($subres)==2) { // There was a record afterwards 04259 $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres); // Forward to the second result... 04260 $subrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres); // There was a record afterwards 04261 $sortNumber = $row[$sortRow]+ floor(($subrow[$sortRow]-$row[$sortRow])/2); // The sortNumber is found in between these values 04262 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 04263 $sortNumber = $this->resorting($table,$row['pid'],$sortRow, $row['uid']); // By this special param, resorting reserves and returns the sortnumber after the uid 04264 } 04265 } else { // If after the last record in the list, we just add the sortInterval to the last sortvalue 04266 $sortNumber = $row[$sortRow]+$this->sortIntervals; 04267 } 04268 } 04269 return Array('pid' => $row['pid'], 'sortNumber' => $sortNumber); 04270 } else { 04271 $propArr = $this->getRecordProperties($table,$uid); 04272 $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... 04273 return false; // There MUST be a page or else this cannot work 04274 } 04275 } 04276 } 04277 } 04278 04290 function resorting($table,$pid,$sortRow, $return_SortNumber_After_This_Uid) { 04291 global $TCA; 04292 if ($TCA[$table] && $sortRow && $TCA[$table]['ctrl']['sortby']==$sortRow) { 04293 $returnVal = 0; 04294 $intervals = $this->sortIntervals; 04295 $i = $intervals*2; 04296 04297 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'pid='.intval($pid).$this->deleteClause($table), '', $sortRow.' ASC'); 04298 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { 04299 $uid=intval($row['uid']); 04300 if ($uid) { 04301 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), array($sortRow=>$i)); 04302 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 04303 $i = $i+$intervals; 04304 $returnVal=$i; 04305 } 04306 } else {die ('Fatal ERROR!! No Uid at resorting.');} 04307 $i = $i+$intervals; 04308 } 04309 return $returnVal; 04310 } 04311 } 04312 04319 function rmComma ($input) { 04320 return ereg_replace(',$','',$input); 04321 } 04322 04329 function convNumEntityToByteValue($input) { 04330 $token = md5(microtime()); 04331 $parts = explode($token,ereg_replace('(&#([0-9]+);)',$token.'\2'.$token,$input)); 04332 04333 foreach($parts as $k => $v) { 04334 if ($k%2) { 04335 $v = intval($v); 04336 if ($v > 32) { // Just to make sure that control bytes are not converted. 04337 $parts[$k] =chr(intval($v)); 04338 } 04339 } 04340 } 04341 04342 return implode('',$parts); 04343 } 04344 04351 function destPathFromUploadFolder ($folder) { 04352 return PATH_site.$folder; 04353 } 04354 04362 function destNotInsideSelf ($dest,$id) { 04363 $loopCheck = 100; 04364 $dest = intval($dest); 04365 $id = intval($id); 04366 if ($dest==$id) { 04367 return false; 04368 } 04369 while ($dest!=0 && $loopCheck>0) { 04370 $loopCheck--; 04371 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('pid, uid', 'pages', 'uid='.intval($dest).$this->deleteClause('pages')); 04372 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { 04373 if ($row['pid']==$id) { 04374 return false; 04375 } 04376 } else { 04377 return false; 04378 } 04379 } 04380 return true; 04381 } 04382 04388 function getExcludeListArray() { 04389 global $TCA; 04390 $list = array(); 04391 reset($TCA); 04392 while (list($table)=each($TCA)) { 04393 t3lib_div::loadTCA($table); 04394 while (list($field,$config)=each($TCA[$table]['columns'])) { 04395 if ($config['exclude'] && !t3lib_div::inList($this->BE_USER->groupData['non_exclude_fields'],$table.':'.$field)) { 04396 $list[]=$table.'-'.$field; 04397 } 04398 } 04399 } 04400 return $list; 04401 } 04402 04412 function doesPageHaveUnallowedTables($page_uid,$doktype) { 04413 global $TCA, $PAGES_TYPES; 04414 $page_uid = intval($page_uid); 04415 if (!$page_uid) { 04416 return FALSE; // Not a number. Probably a new page 04417 } 04418 04419 $allowedTableList = isset($PAGES_TYPES[$doktype]['allowedTables']) ? $PAGES_TYPES[$doktype]['allowedTables'] : $PAGES_TYPES['default']['allowedTables']; 04420 $allowedArray = t3lib_div::trimExplode(',',$allowedTableList,1); 04421 if (strstr($allowedTableList,'*')) { // If all tables is OK the return true 04422 return FALSE; // OK... 04423 } 04424 04425 reset ($TCA); 04426 $tableList = array(); 04427 while (list($table)=each($TCA)) { 04428 if (!in_array($table,$allowedArray)) { // If the table is not in the allowed list, check if there are records... 04429 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', $table, 'pid='.intval($page_uid)); 04430 $count = $GLOBALS['TYPO3_DB']->sql_fetch_row($mres); 04431 if ($count[0]) { 04432 $tableList[]=$table; 04433 } 04434 } 04435 } 04436 return implode(',',$tableList); 04437 } 04438 04445 function deleteClause($table) { 04446 // Returns the proper delete-clause if any for a table from TCA 04447 global $TCA; 04448 if ($TCA[$table]['ctrl']['delete']) { 04449 return ' AND '.$table.'.'.$TCA[$table]['ctrl']['delete'].'=0'; 04450 } else { 04451 return ''; 04452 } 04453 } 04454 04461 function tableReadOnly($table) { 04462 // returns true if table is readonly 04463 global $TCA; 04464 return ($TCA[$table]['ctrl']['readOnly'] ? 1 : 0); 04465 } 04466 04473 function tableAdminOnly($table) { 04474 // returns true if table is admin-only 04475 global $TCA; 04476 return ($TCA[$table]['ctrl']['adminOnly'] ? 1 : 0); 04477 } 04478 04487 function getInterfacePagePositionID($uid) { 04488 global $TCA; 04489 $perms_clause = $this->BE_USER->getPagePermsClause(1); 04490 $deleted = $TCA['pages']['ctrl']['delete'] ? 'AND A.'.$TCA['pages']['ctrl']['delete'].'=0 AND pages.'.$TCA['pages']['ctrl']['delete'].'=0 ' : ''; 04491 04492 // This fetches a list of 1 or 2 pages, where - if 2 - the 2nd is the page BEFORE this ($uid). If 1 then the page ($uid) is at the top itself 04493 $subres = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 04494 'pages.uid, pages.pid', 04495 'pages A, pages', 04496 'A.pid=pages.pid AND A.uid=\''.$uid.'\' 04497 '.$deleted.' 04498 AND pages.sorting<=A.sorting 04499 AND '.$perms_clause, 04500 '', 04501 'pages.sorting DESC', 04502 '2' 04503 ); 04504 if ($GLOBALS['TYPO3_DB']->sql_num_rows($subres)==2) { // There was a record before 04505 $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres); // forwards to the second result 04506 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres); 04507 return -$row['uid']; 04508 } else { 04509 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres); 04510 return $row['pid']; 04511 } 04512 } 04513 04520 function isReferenceField($conf) { 04521 return ($conf['type']=='group' && $conf['internal_type']=='db') || ($conf['type']=='select' && $conf['foreign_table']); 04522 } 04523 04530 function getTCEMAIN_TSconfig($tscPID) { 04531 if (!isset($this->cachedTSconfig[$tscPID])) { 04532 $this->cachedTSconfig[$tscPID] = $this->BE_USER->getTSConfig('TCEMAIN',t3lib_BEfunc::getPagesTSconfig($tscPID)); 04533 } 04534 return $this->cachedTSconfig[$tscPID]['properties']; 04535 } 04536 04544 function getTableEntries($table,$TSconfig) { 04545 $tA = is_array($TSconfig['table.'][$table.'.']) ? $TSconfig['table.'][$table.'.'] : array();; 04546 $dA = is_array($TSconfig['default.']) ? $TSconfig['default.'] : array(); 04547 return t3lib_div::array_merge_recursive_overrule($dA,$tA); 04548 } 04549 04558 function setHistory($table,$id,$logId) { 04559 if (isset($this->historyRecords[$table.':'.$id])) { 04560 04561 list($tscPID) = t3lib_BEfunc::getTSCpid($table,$id,''); 04562 $TSConfig = $this->getTCEMAIN_TSconfig($tscPID); 04563 04564 $tE = $this->getTableEntries($table,$TSConfig); 04565 $keepEntries = strcmp($tE['history.']['keepEntries'],'') ? t3lib_div::intInRange($tE['history.']['keepEntries'],0,200) : 10; 04566 $maxAgeSeconds = 60*60*24*(strcmp($tE['history.']['maxAgeDays'],'') ? t3lib_div::intInRange($tE['history.']['maxAgeDays'],0,200) : 7); // one week 04567 $this->clearHistory($table,$id,t3lib_div::intInRange($keepEntries-1,0),$maxAgeSeconds); 04568 04569 if ($keepEntries) { 04570 $fields_values = array(); 04571 $fields_values['history_data'] = serialize($this->historyRecords[$table.':'.$id]); 04572 $fields_values['fieldlist'] = implode(',',array_keys($this->historyRecords[$table.':'.$id]['newRecord'])); 04573 $fields_values['tstamp'] = time(); 04574 $fields_values['tablename'] = $table; 04575 $fields_values['recuid'] = $id; 04576 $fields_values['sys_log_uid'] = $logId; 04577 04578 $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_history', $fields_values); 04579 } 04580 } 04581 } 04582 04595 function clearHistory($table,$id,$keepEntries=10,$maxAgeSeconds=604800) { 04596 $tstampLimit = $maxAgeSeconds ? time()-$maxAgeSeconds : 0; 04597 04598 $where = ' 04599 tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_history').' 04600 AND recuid='.intval($id).' 04601 AND snapshot=0'; 04602 04603 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,tstamp', 'sys_history', $where, '', 'uid DESC', intval($keepEntries).',1'); 04604 $resRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res); 04605 if ($tstampLimit && intval($resRow['tstamp'])<$tstampLimit) { 04606 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,tstamp', 'sys_history', $where.' AND tstamp<'.intval($tstampLimit), '', 'uid DESC', '1'); 04607 $resRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res); 04608 04609 $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_history', $where.' AND uid<='.intval($resRow['uid'])); 04610 } elseif (is_array($resRow)) { 04611 $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_history', $where.' AND uid<='.intval($resRow['uid'])); 04612 } 04613 } 04614 04643 function log($table,$recuid,$action,$recpid,$error,$details,$details_nr=0,$data=array(),$event_pid=-1,$NEWid='') { 04644 if ($this->enableLogging) { 04645 $type=1; // Type value for tce_db.php 04646 if (!$this->storeLogMessages) {$details='';} 04647 return $this->BE_USER->writelog($type,$action,$error,$details_nr,$details,$data,$table,$recuid,$recpid,$event_pid,$NEWid); 04648 } 04649 } 04650 04657 function printLogErrorMessages($redirect) { 04658 $res_log = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 04659 '*', 04660 'sys_log', 04661 'type=1 AND userid='.intval($this->BE_USER->user['uid']).' AND tstamp='.intval($GLOBALS['EXEC_TIME']).' AND error!=0' 04662 ); 04663 $errorJS = array(); 04664 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_log)) { 04665 $log_data = unserialize($row['log_data']); 04666 $errorJS[] = $row[error].': '.sprintf($row['details'], $log_data[0],$log_data[1],$log_data[2],$log_data[3],$log_data[4]); 04667 } 04668 04669 if (count($errorJS)) { 04670 $error_doc = t3lib_div::makeInstance('template'); 04671 $error_doc->backPath = ''; 04672 04673 $content.= $error_doc->startPage('tce_db.php Error output'); 04674 04675 $lines[] = ' 04676 <tr class="bgColor5"> 04677 <td colspan="2" align="center"><strong>Errors:</strong></td> 04678 </tr>'; 04679 04680 foreach($errorJS as $line) { 04681 $lines[] = ' 04682 <tr class="bgColor4"> 04683 <td valign="top"><img'.t3lib_iconWorks::skinImg('','gfx/icon_fatalerror.gif','width="18" height="16"').' alt="" /></td> 04684 <td>'.htmlspecialchars($line).'</td> 04685 </tr>'; 04686 } 04687 04688 $lines[] = ' 04689 <tr> 04690 <td colspan="2" align="center"><br />'. 04691 '<form action=""><input type="submit" value="Continue" onclick="'.htmlspecialchars('document.location=\''.$redirect.'\';return false;').'"></form>'. 04692 '</td> 04693 </tr>'; 04694 04695 $content.= ' 04696 <br/><br/> 04697 <table border="0" cellpadding="1" cellspacing="1" width="300" align="center"> 04698 '.implode('',$lines).' 04699 </table>'; 04700 04701 $content.= $error_doc->endPage(); 04702 echo $content; 04703 exit; 04704 } 04705 } 04706 04719 function clear_cacheCmd($cacheCmd) { 04720 global $TYPO3_CONF_VARS; 04721 04722 // Clear cache for either ALL pages or ALL tables! 04723 switch($cacheCmd) { 04724 case 'pages': 04725 if ($this->admin || $this->BE_USER->getTSConfigVal('options.clearCache.pages')) { 04726 if (t3lib_extMgm::isLoaded('cms')) { 04727 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages',''); 04728 } 04729 } 04730 break; 04731 case 'all': 04732 if ($this->admin || $this->BE_USER->getTSConfigVal('options.clearCache.all')) { 04733 if (t3lib_extMgm::isLoaded('cms')) { 04734 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages',''); 04735 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection',''); 04736 } 04737 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_hash',''); 04738 04739 // Clearing additional cache tables: 04740 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearAllCache_additionalTables'])) { 04741 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearAllCache_additionalTables'] as $tableName) { 04742 if (!ereg('[^[:alnum:]_]',$tableName) && substr($tableName,-5)=='cache') { 04743 $GLOBALS['TYPO3_DB']->exec_DELETEquery($tableName,''); 04744 } else { 04745 die('Fatal Error: Trying to flush table "'.$tableName.'" with "Clear All Cache"'); 04746 } 04747 } 04748 } 04749 } 04750 break; 04751 case 'temp_CACHED': 04752 if ($this->admin && $TYPO3_CONF_VARS['EXT']['extCache']) { 04753 $this->removeCacheFiles(); 04754 } 04755 break; 04756 } 04757 04758 // Clear cache for a page ID! 04759 if (t3lib_div::testInt($cacheCmd)) { 04760 if (t3lib_extMgm::isLoaded('cms')) { 04761 04762 $list_cache = array($cacheCmd); 04763 04764 // Call pre-processing function for clearing of cache for page ids: 04765 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval'])) { 04766 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearPageCacheEval'] as $funcName) { 04767 $_params = array('pageIdArray' => &$list_cache, 'cacheCmd' => $cacheCmd, 'functionID' => 'clear_cacheCmd()'); 04768 // Returns the array of ids to clear, false if nothing should be cleared! Never an empty array! 04769 t3lib_div::callUserFunction($funcName,$_params,$this); 04770 } 04771 } 04772 04773 // Delete cache for selected pages: 04774 if (is_array($list_cache)) { 04775 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')'); 04776 $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! 04777 } 04778 } 04779 } 04780 04781 // Call post processing function for clear-cache: 04782 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'])) { 04783 $_params = array('cacheCmd'=>$cacheCmd); 04784 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'] as $_funcRef) { 04785 t3lib_div::callUserFunction($_funcRef,$_params,$this); 04786 } 04787 } 04788 } 04789 04795 function removeCacheFiles() { 04796 $cacheFiles=t3lib_extMgm::currentCacheFiles(); 04797 $out=0; 04798 if (is_array($cacheFiles)) { 04799 reset($cacheFiles); 04800 while(list(,$cfile)=each($cacheFiles)) { 04801 @unlink($cfile); 04802 clearstatcache(); 04803 $out++; 04804 } 04805 } 04806 04807 return $out; 04808 } 04809 } 04810 04811 04812 04813 04814 /* 04815 Log messages: 04816 [action]-[details_nr.] 04817 04818 REMEMBER to UPDATE the real messages set in tools/log/localconf_log.php 04819 04820 0-1: Referer host '%s' and server host '%s' did not match! 04821 1-11: Attempt to insert record on page '%s' (%s) where this table, %s, is not allowed 04822 1-12: Attempt to insert a record on page '%s' (%s) from table '%s' without permissions. Or non-existing page. 04823 2-1: Attempt to modify table '%s' without permission 04824 2-2: Attempt to modify record '%s' (%s) without permission. Or non-existing page. 04825 2-10: Record '%s' (%s) was updated. 04826 2-12: SQL error: '%s' (%s) 04827 2-13: Write-file error: '%s' 04828 4-1: Attempt to move record '%s' (%s) to after a non-existing record (uid=%s) 04829 4-2: Moved record '%s' (%s) to page '%s' (%s) 04830 4-3: Moved record '%s' (%s) from page '%s' (%s) 04831 4-4: Moved record '%s' (%s) on page '%s' (%s) 04832 4-10: Attempt to move page '%s' (%s) to inside of its own rootline (at page '%s' (%s)) 04833 4-11: Attempt to insert record on page '%s' (%s) where this table, %s, is not allowed 04834 4-12: Attempt to insert a record on page '%s' (%s) from table '%s' without permissions. Or non-existing page. 04835 4-13: Attempt to move record '%s' (%s) to after another record, although the table has no sorting row. 04836 4-14: Attempt to move record '%s' (%s) without having permissions to do so 04837 5-1: You cannot change the 'doktype' of page '%s' to the desired value. 04838 5-2: 'doktype' of page '%s' could not be changed because the page contains records from disallowed tables; %s 04839 5-3: Too few items in the list of values. (%s) 04840 5-10: Could not delete file '%s' (does not exist). (%s) 04841 5-11: Copying file '%s' failed!: No destination file (%s) possible!. (%s) 04842 5-12: Fileextension '%' not allowed. (%s) 04843 5-13: Filesize (%s) of file '%s' exceeds limit (%s). (%s) 04844 5-14: The destination (%s) or the source file (%s) does not exist. (%s) 04845 5-15: Copying to file '%s' failed! (%s) 04846 5-16: Copying file '%s' failed!: The destination path (%s) may be write protected. Please make it write enabled!. (%s) 04847 04848 */ 04849 04850 04851 04852 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tcemain.php']) { 04853 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tcemain.php']); 04854 } 04855 ?>