【问题标题】:Create temporary file and auto removed创建临时文件并自动删除
【发布时间】:2025-05-03 14:35:01
【问题描述】:

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

非常感谢您的回复

【问题讨论】:

  • 文件应该保存多久?
  • 您能否更具体地说明您要实现的目标? Anti-Leeching DL Script 有点模糊。脚本试图解决的用例或问题是什么?
  • 嗨,lkke,我只想让用户在他/她的会话中下载,就像他不能简单地将链接复制并粘贴给其他人一样嗨戈登,我想强迫用户从我的网站下载文件,控制速度。所以,我想在 HTTP 文档的临时目录中创建一个临时文件,以便用户可以下载它们,然后在会话到期后(自动)删除它们
  • 也许你可以使用用户的IP地址?
  • 对不起,我猜你是对的。检查更新的答案

标签: php temporary-files


【解决方案1】:

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

例如手册中的示例:

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

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

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

【讨论】:

  • 我认为这不是 mrblue 问题的解决方案,因为文件在脚本 end/fclose() 上被删除,而不是在会话到期时被删除。
  • 我猜你是对的。一定读过那部分。在我的帖子中添加了更多信息。现在由他决定;)
  • 您好 TheGrandWazoo,感谢您的回答。我已经考虑过那个解决方案,但是如果站点扩展并且Philippe是正确的,由于性能问题是不可能的,我担心的是PHP支持“hook”功能,比如在会话到期或启动后自动调用。
  • 使用 cronjob 时不需要涉及数据库。当 dl 文件共享该用户会话文件的名称时,cron 调用的脚本只需删除当前不存在会话文件的所有 dl 文件。
【解决方案2】:

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

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

【讨论】:

  • 嗨 pygorex1,这正是我要找的。非常感谢。
  • 链接现在是404,只是ping你,让你修复它
  • 如果这是一个 api 请求而不是带有会话的 Web 应用程序怎么办! ?
【解决方案3】:

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

【讨论】:

  • 嗨菲利普,是的,我真的很想用户 $_SESSION(实际上我做过),但我找不到任何文档或主题来提及某事,例如“挂钩”操作,例如:我们可以制作一个在会话过期或启动后系统自动调用的函数。这是我的想法和担忧。感谢您的宝贵时间
  • 走另一条路。在创建新会话时做出反应(例如,$_SESSION 为空,而您之前已填充它),而不是在会话到期时做出反应。问题是,会话可能会在用户不采取任何操作的情况下到期(会话已过期并被垃圾收集器删除)。你到底想做什么?
【解决方案4】:

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

  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 控制速度,但如果您在发送文件后不销毁会话,则可以在会话中写入计数器并限制用户在会话期间发送的文件数。

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

【讨论】:

  • 嗨,戈登,这几乎是我在代码中编写的内容的 90%,但您的代码使用令牌进行了更好的安全检查。非常感谢。
  • 令牌增加了安全性,但它也使您不必再符号链接或复制文件,因为令牌对于会话+文件是唯一的。令牌基本上是 pygorex1 为符号链接名称创建的。与其创建一个符号链接,稍后您必须以某种方式将其删除,您只需发送带有常规 fileId 的名称/令牌。更少的维护。
【解决方案5】:

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

tmpfile

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

【讨论】:

  • 我认为这不是 mrblue 问题的解决方案,因为文件在脚本 end/fclose() 上被删除,而不是在会话到期时被删除。
  • 嗨 roddik,Philippe 是对的,我考虑过那个解决方案,但它不适用于我的情况,尤其是性能问题
【解决方案6】:

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

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

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

【讨论】:

    【解决方案7】:

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

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

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

    【讨论】: