You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP音频文件损坏检测函数失效:损坏文件被误判为正常

修复音频文件损坏检测的PHP函数

你的函数当前只验证了MP3文件ID3标签的基本格式,完全没有检查实际的音频数据部分——这就是损坏文件仍返回true的核心原因。比如:

  • 仅包含完整ID3头、但后续音频数据被截断/篡改的文件,会被判定为有效;
  • 不带ID3头的MP3、WAV/AAC等其他格式的损坏文件,函数会直接跳过检查返回true。

改进方案

方案1:纯PHP解析(针对MP3基础验证)

这个版本会跳过ID3标签,直接检查音频帧的有效性(MP3帧以同步字0xFFE/0xFFF开头),同时验证文件完整性:

function checkAudio($filename) {
    if (!file_exists($filename) || !is_readable($filename)) {
        return false;
    }

    $fileSize = filesize($filename);
    $handle = fopen($filename, 'rb');
    if (!$handle) {
        return false;
    }

    $offset = 0;
    // 跳过ID3标签(如果存在)
    $header = fread($handle, 10);
    if (strpos($header, 'ID3') === 0) {
        // 计算ID3标签总大小(含头10字节)
        $tagSize = (ord($header[6]) & 0x7F) << 21 |
                   (ord($header[7]) & 0x7F) << 14 |
                   (ord($header[8]) & 0x7F) << 7 |
                   (ord($header[9]) & 0x7F);
        $offset = 10 + $tagSize;
        
        // 检查标签大小是否超出文件范围(防止伪造标签)
        if ($offset > $fileSize) {
            fclose($handle);
            return false;
        }
        fseek($handle, $offset);
    }

    // 读取后续内容,检查是否存在有效MP3帧
    $foundValidFrame = false;
    // 最多检查10KB内容,避免读取大文件耗时
    $maxCheckBytes = 10240;
    $remaining = min($fileSize - $offset, $maxCheckBytes);
    
    while ($remaining > 4) {
        $bytes = fread($handle, 4);
        if (strlen($bytes) < 4) {
            break;
        }
        
        // 检查MP3同步字:前11位必须是1(0xFFE00000的掩码)
        $sync = (ord($bytes[0]) << 16) | (ord($bytes[1]) << 8) | ord($bytes[2]);
        if (($sync & 0xFFE000) === 0xFFE000) {
            $foundValidFrame = true;
            break;
        }
        
        $remaining -= 1;
        fseek($handle, -3, SEEK_CUR); // 回退3字节,避免漏检帧
    }

    fclose($handle);
    
    // 至少找到一个有效帧,且文件大小合理
    return $foundValidFrame && ($fileSize > $offset);
}

方案2:调用专业工具(推荐,支持全格式)

纯PHP解析所有音频格式的成本极高且易出错。如果服务器允许执行系统命令,用ffprobe(FFmpeg套件的一部分)是最可靠的方式——它会完整分析音频流的有效性:

function checkAudio($filename) {
    if (!file_exists($filename) || !is_readable($filename)) {
        return false;
    }

    // 构造ffprobe命令,禁止输出冗余信息,只检查流有效性
    $cmd = sprintf(
        'ffprobe -v error -show_streams "%s" > /dev/null 2>&1',
        escapeshellarg($filename)
    );
    
    // 执行命令,返回码为0表示文件有效
    exec($cmd, $output, $returnCode);
    return $returnCode === 0;
}

关键说明

  • 方案1仅针对MP3,适合无法调用外部工具的场景,但仍无法覆盖所有损坏情况(比如帧数据错误但同步字正常);
  • 方案2支持MP3、WAV、AAC、FLAC等几乎所有音频格式,准确性远高于纯PHP解析,是生产环境的首选;
  • 无论哪种方案,都要先检查文件是否存在、是否可读,避免基础错误。

内容的提问来源于stack exchange,提问作者Tarika Lalwani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 23:32:07