Changed lots of stuff...
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_tcemain.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2004 Kasper Skaarhoj (kasper@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains the TYPO3 Core Engine
29 *
30 * $Id$
31 * Revised for TYPO3 3.6 August/2003 by Kasper Skaarhoj
32 *
33 * @author Kasper Skaarhoj <kasper@typo3.com>
34 */
35 /**
36 * [CLASS/FUNCTION INDEX of SCRIPT]
37 *
38 *
39 *
40 * 182: class t3lib_TCEmain
41 * 269: function start($data,$cmd,$altUserObject='')
42 * 314: function setMirror($mirror)
43 * 339: function setDefaultsFromUserTS($userTS)
44 * 363: function process_uploads($postFiles)
45 * 393: function process_uploads_traverseArray(&$outputArr,$inputArr,$keyToSet)
46 *
47 * SECTION: PROCESSING DATA
48 * 429: function process_datamap()
49 * 600: function fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$realPid,$status,$tscPID)
50 * 756: function checkModifyAccessList($table)
51 * 768: function isRecordInWebMount($table,$id)
52 * 782: function isInWebMount($pid)
53 * 799: function checkRecordUpdateAccess($table,$id)
54 * 824: function checkRecordInsertAccess($insertTable,$pid,$action=1)
55 * 860: function isTableAllowedForThisPage($page_uid, $checkTable)
56 * 895: function doesRecordExist($table,$id,$perms)
57 * 958: function doesBranchExist($inList,$pid,$perms, $recurse)
58 * 987: function pageInfo($id,$field)
59 * 1007: function recordInfo($table,$id,$fieldList)
60 * 1024: function getRecordProperties($table,$id)
61 * 1036: function getRecordPropertiesFromRow($table,$row)
62 * 1055: function setTSconfigPermissions($fieldArray,$TSConfig_p)
63 * 1071: function newFieldArray($table)
64 * 1102: function overrideFieldArray($table,$data)
65 * 1115: function assemblePermissions($string)
66 *
67 * SECTION: Evaluation of input values
68 * 1164: function checkValue($table,$field,$value,$id,$status,$realPid)
69 * 1220: function checkValue_SW($res,$value,$tcaFieldConf,$table,$id,$curValue,$status,$realPid,$recFID,$field,$uploadedFiles)
70 * 1259: function checkValue_input($res,$value,$tcaFieldConf,$PP,$field='')
71 * 1297: function checkValue_check($res,$value,$tcaFieldConf,$PP)
72 * 1320: function checkValue_radio($res,$value,$tcaFieldConf,$PP)
73 * 1345: function checkValue_group_select($res,$value,$tcaFieldConf,$PP,$uploadedFiles)
74 * 1423: function checkValue_group_select_file($valueArray,$tcaFieldConf,$curValue,$uploadedFileArray,$status,$table,$id,$recFID)
75 * 1568: function checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$curRecordArr,$field)
76 * 1627: function _DELETE_FLEX_FORMdata(&$valueArrayToRemoveFrom,$deleteCMDS)
77 *
78 * SECTION: Helper functions for evaluation functions.
79 * 1675: function getUnique($table,$field,$value,$id,$newPid=0)
80 * 1708: function checkValue_input_Eval($value,$evalArray,$is_in)
81 * 1796: function checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,$type)
82 * 1829: function checkValue_group_select_explodeSelectGroupValue($value)
83 * 1850: function checkValue_flex_procInData($dataPart,$dataPart_current,$uploadedFiles,$dataStructArray,$pParams)
84 * 1884: function checkValue_flex_procInData_travDS(&$dataValues,$dataValues_current,$uploadedFiles,$DSelements,$pParams)
85 *
86 * SECTION: ...
87 * 1984: function updateDB($table,$id,$fieldArray)
88 * 2023: function compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray)
89 * 2069: function insertDB($table,$id,$fieldArray)
90 * 2120: function checkStoredRecord($table,$id,$fieldArray,$action)
91 * 2146: function dbAnalysisStoreExec()
92 * 2162: function removeRegisteredFiles()
93 * 2180: function clear_cache($table,$uid)
94 * 2261: function getPID($table,$uid)
95 *
96 * SECTION: PROCESSING COMMANDS
97 * 2303: function process_cmdmap()
98 * 2360: function moveRecord($table,$uid,$destPid)
99 * 2493: function copyRecord($table,$uid,$destPid,$first=0)
100 * 2630: function copyPages($uid,$destPid)
101 * 2680: function copySpecificPage($uid,$destPid,$copyTablesArray,$first=0)
102 * 2708: function int_pageTreeInfo($CPtable,$pid,$counter, $rootID)
103 * 2730: function compileAdminTables()
104 * 2747: function fixUniqueInPid($table,$uid)
105 * 2783: function fixCopyAfterDuplFields($table,$uid,$prevUid,$update, $newData=array())
106 * 2808: function extFileFields ($table)
107 * 2834: function getCopyHeader ($table,$pid,$field,$value,$count,$prevTitle="")
108 * 2860: function resolvePid ($table,$pid)
109 * 2878: function prependLabel ($table)
110 * 2895: function clearPrefixFromValue($table,$value)
111 * 2906: function remapListedDBRecords()
112 * 2969: function extFileFunctions($table,$field,$filelist,$func)
113 * 3001: function deleteRecord($table,$uid, $noRecordCheck)
114 * 3057: function deletePages($uid)
115 * 3099: function deleteSpecificPage($uid)
116 * 3124: function noRecordsFromUnallowedTables($inList)
117 *
118 * SECTION: MISC FUNCTIONS
119 * 3186: function getSortNumber($table,$uid,$pid)
120 * 3247: function resorting($table,$pid,$sortRow, $return_SortNumber_After_This_Uid)
121 * 3276: function rmComma ($input)
122 * 3286: function destPathFromUploadFolder ($folder)
123 * 3297: function destNotInsideSelf ($dest,$id)
124 * 3326: function getExcludeListArray()
125 * 3350: function doesPageHaveUnallowedTables($page_uid,$doktype)
126 * 3380: function deleteClause($table)
127 * 3396: function tableReadOnly($table)
128 * 3408: function tableAdminOnly($table)
129 * 3422: function getInterfacePagePositionID($uid)
130 * 3451: function getTCEMAIN_TSconfig($tscPID)
131 * 3465: function getTableEntries($table,$TSconfig)
132 * 3479: function setHistory($table,$id,$logId)
133 * 3516: function clearHistory($table,$id,$keepEntries=10,$maxAgeSeconds=604800)
134 * 3565: function log($table,$recuid,$action,$recpid,$error,$details,$details_nr=0,$data=array(),$event_pid=-1,$NEWid="")
135 * 3579: function printLogErrorMessages($redirect)
136 * 3625: function clear_cacheCmd($cacheCmd)
137 *
138 * TOTAL FUNCTIONS: 84
139 * (This index is automatically created/updated by the extension "extdeveval")
140 *
141 */
142
143
144
145
146 // *******************************
147 // Including necessary libraries
148 // *******************************
149 require_once (PATH_t3lib."class.t3lib_loaddbgroup.php");
150 require_once (PATH_t3lib."class.t3lib_parsehtml_proc.php");
151 require_once (PATH_t3lib."class.t3lib_stdgraphic.php");
152 require_once (PATH_t3lib."class.t3lib_basicfilefunc.php");
153
154
155
156
157
158
159
160
161
162
163
164
165
166 /**
167 * This is the TYPO3 Core Engine class for manipulation of the database
168 * This class is used by eg. the tce_db.php script which provides an the interface for POST forms to this class.
169 *
170 * Dependencies:
171 * - $GLOBALS["TCA"] must exist
172 * - $GLOBALS["LANG"] (languageobject) may be preferred, but not fatal.
173 *
174 * Note: Seems like many instances of array_merge() in this class are candidates for t3lib_div::array_merge() if integer-keys will some day make trouble...
175 *
176 * tce_db.php for further comments and SYNTAX! Also see document "Inside TYPO3" for details.
177 *
178 * @author Kasper Skaarhoj <kasper@typo3.com>
179 * @package TYPO3
180 * @subpackage t3lib
181 */
182 class t3lib_TCEmain {
183 var $debug = 0;
184 var $log_table = "sys_log";
185
186 var $clearCache_like = 0; // If set, the clear_cache function will make a text-search for references to the page-id for which to clear cache and delete cached information for those pages in the result.
187 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
188 var $checkStoredRecords_loose=1; // If set, values '' and 0 will equal each other when the stored records are checked.
189 var $sortIntervals = 256; // The interval between sorting numbers used with tables with a "sorting" field defined. Min 1
190
191 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
192 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
193 var $neverHideAtCopy = 0; // Boolean. If set, then the "hideAtCopy" flag for tables will be ignored.
194 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.
195 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)
196 var $stripslashes_values=1; // If set, incoming values in the data-array have their slashes stripped. This is default, because tce_main expects HTTP_POST_VARS and HTTP_GET_VARS to be slashed (which is probably done in init.php). If you supply your own data to the data-array, you can just unset this flag and slashes will not be stripped then. NOTICE: This flag may be set false by default in the future! ALWAYS supply a stripped (normalized values) array for data!!!!
197 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.
198 var $enableLogging=1; // If set, actions are logged.
199
200 // var $history=1; // Bit-array: Bit0: History on/off. DEPENDS on checkSimilar to be set!
201 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.
202 var $dontProcessTransformations=0; // Boolean: If set, then transformations are NOT performed on the input.
203 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.
204
205 var $pMap = Array( // Permission mapping
206 "show" => 1, // 1st bit
207 "edit" => 2, // 2nd bit
208 "delete" => 4, // 3rd bit
209 "new" => 8, // 4th bit
210 "editcontent" => 16 // 5th bit
211 );
212 var $defaultPermissions = array( // Can be overridden from $TYPO3_CONF_VARS
213 "user" => "show,edit,delete,new,editcontent",
214 "group" => "show,edit,new,editcontent",
215 "everybody" => ""
216 );
217
218
219 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.
220 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.
221 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.
222 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!
223
224 // *********
225 // internal
226 // *********
227 var $fileFunc; // May contain an object
228 var $last_log_id;
229 var $BE_USER; // The user-object the the script uses. If not set from outside, this is set to the current global $BE_USER.
230 var $userid; // will be set to uid of be_user executing this script
231 var $username; // will be set to username of be_user executing this script
232 var $admin; // will be set if user is admin
233 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.
234
235 var $data = Array();
236 var $datamap = Array();
237 var $cmd = Array();
238 var $cmdmap = Array();
239 var $uploadedFileArray = array();
240
241 var $cachedTSconfig = array();
242 var $substNEWwithIDs = Array();
243 var $substNEWwithIDs_table = Array();
244 var $recUpdateAccessCache = Array(); // Used by function checkRecordUpdateAccess() to store whether a record is updatable or not.
245 var $recInsertAccessCache = Array();
246 var $isRecordInWebMount_Cache=array();
247 var $isInWebMount_Cache=array();
248 var $pageCache = Array();
249 var $copyMappingArray = Array(); // Use by the copy action to track the ids of new pages so subpages are correctly inserted!
250 var $copyMappingArray_merged = Array(); // This array is the sum of all copying operations in this class
251 var $registerDBList=array();
252 var $dbAnalysisStore=array();
253 var $removeFilesStore=array();
254 var $copiedFileMap=array();
255
256
257
258
259 /**
260 * Initializing.
261 * For details, see 'Inside TYPO3' document.
262 * This function does not start the processing of data, by merely initializes the object
263 *
264 * @param array Data to be modified or inserted in the database
265 * @param array Commands to copy, move, delete records.
266 * @param object An alternative userobject you can set instead of the default, which is $GLOBALS['BE_USER']
267 * @return void
268 */
269 function start($data,$cmd,$altUserObject='') {
270 // Initializing BE_USER
271 $this->BE_USER = is_object($altUserObject) ? $altUserObject : $GLOBALS['BE_USER'];
272 $this->userid = $this->BE_USER->user['uid'];
273 $this->username = $this->BE_USER->user['username'];
274 $this->admin = $this->BE_USER->user['admin'];
275
276 // Initializing default permissions for pages
277 $defaultPermissions = $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPermissions'];
278 if (isset($defaultPermissions['user'])) {$this->defaultPermissions['user'] = $defaultPermissions['user'];}
279 if (isset($defaultPermissions['group'])) {$this->defaultPermissions['group'] = $defaultPermissions['group'];}
280 if (isset($defaultPermissions['everybody'])) {$this->defaultPermissions['everybody'] = $defaultPermissions['everybody'];}
281
282 // generates the excludelist, based on TCA/exclude-flag and non_exclude_fields for the user:
283 $this->exclude_array = ($this->admin) ? array() : $this->getExcludeListArray();
284
285 // Setting the data and cmd arrays
286 if (is_array($data)) {
287 reset($data);
288 $this->datamap = $data;
289 }
290 if (is_array($cmd)) {
291 reset($cmd);
292 $this->cmdmap = $cmd;
293 }
294
295 // Output debug information
296 if ($this->debug) {
297 echo '<BR>User Information:';
298 debug(Array('username'=>$this->username, 'userid'=>$this->userid, 'admin'=>$this->admin));
299 echo '<BR>DataMap:';
300 debug($this->data);
301 debug($this->datamap);
302 echo '<BR>CommandMap:';
303 debug($this->cmd);
304 debug($this->cmdmap);
305 }
306 }
307
308 /**
309 * [Describe function...]
310 *
311 * @param array This array has the syntax $mirror[table_name][uid] = [list of uids to copy data-value TO!]
312 * @return void
313 */
314 function setMirror($mirror) {
315 if (is_array($mirror)) {
316 reset($mirror);
317 while(list($table,$uid_array)=each($mirror)) {
318 if (isset($this->datamap[$table])) {
319 reset($uid_array);
320 while (list($id,$uidList) = each($uid_array)) {
321 if (isset($this->datamap[$table][$id])) {
322 $theIdsInArray = t3lib_div::trimExplode(',',$uidList,1);
323 while(list(,$copyToUid)=each($theIdsInArray)) {
324 $this->datamap[$table][$copyToUid] = $this->datamap[$table][$id];
325 }
326 }
327 }
328 }
329 }
330 }
331 }
332
333 /**
334 * Initializes default values coming from User TSconfig
335 *
336 * @param array User TSconfig array
337 * @return void
338 */
339 function setDefaultsFromUserTS($userTS) {
340 global $TCA;
341 if (is_array($userTS)) {
342 reset($userTS);
343 while(list($k,$v)=each($userTS)) {
344 $k=substr($k,0,-1);
345 if ($k && is_array($v) && isset($TCA[$k])) {
346 if (is_array($this->defaultValues[$k])) {
347 $this->defaultValues[$k] = array_merge($this->defaultValues[$k],$v);
348 } else {
349 $this->defaultValues[$k] = $v;
350 }
351 }
352 }
353 }
354 }
355
356 /**
357 * Processing of uploaded files.
358 * It turns out that some versions of PHP arranges submitted data for files different if sent in an array. This function will unify this so the internal array $this->uploadedFileArray will always contain files arranged in the same structure.
359 *
360 * @param array HTTP_POST_FILES array
361 * @return void
362 */
363 function process_uploads($postFiles) {
364 if (is_array($postFiles)) {
365 reset($postFiles);
366 $subA = current($postFiles);
367 if (is_array($subA)) {
368 if (is_array($subA['name']) && is_array($subA['type']) && is_array($subA['tmp_name']) && is_array($subA['size'])) {
369 // Initialize the uploadedFilesArray:
370 $this->uploadedFileArray=array();
371
372 // For each entry:
373 foreach($subA as $key => $values) {
374 $this->process_uploads_traverseArray($this->uploadedFileArray,$values,$key);
375 }
376 } else {
377 $this->uploadedFileArray=$subA;
378 }
379 }
380 }
381 }
382
383 /**
384 * Traverse the upload array if needed to rearrange values.
385 *
386 * @param array $this->uploadedFileArray passed by reference
387 * @param array Input array (HTTP_POST_FILES parts)
388 * @param string The current HTTP_POST_FILES array key to set on the outermost level.
389 * @return void
390 * @access private
391 * @see process_uploads()
392 */
393 function process_uploads_traverseArray(&$outputArr,$inputArr,$keyToSet) {
394 if (is_array($inputArr)) {
395 foreach($inputArr as $key => $value) {
396 $this->process_uploads_traverseArray($outputArr[$key],$inputArr[$key],$keyToSet);
397 }
398 } else {
399 $outputArr[$keyToSet]=$inputArr;
400 }
401 }
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417 /*********************************************
418 *
419 * PROCESSING DATA
420 *
421 *********************************************/
422
423 /**
424 * Processing the data-array
425 * Call this function to process the data-array set by start()
426 *
427 * @return [type] ...
428 */
429 function process_datamap() {
430 global $TCA;
431 reset ($this->datamap);
432
433 // 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.
434 $orderOfTables = Array();
435 if (isset($this->datamap['pages'])) { // Set pages first.
436 $orderOfTables[]="pages";
437 }
438 while (list($table,) = each($this->datamap)) {
439 if ($table!="pages") {
440 $orderOfTables[]=$table;
441 }
442 }
443 // Process the tables...
444 reset($orderOfTables);
445 while (list(,$table) = each($orderOfTables)) { // Have found table
446 /* Check if
447 - table is set in $TCA,
448 - table is NOT readOnly,
449 - the table is set with content in the data-array (if not, there's nothing to process...)
450 - permissions for tableaccess OK
451 */
452 $modifyAccessList = $this->checkModifyAccessList($table);
453 if (!$modifyAccessList) {
454 $this->log($table,$id,2,0,1,"Attempt to modify table '%s' without permission",1,array($table));
455 }
456 if (isset($TCA[$table]) && !$this->tableReadOnly($table) && is_array($this->datamap[$table]) && $modifyAccessList) {
457 if ($this->reverseOrder) {
458 $this->datamap[$table] = array_reverse ($this->datamap[$table], 1);
459 }
460 reset ($this->datamap[$table]);
461
462 // For each record from the table, do:
463 // $id is the record uid, may be a string if new records...
464 // $incomingFieldArray is the array of fields
465 while (list($id,$incomingFieldArray) = each($this->datamap[$table])) {
466 if (is_array($incomingFieldArray)) {
467 if ($this->debug) {
468 debug("INCOMING RECORD: ".$table.":".$id);
469 debug($incomingFieldArray);
470 }
471 // ******************************
472 // Checking access to the record
473 // ******************************
474 $recordAccess=0;
475 $old_pid_value = "";
476 if (!t3lib_div::testInt($id)) { // Is it a new record? (Then Id is a string)
477 $fieldArray = $this->newFieldArray($table); // Get a fieldArray with default values
478 if (isset($incomingFieldArray["pid"])) { // A pid must be set for new records.
479 // $value = the pid
480 $pid_value = $incomingFieldArray["pid"];
481
482 // Checking and finding numerical pid, it may be a string-reference to another value
483 $OK = 1;
484 if (strstr($pid_value,"NEW")) { // If a NEW... id
485 if (substr($pid_value,0,1)=="-") {$negFlag=-1;$pid_value=substr($pid_value,1);} else {$negFlag=1;}
486 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.
487 $old_pid_value = $pid_value;
488 $pid_value=intval($negFlag*$this->substNEWwithIDs[$pid_value]);
489 } else {$OK = 0;} // If not found in the substArray we must stop the proces...
490 }
491 $pid_value = intval($pid_value);
492
493 // The $pid_value is now the numerical pid at this point
494 if ($OK) {
495 $sortRow = $TCA[$table]["ctrl"]["sortby"];
496 if ($pid_value>=0) { // Points to a page on which to insert the element, possibly in the top of the page
497 if ($sortRow) { // If this table is sorted we better find the top sorting number
498 $fieldArray[$sortRow] = $this->getSortNumber($table,0,$pid_value);
499 }
500 $fieldArray["pid"] = $pid_value; // The numerical pid is inserted in the data array
501 } else { // points to another record before ifself
502 if ($sortRow) { // If this table is sorted we better find the top sorting number
503 $tempArray=$this->getSortNumber($table,0,$pid_value); // Because $pid_value is < 0, getSortNumber returns an array
504 $fieldArray["pid"] = $tempArray["pid"];
505 $fieldArray[$sortRow] = $tempArray["sortNumber"];
506 } else { // Here we fetch the PID of the record that we point to...
507 $tempdata = $this->recordInfo($table,abs($pid_value),"pid");
508 $fieldArray["pid"]=$tempdata["pid"];
509 }
510 }
511 }
512 }
513 $theRealPid = $fieldArray["pid"];
514 // Now, check if we may insert records on this pid.
515 if ($theRealPid>=0) {
516 $recordAccess = $this->checkRecordInsertAccess($table,$theRealPid); // Checks if records can be inserted on this $pid.
517 } else {
518 debug("Internal ERROR: pid should not be less than zero!");
519 }
520 $status='new'; // Yes new record, change $record_status to 'insert'
521 } else { // Nope... $id is a number
522 $fieldArray = Array();
523 $recordAccess = $this->checkRecordUpdateAccess($table,$id);
524 if (!$recordAccess) {
525 $propArr = $this->getRecordProperties($table,$id);
526 $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"]);
527 } else { // Here we fetch the PID of the record that we point to...
528 $tempdata = $this->recordInfo($table,$id,"pid");
529 $theRealPid=$tempdata["pid"];
530 }
531 $status='update'; // the default is 'update'
532 }
533
534 if ($this->debug) {debug("STATUS: ".$status." RecordAccess:".$recordAccess); }
535 // **************************************
536 // If access was granted above, proceed:
537 // **************************************
538 if ($recordAccess) {
539 //debug("tce_main",-2);
540 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.
541 $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
542 //debug($TSConfig);
543 if ($status=="new" && $table=="pages" && is_array($TSConfig["permissions."])) {
544 $fieldArray = $this->setTSconfigPermissions($fieldArray,$TSConfig["permissions."]);
545 }
546
547 //debug(array($table,$tscPID));
548
549 $fieldArray = $this->fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$theRealPid,$status,$tscPID);
550 $fieldArray = $this->overrideFieldArray($table,$fieldArray);
551
552 // Setting system fields
553 if ($status=="new") {
554 if ($TCA[$table]["ctrl"]["crdate"]) {
555 $fieldArray[$TCA[$table]["ctrl"]["crdate"]]=time();
556 }
557 if ($TCA[$table]["ctrl"]["cruser_id"]) {
558 $fieldArray[$TCA[$table]["ctrl"]["cruser_id"]]=$this->userid;
559 }
560 } elseif ($this->checkSimilar) {
561 $fieldArray = $this->compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray);
562 }
563 if ($TCA[$table]["ctrl"]["tstamp"]) {
564 $fieldArray[$TCA[$table]["ctrl"]["tstamp"]]=time();
565 }
566
567 // Performing insert/update
568 if ($status=="new") {
569 // 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!
570 $this->insertDB($table,$id,$fieldArray);
571 } else {
572 $this->updateDB($table,$id,$fieldArray);
573 }
574 } // if ($recordAccess) {
575 } // if (is_array($incomingFieldArray)) {
576 }
577 }
578 }
579 $this->dbAnalysisStoreExec();
580 $this->removeRegisteredFiles();
581 }
582
583 /**
584 * Filling in the field array
585 *
586 * $incomingFieldArray is which fields/values you want to set
587 * Preset $fieldArray with "pid" maybe (pid and uid will be not be overridden anyway)
588 * $this->exclude_array is used to filter fields if needed.
589 * $status = "new" or "update"
590 *
591 * @param [type] $table: ...
592 * @param [type] $id: ...
593 * @param [type] $fieldArray: ...
594 * @param [type] $incomingFieldArray: ...
595 * @param [type] $realPid: ...
596 * @param [type] $status: ...
597 * @param [type] $tscPID: ...
598 * @return [type] ...
599 */
600 function fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$realPid,$status,$tscPID) {
601 global $TCA;
602 $fieldArray_orig = $fieldArray;
603 t3lib_div::loadTCA($table);
604 /*
605 In the following all incoming value-fields are tested:
606 - Are the user allowed to change the field?
607 - Is the field uid/pid (which are already set)
608 - perms-fields for pages-table, then do special things...
609 - If the field is nothing of the above and the field is configured in TCA, the fieldvalues are evaluated by ->checkValue
610
611 If everything is OK, the field is entered into $fieldArray[]
612 */
613 reset ($incomingFieldArray); // Reset the array of fields
614 while (list($field,$fieldValue) = each($incomingFieldArray)) {
615 if (!in_array($table."-".$field, $this->exclude_array) && !$this->data_disableFields[$table][$id][$field]) { // The field must be editable.
616 if ($this->stripslashes_values) {
617 if (is_array($fieldValue)) {
618 t3lib_div::stripSlashesOnArray($fieldValue);
619 } else $fieldValue=stripslashes($fieldValue);
620 } // Strip slashes
621 switch ($field) {
622 case "uid":
623 case "pid":
624 // Nothing happens, already set
625 break;
626 case "perms_userid":
627 case "perms_groupid":
628 case "perms_user":
629 case "perms_group":
630 case "perms_everybody":
631 // Permissions can be edited by the owner or the administrator
632 if ($table=="pages" && ($this->admin || $status=="new" || $this->pageInfo($id,"perms_userid")==$this->userid) ) {
633 $value=intval($fieldValue);
634 switch($field) {
635 case "perms_userid":
636 $fieldArray[$field]=$value;
637 break;
638 case "perms_groupid":
639 $fieldArray[$field]=$value;
640 break;
641 default:
642 if ($value>=0 && $value<pow(2,5)) {
643 $fieldArray[$field]=$value;
644 }
645 break;
646 }
647 }
648 break;
649 default:
650 if (isset($TCA[$table]["columns"][$field])) {
651 // Evaluating the value.
652 $res = $this->checkValue($table,$field,$fieldValue,$id,$status,$realPid);
653 if (isset($res["value"])) {
654 $fieldArray[$field]=$res["value"];
655 }
656 }
657 break;
658 }
659 }
660 }
661
662 // Checking for RTE-transformations of fields:
663 if (strstr($id,"NEW")) {
664 $currentRecord = $fieldArray_orig; // changed to "_orig" 170502 - must have the "current" array - not the values set in the form.
665 } else {
666 $currentRecord = $this->recordInfo($table,$id,"*"); // We must use the current values as basis for this!
667 }
668 //debug($currentRecord);
669 // debug($id);
670 $types_fieldConfig=t3lib_BEfunc::getTCAtypes($table,$currentRecord);
671 $theTypeString = t3lib_BEfunc::getTCAtypeValue($table,$currentRecord);
672 if (is_array($types_fieldConfig)) {
673 reset($types_fieldConfig);
674 while(list(,$vconf)=each($types_fieldConfig)) {
675 // Write file configuration:
676 $eFile=t3lib_parsehtml_proc::evalWriteFile($vconf["spec"]["static_write"],array_merge($currentRecord,$fieldArray)); // inserted array_merge($currentRecord,$fieldArray) 170502
677 //debug($eFile);
678 // RTE transformations:
679 if (!$this->dontProcessTransformations) {
680 if ($vconf["spec"]["richtext"] && !$this->disableRTE) {
681 // Cross transformation?
682 $this->crossRTEtransformation=0; // Crosstransformation is, when a record is saved, the CType has changed and the other type might also use the RTE - then the transformation of THAT rte is used instead. This is usefull only if we know the TBE interface did it, because in that interface the CType value changes the interface and allows extended options in RTE without first saving the type-shift.
683 if ($this->crossRTEtransformation) {
684 $next_types_fieldConfig=t3lib_BEfunc::getTCAtypes($table,array_merge($currentRecord,$fieldArray),1);
685 if ($next_types_fieldConfig[$vconf["field"]]["spec"]["richtext"]) { // RTE must be enabled for the fields
686 $vconf["spec"] = $next_types_fieldConfig[$vconf["field"]]["spec"];
687 $theTypeString = t3lib_BEfunc::getTCAtypeValue($table,array_merge($currentRecord,$fieldArray));
688 }
689 }
690 //debug($theTypeString);
691 // transform if...
692 if ($vconf["spec"]["rte_transform"]) {
693 $p=t3lib_BEfunc::getSpecConfParametersFromArray($vconf["spec"]["rte_transform"]["parameters"]);
694 if ($p["mode"]) { // There must be a mode set for transformation
695 if (isset($fieldArray[$vconf["field"]])) {
696 if ($tscPID>=0) {
697 //debug("RTEsetup");
698 $RTEsetup = $this->BE_USER->getTSConfig("RTE",t3lib_BEfunc::getPagesTSconfig($tscPID));
699 $thisConfig = t3lib_BEfunc::RTEsetup($RTEsetup["properties"],$table,$vconf["field"],$theTypeString);
700 if (!$thisConfig["disabled"] && (!$p["flag"] || !$currentRecord[$p["flag"]]) && $this->BE_USER->isRTE()) { // ... and any disable flag should not be set!
701 $parseHTML = t3lib_div::makeInstance("t3lib_parsehtml_proc");
702 $parseHTML->init($table.":".$vconf["field"],$currentRecord["pid"]);
703 if (is_array($eFile)) {$parseHTML->setRelPath(dirname($eFile["relEditFile"]));}
704 $fieldArray[$vconf["field"]]=$parseHTML->RTE_transform($fieldArray[$vconf["field"]],$vconf["spec"],"db",$thisConfig);
705 }
706 }
707 }
708 }
709 }
710 }
711 }
712
713 // Write file configuration:
714 if (is_array($eFile)) {
715 $mixedRec = array_merge($currentRecord,$fieldArray);
716 $SW_fileContent = t3lib_div::getUrl($eFile["editFile"]);
717 $parseHTML = t3lib_div::makeInstance("t3lib_parsehtml_proc");
718 $parseHTML->init("","");
719
720 $eFileMarker = $eFile["markerField"]&&trim($mixedRec[$eFile["markerField"]]) ? trim($mixedRec[$eFile["markerField"]]) : "###TYPO3_STATICFILE_EDIT###";
721 $insertContent = str_replace($eFileMarker,"",$mixedRec[$eFile["contentField"]]); // must replace the marker if present in content!
722
723 $SW_fileNewContent = $parseHTML->substituteSubpart(
724 $SW_fileContent,
725 $eFileMarker,
726 chr(10).$insertContent.chr(10),
727 1,1);
728 t3lib_div::writeFile($eFile["editFile"],$SW_fileNewContent);
729
730 // Write status:
731 if (!strstr($id,"NEW") && $eFile["statusField"]) {
732 $SWq = t3lib_BEfunc::DBcompileUpdate($table,"uid=".intval($id),
733 array(
734 $eFile["statusField"]=>$eFile["relEditFile"]." updated ".date("d-m-Y H:i:s").", bytes ".strlen($mixedRec[$eFile["contentField"]])
735 )
736 );
737 mysql(TYPO3_db,$SWq);
738 }
739 } elseif ($eFile && is_string($eFile)) {
740 $this->log($insertTable,$id,2,0,1,"Write-file error: '%s'",13,array($eFile),$realPid);
741 }
742 }
743 }
744 // Return fieldArray
745 return $fieldArray;
746 }
747
748 /**
749 * Checking group modify_table access list
750 *
751 * Returns true if the user has general access to modify the $table
752 *
753 * @param [type] $table: ...
754 * @return [type] ...
755 */
756 function checkModifyAccessList($table) {
757 $res = ($this->admin || (!$this->tableAdminOnly($table) && t3lib_div::inList($this->BE_USER->groupData["tables_modify"],$table)));
758 return $res;
759 }
760
761 /**
762 * [Describe function...]
763 *
764 * @param [type] $table: ...
765 * @param [type] $id: ...
766 * @return [type] ...
767 */
768 function isRecordInWebMount($table,$id) {
769 if (!isset($this->isRecordInWebMount_Cache[$table.":".$id])) {
770 $recP=$this->getRecordProperties($table,$id);
771 $this->isRecordInWebMount_Cache[$table.":".$id]=$this->isInWebMount($recP["event_pid"]);
772 }
773 return $this->isRecordInWebMount_Cache[$table.":".$id];
774 }
775
776 /**
777 * [Describe function...]
778 *
779 * @param [type] $pid: ...
780 * @return [type] ...
781 */
782 function isInWebMount($pid) {
783 if (!isset($this->isInWebMount_Cache[$pid])) {
784 $this->isInWebMount_Cache[$pid]=$this->BE_USER->isInWebMount($pid);
785 }
786 //debug($this->isInWebMount_Cache);
787 return $this->isInWebMount_Cache[$pid];
788 }
789
790 /**
791 * Checks if user may update a certain record.
792 *
793 * Returns true if the user may update the record given by $table and $id
794 *
795 * @param [type] $table: ...
796 * @param [type] $id: ...
797 * @return [type] ...
798 */
799 function checkRecordUpdateAccess($table,$id) {
800 global $TCA;
801 $res = 0;
802 if ($TCA[$table] && intval($id)>0) {
803 if (isset($this->recUpdateAccessCache[$table][$id])) { // If information is cached, return it
804 return $this->recUpdateAccessCache[$table][$id];
805 // Check if record exists and 1) if "pages" the page may be edited, 2) if page-content the page allows for editing
806 } elseif ($this->doesRecordExist($table,$id,"edit")) {
807 $res = 1;
808 }
809 $this->recUpdateAccessCache[$table][$id]=$res; // Cache the result
810 }
811 return $res;
812 }
813
814 /**
815 * Checks if user may insert a certain record.
816 *
817 * Returns true if the user may insert a record from table $insertTable on page $pid
818 *
819 * @param [type] $insertTable: ...
820 * @param [type] $pid: ...
821 * @param [type] $action: ...
822 * @return [type] ...
823 */
824 function checkRecordInsertAccess($insertTable,$pid,$action=1) {
825 global $TCA;
826 $res = 0;
827 $pid = intval($pid);
828 if ($pid>=0) {
829 if (isset($this->recInsertAccessCache[$insertTable][$pid])) { // If information is cached, return it
830 return $this->recInsertAccessCache[$insertTable][$pid];
831 } else {
832 // 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
833 if ( (!$pid && $this->admin) || $this->doesRecordExist("pages",$pid,($insertTable=="pages"?$this->pMap["new"]:$this->pMap["editcontent"])) ) { // Check permissions
834 if ($this->isTableAllowedForThisPage($pid, $insertTable)) {
835 $res = 1;
836 $this->recInsertAccessCache[$insertTable][$pid]=$res; // Cache the result
837 } else {
838 $propArr = $this->getRecordProperties("pages",$pid);
839 $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"]);
840 }
841 } else {
842 $propArr = $this->getRecordProperties("pages",$pid);
843 $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"]);
844 }
845 }
846 }
847 return $res;
848 }
849
850 /**
851 * Checks is a table is allowed on a certain page.
852 *
853 * $checkTable is the tablename
854 * $page_uid is the uid of the page to check
855 *
856 * @param [type] $page_uid: ...
857 * @param [type] $checkTable: ...
858 * @return [type] ...
859 */
860 function isTableAllowedForThisPage($page_uid, $checkTable) {
861 global $TCA, $PAGES_TYPES;
862 $page_uid = intval($page_uid);
863
864 // 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.
865 if (($TCA[$checkTable]["ctrl"]["rootLevel"] xor !$page_uid) && $TCA[$checkTable]["ctrl"]["rootLevel"]!=-1 && $checkTable!="pages") {
866 return false;
867 }
868
869 // Check root-level
870 if (!$page_uid) {
871 if ($this->admin) {
872 return true;
873 }
874 } else {
875 // Check non-root-level
876 $doktype = $this->pageInfo($page_uid,"doktype");
877 $allowedTableList = isset($PAGES_TYPES[$doktype]["allowedTables"]) ? $PAGES_TYPES[$doktype]["allowedTables"] : $PAGES_TYPES["default"]["allowedTables"];
878 $allowedArray = t3lib_div::trimExplode(",",$allowedTableList,1);
879 if (strstr($allowedTableList,"*") || in_array($checkTable,$allowedArray)) { // If all tables or the table is listed as a allowed type, return true
880 return true;
881 }
882 }
883 }
884
885 /**
886 * Checks if record exists
887 *
888 * Returns true if the record given by $table,$id and $perms (which is either a number that is bitwise AND'ed or a string, which points to a key in the ->pMap array)
889 *
890 * @param [type] $table: ...
891 * @param [type] $id: ...
892 * @param [type] $perms: ...
893 * @return [type] ...
894 */
895 function doesRecordExist($table,$id,$perms) {
896 global $TCA;
897
898 $res = 0;
899 $id = intval($id);
900
901 // Processing the incoming $perms
902 if (!t3lib_div::testInt($perms)) {
903 if ($table!="pages") {
904 switch($perms) {
905 case "edit":
906 case "delete":
907 case "new":
908 $perms = "editcontent"; // This holds it all in case the record is not page!!
909 break;
910 }
911 }
912 $perms=intval($this->pMap[$perms]);
913 } else {
914 $perms = intval($perms);
915 }
916
917 if (!$perms) {debug("Internal ERROR: no permissions to check for non-admin user.");}
918
919 // For all tables: Check if record exists:
920 // Notice: If $perms are 0 (zero) no perms-clause is added!
921 if ($TCA[$table] && $id>0 && ($this->isRecordInWebMount($table,$id)||$this->admin)) { // 130502: added isRecordInWebMount() to check for pages being inside the page mounts...!
922 if ($table != "pages") {
923 $query = "select $table.uid from $table,pages where $table.pid=pages.uid && $table.uid=".$id.$this->deleteClause("pages");
924 if ($perms && !$this->admin) { $query.=" AND ".$this->BE_USER->getPagePermsClause($perms); } // admin users don't need check
925 $mres = mysql(TYPO3_db,$query);
926 echo mysql_error();
927 if (mysql_num_rows($mres)) {
928 return true;
929 } else {
930 if ($this->admin) { // admin may do stuff on records in the root
931 $query = "select uid from $table where uid=".$id.$this->deleteClause($table);
932 $mres = mysql(TYPO3_db,$query);
933 return mysql_num_rows($mres);
934 }
935 }
936 } else {
937 $query = "select uid from pages where uid=".$id.$this->deleteClause("pages");
938 if ($perms && !$this->admin) { $query.=" AND ".$this->BE_USER->getPagePermsClause($perms); } // admin users don't need check
939 $mres = mysql(TYPO3_db,$query);
940 return mysql_num_rows($mres);
941 }
942 }
943 }
944
945 /**
946 * Checks if a whole branch of pages exists
947 *
948 * Tests the branch under $pid (like doesRecordExist). It doesn't test the page with $pid as uid. Use doesRecordExist() for this purpose
949 * Returns an ID-list or "" if OK. Else -1 which means that somewhere there was no permission (eg. to delete).
950 * if $recurse is set, then the function will follow subpages. This MUST be set, if we need the idlist for deleting pages or else we get an incomplete list
951 *
952 * @param [type] $inList: ...
953 * @param [type] $pid: ...
954 * @param [type] $perms: ...
955 * @param [type] $recurse: ...
956 * @return [type] ...
957 */
958 function doesBranchExist($inList,$pid,$perms, $recurse) {
959 global $TCA;
960 $pid = intval($pid);
961 $perms = intval($perms);
962 if ($pid>=0) {
963 $query = "select uid, perms_userid, perms_groupid, perms_user, perms_group, perms_everybody from pages where pid=".$pid.$this->deleteClause("pages")." order by sorting";
964 $mres = mysql(TYPO3_db,$query);
965 while ($row = mysql_fetch_assoc($mres)) {
966 if ($this->admin || $this->BE_USER->doesUserHaveAccess($row,$perms)) { // IF admin, then it's OK
967 $inList.=$row['uid'].",";
968 if ($recurse) { // Follow the subpages recursively...
969 $inList = $this->doesBranchExist($inList, $row['uid'], $perms, $recurse);
970 if ($inList == -1) {return -1;} // No permissions somewhere in the branch
971 }
972 } else {
973 return -1; // No permissions
974 }
975 }
976 }
977 return $inList;
978 }
979
980 /**
981 * Returns the value of the $field from page $id
982 *
983 * @param [type] $id: ...
984 * @param [type] $field: ...
985 * @return [type] ...
986 */
987 function pageInfo($id,$field) {
988 if (!isset($this->pageCache[$id])) {
989 $res = mysql(TYPO3_db,"select * from pages where uid='$id'");
990 if (mysql_num_rows($res)) {
991 $this->pageCache[$id]=mysql_fetch_assoc($res);
992 }
993 }
994 return $this->pageCache[$id][$field];
995 }
996
997 /**
998 * Returns the row of a record given by $table and $id and $fieldList (list of fields, may be "*")
999 *
1000 * No check for deleted or access!
1001 *
1002 * @param [type] $table: ...
1003 * @param [type] $id: ...
1004 * @param [type] $fieldList: ...
1005 * @return [type] ...
1006 */
1007 function recordInfo($table,$id,$fieldList) {
1008 global $TCA;
1009 if ($TCA[$table]) {
1010 $res = mysql(TYPO3_db,'SELECT '.$fieldList.' FROM '.$table.' WHERE uid='.intval($id));
1011 if (mysql_num_rows($res)) {
1012 return mysql_fetch_assoc($res);
1013 }
1014 }
1015 }
1016
1017 /**
1018 * Returns an array with record properties, like header and pid
1019 *
1020 * @param [type] $table: ...
1021 * @param [type] $id: ...
1022 * @return [type] ...
1023 */
1024 function getRecordProperties($table,$id) {
1025 $row = ($table=="pages" && !$id) ? array("title"=>"[root-level]", "uid" => 0, "pid" => 0) :$this->recordInfo($table,$id,"*");
1026 return $this->getRecordPropertiesFromRow($table,$row);
1027 }
1028
1029 /**
1030 * Returns an array with record properties, like header and pid, based on the row
1031 *
1032 * @param [type] $table: ...
1033 * @param [type] $row: ...
1034 * @return [type] ...
1035 */
1036 function getRecordPropertiesFromRow($table,$row) {
1037 global $TCA;
1038 if ($TCA[$table]) {
1039 $out = array(
1040 "header" => $row[$TCA[$table]["ctrl"]["label"]],
1041 "pid" => $row["pid"],
1042 "event_pid" => ($table=="pages"?$row["uid"]:$row["pid"])
1043 );
1044 return $out;
1045 }
1046 }
1047
1048 /**
1049 * [Describe function...]
1050 *
1051 * @param [type] $fieldArray: ...
1052 * @param [type] $TSConfig_p: ...
1053 * @return [type] ...
1054 */
1055 function setTSconfigPermissions($fieldArray,$TSConfig_p) {
1056 if (strcmp($TSConfig_p["userid"],"")) $fieldArray["perms_userid"]=intval($TSConfig_p["userid"]);
1057 if (strcmp($TSConfig_p["groupid"],"")) $fieldArray["perms_groupid"]=intval($TSConfig_p["groupid"]);
1058 if (strcmp($TSConfig_p["user"],"")) $fieldArray["perms_user"]=t3lib_div::testInt($TSConfig_p["user"]) ? $TSConfig_p["user"] : $this->assemblePermissions($TSConfig_p["user"]);
1059 if (strcmp($TSConfig_p["group"],"")) $fieldArray["perms_group"]=t3lib_div::testInt($TSConfig_p["group"]) ? $TSConfig_p["group"] : $this->assemblePermissions($TSConfig_p["group"]);
1060 if (strcmp($TSConfig_p["everybody"],"")) $fieldArray["perms_everybody"]=t3lib_div::testInt($TSConfig_p["everybody"]) ? $TSConfig_p["everybody"] : $this->assemblePermissions($TSConfig_p["everybody"]);
1061
1062 return $fieldArray;
1063 }
1064
1065 /**
1066 * Returns a fieldArray with default values.
1067 *
1068 * @param [type] $table: ...
1069 * @return [type] ...
1070 */
1071 function newFieldArray($table) {
1072 global $TCA;
1073 t3lib_div::loadTCA($table);
1074 $fieldArray=Array();
1075 if (is_array($TCA[$table]["columns"])) {
1076 reset ($TCA[$table]["columns"]);
1077 while (list($field,$content)=each($TCA[$table]["columns"])) {
1078 if (isset($this->defaultValues[$table][$field])) {
1079 $fieldArray[$field] = $this->defaultValues[$table][$field];
1080 } elseif (isset($content["config"]["default"])) {
1081 $fieldArray[$field] = $content["config"]["default"];
1082 }
1083 }
1084 }
1085 if ($table=="pages") { // Set default permissions for a page.
1086 $fieldArray["perms_userid"] = $this->userid;
1087 $fieldArray["perms_groupid"] = intval($this->BE_USER->firstMainGroup);
1088 $fieldArray["perms_user"] = $this->assemblePermissions($this->defaultPermissions["user"]);
1089 $fieldArray["perms_group"] = $this->assemblePermissions($this->defaultPermissions["group"]);
1090 $fieldArray["perms_everybody"] = $this->assemblePermissions($this->defaultPermissions["everybody"]);
1091 }
1092 return $fieldArray;
1093 }
1094
1095 /**
1096 * Returns the $data array from $table overridden in the fields defined in ->overrideValues.
1097 *
1098 * @param [type] $table: ...
1099 * @param [type] $data: ...
1100 * @return [type] ...
1101 */
1102 function overrideFieldArray($table,$data) {
1103 if (is_array($this->overrideValues[$table])) {
1104 $data = array_merge($data,$this->overrideValues[$table]); // Candidate for t3lib_div::array_merge() if integer-keys will some day make trouble...
1105 }
1106 return $data;
1107 }
1108
1109 /**
1110 * Calculates the bitvalue of the permissions given in a string, comma-sep
1111 *
1112 * @param [type] $string: ...
1113 * @return [type] ...
1114 */
1115 function assemblePermissions($string) {
1116 $keyArr = t3lib_div::trimExplode(",",$string,1);
1117 $value=0;
1118 while(list(,$key)=each($keyArr)) {
1119 if ($key && isset($this->pMap[$key])) {
1120 $value |= $this->pMap[$key];
1121 }
1122 }
1123 return $value;
1124 }
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145 /*********************************************
1146 *
1147 * Evaluation of input values
1148 *
1149 ********************************************/
1150
1151 /**
1152 * Evaluates a value according to $table/$field settings.
1153 * This function is for real database field - not FlexForm fields.
1154 * NOTICE: Calling this function expects this: 1) That the data is saved! (files are copied and so on) 2) That files registered for deletion IS deleted at the end (with ->removeRegisteredFiles() )
1155 *
1156 * @param string Table name
1157 * @param string Field name
1158 * @param string Value to be evaluated. Notice, this is the INPUT value from the form. The original value (from any existing record) must be manually looked up inside the function if needed.
1159 * @param string The record-uid, mainly - but not exclusively - used for logging
1160 * @param string "update" or "new" flag
1161 * @param [type] $realPid: ...
1162 * @return string Returns the evaluated $value
1163 */
1164 function checkValue($table,$field,$value,$id,$status,$realPid) {
1165 global $TCA, $PAGES_TYPES;
1166 t3lib_div::loadTCA($table);
1167
1168 $res = Array(); // result array
1169 $recFID = $table.':'.$id.':'.$field;
1170
1171 // Processing special case of field pages.doktype
1172 if ($table=='pages' && $field=='doktype') {
1173 // If the user may not use this specific doktype, we issue a warning
1174 if (! ($this->admin || t3lib_div::inList($this->BE_USER->groupData['pagetypes_select'],$value))) {
1175 $propArr = $this->getRecordProperties($table,$id);
1176 $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']);
1177 return $res;
1178 };
1179 if ($status=='update') {
1180 // This checks if 1) we should check for disallowed tables and 2) the there are records from disallowed tables on the current page
1181 $onlyAllowedTables = isset($PAGES_TYPES[$value]['onlyAllowedTables']) ? $PAGES_TYPES[$value]['onlyAllowedTables'] : $PAGES_TYPES['default']['onlyAllowedTables'];
1182 if ($onlyAllowedTables) {
1183 $theWrongTables = $this->doesPageHaveUnallowedTables($id,$value);
1184 if ($theWrongTables) {
1185 $propArr = $this->getRecordProperties($table,$id);
1186 $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']);
1187 return $res;
1188 }
1189 }
1190 }
1191 }
1192
1193 // Get current value:
1194 $curValueRec = $this->recordInfo($table,$id,$field);
1195 $curValue = $curValueRec[$field];
1196
1197 // Getting config for the field
1198 $tcaFieldConf = $TCA[$table]['columns'][$field]['config'];
1199
1200 // Preform processing:
1201 $res = $this->checkValue_SW($res,$value,$tcaFieldConf,$table,$id,$curValue,$status,$realPid,$recFID,$field,$this->uploadedFileArray[$table][$id][$field]);
1202
1203 return $res;
1204 }
1205
1206 /**
1207 * @param [type] $res: ...
1208 * @param [type] $value: ...
1209 * @param [type] $tcaFieldConf: ...
1210 * @param [type] $table: ...
1211 * @param [type] $id: ...
1212 * @param [type] $curValue: ...
1213 * @param [type] $status: ...
1214 * @param [type] $realPid: ...
1215 * @param [type] $recFID: ...
1216 * @param string Field name. Must NOT be set if the call is for a flexform field (since flexforms are not allowed within flexforms).
1217 * @param [type] $uploadedFiles: ...
1218 * @return [type] ...
1219 */
1220 function checkValue_SW($res,$value,$tcaFieldConf,$table,$id,$curValue,$status,$realPid,$recFID,$field,$uploadedFiles) {
1221 switch ($tcaFieldConf['type']) {
1222 case 'text':
1223 case 'passthrough':
1224 $res['value']=$value;
1225 break;
1226 case 'input':
1227 $res = $this->checkValue_input($res,$value,$tcaFieldConf,array($table,$id,$curValue,$status,$realPid,$recFID),$field);
1228 break;
1229 case 'check':
1230 $res = $this->checkValue_check($res,$value,$tcaFieldConf,array($table,$id,$curValue,$status,$realPid,$recFID));
1231 break;
1232 case 'radio':
1233 $res = $this->checkValue_radio($res,$value,$tcaFieldConf,array($table,$id,$curValue,$status,$realPid,$recFID));
1234 break;
1235 case 'group':
1236 case 'select':
1237 $res = $this->checkValue_group_select($res,$value,$tcaFieldConf,array($table,$id,$curValue,$status,$realPid,$recFID),$uploadedFiles);
1238 break;
1239 case 'flex':
1240 if ($field) { // FlexForms are only allowed for real fields.
1241 $res = $this->checkValue_flex($res,$value,$tcaFieldConf,array($table,$id,$curValue,$status,$realPid,$recFID),$uploadedFiles,$this->recordInfo($table,$id,'*'),$field);
1242 }
1243 break;
1244 }
1245
1246 return $res;
1247 }
1248
1249 /**
1250 * Evaluate "input" type values.
1251 *
1252 * @param array The result array. The processed value (if any!) is set in the "value" key.
1253 * @param string The value to set.
1254 * @param array Field configuration from TCA
1255 * @param array Additional parameters in a numeric array: $table,$id,$curValue,$status,$realPid,$recFID
1256 * @param [type] $field: ...
1257 * @return array Modified $res array
1258 */
1259 function checkValue_input($res,$value,$tcaFieldConf,$PP,$field='') {
1260 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
1261
1262 // Secures the string-length to be less than max. Will probably make problems with multi-byte strings!
1263 if (intval($tcaFieldConf['max'])>0) {$value = substr($value,0,intval($tcaFieldConf['max']));}
1264
1265 // Checking range of value:
1266 if ($tcaFieldConf['range'] && $value!=$tcaFieldConf['checkbox']) { // If value is not set to the allowed checkbox-value then it is checked against the ranges
1267 if (isset($tcaFieldConf['range']['upper'])&&$value>$tcaFieldConf['range']['upper']) {$value=$tcaFieldConf['range']['upper'];}
1268 if (isset($tcaFieldConf['range']['lower'])&&$value<$tcaFieldConf['range']['lower']) {$value=$tcaFieldConf['range']['lower'];}
1269 }
1270
1271 // Process evaluation settings:
1272 $evalCodesArray = t3lib_div::trimExplode(',',$tcaFieldConf['eval'],1);
1273 $res = $this->checkValue_input_Eval($value,$evalCodesArray,$tcaFieldConf['is_in']);
1274
1275 // Process UNIQUE settings:
1276 if ($field) { // Field is NOT set for flexForms - which also means that uniqueInPid and unique is NOT available for flexForm fields!
1277 if ($res['value'] && in_array('uniqueInPid',$evalCodesArray)) {
1278 $res['value'] = $this->getUnique($table,$field,$res['value'],$id,$realPid);
1279 }
1280 if ($res['value'] && in_array('unique',$evalCodesArray)) {
1281 $res['value'] = $this->getUnique($table,$field,$res['value'],$id);
1282 }
1283 }
1284
1285 return $res;
1286 }
1287
1288 /**
1289 * Evaluates "check" type values.
1290 *
1291 * @param array The result array. The processed value (if any!) is set in the "value" key.
1292 * @param string The value to set.
1293 * @param array Field configuration from TCA
1294 * @param array Additional parameters in a numeric array: $table,$id,$curValue,$status,$realPid,$recFID
1295 * @return array Modified $res array
1296 */
1297 function checkValue_check($res,$value,$tcaFieldConf,$PP) {
1298 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
1299
1300 $itemC = count($tcaFieldConf['items']);
1301 if (!$itemC) {$itemC=1;}
1302 $maxV = pow(2,$itemC);
1303
1304 if ($value<0) {$value=0;}
1305 if ($value>$maxV) {$value=$maxV;}
1306 $res['value'] = $value;
1307
1308 return $res;
1309 }
1310
1311 /**
1312 * Evaluates "radio" type values.
1313 *
1314 * @param array The result array. The processed value (if any!) is set in the "value" key.
1315 * @param string The value to set.
1316 * @param array Field configuration from TCA
1317 * @param array Additional parameters in a numeric array: $table,$id,$curValue,$status,$realPid,$recFID
1318 * @return array Modified $res array
1319 */
1320 function checkValue_radio($res,$value,$tcaFieldConf,$PP) {
1321 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
1322
1323 if (is_array($tcaFieldConf['items'])) {
1324 foreach($tcaFieldConf['items'] as $set) {
1325 if (!strcmp($set[1],$value)) {
1326 $res['value'] = $value;
1327 break;
1328 }
1329 }
1330 }
1331
1332 return $res;
1333 }
1334
1335 /**
1336 * Evaluates "group" or "select" type values.
1337 *
1338 * @param array The result array. The processed value (if any!) is set in the "value" key.
1339 * @param string The value to set.
1340 * @param array Field configuration from TCA
1341 * @param array Additional parameters in a numeric array: $table,$id,$curValue,$status,$realPid,$recFID
1342 * @param [type] $uploadedFiles: ...
1343 * @return array Modified $res array
1344 */
1345 function checkValue_group_select($res,$value,$tcaFieldConf,$PP,$uploadedFiles) {
1346 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
1347
1348 // This converts all occurencies of "&#123;" to the byte 123 in the string - this is needed in very rare cases where filenames with special characters (like æøå, umlaud etc) gets sent to the server as HTML entities instead of bytes. The error is done only by MSIE, not MOzilla and Opera.
1349 // Anyways, this should NOT disturb anything else:
1350 $value = $this->convNumEntityToByteValue($value);
1351
1352 // When values are send as group or select they come as comma-separated values which are exploded by this function:
1353 $valueArray = $this->checkValue_group_select_explodeSelectGroupValue($value);
1354
1355 // If not multiple is set, then remove duplicates:
1356 if (!$tcaFieldConf['multiple']) {
1357 $valueArray = array_unique($valueArray);
1358 }
1359
1360 // This could be a good spot for parsing the array through a validation-function which checks if the values are allright
1361 // NOTE!!! Must check max-items of files before the later check because that check would just leave out filenames if there are too many!!
1362
1363
1364
1365 // For group types:
1366 if ($tcaFieldConf['type']=='group') {
1367 switch($tcaFieldConf['internal_type']) {
1368 case 'file':
1369 $valueArray = $this->checkValue_group_select_file(
1370 $valueArray,
1371 $tcaFieldConf,
1372 $curValue,
1373 $uploadedFiles,
1374 $status,
1375 $table,
1376 $id,
1377 $recFID
1378 );
1379 break;
1380 case 'db':
1381 $valueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'group');
1382 break;
1383 }
1384 }
1385 // For select types which has a foreign table attached:
1386 if ($tcaFieldConf['type']=='select' && $tcaFieldConf['foreign_table']) {
1387 $valueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'select');
1388 }
1389
1390
1391
1392 // Checking the number of items, that it is correct.
1393 // If files, there MUST NOT be too many files in the list at this point, so check that prior to this code.
1394 $valueArrayC = count($valueArray);
1395 $minI = isset($tcaFieldConf['minitems']) ? intval($tcaFieldConf['minitems']):0;
1396
1397 // 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.
1398 $maxI = isset($tcaFieldConf['maxitems']) ? intval($tcaFieldConf['maxitems']):1;
1399 if ($valueArrayC > $maxI) {$valueArrayC=$maxI;} // Checking for not too many elements
1400
1401 // Dumping array to list
1402 $newVal=array();
1403 foreach($valueArray as $nextVal) {
1404 if ($valueArrayC==0) {break;}
1405 $valueArrayC--;
1406 $newVal[]=$nextVal;
1407 }
1408 $res['value']=implode(',',$newVal);
1409
1410 return $res;
1411 }
1412
1413 /**
1414 * Handling files for group/select function
1415 *
1416 * @param [type] $valueArray: ...
1417 * @param [type] $tcaFieldConf: ...
1418 * @param [type] $curValue: ...
1419 * @param [type] $uploadedFileArray: ...
1420 * @param [type] $status: ...
1421 * @param [type] $table: ...
1422 * @param [type] $id: ...
1423 * @param [type] $recFID: ...
1424 * @return array Modified value array
1425 * @see checkValue_group_select()
1426 */
1427 function checkValue_group_select_file($valueArray,$tcaFieldConf,$curValue,$uploadedFileArray,$status,$table,$id,$recFID) {
1428
1429 // If any files are uploaded:
1430 if (is_array($uploadedFileArray) &&
1431 $uploadedFileArray['name'] &&
1432 strcmp($uploadedFileArray['tmp_name'],'none')) {
1433 $valueArray[]=$uploadedFileArray['tmp_name'];
1434 $this->alternativeFileName[$uploadedFileArray['tmp_name']] = $uploadedFileArray['name'];
1435 }
1436
1437 // Creating fileFunc object.
1438 if (!$this->fileFunc) {
1439 $this->fileFunc = t3lib_div::makeInstance('t3lib_basicFileFunctions');
1440 $this->include_filefunctions=1;
1441 }
1442 // Setting permitted extensions.
1443 $all_files = Array();
1444 $all_files['webspace']['allow'] = $tcaFieldConf['allowed'];
1445 $all_files['webspace']['deny'] = $tcaFieldConf['disallowed'] ? $tcaFieldConf['disallowed'] : '*';
1446 $all_files['ftpspace'] = $all_files['webspace'];
1447 $this->fileFunc->init('', $all_files);
1448
1449 // If there is an upload folder defined:
1450 if ($tcaFieldConf['uploadfolder']) {
1451 // For logging..
1452 $propArr = $this->getRecordProperties($table,$id);
1453
1454 // Get destrination path:
1455 $dest = $this->destPathFromUploadFolder($tcaFieldConf['uploadfolder']);
1456
1457 // If we are updating:
1458 if ($status=='update') {
1459
1460 // Finding the CURRENT files listed, either from MM or from the current record.
1461 $theFileValues=array();
1462 if ($tcaFieldConf['MM']) { // If MM relations for the files also!
1463 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
1464 $dbAnalysis->start('','files',$tcaFieldConf['MM'],$id);
1465 reset($dbAnalysis->itemArray);
1466 while (list($somekey,$someval)=each($dbAnalysis->itemArray)) {
1467 if ($someval['id']) {
1468 $theFileValues[]=$someval['id'];
1469 }
1470 }
1471 } else {
1472 $theFileValues=t3lib_div::trimExplode(',',$curValue,1);
1473 }
1474
1475 // DELETE files: If existing files were found, traverse those and register files for deletion which has been removed:
1476 if (count($theFileValues)) {
1477 // 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!)
1478 foreach($valueArray as $key => $theFile) {
1479 if ($theFile && !strstr(t3lib_div::fixWindowsFilePath($theFile),'/')) {
1480 $theFileValues = t3lib_div::removeArrayEntryByValue($theFileValues,$theFile);
1481 }
1482 }
1483
1484 // This array contains the filenames in the uploadfolder that should be deleted:
1485 foreach($theFileValues as $key => $theFile) {
1486 $theFile = trim($theFile);
1487 if (@is_file($dest.'/'.$theFile)) {
1488 $this->removeFilesStore[]=$dest.'/'.$theFile;
1489 } elseif ($theFile) {
1490 $this->log($table,$id,5,0,1,"Could not delete file '%s' (does not exist). (%s)",10,array($dest.'/'.$theFile, $recFID),$propArr['event_pid']);
1491 }
1492 }
1493 }
1494 }
1495
1496 // Traverse the submitted values:
1497 foreach($valueArray as $key => $theFile) {
1498 // 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)
1499 if (strstr(t3lib_div::fixWindowsFilePath($theFile),'/')) {
1500 // Init:
1501 $maxSize = intval($tcaFieldConf['max_size']);
1502 $cmd='';
1503 $theDestFile=''; // Must be cleared. Else a faulty fileref may be inserted if the below code returns an error!! (Change: 22/12/2000)
1504
1505 // Check various things before copying file:
1506 if (@is_dir($dest) && (@is_file($theFile) || @is_uploaded_file($theFile))) { // File and destination must exist
1507
1508 // Finding size. For safe_mode we have to rely on the size in the upload array if the file is uploaded.
1509 if (is_uploaded_file($theFile) && $theFile==$uploadedFileArray['tmp_name']) {
1510 $fileSize = $uploadedFileArray['size'];
1511 } else {
1512 $fileSize = filesize($theFile);
1513 }
1514
1515 if (!$maxSize || $fileSize<=($maxSize*1024)) { // Check file size:
1516 // Prepare filename:
1517 $theEndFileName = isset($this->alternativeFileName[$theFile]) ? $this->alternativeFileName[$theFile] : $theFile;
1518 $fI = t3lib_div::split_fileref($theEndFileName);
1519
1520 // Check for allowed extension:
1521 if ($this->fileFunc->checkIfAllowed($fI['fileext'], $dest, $theEndFileName)) {
1522 $theDestFile = $this->fileFunc->getUniqueName($this->fileFunc->cleanFileName($fI['file']), $dest);
1523
1524 // If we have a unique destination filename, then write the file:
1525 if ($theDestFile) {
1526 t3lib_div::upload_copy_move($theFile,$theDestFile);
1527 $this->copiedFileMap[$theFile]=$theDestFile;
1528 clearstatcache();
1529 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']);
1530 } 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']);
1531 } else $this->log($table,$id,5,0,1,"Fileextension '%s' not allowed. (%s)",12,array($fI['fileext'], $recFID),$propArr['event_pid']);
1532 } 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']);
1533 } 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']);
1534
1535 // If the destination file was created, we will set the new filename in the value array, otherwise unset the entry in the value array!
1536 if (@is_file($theDestFile)) {
1537 $info = t3lib_div::split_fileref($theDestFile);
1538 $valueArray[$key]=$info['file']; // The value is set to the new filename
1539 } else {
1540 unset($valueArray[$key]); // The value is set to the new filename
1541 }
1542 }
1543 }
1544
1545 // 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!
1546 if ($tcaFieldConf['MM']) {
1547 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
1548 $dbAnalysis->tableArray['files']=array(); // dummy
1549
1550 reset($valueArray);
1551 while (list($key,$theFile)=each($valueArray)) {
1552 // explode files
1553 $dbAnalysis->itemArray[]['id']=$theFile;
1554 }
1555 if ($status=='update') {
1556 $dbAnalysis->writeMM($tcaFieldConf['MM'],$id,0);
1557 } else {
1558 $this->dbAnalysisStore[] = array($dbAnalysis, $tcaFieldConf['MM'], $id, 0); // This will be traversed later to execute the actions
1559 }
1560 $cc=count($dbAnalysis->itemArray);
1561 $valueArray = array($cc);
1562 }
1563 }
1564
1565 return $valueArray;
1566 }
1567
1568 /**
1569 * Evaluates "flex" type values.
1570 *
1571 * @param array The result array. The processed value (if any!) is set in the "value" key.
1572 * @param string The value to set.
1573 * @param array Field configuration from TCA
1574 * @param array Additional parameters in a numeric array: $table,$id,$curValue,$status,$realPid,$recFID
1575 * @param array Uploaded files for the field
1576 * @param array Current record array.
1577 * @param [type] $field: ...
1578 * @return array Modified $res array
1579 */
1580 function checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$curRecordArr,$field) {
1581 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
1582
1583 if (is_array($value)) {
1584
1585 // Get current value array:
1586 $dataStructArray = t3lib_BEfunc::getFlexFormDS($tcaFieldConf,$curRecordArr,$table);
1587 $currentValueArray = t3lib_div::xml2array($curValue);
1588 if (is_array($currentValueArray['meta']['currentLangId'])) unset($currentValueArray['meta']['currentLangId']); // Remove all old meta for languages...
1589
1590 // Evaluation of input values:
1591 $value['data'] = $this->checkValue_flex_procInData($value['data'],$currentValueArray['data'],$uploadedFiles['data'],$dataStructArray,array($table,$id,$curValue,$status,$realPid,$recFID));
1592
1593 // Create XML and convert charsets from input value:
1594 $xmlValue = t3lib_div::array2xml($value,'',0,'T3FlexForms');
1595
1596 // If we wanted to set UTF fixed:
1597 // $storeInCharset='utf-8';
1598 // $currentCharset=$GLOBALS['LANG']->charSet;
1599 // $xmlValue = $GLOBALS['LANG']->csConvObj->conv($xmlValue,$currentCharset,$storeInCharset,1);
1600 $storeInCharset=$GLOBALS['LANG']->charSet;
1601
1602 // Merge them together IF they are both arrays:
1603 // 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).
1604 if (is_array($currentValueArray)) {
1605 $arrValue = t3lib_div::xml2array($xmlValue);
1606 $arrValue = t3lib_div::array_merge_recursive_overrule($currentValueArray,$arrValue);
1607 $xmlValue = t3lib_div::array2xml($arrValue,'',0,'T3FlexForms');
1608 }
1609
1610 // Temporary fix to delete elements:
1611 $deleteCMDs=t3lib_div::_GP('_DELETE_FLEX_FORMdata');
1612
1613 if (is_array($deleteCMDs[$table][$id][$field]['data'])) {
1614 $arrValue = t3lib_div::xml2array($xmlValue);
1615 $this->_DELETE_FLEX_FORMdata($arrValue['data'],$deleteCMDs[$table][$id][$field]['data']);
1616 #debug($deleteCMDs[$table][$id][$field]['data']);
1617 #debug($arrValue);
1618 $xmlValue = t3lib_div::array2xml($arrValue,'',0,'T3FlexForms');
1619 }
1620
1621 // Create the value XML:
1622 $res['value']='';
1623 $res['value'].='<?xml version="1.0" encoding="'.$storeInCharset.'" standalone="yes" ?>'.chr(10);
1624 $res['value'].=$xmlValue;
1625 } else {
1626 $res['value']=$value;
1627 }
1628
1629 return $res;
1630 }
1631
1632 /**
1633 * [Describe function...]
1634 *
1635 * @param [type] $$valueArrayToRemoveFrom: ...
1636 * @param [type] $deleteCMDS: ...
1637 * @return [type] ...
1638 */
1639 function _DELETE_FLEX_FORMdata(&$valueArrayToRemoveFrom,$deleteCMDS) {
1640 if (is_array($valueArrayToRemoveFrom) && is_array($deleteCMDS)) {
1641 foreach($deleteCMDS as $key => $value) {
1642 if (is_array($deleteCMDS[$key])) {
1643 $this->_DELETE_FLEX_FORMdata($valueArrayToRemoveFrom[$key],$deleteCMDS[$key]);
1644 } else {
1645 unset($valueArrayToRemoveFrom[$key]);
1646 }
1647 }
1648 }
1649 }
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670 /*********************************************
1671 *
1672 * Helper functions for evaluation functions.
1673 *
1674 ********************************************/
1675
1676
1677 /**
1678 * Gets a unique value for $table/$id/$field based on $value
1679 *
1680 * @param string Table name
1681 * @param string Field name for which $value must be unique
1682 * @param string Value string.
1683 * @param [type] $id: ...
1684 * @param integer If set, the value will be unique for this PID
1685 * @return string Modified value (if not-unique). Will be the value appended with a number (until 100, then the function just breaks).
1686 */
1687 function getUnique($table,$field,$value,$id,$newPid=0) {
1688 global $TCA;
1689
1690 t3lib_div::loadTCA($table);
1691 $whereAdd='';
1692 $newValue='';
1693 if (intval($newPid)) {$whereAdd.=' AND pid='.intval($newPid);}
1694 $whereAdd.=$this->deleteClause($table);
1695
1696 if (isset($TCA[$table]['columns'][$field])) {
1697 // Look for a record which might already have the value:
1698 $res = mysql(TYPO3_db,'SELECT uid FROM '.$table.' WHERE '.$field.'="'.addslashes($value).'" AND uid!='.intval($id).$whereAdd);
1699 $counter=0;
1700 // For as long as records with the test-value existing, try again (with incremented numbers appended).
1701 while (mysql_num_rows($res)) {
1702 $newValue = $value.$counter;
1703 $res = mysql(TYPO3_db,'SELECT uid FROM '.$table.' WHERE '.$field.'="'.addslashes($newValue).'" AND uid!='.intval($id).$whereAdd);
1704 $counter++;
1705 if ($counter>100) {break;}
1706 }
1707 $value = $newValue ? $newValue : $value;
1708 }
1709 return $value;
1710 }
1711
1712 /**
1713 * Evaluation of 'input'-type values based on 'eval' list
1714 *
1715 * @param string Value
1716 * @param array Array of evaluations to traverse.
1717 * @param string Is-in string
1718 * @return string Modified $value
1719 */
1720 function checkValue_input_Eval($value,$evalArray,$is_in) {
1721 $res = Array();
1722 $newValue = $value;
1723 $set = true;
1724
1725 foreach($evalArray as $func) {
1726 switch($func) {
1727 case 'int':
1728 case 'year':
1729 case 'date':
1730 case 'datetime':
1731 case 'time':
1732 case 'timesec':
1733 $value = intval($value);
1734 break;
1735 case 'double2':
1736 $theDec = 0;
1737 for ($a=strlen($value); $a>0; $a--) {
1738 if (substr($value,$a-1,1)=='.' || substr($value,$a-1,1)==',') {
1739 $theDec = substr($value,$a);
1740 $value = substr($value,0,$a-1);
1741 break;
1742 }
1743 }
1744 $theDec = ereg_replace('[^0-9]','',$theDec).'00';
1745 $value = intval(str_replace(' ','',$value)).'.'.substr($theDec,0,2);
1746 break;
1747 case 'md5':
1748 if (strlen($value)!=32){$set=false;}
1749 break;
1750 case 'trim':
1751 $value = trim($value);
1752 break;
1753 case 'upper':
1754 $value = strtoupper($value);
1755 # $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.
1756 break;
1757 case 'lower':
1758 $value = strtolower($value);
1759 # $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.
1760 break;
1761 case 'required':
1762 if (!$value) {$set=0;}
1763 break;
1764 case 'is_in':
1765 $c=strlen($value);
1766 if ($c) {
1767 $newVal = '';
1768 for ($a=0;$a<$c;$a++) {
1769 $char = substr($value,$a,1);
1770 if (strstr($is_in,$char)) {
1771 $newVal.=$char;
1772 }
1773 }
1774 $value = $newVal;
1775 }
1776 break;
1777 case 'nospace':
1778 $value = str_replace(' ','',$value);
1779 break;
1780 case 'alpha':
1781 $value = ereg_replace('[^a-zA-Z]','',$value);
1782 break;
1783 case 'num':
1784 $value = ereg_replace('[^0-9]','',$value);
1785 break;
1786 case 'alphanum':
1787 $value = ereg_replace('[^a-zA-Z0-9]','',$value);
1788 break;
1789 case 'alphanum_x':
1790 $value = ereg_replace('[^a-zA-Z0-9_-]','',$value);
1791 break;
1792 }
1793 }
1794 if ($set) {$res['value'] = $value;}
1795 return $res;
1796 }
1797
1798 /**
1799 * Returns data for group/db and select fields
1800 *
1801 * @param array Current value array
1802 * @param array TCA field config
1803 * @param integer Record id, used for look-up of MM relations (local_uid)
1804 * @param string Status string ("update" or "new")
1805 * @param string The type, either "select" or "group"
1806 * @return array Modified value array
1807 */
1808 function checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,$type) {
1809 $tables = $type=='group'?$tcaFieldConf['allowed']:$tcaFieldConf['foreign_table'].','.$tcaFieldConf['neg_foreign_table'];
1810 $prep = $type=='group'?$tcaFieldConf['prepend_tname']:$tcaFieldConf['neg_foreign_table'];
1811
1812 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
1813 $dbAnalysis->registerNonTableValues=$tcaFieldConf['allowNonIdValues'] ? 1 : 0;
1814 $dbAnalysis->start(implode($valueArray,','),$tables);
1815
1816 if ($tcaFieldConf['MM']) {
1817 if ($status=='update') {
1818 $dbAnalysis->writeMM($tcaFieldConf['MM'],$id,$prep);
1819 } else {
1820 $this->dbAnalysisStore[] = array($dbAnalysis,$tcaFieldConf['MM'],$id,$prep); // This will be traversed later to execute the actions
1821 }
1822 $cc=count($dbAnalysis->itemArray);
1823 $valueArray = array($cc);
1824 } else {
1825 $valueArray = $dbAnalysis->getValueArray($prep);
1826 if ($type=='select' && $prep) {
1827 $valueArray = $dbAnalysis->convertPosNeg($valueArray,$tcaFieldConf['foreign_table'],$tcaFieldConf['neg_foreign_table']);
1828 }
1829 }
1830
1831 // 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.
1832 return $valueArray;
1833 }
1834
1835 /**
1836 * Explodes the $value, which is a list of files/uids (group select)
1837 *
1838 * @param string Input string, comma separated values. For each part it will also be detected if a "|" is found and the first part will then be used if that is the case. Further the value will be rawurldecoded.
1839 * @return array The value array.
1840 */
1841 function checkValue_group_select_explodeSelectGroupValue($value) {
1842 $valueArray = t3lib_div::trimExplode(',',$value,1);
1843 reset($valueArray);
1844 while(list($key,$newVal)=each($valueArray)) {
1845 $temp=explode('|',$newVal,2);
1846 $valueArray[$key] = str_replace(',','',str_replace('|','',rawurldecode($temp[0])));
1847 }
1848 return $valueArray;
1849 }
1850
1851 /**
1852 * Processing the input data for flexforms. This will traverse all sheets / languages and for each it will traverse the sub-structure.
1853 *
1854 * @param array The "data" part of the INPUT flexform data
1855 * @param array The "data" part of the CURRENT flexform data
1856 * @param array The uploaded files for the "data" part of the INPUT flexform data
1857 * @param array Data structure for the form (might be sheets or not). Only values in the data array which has a configuration in the data structure will be processed.
1858 * @param array A set of parameters to pass through for the calling of the evaluation functions
1859 * @return array The modified "data" part.
1860 * @see checkValue_flex_procInData_travDS()
1861 */
1862 function checkValue_flex_procInData($dataPart,$dataPart_current,$uploadedFiles,$dataStructArray,$pParams) {
1863 #debug(array($dataPart,$dataPart_current));
1864 if (is_array($dataPart)) {
1865 foreach($dataPart as $sKey => $sheetDef) {
1866 list ($dataStruct,$actualSheet) = t3lib_div::resolveSheetDefInDS($dataStructArray,$sKey);
1867
1868 if (is_array($dataStruct) && $actualSheet==$sKey && is_array($sheetDef)) {
1869 foreach($sheetDef as $lKey => $lData) {
1870 $this->checkValue_flex_procInData_travDS(
1871 $dataPart[$sKey][$lKey],
1872 $dataPart_current[$sKey][$lKey],
1873 $uploadedFiles[$sKey][$lKey],
1874 $dataStruct['ROOT']['el'],
1875 $pParams
1876 );
1877 }
1878 }
1879 }
1880 }
1881
1882 return $dataPart;
1883 }
1884
1885 /**
1886 * Processing of the sheet/language data array
1887 *
1888 * @param array Multidimensional Data array for sheet/language, passed by reference!
1889 * @param array Data structure which fits the data array
1890 * @param array A set of parameters to pass through for the calling of the evaluation functions
1891 * @param [type] $DSelements: ...
1892 * @param [type] $pParams: ...
1893 * @return void
1894 * @see checkValue_flex_procInData()
1895 */
1896 function checkValue_flex_procInData_travDS(&$dataValues,$dataValues_current,$uploadedFiles,$DSelements,$pParams) {
1897 if (is_array($DSelements)) {
1898
1899 // For each DS element:
1900 foreach($DSelements as $key => $dsConf) {
1901
1902 // Array/Section:
1903 if ($DSelements[$key]['type']=='array') {
1904 if (is_array($dataValues[$key]['el'])) {
1905 if ($DSelements[$key]['section']) {
1906 foreach($dataValues[$key]['el'] as $ik => $el) {
1907 $theKey = key($el);
1908 if (is_array($dataValues[$key]['el'][$ik][$theKey]['el'])) {
1909 $this->checkValue_flex_procInData_travDS(
1910 $dataValues[$key]['el'][$ik][$theKey]['el'],
1911 $dataValues_current[$key]['el'][$ik][$theKey]['el'],
1912 $uploadedFiles[$key]['el'][$ik][$theKey]['el'],
1913 $DSelements[$key]['el'][$theKey]['el'],
1914 $pParams
1915 );
1916 }
1917 }
1918 } else {
1919 if (!isset($dataValues[$key]['el'])) $dataValues[$key]['el']=array();
1920 $this->checkValue_flex_procInData_travDS(
1921 $dataValues[$key]['el'],
1922 $dataValues_current[$key]['el'],
1923 $uploadedFiles[$key]['el'],
1924 $DSelements[$key]['el'],
1925 $pParams
1926 );
1927 }
1928 }
1929 } else {
1930 if (is_array($dsConf['TCEforms']['config']) && is_array($dataValues[$key])) {
1931 foreach($dataValues[$key] as $vKey => $data) {
1932 list($CVtable,$CVid,$CVcurValue,$CVstatus,$CVrealPid,$CVrecFID) = $pParams;
1933
1934 $res = $this->checkValue_SW(
1935 array(),
1936 $dataValues[$key][$vKey],
1937 $dsConf['TCEforms']['config'],
1938 $CVtable,
1939 $CVid,
1940 $dataValues_current[$key][$vKey],
1941 $CVstatus,
1942 $CVrealPid,
1943 $CVrecFID,
1944 '',
1945 $uploadedFiles[$key][$vKey]
1946 );
1947
1948 // Evaluating the value.
1949 if (isset($res["value"])) {
1950 $dataValues[$key][$vKey]=$res["value"];
1951 }
1952
1953 }
1954 }
1955 }
1956 }
1957 }
1958 }
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979 /*********************************************
1980 *
1981 * ...
1982 *
1983 ********************************************/
1984
1985
1986 /**
1987 * Update database
1988 *
1989 * Does not check permissions but expects them to be verified on beforehand
1990 *
1991 * @param [type] $table: ...
1992 * @param [type] $id: ...
1993 * @param [type] $fieldArray: ...
1994 * @return [type] ...
1995 */
1996 function updateDB($table,$id,$fieldArray) {
1997 global $TCA;
1998 if ($this->debug) {debug($fieldArray);}
1999 if (is_array($fieldArray) && $TCA[$table] && intval($id) ) {
2000 reset($fieldArray);
2001 $fA=array();
2002 while (list($col,$val)=each($fieldArray)) {
2003 if ($col != "uid") { // Do not update the uid field
2004 $fA[]=$col."='".addslashes($val)."'";
2005 }
2006 }
2007 if (count($fA)) {
2008 $query= "UPDATE ".$table." set ".implode($fA,",")." WHERE uid = ".intval($id);
2009 @mysql(TYPO3_db,$query);
2010 if ($this->debug) {echo $query."<BR>".mysql_error();}
2011 if (!mysql_error()) {
2012 if ($this->checkStoredRecords) {$newRow = $this->checkStoredRecord($table,$id,$fieldArray,2);}
2013 $propArr=$this->getRecordPropertiesFromRow($table,$newRow);
2014 $theLogId = $this->log($table,$id,2,$recpid,0,"Record '%s' (%s) was updated.",10,array($propArr["header"],$table.":".$id),$propArr["event_pid"]);
2015 $this->setHistory($table,$id,$theLogId);
2016 $this->clear_cache($table,$id);
2017 if ($table=="pages") unset($this->pageCache[$id]); // Unset the pageCache for the id if table was page.
2018 } else {
2019 $this->log($table,$id,2,0,2,"MySQL error: '%s' (%s)",12,array(mysql_error(),$table.":".$id));
2020 }
2021 }
2022 }
2023 }
2024
2025 /**
2026 * Compares the incoming field array with the current record and unsets all fields which are the same.
2027 * If the returned array is empty, then the record should not be updated!
2028 * $fieldArray must be an array.
2029 *
2030 * @param [type] $table: ...
2031 * @param [type] $id: ...
2032 * @param [type] $fieldArray: ...
2033 * @return [type] ...
2034 */
2035 function compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray) {
2036 unset($currentRecord);
2037 $res = mysql(TYPO3_db,"SELECT * FROM $table WHERE uid=".intval($id));
2038
2039 // Fetch the types of the fields.
2040 if (mysql_num_rows($res)) {
2041 $currentRecord = mysql_fetch_assoc($res);
2042 $c=0;
2043 reset($currentRecord);
2044 $cRecTypes=array();
2045 while (list($col,$val)=each($currentRecord)) {
2046 $cRecTypes[$col]=mysql_field_type($res,$c);
2047 $c++;
2048 }
2049 }
2050
2051 // Unset the fields which are similar.
2052 if (is_array($currentRecord)) { // If current record exists...
2053 reset($fieldArray);
2054 while (list($col,$val)=each($fieldArray)) {
2055 if (!isset($currentRecord[$col]) ||
2056 !strcmp($val,$currentRecord[$col]) ||
2057 ($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.
2058 ) { // The field must exist in the current record and it MUST be different to the letter.
2059 unset($fieldArray[$col]);
2060 } else {
2061 $this->historyRecords[$table.":".$id]["oldRecord"][$col] = $currentRecord[$col];
2062 $this->historyRecords[$table.":".$id]["newRecord"][$col] = $fieldArray[$col];
2063 }
2064 }
2065 } else { // If the current record does not exist this is an error anyways and we just return an empty array here.
2066 $fieldArray=array();
2067 }
2068 return $fieldArray;
2069 }
2070
2071 /**
2072 * Insert into database
2073 *
2074 * Does not check permissions but expects them to be verified on beforehand
2075 *
2076 * @param [type] $table: ...
2077 * @param [type] $id: ...
2078 * @param [type] $fieldArray: ...
2079 * @return [type] ...
2080 */
2081 function insertDB($table,$id,$fieldArray) {
2082 global $TCA;
2083 if ($this->debug) {debug($fieldArray);}
2084 if (is_array($fieldArray) && $TCA[$table] && isset($fieldArray["pid"])) {
2085 reset($fieldArray);
2086 $fA=array();
2087 while (list($col,$val)=each($fieldArray)) {
2088 if ($col != "uid") { // Cannot insert uid
2089 $fA["f"][]=$col;
2090 $fA["v"][]="'".addslashes($val)."'";
2091 }
2092 }
2093 if (count($fA)) {
2094 $query = "INSERT INTO ".$table." (".implode($fA["f"],",").") VALUES (".implode($fA["v"],",").")";
2095 @mysql(TYPO3_db,$query);
2096 if ($this->debug) {echo $query."<BR>".mysql_error();}
2097 if (!mysql_error()) {
2098 $NEW_id = $id; // the NEW_id now holds the "NEWaæsdfjæs9345" -id
2099 $id = mysql_insert_id();
2100 $this->substNEWwithIDs[$NEW_id] = $id;
2101 $this->substNEWwithIDs_table[$NEW_id] = $table;
2102 if($this->debug) {debug($this->substNEWwithIDs);}
2103 if ($table=="pages") {
2104 $thePositionID = $this->getInterfacePagePositionID($id);
2105 } else {
2106 $thePositionID=0;
2107 }
2108 // Checking the record is properly saved and writing to log
2109 if ($this->checkStoredRecords) {$newRow=$this->checkStoredRecord($table,$id,$fieldArray,1);}
2110 $propArr=$this->getRecordPropertiesFromRow($table,$newRow);
2111 $page_propArr= $this->getRecordProperties("pages",$propArr["pid"]);
2112 $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);
2113 $this->clear_cache($table,$id);
2114 } else {
2115 $this->log($table,$id,1,0,2,"MySQL error: '%s' (%s)",12,array(mysql_error(),$table.":".$id));
2116 }
2117 }
2118 }
2119 }
2120
2121 /**
2122 * Checking stored record to see if the written values are properly updated.
2123 *
2124 * $action is only for logging
2125 *
2126 * @param [type] $table: ...
2127 * @param [type] $id: ...
2128 * @param [type] $fieldArray: ...
2129 * @param [type] $action: ...
2130 * @return [type] ...
2131 */
2132 function checkStoredRecord($table,$id,$fieldArray,$action) {
2133 global $TCA;
2134 $id = intval($id);
2135 if ($TCA[$table] && $id) {
2136 $res = mysql(TYPO3_db,"select * from $table where uid = $id");
2137 if ($row=mysql_fetch_assoc($res)) {
2138 reset($fieldArray);
2139 $errorString=array();
2140 while(list($key,$value)=each($fieldArray)){
2141 if ($this->checkStoredRecords_loose && !$value && !$row[$key]) {
2142 // Nothing...
2143 } elseif (strcmp($value,$row[$key])) {$errorString[]=$key;}
2144 }
2145 if (count($errorString)) {
2146 $this->log($table,$id,$action,0,102,"These fields are not properly updated in database: (".implode(",",$errorString).") Probably value mismatch with fieldtype.");
2147 }
2148 return $row;
2149 }
2150 }
2151 }
2152
2153 /**
2154 * Executing dbAnalysisStore
2155 *
2156 * @return [type] ...
2157 */
2158 function dbAnalysisStoreExec() {
2159 reset($this->dbAnalysisStore);
2160 while(list($k,$v)=each($this->dbAnalysisStore)) {
2161 $id = $this->substNEWwithIDs[$v[2]];
2162 if ($id) {
2163 $v[2] = $id;
2164 $v[0]->writeMM($v[1],$v[2],$v[3]);
2165 }
2166 }
2167 }
2168
2169 /**
2170 * Executing dbAnalysisStore
2171 *
2172 * @return [type] ...
2173 */
2174 function removeRegisteredFiles() {
2175 reset($this->removeFilesStore);
2176 while(list($k,$v)=each($this->removeFilesStore)) {
2177 unlink($v);
2178 // debug($v,1);
2179 }
2180 }
2181
2182 /**
2183 * Clearing the cache based on a page being updated
2184 *
2185 * If the $table is "pages" then cache is cleared for all pages on the same level (and subsequent?)
2186 * Else just clear the cache for the parent page of the record.
2187 *
2188 * @param [type] $table: ...
2189 * @param [type] $uid: ...
2190 * @return [type] ...
2191 */
2192 function clear_cache($table,$uid) {
2193 global $TCA;
2194 $uid = intval($uid);
2195 if ($TCA[$table] && $uid > 0) {
2196 if ($table=='pages') {
2197 // Builds list of pages on the SAME level as this page
2198 $res_tmp = mysql(TYPO3_db,"select A.pid as pid ,B.uid as uid ,B.title as title from $table A, $table B where A.uid=$uid and B.pid=A.pid");
2199 $list_cache='(';
2200 while ($row_tmp = mysql_fetch_assoc($res_tmp)) {
2201 $list_cache.=$row_tmp["uid"].',';
2202 $pid_tmp=$row_tmp["pid"];
2203 }
2204 $list_cache.=$pid_tmp.')';
2205 $query = "DELETE FROM cache_pages WHERE page_id IN $list_cache";
2206 if ($this->debug) {echo $query."<BR>";}
2207 $res_tmp = mysql(TYPO3_db,$query);
2208 if ($this->debug) {echo mysql_affected_rows()."<BR>";}
2209
2210 // $query2 is used to clear the caching of the template-setup. This should only be needed when pages are moved or the template is rebuild. I should consider doing this only in these cases or make it a manual operation...
2211 $query2 = "DELETE FROM cache_pagesection WHERE page_id IN $list_cache";
2212 $res_tmp = mysql(TYPO3_db,$query2);
2213
2214 // Deletes all cached pages with a reference to the page. This is being tested
2215 if ($this->clearCache_like) {
2216 $query = "DELETE FROM cache_pages WHERE (".
2217 "HTML like '%?id=".$uid."%'".
2218 " OR HTML like '%?id=".$uid."&%'".
2219 " OR HTML like '%?".$uid."%'".
2220 " OR HTML like '%?".$uid."&%'".
2221 ")";
2222 if ($this->debug) {echo $query."<BR>";}
2223 $res_tmp = mysql(TYPO3_db,$query);
2224 if ($this->debug) {echo mysql_affected_rows()."<BR>";}
2225 }
2226 } else {
2227 $uid_page = $this->getPID($table,$uid);
2228 if ($uid_page>0) {
2229 $query="delete from cache_pages where page_id=$uid_page";
2230 if ($this->debug) {echo $query."<BR>";}
2231 $res_tmp = mysql(TYPO3_db,$query);
2232 if ($this->debug) {echo mysql_affected_rows()."<BR>";}
2233
2234
2235 $query2="delete from cache_pagesection where page_id=$uid_page";
2236 $res_tmp = mysql(TYPO3_db,$query2);
2237 }
2238 }
2239
2240 // Clear cache for pages entered in TSconfig:
2241 list($tscPID)=t3lib_BEfunc::getTSCpid($table,$uid,'');
2242 $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
2243 if ($TSConfig['clearCacheCmd']) {
2244 $Commands = t3lib_div::trimExplode(',',strtolower($TSConfig['clearCacheCmd']),1);
2245 $Commands = array_unique($Commands);
2246 foreach($Commands as $cmdPart) {
2247 $this->clear_cacheCmd($cmdPart);
2248 }
2249 }
2250
2251 // Call post processing function for clear-cache:
2252 global $TYPO3_CONF_VARS;
2253 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'])) {
2254 $_params = array('table' => $table,'uid' => $uid,'uid_page' => $uid_page);
2255 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'] as $_funcRef) {
2256 t3lib_div::callUserFunction($_funcRef,$_params,$this);
2257 }
2258 }
2259 }
2260 }
2261
2262 /**
2263 * Returns the pid of a record from $table with $uid
2264 *
2265 * @param [type] $table: ...
2266 * @param [type] $uid: ...
2267 * @return [type] ...
2268 */
2269 function getPID($table,$uid) {
2270 $res_tmp = mysql(TYPO3_db,"select pid from $table where uid=".intval($uid));
2271 if (mysql_num_rows($res_tmp)) {
2272 return mysql_result($res_tmp,0,"pid");
2273 } else {return "";}
2274 }
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300 /*********************************************
2301 *
2302 * PROCESSING COMMANDS
2303 *
2304 ********************************************/
2305
2306 /**
2307 * Processing the cmd-array
2308 *
2309 * @return [type] ...
2310 */
2311 function process_cmdmap() {
2312 global $TCA;
2313 #debug($this->cmdmap);
2314 reset ($this->cmdmap);
2315 while (list($table,) = each($this->cmdmap)) {
2316 $modifyAccessList = $this->checkModifyAccessList($table);
2317 if (!$modifyAccessList) {
2318 $this->log($table,$id,2,0,1,"Attempt to modify table '%s' without permission",1,array($table));
2319 }
2320 if (isset($TCA[$table]) && !$this->tableReadOnly($table) && is_array($this->cmdmap[$table]) && $modifyAccessList) { // Is table from $TCA and
2321 #debug();
2322 reset ($this->cmdmap[$table]);
2323 while (list($id,$incomingCmdArray) = each($this->cmdmap[$table])) { // Har fundet en tabel
2324 if (is_array($incomingCmdArray)) { // Har fundet et ID-nummer
2325 reset($incomingCmdArray);
2326 $command = key($incomingCmdArray);
2327 $value = current($incomingCmdArray);
2328 switch ($command) {
2329 case "move":
2330 $this->moveRecord($table,$id,$value);
2331 break;
2332 case "copy":
2333 $this->copyMappingArray = Array(); // Must clear this array before call from here to those functions.
2334 if ($table == "pages") {
2335 $this->copyPages($id,$value);
2336 } else {
2337 $this->copyRecord($table,$id,$value,1);
2338 #debug(array($table,$id,$value));
2339 }
2340 // Merging the copy-array info together for remapping purposes.
2341 $this->copyMappingArray_merged= t3lib_div::array_merge_recursive_overrule($this->copyMappingArray_merged,$this->copyMappingArray);
2342 break;
2343 case "delete":
2344 if ($table == "pages") {
2345 $this->deletePages($id);
2346 } else {
2347 $this->deleteRecord($table,$id, 0);
2348 }
2349 break;
2350 }
2351 }
2352 }
2353 }
2354 }
2355 $this->remapListedDBRecords();
2356 }
2357
2358 /**
2359 * Moving records
2360 *
2361 * $destPid: >=0 then it points to a page-id on which to insert the record (as the first element). <0 then it points to a uid from its own table after which to insert it (works if
2362 *
2363 * @param [type] $table: ...
2364 * @param [type] $uid: ...
2365 * @param [type] $destPid: ...
2366 * @return [type] ...
2367 */
2368 function moveRecord($table,$uid,$destPid) {
2369 global $TCA;
2370 $sortRow = $TCA[$table]["ctrl"]["sortby"];
2371 $destPid = intval($destPid);
2372 $origDestPid = $destPid;
2373 if ($TCA[$table]) {
2374 $propArr = $this->getRecordProperties($table,$uid); // Get this before we change the pid (for logging)
2375 $resolvedPid = $this->resolvePid($table,$destPid); // This is the actual pid of the moving.
2376
2377 // 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.
2378 // 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.
2379 if ($table!="pages" || $resolvedPid==$propArr["pid"]) {
2380 $mayMoveAccess=$this->checkRecordUpdateAccess($table,$uid); // Edit rights for the record...
2381 } else {
2382 $mayMoveAccess=$this->doesRecordExist($table,$uid,"delete");
2383 }
2384
2385 // 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
2386 if ($table!="pages" || $resolvedPid!=$propArr["pid"]) {
2387 $mayInsertAccess = $this->checkRecordInsertAccess($table,$resolvedPid,4); // Edit rights for the record...
2388 } else {
2389 $mayInsertAccess=$this->checkRecordUpdateAccess($table,$uid);
2390 }
2391
2392 // 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...)
2393 if ($destPid<0 && !$sortRow) {
2394 $destPid = $resolvedPid;
2395 }
2396
2397 //
2398 if ($TCA[$table]["ctrl"]["tstamp"]) {
2399 $tstampC = ", ".$TCA[$table]["ctrl"]["tstamp"]."=".time();
2400 } else $tstampC="";
2401
2402
2403 if ($mayMoveAccess) {
2404 if ($destPid>=0) { // insert as first element on page (where uid = $destPid)
2405 if ($mayInsertAccess) {
2406 if ($table!="pages" || $this->destNotInsideSelf ($destPid,$uid)) {
2407 $this->clear_cache($table,$uid); // clear cache before moving
2408 if ($sortRow) { // table is sorted by 'sortby'
2409 $sortNumber = $this->getSortNumber($table,$uid,$destPid);
2410 $query = "UPDATE $table SET pid='$destPid', $sortRow='$sortNumber'".$tstampC." WHERE uid = '$uid'"; // We now update the pid and sortnumber
2411 $res = mysql(TYPO3_db,$query);
2412 if ($this->debug) {echo $table.$uid.": Update pid(".$destPid.") and sorting number(".$sortNumber.")<BR>";}
2413 } else { // table is NOT sorted
2414 $query = "UPDATE $table SET pid='$destPid'".$tstampC." WHERE uid = '$uid'"; // We need only update the pid as this table is not sorted
2415 $res = mysql(TYPO3_db,$query);
2416 if ($this->debug) {echo $table.$uid.": Update pid only (no sorting)<BR>";}
2417 }
2418
2419 // Logging...
2420 $newPropArr = $this->getRecordProperties($table,$uid);
2421 $oldpagePropArr = $this->getRecordProperties("pages",$propArr["pid"]);
2422 $newpagePropArr = $this->getRecordProperties("pages",$destPid);
2423
2424 if ($destPid!=$propArr["pid"]) {
2425 $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
2426 $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
2427 } else {
2428 $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
2429 }
2430 $this->clear_cache($table,$uid); // clear cache after moving
2431 $this->fixUniqueInPid($table,$uid);
2432 // fixCopyAfterDuplFields
2433 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.
2434 } else {
2435 $destPropArr = $this->getRecordProperties("pages",$destPid);
2436 $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"]);
2437 }
2438 }
2439 } else { // Put after another record
2440 if ($sortRow) { // table is being sorted
2441 $sortInfo = $this->getSortNumber($table,$uid,$destPid);
2442 $destPid = $sortInfo["pid"]; // Setting the destPid to the new pid of the record.
2443 if (is_array($sortInfo)) { // If not an array, there was an error (which is already logged)
2444 if ($mayInsertAccess) {
2445 if ($table!="pages" || $this->destNotInsideSelf ($destPid,$uid)) {
2446 $this->clear_cache($table,$uid); // clear cache before moving
2447 $query = "UPDATE $table SET pid='".$destPid."', $sortRow='".$sortInfo["sortNumber"]."'".$tstampC." WHERE uid = '$uid'"; // We now update the pid and sortnumber
2448 $res = mysql(TYPO3_db,$query);
2449 if ($this->debug) {echo $table.$uid.": Update pid(".$destPid.") and sorting number(".$sortInfo["sortNumber"].")<BR>";}
2450 // Logging...
2451 if ($table=="pages") {
2452 $thePositionID = $this->getInterfacePagePositionID($uid);
2453 } else {
2454 $thePositionID=0;
2455 }
2456
2457 $this->log($table,$uid,4,$thePositionID,0,"");
2458 // Logging...
2459 $newPropArr = $this->getRecordProperties($table,$uid);
2460 $oldpagePropArr = $this->getRecordProperties("pages",$propArr["pid"]);
2461 if ($destPid!=$propArr["pid"]) {
2462 $newpagePropArr = $this->getRecordProperties("pages",$destPid);
2463 $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
2464 $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
2465 } else {
2466 $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
2467 }
2468 $this->clear_cache($table,$uid); // clear cache after moving
2469 // fixUniqueInPid
2470 $this->fixUniqueInPid($table,$uid);
2471 // fixCopyAfterDuplFields
2472 if ($origDestPid<0) {$this->fixCopyAfterDuplFields($table,$uid,abs($origDestPid),1);}
2473 } else {
2474 $destPropArr = $this->getRecordProperties("pages",$destPid);
2475 $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"]);
2476 }
2477 }
2478 }
2479 } else {
2480 $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"]);
2481 }
2482 }
2483 } else {
2484 $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"]);
2485 }
2486 }
2487 }
2488
2489 /**
2490 * Copying records
2491 *
2492 * $destPid: >=0 then it points to a page-id on which to insert the record (as the first element). <0 then it points to a uid from its own table after which to insert it (works if
2493 * $first is a flag set, if the record copied is NOT a "slave" to another record copied. That is, if this record was asked to be copied in the cmd-array
2494 *
2495 * @param [type] $table: ...
2496 * @param [type] $uid: ...
2497 * @param [type] $destPid: ...
2498 * @param [type] $first: ...
2499 * @return [type] ...
2500 */
2501 function copyRecord($table,$uid,$destPid,$first=0) {
2502 global $TCA;
2503 $uid = intval($uid);
2504 if ($TCA[$table] && $uid) {
2505 t3lib_div::loadTCA($table);
2506 if ($this->doesRecordExist($table,$uid,"show")) {
2507 $data = Array();
2508 $nonFields = explode(",","uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody");
2509 $row = $this->recordInfo($table,$uid,"*");
2510 if (is_array($row)) {
2511 $theNewID = uniqid("NEW");
2512 // $fileFieldArr = $this->extFileFields($table); // Fetches all fields that holds references to files
2513 $enableField = isset($TCA[$table]["ctrl"]["enablecolumns"]) ? $TCA[$table]["ctrl"]["enablecolumns"]["disabled"] : "";
2514 $headerField = $TCA[$table]["ctrl"]["label"];
2515 $defaultData = $this->newFieldArray($table);
2516
2517 $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...
2518 $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
2519 $tE = $this->getTableEntries($table,$TSConfig);
2520 //debug(array($table,$destPid,$TSConfig));
2521
2522 reset($row);
2523 while (list($field,$value)=each($row)) {
2524 if (!in_array($field,$nonFields)) {
2525 $conf = $TCA[$table]["columns"][$field]["config"];
2526
2527 if ($field=="pid") {
2528 $value = $destPid;
2529 }
2530
2531 if ($TCA[$table]["ctrl"]["setToDefaultOnCopy"] && t3lib_div::inList($TCA[$table]["ctrl"]["setToDefaultOnCopy"],$field)) {
2532 $value = $defaultData[$field];
2533 } else {
2534 if ($first && $field==$enableField && $TCA[$table]["ctrl"]["hideAtCopy"] && !$this->neverHideAtCopy && !$tE["disableHideAtCopy"]) {
2535 $value=1;
2536 }
2537 if ($first && $field==$headerField && $TCA[$table]["ctrl"]["prependAtCopy"] && !$tE["disablePrependAtCopy"]) {
2538 $value = $this->getCopyHeader ($table,$this->resolvePid($table,$destPid),$field,$this->clearPrefixFromValue($table,$value),0);
2539 }
2540
2541 // Take care of files...
2542 if ($conf["type"]=="group" && $conf["internal_type"]=="file") {
2543 if ($conf["MM"]) {
2544 $theFileValues=array();
2545 $dbAnalysis = t3lib_div::makeInstance("t3lib_loadDBGroup");
2546 $dbAnalysis->start("","files",$conf["MM"],$uid);
2547 reset($dbAnalysis->itemArray);
2548 while (list($somekey,$someval)=each($dbAnalysis->itemArray)) {
2549 // debug($someval["id"]);
2550 if ($someval["id"]) {
2551 $theFileValues[]=$someval["id"];
2552 }
2553 }
2554 } else {
2555 $theFileValues = explode(",",$value);
2556 }
2557 // debug($theFileValues);
2558 reset($theFileValues);
2559 $uploadFolder = $conf["uploadfolder"];
2560 $dest = $this->destPathFromUploadFolder($uploadFolder);
2561 $newValue = array();
2562 while (list(,$file)=each($theFileValues)) {
2563 if (trim($file)) {
2564 $realFile = $dest."/".trim($file);
2565 if (@is_file($realFile)) {
2566 $newValue[]=$realFile;
2567 }
2568 }
2569 }
2570 $value = implode(",",$newValue);
2571 }
2572 // db record lists:
2573 if (($conf["type"]=="group" && $conf["internal_type"]=="db") || ($conf["type"]=="select" && $conf["foreign_table"])) {
2574 $allowedTables = $conf["type"]=="group" ? $conf["allowed"] : $conf["foreign_table"].",".$conf["neg_foreign_table"];
2575 $prependName = $conf["type"]=="group" ? $conf["prepend_tname"] : $conf["neg_foreign_table"];
2576 if ($conf["MM"]) {
2577 $dbAnalysis = t3lib_div::makeInstance("t3lib_loadDBGroup");
2578 $dbAnalysis->start("",$allowedTables,$conf["MM"],$uid);
2579 $value = implode(",",$dbAnalysis->getValueArray($prependName));
2580 }
2581 if ($value) {
2582 $this->registerDBList[$table][$uid][$field]=$value;
2583 }
2584 }
2585 }
2586
2587 // Add value to array.
2588 $value=addSlashes($value); // Added 15-03-00
2589 $data[$table][$theNewID][$field]=$value;
2590 }
2591 }
2592
2593 // Added 02-05-02 to set the fields correctly for copied records...
2594 if ($destPid<0 && is_array($data[$table][$theNewID])) {
2595 $copyAfterFields = $this->fixCopyAfterDuplFields($table,$uid,abs($destPid),0);
2596 $data[$table][$theNewID] = array_merge($data[$table][$theNewID],$copyAfterFields);
2597 //debug($data[$table][$theNewID]);
2598 } // 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.
2599
2600
2601 // Do the copy:
2602 //debug($data[$table][$theNewID]);
2603 $copyTCE = t3lib_div::makeInstance("t3lib_TCEmain");
2604 $copyTCE->copyTree = $this->copyTree;
2605 $copyTCE->cachedTSconfig = $this->cachedTSconfig; // Copy forth the cached TSconfig
2606 $copyTCE->debug = $this->debug;
2607 $copyTCE->dontProcessTransformations=1; // Transformations should NOT be carried out during copy
2608 // $copyTCE->enableLogging = $table=="pages"?1:0; // If enabled the list-view does not update...
2609
2610 $copyTCE->start($data,"",$this->BE_USER);
2611 $copyTCE->process_datamap();
2612
2613 $theNewSQLID = $copyTCE->substNEWwithIDs[$theNewID];
2614 if ($theNewSQLID) {
2615 $this->copyMappingArray[$table][$uid] = $theNewSQLID;
2616 }
2617 $this->cachedTSconfig = $copyTCE->cachedTSconfig; // Copy back the cached TSconfig
2618 unset($copyTCE);
2619 } else {
2620 $this->log($table,$uid,3,0,1,"Attempt to copy record that did not exist!");
2621 }
2622 } else {
2623 $this->log($table,$uid,3,0,1,"Attempt to copy record without permission");
2624 }
2625 }
2626 }
2627
2628 /**
2629 * Copying pages
2630 *
2631 * Main function for copying pages.
2632 * $destPid: >=0 then it points to a page-id on which to insert the record (as the first element). <0 then it points to a uid from its own table after which to insert it (works if
2633 *
2634 * @param [type] $uid: ...
2635 * @param [type] $destPid: ...
2636 * @return [type] ...
2637 */
2638 function copyPages($uid,$destPid) {
2639 $uid = intval($uid);
2640 $destPid = intval($destPid);
2641 // $this->copyMappingArray = Array(); // This must be done, but it's comment out because it's done in process_cmdmap()
2642
2643 // Finding list of tables to copy.
2644 $copyTablesArray = ($this->admin) ? $this->compileAdminTables() : explode(",",$this->BE_USER->groupData["tables_modify"]); // These are the tables, the user may modify
2645 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
2646 reset($copyTablesArray);
2647 while(list($k,$table)=each($copyTablesArray)) {
2648 if (!$table || !t3lib_div::inList($this->copyWhichTables.",pages",$table)) { // pages are always going...
2649 unset($copyTablesArray[$k]);
2650 }
2651 }
2652 }
2653 $copyTablesArray = array_unique($copyTablesArray);
2654 if ($this->admin || in_array("pages",$copyTablesArray)) { // If we're allowed to copy pages
2655 $this->copySpecificPage($uid,$destPid,$copyTablesArray,1); // Copy this page we're on. And set first-flag!
2656 $theNewRootID = $this->copyMappingArray["pages"][$uid]; // This is the new ID of the rootpage of the copyaction. This ID is excluded when the list is gathered lateron
2657 if ($theNewRootID && $this->copyTree) { // If we're going to copy recursively...
2658 $CPtable = $this->int_pageTreeInfo(Array(), $uid, intval($this->copyTree), $theNewRootID);
2659 if ($this->debug) {debug($CPtable);}
2660 // Now copying the pages
2661 reset($CPtable);
2662 while (list($thePageUid,$thePagePid)=each($CPtable)) {
2663 $newPid = $this->copyMappingArray["pages"][$thePagePid];
2664 if (isset($newPid)) {
2665 $this->copySpecificPage($thePageUid,$newPid,$copyTablesArray);
2666 } else {
2667 $this->log("pages",$uid,5,0,1,"Something went wrong during copying branch");
2668 break;
2669 }
2670 }
2671 } // else the page was not copied. Too bad...
2672 } else {
2673 $this->log("pages",$uid,5,0,1,"Attempt to copy page without permission to this table");
2674 }
2675 }
2676
2677 /**
2678 * Copying a single page ($uid) to $destPid and all tables in the array copyTablesArray.
2679 *
2680 * $destPid: >=0 then it points to a page-id on which to insert the record (as the first element). <0 then it points to a uid from its own table after which to insert it (works if
2681 *
2682 * @param [type] $uid: ...
2683 * @param [type] $destPid: ...
2684 * @param [type] $copyTablesArray: ...
2685 * @param [type] $first: ...
2686 * @return [type] ...
2687 */
2688 function copySpecificPage($uid,$destPid,$copyTablesArray,$first=0) {
2689 global $TCA;
2690 $this->copyRecord("pages",$uid,$destPid,$first); // Copy the page itselft.
2691 $theNewRootID = $this->copyMappingArray["pages"][$uid]; // The new uid
2692 if ($theNewRootID) { // copy of the page went fine
2693 reset($copyTablesArray);
2694 while(list(,$table)=each($copyTablesArray)) {
2695 if ($table && $TCA[$table] && $table!="pages") { // all records under the page is copied.
2696 $orderby = ($TCA[$table]["ctrl"]["sortby"]) ? " ORDER BY ".$TCA[$table]["ctrl"]["sortby"]." DESC" : "";
2697 $query = "SELECT uid FROM $table WHERE pid = $uid ".$this->deleteClause($table).$orderby;
2698 $mres = mysql(TYPO3_db,$query);
2699 while ($row = mysql_fetch_assoc($mres)) {
2700 $this->copyRecord($table,$row['uid'], $theNewRootID); // Copying each of the underlying records...
2701 }
2702 }
2703 }
2704 }
2705 }
2706
2707 /**
2708 * Returns array, $CPtable, of pages under the $pid going down to $counter levels
2709 *
2710 * @param [type] $CPtable: ...
2711 * @param [type] $pid: ...
2712 * @param [type] $counter: ...
2713 * @param [type] $rootID: ...
2714 * @return [type] ...
2715 */
2716 function int_pageTreeInfo($CPtable,$pid,$counter, $rootID) {
2717 if ($counter) {
2718 $addW = !$this->admin ? " AND ".$this->BE_USER->getPagePermsClause($this->pMap["show"]) : "";
2719 $query = "SELECT uid FROM pages WHERE pid = $pid ".$this->deleteClause("pages").$addW." ORDER BY sorting DESC";
2720 $mres = mysql(TYPO3_db,$query);
2721 while($row=mysql_fetch_assoc($mres)) {
2722 if ($row["uid"]!=$rootID) {
2723 $CPtable[$row["uid"]]=$pid;
2724 if ($counter-1) { // If the uid is NOT the rootID of the copyaction and if we are supposed to walk further down
2725 $CPtable = $this->int_pageTreeInfo($CPtable,$row['uid'],$counter-1, $rootID);
2726 }
2727 }
2728 }
2729 }
2730 return $CPtable;
2731 }
2732
2733 /**
2734 * List of all tables (those administrators has access to)
2735 *
2736 * @return [type] ...
2737 */
2738 function compileAdminTables() {
2739 global $TCA;
2740 reset ($TCA);
2741 $listArr = array();
2742 while (list($table)=each($TCA)) {
2743 $listArr[]=$table;
2744 }
2745 return $listArr;
2746 }
2747
2748 /**
2749 * Checks if any uniqueInPid eval input fields are in the record and if so, they are re-written to be correct.
2750 *
2751 * @param [type] $table: ...
2752 * @param [type] $uid: ...
2753 * @return [type] ...
2754 */
2755 function fixUniqueInPid($table,$uid) {
2756 global $TCA;
2757 if ($TCA[$table]) {
2758 t3lib_div::loadTCA($table);
2759 reset ($TCA[$table]["columns"]);
2760 $curData=$this->recordInfo($table,$uid,"*");
2761 $newData=array();
2762 while (list($field,$conf)=each($TCA[$table]["columns"])) {
2763 if ($conf["config"]["type"]=="input") {
2764 $evalCodesArray = t3lib_div::trimExplode(",",$conf["config"]["eval"],1);
2765 if (in_array("uniqueInPid",$evalCodesArray)) {
2766 $newV = $this->getUnique($table,$field,$curData[$field],$uid,$curData["pid"]);
2767 if (strcmp($newV,$curData[$field])) {
2768 $newData[$field]=$newV;
2769 }
2770 }
2771 }
2772 }
2773 // IF there are changed fields, then update the database
2774 if (count($newData)) {
2775 $this->updateDB($table,$uid,$newData);
2776 }
2777 }
2778 }
2779
2780 /**
2781 * When er record is copied you can specify fields from the previous record which should be copied into the new one
2782 * This function is also called with new elements. But then $update must be set to zero and $newData containing the data array. In that case data in the incoming array is NOT overridden. (250202)
2783 *
2784 * @param [type] $table: ...
2785 * @param [type] $uid: ...
2786 * @param [type] $prevUid: ...
2787 * @param [type] $update: ...
2788 * @param [type] $newData: ...
2789 * @return [type] ...
2790 */
2791 function fixCopyAfterDuplFields($table,$uid,$prevUid,$update, $newData=array()) {
2792 global $TCA;
2793 if ($TCA[$table] && $TCA[$table]["ctrl"]["copyAfterDuplFields"]) {
2794 t3lib_div::loadTCA($table);
2795 $prevData=$this->recordInfo($table,$prevUid,"*");
2796 $theFields = t3lib_div::trimExplode(",",$TCA[$table]["ctrl"]["copyAfterDuplFields"],1);
2797 reset($theFields);
2798 while(list(,$field)=each($theFields)) {
2799 if ($TCA[$table]["columns"][$field] && ($update || !isset($newData[$field]))) {
2800 $newData[$field]=$prevData[$field];
2801 }
2802 }
2803 if ($update && count($newData)) {
2804 $this->updateDB($table,$uid,$newData);
2805 }
2806 }
2807 return $newData;
2808 }
2809
2810 /**
2811 * Returns all fieldnames from a table which are a list of files
2812 *
2813 * @param [type] $table: ...
2814 * @return [type] ...
2815 */
2816 function extFileFields ($table) {
2817 global $TCA;
2818 $listArr=array();
2819 t3lib_div::loadTCA($table);
2820 if ($TCA[$table]["columns"]) {
2821 reset($TCA[$table]["columns"]);
2822 while (list($field,$configArr)=each($TCA[$table]["columns"])) {
2823 if ($configArr["config"]["type"]=="group" && $configArr["config"]["internal_type"]=="file") {
2824 $listArr[]=$field;
2825 }
2826 }
2827 }
2828 return $listArr;
2829 }
2830
2831 /**
2832 * Get copy header
2833 *
2834 * @param [type] $table: ...
2835 * @param [type] $pid: ...
2836 * @param [type] $field: ...
2837 * @param [type] $value: ...
2838 * @param [type] $count: ...
2839 * @param [type] $prevTitle: ...