TYPO3 CMS  TYPO3_6-2
RecordHistory.php
Go to the documentation of this file.
1 <?php
3 
20 
34 
35  // External, static:
36  // Maximum number of sys_history steps to show.
40  public $maxSteps = 20;
41 
42  // display diff or not (0-no diff, 1-inline)
46  public $showDiff = 1;
47 
48  // on a pages table - show sub elements as well.
52  public $showSubElements = 1;
53 
54  // show inserts and deletes as well
58  public $showInsertDelete = 1;
59 
60  // Internal, GPvars
61  // Element reference, syntax [tablename]:[uid]
65  public $element;
66 
67  // syslog ID which is not shown anymore
71  public $lastSyslogId;
72 
76  public $returnUrl;
77 
78  // Internal
82  public $changeLog = array();
83 
87  public $showMarked = FALSE;
88 
92  protected $recordCache = array();
93 
97  protected $pageAccessCache = array();
98 
104  public function __construct() {
105  // GPvars:
106  $this->element = $this->getArgument('element');
107  $this->returnUrl = $this->getArgument('returnUrl');
108  $this->lastSyslogId = $this->getArgument('diff');
109  $this->rollbackFields = $this->getArgument('rollbackFields');
110  // Resolve sh_uid if set
111  $this->resolveShUid();
112  }
113 
121  public function main() {
122  $content = '';
123  // Single-click rollback
124  if ($this->getArgument('revert') && $this->getArgument('sumUp')) {
125  $this->rollbackFields = $this->getArgument('revert');
126  $this->showInsertDelete = 0;
127  $this->showSubElements = 0;
128  $element = explode(':', $this->element);
129  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_history', 'tablename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($element[0], 'sys_history') . ' AND recuid=' . (int)$element[1], '', 'uid DESC', '1');
130  $record = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
131  $this->lastSyslogId = $record['sys_log_uid'];
132  $this->createChangeLog();
133  $completeDiff = $this->createMultipleDiff();
134  $this->performRollback($completeDiff);
136  }
137  // Save snapshot
138  if ($this->getArgument('highlight') && !$this->getArgument('settings')) {
139  $this->toggleHighlight($this->getArgument('highlight'));
140  }
141  $content .= $this->displaySettings();
142  if ($this->createChangeLog()) {
143  if ($this->rollbackFields) {
144  $completeDiff = $this->createMultipleDiff();
145  $content .= $this->performRollback($completeDiff);
146  }
147  if ($this->lastSyslogId) {
148  $completeDiff = $this->createMultipleDiff();
149  $content .= $this->displayMultipleDiff($completeDiff);
150  }
151  if ($this->element) {
152  $content .= $this->displayHistory();
153  }
154  }
155  return $content;
156  }
157 
158  /*******************************
159  *
160  * database actions
161  *
162  *******************************/
170  public function toggleHighlight($uid) {
171  $uid = (int)$uid;
172  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('snapshot', 'sys_history', 'uid=' . $uid);
173  $tmp = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
174  $GLOBALS['TYPO3_DB']->exec_UPDATEquery('sys_history', 'uid=' . $uid, array('snapshot' => !$tmp['snapshot']));
175  }
176 
185  public function performRollback($diff) {
186  if (!$this->rollbackFields) {
187  return 0;
188  }
189  $reloadPageFrame = 0;
190  $rollbackData = explode(':', $this->rollbackFields);
191  // PROCESS INSERTS AND DELETES
192  // rewrite inserts and deletes
193  $cmdmapArray = array();
194  if ($diff['insertsDeletes']) {
195  switch (count($rollbackData)) {
196  case 1:
197  // all tables
198  $data = $diff['insertsDeletes'];
199  break;
200  case 2:
201  // one record
202  if ($diff['insertsDeletes'][$this->rollbackFields]) {
203  $data[$this->rollbackFields] = $diff['insertsDeletes'][$this->rollbackFields];
204  }
205  break;
206  case 3:
207  // one field in one record -- ignore!
208  break;
209  }
210  if ($data) {
211  foreach ($data as $key => $action) {
212  $elParts = explode(':', $key);
213  if ($action == 1) {
214  // inserted records should be deleted
215  $cmdmapArray[$elParts[0]][$elParts[1]]['delete'] = 1;
216  // When the record is deleted, the contents of the record do not need to be updated
217  unset($diff['oldData'][$key]);
218  unset($diff['newData'][$key]);
219  } elseif ($action == -1) {
220  // deleted records should be inserted again
221  $cmdmapArray[$elParts[0]][$elParts[1]]['undelete'] = 1;
222  }
223  }
224  }
225  }
226  // Writes the data:
227  if ($cmdmapArray) {
228  $tce = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\DataHandling\\DataHandler');
229  $tce->stripslashes_values = 0;
230  $tce->debug = 0;
231  $tce->dontProcessTransformations = 1;
232  $tce->start(array(), $cmdmapArray);
233  $tce->process_cmdmap();
234  unset($tce);
235  if (isset($cmdmapArray['pages'])) {
236  $reloadPageFrame = 1;
237  }
238  }
239  // PROCESS CHANGES
240  // create an array for process_datamap
241  $diff_modified = array();
242  foreach ($diff['oldData'] as $key => $value) {
243  $splitKey = explode(':', $key);
244  $diff_modified[$splitKey[0]][$splitKey[1]] = $value;
245  }
246  switch (count($rollbackData)) {
247  case 1:
248  // all tables
249  $data = $diff_modified;
250  break;
251  case 2:
252  // one record
253  $data[$rollbackData[0]][$rollbackData[1]] = $diff_modified[$rollbackData[0]][$rollbackData[1]];
254  break;
255  case 3:
256  // one field in one record
257  $data[$rollbackData[0]][$rollbackData[1]][$rollbackData[2]] = $diff_modified[$rollbackData[0]][$rollbackData[1]][$rollbackData[2]];
258  break;
259  }
260  // Removing fields:
261  $data = $this->removeFilefields($rollbackData[0], $data);
262  // Writes the data:
263  $tce = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\DataHandling\\DataHandler');
264  $tce->stripslashes_values = 0;
265  $tce->debug = 0;
266  $tce->dontProcessTransformations = 1;
267  $tce->start($data, array());
268  $tce->process_datamap();
269  unset($tce);
270  if (isset($data['pages'])) {
271  $reloadPageFrame = 1;
272  }
273  // Return to normal operation
274  $this->lastSyslogId = FALSE;
275  $this->rollbackFields = FALSE;
276  $this->createChangeLog();
277  // Reload page frame if necessary
278  if ($reloadPageFrame) {
279  return '<script type="text/javascript">
280  /*<![CDATA[*/
281  if (top.content && top.content.nav_frame && top.content.nav_frame.refresh_nav) {
282  top.content.nav_frame.refresh_nav();
283  }
284  /*]]>*/
285  </script>';
286  }
287  }
288 
289  /*******************************
290  *
291  * Display functions
292  *
293  *******************************/
300  public function displaySettings() {
301  // Get current selection from UC, merge data, write it back to UC
302  $currentSelection = is_array($GLOBALS['BE_USER']->uc['moduleData']['history']) ? $GLOBALS['BE_USER']->uc['moduleData']['history'] : array('maxSteps' => '', 'showDiff' => 1, 'showSubElements' => 1, 'showInsertDelete' => 1);
303  $currentSelectionOverride = $this->getArgument('settings');
304  if ($currentSelectionOverride) {
305  $currentSelection = array_merge($currentSelection, $currentSelectionOverride);
306  $GLOBALS['BE_USER']->uc['moduleData']['history'] = $currentSelection;
307  $GLOBALS['BE_USER']->writeUC($GLOBALS['BE_USER']->uc);
308  }
309  // Display selector for number of history entries
310  $selector['maxSteps'] = array(
311  10 => 10,
312  20 => 20,
313  50 => 50,
314  100 => 100,
315  '' => 'maxSteps_all',
316  'marked' => 'maxSteps_marked'
317  );
318  $selector['showDiff'] = array(
319  0 => 'showDiff_no',
320  1 => 'showDiff_inline'
321  );
322  $selector['showSubElements'] = array(
323  0 => 'no',
324  1 => 'yes'
325  );
326  $selector['showInsertDelete'] = array(
327  0 => 'no',
328  1 => 'yes'
329  );
330  // render selectors
331  $displayCode = '';
332  foreach ($selector as $key => $values) {
333  $displayCode .= '<tr><td>' . $GLOBALS['LANG']->getLL($key, 1) . '</td>';
334  $displayCode .= '<td><select name="settings[' . $key . ']" onChange="document.settings.submit()" style="width:100px">';
335  foreach ($values as $singleKey => $singleVal) {
336  $caption = $GLOBALS['LANG']->getLL($singleVal, 1) ?: $singleVal;
337  $displayCode .= '<option value="' . $singleKey . '"' . ($singleKey == $currentSelection[$key] ? ' selected="selected"' : '') . '> ' . $caption . '</option>';
338  }
339  $displayCode .= '</select></td></tr>';
340  }
341  // set values correctly
342  if ($currentSelection['maxSteps'] != 'marked') {
343  $this->maxSteps = $currentSelection['maxSteps'] ? (int)$currentSelection['maxSteps'] : '';
344  } else {
345  $this->showMarked = TRUE;
346  $this->maxSteps = FALSE;
347  }
348  $this->showDiff = (int)$currentSelection['showDiff'];
349  $this->showSubElements = (int)$currentSelection['showSubElements'];
350  $this->showInsertDelete = (int)$currentSelection['showInsertDelete'];
351  $content = '';
352  // Get link to page history if the element history is shown
353  $elParts = explode(':', $this->element);
354  if (!empty($this->element) && $elParts[0] != 'pages') {
355  $content .= '<strong>' . $GLOBALS['LANG']->getLL('elementHistory', 1) . '</strong><br />';
356  $pid = $this->getRecord($elParts[0], $elParts[1]);
357 
358  if ($this->hasPageAccess('pages', $pid['pid'])) {
359  $content .= $this->linkPage($GLOBALS['LANG']->getLL('elementHistory_link', 1), array('element' => 'pages:' . $pid['pid']));
360  }
361  }
362  $content .= '<form name="settings" action="' . htmlspecialchars(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL')) . '" method="post"><table>' . $displayCode . '</table></form>';
363  return $GLOBALS['SOBE']->doc->section($GLOBALS['LANG']->getLL('settings', 1), $content, FALSE, TRUE, FALSE, FALSE);
364  }
365 
372  public function displayHistory() {
373  $lines = array();
374  // Initialize:
375  $lines[] = '<thead><tr>
376  <th> </th>
377  <th>' . $GLOBALS['LANG']->getLL('time', 1) . '</th>
378  <th>' . $GLOBALS['LANG']->getLL('age', 1) . '</th>
379  <th>' . $GLOBALS['LANG']->getLL('user', 1) . '</th>
380  <th>' . $GLOBALS['LANG']->getLL('tableUid', 1) . '</th>
381  <th>' . $GLOBALS['LANG']->getLL('differences', 1) . '</th>
382  <th>&nbsp;</th>
383  </tr></thead>';
384  $be_user_array = BackendUtility::getUserNames();
385  // Traverse changelog array:
386  if (!$this->changeLog) {
387  return 0;
388  }
389  $i = 0;
390  foreach ($this->changeLog as $sysLogUid => $entry) {
391  // stop after maxSteps
392  if ($i > $this->maxSteps && $this->maxSteps) {
393  break;
394  }
395  // Show only marked states
396  if (!$entry['snapshot'] && $this->showMarked) {
397  continue;
398  }
399  $i++;
400  // Get user names
401  $userName = $entry['user'] ? $be_user_array[$entry['user']]['username'] : $GLOBALS['LANG']->getLL('externalChange', 1);
402  // Build up single line
403  $singleLine = array();
404  // Diff link
405  $image = IconUtility::getSpriteIcon('actions-view-go-forward', array('title' => $GLOBALS['LANG']->getLL('sumUpChanges', TRUE)));
406  $singleLine[] = '<span>' . $this->linkPage($image, array('diff' => $sysLogUid)) . '</span>';
407  // remove first link
408  $singleLine[] = htmlspecialchars(BackendUtility::datetime($entry['tstamp']));
409  // add time
410  $singleLine[] = htmlspecialchars(BackendUtility::calcAge($GLOBALS['EXEC_TIME'] - $entry['tstamp'], $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')));
411  // add age
412  $singleLine[] = htmlspecialchars($userName);
413  // add user name
414  $singleLine[] = $this->linkPage($this->generateTitle($entry['tablename'], $entry['recuid']), array('element' => $entry['tablename'] . ':' . $entry['recuid']), '', $GLOBALS['LANG']->getLL('linkRecordHistory', 1));
415  // add record UID
416  // Show insert/delete/diff/changed field names
417  if ($entry['action']) {
418  // insert or delete of element
419  $singleLine[] = '<strong>' . htmlspecialchars($GLOBALS['LANG']->getLL($entry['action'], 1)) . '</strong>';
420  } else {
421  // Display field names instead of full diff
422  if (!$this->showDiff) {
423  // Re-write field names with labels
424  $tmpFieldList = explode(',', $entry['fieldlist']);
425  foreach ($tmpFieldList as $key => $value) {
426  $tmp = str_replace(':', '', $GLOBALS['LANG']->sl(BackendUtility::getItemLabel($entry['tablename'], $value), 1));
427  if ($tmp) {
428  $tmpFieldList[$key] = $tmp;
429  } else {
430  // remove fields if no label available
431  unset($tmpFieldList[$key]);
432  }
433  }
434  $singleLine[] = htmlspecialchars(implode(',', $tmpFieldList));
435  } else {
436  // Display diff
437  $diff = $this->renderDiff($entry, $entry['tablename']);
438  $singleLine[] = $diff;
439  }
440  }
441  // Show link to mark/unmark state
442  if (!$entry['action']) {
443  if ($entry['snapshot']) {
444  $image = IconUtility::getSpriteIcon('actions-unmarkstate', array('title' => $GLOBALS['LANG']->getLL('unmarkState', TRUE)), array());
445  } else {
446  $image = IconUtility::getSpriteIcon('actions-markstate', array('title' => $GLOBALS['LANG']->getLL('markState', TRUE)), array());
447  }
448  $singleLine[] = $this->linkPage($image, array('highlight' => $entry['uid']));
449  } else {
450  $singleLine[] = '';
451  }
452  // put line together
453  $lines[] = '
454  <tr>
455  <td>' . implode('</td><td>', $singleLine) . '</td>
456  </tr>';
457  }
458  // Finally, put it all together:
459  $theCode = '
460  <!--
461  History (list):
462  -->
463  <table class="t3-table" id="typo3-history">
464  ' . implode('', $lines) . '
465  </table>';
466  if ($this->lastSyslogId) {
467  $theCode .= '<br />' . $this->linkPage(IconUtility::getSpriteIcon('actions-move-to-bottom', array('title' => $GLOBALS['LANG']->getLL('fullView', TRUE))), array('diff' => ''));
468  }
469  // Add message about the difference view.
470  $flashMessage = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessage', $GLOBALS['LANG']->getLL('differenceMsg'), '', \TYPO3\CMS\Core\Messaging\FlashMessage::INFO);
471  $theCode .= '<br /><br />' . $flashMessage->render() . '<br />';
472  // Add the whole content as a module section:
473  return $GLOBALS['SOBE']->doc->section($GLOBALS['LANG']->getLL('changes'), $theCode, FALSE, TRUE);
474  }
475 
483  public function displayMultipleDiff($diff) {
484  $content = '';
485  // Get all array keys needed
486  $arrayKeys = array_merge(array_keys($diff['newData']), array_keys($diff['insertsDeletes']), array_keys($diff['oldData']));
487  $arrayKeys = array_unique($arrayKeys);
488  if ($arrayKeys) {
489  foreach ($arrayKeys as $key) {
490  $record = '';
491  $elParts = explode(':', $key);
492  // Turn around diff because it should be a "rollback preview"
493  if ($diff['insertsDeletes'][$key] == 1) {
494  // insert
495  $record .= '<strong>' . $GLOBALS['LANG']->getLL('delete', 1) . '</strong>';
496  $record .= '<br />';
497  } elseif ($diff['insertsDeletes'][$key] == -1) {
498  $record .= '<strong>' . $GLOBALS['LANG']->getLL('insert', 1) . '</strong>';
499  $record .= '<br />';
500  }
501  // Build up temporary diff array
502  // turn around diff because it should be a "rollback preview"
503  if ($diff['newData'][$key]) {
504  $tmpArr['newRecord'] = $diff['oldData'][$key];
505  $tmpArr['oldRecord'] = $diff['newData'][$key];
506  $record .= $this->renderDiff($tmpArr, $elParts[0], $elParts[1]);
507  }
508  $elParts = explode(':', $key);
509  $titleLine = $this->createRollbackLink($key, $GLOBALS['LANG']->getLL('revertRecord', 1), 1) . $this->generateTitle($elParts[0], $elParts[1]);
510  $record = '<div style="margin-left:10px;padding-left:5px;border-left:1px solid black;border-bottom:1px dotted black;padding-bottom:2px;">' . $record . '</div>';
511  $content .= $GLOBALS['SOBE']->doc->section($titleLine, $record, FALSE, FALSE, FALSE, TRUE);
512  }
513  $content = $this->createRollbackLink('ALL', $GLOBALS['LANG']->getLL('revertAll', 1), 0) . '<div style="margin-left:10px;padding-left:5px;border-left:1px solid black;border-bottom:1px dotted black;padding-bottom:2px;">' . $content . '</div>';
514  } else {
515  $content = $GLOBALS['LANG']->getLL('noDifferences', 1);
516  }
517  return $GLOBALS['SOBE']->doc->section($GLOBALS['LANG']->getLL('mergedDifferences', 1), $content, FALSE, TRUE, FALSE, TRUE);
518  }
519 
530  public function renderDiff($entry, $table, $rollbackUid = 0) {
531  $lines = array();
532  if (is_array($entry['newRecord'])) {
533  $t3lib_diff_Obj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Utility\\DiffUtility');
534  $fieldsToDisplay = array_keys($entry['newRecord']);
535  foreach ($fieldsToDisplay as $fN) {
536  if (is_array($GLOBALS['TCA'][$table]['columns'][$fN]) && $GLOBALS['TCA'][$table]['columns'][$fN]['config']['type'] != 'passthrough') {
537  // Create diff-result:
538  $diffres = $t3lib_diff_Obj->makeDiffDisplay(BackendUtility::getProcessedValue($table, $fN, $entry['oldRecord'][$fN], 0, 1), BackendUtility::getProcessedValue($table, $fN, $entry['newRecord'][$fN], 0, 1));
539  $lines[] = '
540  <tr class="bgColor4">
541  ' . ($rollbackUid ? '<td style="width:33px">' . $this->createRollbackLink(($table . ':' . $rollbackUid . ':' . $fN), $GLOBALS['LANG']->getLL('revertField', 1), 2) . '</td>' : '') . '
542  <td style="width:90px"><em>' . $GLOBALS['LANG']->sl(BackendUtility::getItemLabel($table, $fN), 1) . '</em></td>
543  <td style="width:300px">' . nl2br($diffres) . '</td>
544  </tr>';
545  }
546  }
547  }
548  if ($lines) {
549  $content = '<table border="0" cellpadding="2" cellspacing="2" id="typo3-history-item">
550  ' . implode('', $lines) . '
551  </table>';
552  return $content;
553  }
554  // error fallback
555  return NULL;
556  }
557 
558  /*******************************
559  *
560  * build up history
561  *
562  *******************************/
569  public function createMultipleDiff() {
570  $insertsDeletes = array();
571  $newArr = array();
572  $differences = array();
573  if (!$this->changeLog) {
574  return 0;
575  }
576  // traverse changelog array
577  foreach ($this->changeLog as $key => $value) {
578  $field = $value['tablename'] . ':' . $value['recuid'];
579  // inserts / deletes
580  if ($value['action']) {
581  if (!$insertsDeletes[$field]) {
582  $insertsDeletes[$field] = 0;
583  }
584  if ($value['action'] == 'insert') {
585  $insertsDeletes[$field]++;
586  } else {
587  $insertsDeletes[$field]--;
588  }
589  // unset not needed fields
590  if ($insertsDeletes[$field] == 0) {
591  unset($insertsDeletes[$field]);
592  }
593  } else {
594  // update fields
595  // first row of field
596  if (!isset($newArr[$field])) {
597  $newArr[$field] = $value['newRecord'];
598  $differences[$field] = $value['oldRecord'];
599  } else {
600  // standard
601  $differences[$field] = array_merge($differences[$field], $value['oldRecord']);
602  }
603  }
604  }
605  // remove entries where there were no changes effectively
606  foreach ($newArr as $record => $value) {
607  foreach ($value as $key => $innerVal) {
608  if ($newArr[$record][$key] == $differences[$record][$key]) {
609  unset($newArr[$record][$key]);
610  unset($differences[$record][$key]);
611  }
612  }
613  if (empty($newArr[$record]) && empty($differences[$record])) {
614  unset($newArr[$record]);
615  unset($differences[$record]);
616  }
617  }
618  return array(
619  'newData' => $newArr,
620  'oldData' => $differences,
621  'insertsDeletes' => $insertsDeletes
622  );
623  }
624 
631  public function createChangeLog() {
632  $elParts = explode(':', $this->element);
633 
634  if (empty($this->element)) {
635  return 0;
636  }
637 
638  $changeLog = $this->getHistoryData($elParts[0], $elParts[1]);
639  // get history of tables of this page and merge it into changelog
640  if ($elParts[0] == 'pages' && $this->showSubElements && $this->hasPageAccess('pages', $elParts[1])) {
641  foreach ($GLOBALS['TCA'] as $tablename => $value) {
642  // check if there are records on the page
643  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $tablename, 'pid=' . (int)$elParts[1]);
644  while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
645  // if there is history data available, merge it into changelog
646  if ($newChangeLog = $this->getHistoryData($tablename, $row['uid'])) {
647  foreach ($newChangeLog as $key => $value) {
648  $changeLog[$key] = $value;
649  }
650  }
651  }
652  }
653  }
654  if (!$changeLog) {
655  return 0;
656  }
657  krsort($changeLog);
658  $this->changeLog = $changeLog;
659  return 1;
660  }
661 
670  public function getHistoryData($table, $uid) {
671  // If table is found in $GLOBALS['TCA']:
672  if ($GLOBALS['TCA'][$table] && $this->hasTableAccess($table) && $this->hasPageAccess($table, $uid)) {
673  $uid = $this->resolveElement($table, $uid);
674  // Selecting the $this->maxSteps most recent states:
675  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('sys_history.*, sys_log.userid', 'sys_history, sys_log', 'sys_history.sys_log_uid = sys_log.uid
676  AND sys_history.tablename = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_history') . '
677  AND sys_history.recuid = ' . (int)$uid, '', 'sys_log.uid DESC', $this->maxSteps);
678  // Traversing the result, building up changesArray / changeLog:
679  $changeLog = array();
680  while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
681  // Only history until a certain syslog ID needed
682  if ($row['sys_log_uid'] < $this->lastSyslogId && $this->lastSyslogId) {
683  continue;
684  }
685  $hisDat = unserialize($row['history_data']);
686  if (is_array($hisDat['newRecord']) && is_array($hisDat['oldRecord'])) {
687  // Add hisDat to the changeLog
688  $hisDat['uid'] = $row['uid'];
689  $hisDat['tstamp'] = $row['tstamp'];
690  $hisDat['user'] = $row['userid'];
691  $hisDat['snapshot'] = $row['snapshot'];
692  $hisDat['fieldlist'] = $row['fieldlist'];
693  $hisDat['tablename'] = $row['tablename'];
694  $hisDat['recuid'] = $row['recuid'];
695  $changeLog[$row['sys_log_uid']] = $hisDat;
696  } else {
697  debug('ERROR: [getHistoryData]');
698  // error fallback
699  return 0;
700  }
701  }
702  // SELECT INSERTS/DELETES
703  if ($this->showInsertDelete) {
704  // Select most recent inserts and deletes // WITHOUT snapshots
705  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid, userid, action, tstamp', 'sys_log', 'type = 1
706  AND (action=1 OR action=3)
707  AND tablename = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_log') . '
708  AND recuid = ' . (int)$uid, '', 'uid DESC', $this->maxSteps);
709  while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
710  if ($row['uid'] < $this->lastSyslogId && $this->lastSyslogId) {
711  continue;
712  }
713  $hisDat = array();
714  switch ($row['action']) {
715  case 1:
716  // Insert
717  $hisDat['action'] = 'insert';
718  break;
719  case 3:
720  // Delete
721  $hisDat['action'] = 'delete';
722  break;
723  }
724  $hisDat['tstamp'] = $row['tstamp'];
725  $hisDat['user'] = $row['userid'];
726  $hisDat['tablename'] = $table;
727  $hisDat['recuid'] = $uid;
728  $changeLog[$row['uid']] = $hisDat;
729  }
730  }
731  return $changeLog;
732  }
733  // error fallback
734  return 0;
735  }
736 
737  /*******************************
738  *
739  * Various helper functions
740  *
741  *******************************/
750  public function generateTitle($table, $uid) {
751  $out = $table . ':' . $uid;
752  if ($labelField = $GLOBALS['TCA'][$table]['ctrl']['label']) {
753  $record = $this->getRecord($table, $uid);
754  $out .= ' (' . BackendUtility::getRecordTitle($table, $record, TRUE) . ')';
755  }
756  return $out;
757  }
758 
768  public function createRollbackLink($key, $alt = '', $type = 0) {
769  return $this->linkPage('<img ' . IconUtility::skinImg('', ('gfx/revert_' . $type . '.gif'), 'width="33" height="33"') . ' alt="' . $alt . '" title="' . $alt . '" align="middle" />', array('rollbackFields' => $key));
770  }
771 
783  public function linkPage($str, $inparams = array(), $anchor = '', $title = '') {
784  // Setting default values based on GET parameters:
785  $params['element'] = $this->element;
786  $params['returnUrl'] = $this->returnUrl;
787  $params['diff'] = $this->lastSyslogId;
788  // Mergin overriding values:
789  $params = array_merge($params, $inparams);
790  // Make the link:
791  $link = BackendUtility::getModuleUrl('record_history', $params) . ($anchor ? '#' . $anchor : '');
792  return '<a href="' . htmlspecialchars($link) . '"' . ($title ? ' title="' . $title . '"' : '') . '>' . $str . '</a>';
793  }
794 
804  public function removeFilefields($table, $dataArray) {
805  if ($GLOBALS['TCA'][$table]) {
806  foreach ($GLOBALS['TCA'][$table]['columns'] as $field => $config) {
807  if ($config['config']['type'] == 'group' && $config['config']['internal_type'] == 'file') {
808  unset($dataArray[$field]);
809  }
810  }
811  }
812  return $dataArray;
813  }
814 
823  public function resolveElement($table, $uid) {
824  if (isset($GLOBALS['TCA'][$table])) {
825  if ($workspaceVersion = BackendUtility::getWorkspaceVersionOfRecord($GLOBALS['BE_USER']->workspace, $table, $uid, 'uid')) {
826  $uid = $workspaceVersion['uid'];
827  }
828  }
829  return $uid;
830  }
831 
838  public function resolveShUid() {
839  if ($this->getArgument('sh_uid')) {
840  $sh_uid = $this->getArgument('sh_uid');
841  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_history', 'uid=' . (int)$sh_uid);
842  $record = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
843  $this->element = $record['tablename'] . ':' . $record['recuid'];
844  $this->lastSyslogId = $record['sys_log_uid'] - 1;
845  }
846  }
847 
855  protected function hasPageAccess($table, $uid) {
856  $uid = (int)$uid;
857 
858  if ($table === 'pages') {
859  $pageId = $uid;
860  } else {
861  $record = $this->getRecord($table, $uid);
862  $pageId = $record['pid'];
863  }
864 
865  if (!isset($this->pageAccessCache[$pageId])) {
866  $this->pageAccessCache[$pageId] = BackendUtility::readPageAccess(
867  $pageId, $this->getBackendUser()->getPagePermsClause(1)
868  );
869  }
870 
871  return ($this->pageAccessCache[$pageId] !== FALSE);
872  }
873 
880  protected function hasTableAccess($table) {
881  return $this->getBackendUser()->check('tables_select', $table);
882  }
883 
891  protected function getRecord($table, $uid) {
892  if (!isset($this->recordCache[$table][$uid])) {
893  $this->recordCache[$table][$uid] = BackendUtility::getRecord($table, $uid, '*', '', FALSE);
894  }
895  return $this->recordCache[$table][$uid];
896  }
897 
903  protected function getBackendUser() {
904  return $GLOBALS['BE_USER'];
905  }
906 
915  protected function getArgument($name) {
916  $value = GeneralUtility::_GP($name);
917 
918  switch ($name) {
919  case 'element':
920  if ($value !== '' && !preg_match('#^[a-z0-9_.]+:[0-9]+$#i', $value)) {
921  $value = '';
922  }
923  break;
924  case 'rollbackFields':
925  case 'revert':
926  if ($value !== '' && !preg_match('#^[a-z0-9_.]+(:[0-9]+(:[a-z0-9_.]+)?)?$#i', $value)) {
927  $value = '';
928  }
929  break;
930  case 'returnUrl':
931  $value = GeneralUtility::sanitizeLocalUrl($value);
932  break;
933  case 'diff':
934  case 'highlight':
935  case 'sh_uid':
936  $value = (int)$value;
937  break;
938  case 'settings':
939  if (!is_array($value)) {
940  $value = array();
941  }
942  break;
943  default:
944  $value = '';
945  }
946 
947  return $value;
948  }
949 
950 }
linkPage($str, $inparams=array(), $anchor='', $title='')
createRollbackLink($key, $alt='', $type=0)
static skinImg($backPath, $src, $wHattribs='', $outputMode=0)
static readPageAccess($id, $perms_clause)
static getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields=' *')
static getItemLabel($table, $col, $printAllWrap='')
$uid
Definition: server.php:36
static calcAge($seconds, $labels=' min|hrs|days|yrs|min|hour|day|year')
static getRecordTitle($table, $row, $prep=FALSE, $forceResult=TRUE)
static getModuleUrl($moduleName, $urlParameters=array(), $backPathOverride=FALSE, $returnAbsoluteUrl=FALSE)
static getUserNames($fields='username, usergroup, usergroup_cached_list, uid', $where='')
static getSpriteIcon($iconName, array $options=array(), array $overlays=array())
debug($variable='', $name=' *variable *', $line=' *line *', $file=' *file *', $recursiveDepth=3, $debugLevel=E_DEBUG)
static redirect($url, $httpStatus=self::HTTP_STATUS_303)
Definition: HttpUtility.php:76
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
renderDiff($entry, $table, $rollbackUid=0)