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