/** * Computes the two textes and returns an array with the changes needed * to trade back to the old text. * * @author Johannes Klose <*****@*****.**> * @param string $text1 The old text * @param string $text2 The new text * @return array Differences between $text1 and $text2 **/ function getDiff($text1, $text2) { $lines1 = explode("\n", $text1); $lines2 = explode("\n", $text2); $obj = new Text_Diff($lines2, $lines1); $diff = $obj->getDiff(); $ndiff = array(); $lines = 0; /** * Take the array with the differences and strip * informations (unchanged lines, old values on changed lines) * we do not need to store in the database to get from the * new page version to the old one. **/ foreach ($diff as $op) { if (strtolower(get_class($op)) == 'text_diff_op_copy') { $lines += count($op->orig); continue; } elseif (strtolower(get_class($op)) == 'text_diff_op_change') { if (count($op->orig) == count($op->final)) { foreach ($op->final as $key => $val) { if (isset($op->orig[$key])) { $ndiff[$lines + $key] = array('~', $val); } else { $ndiff[$lines + $key] = array('+', $val); } } } elseif (count($op->orig) > count($op->final)) { foreach ($op->orig as $key => $val) { if (isset($op->final[$key])) { $ndiff[$lines + $key] = array('~', $op->final[$key]); } else { $ndiff[$lines + $key] = array('-'); } } } else { foreach ($op->final as $key => $val) { if (isset($op->orig[$key])) { $ndiff[$lines + $key] = array('~', $op->final[$key]); } else { $ndiff[$lines + $key] = array('+', $op->final[$key]); } } } } elseif (strtolower(get_class($op)) == 'text_diff_op_add') { foreach ($op->final as $key => $val) { $ndiff[$lines + $key] = array('+', $val); } } elseif (strtolower(get_class($op)) == 'text_diff_op_delete') { foreach ($op->orig as $key => $val) { $ndiff[$lines + $key] = array('-'); } } $lines += count($op->orig) > count($op->final) ? count($op->orig) : count($op->final); } return $ndiff; }
/** * Renders a diff. * * @param Text_Diff $diff A Text_Diff object. * * @return string The formatted output. */ function render($diff) { $xi = $yi = 1; $block = false; $context = array(); $nlead = $this->_leading_context_lines; $ntrail = $this->_trailing_context_lines; $output = $this->_startDiff(); $diffs = $diff->getDiff(); foreach ($diffs as $i => $edit) { if (is_a($edit, 'Text_Diff_Op_copy')) { if (is_array($block)) { $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail; if (count($edit->orig) <= $keep) { $block[] = $edit; } else { if ($ntrail) { $context = array_slice($edit->orig, 0, $ntrail); $block[] =& new Text_Diff_Op_copy($context); } $output .= $this->_block($x0, $ntrail + $xi - $x0, $y0, $ntrail + $yi - $y0, $block); $block = false; } } $context = $edit->orig; } else { if (!is_array($block)) { $context = array_slice($context, count($context) - $nlead); $x0 = $xi - count($context); $y0 = $yi - count($context); $block = array(); if ($context) { $block[] =& new Text_Diff_Op_copy($context); } } $block[] = $edit; } if ($edit->orig) { $xi += count($edit->orig); } if ($edit->final) { $yi += count($edit->final); } } if (is_array($block)) { $output .= $this->_block($x0, $xi - $x0, $y0, $yi - $y0, $block); } return $output . $this->_endDiff(); }
/** * Renders a diff. * * @param Text_Diff $diff A Text_Diff object. * * @return string The formatted output. */ function render($diff) { $xi = $yi = 1; $block = false; $context = array(); $nlead = $this->_leading_context_lines; $ntrail = $this->_trailing_context_lines; $output = $this->_startDiff(); $diffs = $diff->getDiff(); foreach ($diffs as $i => $edit) { /* If these are unchanged (copied) lines, and we want to keep * leading or trailing context lines, extract them from the copy * block. */ if (is_a($edit, 'Text_Diff_Op_copy')) { /* Do we have any diff blocks yet? */ if (is_array($block)) { /* How many lines to keep as context from the copy * block. */ $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail; if (count($edit->orig) <= $keep) { /* We have less lines in the block than we want for * context => keep the whole block. */ $block[] = $edit; } else { if ($ntrail) { /* Create a new block with as many lines as we need * for the trailing context. */ $context = array_slice($edit->orig, 0, $ntrail); $block[] = new Text_Diff_Op_copy($context); } /* @todo */ $output .= $this->_block($x0, $ntrail + $xi - $x0, $y0, $ntrail + $yi - $y0, $block); $block = false; } } /* Keep the copy block as the context for the next block. */ $context = $edit->orig; } else { /* Don't we have any diff blocks yet? */ if (!is_array($block)) { /* Extract context lines from the preceding copy block. */ $context = array_slice($context, count($context) - $nlead); $x0 = $xi - count($context); $y0 = $yi - count($context); $block = array(); if ($context) { $block[] = new Text_Diff_Op_copy($context); } } $block[] = $edit; } if ($edit->orig) { $xi += count($edit->orig); } if ($edit->final) { $yi += count($edit->final); } } if (is_array($block)) { $output .= $this->_block($x0, $xi - $x0, $y0, $yi - $y0, $block); } return $output . $this->_endDiff(); }
/** * * merges a newer version of a page into the current document * @param string $newpage a string with a later version of the page * @param string $newauthor name of the author of the new version */ function mergeDiff($newpage, $newauthor) { global $tikilib; $this->_history=false; $author=$newauthor; $deleted=false; $deleted_by=''; $newdoc=array(); $page=preg_replace(array('/\{AUTHOR\(.+?\)\}/','/{AUTHOR\}/','/\{INCLUDE\(.+?\)\}\{INCLUDE\}/'), ' ~np~$0~/np~', $newpage); if ($this->_parsed) { $page=$tikilib->parse_data($page, array('suppress_icons'=>true)); $page=preg_replace(array('/\{AUTHOR\(.+?\)\}/','/{AUTHOR\}/','/\{INCLUDE\(.+?\)\}\{INCLUDE\}/'), ' ~np~$0~/np~', $page); } if ($this->_nohtml) { $page=strip_tags($page); } preg_match_all($this->_search, $page, $out, PREG_PATTERN_ORDER); $new=$out[0]; $z = new Text_Diff($this->getDiffArray(), $new); $pos=0; foreach ($z->getDiff() as $element) { if (is_a($element, 'Text_Diff_Op_copy')) { $this->moveWords($newdoc, $pos, $element->orig, $deleted, $deleted_by); } else { if (is_a($element, 'Text_Diff_Op_add')) { $newdoc=$this->addWords($newdoc, $element->final, $author, $deleted, $deleted_by); } else { if (is_a($element, 'Text_Diff_Op_delete')) { $this->moveWords($newdoc, $pos, $element->orig, $deleted, $author); } else { //change $newdoc=$this->addWords($newdoc, $element->final, $author, $deleted, $deleted_by); $this->moveWords($newdoc, $pos, $element->orig, true, $author); } //delete } // add } // copy } // foreach diff $this->_document=$newdoc; }
$end += strspn($text, $delimiter, $end); if ($end === $start) { break; } $fragments[] = substr($text, $start, $end - $start); $start = $end; } return $fragments; } $from_fragments = extractFragments($from, $delimiters[$granularity]); $to_fragments = extractFragments($to, $delimiters[$granularity]); $diff = new Text_Diff('native', array($from_fragments, $to_fragments)); $exec_time = sprintf('%.3f sec', gettimeofday(true) - $start_time); $edits = array(); ob_start(); foreach ($diff->getDiff() as $edit) { if ($edit instanceof Text_Diff_Op_copy) { $orig = str_replace(array("", ""), array("\n", "\r"), implode('', $edit->orig)); $edits[] = new fineDiffCopyOp(strlen($orig)); echo htmlentities($orig); } else { if ($edit instanceof Text_Diff_Op_delete) { $orig = str_replace(array("", ""), array("\n", "\r"), implode('', $edit->orig)); $edits[] = new fineDiffDeleteOp(strlen($orig)); echo '<del>', htmlentities($orig), '</del>'; } else { if ($edit instanceof Text_Diff_Op_add) { $final = str_replace(array("", ""), array("\n", "\r"), implode('', $edit->final)); $edits[] = new fineDiffInsertOp($final); echo '<ins>', htmlentities($final), '</ins>'; } else {
function diffLatestWithArchive($archive = 0) { include_once "lib/diff/Diff.php"; $textDiff = new Text_Diff(FileGallery_File::id($this->getParam('fileId'))->archive($archive)->data(), $this->data()); return $textDiff->getDiff(); }
function diff_sheets_as_html($id, $dates = null) { global $prefs, $sheetlib; function count_longest($array1, $array2) { return count($array1) > count($array2) ? count($array1) : count($array2); } function join_with_sub_grids($id, $date) { global $prefs, $sheetlib; $result1 = ""; $result2 = ""; $handler = new TikiSheetDatabaseHandler($id, $date); $handler->setReadDate($date); $grid = new TikiSheet(); $grid->import($handler); $childSheetIds = $sheetlib->get_related_sheet_ids($grid->id); $i = 0; $grids = array($grid); foreach ($childSheetIds as $childSheetId) { $handler = new TikiSheetDatabaseHandler($childSheetId, $date); $handler->setReadDate($date); $childSheet = new TikiSheet(); $childSheet->import($handler); array_push($grids, $childSheet); $i++; } return $grids; } function sanitize_for_diff($val) { $val = str_replace("<br/>", "<br>", $val); $val = str_replace("<br />", "<br>", $val); $val = str_replace("<br />", "<br>", $val); $val = str_replace("<BR/>", "<br>", $val); $val = str_replace("<BR />", "<br>", $val); $val = str_replace("<BR />", "<br>", $val); return explode("<br>", $val); } function diff_to_html($changes) { $result = array("", ""); for ($i = 0; $i < count_longest($changes->orig, $changes->final); $i++) { $class = array("", ""); $char = array("", ""); $vals = array(trim($changes->orig[$i]), trim($changes->final[$i])); if ($vals[0] && $vals[1]) { if ($vals[0] != $vals[1]) { $class[1] .= "diffadded"; } } else { if ($vals[0]) { $class[0] .= "diffadded"; $class[1] .= "diffdeleted"; $vals[1] = $vals[0]; $char[1] = "-"; } else { if ($vals[1]) { $class[0] .= "diffdeleted"; $class[1] .= "diffadded"; $char[1] = "+"; } } } if ($vals[0]) { $result[0] .= "<td class='{$class['0']}'>" . $char[0] . $vals[0] . "</td>"; } if ($vals[1]) { $result[1] .= "<td class='{$class['1']}'>" . $char[1] . $vals[1] . "</td>"; } } return $result; } $grids1 = join_with_sub_grids($id, $dates[0]); $grids2 = join_with_sub_grids($id, $dates[1]); for ($i = 0; $i < count_longest($grids1, $grids2); $i++) { //cycle through the sheets within a spreadsheet $result1 .= "<table title='" . $grids1[$i]->name() . "'>"; $result2 .= "<table title='" . $grids2[$i]->name() . "'>"; for ($row = 0; $row < count_longest($grids1[$i]->dataGrid, $grids2[$i]->dataGrid); $row++) { //cycle through rows $result1 .= "<tr>"; $result2 .= "<tr>"; for ($col = 0; $col < count_longest($grids1[$i]->dataGrid[$row], $grids2[$i]->dataGrid[$row]); $col++) { //cycle through columns $diff = new Text_Diff(sanitize_for_diff($grids1[$i]->dataGrid[$row][$col]), sanitize_for_diff($grids2[$i]->dataGrid[$row][$col])); $changes = $diff->getDiff(); //print_r($changes); $class = array('', ''); $values = array('', ''); //I left this diff switch, but it really isn't being used as of now, in the future we may though. switch (get_class($changes[0])) { case 'Text_Diff_Op_copy': $values = diff_to_html($changes[0]); break; case 'Text_Diff_Op_change': $values = diff_to_html($changes[0]); break; case 'Text_Diff_Op_delete': $values = diff_to_html($changes[0]); break; case 'Text_Diff_Op_add': $values = diff_to_html($changes[0]); break; default: $values = diff_to_html($changes[0]); } $result1 .= empty($values[0]) ? '<td></td>' : $values[0]; $result2 .= empty($values[1]) ? '<td></td>' : $values[1]; } $result1 .= "</tr>"; $result2 .= "</tr>"; } $result1 .= "</table>"; $result2 .= "</table>"; } return array($result1, $result2); }