我正在尝试将一些 AIFF 音频文件放在 PHP 站点上的登录墙后面(即在 Web 根目录之外)。第一个挑战是并非所有浏览器都支持 AIFF,但这是意料之中的——请参阅http://www.jplayer.org/HTML5.Audio.Support/ 现在我正在使用 Safari 进行测试,因为它支持 AIFF。
我不明白为什么 Safari 会以不同的方式处理同一文件的 2 个版本。对于直接文件,它会提示播放器并且可以正常工作。对于流式文件,播放器不起作用。
正常的下载
以下是我直接下载文件时的标题(即,如果我暂时将文件放入 Web 根目录进行测试):
curl -v http://audio.app/Morse.aiff -o /dev/null
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 192.168.10.10...
* Connected to audio.app (192.168.10.10) port 80 (#0)
> GET /Morse.aiff HTTP/1.1
> Host: audio.app
> User-Agent: curl/7.49.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.8.0
< Date: Sun, 06 Nov 2016 03:19:03 GMT
< Content-Type: application/octet-stream
< Content-Length: 55530
< Last-Modified: Sat, 05 Nov 2016 21:51:02 GMT
< Connection: keep-alive
< ETag: "581e5446-d8ea"
< Accept-Ranges: bytes
<
{ [5537 bytes data]
100 55530 100 55530 0 0 8991k 0 --:--:-- --:--:-- --:--:-- 10.5M
* Connection #0 to host audio.app left intact
通过 PHP
以下是我通过 PHP 脚本(名为 source.php)流式传输文件时的标题:
curl -v http://audio.app/source.php?file=Morse.aiff -o /dev/null
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 192.168.10.10...
* Connected to audio.app (192.168.10.10) port 80 (#0)
> GET /source.php?file=Morse.aiff HTTP/1.1
> Host: audio.app
> User-Agent: curl/7.49.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.8.0
< Date: Sun, 06 Nov 2016 03:36:46 GMT
< Content-Type: application/octet-stream
< Content-Length: 55530
< Connection: keep-alive
< Last-Modified: Sat, 05 Nov 2016 21:51:02 GMT
< ETag: "581e5446T-d8eaO"
< Accept-Ranges: bytes
<
{ [8431 bytes data]
100 55530 100 55530 0 0 4915k 0 --:--:-- --:--:-- --:--:-- 5422k
* Connection #0 to host audio.app left intact
标头几乎相同——我能看出的唯一区别是它们的顺序和我的本地开发盒用于 ETag 值的散列算法。
这是我用来流式传输同一文件(位于 webroot 上方)的测试 PHP 脚本(名为 source.php):
// Adapted from http://php.net/manual/en/function.readfile.php
$filename = (isset($_GET['file'])) ? $_GET['file'] : null;
// <do sanitization here>
$file = dirname(dirname(__FILE__)).'/audio/' . $filename;
// Mimicking AIFF headers from curl headers (does not work!)
$content_length = filesize($file);
$last_modified = date("D, d M Y H:i:s", filemtime($filename)). ' GMT';
header("HTTP/1.1 200 OK");
header("Content-type: application/octet-stream");
header('Content-Length: ' . $content_length);
header('Last-Modified: ' .$last_modified);
// attempts to do the same thing as NGINX... md5_file() would probably work
$etag = sprintf("\"%xT-%xO\"", filemtime($filename), $content_length);
header("ETag: $etag"); // quoting it exactly
header("Accept-Ranges: bytes");
// Output the file
readfile($file);
预期的行为是浏览器会将两个版本视为相同。在我的示例 HTML 页面(改编自http://www.w3schools.com/html/html5_audio.asp)中,只有直接下载有效——通过 PHP 提供的文件版本无法播放。当我直接在浏览器中点击这两个文件时,也会发生相同的行为。
<!DOCTYPE html>
<html>
<body>
<h2>From Stream</h2>
<audio controls>
<source src="/source.php?file=Morse.aiff&breakcache=<?php print uniqid(); ?>" type="audio/x-aiff">
Your browser does not support the audio element.
</audio>
<hr/>
<h2>Direct Downloads</h2>
<audio controls>
<source src="/Morse.aiff" type="audio/x-aiff">
Your browser does not support the audio element.
</audio>
</body>
</html>
同样的方法也适用于播放 mp3(但标题略有不同)。有谁知道我在这里做错了什么,或者有谁知道为什么这种方法不适用于 AIFF?我还没有尝试使用另一种服务器端语言进行相同的测试,但我怀疑这不是 PHP 问题,并且与 AIFF 相关。任何人都可以阐明这一点吗?