【问题标题】:Best way to track (direct) file downloads跟踪(直接)文件下载的最佳方式
【发布时间】:2011-12-30 15:17:13
【问题描述】:

跟踪直接文件下载的最佳方法是什么?我找到了一些解决方案,例如这个:

http://www.gayadesign.com/diy/download-counter-in-php-using-htaccess/

但这对我不起作用,我在尝试下载文件时只得到一个空白页 + 我不知道它是否足够安全......

Google Analytics 仅适用于 javascript,无法跟踪直接文件下载。

最好是一个安全且自有托管的解决方案。

【问题讨论】:

  • 这是什么协议?你的日志不会告诉你你需要知道的一切吗?
  • 获取日志分析器并从您的 access_log 中提取直接下载 URL?
  • Apache 日志对用户不太友好,我想稍后在我的网站上显示计数器。

标签: php html apache .htaccess statistics


【解决方案1】:

随意使用:)

.htaccess:

RewriteEngine on    
RewriteRule ^(.*).(rar|zip|pdf)$ http://xy.com/downloads/download.php?file=$1.$2 [R,L]    

mysql:

CREATE TABLE `download` (
    `filename` varchar(255) NOT NULL,
    `stats` int(11) NOT NULL,
    PRIMARY KEY  (`filename`)
)

download.php

<?php

mysql_connect("localhost", "name", "password")
or die ("Sorry, can't connect to database.");
mysql_select_db("dbname"); 
$baseDir = "/home/public_html/downloads"; 
$path = realpath($baseDir . "/" . basename($_GET['file'])); 

if (dirname($path) == $baseDir) {
if(!is_bot())
mysql_query("INSERT INTO download SET filename='".mysql_real_escape_string(basename($_GET['file']))."' ON DUPLICATE KEY UPDATE stats=stats+1");


header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=" . basename($_GET['file']));
header("Content-Length: ".filesize($path));
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: binary");
ob_clean();
ob_end_flush();
readfile($path);    
}

function is_bot()
{

    $botlist = array("Teoma", "alexa", "froogle", "Gigabot", "inktomi",
    "looksmart", "URL_Spider_SQL", "Firefly", "NationalDirectory",
    "Ask Jeeves", "TECNOSEEK", "InfoSeek", "WebFindBot", "girafabot",
    "crawler", "www.galaxy.com", "Googlebot", "Scooter", "Slurp",
    "msnbot", "appie", "FAST", "WebBug", "Spade", "ZyBorg", "rabaz",
    "Baiduspider", "Feedfetcher-Google", "TechnoratiSnoop", "Rankivabot",
    "Mediapartners-Google", "Sogou web spider", "WebAlta Crawler","TweetmemeBot",
    "Butterfly","Twitturls","Me.dium","Twiceler");

    foreach($botlist as $bot)
    {
        if(strpos($_SERVER['HTTP_USER_AGENT'],$bot)!==false)
        return true;    // Is a bot
    }

    return false;
}

?>

来源 - gayadesign.com

【讨论】:

【解决方案2】:

您的 apache 日志应该包含很多信息,但我认为您要求的是更多地控制记录的内容和时间。所以你要做的是有两个页面:一个是文件的链接,另一个是跟踪文件,如下所示:

file_page.php

<a href="download.php?id=1234">Download File!</a>

download.php

