【问题标题】:how to download mp4 file and hide url path using php如何使用 php 下载 mp4 文件并隐藏 url 路径
【发布时间】:2019-01-09 05:47:21
【问题描述】:

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

我有下载按钮所在的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 脚本文件必须以某种方式损坏。我尝试添加/删除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);

然而,这仍然不能正确下载。如果我在没有脚本的情况下直接下载文件,它可以正常工作。

【问题讨论】:

  • 仅供参考,如果您提供另一种下载文件的方式,“隐藏路径”将毫无用处。你想要的是dl-script.php 中的某种权限检查,它只允许用户下载一次文件。
  • 如果我提供另一种方式,你是什么意思?这是他们应该能够下载的唯一方式。我对右键单击的评论只是我为测试文件所做的事情。用户应该只使用提到的一个下载按钮。 @deceze
  • 是的,当然,但这不会“隐藏文件”。这只是获取文件的另一种方式。你能向特定的 URL 发出特定的请求,然后你会得到一个文件吗? → 是 → 没有“隐藏”。
  • 是的,但它不会将 url 暴露给不是“技术娴熟”的用户。大多数情况下——如果不是全部的话,我的用户也不会。我现在的问题和第一步是让文件正确下载。对于问题中提到的整个过程,您还有什么建议,并给出答案吗?
  • 我会尝试将下载的文件与原始文件进行比较,看看有什么区别。尤其是前几个字节可能不同,如果有的话。

标签: php download http-headers mp4


【解决方案1】:

脚本看起来不错。

根据 cmets,您似乎正在尝试从远程位置获取文件,函数 filesize 不起作用,您必须找到另一种获取文件大小的方法或干脆将其删除

获取文件大小的方法是通过标题

以下代码应该从$nameOld远程位置获取文件大小

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

get_headers() documentation

readfile() 支持远程文件位置,但allow_url_fopen php 配置应开启


为了让它工作,你必须找到相关的错误日志,如果错误报告是 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

【讨论】:

  • @Rich 用我运行的测试示例更新了我的答案,以验证代码是否有效。下载的文件处于可播放状态。
  • 我检查了两台服务器,并且两者的 allow_url_fopen 都设置为“开启”。我也复制粘贴了你的代码,下载的还是打不开。
  • @Rich 能不能让你的报错更冗长,然后你基本上可以看出是什么错误导致它失败了,否则只是猜测。如果您更改错误报告,则可以删除标头 Content-Type 或使用文本编辑器打开下载的文件以查看其内容(或只需检查 error.log)
  • 更冗长是什么意思?怎么会这样?我当前的错误日志没有显示任何相关的错误。打开文件会显示文件的文本/代码。
【解决方案2】:

服务器端 https 处理可能有问题吗?您是否尝试过向第二台服务器发送普通的 http 请求?

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

【讨论】:

    【解决方案3】:

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

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

    让它工作的关键是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);
    

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

    【讨论】:

    • 看来这种方法也是将文件保存在临时内存中。您确定这种方法在 I/O 性能方面更好吗?
    猜你喜欢
    • 1970-01-01
    • 2017-02-03
    • 2018-04-05
    • 1970-01-01
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    • 1970-01-01
    相关资源
    最近更新 更多