Счётчик кликов по ссылке или по кнопке | PHP

На ряде сайтов можно увидеть ссылку, а рядом надпись "То-то скачено столько-то раз". Или свою кнопку "Нравится" со счётчиком. Или пару "Нравится/Не нравится". Реализуются они подобным образом:

  1. Число нажатий хранится в базе данных (или отдельном файле). При загрузке браузером HTML-страницы оно подставляется в указанное в шаблоне место.
  2. Когда посетитель нажимает на кнопку на HTML-странице, JavaScript передаёт в PHP с какой страницы произошёл клик по кнопке.
  3. PHP меняет значение, записанное в базе данных. И передаёт число, увеличенное на единицу, в JavaScript.
  4. JavaScript меняет число на счётчике без перезагрузки HTML-страницы.

Ниже представлен упрощённый вариант (без подключения БД).

условия

Файл 1.html

<button type="button" id="like">Нравится: <a href="#" id="like">Файл [скачено <output id="statlike">0</output></button> раз]</a>

<script>
document.getElementById('like').addEventListener('click', function(e){
  if (window.XMLHttpRequest && localStorage.getItem('like') != location.pathname) {
    e.preventDefault();  // по ссылке нельзя перейти, перенаправление осуществляется с помощью location в событии loadend
    var http = new XMLHttpRequest(), href = this.href;
    http.open('POST', 'stat.php');  // совет: заменить на абсолютный адрес, например, http://сайт.ru/stat.php
    http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    http.addEventListener('readystatechange', function() {
      if (this.readyState == 4 && this.status == 200) {
        document.getElementById('statlike').innerHTML = this.responseText;  // изменить число в теге output, после того, как запрос будет исполнен
      }
    });
    http.timeout = 10000;  // прервать запрос, если он длиться более 10 секунд
    http.addEventListener('loadend', function() { location = href });
    http.send('url=' + location.pathname);  // передать в POST запросе адрес файла, который нужно изменить
    localStorage.setItem('like', location.pathname);  // запись в локальное хранилище о том, что был сделан клик (более надёжно отслеживать cookie авторизованных пользователей)
  }
});
</script>

Файл stat.php

<?php
if (isset ($_POST['url'])) {  // если переменная установлена (передана)
    $fn = $_SERVER['DOCUMENT_ROOT'] . $_POST['url'];  // абсолютный адрес файла
    if (file_exists($fn)) {  // если файл существует
      $f = fopen($fn, "r+");  // открыть файл
      if (flock($f, LOCK_EX)) {  // заблокировать файл, пока выполняется скрипт [php.net]
        $fr = fread($f, filesize($fn));  // записать в переменную содержимое файла
        $pattern = '/(<output id="statlike">)(\d+)(<\/output>)/i';
        $line_ok = preg_match($pattern, $fr, $matches);
        if($line_ok == 1) {  // если в содержимом был найден тег output с id="statlike"
          $m = $matches[2] + 1;  // к числу прибавить 1
          $fr = preg_replace($pattern, '${1}'.$m.'$3', $fr, 1);  // изменить число в содержимом
          rewind($f); // переместить указатель в начало файла
          ftruncate($f, 0); // очистить файл
          fwrite($f, $fr);  // записать в файл содержимое с изменённым числом
        }
      echo $m;  // вывести число, чтобы передать в JS
      flock($f, LOCK_UN);  // разблокировать файл
      }
      fclose($f);  // закрыть файл
    }
  }
?>

Внимание: пример демонстрирует работу JS. PHP всё же должен менять базу данных, так как при использовании предложенного варианта могут возникнуть сложности при одновременном доступе к файлу (см. про flock).

в f t
наверх ↑

4 комментария:

Василий Кульков
Здравствуйте, как раз то что нужно, спасибо большое!!! А можете еще написать как сделать чтоб результат клика на кнопку отображался на странице, на которую ведет эта кнопка?
NMitra
Здравствуйте, у вас какой HTML кнопки? Можно ссылку стилизовать под кнопку.
Павел Героним
как сделать большое количество кнопок? скажем, для каждой отдельной фотографии?
NMitra
Павел, у кода PHP есть недостаток, как бы я ни старалась его минимизировать. Может случиться так, что исчезнет всё содержимое страницы. Я бы не советовала его использовать в таких объёмах.