*** empty log message ***
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_tcemain.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2003 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.
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 // When values are send as group or select they come as comma-separated values which are exploded by this function:
1349 $valueArray = $this->checkValue_group_select_explodeSelectGroupValue($value);
1350
1351 // If not multiple is set, then remove duplicates:
1352 if (!$tcaFieldConf['multiple']) {
1353 $valueArray = array_unique($valueArray);
1354 }
1355
1356 // This could be a good spot for parsing the array through a validation-function which checks if the values are allright
1357 // NOTE!!! Must check max-items of files before the later check because that check would just leave out filenames if there are too many!!
1358
1359
1360
1361 // For group types:
1362 if ($tcaFieldConf['type']=='group') {
1363 switch($tcaFieldConf['internal_type']) {
1364 case 'file':
1365 $valueArray = $this->checkValue_group_select_file(
1366 $valueArray,
1367 $tcaFieldConf,
1368 $curValue,
1369 $uploadedFiles,
1370 $status,
1371 $table,
1372 $id,
1373 $recFID
1374 );
1375 break;
1376 case 'db':
1377 $valueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'group');
1378 break;
1379 }
1380 }
1381 // For select types which has a foreign table attached:
1382 if ($tcaFieldConf['type']=='select' && $tcaFieldConf['foreign_table']) {
1383 $valueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'select');
1384 }
1385
1386
1387
1388 // Checking the number of items, that it is correct.
1389 // If files, there MUST NOT be too many files in the list at this point, so check that prior to this code.
1390 $valueArrayC = count($valueArray);
1391 $minI = isset($tcaFieldConf['minitems']) ? intval($tcaFieldConf['minitems']):0;
1392
1393 // 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.
1394 $maxI = isset($tcaFieldConf['maxitems']) ? intval($tcaFieldConf['maxitems']):1;
1395 if ($valueArrayC > $maxI) {$valueArrayC=$maxI;} // Checking for not too many elements
1396
1397 // Dumping array to list
1398 $newVal=array();
1399 foreach($valueArray as $nextVal) {
1400 if ($valueArrayC==0) {break;}
1401 $valueArrayC--;
1402 $newVal[]=$nextVal;
1403 }
1404 $res['value']=implode(',',$newVal);
1405
1406 return $res;
1407 }
1408
1409 /**
1410 * Handling files for group/select function
1411 *
1412 * @param [type] $valueArray: ...
1413 * @param [type] $tcaFieldConf: ...
1414 * @param [type] $curValue: ...
1415 * @param [type] $uploadedFileArray: ...
1416 * @param [type] $status: ...
1417 * @param [type] $table: ...
1418 * @param [type] $id: ...
1419 * @param [type] $recFID: ...
1420 * @return array Modified value array
1421 * @see checkValue_group_select()
1422 */
1423 function checkValue_group_select_file($valueArray,$tcaFieldConf,$curValue,$uploadedFileArray,$status,$table,$id,$recFID) {
1424
1425 // If any files are uploaded:
1426 if (is_array($uploadedFileArray) &&
1427 $uploadedFileArray['name'] &&
1428 strcmp($uploadedFileArray['tmp_name'],'none')) {
1429 $valueArray[]=$uploadedFileArray['tmp_name'];
1430 $this->alternativeFileName[$uploadedFileArray['tmp_name']] = $uploadedFileArray['name'];
1431 }
1432
1433 // Creating fileFunc object.
1434 if (!$this->fileFunc) {
1435 $this->fileFunc = t3lib_div::makeInstance('t3lib_basicFileFunctions');
1436 $this->include_filefunctions=1;
1437 }
1438 // Setting permitted extensions.
1439 $all_files = Array();
1440 $all_files['webspace']['allow'] = $tcaFieldConf['allowed'];
1441 $all_files['webspace']['deny'] = $tcaFieldConf['disallowed'] ? $tcaFieldConf['disallowed'] : '*';
1442 $all_files['ftpspace'] = $all_files['webspace'];
1443 $this->fileFunc->init('', $all_files);
1444
1445 // If there is an upload folder defined:
1446 if ($tcaFieldConf['uploadfolder']) {
1447 // For logging..
1448 $propArr = $this->getRecordProperties($table,$id);
1449
1450 // Get destrination path:
1451 $dest = $this->destPathFromUploadFolder($tcaFieldConf['uploadfolder']);
1452
1453 // If we are updating:
1454 if ($status=='update') {
1455
1456 // Finding the CURRENT files listed, either from MM or from the current record.
1457 $theFileValues=array();
1458 if ($tcaFieldConf['MM']) { // If MM relations for the files also!
1459 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
1460 $dbAnalysis->start('','files',$tcaFieldConf['MM'],$id);
1461 reset($dbAnalysis->itemArray);
1462 while (list($somekey,$someval)=each($dbAnalysis->itemArray)) {
1463 if ($someval['id']) {
1464 $theFileValues[]=$someval['id'];
1465 }
1466 }
1467 } else {
1468 $theFileValues=t3lib_div::trimExplode(',',$curValue,1);
1469 }
1470
1471 // DELETE files: If existing files were found, traverse those and register files for deletion which has been removed:
1472 if (count($theFileValues)) {
1473 // 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!)
1474 foreach($valueArray as $key => $theFile) {
1475 if ($theFile && !strstr(t3lib_div::fixWindowsFilePath($theFile),'/')) {
1476 $theFileValues = t3lib_div::removeArrayEntryByValue($theFileValues,$theFile);
1477 }
1478 }
1479
1480 // This array contains the filenames in the uploadfolder that should be deleted:
1481 foreach($theFileValues as $key => $theFile) {
1482 $theFile = trim($theFile);
1483 if (@is_file($dest.'/'.$theFile)) {
1484 $this->removeFilesStore[]=$dest.'/'.$theFile;
1485 } elseif ($theFile) {
1486 $this->log($table,$id,5,0,1,"Could not delete file '%s' (does not exist). (%s)",10,array($dest.'/'.$theFile, $recFID),$propArr['event_pid']);
1487 }
1488 }
1489 }
1490 }
1491
1492 // Traverse the submitted values:
1493 foreach($valueArray as $key => $theFile) {
1494 // 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)
1495 if (strstr(t3lib_div::fixWindowsFilePath($theFile),'/')) {
1496 // Init:
1497 $maxSize = intval($tcaFieldConf['max_size']);
1498 $cmd='';
1499 $theDestFile=''; // Must be cleared. Else a faulty fileref may be inserted if the below code returns an error!! (Change: 22/12/2000)
1500
1501 // Check various things before copying file:
1502 if (@is_dir($dest) && @is_file($theFile)) { // File and destination must exist
1503 if (!$maxSize || filesize($theFile)<=($maxSize*1024)) { // Check file size:
1504 // Prepare filename:
1505 $theEndFileName = isset($this->alternativeFileName[$theFile]) ? $this->alternativeFileName[$theFile] : $theFile;
1506 $fI = t3lib_div::split_fileref($theEndFileName);
1507
1508 // Check for allowed extension:
1509 if ($this->fileFunc->checkIfAllowed($fI['fileext'], $dest, $theEndFileName)) {
1510 $theDestFile = $this->fileFunc->getUniqueName($this->fileFunc->cleanFileName($fI['file']), $dest);
1511
1512 // If we have a unique destination filename, then write the file:
1513 if ($theDestFile) {
1514 t3lib_div::upload_copy_move($theFile,$theDestFile);
1515 $this->copiedFileMap[$theFile]=$theDestFile;
1516 clearstatcache();
1517 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']);
1518 } 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']);
1519 } else $this->log($table,$id,5,0,1,"Fileextension '%s' not allowed. (%s)",12,array($fI['fileext'], $recFID),$propArr['event_pid']);
1520 } else $this->log($table,$id,5,0,1,"Filesize (%s) of file '%s' exceeds limit (%s). (%s)",13,array(t3lib_div::formatSize(@filesize($theFile)),$theFile,t3lib_div::formatSize($maxSize*1024),$recFID),$propArr['event_pid']);
1521 } 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']);
1522
1523 // If the destination file was created, we will set the new filename in the value array, otherwise unset the entry in the value array!
1524 if (@is_file($theDestFile)) {
1525 $info = t3lib_div::split_fileref($theDestFile);
1526 $valueArray[$key]=$info['file']; // The value is set to the new filename
1527 } else {
1528 unset($valueArray[$key]); // The value is set to the new filename
1529 }
1530 }
1531 }
1532
1533 // 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!
1534 if ($tcaFieldConf['MM']) {
1535 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
1536 $dbAnalysis->tableArray['files']=array(); // dummy
1537
1538 reset($valueArray);
1539 while (list($key,$theFile)=each($valueArray)) {
1540 // explode files
1541 $dbAnalysis->itemArray[]['id']=$theFile;
1542 }
1543 if ($status=='update') {
1544 $dbAnalysis->writeMM($tcaFieldConf['MM'],$id,0);
1545 } else {
1546 $this->dbAnalysisStore[] = array($dbAnalysis, $tcaFieldConf['MM'], $id, 0); // This will be traversed later to execute the actions
1547 }
1548 $cc=count($dbAnalysis->itemArray);
1549 $valueArray = array($cc);
1550 }
1551 }
1552
1553 return $valueArray;
1554 }
1555
1556 /**
1557 * Evaluates "flex" type values.
1558 *
1559 * @param array The result array. The processed value (if any!) is set in the "value" key.
1560 * @param string The value to set.
1561 * @param array Field configuration from TCA
1562 * @param array Additional parameters in a numeric array: $table,$id,$curValue,$status,$realPid,$recFID
1563 * @param array Uploaded files for the field
1564 * @param array Current record array.
1565 * @param [type] $field: ...
1566 * @return array Modified $res array
1567 */
1568 function checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$curRecordArr,$field) {
1569 list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
1570
1571 if (is_array($value)) {
1572
1573 // Get current value array:
1574 $dataStructArray = t3lib_BEfunc::getFlexFormDS($tcaFieldConf,$curRecordArr,$table);
1575 $currentValueArray = t3lib_div::xml2array($curValue);
1576 if (is_array($currentValueArray['meta']['currentLangId'])) unset($currentValueArray['meta']['currentLangId']); // Remove all old meta for languages...
1577
1578 // Evaluation of input values:
1579 $value['data'] = $this->checkValue_flex_procInData($value['data'],$currentValueArray['data'],$uploadedFiles['data'],$dataStructArray,array($table,$id,$curValue,$status,$realPid,$recFID));
1580
1581 // Create XML and convert charsets from input value:
1582 $xmlValue = t3lib_div::array2xml($value,'',0,'T3FlexForms');
1583
1584 // If we wanted to set UTF fixed:
1585 // $storeInCharset='utf-8';
1586 // $currentCharset=$GLOBALS['LANG']->charSet;
1587 // $xmlValue = $GLOBALS['LANG']->csConvObj->conv($xmlValue,$currentCharset,$storeInCharset,1);
1588 $storeInCharset=$GLOBALS['LANG']->charSet;
1589
1590 // Merge them together IF they are both arrays:
1591 // 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).
1592 if (is_array($currentValueArray)) {
1593 $arrValue = t3lib_div::xml2array($xmlValue);
1594 $arrValue = t3lib_div::array_merge_recursive_overrule($currentValueArray,$arrValue);
1595 $xmlValue = t3lib_div::array2xml($arrValue,'',0,'T3FlexForms');
1596 }
1597
1598 // Temporary fix to delete elements:
1599 $deleteCMDs=t3lib_div::GPvar('_DELETE_FLEX_FORMdata');
1600
1601 if (is_array($deleteCMDs[$table][$id][$field]['data'])) {
1602 $arrValue = t3lib_div::xml2array($xmlValue);
1603 $this->_DELETE_FLEX_FORMdata($arrValue['data'],$deleteCMDs[$table][$id][$field]['data']);
1604 #debug($deleteCMDs[$table][$id][$field]['data']);
1605 #debug($arrValue);
1606 $xmlValue = t3lib_div::array2xml($arrValue,'',0,'T3FlexForms');
1607 }
1608
1609 // Create the value XML:
1610 $res['value']='';
1611 $res['value'].='<?xml version="1.0" encoding="'.$storeInCharset.'" standalone="yes" ?>'.chr(10);
1612 $res['value'].=$xmlValue;
1613 } else {
1614 $res['value']=$value;
1615 }
1616
1617 return $res;
1618 }
1619
1620 /**
1621 * [Describe function...]
1622 *
1623 * @param [type] $$valueArrayToRemoveFrom: ...
1624 * @param [type] $deleteCMDS: ...
1625 * @return [type] ...
1626 */
1627 function _DELETE_FLEX_FORMdata(&$valueArrayToRemoveFrom,$deleteCMDS) {
1628 if (is_array($valueArrayToRemoveFrom) && is_array($deleteCMDS)) {
1629 foreach($deleteCMDS as $key => $value) {
1630 if (is_array($deleteCMDS[$key])) {
1631 $this->_DELETE_FLEX_FORMdata($valueArrayToRemoveFrom[$key],$deleteCMDS[$key]);
1632 } else {
1633 unset($valueArrayToRemoveFrom[$key]);
1634 }
1635 }
1636 }
1637 }
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658 /*********************************************
1659 *
1660 * Helper functions for evaluation functions.
1661 *
1662 ********************************************/
1663
1664
1665 /**
1666 * Gets a unique value for $table/$id/$field based on $value
1667 *
1668 * @param string Table name
1669 * @param string Field name for which $value must be unique
1670 * @param string Value string.
1671 * @param [type] $id: ...
1672 * @param integer If set, the value will be unique for this PID
1673 * @return string Modified value (if not-unique). Will be the value appended with a number (until 100, then the function just breaks).
1674 */
1675 function getUnique($table,$field,$value,$id,$newPid=0) {
1676 global $TCA;
1677
1678 t3lib_div::loadTCA($table);
1679 $whereAdd='';
1680 $newValue='';
1681 if (intval($newPid)) {$whereAdd.=' AND pid='.intval($newPid);}
1682 $whereAdd.=$this->deleteClause($table);
1683
1684 if (isset($TCA[$table]['columns'][$field])) {
1685 // Look for a record which might already have the value:
1686 $res = mysql(TYPO3_db,'SELECT uid FROM '.$table.' WHERE '.$field.'="'.addslashes($value).'" AND uid!='.intval($id).$whereAdd);
1687 $counter=0;
1688 // For as long as records with the test-value existing, try again (with incremented numbers appended).
1689 while (mysql_num_rows($res)) {
1690 $newValue = $value.$counter;
1691 $res = mysql(TYPO3_db,'SELECT uid FROM '.$table.' WHERE '.$field.'="'.addslashes($newValue).'" AND uid!='.intval($id).$whereAdd);
1692 $counter++;
1693 if ($counter>100) {break;}
1694 }
1695 $value = $newValue ? $newValue : $value;
1696 }
1697 return $value;
1698 }
1699
1700 /**
1701 * Evaluation of 'input'-type values based on 'eval' list
1702 *
1703 * @param string Value
1704 * @param array Array of evaluations to traverse.
1705 * @param string Is-in string
1706 * @return string Modified $value
1707 */
1708 function checkValue_input_Eval($value,$evalArray,$is_in) {
1709 $res = Array();
1710 $newValue = $value;
1711 $set = true;
1712
1713 foreach($evalArray as $func) {
1714 switch($func) {
1715 case 'int':
1716 case 'year':
1717 case 'date':
1718 case 'datetime':
1719 case 'time':
1720 case 'timesec':
1721 $value = intval($value);
1722 break;
1723 case 'double2':
1724 $theDec = 0;
1725 for ($a=strlen($value); $a>0; $a--) {
1726 if (substr($value,$a-1,1)=='.' || substr($value,$a-1,1)==',') {
1727 $theDec = substr($value,$a);
1728 $value = substr($value,0,$a-1);
1729 break;
1730 }
1731 }
1732 $theDec = ereg_replace('[^0-9]','',$theDec).'00';
1733 $value = intval(str_replace(' ','',$value)).'.'.substr($theDec,0,2);
1734 break;
1735 case 'md5':
1736 if (strlen($value)!=32){$set=false;}
1737 break;
1738 case 'trim':
1739 $value = trim($value);
1740 break;
1741 case 'upper':
1742 $value = strtoupper($value);
1743 # $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.
1744 break;
1745 case 'lower':
1746 $value = strtolower($value);
1747 # $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.
1748 break;
1749 case 'required':
1750 if (!$value) {$set=0;}
1751 break;
1752 case 'is_in':
1753 $c=strlen($value);
1754 if ($c) {
1755 $newVal = '';
1756 for ($a=0;$a<$c;$a++) {
1757 $char = substr($value,$a,1);
1758 if (strstr($is_in,$char)) {
1759 $newVal.=$char;
1760 }
1761 }
1762 $value = $newVal;
1763 }
1764 break;
1765 case 'nospace':
1766 $value = str_replace(' ','',$value);
1767 break;
1768 case 'alpha':
1769 $value = ereg_replace('[^a-zA-Z]','',$value);
1770 break;
1771 case 'num':
1772 $value = ereg_replace('[^0-9]','',$value);
1773 break;
1774 case 'alphanum':
1775 $value = ereg_replace('[^a-zA-Z0-9]','',$value);
1776 break;
1777 case 'alphanum_x':
1778 $value = ereg_replace('[^a-zA-Z0-9_-]','',$value);
1779 break;
1780 }
1781 }
1782 if ($set) {$res['value'] = $value;}
1783 return $res;
1784 }
1785
1786 /**
1787 * Returns data for group/db and select fields
1788 *
1789 * @param array Current value array
1790 * @param array TCA field config
1791 * @param integer Record id, used for look-up of MM relations (local_uid)
1792 * @param string Status string ("update" or "new")
1793 * @param string The type, either "select" or "group"
1794 * @return array Modified value array
1795 */
1796 function checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,$type) {
1797 $tables = $type=='group'?$tcaFieldConf['allowed']:$tcaFieldConf['foreign_table'].','.$tcaFieldConf['neg_foreign_table'];
1798 $prep = $type=='group'?$tcaFieldConf['prepend_tname']:$tcaFieldConf['neg_foreign_table'];
1799
1800 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
1801 $dbAnalysis->registerNonTableValues=$tcaFieldConf['allowNonIdValues'] ? 1 : 0;
1802 $dbAnalysis->start(implode($valueArray,','),$tables);
1803
1804 if ($tcaFieldConf['MM']) {
1805 if ($status=='update') {
1806 $dbAnalysis->writeMM($tcaFieldConf['MM'],$id,$prep);
1807 } else {
1808 $this->dbAnalysisStore[] = array($dbAnalysis,$tcaFieldConf['MM'],$id,$prep); // This will be traversed later to execute the actions
1809 }
1810 $cc=count($dbAnalysis->itemArray);
1811 $valueArray = array($cc);
1812 } else {
1813 $valueArray = $dbAnalysis->getValueArray($prep);
1814 if ($type=='select' && $prep) {
1815 $valueArray = $dbAnalysis->convertPosNeg($valueArray,$tcaFieldConf['foreign_table'],$tcaFieldConf['neg_foreign_table']);
1816 }
1817 }
1818
1819 // 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.
1820 return $valueArray;
1821 }
1822
1823 /**
1824 * Explodes the $value, which is a list of files/uids (group select)
1825 *
1826 * @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.
1827 * @return array The value array.
1828 */
1829 function checkValue_group_select_explodeSelectGroupValue($value) {
1830 $valueArray = t3lib_div::trimExplode(',',$value,1);
1831 reset($valueArray);
1832 while(list($key,$newVal)=each($valueArray)) {
1833 $temp=explode('|',$newVal,2);
1834 $valueArray[$key] = str_replace(',','',str_replace('|','',rawurldecode($temp[0])));
1835 }
1836 return $valueArray;
1837 }
1838
1839 /**
1840 * Processing the input data for flexforms. This will traverse all sheets / languages and for each it will traverse the sub-structure.
1841 *
1842 * @param array The "data" part of the INPUT flexform data
1843 * @param array The "data" part of the CURRENT flexform data
1844 * @param array The uploaded files for the "data" part of the INPUT flexform data
1845 * @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.
1846 * @param array A set of parameters to pass through for the calling of the evaluation functions
1847 * @return array The modified "data" part.
1848 * @see checkValue_flex_procInData_travDS()
1849 */
1850 function checkValue_flex_procInData($dataPart,$dataPart_current,$uploadedFiles,$dataStructArray,$pParams) {
1851 #debug(array($dataPart,$dataPart_current));
1852 if (is_array($dataPart)) {
1853 foreach($dataPart as $sKey => $sheetDef) {
1854 list ($dataStruct,$actualSheet) = t3lib_div::resolveSheetDefInDS($dataStructArray,$sKey);
1855
1856 if (is_array($dataStruct) && $actualSheet==$sKey && is_array($sheetDef)) {
1857 foreach($sheetDef as $lKey => $lData) {
1858 $this->checkValue_flex_procInData_travDS(
1859 $dataPart[$sKey][$lKey],
1860 $dataPart_current[$sKey][$lKey],
1861 $uploadedFiles[$sKey][$lKey],
1862 $dataStruct['ROOT']['el'],
1863 $pParams
1864 );
1865 }
1866 }
1867 }
1868 }
1869
1870 return $dataPart;
1871 }
1872
1873 /**
1874 * Processing of the sheet/language data array
1875 *
1876 * @param array Multidimensional Data array for sheet/language, passed by reference!
1877 * @param array Data structure which fits the data array
1878 * @param array A set of parameters to pass through for the calling of the evaluation functions
1879 * @param [type] $DSelements: ...
1880 * @param [type] $pParams: ...
1881 * @return void
1882 * @see checkValue_flex_procInData()
1883 */
1884 function checkValue_flex_procInData_travDS(&$dataValues,$dataValues_current,$uploadedFiles,$DSelements,$pParams) {
1885 if (is_array($DSelements)) {
1886
1887 // For each DS element:
1888 foreach($DSelements as $key => $dsConf) {
1889
1890 // Array/Section:
1891 if ($DSelements[$key]['type']=='array') {
1892 if (is_array($dataValues[$key]['el'])) {
1893 if ($DSelements[$key]['section']) {
1894 foreach($dataValues[$key]['el'] as $ik => $el) {
1895 $theKey = key($el);
1896 if (is_array($dataValues[$key]['el'][$ik][$theKey]['el'])) {
1897 $this->checkValue_flex_procInData_travDS(
1898 $dataValues[$key]['el'][$ik][$theKey]['el'],
1899 $dataValues_current[$key]['el'][$ik][$theKey]['el'],
1900 $uploadedFiles[$key]['el'][$ik][$theKey]['el'],
1901 $DSelements[$key]['el'][$theKey]['el'],
1902 $pParams
1903 );
1904 }
1905 }
1906 } else {
1907 if (!isset($dataValues[$key]['el'])) $dataValues[$key]['el']=array();
1908 $this->checkValue_flex_procInData_travDS(
1909 $dataValues[$key]['el'],
1910 $dataValues_current[$key]['el'],
1911 $uploadedFiles[$key]['el'],
1912 $DSelements[$key]['el'],
1913 $pParams
1914 );
1915 }
1916 }
1917 } else {
1918 if (is_array($dsConf['TCEforms']['config']) && is_array($dataValues[$key])) {
1919 foreach($dataValues[$key] as $vKey => $data) {
1920 list($CVtable,$CVid,$CVcurValue,$CVstatus,$CVrealPid,$CVrecFID) = $pParams;
1921
1922 $res = $this->checkValue_SW(
1923 array(),
1924 $dataValues[$key][$vKey],
1925 $dsConf['TCEforms']['config'],
1926 $CVtable,
1927 $CVid,
1928 $dataValues_current[$key][$vKey],
1929 $CVstatus,
1930 $CVrealPid,
1931 $CVrecFID,
1932 '',
1933 $uploadedFiles[$key][$vKey]
1934 );
1935
1936 // Evaluating the value.
1937 if (isset($res["value"])) {
1938 $dataValues[$key][$vKey]=$res["value"];
1939 }
1940
1941 }
1942 }
1943 }
1944 }
1945 }
1946 }
1947
1948
1949
1950
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 * Update database
1976 *
1977 * Does not check permissions but expects them to be verified on beforehand
1978 *
1979 * @param [type] $table: ...
1980 * @param [type] $id: ...
1981 * @param [type] $fieldArray: ...
1982 * @return [type] ...
1983 */
1984 function updateDB($table,$id,$fieldArray) {
1985 global $TCA;
1986 if ($this->debug) {debug($fieldArray);}
1987 if (is_array($fieldArray) && $TCA[$table] && intval($id) ) {
1988 reset($fieldArray);
1989 $fA=array();
1990 while (list($col,$val)=each($fieldArray)) {
1991 if ($col != "uid") { // Do not update the uid field
1992 $fA[]=$col."='".addslashes($val)."'";
1993 }
1994 }
1995 if (count($fA)) {
1996 $query= "UPDATE ".$table." set ".implode($fA,",")." WHERE uid = ".intval($id);
1997 @mysql(TYPO3_db,$query);
1998 if ($this->debug) {echo $query."<BR>".mysql_error();}
1999 if (!mysql_error()) {
2000 if ($this->checkStoredRecords) {$newRow = $this->checkStoredRecord($table,$id,$fieldArray,2);}
2001 $propArr=$this->getRecordPropertiesFromRow($table,$newRow);
2002 $theLogId = $this->log($table,$id,2,$recpid,0,"Record '%s' (%s) was updated.",10,array($propArr["header"],$table.":".$id),$propArr["event_pid"]);
2003 $this->setHistory($table,$id,$theLogId);
2004 $this->clear_cache($table,$id);
2005 if ($table=="pages") unset($this->pageCache[$id]); // Unset the pageCache for the id if table was page.
2006 } else {
2007 $this->log($table,$id,2,0,2,"MySQL error: '%s' (%s)",12,array(mysql_error(),$table.":".$id));
2008 }
2009 }
2010 }
2011 }
2012
2013 /**
2014 * Compares the incoming field array with the current record and unsets all fields which are the same.
2015 * If the returned array is empty, then the record should not be updated!
2016 * $fieldArray must be an array.
2017 *
2018 * @param [type] $table: ...
2019 * @param [type] $id: ...
2020 * @param [type] $fieldArray: ...
2021 * @return [type] ...
2022 */
2023 function compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray) {
2024 unset($currentRecord);
2025 $res = mysql(TYPO3_db,"SELECT * FROM $table WHERE uid=".intval($id));
2026
2027 // Fetch the types of the fields.
2028 if (mysql_num_rows($res)) {
2029 $currentRecord = mysql_fetch_assoc($res);
2030 $c=0;
2031 reset($currentRecord);
2032 $cRecTypes=array();
2033 while (list($col,$val)=each($currentRecord)) {
2034 $cRecTypes[$col]=mysql_field_type($res,$c);
2035 $c++;
2036 }
2037 }
2038
2039 // Unset the fields which are similar.
2040 if (is_array($currentRecord)) { // If current record exists...
2041 reset($fieldArray);
2042 while (list($col,$val)=each($fieldArray)) {
2043 if (!isset($currentRecord[$col]) ||
2044 !strcmp($val,$currentRecord[$col]) ||
2045 ($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.
2046 ) { // The field must exist in the current record and it MUST be different to the letter.
2047 unset($fieldArray[$col]);
2048 } else {
2049 $this->historyRecords[$table.":".$id]["oldRecord"][$col] = $currentRecord[$col];
2050 $this->historyRecords[$table.":".$id]["newRecord"][$col] = $fieldArray[$col];
2051 }
2052 }
2053 } else { // If the current record does not exist this is an error anyways and we just return an empty array here.
2054 $fieldArray=array();
2055 }
2056 return $fieldArray;
2057 }
2058
2059 /**
2060 * Insert into database
2061 *
2062 * Does not check permissions but expects them to be verified on beforehand
2063 *
2064 * @param [type] $table: ...
2065 * @param [type] $id: ...
2066 * @param [type] $fieldArray: ...
2067 * @return [type] ...
2068 */
2069 function insertDB($table,$id,$fieldArray) {
2070 global $TCA;
2071 if ($this->debug) {debug($fieldArray);}
2072 if (is_array($fieldArray) && $TCA[$table] && isset($fieldArray["pid"])) {
2073 reset($fieldArray);
2074 $fA=array();
2075 while (list($col,$val)=each($fieldArray)) {
2076 if ($col != "uid") { // Cannot insert uid
2077 $fA["f"][]=$col;
2078 $fA["v"][]="'".addslashes($val)."'";
2079 }
2080 }
2081 if (count($fA)) {
2082 $query = "INSERT INTO ".$table." (".implode($fA["f"],",").") VALUES (".implode($fA["v"],",").")";
2083 @mysql(TYPO3_db,$query);
2084 if ($this->debug) {echo $query."<BR>".mysql_error();}
2085 if (!mysql_error()) {
2086 $NEW_id = $id; // the NEW_id now holds the "NEWaæsdfjæs9345" -id
2087 $id = mysql_insert_id();
2088 $this->substNEWwithIDs[$NEW_id] = $id;
2089 $this->substNEWwithIDs_table[$NEW_id] = $table;
2090 if($this->debug) {debug($this->substNEWwithIDs);}
2091 if ($table=="pages") {
2092 $thePositionID = $this->getInterfacePagePositionID($id);
2093 } else {
2094 $thePositionID=0;
2095 }
2096 // Checking the record is properly saved and writing to log
2097 if ($this->checkStoredRecords) {$newRow=$this->checkStoredRecord($table,$id,$fieldArray,1);}
2098 $propArr=$this->getRecordPropertiesFromRow($table,$newRow);
2099 $page_propArr= $this->getRecordProperties("pages",$propArr["pid"]);
2100 $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);
2101 $this->clear_cache($table,$id);
2102 } else {
2103 $this->log($table,$id,1,0,2,"MySQL error: '%s' (%s)",12,array(mysql_error(),$table.":".$id));
2104 }
2105 }
2106 }
2107 }
2108
2109 /**
2110 * Checking stored record to see if the written values are properly updated.
2111 *
2112 * $action is only for logging
2113 *
2114 * @param [type] $table: ...
2115 * @param [type] $id: ...
2116 * @param [type] $fieldArray: ...
2117 * @param [type] $action: ...
2118 * @return [type] ...
2119 */
2120 function checkStoredRecord($table,$id,$fieldArray,$action) {
2121 global $TCA;
2122 $id = intval($id);
2123 if ($TCA[$table] && $id) {
2124 $res = mysql(TYPO3_db,"select * from $table where uid = $id");
2125 if ($row=mysql_fetch_assoc($res)) {
2126 reset($fieldArray);
2127 $errorString=array();
2128 while(list($key,$value)=each($fieldArray)){
2129 if ($this->checkStoredRecords_loose && !$value && !$row[$key]) {
2130 // Nothing...
2131 } elseif (strcmp($value,$row[$key])) {$errorString[]=$key;}
2132 }
2133 if (count($errorString)) {
2134 $this->log($table,$id,$action,0,102,"These fields are not properly updated in database: (".implode(",",$errorString).") Probably value mismatch with fieldtype.");
2135 }
2136 return $row;
2137 }
2138 }
2139 }
2140
2141 /**
2142 * Executing dbAnalysisStore
2143 *
2144 * @return [type] ...
2145 */
2146 function dbAnalysisStoreExec() {
2147 reset($this->dbAnalysisStore);
2148 while(list($k,$v)=each($this->dbAnalysisStore)) {
2149 $id = $this->substNEWwithIDs[$v[2]];
2150 if ($id) {
2151 $v[2] = $id;
2152 $v[0]->writeMM($v[1],$v[2],$v[3]);
2153 }
2154 }
2155 }
2156
2157 /**
2158 * Executing dbAnalysisStore
2159 *
2160 * @return [type] ...
2161 */
2162 function removeRegisteredFiles() {
2163 reset($this->removeFilesStore);
2164 while(list($k,$v)=each($this->removeFilesStore)) {
2165 unlink($v);
2166 // debug($v,1);
2167 }
2168 }
2169
2170 /**
2171 * Clearing the cache based on a page being updated
2172 *
2173 * If the $table is "pages" then cache is cleared for all pages on the same level (and subsequent?)
2174 * Else just clear the cache for the parent page of the record.
2175 *
2176 * @param [type] $table: ...
2177 * @param [type] $uid: ...
2178 * @return [type] ...
2179 */
2180 function clear_cache($table,$uid) {
2181 global $TCA;
2182 $uid = intval($uid);
2183 if ($TCA[$table] && $uid > 0) {
2184 if ($table=='pages') {
2185 // Builds list of pages on the SAME level as this page
2186 $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");
2187 $list_cache='(';
2188 while ($row_tmp = mysql_fetch_assoc($res_tmp)) {
2189 $list_cache.=$row_tmp["uid"].',';
2190 $pid_tmp=$row_tmp["pid"];
2191 }
2192 $list_cache.=$pid_tmp.')';
2193 $query = "DELETE FROM cache_pages WHERE page_id IN $list_cache";
2194 if ($this->debug) {echo $query."<BR>";}
2195 $res_tmp = mysql(TYPO3_db,$query);
2196 if ($this->debug) {echo mysql_affected_rows()."<BR>";}
2197
2198 // $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...
2199 $query2 = "DELETE FROM cache_pagesection WHERE page_id IN $list_cache";
2200 $res_tmp = mysql(TYPO3_db,$query2);
2201
2202 // Deletes all cached pages with a reference to the page. This is being tested
2203 if ($this->clearCache_like) {
2204 $query = "DELETE FROM cache_pages WHERE (".
2205 "HTML like '%?id=".$uid."%'".
2206 " OR HTML like '%?id=".$uid."&%'".
2207 " OR HTML like '%?".$uid."%'".
2208 " OR HTML like '%?".$uid."&%'".
2209 ")";
2210 if ($this->debug) {echo $query."<BR>";}
2211 $res_tmp = mysql(TYPO3_db,$query);
2212 if ($this->debug) {echo mysql_affected_rows()."<BR>";}
2213 }
2214 } else {
2215 $uid_page = $this->getPID($table,$uid);
2216 if ($uid_page>0) {
2217 $query="delete from cache_pages where page_id=$uid_page";
2218 if ($this->debug) {echo $query."<BR>";}
2219 $res_tmp = mysql(TYPO3_db,$query);
2220 if ($this->debug) {echo mysql_affected_rows()."<BR>";}
2221
2222
2223 $query2="delete from cache_pagesection where page_id=$uid_page";
2224 $res_tmp = mysql(TYPO3_db,$query2);
2225 }
2226 }
2227
2228 // Clear cache for pages entered in TSconfig:
2229 list($tscPID)=t3lib_BEfunc::getTSCpid($table,$uid,'');
2230 $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
2231 if ($TSConfig['clearCacheCmd']) {
2232 $Commands = t3lib_div::trimExplode(',',strtolower($TSConfig['clearCacheCmd']),1);
2233 $Commands = array_unique($Commands);
2234 foreach($Commands as $cmdPart) {
2235 $this->clear_cacheCmd($cmdPart);
2236 }
2237 }
2238
2239 // Call post processing function for clear-cache:
2240 global $TYPO3_CONF_VARS;
2241 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'])) {
2242 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'] as $funcRef) {
2243 $a = array(
2244 'table' => $table,
2245 'uid' => $uid,
2246 'uid_page' => $uid_page
2247 );
2248 t3lib_div::callUserFunction($funcRef,$a,$this);
2249 }
2250 }
2251 }
2252 }
2253
2254 /**
2255 * Returns the pid of a record from $table with $uid
2256 *
2257 * @param [type] $table: ...
2258 * @param [type] $uid: ...
2259 * @return [type] ...
2260 */
2261 function getPID($table,$uid) {
2262 $res_tmp = mysql(TYPO3_db,"select pid from $table where uid=".intval($uid));
2263 if (mysql_num_rows($res_tmp)) {
2264 return mysql_result($res_tmp,0,"pid");
2265 } else {return "";}
2266 }
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292 /*********************************************
2293 *
2294 * PROCESSING COMMANDS
2295 *
2296 ********************************************/
2297
2298 /**
2299 * Processing the cmd-array
2300 *
2301 * @return [type] ...
2302 */
2303 function process_cmdmap() {
2304 global $TCA;
2305 #debug($this->cmdmap);
2306 reset ($this->cmdmap);
2307 while (list($table,) = each($this->cmdmap)) {
2308 $modifyAccessList = $this->checkModifyAccessList($table);
2309 if (!$modifyAccessList) {
2310 $this->log($table,$id,2,0,1,"Attempt to modify table '%s' without permission",1,array($table));
2311 }
2312 if (isset($TCA[$table]) && !$this->tableReadOnly($table) && is_array($this->cmdmap[$table]) && $modifyAccessList) { // Is table from $TCA and
2313 #debug();
2314 reset ($this->cmdmap[$table]);
2315 while (list($id,$incomingCmdArray) = each($this->cmdmap[$table])) { // Har fundet en tabel
2316 if (is_array($incomingCmdArray)) { // Har fundet et ID-nummer
2317 reset($incomingCmdArray);
2318 $command = key($incomingCmdArray);
2319 $value = current($incomingCmdArray);
2320 switch ($command) {
2321 case "move":
2322 $this->moveRecord($table,$id,$value);
2323 break;
2324 case "copy":
2325 $this->copyMappingArray = Array(); // Must clear this array before call from here to those functions.
2326 if ($table == "pages") {
2327 $this->copyPages($id,$value);
2328 } else {
2329 $this->copyRecord($table,$id,$value,1);
2330 #debug(array($table,$id,$value));
2331 }
2332 // Merging the copy-array info together for remapping purposes.
2333 $this->copyMappingArray_merged= t3lib_div::array_merge_recursive_overrule($this->copyMappingArray_merged,$this->copyMappingArray);
2334 break;
2335 case "delete":
2336 if ($table == "pages") {
2337 $this->deletePages($id);
2338 } else {
2339 $this->deleteRecord($table,$id, 0);
2340 }
2341 break;
2342 }
2343 }
2344 }
2345 }
2346 }
2347 $this->remapListedDBRecords();
2348 }
2349
2350 /**
2351 * Moving records
2352 *
2353 * $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
2354 *
2355 * @param [type] $table: ...
2356 * @param [type] $uid: ...
2357 * @param [type] $destPid: ...
2358 * @return [type] ...
2359 */
2360 function moveRecord($table,$uid,$destPid) {
2361 global $TCA;
2362 $sortRow = $TCA[$table]["ctrl"]["sortby"];
2363 $destPid = intval($destPid);
2364 $origDestPid = $destPid;
2365 if ($TCA[$table]) {
2366 $propArr = $this->getRecordProperties($table,$uid); // Get this before we change the pid (for logging)
2367 $resolvedPid = $this->resolvePid($table,$destPid); // This is the actual pid of the moving.
2368
2369 // 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.
2370 // 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.
2371 if ($table!="pages" || $resolvedPid==$propArr["pid"]) {
2372 $mayMoveAccess=$this->checkRecordUpdateAccess($table,$uid); // Edit rights for the record...
2373 } else {
2374 $mayMoveAccess=$this->doesRecordExist($table,$uid,"delete");
2375 }
2376
2377 // 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
2378 if ($table!="pages" || $resolvedPid!=$propArr["pid"]) {
2379 $mayInsertAccess = $this->checkRecordInsertAccess($table,$resolvedPid,4); // Edit rights for the record...
2380 } else {
2381 $mayInsertAccess=$this->checkRecordUpdateAccess($table,$uid);
2382 }
2383
2384 // 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...)
2385 if ($destPid<0 && !$sortRow) {
2386 $destPid = $resolvedPid;
2387 }
2388
2389 //
2390 if ($TCA[$table]["ctrl"]["tstamp"]) {
2391 $tstampC = ", ".$TCA[$table]["ctrl"]["tstamp"]."=".time();
2392 } else $tstampC="";
2393
2394
2395 if ($mayMoveAccess) {
2396 if ($destPid>=0) { // insert as first element on page (where uid = $destPid)
2397 if ($mayInsertAccess) {
2398 if ($table!="pages" || $this->destNotInsideSelf ($destPid,$uid)) {
2399 $this->clear_cache($table,$uid); // clear cache before moving
2400 if ($sortRow) { // table is sorted by 'sortby'
2401 $sortNumber = $this->getSortNumber($table,$uid,$destPid);
2402 $query = "UPDATE $table SET pid='$destPid', $sortRow='$sortNumber'".$tstampC." WHERE uid = '$uid'"; // We now update the pid and sortnumber
2403 $res = mysql(TYPO3_db,$query);
2404 if ($this->debug) {echo $table.$uid.": Update pid(".$destPid.") and sorting number(".$sortNumber.")<BR>";}
2405 } else { // table is NOT sorted
2406 $query = "UPDATE $table SET pid='$destPid'".$tstampC." WHERE uid = '$uid'"; // We need only update the pid as this table is not sorted
2407 $res = mysql(TYPO3_db,$query);
2408 if ($this->debug) {echo $table.$uid.": Update pid only (no sorting)<BR>";}
2409 }
2410
2411 // Logging...
2412 $newPropArr = $this->getRecordProperties($table,$uid);
2413 $oldpagePropArr = $this->getRecordProperties("pages",$propArr["pid"]);
2414 $newpagePropArr = $this->getRecordProperties("pages",$destPid);
2415
2416 if ($destPid!=$propArr["pid"]) {
2417 $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
2418 $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
2419 } else {
2420 $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
2421 }
2422 $this->clear_cache($table,$uid); // clear cache after moving
2423 $this->fixUniqueInPid($table,$uid);
2424 // fixCopyAfterDuplFields
2425 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.
2426 } else {
2427 $destPropArr = $this->getRecordProperties("pages",$destPid);
2428 $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"]);
2429 }
2430 }
2431 } else { // Put after another record
2432 if ($sortRow) { // table is being sorted
2433 $sortInfo = $this->getSortNumber($table,$uid,$destPid);
2434 $destPid = $sortInfo["pid"]; // Setting the destPid to the new pid of the record.
2435 if (is_array($sortInfo)) { // If not an array, there was an error (which is already logged)
2436 if ($mayInsertAccess) {
2437 if ($table!="pages" || $this->destNotInsideSelf ($destPid,$uid)) {
2438 $this->clear_cache($table,$uid); // clear cache before moving
2439 $query = "UPDATE $table SET pid='".$destPid."', $sortRow='".$sortInfo["sortNumber"]."'".$tstampC." WHERE uid = '$uid'"; // We now update the pid and sortnumber
2440 $res = mysql(TYPO3_db,$query);
2441 if ($this->debug) {echo $table.$uid.": Update pid(".$destPid.") and sorting number(".$sortInfo["sortNumber"].")<BR>";}
2442 // Logging...
2443 if ($table=="pages") {
2444 $thePositionID = $this->getInterfacePagePositionID($uid);
2445 } else {
2446 $thePositionID=0;
2447 }
2448
2449 $this->log($table,$uid,4,$thePositionID,0,"");
2450 // Logging...
2451 $newPropArr = $this->getRecordProperties($table,$uid);
2452 $oldpagePropArr = $this->getRecordProperties("pages",$propArr["pid"]);
2453 if ($destPid!=$propArr["pid"]) {
2454 $newpagePropArr = $this->getRecordProperties("pages",$destPid);
2455 $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
2456 $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
2457 } else {
2458 $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
2459 }
2460 $this->clear_cache($table,$uid); // clear cache after moving
2461 // fixUniqueInPid
2462 $this->fixUniqueInPid($table,$uid);
2463 // fixCopyAfterDuplFields
2464 if ($origDestPid<0) {$this->fixCopyAfterDuplFields($table,$uid,abs($origDestPid),1);}
2465 } else {
2466 $destPropArr = $this->getRecordProperties("pages",$destPid);
2467 $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"]);
2468 }
2469 }
2470 }
2471 } else {
2472 $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"]);
2473 }
2474 }
2475 } else {
2476 $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"]);
2477 }
2478 }
2479 }
2480
2481 /**
2482 * Copying records
2483 *
2484 * $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
2485 * $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
2486 *
2487 * @param [type] $table: ...
2488 * @param [type] $uid: ...
2489 * @param [type] $destPid: ...
2490 * @param [type] $first: ...
2491 * @return [type] ...
2492 */
2493 function copyRecord($table,$uid,$destPid,$first=0) {
2494 global $TCA;
2495 $uid = intval($uid);
2496 if ($TCA[$table] && $uid) {
2497 t3lib_div::loadTCA($table);
2498 if ($this->doesRecordExist($table,$uid,"show")) {
2499 $data = Array();
2500 $nonFields = explode(",","uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody");
2501 $row = $this->recordInfo($table,$uid,"*");
2502 if (is_array($row)) {
2503 $theNewID = uniqid("NEW");
2504 // $fileFieldArr = $this->extFileFields($table); // Fetches all fields that holds references to files
2505 $enableField = isset($TCA[$table]["ctrl"]["enablecolumns"]) ? $TCA[$table]["ctrl"]["enablecolumns"]["disabled"] : "";
2506 $headerField = $TCA[$table]["ctrl"]["label"];
2507 $defaultData = $this->newFieldArray($table);
2508
2509 $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...
2510 $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
2511 $tE = $this->getTableEntries($table,$TSConfig);
2512 //debug(array($table,$destPid,$TSConfig));
2513
2514 reset($row);
2515 while (list($field,$value)=each($row)) {
2516 if (!in_array($field,$nonFields)) {
2517 $conf = $TCA[$table]["columns"][$field]["config"];
2518
2519 if ($field=="pid") {
2520 $value = $destPid;
2521 }
2522
2523 if ($TCA[$table]["ctrl"]["setToDefaultOnCopy"] && t3lib_div::inList($TCA[$table]["ctrl"]["setToDefaultOnCopy"],$field)) {
2524 $value = $defaultData[$field];
2525 } else {
2526 if ($first && $field==$enableField && $TCA[$table]["ctrl"]["hideAtCopy"] && !$this->neverHideAtCopy && !$tE["disableHideAtCopy"]) {
2527 $value=1;
2528 }
2529 if ($first && $field==$headerField && $TCA[$table]["ctrl"]["prependAtCopy"] && !$tE["disablePrependAtCopy"]) {
2530 $value = $this->getCopyHeader ($table,$this->resolvePid($table,$destPid),$field,$this->clearPrefixFromValue($table,$value),0);
2531 }
2532
2533 // Take care of files...
2534 if ($conf["type"]=="group" && $conf["internal_type"]=="file") {
2535 if ($conf["MM"]) {
2536 $theFileValues=array();
2537 $dbAnalysis = t3lib_div::makeInstance("t3lib_loadDBGroup");
2538 $dbAnalysis->start("","files",$conf["MM"],$uid);
2539 reset($dbAnalysis->itemArray);
2540 while (list($somekey,$someval)=each($dbAnalysis->itemArray)) {
2541 // debug($someval["id"]);
2542 if ($someval["id"]) {
2543 $theFileValues[]=$someval["id"];
2544 }
2545 }
2546 } else {
2547 $theFileValues = explode(",",$value);
2548 }
2549 // debug($theFileValues);
2550 reset($theFileValues);
2551 $uploadFolder = $conf["uploadfolder"];
2552 $dest = $this->destPathFromUploadFolder($uploadFolder);
2553 $newValue = array();
2554 while (list(,$file)=each($theFileValues)) {
2555 if (trim($file)) {
2556 $realFile = $dest."/".trim($file);
2557 if (@is_file($realFile)) {
2558 $newValue[]=$realFile;
2559 }
2560 }
2561 }
2562 $value = implode(",",$newValue);
2563 }
2564 // db record lists:
2565 if (($conf["type"]=="group" && $conf["internal_type"]=="db") || ($conf["type"]=="select" && $conf["foreign_table"])) {
2566 $allowedTables = $conf["type"]=="group" ? $conf["allowed"] : $conf["foreign_table"].",".$conf["neg_foreign_table"];
2567 $prependName = $conf["type"]=="group" ? $conf["prepend_tname"] : $conf["neg_foreign_table"];
2568 if ($conf["MM"]) {
2569 $dbAnalysis = t3lib_div::makeInstance("t3lib_loadDBGroup");
2570 $dbAnalysis->start("",$allowedTables,$conf["MM"],$uid);
2571 $value = implode(",",$dbAnalysis->getValueArray($prependName));
2572 }
2573 if ($value) {
2574 $this->registerDBList[$table][$uid][$field]=$value;
2575 }
2576 }
2577 }
2578
2579 // Add value to array.
2580 $value=addSlashes($value); // Added 15-03-00
2581 $data[$table][$theNewID][$field]=$value;
2582 }
2583 }
2584
2585 // Added 02-05-02 to set the fields correctly for copied records...
2586 if ($destPid<0 && is_array($data[$table][$theNewID])) {
2587 $copyAfterFields = $this->fixCopyAfterDuplFields($table,$uid,abs($destPid),0);
2588 $data[$table][$theNewID] = array_merge($data[$table][$theNewID],$copyAfterFields);
2589 //debug($data[$table][$theNewID]);
2590 } // 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.
2591
2592
2593 // Do the copy:
2594 //debug($data[$table][$theNewID]);
2595 $copyTCE = t3lib_div::makeInstance("t3lib_TCEmain");
2596 $copyTCE->copyTree = $this->copyTree;
2597 $copyTCE->cachedTSconfig = $this->cachedTSconfig; // Copy forth the cached TSconfig
2598 $copyTCE->debug = $this->debug;
2599 $copyTCE->dontProcessTransformations=1; // Transformations should NOT be carried out during copy
2600 // $copyTCE->enableLogging = $table=="pages"?1:0; // If enabled the list-view does not update...
2601
2602 $copyTCE->start($data,"",$this->BE_USER);
2603 $copyTCE->process_datamap();
2604
2605 $theNewSQLID = $copyTCE->substNEWwithIDs[$theNewID];
2606 if ($theNewSQLID) {
2607 $this->copyMappingArray[$table][$uid] = $theNewSQLID;
2608 }
2609 $this->cachedTSconfig = $copyTCE->cachedTSconfig; // Copy back the cached TSconfig
2610 unset($copyTCE);
2611 } else {
2612 $this->log($table,$uid,3,0,1,"Attempt to copy record that did not exist!");
2613 }
2614 } else {
2615 $this->log($table,$uid,3,0,1,"Attempt to copy record without permission");
2616 }
2617 }
2618 }
2619
2620 /**
2621 * Copying pages
2622 *
2623 * Main function for copying pages.
2624 * $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
2625 *
2626 * @param [type] $uid: ...
2627 * @param [type] $destPid: ...
2628 * @return [type] ...
2629 */
2630 function copyPages($uid,$destPid) {
2631 $uid = intval($uid);
2632 $destPid = intval($destPid);
2633 // $this->copyMappingArray = Array(); // This must be done, but it's comment out because it's done in process_cmdmap()
2634
2635 // Finding list of tables to copy.
2636 $copyTablesArray = ($this->admin) ? $this->compileAdminTables() : explode(",",$this->BE_USER->groupData["tables_modify"]); // These are the tables, the user may modify
2637 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
2638 reset($copyTablesArray);
2639 while(list($k,$table)=each($copyTablesArray)) {
2640 if (!$table || !t3lib_div::inList($this->copyWhichTables.",pages",$table)) { // pages are always going...
2641 unset($copyTablesArray[$k]);
2642 }
2643 }
2644 }
2645 $copyTablesArray = array_unique($copyTablesArray);
2646 if ($this->admin || in_array("pages",$copyTablesArray)) { // If we're allowed to copy pages
2647 $this->copySpecificPage($uid,$destPid,$copyTablesArray,1); // Copy this page we're on. And set first-flag!
2648 $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
2649 if ($theNewRootID && $this->copyTree) { // If we're going to copy recursively...
2650 $CPtable = $this->int_pageTreeInfo(Array(), $uid, intval($this->copyTree), $theNewRootID);
2651 if ($this->debug) {debug($CPtable);}
2652 // Now copying the pages
2653 reset($CPtable);
2654 while (list($thePageUid,$thePagePid)=each($CPtable)) {
2655 $newPid = $this->copyMappingArray["pages"][$thePagePid];
2656 if (isset($newPid)) {
2657 $this->copySpecificPage($thePageUid,$newPid,$copyTablesArray);
2658 } else {
2659 $this->log("pages",$uid,5,0,1,"Something went wrong during copying branch");
2660 break;
2661 }
2662 }
2663 } // else the page was not copied. Too bad...
2664 } else {
2665 $this->log("pages",$uid,5,0,1,"Attempt to copy page without permission to this table");
2666 }
2667 }
2668
2669 /**
2670 * Copying a single page ($uid) to $destPid and all tables in the array copyTablesArray.
2671 *
2672 * $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
2673 *
2674 * @param [type] $uid: ...
2675 * @param [type] $destPid: ...
2676 * @param [type] $copyTablesArray: ...
2677 * @param [type] $first: ...
2678 * @return [type] ...
2679 */
2680 function copySpecificPage($uid,$destPid,$copyTablesArray,$first=0) {
2681 global $TCA;
2682 $this->copyRecord("pages",$uid,$destPid,$first); // Copy the page itselft.
2683 $theNewRootID = $this->copyMappingArray["pages"][$uid]; // The new uid
2684 if ($theNewRootID) { // copy of the page went fine
2685 reset($copyTablesArray);
2686 while(list(,$table)=each($copyTablesArray)) {
2687 if ($table && $TCA[$table] && $table!="pages") { // all records under the page is copied.
2688 $orderby = ($TCA[$table]["ctrl"]["sortby"]) ? " ORDER BY ".$TCA[$table]["ctrl"]["sortby"]." DESC" : "";
2689 $query = "SELECT uid FROM $table WHERE pid = $uid ".$this->deleteClause($table).$orderby;
2690 $mres = mysql(TYPO3_db,$query);
2691 while ($row = mysql_fetch_assoc($mres)) {
2692 $this->copyRecord($table,$row['uid'], $theNewRootID); // Copying each of the underlying records...
2693 }
2694 }
2695 }
2696 }
2697 }
2698
2699 /**
2700 * Returns array, $CPtable, of pages under the $pid going down to $counter levels
2701 *
2702 * @param [type] $CPtable: ...
2703 * @param [type] $pid: ...
2704 * @param [type] $counter: ...
2705 * @param [type] $rootID: ...
2706 * @return [type] ...
2707 */
2708 function int_pageTreeInfo($CPtable,$pid,$counter, $rootID) {
2709 if ($counter) {
2710 $addW = !$this->admin ? " AND ".$this->BE_USER->getPagePermsClause($this->pMap["show"]) : "";
2711 $query = "SELECT uid FROM pages WHERE pid = $pid ".$this->deleteClause("pages").$addW." ORDER BY sorting DESC";
2712 $mres = mysql(TYPO3_db,$query);
2713 while($row=mysql_fetch_assoc($mres)) {
2714 if ($row["uid"]!=$rootID) {
2715 $CPtable[$row["uid"]]=$pid;
2716 if ($counter-1) { // If the uid is NOT the rootID of the copyaction and if we are supposed to walk further down
2717 $CPtable = $this->int_pageTreeInfo($CPtable,$row['uid'],$counter-1, $rootID);
2718 }
2719 }
2720 }
2721 }
2722 return $CPtable;
2723 }
2724
2725 /**
2726 * List of all tables (those administrators has access to)
2727 *
2728 * @return [type] ...
2729 */
2730 function compileAdminTables() {
2731 global $TCA;
2732 reset ($TCA);
2733 $listArr = array();
2734 while (list($table)=each($TCA)) {
2735 $listArr[]=$table;
2736 }
2737 return $listArr;
2738 }
2739
2740 /**
2741 * Checks if any uniqueInPid eval input fields are in the record and if so, they are re-written to be correct.
2742 *
2743 * @param [type] $table: ...
2744 * @param [type] $uid: ...
2745 * @return [type] ...
2746 */
2747 function fixUniqueInPid($table,$uid) {
2748 global $TCA;
2749 if ($TCA[$table]) {
2750 t3lib_div::loadTCA($table);
2751 reset ($TCA[$table]["columns"]);
2752 $curData=$this->recordInfo($table,$uid,"*");
2753 $newData=array();
2754 while (list($field,$conf)=each($TCA[$table]["columns"])) {
2755 if ($conf["config"]["type"]=="input") {
2756 $evalCodesArray = t3lib_div::trimExplode(",",$conf["config"]["eval"],1);
2757 if (in_array("uniqueInPid",$evalCodesArray)) {
2758 $newV = $this->getUnique($table,$field,$curData[$field],$uid,$curData["pid"]);
2759 if (strcmp($newV,$curData[$field])) {
2760 $newData[$field]=$newV;
2761 }
2762 }
2763 }
2764 }
2765 // IF there are changed fields, then update the database
2766 if (count($newData)) {
2767 $this->updateDB($table,$uid,$newData);
2768 }
2769 }
2770 }
2771
2772 /**
2773 * When er record is copied you can specify fields from the previous record which should be copied into the new one
2774 * 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)
2775 *
2776 * @param [type] $table: ...
2777 * @param [type] $uid: ...
2778 * @param [type] $prevUid: ...
2779 * @param [type] $update: ...
2780 * @param [type] $newData: ...
2781 * @return [type] ...
2782 */
2783 function fixCopyAfterDuplFields($table,$uid,$prevUid,$update, $newData=array()) {
2784 global $TCA;
2785 if ($TCA[$table] && $TCA[$table]["ctrl"]["copyAfterDuplFields"]) {
2786 t3lib_div::loadTCA($table);
2787 $prevData=$this->recordInfo($table,$prevUid,"*");
2788 $theFields = t3lib_div::trimExplode(",",$TCA[$table]["ctrl"]["copyAfterDuplFields"],1);
2789 reset($theFields);
2790 while(list(,$field)=each($theFields)) {
2791 if ($TCA[$table]["columns"][$field] && ($update || !isset($newData[$field]))) {
2792 $newData[$field]=$prevData[$field];
2793 }
2794 }
2795 if ($update && count($newData)) {
2796 $this->updateDB($table,$uid,$newData);
2797 }
2798 }
2799 return $newData;
2800 }
2801
2802 /**
2803 * Returns all fieldnames from a table which are a list of files
2804 *
2805 * @param [type] $table: ...
2806 * @return [type] ...
2807 */
2808 function extFileFields ($table) {
2809 global $TCA;
2810 $listArr=array();
2811 t3lib_div::loadTCA($table);
2812 if ($TCA[$table]["columns"]) {
2813 reset($TCA[$table]["columns"]);
2814 while (list($field,$configArr)=each($TCA[$table]["columns"])) {
2815 if ($configArr["config"]["type"]=="group" && $configArr["config"]["internal_type"]=="file") {
2816 $listArr[]=$field;
2817 }
2818 }
2819 }
2820 return $listArr;
2821 }
2822
2823 /**
2824 * Get copy header
2825 *
2826 * @param [type] $table: ...
2827 * @param [type] $pid: ...
2828 * @param [type] $field: ...
2829 * @param [type] $value: ...
2830 * @param [type] $count: ...
2831 * @param [type] $prevTitle: ...
2832 * @return [type] ...
2833 */
2834 function getCopyHeader ($table,$pid,$field,$value,$count,$prevTitle="") {
2835 global $TCA;
2836 if ($count) {
2837 $checkTitle = $value.sprintf($this->prependLabel($table),$count);
2838 } else {
2839 $checkTitle = $value;
2840 }
2841 if ($prevTitle