<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<style type="text/css">
body {margin:0;border:0;padding:0;font:11pt sans-serif}
body > h1 {margin:0 0 0.5em 0;font:2em sans-serif;background-color:#def}
body > div {padding:2px}
p {margin-top:0}
ins {color:green;background:#dfd;text-decoration:none}
del {color:red;background:#fdd;text-decoration:none}
#params {margin:1em 0;font: 14px sans-serif}
.panecontainer > p {margin:0;border:1px solid #bcd;border-bottom:none;padding:1px 3px;background:#def;font:14px sans-serif}
.panecontainer > p + div {margin:0;padding:2px 0 2px 2px;border:1px solid #bcd;border-top:none}
.pane {margin:0;padding:0;border:0;width:100%;min-height:20em;overflow:auto;font:12px monospace}
#htmldiff {color:gray}
#htmldiff.onlyDeletions ins {display:none}
#htmldiff.onlyInsertions del {display:none}
</style>
<title>PHP Fine Diff: Online Diff Viewer</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<a href="https://github.com/gorhill/PHP-FineDiff"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/38ef81f8aca64bb9a64448d0d70f1308ef5341ab/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6461726b626c75655f3132313632312e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a>
<h1>PHP Fine Diff: Online Diff Viewer</h1>
<div>
<?php
// http://www.php.net/manual/en/function.get-magic-quotes-gpc.php#82524
function stripslashes_deep(&$value)
{
    $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value);
    return $value;
}
if ((function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc()) || (ini_get('magic_quotes_sybase') && strtolower(ini_get('magic_quotes_sybase'))!="off")) {
    stripslashes_deep($_GET);
    stripslashes_deep($_POST);
}

include 'finediff.php';

$cache_lo_water_mark = 900;
$cache_hi_water_mark = 1100;
$compressed_serialized_filename_extension = '.store.gz';

$granularity = 2;
$from_text = '';
$to_text = '';
$diff_opcodes = '';
$diff_opcodes_len = 0;
$data_key = '';

$start_time = gettimeofday(true);

// restore from cache
if (isset($_GET['data'])) {
    if (ctype_alnum($_GET['data'])) {
        $filename = "{$_GET['data']}{$compressed_serialized_filename_extension}";
        $compressed_serialized_data = @file_get_contents("./cache/{$filename}");
        if ($compressed_serialized_data !== false) {
            @touch("./cache/{$filename}");
            $data_from_serialization = unserialize(gzuncompress($compressed_serialized_data));
            $granularity = $data_from_serialization['granularity'];
            $from_text = $data_from_serialization['from_text'];
            $diff_opcodes = $data_from_serialization['diff_opcodes'];
            $diff_opcodes_len = strlen($diff_opcodes);
            $to_text = FineDiff::renderToTextFromOpcodes($from_text, $diff_opcodes);
            $data_key = $data_from_serialization['data_key'];
        } else {
            echo '<p style="font-size:smaller">The page you are looking for has expired.</p>', "\n";
        }
    }
    $exec_time = gettimeofday(true) - $start_time;
}
// new diff
else {
    if (isset($_POST['granularity']) && ctype_digit($_POST['granularity'])) {
        $granularity = max(min(intval($_POST['granularity']), 3), 0);
    }
    if (!empty($_POST['from']) || !empty($_POST['to'])) {
        if (!empty($_POST['from'])) {
            $from_text = $_POST['from'];
        }
        if (!empty($_POST['to'])) {
            $to_text = $_POST['to'];
        }
    }
    // limit input
    $from_text = substr($from_text, 0, 1024*100);
    $to_text = substr($to_text, 0, 1024*100);

    // ensure input is suitable for diff
    $from_text = mb_convert_encoding($from_text, 'HTML-ENTITIES', 'UTF-8');
    $to_text = mb_convert_encoding($to_text, 'HTML-ENTITIES', 'UTF-8');

    $granularityStacks = array(
        FineDiff::$paragraphGranularity,
        FineDiff::$sentenceGranularity,
        FineDiff::$wordGranularity,
        FineDiff::$characterGranularity
        );
    $diff_opcodes = FineDiff::getDiffOpcodes($from_text, $to_text, $granularityStacks[$granularity]);
    $diff_opcodes_len = strlen($diff_opcodes);
    $exec_time = gettimeofday(true) - $start_time;
    if ($diff_opcodes_len) {
        $data_key = sha1(serialize(array('granularity' => $granularity, 'from_text' => $from_text, 'diff_opcodes' => $diff_opcodes)));
        $filename = "{$data_key}{$compressed_serialized_filename_extension}";
        if (!file_exists("./cache/{$filename}")) {
            // purge cache if too many files
            if (!(time() % 100)) {
                $files = glob("./cache/*{$compressed_serialized_filename_extension}");
                $num_files = $files ? count($files) : 0;
                if ($num_files > $cache_hi_water_mark) {
                    $sorted_files = array();
                    foreach ($files as $file) {
                        $sorted_files[strval(@filemtime("./cache/{$file}")).$file] = $file;
                    }
                    ksort($sorted_files);
                    foreach ($sorted_files as $file) {
                        @unlink("./cache/{$file}");
                        $num_files -= 1;
                        if ($num_files < $cache_lo_water_mark) {
                            break;
                        }
                    }
                }
            }
            // save diff in cache
            $data_to_serialize = array(
                'granularity' => $granularity,
                'from_text' => $from_text,
                'diff_opcodes' => $diff_opcodes,
                'data_key' => $data_key,
                );
            $serialized_data = serialize($data_to_serialize);
            @file_put_contents("./cache/{$filename}", gzcompress($serialized_data));
            @chmod("./cache/{$filename}", 0666);
        }
    }
}

$rendered_diff = FineDiff::renderDiffToHTMLFromOpcodes($from_text, $diff_opcodes);
$from_len = strlen($from_text);
$to_len = strlen($to_text);

if (!empty($data_key)) {
    echo '<p style="margin-right:8em;font-size:smaller">Tempolink: <a href="viewdiff.php?data=', $data_key, '">http://', $_SERVER['HTTP_HOST'], '/viewdiff.php?data=', $data_key, '</a> <span style="color:#aaa">(This link is not viewable by others, unless it has been explicitly shared by the creator. This link will exist for a limited period of time, which depends on how often it is visited.)</span></p>', "\n";
}
?>
<div class="panecontainer" style="width:99%"><p>Diff <span style="color:gray">(diff: <?php printf('%.3f', $exec_time); ?> seconds, diff len: <?php echo $diff_opcodes_len; ?> chars)</span>&emsp;/&emsp;Show <input type="radio" name="htmldiffshow" onclick="setHTMLDiffVisibility('deletions');">Deletions only&ensp;<input type="radio" name="htmldiffshow" checked="checked" onclick="setHTMLDiffVisibility();">All&ensp;<input type="radio" name="htmldiffshow" onclick="setHTMLDiffVisibility('insertions');">Insertions only</p><div><div id="htmldiff" class="pane" style="white-space:pre-wrap"><?php
echo $rendered_diff; ?></div></div>
</div>
<form action="viewdiff.php" method="post">
<p style="margin:1em 0 0.5em 0">Enter text to diff below:</p>
<div class="panecontainer" style="display:inline-block;width:49.5%"><p>From</p><div><textarea name="from" class="pane"><?php echo htmlentities($from_text, ENT_QUOTES, 'UTF-8'); ?></textarea></div></div>
<div class="panecontainer" style="display:inline-block;width:49.5%"><p>To</p><div><textarea name="to" class="pane"><?php echo htmlentities($to_text, ENT_QUOTES, 'UTF-8'); ?></textarea></div></div>
<p id="params">Granularity:<input name="granularity" type="radio" value="0"<?php if ($granularity === 0) {
    echo ' checked="checked"';
} ?>>&thinsp;Paragraph/lines&ensp;<input name="granularity" type="radio" value="1"<?php if ($granularity === 1) {
    echo ' checked="checked"';
} ?>>&thinsp;Sentence&ensp;<input name="granularity" type="radio" value="2"<?php if ($granularity === 2) {
    echo ' checked="checked"';
} ?>>&thinsp;Word&ensp;<input name="granularity" type="radio" value="3"<?php if ($granularity === 3) {
    echo ' checked="checked"';
} ?>>&thinsp;Character&emsp;<input type="submit" value="View diff">&emsp;<a href="viewdiff.php"><button>Clear all</button></a></p>
</form>
<p style="margin-top:1em"><a href="viewdiff-ex.php">Go to main page</a></p>
<script type="text/javascript">
<!--
function setHTMLDiffVisibility(what) {
	var htmldiffEl = document.getElementById('htmldiff'),
		className = htmldiffEl.className;
	className = className.replace(/\bonly(Insertions|Deletions)\b/g, '').replace(/\s{2,}/g, ' ').replace(/\s+$/, '').replace(/^\s+/, '');
	if ( what === 'deletions' ) {
		htmldiffEl.className = className + ' onlyDeletions';
		}
	else if ( what === 'insertions' ) {
		htmldiffEl.className = className + ' onlyInsertions';
		}
	else {
		htmldiffEl.className = className;
		}
	}
// -->
</script>
</body>
</html>
