<?php
/**
* BOM 掃描與移除工具
* 用法:
* php remove_bom.php [目錄路徑] [--fix]
* 或瀏覽器訪問 remove_bom.php?dir=./&auto=1
*/
$baseDir = $argv[1] ?? ($_GET['dir'] ?? __DIR__);
$autoFix = in_array('--fix', $argv) || isset($_GET['auto']);
if (!is_dir($baseDir)) {
die("目錄不存在: $baseDir\n");
}
echo "掃描目錄: $baseDir\n";
echo "自動修復: " . ($autoFix ? '啟用' : '僅檢測') . "\n";
echo str_repeat('-', 60) . "\n";
$count = 0;
$fixed = 0;
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($baseDir, FilesystemIterator::SKIP_DOTS)
);
foreach ($iterator as $file) {
if (!$file->isFile() || $file->getExtension() !== 'php') continue;
$path = $file->getPathname();
$content = file_get_contents($path);
if (strlen($content) >= 3 && substr($content, 0, 3) === "\xEF\xBB\xBF") {
$count++;
printf("[BOM] %s\n", $path);
if ($autoFix) {
$newContent = substr($content, 3);
$fp = fopen($path, 'cb');
if ($fp) {
if (flock($fp, LOCK_EX)) {
ftruncate($fp, 0);
fwrite($fp, $newContent);
flock($fp, LOCK_UN);
$fixed++;
echo " → 已移除\n";
} else {
echo " → 鎖定失敗,略過\n";
}
fclose($fp);
}
}
}
}
echo str_repeat('-', 60) . "\n";
echo "掃描完成: 發現 $count 個含 BOM 檔案";
if ($autoFix) echo ",已修復 $fixed 個";
echo "\n";
# 僅檢測
php remove_bom.php /var/www/html
# 自動移除
php remove_bom.php /var/www/html --fix
# 瀏覽器模式 (需注意權限)
# https://example.com/remove_bom.php?dir=/var/www/html&auto=1
// composer.json
{
"scripts": {
"check-bom": "php scripts/remove_bom.php src",
"fix-bom": "php scripts/remove_bom.php src --fix",
"pre-commit": [
"@check-bom"
]
}
}
搭配 `composer require --dev captainhook/captainhook` 於 `pre-commit` 鉤子自動檢查,徹底杜絕 BOM 進入版本庫。
原文摘自 2cto.com