【问题标题】:Host file, log download, and host stats via PHP?通过 PHP 托管文件、日志下载和托管统计信息?
【发布时间】:2011-10-23 17:34:30
【问题描述】:

我是一个 .NET 人,在这里尝试 PHP 的东西,所以我现在完全脱离了我的舒适区。我想我想做的是有3个文件:

  • download.php

    (a) 包含对文件名的 ID 查找(所以download.php?file=11 querystring 告诉我应该托管 abc.zip)

    (b) 将此下载记录到stats.log的一些代码

    (c) 一对header() 电话和一个readfile() 电话,类似于this question 的答案

  • stats.log:一个简单的日志文件,可能类似于以下示例。这允许通过简单地附加一行文本来完成日志记录,但允许我不时压缩它。


abc.zip 1234
xyz.zip 4321
abc.zip 1
abc.zip 1
abc.zip 1
xyz.zip 1
abc.zip 1

  • stats.php:这最终是提供统计信息的 PHP 文件。它们可以是实时的或接近实时的,可能每分钟重新读取文件并将其缓存或其他。我真的不在乎,这不会经常受到打击,但我确实需要确保这不是一个愚蠢的昂贵操作。这不必是一个漂亮的页面。人类可以轻松阅读的东西才是最重要的,所以那里没有花哨的要求。对于上面的 stats.log 示例,我希望它能够提供如下服务:

abc.zip: 1238 downloads
xyz.zip: 4322 downloads

最终,我不想要数据库或任何其他涉及此的系统。我只有对服务器的 FTP 访问权限,所以除了将脚本放入目录之外,我真的无能为力。我意识到我需要确保脚本对stats.txt 具有写入权限,这很好。

所以我的问题。我有很多,但我相信对于了解 PHP 的人来说,它们都很容易。

  1. 我想我可以通过设置标题和使用 readfile 来理解 download.php 的托管部分。但是,我怎样才能拥有代表文件 ID 和文件名的键/值对集合?如果我在 .NET 中,我可以执行以下操作:var foo = new Dictionary<int, string> {{11, "abc.zip"}, {12, "xyz.zip"}},但我不知道这在 PHP 中是什么样子的。
  2. 如何获取查询字符串?我需要从 URL “stuff/download.php?file=11” 中提取 11 以从我的查找集合中获取我的“abc.zip”。
  3. 如何将换行符写入我的stats.log 文件?
  4. 如何在我的stats.php 脚本中循环访问我的stats.log 文件来统计和托管这些统计信息?
  5. 额外问题:如何缓存第 4 步的结果,并且每分钟/每小时/或其他什么时候只读取一次文件?

如果有人至少可以回答这些问题中的大部分,我可能会填补一些空白,但我们将不胜感激! :)

【问题讨论】:

    标签: php


    【解决方案1】:

    1- 您正在寻找array 例如

     $files=array(11=>'abc.zip',
                 12=>'xyz.zip');
    

    2- 查询字符串由超级全局 $_GET 访问,因此在您的情况下,$_GET['file'] 保存您感兴趣的数据。

    3,4,5 我建议存储 JSON 编码的信息。例如

    $rawInfo=file_get_contents('stats.log');
    $Info=json_decode($rawInfo,true);
    if(isset($Info[$_GET['file']])){
        $Info[$_GET['file']]++;
    }else{
        $Info[$_GET['file']]=1;
    }
    $rawInfo=json_encode($Info);
    $h=fopen('stats.log','c');// If $h is false, you couldn't open the file
    flock($h,LOCK_EX);// lock the file
    $b=fwrite($h,$rawInfo);// if $b is not greater than 0, nothing was written
    flock($h,LOCK_UN);
    fclose($h);
    //And then actually serve the file requested
    

    这具有以有用的格式存储信息的优点。

    每当您提取json_decodeed 数据时,它都是array 的格式,您需要知道如何处理。

    stats.php 可能看起来像这样:

    $rStats=file_get_contents('stats.log');
    $Stats=json_decode($rStats,true);
    foreach($Stats as $k=>$v){
       echo $k.': '.$v.' download'.($v==1?'':'s');
    }
    

    【讨论】:

    • 后续问题:这如何处理同时下载?我会丢失下载计数或锁定统计文件,从而导致其他下载错误或类似情况吗?我认为追加一行将比重写整个文件更好地处理并发问题。将其存储为 JSON 数据的有趣想法 - 我没有想到。
    • 好的,我想我已经回答了我自己的问题。我需要在打开文件并写入之前锁定文件,然后释放锁定,类似于此问题的答案:stackoverflow.com/questions/293601/…
    • @Jaxidian 哈哈,我们同时想出了后续的答案,看我编辑的回复。
    • 谢谢!我认为这填补了我显然遗漏的所有空白。我仍然需要学习和破解这个脚本,但我认为你已经给了我现在成功所需的一切。谢谢!
    • @Jaxidian 没问题 =),在我看到你想要的样子后,我将 stats.php 添加到我的答案中。
    【解决方案2】:

    如果没有@Shad 在接受的答案中的帮助,我永远不会这么容易做到这一点。因此,我想在这里发布我的最终解决方案,它几乎适用于任何人。这允许“直接链接”(即没有 301/302 或其他类型的重定向)正常运行(右键单击 -> 另存为作品),同时仍记录下载。请注意,这是相当“资源密集型”的,一些共享主机可能会对使用这样的东西感到不安,但据我所知,这不应该是一个主要的消耗。我要托管的文件约为 3-15MB,不会有大量下载,所以在我的场景中我并不太担心,但如果您使用此解决方案,请务必注意这一事实!

    download.php

    <?php
    $fileLookup = array(
                0=>'subdir/test.zip',
                1=>'another/sub/dir/test2.zip'
            );
    
    $currentRelativeFileName = $fileLookup[$_GET['file']];
    $currentFileName = basename($currentRelativeFileName);
    
    $rawInfo=file_get_contents('stats.log');
    $Info=json_decode($rawInfo,true);
    
    if(isset($Info[$currentFileName])){
        $Info[$currentFileName]++;
    }else{
        $Info[$currentFileName]=1;
    }
    $rawInfo=json_encode($Info);
    $h=fopen('stats.log','c');// If $h is false, you couldn't open the file
    flock($h,LOCK_EX);// lock the file
    $b=fwrite($h,$rawInfo);// if $b is not greater than 0, nothing was written
    flock($h,LOCK_UN);
    fclose($h);
    
    header("Content-type: application/octet-stream"); 
    header("Content-disposition: attachment; filename=" . $currentFileName); 
    readfile($currentRelativeFileName);
    
    ?>
    

    stats.php

    <html>
    <head>
        <title>Here are my stats!</title>
    </head>
    <body>
    <?php
    $rStats=file_get_contents('stats.log');
    if (strlen($rStats) > 5){
        $Stats=json_decode($rStats,true);
        foreach($Stats as $k=>$v){
           echo $k.': '.$v.' download'.($v==1?'':'s') . '<br />';
        }
    }else{
        echo 'No downloads';
    }
    ?>
    </body>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-05
      • 2023-03-16
      相关资源
      最近更新 更多