我是一个。net的家伙,在这里尝试PHP的事情,所以我现在完全离开了我的舒适区。我想我要做的是有3个文件:
-
download.php
:(a)包含对文件名的id查找(因此
download.php?file=11
querystring告诉我应该托管abc.zip)(b)记录下载到
stats.log
的代码(c)一对
header()
呼叫和一个readfile()
呼叫,类似于这个问题的答案 -
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的人来说,它们都很容易。
- 我想我通过设置头和使用readfile来理解
download.php
的托管部分。然而,我怎么能有一个键/值对表示文件id和文件名的集合?如果我在。net中,我可以这样做:var foo = new Dictionary<int, string> {{11, "abc.zip"}, {12, "xyz.zip"}}
,但我不知道这在PHP中是什么样子的。 - 我如何获得查询字符串?我需要从URL "stuff/download.php? "文件=11",并采取11从我的查找集合中抓取我的"abc.zip"。
- 我如何将换行符写入我的
stats.log
文件? - 我如何在我的
stats.php
脚本中循环我的stats.log
文件来计算和托管这些统计数据? - 附加问题:我如何缓存从步骤4的结果,只读取文件每分钟/小时/或什么?
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_decode
ed数据,它都是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');
}
如果没有@Shad的帮助,我永远不会这么容易地完成这个被接受的答案。因此,我想在这里发布我的最终解决方案,应该适用于几乎所有人。这允许"直接链接"(即没有301/302或其他类型的重定向)正常工作(右键单击-> save as works too),同时仍然记录下载。注意,这是相当"资源繁重"的,一些共享主机可能会对使用这样的东西感到不安,但据我所知,这应该不是一个主要的消耗。我将托管的文件大约是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>