* Invision Power Services * IP.Board v3.3.4 * Compare and highlight differences between two strings or files * Last Updated: $Date: 2012-06-12 10:14:49 -0400 (Tue, 12 Jun 2012) $ * * * @author $Author: bfarber $ * @copyright (c) 2001 - 2009 Invision Power Services, Inc. * @license http://www.invisionpower.com/company/standards.php#license * @package IP.Board * @subpackage Kernel * @link http://www.invisionpower.com * @since Thursday 10th February 2005 (10:47) * @version $Revision: 10914 $ */ if ( ! defined( 'IPS_CLASSES_PATH' ) ) { /** * Define classes path */ define( 'IPS_CLASSES_PATH', dirname(__FILE__) ); } class classDifference { /** * Shell command * * @var string */ public $diff_command = 'diff'; /** * Type of diff to use * * @var string [EXEC, PHP] */ public $method = 'EXEC'; /** * Differences found? * * @var integer */ public $diff_found = 0; /** * Post process DIFF result? * * @var integer */ public $post_process = 1; /** * Constructor * * @return @e void */ public function __construct() { //------------------------------- // Server? //------------------------------- if( strpos( strtolower( PHP_OS ), 'win' ) === 0 OR ( ! function_exists('exec') ) ) { $this->method = 'PHP'; } } /** * Retrieve a text string showing the differences between the two supplied strings * * @param string Original string * @param string New string * @param string Inline or unified report (only supported by PHP method) * @return @e string */ public function getDifferences( $str1, $str2, $method='inline' ) { $this->diff_found = 0; if ( $this->method != 'PHP' ) { $str1 = $this->_diffTagSpace($str1); $str2 = $this->_diffTagSpace($str2); $str1_lines = $this->_diffExplodeStringIntoWords($str1); $str2_lines = $this->_diffExplodeStringIntoWords($str2); } if ( $this->method == 'PHP' ) { $diff_res = $this->_getPhpDiff( $str1, $str2, $method ); } else { $diff_res = $this->_getExecDiff( implode( chr(10), $str1_lines ) . chr(10), implode( chr(10), $str2_lines ) . chr(10) ); } //------------------------------- // Post process? //------------------------------- if ( $this->post_process ) { if ( is_array($diff_res) ) { reset($diff_res); $c = 0; $diff_res_array = array(); foreach( $diff_res as $l_val ) { if ( intval($l_val) ) { $c = intval($l_val); $diff_res_array[$c]['changeInfo'] = $l_val; } if (substr($l_val,0,1) == '<') { $diff_res_array[$c]['old'][] = substr($l_val,2); } if (substr($l_val,0,1) == '>') { $diff_res_array[$c]['new'][] = substr($l_val,2); } } $out_str = ''; $clr_buffer = ''; for ( $a = -1; $a < count($str1_lines); $a++ ) { if ( is_array( $diff_res_array[$a+1] ) ) { if ( strstr( $diff_res_array[$a+1]['changeInfo'], 'a') ) { $this->diff_found = 1; $clr_buffer .= htmlspecialchars($str1_lines[$a]).' '; } $out_str .= $clr_buffer; $clr_buffer = ''; if (is_array($diff_res_array[$a+1]['old'])) { $this->diff_found = 1; $out_str.=''.htmlspecialchars(implode(' ',$diff_res_array[$a+1]['old'])).' '; } if (is_array($diff_res_array[$a+1]['new'])) { $this->diff_found = 1; $out_str.=''.htmlspecialchars(implode(' ',$diff_res_array[$a+1]['new'])).' '; } $cip = explode(',',$diff_res_array[$a+1]['changeInfo']); if ( ! strcmp( $cip[0], $a + 1 ) ) { $new_line = intval($cip[1])-1; if ( $new_line > $a ) { $a = $new_line; } } } else { $clr_buffer .= htmlspecialchars($str1_lines[$a]).' '; } } $out_str .= $clr_buffer; $out_str = str_replace(' ',chr(10),$out_str); $out_str = $this->_diffTagSpace($out_str,1); return $out_str; } } else { return $diff_res; } } /** * Adds space character after HTML tags * * @param string String * @param integer [Optional][0=reverse, 1=normal] * @return @e string */ protected function _diffTagSpace( $str, $rev=0 ) { if ( $rev ) { return str_replace(' <','<',str_replace('> ','>',$str) ); } else { return str_replace('<',' <',str_replace('>','> ',$str) ); } } /** * Explodes input string into words * * @access protected * @param string Input string * @return @e array */ protected function _diffExplodeStringIntoWords( $str ) { $str_array = $this->_explodeTrim( chr(10), $str ); $out_array = array(); reset($str_array); foreach( $str_array as $low ) { $all_words = $this->_explodeTrim( ' ', $low, 1 ); $out_array = array_merge($out_array, $all_words); $out_array[] = ''; $out_array[] = ''; } return $out_array; } /** * Explode into array and trim * * @param string Delimiter * @param string String to check * @param integer [Optional] Remove blank lines * @return @e array */ protected function _explodeTrim( $delim, $str, $remove_blank=0 ) { $tmp = explode( $delim, trim($str) ); $final = array(); foreach( $tmp as $i ) { if ( $remove_blank AND ( $i === '' OR $i === NULL ) ) //!$i AND $i !== 0 ) { continue; } else { $final[] = trim($i); } } return $final; } /** * Produce differences using PHP * * @param string comapre string 1 * @param string comapre string 2 * @return @e string */ protected function _getPhpDiff( $str1 , $str2, $method='inline' ) { $str1 = explode( "\n", str_replace( "\r\n", "\n", $str1 ) ); $str2 = explode( "\n", str_replace( "\r\n", "\n", $str2 ) ); /* Set include path.. */ @set_include_path( IPS_KERNEL_PATH . 'PEAR/' );/*noLibHook*/ /* OMG.. too many PHP 5 errors under strict standards */ $oldReportLevel = error_reporting( 0 ); error_reporting( $oldReportLevel ^ E_STRICT ); require_once 'Text/Diff.php';/*noLibHook*/ require_once 'Text/Diff/Renderer.php';/*noLibHook*/ $diff = new Text_Diff( 'auto', array( $str1, $str2 ) ); if ( $method == 'inline' ) { require_once 'Text/Diff/Renderer/inline.php';/*noLibHook*/ $renderer = new Text_Diff_Renderer_inline(); } else { require_once 'Text/Diff/Renderer/unified.php';/*noLibHook*/ $renderer = new Text_Diff_Renderer_unified(); $renderer->_leading_context_lines = 10000; $renderer->_trailing_context_lines = 10000; } $result = $renderer->render($diff); /* Go back to old reporting level */ error_reporting( $oldReportLevel | E_STRICT ); $result = str_replace( "", '', $result ); $result = str_replace( "", '', $result ); # Got a match? if ( strstr( $result, 'style="-ips-match:1"' ) ) { $this->diff_found = 1; } # No post processing please $this->post_process = 0; # Convert lines to a space, and two spaces to a single line //$result = str_replace(' ', chr(10), str_replace( "\n", " ", $result ) ); //$result = $this->_diffTagSpace($result,1); return $result; } /** * Produce differences using unix diff * * @param string comapre string 1 * @param string comapre string 2 * @return @e string */ protected function _getExecDiff( $str1, $str2 ) { //------------------------------- // Write the tmp files //------------------------------- $file1 = IPS_ROOT_PATH . 'uploads/'.time().'-1'; $file2 = IPS_ROOT_PATH . 'uploads/'.time().'-2'; if ( $FH1 = @fopen( $file1, 'w' ) ) { @fwrite( $FH1, $str1, strlen($str1) ); @fclose( $FH1 ); } if ( $FH2 = @fopen( $file2, 'w' ) ) { @fwrite( $FH2, $str2, strlen($str2) ); @fclose( $FH2 ); } //------------------------------- // Check //------------------------------- if ( is_file( $file1 ) and is_file( $file2 ) ) { exec( $this->diff_command.' '.$file1.' '.$file2, $result ); @unlink( $file1 ); @unlink( $file2 ); return $result; } else { return "Error, files not written to disk"; } } /** * Format differences for output (common) * * @param string Differences report * @param string Format method (inline|unified) * @param bool Wrap in pre tags (true) or nl2br for output (false) * @return @e string */ public function formatDifferenceReport( $result, $method='inline', $pre=true ) { if( $result ) { if( $method == 'unified' ) { $result = str_replace( array( "\r\n", "\r" ), "\n", $result ); $result = preg_replace( '#(^|\n)(\-|\+)([^\n]+?)\n#', "\n\\1\\2\\3\n\n", $result ); $result = htmlspecialchars( $result ); $result = preg_replace( '#^@@([^@]+?)@@#m', '', $result ); $result = preg_replace( '#(^|\n)\-([^\n]+?)\n#', "\\1\\2\n", $result ); $result = preg_replace( '#(^|\n)\+([^\n]+?)\n#', "\\1\\2\n", $result ); $result = str_replace( "\n\n", "\n", $result ); $result = str_replace( "\n", '', $result ); $result = str_replace( "\n\n", "\n", $result ); $result = str_replace( "\n\n", "\n", $result ); $result = str_replace( "\n+\n", "\n\n", $result ); $result = str_replace( "\n-\n", "\n\n", $result ); if( $pre ) { $result = '
' . $result . '
'; } else { $result = str_replace( "\t", "    ", $result ); $result = str_replace( ' ', ' ', $result ); $result = nl2br( $result ); } } else { $result = str_replace( "\n", "
", $result ); $result = str_replace( "><", ">\n<", $result ); $result = preg_replace( "#(?' . $result . ''; } else { $result = str_replace( "\t", "    ", $result ); $result = str_replace( ' ', ' ', $result ); $result = nl2br( $result ); } } } return $result; } }