13

我正在写一个防盗链下载脚本,我的计划是创建一个临时文件,以session ID命名,然后在session过期后,该文件会被自动删除。可能吗 ?你能给我一些提示如何在 PHP 中做到这一点吗?

非常感谢您的回复

4

7 回答 7

12

PHP 有一个名称为tmpfile的函数。它创建一个临时文件并返回一个资源。该资源可以像任何其他资源一样使用。

例如手册中的示例:

<?php
$temp = tmpfile();
fwrite($temp, "writing to tempfile");
fseek($temp, 0);
echo fread($temp, 1024);
fclose($temp); // this removes the file
?>

该文件在关闭(使用 fclose())或脚本结束时自动删除。您可以在资源上使用任何文件函数。你可以在这里找到这些。希望对你有帮助?

另一种解决方案是以常规方式创建文件并使用 cronjob 定期检查会话是否已过期。到期日期和其他会话数据可以存储在数据库中。使用脚本查询该数据并确定会话是否已过期。如果是这样,请将其从磁盘中物理删除。确保每小时运行一次脚本(取决于您的超时时间)。

于 2009-11-22T16:41:52.487 回答
10

所以我们有一个或多个文件可供下载。为每个下载请求创建一个临时文件不是一个好主意。相反,为每个文件创建一个symlink()更好的主意。这将节省大量磁盘空间并降低服务器负载。

在用户会话之后命名符号链接是一个不错的主意。一个更好的主意是生成一个随机的符号链接名称并与会话相关联,因此脚本可以在每个会话中处理多个下载。您可以使用session_set_save_handler()( link ) 并注册一个自定义read函数,该函数检查过期会话并在会话过期时删除符号链接。

于 2009-11-23T02:08:44.340 回答
3

好的,所以到目前为止我们有以下要求

  1. 只让用户在他/她的会话中下载
  2. 请勿将链接复制并粘贴给其他人
  3. 用户必须从网站下载,例如没有盗链
  4. 控制速度

让我们来看看。这不是工作代码,但它应该按照以下方式工作:

<?php // download.php

session_start(); // start or resume a session

// always sanitize user input
$fileId  = filter_input(INPUT_GET, 'fileId', FILTER_SANITIZE_NUMBER_INT);
$token   = filter_input(INPUT_GET, 'token', FILTER_UNSAFE_RAW);
$referer = filter_input(INPUT_SERVER, 'HTTP_REFERER', FILTER_SANITIZE_URL);
$script  = filter_input(INPUT_SERVER, 'SCRIPT_NAME', FILTER_SANITIZE_URL);

// mush session_id and fileId into an access token
$secret        = 'i can haz salt?';
$expectedToken = md5($secret . session_id() . $fileId);

// check if request came from download.php and has the valid access token
if(($expectedToken === $token) && ($referer === $script)) {
   $file = realpath('path/to/files/' . $fileId . '.zip');
   if(is_readable($file)) {
        session_destroy(); // optional
        header(/* stuff */);
        fpassthru($file);
        exit;
    }
}
// if no file was sent, send the page with the download link.
?>
<html ...

<?php printf('a href="/download.php?fileId=%s&amp;token=%s', 
              $fileId, $expectedToken); ?>

...
</html>

就是这样。不需要数据库。这应涵盖要求 1-3。您无法使用 PHP 控制速度,但如果您在发送文件后不销毁会话,则可以向会话写入计数器并限制用户在会话期间发送的文件数量。

我完全同意这可以比使用这种猴子形式的黑客更优雅地解决,但作为概念验证,它应该足够了。

于 2009-11-22T23:52:02.103 回答
3

你能更深入地解释你的问题吗?因为我看不出为什么不使用$_SESSION. 中的数据$_SESSION存储在服务器端的文件中(请参阅http://php.net/session.save-path)顺便说一句。至少默认情况下。;-)

于 2009-11-22T16:50:47.913 回答
2

我建议您首先不要复制该文件。我会做以下事情:当用户请求文件时,你生成一个随机的唯一字符串,以这种方式给他链接:dl.php?k=hd8DcjCjdCkk123然后将此字符串放入数据库,存储他的 IP 地址,也许会话和你生成的时间关联。然后另一个用户请求该文件,确保所有内容(哈希、ip 等)都匹配并且链接没有过期(例如,自生成以来不超过 N 小时),如果一切正常,使用 PHP 进行管道传输文件。设置一个 cron 作业来查看数据库并删除过期的条目。你怎么看?

临时文件

在读写 (w+) 模式下创建一个具有唯一名称的临时文件并返回一个文件句柄。该文件在关闭(使用 fclose())或脚本结束时自动删除。

于 2009-11-22T16:42:14.530 回答
0

也许现在回答为时已晚,但我正在尝试分享功能谷歌!

如果您使用 CPanel,则有一种简短快捷的方法可以阻止对托管文件的外部请求,其名称为:HotLink

您可以在您的 Cpanel 上启用热链接,并确保没有人可以从其他主机请求您的文件或使用您的文件作为下载参考。

于 2013-06-20T19:21:01.763 回答
0

为了实现这一点,我会制作一个文件并使用 chmod 保护它 - 使其对公众不可用。或者,将内容保存在数据库表行中,在需要时获取它。

使其可作为文件下载。为此,我将从受保护文件中获取内容,或者如果它存储在数据库表中,则获取它并简单地输出它。使用 php 标头,我会给它一个所需的名称、扩展名、指定它的类型,最后强制浏览器将输出下载为一个实体文件。

这样,您只需将数据保存在一个地方,即受保护的文件或数据库中。强制客户端浏览器在满足条件的情况下多次下载它,例如,只要用户登录等等。无需担心磁盘空间、制作任何临时文件、cronJobs 和/或文件的自动删除。

于 2015-07-04T00:50:44.187 回答