Last active
April 8, 2021 14:33
-
-
Save sagittaracc/2c8f4531cc026568d817e3ef60f72356 to your computer and use it in GitHub Desktop.
Счётчик уникальных посещений на примере скачивания дистрибутива (PHP)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* ListInterface это интерфейс для классов IPIgnoreList, UserAgentIgnoreList и SearchBotList | |
* | |
* Должен реализовать метод `has($item)` для определения принадлежности пользователя к реализуемому списку | |
*/ | |
interface ListInterface | |
{ | |
/** | |
* Задает правило принадлежности пользователя к данному списку | |
* | |
* @param mixed $item - какая-либо информация по пользователю | |
* @return boolean | |
*/ | |
public function has($item); | |
} | |
/** | |
* IPIgnoreList - это класс для задания списка адресов пользователей которых мы не будем учитывать | |
*/ | |
class IPIgnoreList implements ListInterface | |
{ | |
/** | |
* @var array $ipList - список игнорируемых адресов пользователей | |
*/ | |
private $ipList; | |
/** | |
* Constructor | |
* | |
* @param array $ipList | |
*/ | |
function __construct($ipList) | |
{ | |
$this->ipList = $ipList; | |
} | |
/** | |
* Возвращает принадлежит ли переданный $ip к списку игнорируемых | |
* | |
* @param string $ip | |
* @return boolean | |
*/ | |
public function has($ip) | |
{ | |
return in_array($ip, $this->ipList); | |
} | |
} | |
/** | |
* UserAgentIgnoreList - это класс для задания списка браузеров которых мы не будем учитывать | |
*/ | |
class UserAgentIgnoreList implements ListInterface | |
{ | |
/** | |
* @var array $keywords - список игнорируемых ключевых слов по которым определяется браузер пользователя | |
*/ | |
protected $keywords; | |
/** | |
* Constructor | |
* | |
* @param array $keywords | |
*/ | |
function __construct($keywords) | |
{ | |
$this->keywords = $keywords; | |
} | |
/** | |
* Возвращает если это тот браузер который нас не интересует | |
* | |
* @param string $userAgent | |
* @return boolean | |
*/ | |
public function has($userAgent) | |
{ | |
$userAgent = strtolower($userAgent); | |
foreach($this->keywords as $keyword) | |
{ | |
if(strpos($userAgent, $keyword) !== false) | |
return true; | |
} | |
return false; | |
} | |
} | |
/** | |
* SearchBotList - это класс для перечисления всевозможных ботов | |
*/ | |
class SearchBotList extends UserAgentIgnoreList | |
{ | |
/** | |
* Constructor | |
*/ | |
function __construct() | |
{ | |
parent::__construct([ | |
'bot', | |
'spider', | |
'spyder', | |
'crawlwer', | |
'walker', | |
'search', | |
'yahoo', | |
'holmes', | |
'htdig', | |
'archive', | |
'tineye', | |
'yacy', | |
'yeti', | |
]); | |
} | |
} | |
/** | |
* Visit - это класс для определения уникальных посетителей по дням | |
*/ | |
class Visit | |
{ | |
/** | |
* @var string $token - ежедневный токен пользователя | |
*/ | |
protected $token; | |
/** | |
* @var string $id - уникальный идентификатор пользователя | |
*/ | |
protected $id; | |
/** | |
* @const string TOKEN_NAME - название куки для $token | |
*/ | |
const TOKEN_NAME = 'VisitToken'; | |
/** | |
* @const string ID_NAME - название куки для $id | |
*/ | |
const ID_NAME = 'VisitId'; | |
/** | |
* Constructor | |
* | |
* Генерирует ежедневный токен для пользователя | |
*/ | |
function __construct() | |
{ | |
$this->token = $this->getToken(); | |
} | |
public function getUser() | |
{ | |
return $this; | |
} | |
/** | |
* Возвращает если сегодняшнее посещение является новым | |
* Если ежедневная кука пользователя не установлена или если она вчерашняя | |
* | |
* @return boolean | |
*/ | |
public function isNew() | |
{ | |
return !isset($_COOKIE[self::TOKEN_NAME]) | |
|| $_COOKIE[self::TOKEN_NAME] !== $this->token; | |
} | |
/** | |
* Очищает старые токены перед тем как перезаписать новые | |
*/ | |
public function clearToken() | |
{ | |
unset($_COOKIE[self::TOKEN_NAME]); | |
unset($_COOKIE[self::ID_NAME]); | |
} | |
/** | |
* Генерирует и сохраняет новую пару ежедневных токенов | |
* Хранит сутки пока не наступит новый день | |
*/ | |
public function saveToken() | |
{ | |
setcookie(self::TOKEN_NAME, $this->getToken(), time() + 60 * 60 * 24); | |
$this->id = uniqid(); | |
setcookie(self::ID_NAME, $this->id, time() + 60 * 60 * 24); | |
} | |
/** | |
* Возвращает токен исходя из IP адреса пользователя и текущего дня | |
* | |
* @return string | |
*/ | |
protected function getToken() | |
{ | |
return md5($_SERVER['REMOTE_ADDR'] . date('Ymd')); | |
} | |
/** | |
* Возвращает уникальный идентификатор пользователя | |
* Возвращает только что сгенерированный или тот что был передан самим пользователем | |
* | |
* @return string | |
*/ | |
public function getId() | |
{ | |
if (isset($_COOKIE[self::ID_NAME])) | |
{ | |
$this->id = $_COOKIE[self::ID_NAME]; | |
} | |
return $this->id; | |
} | |
} | |
/** | |
* Download - это класс для подсчета уникальных скачек дистрибутивов | |
* | |
* Если загрузка файлов реализована через общий скрипт то загрузку можно рассматривать как посещение данной страницы | |
* К ежедневному определению уникальности также добавляется параметр build дистрибутива | |
* Так как в один и тот же день можно одним пользователем скачать разные билды - что будет считаться уникальным посещением | |
*/ | |
class Download extends Visit | |
{ | |
/** | |
* @var string $build - строковое представление уникальности файла (версия или название) | |
*/ | |
private $build; | |
/** | |
* Constructor | |
* | |
* @param string $build | |
*/ | |
function __construct($build) | |
{ | |
$this->build = $build; | |
parent::__construct(); | |
} | |
/** | |
* Возвращает токен но с учетом билда | |
* | |
* @return string | |
*/ | |
protected function getToken() | |
{ | |
return md5(parent::getToken() . $this->build); | |
} | |
} | |
/**************************************************** | |
* Example: * | |
****************************************************/ | |
$searchBotList = new SearchBotList(); | |
if ($searchBotList->has($_SERVER['HTTP_USER_AGENT'])) | |
return; | |
$ipIgnoreList = new IPIgnoreList([ | |
'127.0.0.1' | |
]); | |
if ($ipIgnoreList->has($_SERVER['REMOTE_ADDR'])) | |
return; | |
// DNT - Do Not Track header | |
if (isset($_SERVER['HTTP_DNT']) && $_SERVER['HTTP_DNT'] == "1") | |
return; | |
$download = new Download("build 4.1.7"); | |
if ($download->getUser()->isNew()) | |
{ | |
$download->getUser()->clearToken(); | |
$download->getUser()->saveToken(); | |
} | |
//Данный уникальный идентификатор пользователя нужно сохранить чтобы потом по нему подсчитать уникальные загрузки | |
echo($download->getUser()->getId()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment