option('dry-run'); $fixed = 0; Entry::withTrashed() ->withoutGlobalScopes() ->chunkById(100, function ($entries) use (&$fixed, $dryRun) { foreach ($entries as $entry) { $original = $entry->description; if ($original === null || $original === '') { continue; } $decoded = $original; for ($i = 0; $i < 20; $i++) { $next = html_entity_decode($decoded, ENT_QUOTES | ENT_HTML5); if ($next === $decoded) { break; } $decoded = $next; } $decoded = stripslashes($decoded); if ($decoded !== $original) { $fixed++; $this->line("Entry #{$entry->id}: " . $this->preview($original) . ' => ' . $this->preview($decoded)); if (!$dryRun) { $entry->description = $decoded; $entry->saveQuietly(); } } } }); $this->info(($dryRun ? '[DRY RUN] ' : '') . "{$fixed} entries fixed.)."); return self::SUCCESS; } private function preview(string $text, int $len = 60): string { $text = str_replace(["\n", "\r"], ' ', $text); return mb_strlen($text) > $len ? mb_substr($text, 0, $len) . '...' : $text; } }