PHP获取WAV与MP3文件时长问题求助:MP3无返回结果
解决WAV/MP3时长获取问题:MP3无返回的修复方案
你的问题很明确:当前函数只针对WAV格式做了处理,完全没考虑MP3的解析逻辑,所以调用它处理MP3时自然没有返回结果。我帮你修改并扩展了函数,同时提供两种方案供你选择:原生PHP解析,或者用更可靠的第三方库。
方案一:原生PHP扩展函数(支持WAV+MP3)
这个方案不需要额外依赖,直接扩展你原有的函数,添加MP3解析逻辑:
function audioDur($file) { $fp = fopen($file, 'r'); if (!$fp) { return ''; // 文件打开失败返回空值 } // 处理WAV文件(保留你原有的正确逻辑) $header = fread($fp, 4); if ($header == 'RIFF') { fseek($fp, 20); $rawheader = fread($fp, 16); $header = unpack('vtype/vchannels/Vsamplerate/Vbytespersec/valignment/vbits', $rawheader); $pos = ftell($fp); while (fread($fp,4) != 'data' && !feof($fp)) { $pos++; fseek($fp, $pos); } $rawheader = fread($fp, 4); $data = unpack('Vdatasize', $rawheader); $sec = $data['datasize'] / $header['bytespersec']; $minutes = intval(($sec / 60) % 60); $seconds = intval($sec % 60); fclose($fp); return str_pad($minutes, 2, '0', STR_PAD_LEFT) . ':' . str_pad($seconds, 2, '0', STR_PAD_LEFT); } // 新增:处理MP3文件 elseif ($header == 'ID3' || strpos($header, "\xFF") !== false) { // 跳过ID3标签(如果存在) if ($header == 'ID3') { fseek($fp, 6); $rawSize = fread($fp, 4); // ID3标签大小是同步安全整数,需要转换 $size = (ord($rawSize[0]) & 0x7F) << 21 | (ord($rawSize[1]) & 0x7F) << 14 | (ord($rawSize[2]) & 0x7F) << 7 | ord($rawSize[3]) & 0x7F; fseek($fp, 10 + $size); } $frames = 0; $samplerate = 0; while (!feof($fp)) { $byte = fread($fp, 1); // 寻找MP3帧头标识(0xFF开头,且后续字节符合帧头规则) if (ord($byte) == 0xFF) { $nextByte = fread($fp, 1); if ((ord($nextByte) & 0xE0) == 0xE0) { $frameHeader = $byte . $nextByte . fread($fp, 2); $version = (ord($frameHeader[1]) & 0x18) >> 3; $samplerateIndex = (ord($frameHeader[2]) & 0x0C) >> 2; // 根据MP3版本获取采样率 $samplerates = [ [44100, 48000, 32000], // MPEG 2.5 [0, 0, 0], // 保留值 [22050, 24000, 16000], // MPEG 2 [44100, 48000, 32000] // MPEG 1 ]; $versionIndex = $version == 0 ? 0 : ($version == 2 ? 2 : 3); $samplerate = $samplerates[$versionIndex][$samplerateIndex]; if ($samplerate == 0) continue; // 计算当前帧长度,跳过帧内容 $bitrateIndex = (ord($frameHeader[2]) & 0xF0) >> 4; $bitrates = [ [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320], // MPEG1 [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160] // MPEG2/2.5 ]; $bitrateTableIndex = $versionIndex == 3 ? 0 : 1; $bitrate = $bitrates[$bitrateTableIndex][$bitrateIndex] * 1000; if ($bitrate == 0) continue; $padding = (ord($frameHeader[2]) & 0x02) >> 1; $frameLength = (144 * $bitrate) / $samplerate + $padding; $frames++; // 跳过当前帧剩余内容 fseek($fp, ftell($fp) + $frameLength - 4); } } } // 计算总时长 if ($frames > 0 && $samplerate > 0) { $samplesPerFrame = 1152; // MP3 Layer III每帧采样数 $totalSamples = $frames * $samplesPerFrame; $sec = $totalSamples / $samplerate; $minutes = intval(($sec / 60) % 60); $seconds = intval($sec % 60); fclose($fp); return str_pad($minutes, 2, '0', STR_PAD_LEFT) . ':' . str_pad($seconds, 2, '0', STR_PAD_LEFT); } else { fclose($fp); return ''; } } else { fclose($fp); return ''; // 不支持的格式 } } // 调用方式(和你原来的逻辑一致) $file = "your-audio-file.mp3"; // 替换成你的文件路径 if (preg_match('/[.](wav|WAV|mp3|MP3)$/', $file)) { $dur = audioDur($file); } else { $dur = ''; } echo $dur;
关键修改点:
- 函数重命名为
audioDur,明确支持两种格式 - 新增MP3解析逻辑:处理ID3标签、识别MP3帧头、计算总帧数和时长
- 增加了文件打开失败的容错处理
- 完善了文件资源释放,避免内存泄漏
方案二:使用getID3库(更可靠的生产环境方案)
原生解析MP3容易遇到边缘情况(比如VBR编码、特殊标签的MP3),如果你的项目需要更高的兼容性,推荐使用getID3这个专门处理音频元数据的PHP库:
- 先下载getID3库文件,解压到你的项目目录
- 使用以下代码:
require_once('getid3/getid3.php'); // 替换成你的getID3路径 function audioDur($file) { $getID3 = new getID3(); $audioInfo = $getID3->analyze($file); // 检查是否成功获取时长 if (isset($audioInfo['playtime_seconds'])) { $totalSeconds = $audioInfo['playtime_seconds']; $minutes = intval(($totalSeconds / 60) % 60); $seconds = intval($totalSeconds % 60); return str_pad($minutes, 2, '0', STR_PAD_LEFT) . ':' . str_pad($seconds, 2, '0', STR_PAD_LEFT); } return ''; // 无法获取时长时返回空 } // 调用方式不变 $file = "your-audio-file.mp3"; if (preg_match('/[.](wav|WAV|mp3|MP3)$/', $file)) { $dur = audioDur($file); } else { $dur = ''; } echo $dur;
优势:
- 无需自己处理复杂的格式解析逻辑
- 支持几乎所有常见音频格式(不只是WAV和MP3)
- 兼容性更好,能处理各种特殊编码的音频文件
内容的提问来源于stack exchange,提问作者medk
相关产品推荐
相关产品推荐

