Tons of changes made to the CORE. All scripts has more a less been modified. Primaril...
[Packages/TYPO3.CMS.git] / typo3 / class.show_rechis.inc
1 <?php
2 /***************************************************************
3 *  Copyright notice
4 *  
5 *  (c) 1999-2003 Kasper Skaarhoj (kasper@typo3.com)
6 *  All rights reserved
7 *
8 *  This script is part of the TYPO3 project. The TYPO3 project is 
9 *  free software; you can redistribute it and/or modify
10 *  it under the terms of the GNU General Public License as published by
11 *  the Free Software Foundation; either version 2 of the License, or
12 *  (at your option) any later version.
13
14 *  The GNU General Public License can be found at
15 *  http://www.gnu.org/copyleft/gpl.html.
16 *  A copy is found in the textfile GPL.txt and important notices to the license 
17 *  from the author is found in LICENSE.txt distributed with these scripts.
18 *
19
20 *  This script is distributed in the hope that it will be useful,
21 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 *  GNU General Public License for more details.
24 *
25 *  This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /** 
28  * 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::GPvar('sh_uid');     
110                 $this->element = t3lib_div::GPvar('element');
111                 $this->saveState = t3lib_div::GPvar('saveState');
112                 $this->returnUrl = t3lib_div::GPvar('returnUrl');
113                 $this->revert = t3lib_div::GPvar('revert');
114                 $this->sumUp = t3lib_div::GPvar('sumUp');
115                 $this->doReturn = t3lib_div::GPvar('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 ?>