<? // Code to track the file using PHP, whether that means storing data in a database, saving to a log, or emailing you. I'd use a DB, like so:

   // Prep the vars
   $file_id = $_GET['file_id']; // You should sanitize this first.
   $file_path = '/files/'.$file_id.'.pdf';

   // Save data to database
   mysql_query('INSERT INTO download_log
      SET file_id = '.$file_id.',
          date_downloaded = '.date('Y-m-d H:i:s').',
          user_id = '.$_SESSION['user_id']);

   // Now find the file and download it
   header('Content-type: application/pdf');
   header('Content-Disposition: attachment; filename='.$file_id.'.pdf); // or whatever the file name is
   readfile($file_path);

反正就是这样。

完成后页面将是空白的,但所有浏览器都应在页面加载后开始下载文件。

所以我在这里所做的是保存文件 ID、当前日期时间和下载者的用户 ID(来自 $_SESSION 变量)。您可能想要存储更多信息,例如用户的 IP 地址、HTTP_REFERRER 或其他 $_SERVER 信息,以便您可以跟踪用户来自何处以及下载的时间和内容。

祝你好运。

【讨论】:

  • 这行得通。但是,请记住,如果您要通过 readfile 发送大文件并且您的站点很繁忙,这将消耗大量 RAM。
  • @MichaelIrey,是否有任何其他方法可以跟踪低 RAM 消耗的文件下载?
【解决方案3】:

为了使代码与 PHP7.3 、 Mysqli 和 Mariadb 引擎一起使用,我对原始答案进行了两次修改:

  1. 对我来说,“mysqly_real_escape_string”不起作用,所以我使用了“basename($_GET['file'])”

2:Mariadb SQL 在“UPDATE”之后不接受“SET”,因此我使用了“ON DUPLICATE KEY UPDATE stats = stats + 1”

因此我在这里发布了一个新问题:Download counter for direct download links using .htaccess, mysql and php

查看下面的完整代码...

<?php

$conn =  mysqli_connect('localhost', 'user_name', 'password','database');
if (!$conn) {
      die("Connection failed: " . mysqli_connect_error());
}

$baseDir = '/home/user/domains/mydomain.com/public_html/downloads'; 
$path = realpath($baseDir . '/' . basename($_GET['file'])); 

$file = basename($_GET['file']);// this is what I used instead mysqli_real_escape_string
$sql = 'INSERT INTO downloads VALUES ("'.$file.'", 1) ON DUPLICATE KEY UPDATE  stats = stats + 1';

//***************************************************
// following SQL line inserts record with empty filname field value but updates the counter as it is supposed to:
// $sql = 'INSERT INTO download  VALUES ('.mysqli_real_escape_string(basename($_GET['file'])).", 1)' ON DUPLICATE KEY UPDATE stats=stats+1";
//**********************************************************


if (dirname($path) == $baseDir) {
if(!is_bot())
mysqli_query($conn,$sql);
mysqli_close($conn);
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=" . basename($_GET['file']));
header("Content-Length: ".filesize($path));
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: binary");
ob_clean();
ob_end_flush();
readfile($path); 

}

function is_bot()
{

    $botlist = array("Teoma", "alexa", "froogle", "Gigabot", "inktomi",
    "looksmart", "URL_Spider_SQL", "Firefly", "NationalDirectory",
    "Ask Jeeves", "TECNOSEEK", "InfoSeek", "WebFindBot", "girafabot",
    "crawler", "www.galaxy.com", "Googlebot", "Scooter", "Slurp",
    "msnbot", "appie", "FAST", "WebBug", "Spade", "ZyBorg", "rabaz",
    "Baiduspider", "Feedfetcher-Google", "TechnoratiSnoop", "Rankivabot",
    "Mediapartners-Google", "Sogou web spider", "WebAlta Crawler","TweetmemeBot",
    "Butterfly","Twitturls","Me.dium","Twiceler");

    foreach($botlist as $bot)
    {
        if(strpos($_SERVER['HTTP_USER_AGENT'],$bot)!==false)
        return true;    // Is a bot
    }

    return false;
}


function alert($msg) {
    echo "<script type='text/javascript'>alert('$msg');</script>";
}

?>

【讨论】:

    【解决方案4】:

    我也对此处发布的原始代码进行了一些改进。 我添加了一些额外的统计数据,例如国家、地区、纬度和经度,仅举几例......

    这是更新后的代码:

    <?php
    
    $conn =  mysqli_connect('localhost', 'aeon_dl_usr', 'Turions@1522','aeon_downloads');
    if (!$conn) {
          die("Connection failed: " . mysqli_connect_error());
    }
    
    if($_GET['f']=="workbook"){
        $file="work_log_book_public.pdf";
    }else{
        die("File not found.");
    }
    
    
    $baseDir = substr(__FILE__,0,strpos(__FILE__,"downloads"))."downloads/"; 
    $path = realpath($baseDir . '/' . $file); 
    
    $ipAddress=get_client_ip();
    
    $geo = unserialize(file_get_contents("http://www.geoplugin.net/php.gp?ip=".$ipAddress));
    $User_Ipaddress=$geo["geoplugin_request"];
    $User_Country = $geo["geoplugin_countryName"];
    $User_City = $geo["geoplugin_city"];
    $User_Region = $geo["geoplugin_region"];
    $User_CurrencySymbol = $geo["geoplugin_currencySymbol"];
    $User_CurrencyCode = $geo["geoplugin_currencyCode"];
    $User_Latitude = $geo["geoplugin_latitude"];
    $User_Longitude = $geo["geoplugin_longitude"];
    
    
    $sql = 'INSERT INTO downloads VALUES ("'.$User_Longitude.'", "'.$User_Latitude.'","'.$User_CurrencyCode.'","'.$User_CurrencySymbol.'","'.$User_Region.'","'.$User_City.'","'.$User_Country.'","'.$User_Ipaddress.'", "'.$file.'", 1) ON DUPLICATE KEY UPDATE  stats = stats + 1';
    
    
    if (dirname($path) == $baseDir) {
        if(!is_bot()){
            mysqli_query($conn,$sql);
            mysqli_close($conn);
    
            header("Cache-Control: public");
            header("Content-Description: File Transfer");
            header("Content-Disposition: attachment; filename=".$file);
            header("Content-Length: ".filesize($path));
            header("Content-Type: application/force-download");
            header("Content-Transfer-Encoding: binary");
            ob_clean();
            ob_end_flush();
            readfile($path); 
        }
    }else{
        die("error on loading file");
    }
    
    
    
    function is_bot(){
        $botlist = array("Teoma", "alexa", "froogle", "Gigabot", "inktomi",
        "looksmart", "URL_Spider_SQL", "Firefly", "NationalDirectory",
        "Ask Jeeves", "TECNOSEEK", "InfoSeek", "WebFindBot", "girafabot",
        "crawler", "www.galaxy.com", "Googlebot", "Scooter", "Slurp",
        "msnbot", "appie", "FAST", "WebBug", "Spade", "ZyBorg", "rabaz",
        "Baiduspider", "Feedfetcher-Google", "TechnoratiSnoop", "Rankivabot",
        "Mediapartners-Google", "Sogou web spider", "WebAlta Crawler","TweetmemeBot",
        "Butterfly","Twitturls","Me.dium","Twiceler");
    
        foreach($botlist as $bot)
        {
            if(strpos($_SERVER['HTTP_USER_AGENT'],$bot)!==false)
            return true;    // Is a bot
        }
    
        return false;
    }
    
    
    function alert($msg) {
        echo "<script type='text/javascript'>alert('$msg');</script>";
    }
    
    
    function get_client_ip() {
        $ipaddress="";
        if (isset($_SERVER['HTTP_CLIENT_IP']))
            $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
        else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
            $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
        else if(isset($_SERVER['HTTP_X_FORWARDED']))
            $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
        else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
            $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
        else if(isset($_SERVER['HTTP_FORWARDED']))
            $ipaddress = $_SERVER['HTTP_FORWARDED'];
        else if(isset($_SERVER['REMOTE_ADDR']))
            $ipaddress = $_SERVER['REMOTE_ADDR'];
        else
            $ipaddress = 'UNKNOWN';
    
        return $ipaddress;
       
    }
    
    
    ?>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-05
      • 1970-01-01
      • 1970-01-01
      • 2016-03-06
      • 2011-05-29
      相关资源
      最近更新 更多