Changed lots of stuff...
[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 * 216: function revertToPreviousValues($element,$field)
46 * 278: function saveState($element,$sumUp)
47 * 328: function displayHistory($element)
48 *
49 * SECTION: Various helper functions
50 * 520: function nextHisUid($element,$hisUid)
51 * 558: function compareChangesWithCurrent($element,$changeRec)
52 * 603: function readFieldTypes($table,$id)
53 * 630: function cmp($changeStatus,$oldRecord)
54 * 653: function removeFilefields($table,$dataArray)
55 * 676: function renderEntry($entry,$table)
56 * 734: function listHeader()
57 * 778: function linkPage($str,$inparams=array(),$anchor='')
58 * 806: 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 $query='SELECT * FROM sys_history WHERE uid='.intval($sh_uid);
160 $res = mysql(TYPO3_db,$query);
161 $newRow = mysql_fetch_assoc($res);
162
163 // If an entry was found:
164 if (is_array($newRow)) {
165
166 // Init:
167 $this->listType=0;
168 $lines=array();
169
170 // Create header:
171 $recIdentString = $LANG->sL($TCA[$newRow['tablename']]['ctrl']['title']).'/'.$newRow['recuid'];
172 $recIdentString = $this->linkPage(htmlspecialchars($recIdentString),array('sh_uid'=>'','element'=>$newRow['tablename'].':'.$newRow['recuid']),'uid_'.$sh_uid);
173 $theTime = t3lib_BEfunc::datetime($newRow['tstamp']).', '.t3lib_BEfunc::calcAge(time()-$newRow['tstamp'],$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears'));
174 $lines[]='
175 <tr class="bgColor5">
176 <td colspan="4">
177 <strong>'.$LANG->getLL('tableUid',1).':</strong> '.$recIdentString.'<br />
178 <strong>'.$LANG->getLL('time',1).':</strong> '.htmlspecialchars($theTime).'<br />
179 </td>
180 </tr>';
181
182 // Add header to accumulation:
183 $lines[]=$this->listHeader();
184
185 // Get the entry data and add it:
186 $historyData = unserialize($newRow['history_data']);
187 $lines = array_merge($lines,$this->renderEntry($historyData,$newRow['tablename']));
188
189 // Combine all content into a table for layout:
190 $theCode='
191
192 <!--
193 History for item:
194 -->
195 <table border="0" cellpadding="2" cellspacing="2" id="typo3-history-item">
196 '.implode('',$lines).'
197 </table>';
198 $theCode.='
199 <br /><img'.t3lib_iconWorks::skinImg('','gfx/icon_note.gif','width="18" height="16"').' align="top" alt="" />'.$LANG->getLL('differenceMsg').'<br /><br />';
200
201 // Create the module section:
202 $content.=$SOBE->doc->section($LANG->getLL('changes'),$theCode,0,1);
203 }
204
205 // Return content:
206 return $content;
207 }
208
209 /**
210 * Return to previous values for element
211 *
212 * @param string Element reference, syntax "[table]:[uid]"
213 * @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"
214 * @return void The function writes through tceMain and ends with a header-location, if instructed to.
215 */
216 function revertToPreviousValues($element,$field) {
217 $sumUp = $this->sumUp; // sys_history uid from which to get previous values
218
219 $elParts = explode(':',$element);
220 $redirect = intval($this->doReturn);
221 if ($sumUp==-1) { // Undo/Redo
222 $query='SELECT uid FROM sys_history WHERE
223 sys_history.tablename="'.addslashes($elParts[0]).'"
224 AND sys_history.recuid='.intval($elParts[1]).'
225 ORDER BY uid DESC LIMIT 1';
226 $res = mysql(TYPO3_db,$query);
227 if ($row = mysql_fetch_assoc($res)) {
228 $sumUp=$row['uid'];
229 }
230 $redirect = 1;
231 }
232 if ($sumUp!=-1) {
233 $changeRec=$this->compareChangesWithCurrent($element,$this->getChangesSinceRecord($element,$sumUp));
234
235 $data =array();
236 if (t3lib_BEfunc::getRecord($elParts[0],$elParts[1])) {
237
238 // Fields field(s) to restore:
239 if ($field=='ALL_FIELDS') {
240 $data=$changeRec['oldRecord'];
241 } elseif(substr($field,0,6)=='field:') {
242 $data[substr($field,6)]=$changeRec['oldRecord'][substr($field,6)];
243 }
244 // Removing fields:
245 $data = $this->removeFilefields($elParts[0],$data);
246
247 // If there are fields to write:
248 if (count($data)) {
249
250 // Setting data right:
251 $inData=array();
252 $inData[$elParts[0]][$elParts[1]]=$data;
253
254 // Writes the data:
255 $tce = t3lib_div::makeInstance('t3lib_TCEmain');
256 $tce->stripslashes_values=0;
257 $tce->debug=0;
258 $tce->dontProcessTransformations=1;
259 $tce->start($inData,array());
260 $tce->process_datamap();
261 }
262 }
263 }
264
265 if ($redirect) {
266 Header ('Location: '.t3lib_div::locationHeaderUrl($this->returnUrl));
267 exit;
268 }
269 }
270
271 /**
272 * Will save state uid $sumUp of element
273 *
274 * @param string Element reference, syntax "[table]:[uid]"
275 * @param integer sys_history uid from which to get previous values
276 * @return void
277 */
278 function saveState($element,$sumUp) {
279 $elParts = explode(':',$element);
280
281 // Find the changes since $sumUp sys_history uid
282 $changeRec = $this->getChangesSinceRecord($element,$sumUp);
283
284 // Select most recent sys_history record for the element:
285 $lastestData = array();
286 $query='SELECT history_data FROM sys_history WHERE
287 sys_history.tablename="'.addslashes($elParts[0]).'"
288 AND sys_history.recuid='.intval($elParts[1]).'
289 ORDER BY uid DESC LIMIT 1';
290 $res = mysql(TYPO3_db,$query);
291 if ($row = mysql_fetch_assoc($res)) {
292 $lastestData = unserialize($row['history_data']);
293 }
294
295 // Create forged history data from the most recent state and the previous state to save:
296 $historyRecords=array();
297 $historyRecords['oldRecord'] = $changeRec['changes'];
298 $historyRecords['newRecord'] = array();
299 reset($historyRecords['oldRecord']);
300 while(list($kk)=each($historyRecords['oldRecord'])) {
301 $historyRecords['newRecord'][$kk]=$lastestData['newRecord'][$kk];
302 }
303
304 // Update log:
305 $updateID = $GLOBALS['BE_USER']->writelog(3,1,0,1,'Saved state','');
306
307 // Create query for inserting into sys_history table:
308 $fields_values=array();
309 $fields_values['history_data']=serialize($historyRecords);
310 $fields_values['fieldlist']=implode(',',array_keys($historyRecords['oldRecord']));
311 $fields_values['tstamp']=time();
312 $fields_values['tablename']=$elParts[0];
313 $fields_values['recuid']=$elParts[1];
314 $fields_values['sys_log_uid']=$updateID;
315 $fields_values['snapshot']=1;
316 $query = t3lib_BEfunc::DBcompileInsert('sys_history',$fields_values);
317
318 // Save state by executing this query:
319 $res = mysql(TYPO3_db,$query);
320 }
321
322 /**
323 * Displays the history states of an element
324 *
325 * @param string Element reference, syntax "[table]:[uid]"
326 * @return string HTML for list, wrapped in a table.
327 */
328 function displayHistory($element) {
329 global $SOBE, $LANG, $TCA;
330
331 // Initialize:
332 $elParts = explode(':',$element);
333 $table = $elParts[0];
334
335 // If table is found in $TCA:
336 if ($TCA[$table]) {
337
338 // Creating main query for selecting history states of the element.
339 $mainQBody = 'FROM sys_history,sys_log WHERE
340 sys_history.sys_log_uid=sys_log.uid
341 AND sys_history.tablename="'.addslashes($table).'"
342 AND sys_history.recuid='.intval($elParts[1]);
343
344 // Counting number of states:
345 $query='SELECT count(*) '.$mainQBody;
346 $res = mysql(TYPO3_db,$query);
347 list($Rcount)=mysql_fetch_row($res);
348
349 // Selecting the $this->maxSteps most recent states:
350 $query='SELECT sys_history.*,sys_log.userid '.$mainQBody.'
351 ORDER BY uid LIMIT '.t3lib_div::intInRange($Rcount-$this->maxSteps,0).','.$this->maxSteps;
352 $res = mysql(TYPO3_db,$query);
353
354 // Traversing the result, building up changesArray / changeLog:
355 $changesArray=array();
356 $changeLog=array();
357 while ($newRow = mysql_fetch_assoc($res)) {
358 $hisDat = unserialize($newRow['history_data']);
359 if (is_array($hisDat['newRecord']) && is_array($hisDat['oldRecord'])) {
360 // If intermedia changes:
361 $intermediaChanges = $this->cmp($changesArray,$hisDat['oldRecord']);
362 if (count($intermediaChanges) && !$newRow['snapshot']) {
363 $changeLog[]=$intermediaChanges;
364 }
365
366 // Add hisDat to the changeLog
367 $hisDat['uid']=$newRow['uid'];
368 $hisDat['tstamp']=$newRow['tstamp'];
369 $hisDat['user']=$newRow['userid'];
370 $hisDat['snapshot']=$newRow['snapshot'];
371 $changeLog[]=$hisDat;
372
373 // Update change array
374 // This is used to detect if any intermedia changes has been made.
375 $changesArray = array_merge($changesArray,$hisDat['newRecord']);
376 } else {
377 debug('ERROR: [displayHistory]');
378 }
379 }
380
381
382 $lines=array();
383 $darkerBgColor_interM = '#cccccc';
384 if ($this->sumUp) { // Show details for a single point in the list:
385
386 // Initialize:
387 $changeLog=array(); // array is reset here because we want to show only one item (and therefore we will build it all over again...)
388 $changeLog[]=$this->compareChangesWithCurrent($element,$this->getChangesSinceRecord($element,$this->sumUp));
389 $this->listType=2;
390 $lines[]=$this->listHeader();
391 $be_users = t3lib_BEfunc::getUserNames();
392
393 // Get the previous/next uids:
394 list($prevHisUid,$nextHisUid) = $this->nextHisUid($element,$this->sumUp);
395
396 // Create the set of navigation links:
397 $linkPack =
398 ($prevHisUid ? $this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/pilup.gif','width="14" height="14"').' title="'.$LANG->getLL('prev',1).'" alt="" />', array('sumUp'=>$prevHisUid)) : ''). // previous
399 ($nextHisUid ? $this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/pildown.gif','width="14" height="14"').' title="'.$LANG->getLL('next',1).'" alt="" />', array('sumUp'=>$nextHisUid)) : ''). // next
400 '<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
401 $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
402
403 // Traverse changelog array:
404 foreach($changeLog as $entry) {
405
406 // Set user-names:
407 if (!is_array($entry['userList'])) $entry['userList']=array();
408 foreach($entry['userList'] as $uLk => $uV) {
409 $entry['userList'][$uLk]=$be_users[$uV]['username'];
410 }
411
412 // Add the header:
413 $theTime = t3lib_BEfunc::datetime($entry['tstamp']).', '.t3lib_BEfunc::calcAge(time()-$entry['tstamp'],$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears'));
414 $lines[]='
415 <tr class="bgColor4-20">
416 <td valign="top">'.$linkPack.'</td>
417 <td colspan="4"><b>'.$LANG->getLL('time',1).':</b> '.htmlspecialchars($theTime).' &nbsp; - &nbsp; <b>'.$LANG->getLL('changeCount',1).':</b> '.$entry['counter'].'<br />
418 <b>'.$LANG->getLL('users',1).':</b> '.implode(', ',$entry['userList']).'
419 </td>
420 </tr>';
421
422 // Add content:
423 if (isset($entry['oldRecord']) && isset($entry['newRecord'])) { // If there ARE differences to show, then add lines for each changed field:
424 $lines = array_merge($lines,$this->renderEntry($entry,$table));
425 } else { // Otherwise, if no changes - show a message about that!
426 $lines[]='
427 <tr class="bgColor4">
428 <td colspan="5" align="center"><br /><b>'.$LANG->getLL('similar',1).'</b><br /><br /></td>
429 </tr>';
430 }
431 }
432 } else { // Show the full change Log:
433
434 // Initialize:
435 $this->listType=1;
436 $be_users = t3lib_BEfunc::getUserNames();
437 $lines[]=$this->listHeader();
438
439 // Traverse changelog array:
440 foreach($changeLog as $c => $entry) {
441
442 // Add spacer line:
443 $lines[]='
444 <tr>
445 <td colspan="3">&nbsp;</td>
446 </tr>';
447
448 // Anchor to latest entry:
449 $lastAnchor = ($c+1==count($changeLog)?'<a name="latest"></a>':'');
450
451 // Render state header:
452 if ($entry['uid']) { // This state was made by the backend:
453 $theTime = $this->linkPage(t3lib_BEfunc::datetime($entry['tstamp']),array('sh_uid'=>$entry['uid'],'element'=>''));
454 $theAge = ', '.t3lib_BEfunc::calcAge(time()-$entry['tstamp'],$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears'));
455 $bgColorClass = $entry['snapshot'] ? 'bgColor2' : 'bgColor4-20';
456 $lines[]='
457 <tr class="'.$bgColorClass.'">
458 <td colspan="2">'.
459 $lastAnchor.
460 '<a name="uid_'.$entry['uid'].'"></a>'.
461 ($entry['snapshot'] ? '<img'.t3lib_iconWorks::skinImg('','gfx/snapshot.gif','width="12" height="12"').' alt="" />':'').
462 '<b>'.$LANG->getLL('time',1).':</b> '.$theTime.htmlspecialchars($theAge).' &nbsp; - &nbsp; <b>'.$LANG->getLL('user',1).':</b> '.$be_users[$entry['user']]['username'].
463 '</td>
464 <td>'.
465 $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)).
466 $this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/history_details.gif','width="12" height="12"').' title="'.$LANG->getLL('sumUpChanges',1).'" alt="" />', array('sumUp'=>$entry['uid'])).
467 '</td>
468 </tr>';
469 } else { // This state must have been some external change:
470 $lines[]='
471 <tr bgcolor="'.$darkerBgColor_interM.'">
472 <td colspan="3"><strong>'.$LANG->getLL('externalChange',1).'</strong></td>
473 </tr>';
474 }
475 // Merge state header with all entries in the state:
476 $lines = array_merge($lines,$this->renderEntry($entry,$table));
477 }
478 }
479
480 // Finally, put it all together:
481 $theCode='
482
483 <!--
484 Item history (either list or single):
485 -->
486 <table border="0" cellpadding="2" cellspacing="2" id="typo3-history">
487 '.implode('',$lines).'
488 </table>';
489
490 // Add message about the difference view.
491 $theCode.='<br /><img'.t3lib_iconWorks::skinImg('','gfx/icon_note.gif','width="18" height="16"').' align="top" alt="" />'.$LANG->getLL('differenceMsg').'<br /><br />';
492
493 // Add the whole content as a module section:
494 return $SOBE->doc->section($LANG->getLL('changes'),$theCode,0,1);
495 }
496 }
497
498
499
500
501
502
503
504
505
506 /*******************************
507 *
508 * Various helper functions
509 *
510 *******************************/
511
512 /**
513 * 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)
514 *
515 * @param string Element reference, syntax "[table]:[uid]"
516 * @param integer Current state uid
517 * @return array Array with previous and next uid as key 0 / 1
518 * @access private
519 */
520 function nextHisUid($element,$hisUid) {
521 $elParts = explode(':',$element);
522
523 // Prev:
524 $query='SELECT uid FROM sys_history WHERE
525 tablename="'.addslashes($elParts[0]).'"
526 AND recuid='.intval($elParts[1]).'
527 AND uid<'.intval($hisUid).'
528 ORDER BY uid DESC LIMIT 1';
529 $res = mysql(TYPO3_db,$query);
530 if ($row = mysql_fetch_assoc($res)) {
531 $prevUid=$row['uid'];
532 }
533
534 // Next:
535 $query='SELECT uid FROM sys_history WHERE
536 tablename="'.addslashes($elParts[0]).'"
537 AND recuid='.intval($elParts[1]).'
538 AND uid>'.intval($hisUid).'
539 ORDER BY uid LIMIT 1';
540 $res = mysql(TYPO3_db,$query);
541 if ($row = mysql_fetch_assoc($res)) {
542 $nextUid=$row['uid'];
543 }
544
545 // Return next and previous ids:
546 return array($prevUid,$nextUid);
547 }
548
549 /**
550 * This compares a certain sys_history state (given by the $changeRec array) with the current values of the element refered to by $element.
551 *
552 * @param string Element reference, syntax "[table]:[uid]"
553 * @param array Array with the state information from a certain state. This kind of array is produced by getChangesSinceRecord()
554 * @return array Array with the changes registered in.
555 * @access private
556 * @see getChangesSinceRecord()
557 */
558 function compareChangesWithCurrent($element,$changeRec) {
559 global $TCA;
560
561 // Initialize:
562 $sumChangesArray=array();
563 $elParts = explode(':',$element);
564 $newChangeRec=array();
565
566 // If tablename is found in $TCA:
567 if ($TCA[$elParts[0]]) {
568
569 // Select current record content of element:
570 $currentRecord = t3lib_BEfunc::getRecord($elParts[0],$elParts[1]);
571
572 // If that is found and the "changes" entry of the $changeRec is an array, then proceed:
573 if (is_array($currentRecord) && is_array($changeRec['changes'])) {
574
575 // 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
576 foreach($changeRec['changes'] as $fN => $fV) {
577 if (strcmp($fV,$currentRecord[$fN])) {
578 $newChangeRec['oldRecord'][$fN]=$fV;
579 $newChangeRec['newRecord'][$fN]=$currentRecord[$fN];
580 }
581 }
582 // Finally, setting some general information fields:
583 $newChangeRec['tstamp']=min($changeRec['tstamp']);
584 $newChangeRec['counter']=$changeRec['counter'];
585 $newChangeRec['userList']=array_unique($changeRec['userList']);
586 } else {
587 return false; // No arrays, possibly no record
588 }
589 }
590
591 // Returns the array of changes detected:
592 return $newChangeRec;
593 }
594
595 /**
596 * Returns the record of $table/$id along with the mysql field types for each field
597 *
598 * @param string The table name
599 * @param integer The uid of the record
600 * @return array An array with two num keys; in 0 is the current record, in 1 is the field types for each field.
601 * @access private
602 */
603 function readFieldTypes($table,$id) {
604
605 // Select record:
606 $query = 'SELECT * FROM '.$table.' WHERE uid='.intval($id);
607 $res = mysql(TYPO3_db,$query);
608
609 // Fetch the types of the fields.
610 if (mysql_num_rows($res)) {
611 $currentRecord = mysql_fetch_assoc($res);
612 $c=0;
613 $cRecTypes=array();
614 foreach($currentRecord as $col => $val) {
615 $cRecTypes[$col]=mysql_field_type($res,$c);
616 $c++;
617 }
618 }
619 return array($currentRecord,$cRecTypes);
620 }
621
622 /**
623 * Compares the old record with the changed fields.
624 *
625 * @param array Record with field/value pairs (what has changed)
626 * @param array Record with field/value pairs
627 * @return array Comparison result.
628 * @access private
629 */
630 function cmp($changeStatus,$oldRecord) {
631
632 // Initialize:
633 $changes=array();
634
635 // Traverse $oldRecord
636 foreach($oldRecord as $fN => $fV) {
637 if (isset($changeStatus[$fN]) && strcmp($fV,$changeStatus[$fN])) {
638 $changes['oldRecord'][$fN]=$changeStatus[$fN];
639 $changes['newRecord'][$fN]=$fV;
640 }
641 }
642 return $changes;
643 }
644
645 /**
646 * 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")
647 *
648 * @param string Table name
649 * @param array The data array
650 * @return array The modified data array
651 * @access private
652 */
653 function removeFilefields($table,$dataArray) {
654 global $TCA;
655
656 if ($TCA[$table]) {
657 t3lib_div::loadTCA($table);
658
659 foreach($TCA[$table]['columns'] as $field => $config) {
660 if ($config['config']['type']=='group' && $config['config']['internal_type']=='file') {
661 unset($dataArray[$field]);
662 }
663 }
664 }
665 return $dataArray;
666 }
667
668 /**
669 * Renders HTML table-rows with the comparison information of an sys_history entry record
670 *
671 * @param array sys_history entry record.
672 * @param string The table name
673 * @return array HTML table rows in an array
674 * @access private
675 */
676 function renderEntry($entry,$table) {
677 global $SOBE, $LANG;
678
679 $lines=array();
680 if (is_array($entry['newRecord'])) {
681
682 $t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff');
683
684 $fieldsToDisplay = array_keys($entry['newRecord']);
685 foreach($fieldsToDisplay as $fN) {
686
687 // Create diff-result:
688 $diffres = $t3lib_diff_Obj->makeDiffDisplay(
689 t3lib_BEfunc::getProcessedValue($table,$fN,$entry['oldRecord'][$fN],0,1),
690 t3lib_BEfunc::getProcessedValue($table,$fN,$entry['newRecord'][$fN],0,1)
691 );
692
693 // Depending on list type, we make the row:
694 switch($this->listType) {
695 case 1:
696 $lines[]='
697 <tr class="bgColor4">
698 <td><em>'.$LANG->sl(t3lib_BEfunc::getItemLabel($table,$fN),1).'</em></td>
699 <td>'.nl2br($diffres).'</td>
700 <td>&nbsp;</td>
701 </tr>';
702 break;
703 case 2:
704 $lines[]='
705 <tr class="bgColor4">
706 <td><em>'.$LANG->sl(t3lib_BEfunc::getItemLabel($table,$fN)).'</em></td>
707 <td>'.t3lib_BEfunc::getProcessedValue($table,$fN,$entry['oldRecord'][$fN]).'</td>
708 <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>
709 <td>'.t3lib_BEfunc::getProcessedValue($table,$fN,$entry['newRecord'][$fN]).'</td>
710 <td>'.nl2br($diffres).'</td>
711 </tr>';
712 break;
713 default:
714 $lines[]='
715 <tr class="bgColor4">
716 <td><em>'.$LANG->sl(t3lib_BEfunc::getItemLabel($table,$fN)).'</em></td>
717 <td>'.t3lib_BEfunc::getProcessedValue($table,$fN,$entry['oldRecord'][$fN]).'</td>
718 <td>'.t3lib_BEfunc::getProcessedValue($table,$fN,$entry['newRecord'][$fN]).'</td>
719 <td>'.nl2br($diffres).'</td>
720 </tr>';
721 break;
722 }
723 }
724 }
725 return $lines;
726 }
727
728 /**
729 * Creates a header row based on the value of $this->listType
730 *
731 * @return string HTML table header row
732 * @access private
733 */
734 function listHeader() {
735 global $SOBE, $LANG;
736
737 switch($this->listType) {
738 case 1:
739 $out='
740 <tr class="bgColor5 c-head">
741 <td>'.$LANG->getLL('fieldName',1).':</td>
742 <td>'.$LANG->getLL('difference',1).':</td>
743 <td>&nbsp;</td>
744 </tr>';
745 break;
746 case 2:
747 $out='
748 <tr class="bgColor5 c-head">
749 <td>'.$LANG->getLL('fieldName',1).':</td>
750 <td>'.$LANG->getLL('oldValue',1).':</td>
751 <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>
752 <td>'.$LANG->getLL('currentValue',1).':</td>
753 <td>'.$LANG->getLL('difference',1).':</td>
754 </tr>';
755 break;
756 default:
757 $out='
758 <tr class="bgColor5 c-head">
759 <td>'.$LANG->getLL('fieldName',1).':</td>
760 <td>'.$LANG->getLL('oldValue',1).':</td>
761 <td>'.$LANG->getLL('newValue',1).':</td>
762 <td>'.$LANG->getLL('difference',1).':</td>
763 </tr>';
764 break;
765 }
766 return $out;
767 }
768
769 /**
770 * Creates a link to the same page.
771 *
772 * @param string String to wrap in <a> tags (must be htmlspecialchars()'ed prior to calling function)
773 * @param array Array of key/value pairs to override the default values with.
774 * @param string Possible anchor value.
775 * @return string Link.
776 * @access private
777 */
778 function linkPage($str,$inparams=array(),$anchor='') {
779
780 // Setting default values based on GET parameters:
781 $params['sh_uid']=$this->sh_uid;
782 $params['sumUp']=$this->sumUp;
783 $params['element']=$this->element;
784 $params['returnUrl']=$this->returnUrl;
785
786 // Mergin overriding values:
787 $params = array_merge($params,$inparams);
788
789 // Make the link:
790 $Ahref = 'show_rechis.php?'.t3lib_div::implodeArrayForUrl('',$params).($anchor?'#'.$anchor:'');
791 $link = '<a href="'.htmlspecialchars($Ahref).'">'.$str.'</a>';
792
793 // Return link:
794 return $link;
795 }
796
797 /**
798 * This creates an array with the sum of differences between two points in the sys_history
799 *
800 * @param string Element reference, syntax "[table]:[uid]"
801 * @param integer sys_history uid from which to start the selection process
802 * @param integer optional sys_history uid at which to stop the selection (thus applying an upper limit)
803 * @return array Array with difference information
804 * @access private
805 */
806 function getChangesSinceRecord($element,$hisUid=0,$hisUid_Stop=0) {
807 global $TCA;
808
809 // Init:
810 $sumChangesArray=array();
811 $sumChangesArray['changes']=array();
812 $elParts = explode(':',$element);
813
814 // If there is a table by the requested name:
815 if ($TCA[$elParts[0]]) {
816
817 // Create query for selecting sys_history records in time interval:
818 $addWhere = ' AND sys_history.uid>='.$hisUid;
819 if ($hisUid_Stop) $addWhere.= ' AND sys_history.uid<='.$hisUid_Stop;
820 $query='SELECT sys_history.*,sys_log.userid FROM sys_history,sys_log WHERE
821 sys_history.sys_log_uid=sys_log.uid
822 AND sys_history.tablename="'.addslashes($elParts[0]).'"
823 AND sys_history.recuid='.intval($elParts[1]).$addWhere.'
824 ORDER BY uid DESC';
825
826 // Make query:
827 $res = mysql(TYPO3_db,$query);
828 $times=array();
829
830 // Travese results:
831 while ($newRow = mysql_fetch_assoc($res)) {
832 $hisDat = unserialize($newRow['history_data']);
833 if (is_array($hisDat['newRecord']) && is_array($hisDat['oldRecord'])) {
834 $sumChangesArray['changes']=array_merge($sumChangesArray['changes'],$hisDat['oldRecord']);
835 $sumChangesArray['counter']++;
836 $sumChangesArray['tstamp'][]=$newRow['tstamp'];
837 $sumChangesArray['userList'][]=$newRow['userid'];
838 } else {
839 debug('ERROR!');
840 }
841
842 }
843 }
844 return $sumChangesArray;
845 }
846 }
847
848 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/class.show_rechis.inc']) {
849 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/class.show_rechis.inc']);
850 }
851 ?>