PHP:让用户只下载购买的文件

时间:2012-10-04 00:14:23

标签: php redirect download client-side

我正在考虑允许通过PayPal从我这里购买一些内容的客户的问题。我会提供多种无形商品。当有人完成对其中一件商品的购买时,他们将被重定向到一个登陆页面 - 让我们称之为“thank_you.php” - 这将自动排队下载并允许链接排队下载以防万一自动开始。这将通过将唯一项ID传递到下载页面(“download.php”)来完成。

这种方法基本上模仿了这些主题的最佳答案:

PHP generate file for download then redirect

A PHP script to let users download a file from my website without revealing the actual file link in my website?

但是,我担心一旦用户使用“thank_you.php”,他们就可以下载他们的项目,然后使用Firebug(或等同物)编辑项目ID并下载另一个不同的项目:

<a href="download.php/38a205ec300a3874c867b9db25f47c61">Download Here</a>

<a href="download.php/7c8ddc86c0e4c14517b9439c599f9957">Download Here</a>

我需要那些比我更好的人的想法和帮助:我可以实现什么(以及如何)作为一种解决方案,仍然允许相同的客户访问和休闲,但阻止这种操作?

编辑:ID哈希用于预览和引用整个网站中的项目,我不用担心人们会猜测,而是他们在单独的标签页中浏览网站以获取其他ID并继续下载不同的项目。

5 个答案:

答案 0 :(得分:4)

虽然这些其他答案假设你有一个会话,用户名,听起来好像你刚刚创建一个文件的哈希来隐藏文件名。换句话说,您可能还需要在键盘上放一只猴子锤,并将其作为您所拥有文件的文件名。

然后听起来你担心用户会来,敲击键盘,并最终与你的猴子完全匹配。这不太可能。

更有可能的是,有人会复制并粘贴您的链接并进行分享。听起来好像你需要在你的身份验证方案中添加至少一层(例如,用户名和项目ID的哈希),或者一旦使用链接就会过期。

从您的评论中,听起来好像您正在使用哈希来识别您网站其他部分的项目,这意味着用户可以通过查看您的另一部分的来源来确定项目的哈希值网站。在这一点上,你通过默默无闻的安全就像我使用代码词(例如“鱼意味着约翰,猫意味着丽莎”),同时与某人闲聊并说“鱼和猫正在制作”,同时还有一张写在一边的纸张写下来,任何人都可以看到。听起来你只是想隐藏文件名,所以人们无法猜测它们。这被称为security through obscurity,并没有真正为你买单。

大多数其他答案都假设某个项目存在,并且它将有多个不同的哈希指向它(例如file1,将有hash1,hash2和hash3都是有效的链接)。在这种情况下,他们创建了多个哈希值,每个哈希值对于某个用户+项目是唯一的。我想他们也假设网站上的每个人都会将下载项称为item1而不是hash1,这听起来像你在做什么?

您可能最好只在代码中的某处创建一个字典,该字典包含项目名称和散列之间的映射,然后仅在下载页面上,用散列替换名称。同样,这只是通过默默无闻的安全性,链接可以共享,但人们将无法获得哈希只是浏览您的网站。

答案 1 :(得分:3)

当他们付款时,将可用下载的ID和随机散列存储在付款表中。使用那个哈希然后获取ID。然后,哈希应该永远不会与特定产品相关,而是与付款相关。

答案 2 :(得分:3)

我原来的回答:

您需要存储(在数据库或会话变量中)用户可以访问的项目,您将为每个项目生成唯一的随机令牌。该令牌将用于识别购买的物品。将令牌传递到他们能够下载的页面(在会话变量,POST参数或作为URL中的最后一个选项,即GET)。在您需要下载的页面中,您将使用会话信息查询数据库/会话变量,以识别客户和传递的令牌(但是您已通过它),并检索要下载的文件。

如果您需要保留已购买商品的列表以便重新下载,您也可以这样做,但请记住在用户请求下载时再次创建令牌。如果您愿意,也可以添加到期日期。


现在我已经提到了几个替代方案,然后再次根据所引用答案的性质,我想你需要更多细节来解决这个问题。

可能是厄尼是对的,我不应该假设你有一个会话。可能是我应该告诉你如何开会。

所以我会选择其中一个选项来实现,这是最简单的选择。


<?php
    //Oh, I'm in a PHP page...
    //check if there is not a session
    if (session_id() != '')
    {
        //Ok, there is no session, let's create one
        session_start();
    }
    //Now we are sure there is a session
    //Let's store in the session the id of the file I want to allow to download
    $_SESSION['download'] = GetFileId();
    //GetFileId will do some mambo jambo expecto patronum to return an id
    //The id will be 38a205ec300a3874c867b9db25f47c61 or something
?>

现在在下载页面....

<?php
    //Oh, I'm in another PHP page...
    //check if there is not a session
    if (session_id() != '')
    {
        //no session? screw you, no download for you
        header('Location: sorry.php');
    }
    else
    {
        //Now we are sure there is a session
        //Let's get from the session the id of the file I want to allow to download
        $id = $_SESSION['download'];
        //Now get the url to redirect to allow the download
        $url = GetUrl($id);
        //GetUrl will do some mambo jambo expecto patronum to return an url
        //Ok, now we are going to return that file...
        //So put the correct MIME type
        header('content-type: image/gif');  //if it is a gif...
        //Load the file
        $contents = file_get_contents($url); 
        echo $contents;
        //That's the only output
        exit();
     }
?>

请注意,我确实只允许从PHP访问该文件,因此我可以先验证用户是否有权访问。您不应该允许用户只是放置网址(即使他无法猜测)并访问该文件。因此,如果您正在运行服务器,则希望将这些文件放在服务器Web文件夹之外,或者如果您使用的是托管,请使用.htaccess(或您的托管提供的其他机制)保护它们。


对此解决方案做出贡献:

简单易行。但它有一些缺点:

  • 如果会话在下载之前终止,则用户丢失了他的钱*。
  • 没有明确的方法来重新下载。
  • 它仍然容易受到会话劫持的影响(我知道,但是最好是安全的)。

*:说连接丢失,会话在客户端过期。哦,不,我们不需要任何满意的客户。

所以,你真的,真的,需要用数据库备份它并创建随机令牌,最好是有效期。

答案 3 :(得分:1)

您可以实施的最简单的事情之一是跟踪用户购买的日志记录系统。您可以将所请求的ID与存储的与用户购买相关的ID进行交叉引用。如果它们不相关,请不要提供该文件。

答案 4 :(得分:1)

您需要跟踪用户在数据库中购买的商品。 download.php然后可以检查用户是否购买了他们试图下载的项目。