Only changes to function indexes, comments and stripping of trailing whitespace in...
[Packages/TYPO3.CMS.git] / typo3 / class.show_rechis.inc
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2004 Kasper Skaarhoj (kasper@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Class for the record history display script (show_rechis.php)
29 *
30 * $Id$
31 * Revised for TYPO3 3.6 November/2003 by Kasper Skaarhoj
32 * XHTML Compliant
33 *
34 * @author Kasper Skaarhoj <kasper@typo3.com>
35 */
36 /**
37 * [CLASS/FUNCTION INDEX of SCRIPT]
38 *
39 *
40 *
41 * 83: class recordHistory
42 * 106: function recordHistory()
43 * 124: function main()
44 * 155: function displaySysHistoryEntry($sh_uid)
45 * 215: function revertToPreviousValues($element,$field)
46 * 281: function saveState($element,$sumUp)
47 * 335: function displayHistory($element)
48 *
49 * SECTION: Various helper functions
50 * 533: function nextHisUid($element,$hisUid)
51 * 579: function compareChangesWithCurrent($element,$changeRec)
52 * 624: function readFieldTypes($table,$id)
53 * 653: function cmp($changeStatus,$oldRecord)
54 * 676: function removeFilefields($table,$dataArray)
55 * 699: function renderEntry($entry,$table)
56 * 757: function listHeader()
57 * 801: function linkPage($str,$inparams=array(),$anchor='')
58 * 829: function getChangesSinceRecord($element,$hisUid=0,$hisUid_Stop=0)
59 *
60 * TOTAL FUNCTIONS: 15
61 * (This index is automatically created/updated by the extension "extdeveval")
62 *
63 */
64
65
66
67
68
69
70
71
72
73
74
75
76 /**
77 * Class for the record history display script (show_rechis.php)
78 *
79 * @author Kasper Skaarhoj <kasper@typo3.com>
80 * @package TYPO3
81 * @subpackage core
82 */
83 class recordHistory {
84
85 // External, static:
86 var $maxSteps=20; // Maximum number of sys_history steps to show.
87
88 // Internal, dynamic:
89 var $listType = 0; // This value determines the kind of list build. The variable is used as a parameter from some functions.
90
91 // Internal, static. GPvars:
92 var $sh_uid; // sh_uid is the id-number of the sys_history log item to SHOW
93 var $element; // Element reference, syntax [tablename]:[uid]
94 var $saveState; // Saving states: Points to a sys_history UID which should be saved.
95 var $returnUrl; // Return URL - kept in links, used to link back to calling module.
96 var $revert; // String identifying mode of reverting: Either all fields or only a single field to revert. See function revertToPreviousValues()
97 var $sumUp; // Generally used as a pointer to a sys_history uid as a state.
98 var $doReturn; // If set, function revertToPreviousValues() will perform a redirect to returnUrl
99
100
101 /**
102 * Constructor for the class
103 *
104 * @return void
105 */
106 function recordHistory() {
107
108 // GPvars:
109 $this->sh_uid = t3lib_div::_GP('sh_uid');
110 $this->element = t3lib_div::_GP('element');
111 $this->saveState = t3lib_div::_GP('saveState');
112 $this->returnUrl = t3lib_div::_GP('returnUrl');
113 $this->revert = t3lib_div::_GP('revert');
114 $this->sumUp = t3lib_div::_GP('sumUp');
115 $this->doReturn = t3lib_div::_GP('doReturn');
116 }
117
118 /**
119 * Main function for the listing of history.
120 * It detects incoming variables like element reference, history element uid etc. and renders the correct screen.
121 *
122 * @return void
123 */
124 function main() {
125
126 $content='';
127
128 // If link from sys log:
129 // sh_uid is the id-number of the sys_history log item
130 if ($this->sh_uid) {
131 $content.=$this->displaySysHistoryEntry($this->sh_uid);
132 }
133
134 // If link to element:
135 if ($this->element) {
136 if ($this->revert && $this->sumUp) {
137 $content.=$this->revertToPreviousValues($this->element,$this->revert);
138 }
139 if ($this->saveState) {
140 $content.=$this->saveState($this->element,$this->saveState);
141 }
142 $content.=$this->displayHistory($this->element);
143 }
144
145 // Return content variable:
146 return $content;
147 }
148
149 /**
150 * Displays a specific entry from the sys_history table
151 *
152 * @param integer UID of sys_history table entry
153 * @return string HTML content
154 */
155 function displaySysHistoryEntry($sh_uid) {
156 global $SOBE, $LANG, $TCA;
157
158 // Select the entry from the table:
159 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_history', 'uid='.intval($sh_uid));
160 $newRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
161
162 // If an entry was found:
163 if (is_array($newRow)) {
164
165 // Init:
166 $this->listType=0;
167 $lines=array();
168
169 // Create header:
170 $recIdentString = $LANG->sL($TCA[$newRow['tablename']]['ctrl']['title']).'/'.$newRow['recuid'];
171 $recIdentString = $this->linkPage(htmlspecialchars($recIdentString),array('sh_uid'=>'','element'=>$newRow['tablename'].':'.$newRow['recuid']),'uid_'.$sh_uid);
172 $theTime = t3lib_BEfunc::datetime($newRow['tstamp']).', '.t3lib_BEfunc::calcAge(time()-$newRow['tstamp'],$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears'));
173 $lines[]='
174 <tr class="bgColor5">
175 <td colspan="4">
176 <strong>'.$LANG->getLL('tableUid',1).':</strong> '.$recIdentString.'<br />
177 <strong>'.$LANG->getLL('time',1).':</strong> '.htmlspecialchars($theTime).'<br />
178 </td>
179 </tr>';
180
181 // Add header to accumulation:
182 $lines[]=$this->listHeader();
183
184 // Get the entry data and add it:
185 $historyData = unserialize($newRow['history_data']);
186 $lines = array_merge($lines,$this->renderEntry($historyData,$newRow['tablename']));
187
188 // Combine all content into a table for layout:
189 $theCode='
190
191 <!--
192 History for item:
193 -->
194 <table border="0" cellpadding="2" cellspacing="2" id="typo3-history-item">
195 '.implode('',$lines).'
196 </table>';
197 $theCode.='
198 <br /><img'.t3lib_iconWorks::skinImg('','gfx/icon_note.gif','width="18" height="16"').' align="top" alt="" />'.$LANG->getLL('differenceMsg').'<br /><br />';
199
200 // Create the module section:
201 $content.=$SOBE->doc->section($LANG->getLL('changes'),$theCode,0,1);
202 }
203
204 // Return content:
205 return $content;
206 }
207
208 /**
209 * Return to previous values for element
210 *
211 * @param string Element reference, syntax "[table]:[uid]"
212 * @param string Tells which field to restore. A single field (eg named "myField") is defined as "field:myField" while ALL fields is indicated by the string "ALL_FIELDS"
213 * @return void The function writes through tceMain and ends with a header-location, if instructed to.
214 */
215 function revertToPreviousValues($element,$field) {
216 $sumUp = $this->sumUp; // sys_history uid from which to get previous values
217
218 $elParts = explode(':',$element);
219 $redirect = intval($this->doReturn);
220 if ($sumUp==-1) { // Undo/Redo
221 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
222 'uid',
223 'sys_history',
224 'sys_history.tablename="'.$GLOBALS['TYPO3_DB']->quoteStr($elParts[0], 'sys_history').'"
225 AND sys_history.recuid='.intval($elParts[1]),
226 '',
227 'uid DESC',
228 '1'
229 );
230 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
231 $sumUp=$row['uid'];
232 }
233 $redirect = 1;
234 }
235 if ($sumUp!=-1) {
236 $changeRec=$this->compareChangesWithCurrent($element,$this->getChangesSinceRecord($element,$sumUp));
237
238 $data =array();
239 if (t3lib_BEfunc::getRecord($elParts[0],$elParts[1])) {
240
241 // Fields field(s) to restore:
242 if ($field=='ALL_FIELDS') {
243 $data=$changeRec['oldRecord'];
244 } elseif(substr($field,0,6)=='field:') {
245 $data[substr($field,6)]=$changeRec['oldRecord'][substr($field,6)];
246 }
247 // Removing fields:
248 $data = $this->removeFilefields($elParts[0],$data);
249
250 // If there are fields to write:
251 if (count($data)) {
252
253 // Setting data right:
254 $inData=array();
255 $inData[$elParts[0]][$elParts[1]]=$data;
256
257 // Writes the data:
258 $tce = t3lib_div::makeInstance('t3lib_TCEmain');
259 $tce->stripslashes_values=0;
260 $tce->debug=0;
261 $tce->dontProcessTransformations=1;
262 $tce->start($inData,array());
263 $tce->process_datamap();
264 }
265 }
266 }
267
268 if ($redirect) {
269 Header ('Location: '.t3lib_div::locationHeaderUrl($this->returnUrl));
270 exit;
271 }
272 }
273
274 /**
275 * Will save state uid $sumUp of element
276 *
277 * @param string Element reference, syntax "[table]:[uid]"
278 * @param integer sys_history uid from which to get previous values
279 * @return void
280 */
281 function saveState($element,$sumUp) {
282 $elParts = explode(':',$element);
283
284 // Find the changes since $sumUp sys_history uid
285 $changeRec = $this->getChangesSinceRecord($element,$sumUp);
286
287 // Select most recent sys_history record for the element:
288 $lastestData = array();
289 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
290 'history_data',
291 'sys_history',
292 'sys_history.tablename="'.$GLOBALS['TYPO3_DB']->quoteStr($elParts[0], 'sys_history').'"
293 AND sys_history.recuid='.intval($elParts[1]),
294 '',
295 'uid DESC',
296 '1'
297 );
298 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
299 $lastestData = unserialize($row['history_data']);
300 }
301
302 // Create forged history data from the most recent state and the previous state to save:
303 $historyRecords=array();
304 $historyRecords['oldRecord'] = $changeRec['changes'];
305 $historyRecords['newRecord'] = array();
306
307 reset($historyRecords['oldRecord']);
308 while(list($kk)=each($historyRecords['oldRecord'])) {
309 $historyRecords['newRecord'][$kk]=$lastestData['newRecord'][$kk];
310 }
311
312 // Update log:
313 $updateID = $GLOBALS['BE_USER']->writelog(3,1,0,1,'Saved state','');
314
315 // Create query for inserting into sys_history table:
316 $fields_values = array(
317 'history_data' => serialize($historyRecords),
318 'fieldlist' => implode(',',array_keys($historyRecords['oldRecord'])),
319 'tstamp' => time(),
320 'tablename' => $elParts[0],
321 'recuid' => $elParts[1],
322 'sys_log_uid' => $updateID,
323 'snapshot' => 1
324 );
325 // Save state by executing this query:
326 $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_history', $fields_values);
327 }
328
329 /**
330 * Displays the history states of an element
331 *
332 * @param string Element reference, syntax "[table]:[uid]"
333 * @return string HTML for list, wrapped in a table.
334 */
335 function displayHistory($element) {
336 global $SOBE, $LANG, $TCA;
337
338 // Initialize:
339 $elParts = explode(':',$element);
340 $table = $elParts[0];
341
342 // If table is found in $TCA:
343 if ($TCA[$table]) {
344
345 // Counting number of states:
346 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
347 'count(*)',
348 'sys_history,sys_log',
349 'sys_history.sys_log_uid=sys_log.uid
350 AND sys_history.tablename="'.$GLOBALS['TYPO3_DB']->quoteStr($table, 'sys_history').'"
351 AND sys_history.recuid='.intval($elParts[1])
352 );
353 list($Rcount) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
354
355 // Selecting the $this->maxSteps most recent states:
356 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
357 'sys_history.*,sys_log.userid',
358 'sys_history,sys_log',
359 'sys_history.sys_log_uid=sys_log.uid
360 AND sys_history.tablename="'.$GLOBALS['TYPO3_DB']->quoteStr($table, 'sys_history').'"
361 AND sys_history.recuid='.intval($elParts[1]),
362 '',
363 'uid',
364 t3lib_div::intInRange($Rcount-$this->maxSteps,0).','.$this->maxSteps
365 );
366
367 // Traversing the result, building up changesArray / changeLog:
368 $changesArray=array();
369 $changeLog=array();
370 while ($newRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
371 $hisDat = unserialize($newRow['history_data']);
372 if (is_array($hisDat['newRecord']) && is_array($hisDat['oldRecord'])) {
373 // If intermedia changes:
374 $intermediaChanges = $this->cmp($changesArray,$hisDat['oldRecord']);
375 if (count($intermediaChanges) && !$newRow['snapshot']) {
376 $changeLog[]=$intermediaChanges;
377 }
378
379 // Add hisDat to the changeLog
380 $hisDat['uid']=$newRow['uid'];
381 $hisDat['tstamp']=$newRow['tstamp'];
382 $hisDat['user']=$newRow['userid'];
383 $hisDat['snapshot']=$newRow['snapshot'];
384 $changeLog[]=$hisDat;
385
386 // Update change array
387 // This is used to detect if any intermedia changes has been made.
388 $changesArray = array_merge($changesArray,$hisDat['newRecord']);
389 } else {
390 debug('ERROR: [displayHistory]');
391 }
392 }
393
394
395 $lines=array();
396 $darkerBgColor_interM = '#cccccc';
397 if ($this->sumUp) { // Show details for a single point in the list:
398
399 // Initialize:
400 $changeLog=array(); // array is reset here because we want to show only one item (and therefore we will build it all over again...)
401 $changeLog[]=$this->compareChangesWithCurrent($element,$this->getChangesSinceRecord($element,$this->sumUp));
402 $this->listType=2;
403 $lines[]=$this->listHeader();
404 $be_users = t3lib_BEfunc::getUserNames();
405
406 // Get the previous/next uids:
407 list($prevHisUid,$nextHisUid) = $this->nextHisUid($element,$this->sumUp);
408
409 // Create the set of navigation links:
410 $linkPack =
411 ($prevHisUid ? $this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/pilup.gif','width="14" height="14"').' title="'.$LANG->getLL('prev',1).'" alt="" />', array('sumUp'=>$prevHisUid)) : ''). // previous
412 ($nextHisUid ? $this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/pildown.gif','width="14" height="14"').' title="'.$LANG->getLL('next',1).'" alt="" />', array('sumUp'=>$nextHisUid)) : ''). // next
413 '<br />'.$this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/history2.gif','width="13" height="12"').' title="'.$LANG->getLL('historyList',1).'" alt="" />', array('sumUp'=>''), 'uid_'.$this->sumUp). // back to list
414 $this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/savesnapshot.gif','width="17" height="12"').' title="'.$LANG->getLL('saveState',1).'" alt="" />', array('saveState'=>$this->sumUp,'sumUp'=>''), 'latest'); // save state
415
416 // Traverse changelog array:
417 foreach($changeLog as $entry) {
418
419 // Set user-names:
420 if (!is_array($entry['userList'])) $entry['userList']=array();
421 foreach($entry['userList'] as $uLk => $uV) {
422 $entry['userList'][$uLk]=$be_users[$uV]['username'];
423 }
424
425 // Add the header:
426 $theTime = t3lib_BEfunc::datetime($entry['tstamp']).', '.t3lib_BEfunc::calcAge(time()-$entry['tstamp'],$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears'));
427 $lines[]='
428 <tr class="bgColor4-20">
429 <td valign="top">'.$linkPack.'</td>
430 <td colspan="4"><b>'.$LANG->getLL('time',1).':</b> '.htmlspecialchars($theTime).' &nbsp; - &nbsp; <b>'.$LANG->getLL('changeCount',1).':</b> '.$entry['counter'].'<br />
431 <b>'.$LANG->getLL('users',1).':</b> '.implode(', ',$entry['userList']).'
432 </td>
433 </tr>';
434
435 // Add content:
436 if (isset($entry['oldRecord']) && isset($entry['newRecord'])) { // If there ARE differences to show, then add lines for each changed field:
437 $lines = array_merge($lines,$this->renderEntry($entry,$table));
438 } else { // Otherwise, if no changes - show a message about that!
439 $lines[]='
440 <tr class="bgColor4">
441 <td colspan="5" align="center"><br /><b>'.$LANG->getLL('similar',1).'</b><br /><br /></td>
442 </tr>';
443 }
444 }
445 } else { // Show the full change Log:
446
447 // Initialize:
448 $this->listType=1;
449 $be_users = t3lib_BEfunc::getUserNames();
450 $lines[]=$this->listHeader();
451
452 // Traverse changelog array:
453 foreach($changeLog as $c => $entry) {
454
455 // Add spacer line:
456 $lines[]='
457 <tr>
458 <td colspan="3">&nbsp;</td>
459 </tr>';
460
461 // Anchor to latest entry:
462 $lastAnchor = ($c+1==count($changeLog)?'<a name="latest"></a>':'');
463
464 // Render state header:
465 if ($entry['uid']) { // This state was made by the backend:
466 $theTime = $this->linkPage(t3lib_BEfunc::datetime($entry['tstamp']),array('sh_uid'=>$entry['uid'],'element'=>''));
467 $theAge = ', '.t3lib_BEfunc::calcAge(time()-$entry['tstamp'],$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears'));
468 $bgColorClass = $entry['snapshot'] ? 'bgColor2' : 'bgColor4-20';
469 $lines[]='
470 <tr class="'.$bgColorClass.'">
471 <td colspan="2">'.
472 $lastAnchor.
473 '<a name="uid_'.$entry['uid'].'"></a>'.
474 ($entry['snapshot'] ? '<img'.t3lib_iconWorks::skinImg('','gfx/snapshot.gif','width="12" height="12"').' alt="" />':'').
475 '<b>'.$LANG->getLL('time',1).':</b> '.$theTime.htmlspecialchars($theAge).' &nbsp; - &nbsp; <b>'.$LANG->getLL('user',1).':</b> '.$be_users[$entry['user']]['username'].
476 '</td>
477 <td>'.
478 $this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/history.gif','width="13" height="12"').' title="'.$LANG->getLL('revertAllFields',1).'" alt="" />', array('revert'=>'ALL_FIELDS','sumUp'=>$entry['uid'],'doReturn'=>1)).
479 $this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/history_details.gif','width="12" height="12"').' title="'.$LANG->getLL('sumUpChanges',1).'" alt="" />', array('sumUp'=>$entry['uid'])).
480 '</td>
481 </tr>';
482 } else { // This state must have been some external change:
483 $lines[]='
484 <tr bgcolor="'.$darkerBgColor_interM.'">
485 <td colspan="3"><strong>'.$LANG->getLL('externalChange',1).'</strong></td>
486 </tr>';
487 }
488 // Merge state header with all entries in the state:
489 $lines = array_merge($lines,$this->renderEntry($entry,$table));
490 }
491 }
492
493 // Finally, put it all together:
494 $theCode='
495
496 <!--
497 Item history (either list or single):
498 -->
499 <table border="0" cellpadding="2" cellspacing="2" id="typo3-history">
500 '.implode('',$lines).'
501 </table>';
502
503 // Add message about the difference view.
504 $theCode.='<br /><img'.t3lib_iconWorks::skinImg('','gfx/icon_note.gif','width="18" height="16"').' align="top" alt="" />'.$LANG->getLL('differenceMsg').'<br /><br />';
505
506 // Add the whole content as a module section:
507 return $SOBE->doc->section($LANG->getLL('changes'),$theCode,0,1);
508 }
509 }
510
511
512
513
514
515
516
517
518
519 /*******************************
520 *
521 * Various helper functions
522 *
523 *******************************/
524
525 /**
526 * Based on the uid of a sys_history record (a state) this method will find the uids of the previous and next state (if any)
527 *
528 * @param string Element reference, syntax "[table]:[uid]"
529 * @param integer Current state uid
530 * @return array Array with previous and next uid as key 0 / 1
531 * @access private
532 */
533 function nextHisUid($element,$hisUid) {
534 $elParts = explode(':',$element);
535
536 // Prev:
537 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
538 'uid',
539 'sys_history',
540 'tablename="'.$GLOBALS['TYPO3_DB']->quoteStr($elParts[0], 'sys_history').'"
541 AND recuid='.intval($elParts[1]).'
542 AND uid<'.intval($hisUid),
543 '',
544 'uid DESC',
545 '1'
546 );
547 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
548 $prevUid = $row['uid'];
549 }
550
551 // Next:
552 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
553 'uid',
554 'sys_history',
555 'tablename="'.$GLOBALS['TYPO3_DB']->quoteStr($elParts[0], 'sys_history').'"
556 AND recuid='.intval($elParts[1]).'
557 AND uid>'.intval($hisUid),
558 '',
559 'uid',
560 '1'
561 );
562 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
563 $nextUid = $row['uid'];
564 }
565
566 // Return next and previous ids:
567 return array($prevUid,$nextUid);
568 }
569
570 /**
571 * This compares a certain sys_history state (given by the $changeRec array) with the current values of the element refered to by $element.
572 *
573 * @param string Element reference, syntax "[table]:[uid]"
574 * @param array Array with the state information from a certain state. This kind of array is produced by getChangesSinceRecord()
575 * @return array Array with the changes registered in.
576 * @access private
577 * @see getChangesSinceRecord()
578 */
579 function compareChangesWithCurrent($element,$changeRec) {
580 global $TCA;
581
582 // Initialize:
583 $sumChangesArray=array();
584 $elParts = explode(':',$element);
585 $newChangeRec=array();
586
587 // If tablename is found in $TCA:
588 if ($TCA[$elParts[0]]) {
589
590 // Select current record content of element:
591 $currentRecord = t3lib_BEfunc::getRecord($elParts[0],$elParts[1]);
592
593 // If that is found and the "changes" entry of the $changeRec is an array, then proceed:
594 if (is_array($currentRecord) && is_array($changeRec['changes'])) {
595
596 // For each entry in "changes" we compare the field content with the current and if there is a difference, it is tracked in the array $newChangeRec
597 foreach($changeRec['changes'] as $fN => $fV) {
598 if (strcmp($fV,$currentRecord[$fN])) {
599 $newChangeRec['oldRecord'][$fN]=$fV;
600 $newChangeRec['newRecord'][$fN]=$currentRecord[$fN];
601 }
602 }
603 // Finally, setting some general information fields:
604 $newChangeRec['tstamp']=min($changeRec['tstamp']);
605 $newChangeRec['counter']=$changeRec['counter'];
606 $newChangeRec['userList']=array_unique($changeRec['userList']);
607 } else {
608 return false; // No arrays, possibly no record
609 }
610 }
611
612 // Returns the array of changes detected:
613 return $newChangeRec;
614 }
615
616 /**
617 * Returns the record of $table/$id along with the sql field types for each field
618 *
619 * @param string The table name
620 * @param integer The uid of the record
621 * @return array An array with two num keys; in 0 is the current record, in 1 is the field types for each field.
622 * @access private
623 */
624 function readFieldTypes($table,$id) {
625
626 // Select record:
627 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($id));
628
629 // Fetch the types of the fields.
630 if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) {
631 $currentRecord = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
632 $c=0;
633 $cRecTypes=array();
634 foreach($currentRecord as $col => $val) {
635 $cRecTypes[$col] = $GLOBALS['TYPO3_DB']->sql_field_type($res,$c);
636 $c++;
637 }
638 }
639
640 $GLOBALS['TYPO3_DB']->sql_free_result($res);
641
642 return array($currentRecord,$cRecTypes);
643 }
644
645 /**
646 * Compares the old record with the changed fields.
647 *
648 * @param array Record with field/value pairs (what has changed)
649 * @param array Record with field/value pairs
650 * @return array Comparison result.
651 * @access private
652 */
653 function cmp($changeStatus,$oldRecord) {
654
655 // Initialize:
656 $changes=array();
657
658 // Traverse $oldRecord
659 foreach($oldRecord as $fN => $fV) {
660 if (isset($changeStatus[$fN]) && strcmp($fV,$changeStatus[$fN])) {
661 $changes['oldRecord'][$fN]=$changeStatus[$fN];
662 $changes['newRecord'][$fN]=$fV;
663 }
664 }
665 return $changes;
666 }
667
668 /**
669 * Will traverse the field names in $dataArray and look in $TCA if the fields are of types which cannot be handled by the sys_history (that is currently group types with internal_type set to "file")
670 *
671 * @param string Table name
672 * @param array The data array
673 * @return array The modified data array
674 * @access private
675 */
676 function removeFilefields($table,$dataArray) {
677 global $TCA;
678
679 if ($TCA[$table]) {
680 t3lib_div::loadTCA($table);
681
682 foreach($TCA[$table]['columns'] as $field => $config) {
683 if ($config['config']['type']=='group' && $config['config']['internal_type']=='file') {
684 unset($dataArray[$field]);
685 }
686 }
687 }
688 return $dataArray;
689 }
690
691 /**
692 * Renders HTML table-rows with the comparison information of an sys_history entry record
693 *
694 * @param array sys_history entry record.
695 * @param string The table name
696 * @return array HTML table rows in an array
697 * @access private
698 */
699 function renderEntry($entry,$table) {
700 global $SOBE, $LANG;
701
702 $lines=array();
703 if (is_array($entry['newRecord'])) {
704
705 $t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff');
706
707 $fieldsToDisplay = array_keys($entry['newRecord']);
708 foreach($fieldsToDisplay as $fN) {
709
710 // Create diff-result:
711 $diffres = $t3lib_diff_Obj->makeDiffDisplay(
712 t3lib_BEfunc::getProcessedValue($table,$fN,$entry['oldRecord'][$fN],0,1),
713 t3lib_BEfunc::getProcessedValue($table,$fN,$entry['newRecord'][$fN],0,1)
714 );
715
716 // Depending on list type, we make the row:
717 switch($this->listType) {
718 case 1:
719 $lines[]='
720 <tr class="bgColor4">
721 <td><em>'.$LANG->sl(t3lib_BEfunc::getItemLabel($table,$fN),1).'</em></td>
722 <td>'.nl2br($diffres).'</td>
723 <td>&nbsp;</td>
724 </tr>';
725 break;
726 case 2:
727 $lines[]='
728 <tr class="bgColor4">
729 <td><em>'.$LANG->sl(t3lib_BEfunc::getItemLabel($table,$fN)).'</em></td>
730 <td>'.htmlspecialchars(t3lib_BEfunc::getProcessedValue($table,$fN,$entry['oldRecord'][$fN])).'</td>
731 <td>'.$this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/history.gif','width="13" height="12"').' title="'.$LANG->getLL('revertField',1).'" alt="" />', array('revert'=>'field:'.$fN)).'</td>
732 <td>'.htmlspecialchars(t3lib_BEfunc::getProcessedValue($table,$fN,$entry['newRecord'][$fN])).'</td>
733 <td>'.nl2br($diffres).'</td>
734 </tr>';
735 break;
736 default:
737 $lines[]='
738 <tr class="bgColor4">
739 <td><em>'.$LANG->sl(t3lib_BEfunc::getItemLabel($table,$fN)).'</em></td>
740 <td>'.htmlspecialchars(t3lib_BEfunc::getProcessedValue($table,$fN,$entry['oldRecord'][$fN])).'</td>
741 <td>'.htmlspecialchars(t3lib_BEfunc::getProcessedValue($table,$fN,$entry['newRecord'][$fN])).'</td>
742 <td>'.nl2br($diffres).'</td>
743 </tr>';
744 break;
745 }
746 }
747 }
748 return $lines;
749 }
750
751 /**
752 * Creates a header row based on the value of $this->listType
753 *
754 * @return string HTML table header row
755 * @access private
756 */
757 function listHeader() {
758 global $SOBE, $LANG;
759
760 switch($this->listType) {
761 case 1:
762 $out='
763 <tr class="bgColor5 c-head">
764 <td>'.$LANG->getLL('fieldName',1).':</td>
765 <td>'.$LANG->getLL('difference',1).':</td>
766 <td>&nbsp;</td>
767 </tr>';
768 break;
769 case 2:
770 $out='
771 <tr class="bgColor5 c-head">
772 <td>'.$LANG->getLL('fieldName',1).':</td>
773 <td>'.$LANG->getLL('oldValue',1).':</td>
774 <td>'.$this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/history.gif','width="13" height="12"').' title="'.$LANG->getLL('revertAllFields',1).'" alt="" />', array('revert'=>'ALL_FIELDS')).'</td>
775 <td>'.$LANG->getLL('currentValue',1).':</td>
776 <td>'.$LANG->getLL('difference',1).':</td>
777 </tr>';
778 break;
779 default:
780 $out='
781 <tr class="bgColor5 c-head">
782 <td>'.$LANG->getLL('fieldName',1).':</td>
783 <td>'.$LANG->getLL('oldValue',1).':</td>
784 <td>'.$LANG->getLL('newValue',1).':</td>
785 <td>'.$LANG->getLL('difference',1).':</td>
786 </tr>';
787 break;
788 }
789 return $out;
790 }
791
792 /**
793 * Creates a link to the same page.
794 *
795 * @param string String to wrap in <a> tags (must be htmlspecialchars()'ed prior to calling function)
796 * @param array Array of key/value pairs to override the default values with.
797 * @param string Possible anchor value.
798 * @return string Link.
799 * @access private
800 */
801 function linkPage($str,$inparams=array(),$anchor='') {
802
803 // Setting default values based on GET parameters:
804 $params['sh_uid']=$this->sh_uid;
805 $params['sumUp']=$this->sumUp;
806 $params['element']=$this->element;
807 $params['returnUrl']=$this->returnUrl;
808
809 // Mergin overriding values:
810 $params = array_merge($params,$inparams);
811
812 // Make the link:
813 $Ahref = 'show_rechis.php?'.t3lib_div::implodeArrayForUrl('',$params).($anchor?'#'.$anchor:'');
814 $link = '<a href="'.htmlspecialchars($Ahref).'">'.$str.'</a>';
815
816 // Return link:
817 return $link;
818 }
819
820 /**
821 * This creates an array with the sum of differences between two points in the sys_history
822 *
823 * @param string Element reference, syntax "[table]:[uid]"
824 * @param integer sys_history uid from which to start the selection process
825 * @param integer optional sys_history uid at which to stop the selection (thus applying an upper limit)
826 * @return array Array with difference information
827 * @access private
828 */
829 function getChangesSinceRecord($element,$hisUid=0,$hisUid_Stop=0) {
830 global $TCA;
831
832 // Init:
833 $sumChangesArray=array();
834 $sumChangesArray['changes']=array();
835 $elParts = explode(':',$element);
836
837 // If there is a table by the requested name:
838 if ($TCA[$elParts[0]]) {
839 $times = array();
840
841 // Create query for selecting sys_history records in time interval:
842 $addWhere = ' AND sys_history.uid>='.$hisUid;
843 if ($hisUid_Stop) $addWhere.= ' AND sys_history.uid<='.$hisUid_Stop;
844 // Make query:
845 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
846 'sys_history.*,sys_log.userid',
847 'sys_history,sys_log',
848 'sys_history.sys_log_uid=sys_log.uid
849 AND sys_history.tablename="'.$GLOBALS['TYPO3_DB']->quoteStr($elParts[0], 'sys_history').'"
850 AND sys_history.recuid='.intval($elParts[1]).$addWhere,
851 '',
852 'uid DESC'
853 );
854
855 // Travese results:
856 while ($newRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
857 $hisDat = unserialize($newRow['history_data']);
858 if (is_array($hisDat['newRecord']) && is_array($hisDat['oldRecord'])) {
859 $sumChangesArray['changes']=array_merge($sumChangesArray['changes'],$hisDat['oldRecord']);
860 $sumChangesArray['counter']++;
861 $sumChangesArray['tstamp'][]=$newRow['tstamp'];
862 $sumChangesArray['userList'][]=$newRow['userid'];
863 } else {
864 debug('ERROR!');
865 }
866
867 }
868 }
869 return $sumChangesArray;
870 }
871 }
872
873 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/class.show_rechis.inc']) {
874 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/class.show_rechis.inc']);
875 }
876 ?>