如何下载 mp4 文件并使用 php 隐藏 url 路径

how to download mp4 file and hide url path using php

我有一个网站,用户必须付费才能下载他们在该网站上创建的视频。因此,我需要隐藏下载路径。

我有 php 页面,下载按钮是 -

<form id="dl_script_form" action="dl-script.php" method="post" target="_blank">
<input name="userID" type="hidden" value="<?php echo $user->ID;?>" />
<input name="videosID" type="hidden" value="<?php echo $vId; ?>" />
<input name="downloadvids" id="downloadvids" type="submit" value="Download"/>
</form>

和dl-script.php --

require_once $_SERVER['DOCUMENT_ROOT'] . '/wp-load.php';

global $post;
$userid = $_POST['userID'];
$videosid = $_POST['videosID'];

$nameOld = '/path/to/'.$userid.'/'.$videosid.'/'.$videosid.'.mp4';
$nameNew = "download.mp4";
header('Content-type: video/mp4');
header("Content-disposition: attachment; filename=$nameNew");
header("Content-Length: ".filesize($nameOld));
readfile($nameOld);
exit(); 

当尝试点击提交时,开始下载(文件名为 download.mp4)但是当我尝试在 windows 媒体播放器中打开 mp4 时,它告诉我 -

Windows Media Player cannot play the file. The Player might not support the file type or might not support the codec that was used to compress the file.

我已经检查了文件路径并且能够在我的浏览器中播放视频或右键单击下载没有问题。

所以对于 php 脚本,文件一定是被破坏了。我尝试了 adding/removing header content-*file_get_contents,但仍然没有成功。

我做错了什么?

编辑

出于测试目的,我修改了代码以从我的第二个服务器下载到我所在的原始服务器,运行 脚本来自该服务器。

$userid = $_POST['userID'];
$videosid = $_POST['videosID'];

$path = 'https://path/to/'.$userid.'/'.$videosid.'/'.$videosid.'.mp4';
$save = '/var/path/to/'.$userid.'/'.$videosid.'/'.$videosid.'.mp4';

file_put_contents($save, fopen($path, 'r'));

$nameNew = "download.mp4";

header('Content-type: video/mp4');
header("Content-disposition: attachment; filename=$nameNew");
header("Content-Length: ".filesize($save));
readfile($save);

然而,这仍然没有正确下载。如果我没有脚本直接下载文件,它工作正常。

脚本看起来不错。

根据评论,您似乎正试图从远程位置获取文件,函数 filesize 不起作用,您必须找到另一种获取文件大小或简单地删除它的方法

一种获取文件大小的方法是通过 headers

以下代码应该从 $nameOld 远程位置

获取文件大小
$headers= get_headers($nameOld, 1);
$filesize = $headers['Content-Length'];

get_headers() documentation

readfile() 支持远程文件位置,但是 allow_url_fopen php 配置应该是 On


为了让它工作,你必须找到相关的错误日志,如果错误报告是 error_reporting=E_ALL 那么你下载的文件包含错误,所以如果你在文本编辑器中打开它你将能够看到错误,否则在你的 error.log 中搜索,有很大的变化 allow_url_fopen 没有正确配置,但找到错误将帮助你解决问题。


编辑:

我已经测试了你的代码,可以从远程位置下载示例 mp4

$nameOld = 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_2mb.mp4';
$nameNew = "download.mp4";

$headers= get_headers($nameOld, 1);
$filesize = $headers['Content-Length'];

header('Content-type: video/mp4');
header("Content-disposition: attachment; filename=$nameNew");
header("Content-Length: ".$filesize);

readfile($nameOld);

如果这对您不起作用,那么问题出在您的服务器设置上,可能是我之前提到的 allow_url_fopen

会不会是服务器端 https 处理有问题?您是否尝试过对第二台服务器的纯 http 请求?

您是否考虑过使用安全网址?这有助于减少服务器上的网络和 cpu 负载。 您可以为用户提供临时的 link,而不是隐藏真实的 URL,这仅适用于他的 IP(并在一段时间后过期)。这是大多数管网站所做的。 检查这个:http://nginx.org/en/docs/http/ngx_http_secure_link_module.html

我无法使用此处的任何建议让它工作,但在继续深入挖掘之后,我能够让它工作。

唯一的问题是我必须将文件从我的第二台服务器保存到我的第一台服务器,才能进行下载。然后我将其删除,但我很确定这在性能方面效率不高。但是,我没有尝试任何其他工作。

让它发挥作用的关键是ob_start(), while (ob_get_level()) { ob_end_clean(); }

完整代码 -

ob_start();

$userid = $_POST['userID'];
$videosid = $_POST['videosID'];

$nameOld = 'https://path/to/get/'.$userid.'/'.$videosid.'/'.$videosid.'.mp4';
$save = '/path/to/save/it/'.$userid.'/'.$videosid.'/'.$videosid.'.mp4';

$nameNew = "download.mp4";

file_put_contents($save, fopen($nameOld, 'r'));

set_time_limit(0);

header('Connection: Keep-Alive');
header('Content-Description: File Transfer');
header('Content-Type: application/force-download');
header("Content-Disposition: attachment; filename=$nameNew");
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($save));

      while (ob_get_level()) {
        ob_end_clean();
      }

readfile($save);
exit;

// delete file when done
unlink($save);

如果有人可以提出更有效的代码示例,请继续。