Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Htmldiff Laravel Package

caxy/php-htmldiff

Compare two HTML snippets/files and generate a marked-up diff highlighting insertions, deletions, and changes. Easy Composer install, simple API (HtmlDiff->build()), configurable behavior and CSS-friendly output; includes a live demo and Symfony bundle option.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require caxy/php-htmldiff
    

    Add to composer.json if using Laravel’s require-dev for testing:

    "require-dev": {
        "caxy/php-htmldiff": "^0.1.14"
    }
    
  2. First Use Case: Compare two HTML strings (e.g., from a database or API response) and render differences in a Blade view:

    use Caxy\HtmlDiff\HtmlDiff;
    
    $oldHtml = '<p>Hello <strong>World</strong></p>';
    $newHtml = '<p>Hello <strong>PHP</strong></p>';
    
    $htmlDiff = new HtmlDiff($oldHtml, $newHtml);
    $diffHtml = $htmlDiff->build();
    

    Output the result in a Blade template:

    <div class="htmldiff">{{ $diffHtml }}</div>
    
  3. Styling: Include the demo CSS from the package’s demo/codes.css or use a minimal custom style:

    .htmldiff ins { background: #ddffdd; }
    .htmldiff del { background: #ffdddd; }
    

Implementation Patterns

Core Workflows

  1. Comparing Dynamic Content:

    • Database Records: Fetch old_version and new_version fields (e.g., CMS content, user profiles) and diff them:
      $oldContent = $post->old_content;
      $newContent = $post->new_content;
      $diff = (new HtmlDiff($oldContent, $newContent))->build();
      
    • API Responses: Compare JSON-rendered HTML (e.g., from a frontend framework):
      $oldResponse = response()->json(['html' => $oldHtml]);
      $newResponse = response()->json(['html' => $newHtml]);
      
  2. Reusable Configuration:

    • Create a config object for consistent diffing (e.g., for admin panels):
      $config = (new HtmlDiffConfig())
          ->setMatchThreshold(90)
          ->setGroupDiffs(true);
      
      $diff = HtmlDiff::create($oldHtml, $newHtml, $config)->build();
      
  3. Caching Diffs:

    • Cache results for performance (e.g., in a diff_cache table):
      $cacheKey = md5($oldHtml . $newHtml);
      if (cache()->has($cacheKey)) {
          $diff = cache()->get($cacheKey);
      } else {
          $diff = (new HtmlDiff($oldHtml, $newHtml))->build();
          cache()->put($cacheKey, $diff, now()->addHours(1));
      }
      
  4. Integration with Laravel Services:

    • Form Requests: Validate HTML changes before saving:
      public function rules() {
          return [
              'content' => 'required|htmldiff:' . $this->oldContent,
          ];
      }
      
      Create a custom validation rule:
      use Caxy\HtmlDiff\HtmlDiff;
      
      class HtmlDiffRule extends AbstractRule {
          public function passes($attribute, $value) {
              $diff = (new HtmlDiff($this->oldContent, $value))->build();
              return strpos($diff, '<del') === false; // No deletions allowed
          }
      }
      
  5. Table/List-Specific Diffs:

    • Enable table diffing for structured data:
      $config = (new HtmlDiffConfig())->setUseTableDiffing(true);
      $diff = HtmlDiff::create($oldTableHtml, $newTableHtml, $config)->build();
      

Advanced Patterns

  1. Diffing in Artisan Commands:

    • Audit changes in a batch process:
      public function handle() {
          $posts = Post::where('needs_review', true)->get();
          foreach ($posts as $post) {
              $diff = (new HtmlDiff($post->old_content, $post->new_content))->build();
              $this->info("Changes: " . substr($diff, 0, 50));
          }
      }
      
  2. Real-Time Diffing (Livewire/Alpine):

    • Use JavaScript to trigger diffs on input changes:
      document.getElementById('content').addEventListener('input', function() {
          fetch('/diff', {
              method: 'POST',
              body: JSON.stringify({
                  oldHtml: oldContent,
                  newHtml: this.value
              })
          }).then(response => response.text())
            .then(diff => document.getElementById('diff').innerHTML = diff);
      });
      
    • Laravel route:
      Route::post('/diff', function (Request $request) {
          return (new HtmlDiff($request->oldHtml, $request->newHtml))->build();
      });
      
  3. Diffing Markdown/Converted HTML:

    • Use a package like spatie/laravel-markdown to convert Markdown to HTML before diffing:
      $oldMarkdown = "# Old Title";
      $newMarkdown = "# New Title";
      $oldHtml = Markdown::parse($oldMarkdown);
      $newHtml = Markdown::parse($newMarkdown);
      $diff = (new HtmlDiff($oldHtml, $newHtml))->build();
      

Gotchas and Tips

Pitfalls

  1. HTML Purifier Dependencies:

    • The package requires ezyang/htmlpurifier for sanitization. If disabled (setPurifierEnabled(false)), unsanitized input may break diffing:
      $config = (new HtmlDiffConfig())->setPurifierEnabled(false);
      // Risk: Malformed HTML may cause errors or incorrect diffs.
      
  2. Performance with Large HTML:

    • Complex tables/lists may slow down diffing. Use setMatchThreshold(70) to balance accuracy/speed:
      $config = (new HtmlDiffConfig())->setMatchThreshold(70);
      
  3. Newlines Handling:

    • Pre-tags (<pre>) may lose formatting if setKeepNewLines(false) (default). Enable for code blocks:
      $config = (new HtmlDiffConfig())->setKeepNewLines(true);
      
  4. Self-Closing Tags:

    • Tags like <img/> or <br/> may cause issues. Ensure proper HTML structure before diffing.
  5. Unicode/Encoding:

    • Default encoding is UTF-8. For non-UTF-8 content (e.g., legacy systems), set explicitly:
      $config = (new HtmlDiffConfig())->setEncoding('ISO-8859-1');
      

Debugging Tips

  1. Inspect Raw Diff Output:

    • Log the raw diff HTML to debug unexpected results:
      $diff = (new HtmlDiff($oldHtml, $newHtml))->build();
      Log::debug('Diff HTML:', ['diff' => $diff]);
      
  2. Test with Minimal HTML:

    • Isolate issues by diffing simple strings first:
      $diff = (new HtmlDiff('<p>Hello</p>', '<p>Hi</p>'))->build();
      
  3. Check for Malformed HTML:

    • Use htmlspecialchars() to validate input before diffing:
      $oldHtml = htmlspecialchars_decode($oldHtml);
      $newHtml = htmlspecialchars_decode($newHtml);
      
  4. Cache Provider Issues:

    • If using Doctrine Cache, ensure the cache directory is writable:
      $config = (new HtmlDiffConfig())->setCacheProvider($cacheProvider);
      

Extension Points

  1. Custom Diff Styling:

    • Override CSS classes in the diff output:
      .htmldiff ins { border-bottom: 2px solid green; }
      .htmldiff del { border-bottom: 2px solid red; }
      
  2. Post-Processing Diffs:

    • Modify the diff HTML after generation (e.g., add tooltips):
      $diff = (new HtmlDiff($oldHtml, $newHtml))->build();
      $diff = str_replace(
          '<ins>',
          '<ins title="Added in this version">',
          $diff
      );
      
  3. Integrate with Laravel Notifications:

    • Send diffs as email notifications:
      Notification::send($user, new HtmlDiffNotification($diffHtml));
      
      Custom notification:
      class HtmlDiffNotification extends Notification {
          public function toMail($notifiable) {
              return (new MailMessage)
                  ->subject('HTML Changes')
                  ->line('The following changes were detected:')
                  ->line($this->diffHtml);
          }
      }
      
  4. Extend for Custom Tags:

    • While setIsolatedDiffTags() is deprecated, you can manually wrap tags before diffing:
      $oldHtml = preg_replace('/<script>(
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours