最稳妥方案是用 uniqid('', true) 生成微秒级唯一字符串并截取后6–8位,结合 pathinfo($filename, PATHINFO_EXTENSION) 安全提取小写扩展名,禁用不可信的 $_FILES'audio' 和 file_exists() 轮询。

直接用 time() + uniqid() 组合最稳妥
音频文件(如 .mp3、.wav、.ogg)本身不带业务标识,靠原始名毫无区分度,且并发上传时 time() 秒级精度极易撞名。必须用微秒级唯一性组合:uniqid('', true) 返回带熵的字符串(如 65a1f2b3c4d5e6.78901234),再截取后 6–8 位,比纯时间戳或 rand() 更可靠。
别用 microtime(true) 直接拼字符串——浮点转字符串可能含小数点或科学计数法,导致非法文件名。
pathinfo() 提取扩展名必须用 PATHINFO_EXTENSION
用户传 song.php.mp3 或 ../../config.ini.wav 很常见,不能直接信任 $_FILES['audio']['name'] 里的后缀。必须用 pathinfo($filename, PATHINFO_EXTENSION) 安全提取,且强制转小写:strtolower()。否则 Windows 下 .MP3 和 .mp3 可能被当成不同扩展名,绕过白名单校验。
避免用 MIME 类型生成文件名
$_FILES['audio']['type'] 是客户端传的,不可信。值可能是 audio/mpeg、audio/x-wav,甚至空或伪造的 text/plain。若拼进文件名(如 user-audio/mpeg-170826.mp3),斜杠 / 会导致 move_uploaded_file() 报 No such file or directory 错误——这不是权限问题,是路径非法。真正需要语义化时,只取主类型:$main_type = explode('/', $_FILES['audio']['type'])[0] ?? 'audio',但更推荐完全弃用它。
高并发场景下别依赖 file_exists() 轮询重试
用“原名 + 计数器”方案(如 song_1.mp3 → song_2.mp3)在并发请求下存在竞态:两个请求同时判断 file_exists('song.mp3') 为 false,然后都写入 song.mp3,最终一个覆盖另一个。这不是理论风险,压测时很容易复现。唯一解是命名即唯一——用 uniqid()、md5_file() 或数据库自增 ID + 时间戳组合,不查盘、不轮询。
立即学习“PHP免费学习笔记(深入)”;
真正麻烦的是音频文件体积大、上传慢,move_uploaded_file() 前若不做 is_uploaded_file() 校验,可能把临时文件残留或恶意伪造路径当真文件处理。这点常被忽略。



















