gluon-web-remote

Web remote Administration for big size of gluon routers
git clone git://archive.git.mtrnord.blog/MTRNord/gluon-web-remote.git
Log | Files | Refs | README

Differ.php (7189B)


      1 <?php
      2 /*
      3  * This file is part of the Diff package.
      4  *
      5  * (c) Sebastian Bergmann <sebastian@phpunit.de>
      6  *
      7  * For the full copyright and license information, please view the LICENSE
      8  * file that was distributed with this source code.
      9  */
     10 
     11 namespace SebastianBergmann\Diff;
     12 
     13 use SebastianBergmann\Diff\LCS\LongestCommonSubsequence;
     14 use SebastianBergmann\Diff\LCS\TimeEfficientImplementation;
     15 use SebastianBergmann\Diff\LCS\MemoryEfficientImplementation;
     16 
     17 /**
     18  * Diff implementation.
     19  *
     20  * @package    Diff
     21  * @author     Sebastian Bergmann <sebastian@phpunit.de>
     22  * @author     Kore Nordmann <mail@kore-nordmann.de>
     23  * @copyright  Sebastian Bergmann <sebastian@phpunit.de>
     24  * @license    http://www.opensource.org/licenses/BSD-3-Clause  The BSD 3-Clause License
     25  * @link       http://www.github.com/sebastianbergmann/diff
     26  */
     27 class Differ
     28 {
     29     /**
     30      * @var string
     31      */
     32     private $header;
     33 
     34     /**
     35      * @param string $header
     36      */
     37     public function __construct($header = "--- Original\n+++ New\n")
     38     {
     39         $this->header = $header;
     40     }
     41 
     42     /**
     43      * Returns the diff between two arrays or strings as string.
     44      *
     45      * @param  array|string             $from
     46      * @param  array|string             $to
     47      * @param  LongestCommonSubsequence $lcs
     48      * @return string
     49      */
     50     public function diff($from, $to, LongestCommonSubsequence $lcs = null)
     51     {
     52         if (!is_array($from) && !is_string($from)) {
     53             $from = (string) $from;
     54         }
     55 
     56         if (!is_array($to) && !is_string($to)) {
     57             $to = (string) $to;
     58         }
     59 
     60         $buffer = $this->header;
     61         $diff   = $this->diffToArray($from, $to, $lcs);
     62 
     63         $inOld = false;
     64         $i     = 0;
     65         $old   = array();
     66 
     67         foreach ($diff as $line) {
     68             if ($line[1] ===  0 /* OLD */) {
     69                 if ($inOld === false) {
     70                     $inOld = $i;
     71                 }
     72             } elseif ($inOld !== false) {
     73                 if (($i - $inOld) > 5) {
     74                     $old[$inOld] = $i - 1;
     75                 }
     76 
     77                 $inOld = false;
     78             }
     79 
     80             ++$i;
     81         }
     82 
     83         $start = isset($old[0]) ? $old[0] : 0;
     84         $end   = count($diff);
     85 
     86         if ($tmp = array_search($end, $old)) {
     87             $end = $tmp;
     88         }
     89 
     90         $newChunk = true;
     91 
     92         for ($i = $start; $i < $end; $i++) {
     93             if (isset($old[$i])) {
     94                 $buffer  .= "\n";
     95                 $newChunk = true;
     96                 $i        = $old[$i];
     97             }
     98 
     99             if ($newChunk) {
    100                 $buffer  .= "@@ @@\n";
    101                 $newChunk = false;
    102             }
    103 
    104             if ($diff[$i][1] === 1 /* ADDED */) {
    105                 $buffer .= '+' . $diff[$i][0] . "\n";
    106             } elseif ($diff[$i][1] === 2 /* REMOVED */) {
    107                 $buffer .= '-' . $diff[$i][0] . "\n";
    108             } else {
    109                 $buffer .= ' ' . $diff[$i][0] . "\n";
    110             }
    111         }
    112 
    113         return $buffer;
    114     }
    115 
    116     /**
    117      * Returns the diff between two arrays or strings as array.
    118      *
    119      * Each array element contains two elements:
    120      *   - [0] => string $token
    121      *   - [1] => 2|1|0
    122      *
    123      * - 2: REMOVED: $token was removed from $from
    124      * - 1: ADDED: $token was added to $from
    125      * - 0: OLD: $token is not changed in $to
    126      *
    127      * @param  array|string             $from
    128      * @param  array|string             $to
    129      * @param  LongestCommonSubsequence $lcs
    130      * @return array
    131      */
    132     public function diffToArray($from, $to, LongestCommonSubsequence $lcs = null)
    133     {
    134         preg_match_all('(\r\n|\r|\n)', $from, $fromMatches);
    135         preg_match_all('(\r\n|\r|\n)', $to, $toMatches);
    136 
    137         if (is_string($from)) {
    138             $from = preg_split('(\r\n|\r|\n)', $from);
    139         }
    140 
    141         if (is_string($to)) {
    142             $to = preg_split('(\r\n|\r|\n)', $to);
    143         }
    144 
    145         $start      = array();
    146         $end        = array();
    147         $fromLength = count($from);
    148         $toLength   = count($to);
    149         $length     = min($fromLength, $toLength);
    150 
    151         for ($i = 0; $i < $length; ++$i) {
    152             if ($from[$i] === $to[$i]) {
    153                 $start[] = $from[$i];
    154                 unset($from[$i], $to[$i]);
    155             } else {
    156                 break;
    157             }
    158         }
    159 
    160         $length -= $i;
    161 
    162         for ($i = 1; $i < $length; ++$i) {
    163             if ($from[$fromLength - $i] === $to[$toLength - $i]) {
    164                 array_unshift($end, $from[$fromLength - $i]);
    165                 unset($from[$fromLength - $i], $to[$toLength - $i]);
    166             } else {
    167                 break;
    168             }
    169         }
    170 
    171         if ($lcs === null) {
    172             $lcs = $this->selectLcsImplementation($from, $to);
    173         }
    174 
    175         $common = $lcs->calculate(array_values($from), array_values($to));
    176         $diff   = array();
    177 
    178         if (isset($fromMatches[0]) && $toMatches[0] &&
    179             count($fromMatches[0]) === count($toMatches[0]) &&
    180             $fromMatches[0] !== $toMatches[0]) {
    181             $diff[] = array(
    182               '#Warning: Strings contain different line endings!', 0
    183             );
    184         }
    185 
    186         foreach ($start as $token) {
    187             $diff[] = array($token, 0 /* OLD */);
    188         }
    189 
    190         reset($from);
    191         reset($to);
    192 
    193         foreach ($common as $token) {
    194             while ((($fromToken = reset($from)) !== $token)) {
    195                 $diff[] = array(array_shift($from), 2 /* REMOVED */);
    196             }
    197 
    198             while ((($toToken = reset($to)) !== $token)) {
    199                 $diff[] = array(array_shift($to), 1 /* ADDED */);
    200             }
    201 
    202             $diff[] = array($token, 0 /* OLD */);
    203 
    204             array_shift($from);
    205             array_shift($to);
    206         }
    207 
    208         while (($token = array_shift($from)) !== null) {
    209             $diff[] = array($token, 2 /* REMOVED */);
    210         }
    211 
    212         while (($token = array_shift($to)) !== null) {
    213             $diff[] = array($token, 1 /* ADDED */);
    214         }
    215 
    216         foreach ($end as $token) {
    217             $diff[] = array($token, 0 /* OLD */);
    218         }
    219 
    220         return $diff;
    221     }
    222 
    223     /**
    224      * @param  array $from
    225      * @param  array $to
    226      * @return LongestCommonSubsequence
    227      */
    228     private function selectLcsImplementation(array $from, array $to)
    229     {
    230         // We do not want to use the time-efficient implementation if its memory
    231         // footprint will probably exceed this value. Note that the footprint
    232         // calculation is only an estimation for the matrix and the LCS method
    233         // will typically allocate a bit more memory than this.
    234         $memoryLimit = 100 * 1024 * 1024;
    235 
    236         if ($this->calculateEstimatedFootprint($from, $to) > $memoryLimit) {
    237             return new MemoryEfficientImplementation;
    238         }
    239 
    240         return new TimeEfficientImplementation;
    241     }
    242 
    243     /**
    244      * Calculates the estimated memory footprint for the DP-based method.
    245      *
    246      * @param  array $from
    247      * @param  array $to
    248      * @return integer
    249      */
    250     private function calculateEstimatedFootprint(array $from, array $to)
    251     {
    252         $itemSize = PHP_INT_SIZE == 4 ? 76 : 144;
    253 
    254         return $itemSize * pow(min(count($from), count($to)), 2);
    255     }
    256 }