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