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