Удаляем символ BOM с файлов на сервере - PHP

Поиск UTF-8 BOM в текстовых файлах через PHP CLI: предварительный просмотр, ограниченный каталог, пропуск symlink и резерв перед изменением.

Содержание статьи

BOM в UTF-8 — три начальных байта EF BB BF. Удаление этой сигнатуры не исправляет неверную кодировку всего файла. BOM допустим в некоторых текстовых форматах, но в PHP до открывающего тега может привести к преждевременному выводу.

Старый скрипт перезаписывал все файлы сайта из браузера. Ниже используется PHP CLI, список текстовых расширений и предварительный просмотр. Работайте с локальной копией или остановите процессы, меняющие файлы; скрипт не размещается в публичной директории.

Файл remove-bom.php

<?php
if (PHP_SAPI !== 'cli') {
    http_response_code(403);
    exit('Только CLI');
}
$root = realpath($argv[1] ?? '');
if ($root === false || !is_dir($root)) {
    exit("Укажите существующий каталог\n");
}
$apply = ($argv[2] ?? '') === '--apply';
$prefix = rtrim($root, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
$allowed = ['php', 'css', 'js', 'json', 'html', 'htm', 'txt', 'md', 'xml'];
$iterator = new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS);
$filter = new RecursiveCallbackFilterIterator($iterator,
    static function (SplFileInfo $file): bool {
        if ($file->isLink()) return false;
        return !$file->isDir() || !in_array($file->getFilename(),
            ['.git', 'node_modules', 'vendor', 'backups'], true);
    }
);
foreach (new RecursiveIteratorIterator($filter) as $file) {
    if (!$file->isFile() || $file->isLink() || $file->getSize() > 10 * 1024 * 1024) continue;
    if (!in_array(strtolower($file->getExtension()), $allowed, true)) continue;
    $path = $file->getRealPath();
    if ($path === false || !str_starts_with($path, $prefix)) continue;
    $content = file_get_contents($path);
    if ($content === false) throw new RuntimeException('Ошибка чтения файла');
    if (!str_starts_with($content, "\xEF\xBB\xBF")) continue;
    if (preg_match('//u', $content) !== 1) continue;
    echo ($apply ? 'Исправление: ' : 'Найден BOM: ') . $path . PHP_EOL;
    if (!$apply) continue;
    $backup = $path . '.before-bom';
    $handle = fopen($backup, 'xb'); // существующий резерв не перезаписывается
    if ($handle === false) throw new RuntimeException('Не удалось создать резерв');
    $written = fwrite($handle, $content);
    fclose($handle);
    if ($written !== strlen($content)) throw new RuntimeException('Неполный резерв');
    $clean = substr($content, 3);
    if (file_put_contents($path, $clean, LOCK_EX) !== strlen($clean)) {
        throw new RuntimeException('Ошибка записи; восстановите файл из резерва');
    }
}

Запуск и проверка

php remove-bom.php /path/to/site-copy
php remove-bom.php /path/to/site-copy --apply

Проверенные источники

www.php.net, www.php.net. Проверено 10 октября 2026 года.

Все материалы раздела «Программирование»Каталог инструментов

Ещё в разделе «Программирование»