├── .github ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ ├── Feature_request.md │ └── Support_question.md ├── funding.yml ├── pull_request_template.md └── workflows │ ├── coding-style.yml │ └── main.yml ├── LICENSE ├── README.md ├── composer.json ├── doc ├── diff-to-html.png └── simple-diff.png ├── phpstan.neon └── src ├── Diff.php └── SimpleDiff.php /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "🐛 Bug Report" 3 | about: "If something isn't working as expected 🤔" 4 | 5 | --- 6 | 7 | Version: ?.?.? 8 | 9 | ### Bug Description 10 | ... A clear and concise description of what the bug is. A good bug report shouldn't leave others needing to chase you up for more information. 11 | 12 | ### Steps To Reproduce 13 | ... If possible a minimal demo of the problem ... 14 | 15 | ### Expected Behavior 16 | ... A clear and concise description of what you expected to happen. 17 | 18 | ### Possible Solution 19 | ... Only if you have suggestions on a fix for the bug 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "🚀 Feature Request" 3 | about: "I have a suggestion (and may want to implement it) 🙂" 4 | 5 | --- 6 | 7 | - Is your feature request related to a problem? Please describe. 8 | - Explain your intentions. 9 | - It's up to you to make a strong case to convince the project's developers of the merits of this feature. 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Support_question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "🤗 Support Question" 3 | about: "If you have a question 💬" 4 | 5 | --- 6 | 7 | --------------^ Click "Preview" for a nicer view! 8 | We primarily use GitHub as an issue tracker; for usage and support questions, please check out https://php.baraja.cz. Thanks! 😁. 9 | -------------------------------------------------------------------------------- /.github/funding.yml: -------------------------------------------------------------------------------- 1 | github: janbarasek 2 | custom: ["https://baraja.cz", "https://php.baraja.cz", "https://vue.baraja.cz"] 3 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | - bug fix / new feature? 2 | - BC break? yes/no 3 | 4 | 11 | -------------------------------------------------------------------------------- /.github/workflows/coding-style.yml: -------------------------------------------------------------------------------- 1 | name: Coding Style 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | nette_cc: 7 | name: Nette Code Checker 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: shivammathur/setup-php@v2 12 | with: 13 | php-version: 8.1 14 | coverage: none 15 | 16 | - run: composer create-project nette/code-checker temp/code-checker ^3 --no-progress 17 | - run: php temp/code-checker/code-checker --strict-types --no-progress 18 | 19 | nette_cs: 20 | name: Nette Coding Standard 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v2 24 | - uses: shivammathur/setup-php@v2 25 | with: 26 | php-version: 8.1 27 | coverage: none 28 | 29 | - run: composer create-project nette/coding-standard temp/coding-standard ^3 --no-progress --ignore-platform-reqs 30 | - run: php temp/coding-standard/ecs check src 31 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Integrity check 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | types: [ assigned, opened, synchronize, reopened ] 9 | schedule: 10 | - cron: '1 * * * *' 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@master 18 | 19 | - name: Install PHP 20 | uses: shivammathur/setup-php@master 21 | with: 22 | php-version: 8.1 23 | 24 | - name: Install composer deps 25 | run: | 26 | composer create-project nette/code-checker temp/code-checker ^3 --no-progress 27 | composer create-project nette/coding-standard temp/coding-standard ^3 --no-progress 28 | 29 | # Install app deps 30 | composer install --no-interaction --prefer-dist 31 | 32 | - name: The PHP Security Checker 33 | uses: symfonycorp/security-checker-action@v3 34 | 35 | - name: Check PHPStan rules 36 | run: composer phpstan 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Baraja packages 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Simple PHP diff 2 | =============== 3 | 4 | Find the quick difference between two text files in PHP. 5 | 6 | Idea 7 | ---- 8 | 9 | The library compares two text files very quickly and returns the object with the differences. 10 | 11 | The difference has numbered lines for easy display of changes to the user. You can also read an array of changed rows as an integer array from the `Diff` object as you browse for changes. 12 | 13 | 📦 Installation 14 | --------------- 15 | 16 | It's best to use [Composer](https://getcomposer.org) for installation, and you can also find the package on 17 | [Packagist](https://packagist.org/packages/baraja-core/simple-php-diff) and 18 | [GitHub](https://github.com/baraja-core/simple-php-diff). 19 | 20 | To install, simply use the command: 21 | 22 | ``` 23 | $ composer require baraja-core/simple-php-diff 24 | ``` 25 | 26 | You can use the package manually by creating an instance of the internal classes, or register a DIC extension to link the services directly to the Nette Framework. 27 | 28 | Example 29 | ------- 30 | 31 | ![Default theme](doc/simple-diff.png) 32 | 33 | Diff can be rendered to HTML (with native method `SimpleDiff::renderDiff($diff)`: 34 | 35 | ![Default theme](doc/diff-to-html.png) 36 | 37 | How to use 38 | ---------- 39 | 40 | Simply create a SimpleDiff instance and compare the two files: 41 | 42 | ```php 43 | $left = 'First text'; 44 | $right = 'Second text'; 45 | 46 | $diff = (new \Baraja\DiffGenerator\SimpleDiff)->compare($left, $right); 47 | 48 | // simple render diff 49 | echo '
'
50 |      . htmlspecialchars((string) $diff)
51 |      . '
'; 52 | ``` 53 | 54 | The `compare()` method returns a complete object `Diff` with the results of the comparison, from which you can get much more. 55 | 56 | For example, to get a list of changed rows: 57 | 58 | ```php 59 | echo 'Changed lines: '; 60 | echo implode(', ', $diff->getChangedLines()); 61 | ``` 62 | 63 | Display the Diff in HTML 64 | ------------------------ 65 | 66 | Very often we need to display the differences directly in the browser, for this the native method `renderDiff()` is suitable. 67 | 68 | ```php 69 | $left = 'First text'; 70 | $right = 'Second text'; 71 | 72 | $simpleDiff = new \Baraja\DiffGenerator\SimpleDiff; 73 | $diff = $simpleDiff->compare($left, $right); 74 | 75 | echo $simpleDiff->renderDiff($diff); 76 | ``` 77 | 78 | The method accepts Diff and returns valid treated HTML that can be displayed directly to the user. 79 | 80 | Comparison mode 81 | --------------- 82 | 83 | This tool supports strict and basic comparison modes (strict mode is disabled by default). 84 | Strict mode also allows you to compare changes in different line wrapping methods (for example, `"\n"` and so on). 85 | 86 | 87 | 📄 License 88 | ----------- 89 | 90 | `baraja-core/simple-php-diff` is licensed under the MIT license. See the [LICENSE](https://github.com/baraja-core/template/blob/master/LICENSE) file for more details. 91 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baraja-core/simple-php-diff", 3 | "description": "Find the quick difference between two text files in PHP.", 4 | "homepage": "https://github.com/baraja-core/simple-php-diff", 5 | "authors": [ 6 | { 7 | "name": "Jan Barášek", 8 | "homepage": "https://php.baraja.cz" 9 | } 10 | ], 11 | "require": { 12 | "php": "^8.0" 13 | }, 14 | "require-dev": { 15 | "phpstan/phpstan": "^1.0", 16 | "phpstan/extension-installer": "^1.1", 17 | "phpstan/phpstan-nette": "^1.0", 18 | "phpstan/phpstan-deprecation-rules": "^1.0", 19 | "phpstan/phpstan-strict-rules": "^1.0", 20 | "spaze/phpstan-disallowed-calls": "^2.0", 21 | "roave/security-advisories": "dev-master" 22 | }, 23 | "autoload": { 24 | "classmap": [ 25 | "src/" 26 | ] 27 | }, 28 | "scripts": { 29 | "phpstan": [ 30 | "vendor/bin/phpstan analyse src -c phpstan.neon --level 9 --no-progress" 31 | ] 32 | }, 33 | "minimum-stability": "stable", 34 | "config": { 35 | "allow-plugins": { 36 | "phpstan/extension-installer": true 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /doc/diff-to-html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baraja-core/simple-php-diff/612e9a1429fd820df7067cb2753b7d7561dab12e/doc/diff-to-html.png -------------------------------------------------------------------------------- /doc/simple-diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baraja-core/simple-php-diff/612e9a1429fd820df7067cb2753b7d7561dab12e/doc/simple-diff.png -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | includes: 2 | - vendor/spaze/phpstan-disallowed-calls/disallowed-dangerous-calls.neon 3 | - vendor/spaze/phpstan-disallowed-calls/disallowed-execution-calls.neon 4 | 5 | parameters: 6 | checkMissingIterableValueType: false 7 | -------------------------------------------------------------------------------- /src/Diff.php: -------------------------------------------------------------------------------- 1 | $changedLines 12 | */ 13 | public function __construct( 14 | private string $original, 15 | private string $target, 16 | private string $diff, 17 | private array $changedLines, 18 | ) { 19 | } 20 | 21 | 22 | public function __toString(): string 23 | { 24 | return $this->diff; 25 | } 26 | 27 | 28 | public function getOriginal(): string 29 | { 30 | return $this->original; 31 | } 32 | 33 | 34 | public function getTarget(): string 35 | { 36 | return $this->target; 37 | } 38 | 39 | 40 | public function getDiff(): string 41 | { 42 | return $this->diff; 43 | } 44 | 45 | 46 | /** 47 | * @return array 48 | */ 49 | public function getChangedLines(): array 50 | { 51 | return $this->changedLines; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/SimpleDiff.php: -------------------------------------------------------------------------------- 1 | prettyRender($original)); 40 | $captureBuffer['+'][] = sprintf('+ %d%s', $lineNumber, $this->prettyRender($target)); 41 | $changedLines[] = $i + 1; 42 | } 43 | } 44 | 45 | return new Diff($left, $right, implode("\n", $return), $changedLines); 46 | } 47 | 48 | 49 | public function renderDiff(Diff|string $diff): string 50 | { 51 | $return = []; 52 | foreach (explode("\n", is_string($diff) ? $diff : $diff->getDiff()) as $line) { 53 | if (($line[0] ?? '') === '+') { 54 | $return[] = sprintf('
%s
', htmlspecialchars($line)); 55 | } elseif (($line[0] ?? '') === '-') { 56 | $return[] = sprintf('
%s
', htmlspecialchars($line)); 57 | } else { 58 | $return[] = sprintf('
%s
', htmlspecialchars($line)); 59 | } 60 | } 61 | 62 | return sprintf('
%s
', implode("\n", $return)); 63 | } 64 | 65 | 66 | private function prettyRender(string $haystack): string 67 | { 68 | return str_replace(["\t", ' '], ['→→→→', '·'], $haystack); 69 | } 70 | } 71 | --------------------------------------------------------------------------------