Как сделать счетчик уникальных скачиваний файлов

Возникли трудности с реализацией скрипта, который читает файл статистики скачиваний и подсчитывает количество скачиваний по каждому файлу. Полученную информацию планируется выводить на страницах возле ссылок для скачивания на соответствующие файлы. Вот мой код:

   index.php
<html>
<head>
<title></title>

</head>
<body>
<a href="script.php?click=file1.txt" download="file1.txt" >Файл 1</a>
<p>Количество скачиваний: , $counter_file1</p> </br>
<a href="script.php?click=file2.txt" download="file2.txt" >Файл 2</a>
<p>Количество скачиваний: , $counter_file2</p> </br>
<a href="script.php?click=file3.txt" download="file3.txt" >Файл 3</a>
<p>Количество скачиваний: , $counter_file3</p> </br>
</body></html>


script.php
    <?php
if(isset($_GET['click']))
{
$ip = $_SERVER['REMOTE_ADDR'];
$data = sprintf("файл:%s, дата:%s, ip:%s \r\n",$_GET["click"], date("d.F.Y"), $ip);
file_put_contents('counter.txt', $data, FILE_APPEND );
header("location:".$_GET["click"]);
}
?>

Пример записи в файл: файл:file3, дата:22.May.2020, ip:127.0.0.1

как сделать такой срипт?


Ответы (1 шт):

Автор решения: Макс Максимус

Такую информацию, как вам нужна, лучше хранить в базе данных. Это проще и надежнее. Если все же будете хранить в файле, нужно учесть следующие моменты. Данных будет много и необходимо их как-то разделять. Для этого нужно взять какой-нибудь символ (| или # или любой другой) и использовать его для сепарации. Пользоваться строго только им, иначе при разборе данных файла все собьется. Пример строки для записи в файл: book.txt|1590261980|190.163.47.135

Так же нельзя менять последовательность значений в строке (например, идет имя файла, потом временная метка, потом ip).

При записи в файл данных о скачивании обязательно в конец строки доклеивайте спецсимвол перевода строки. Это лучше делать с помощью константы PHP_EOL.

Дату и время скачивания лучше хранить в виде временной метки, получаемой с помощью функции time().

Для того чтоб использовать хранящихся в файле данные, их нужно получить, а потом распарсить для удобства. Пример, как может выглядеть функция для записи данных из файла в виде двумерного массива:

function getInfoFromFile($file){
    return array_map(function($el){
        return explode('|', $el);
    }, file($file));
}

В качестве разделителя использован символ |. Но с таким массивом работать неудобно, поэтому полученные данные лучше переформатировать:

function parseInfo($arr)
{
    foreach ($arr as $v) {
        $res[$v[0]]['file_name'] = $v[0];
        $res[$v[0]]['visited_at'][] = $v[1];
        $res[$v[0]]['user_ip'][] = trim($v[2], PHP_EOL);
        $res[$v[0]]['downloads_cnt'] = count($res[$v[0]]['user_ip']);
    }
    return array_values($res);
}

Теперь можно получить удобный для работы массив с нужной нам информацией:

$res = parseInfo( getInfoFromFile( __DIR__.'/info.txt' ) ); print_r($res);

Array
(
    [0] => Array
        (
            [file_name] => book.txt
            [visited_at] => Array
                (
                    [0] => 1590087485
                    [1] => 1590261980
                )

            [user_ip] => Array
                (
                    [0] => 188.163.47.1
                    [1] => 190.163.47.135
                )

            [downloads_cnt] => 2
        )

    [1] => Array
        (
            [file_name] => nature.jpg
            [visited_at] => Array
                (
                    [0] => 1590174208
                )

            [user_ip] => Array
                (
                    [0] => 188.163.47.255
                )

            [downloads_cnt] => 1
        )

)

Теперь используем данные из массива для вывода на страницу нужного контента:

<ul>
    <?php foreach ($res as $v) : ?>
        <li>
            <a href="http://mysite/?script.php?click=<?php echo $v['file_name'] ;?>"><?php echo $v['file_name']; ?></a>
                <span>(скачиваний - <?php echo $v['downloads_cnt']; ?>)</span>
        </li>
    <?php endforeach; ?>
</ul>

Получаем список со ссылками на файлы и информацией:

  • book.txt (скачиваний - 2)
  • nature.jpg (скачиваний - 1)

Код, отвечающий за запись в файл лучше немножко подправить:

if(isset($_GET['click'])){
    $fileName = filter_input(INPUT_GET, 'click', FILTER_SANITIZE_SPECIAL_CHARS); 
    $time = time();
    $ip = $_SERVER['REMOTE_ADDR'];
    $str = $fileName . '|' . $time . '|' . $ip . PHP_EOL;
    file_put_contents( __DIR__ . '/counter.txt', $str, FILE_APPEND );
    header('Location: /' . $fileName);
}

Для админки можно вывести данные в виде таблицы:

<table>
    <tr>
        <th>File</th>
        <th>date</th>
        <th>ip</th>
        <th>downloads</th>
    </tr>
    <?php foreach ($res as $v) : ?>
        <tr>
            <td><?php echo $v['file_name']; ?></td>
            <td><?php echo implode( '<br>', array_map( function($x){
                return date("d.m.Y h:m:s", $x); 
            }, $v['visited_at'] ) ); ?></td>
            <td><?php echo implode('<br>', $v['user_ip']); ?></td>
            <td><?php echo $v['downloads_cnt']; ?></td>
        </tr>
    <?php endforeach; ?>
</table>
<style>
    table, tr, td, th {
        border: 1px solid #aaa;
    }
    tr, td {
        padding: 5px;
    }
</style>

таблица для админки

Так же есть и другие способы работы с файлами (можно считывать построчно, по байтам), почитайте статьи. Так же для хранения данных существует CSV формат (https://ru.wikipedia.org/wiki/CSV), в php есть функция для удобной работы с ним https://www.php.net/manual/ru/function.fgetcsv.php. Может это вам больше понравится.

→ Ссылка