Парсер REFERER'ов с поисковых систем
Обработка заголовка HTTP referer является одной из важных задач при раскрутке сайта и сборе статистики. По нему можно определить, какие ресурсы ссылаются на ваш сайт. Но особую ценность представляют данные посещений с поисковых систем, так как эта информация позволяет наиболее четко определить, по каким ключевым словам ваш сайт может быть найден, а также проанализировать эффективность поисковой оптимизации вашего ресурса. Если вы пользуетесь сторонними счетчиками посещений, то эту информацию они обычно предоставляют сами. В некоторых случаях такие данные предоставляют серверные системы статистики типа Webalizer. Я принципиально не пользуюсь ни тем, ни другим, обрабатываю все данные самостоятельно. Для этого была написана функция обработки рефереров, которую я использую в своих проектах. Данные поискового запроса обычно передаются методом GET и содержатся в строке браузера, но основная проблема в том, что кодировка этих данных может быть разной даже в пределах одной и той же поисковой системы. Как выяснилось, не везде доступна штатная функция PHP is_unicode(), поэтому для подстраховки пришлось написать свою. Проверка выполняется согласно правилам формирования Юникода.Code (PHP) : Убрать нумерацию
- // Функция проверки является ли переменная строкой в Юникоде
- // Если штатная функция не определена, то применить нашу
- if (!function_exists('is_unicode')) {
- function is_unicode($str) {
- for ($i=0; $i<strlen($str); $i++) {
- // Если символ с кодом больше 191, то возможно это юникод
- if (ord($str[$i])>191) {
- // Следующий символ должен быть в интервале
- // 10000000b ... 10111111b (128...191)
- if (ord($str[($i+1)])<128 || ord($str[($i+1)])>191) {
- // Условие не выполнено, значит это не юникод
- return false;
- }
- else {
- // Пропускаем один байт, т.к. он является частью символа
- $i++;
- }
- }
- }
- // Проверка пройдена, это юникод
- return true;
- }
- }
Если сервер настроен правильно, то поле реферера обычно доступно в переменных окружения через функцию getenv() или через суперглобальные массивы $_ENV и $_SERVER. Готовая функция разбора реферера у меня получилась следующей:
Code (PHP) : Убрать нумерацию
- // Функция разбора поля REFERER
- function parse_refer($refer) {
- // База данных поисковых систем
- $search_engines=Array(
- Array("name"=>"Картинки.Mail", "pattern"=>"go.mail.ru/search_images", "param"=>"q="),
- Array("name"=>"Mail", "pattern"=>"go.mail.ru", "param"=>"q="),
- Array("name"=>"Google Images", "pattern"=>"images.google.", "param"=>"q="),
- Array("name"=>"Google", "pattern"=>"google.", "param"=>"q="),
- Array("name"=>"Google", "pattern"=>"google.", "param"=>"as_q="),
- Array("name"=>"Live Search", "pattern"=>"search.live.com", "param"=>"q="),
- Array("name"=>"RapidShare Search Engine", "pattern"=>"rapidshare-search-engine", "param"=>"s="),
- Array("name"=>"Rambler", "pattern"=>"rambler.ru", "param"=>"query="),
- Array("name"=>"Rambler", "pattern"=>"rambler.ru", "param"=>"words="),
- Array("name"=>"Yahoo!", "pattern"=>"search.yahoo.com", "param"=>"p="),
- Array("name"=>"Nigma", "pattern"=>"nigma.ru/index.php", "param"=>"s="),
- Array("name"=>"Nigma", "pattern"=>"nigma.ru/index.php", "param"=>"q="),
- Array("name"=>"MSN", "pattern"=>"search.msn.com/results", "param"=>"q="),
- Array("name"=>"Ask", "pattern"=>"ask.com/web", "param"=>"q="),
- Array("name"=>"QIP", "pattern"=>"search.qip.ru/search", "param"=>"query="),
- Array("name"=>"RapidAll", "pattern"=>"rapidall.com/search.php", "param"=>"query="),
- Array("name"=>"Яндекс.Картинки", "pattern"=>"images.yandex.ru/", "param"=>"text="),
- Array("name"=>"Яндекс.Mobile", "pattern"=>"m.yandex.ru/search", "param"=>"query="),
- Array("name"=>"Яндекс", "pattern"=>"hghltd.yandex.net", "param"=>"text="),
- Array("name"=>"Яндекс", "pattern"=>"yandex.ru", "param"=>"text=")
- );
- // Отрезать от ссылки "хвост"
- $tmp=explode("?",$refer);
- $chk_site=$tmp[0]; // Имя сайта
- // Разобрать "хвост" на отдельные параметры
- $params=split("&",implode("&",$tmp));
- $result_engine="";
- $result_title=$refer;
- for ($i=0; $i<count($params); $i++) {
- // Параметр пустой, пропустить
- if ($params[$i]=="") { continue; }
- foreach ($search_engines as $engine) {
- // Поиск по всем сигнатурам
- if (strpos($chk_site,$engine['pattern']) && substr($params[$i],0,strlen($engine['param']))==$engine['param']) {
- // Сигнатура найдена
- $result_title=substr($params[$i],strlen($engine['param']));
- $result_engine=$engine['name'];
- break;
- }
- }
- }
- if ($result_engine!="") {
- // Привести строку в текстовый вид
- $str=trim(urldecode($result_title));
- // Если строка в юникоде, то перевести ее в кодировку win1251
- if (is_unicode($str)) {
- $str=iconv("utf-8","windows-1251",$str);
- }
- if ($str!="") {
- // Сформировать строку "Имя поисковой системы: запрос"
- $result=$result_engine.": ".$str;
- }
- // Пустой поисковый запрос
- else {
- $result="";
- }
- }
- else {
- $result="";
- }
- return $result;
- }
Code (PHP) : Убрать нумерацию
- $refer=trim(getenv('HTTP_REFERER'));
- $engine=parse_refer($refer);
- // Дальше выполняются какие-то действия, например запись в базу
Просмотров: 28431 | Комментариев: 27
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(03.04.2015 в 22:17):
Ну какой год-то был. Все течет, все изменяется.
Дмитрий
(03.04.2015 в 22:12):
А вот так, кстати, работает тоже не плохо: mb_convert_encoding() … проверка у вас злая
ManHunter
(05.09.2014 в 18:06):
Гуглояндексами дело не ограничивается, есть же всякие mail, rambler, nigma и т.п. Не так много, но скрипт на них до сих пор прекрасно работает. Да и гугл с яндексом в статистике изредка проскакивает.
Роман Петрович
(05.09.2014 в 18:04):
усё закрыли лавочку, посковики больше не отдают поисковый запрос в реферере
ManHunter
(28.08.2012 в 11:48):
Напиши быстрее, выше, сильнее. А пока из всего говна я тут вижу только тебя.
шкодер
(28.08.2012 в 11:47):
скрипт парсера полное говно. совершенно не оптимизирован с точки зрения быстродействия
Alex
(07.06.2012 в 02:11):
Как раз то, что искал. Спасибо. Отличный блог!
M@k][SiMk0
(29.04.2012 в 11:55):
можно просто резать ссылку реферера и выделять имя домена
а можно и юзать сигнатуры
$referer = $_SERVER['HTTP_REFERER']; // узнаем рефера
$url_referer = str_replace("http://", "", $referer); // удаляем http:// перед ссылкой
list($domen, $domen2, $domen3, $domen4) = explode("/", $url_referer;); // разбиваем на масив то что перед каждым / слешем
echo $url_referer; // выводим нужный нам отрезок текста - в данном случае тоупо адрес домена
а можно и юзать сигнатуры
$referer = $_SERVER['HTTP_REFERER']; // узнаем рефера
$url_referer = str_replace("http://", "", $referer); // удаляем http:// перед ссылкой
list($domen, $domen2, $domen3, $domen4) = explode("/", $url_referer;); // разбиваем на масив то что перед каждым / слешем
echo $url_referer; // выводим нужный нам отрезок текста - в данном случае тоупо адрес домена
ManHunter
(30.09.2011 в 14:39):
Кроме сигнатур надо еще много чего добавлять, так что здесь халявы не будет.
Riller
(15.09.2011 в 15:23):
А скажите пожалуйста, новые сигнатуры для определения появились или нет? Если появились просьба выложить их здесь.
Kola
(18.05.2011 в 13:35):
for ($i=0; $i<count($params); $i++)
Этот цикл можно начинать с единички, хотя так ошибки никакой. И спасибо за скрипт, оказался полезным.
Этот цикл можно начинать с единички, хотя так ошибки никакой. И спасибо за скрипт, оказался полезным.
QQq
(09.02.2011 в 20:14):
огромное спасибо за парсер!
Алексей
(07.07.2010 в 16:55):
Огромное Вам спасибо! Как просто и ясно все получилось.
Vasek
(26.05.2010 в 20:34):
Появилась ли более свежая версия парсера?
ManHunter
(16.02.2010 в 06:56):
По той же причине, по которой я не пользуюсь готовыми фреймворками, jquery, вордпрессами и прочим. Все, что я в состоянии написать сам - я обязательно напишу сам.
sharovatov
(15.02.2010 в 23:34):
а почему Вы принципиально не пользуетесь системами вроде awstats/webalizer?
ManHunter
(05.10.2009 в 18:06):
Есть такое дело, я уже штук пять разных сигнатур для всяких гуглов добавил.
Александр
(05.10.2009 в 17:54):
Кстати, недавно обратил внимание, что реферер с images.google.ru и images.google.com отличаются тем, как передается поисковая фраза. Если при переходе с images.google.ru через GET передается параметр "q", то при переходе с com текст запроса запрятан уже в "prev", т.е. там приходится еще произвести дополнительный парсинг и urldecode.
ManHunter
(18.07.2009 в 09:25):
Очень неудачная аналогия. Но спорить не собираюсь.
Василий
(18.07.2009 в 08:06):
Значит программы ломать и закодированные скрипты вскрывать - это по честному, а накрутить счетчик у сайта это преступление? Чушь собачья.
ManHunter
(16.07.2009 в 19:42):
Ты явно ошибся сайтом с такими вопросами. Если не можешь продвигать сайты по-честному, то здесь тебе делать нечего.
Василий
(16.07.2009 в 19:26):
А как сделать чтобы скрыть свой REFERER при раскрутке сайта (при накрутке) или заменять его каждый раз на разные данные?
ManHunter
(10.07.2009 в 14:01):
Идешь и читаешь:
http://ru2.php.net/manual/ru/r...lesystem.php
http://ru2.php.net/manual/ru/r...lesystem.php
Сергей
(10.07.2009 в 13:58):
Подскажите пожалуйста как результат записывать в файл. Пожалуйста, а то я новичек в этом деле.
Den
(20.04.2009 в 05:14):
function utf8_to_cp1251($text)
{
$encoded_data = mb_convert_encoding($text, 'Windows-1251', 'UTF-8');
$data = (mb_detect_encoding($str, "auto", true) == '') ? $text : $encoded_data;
return $data;
}
{
$encoded_data = mb_convert_encoding($text, 'Windows-1251', 'UTF-8');
$data = (mb_detect_encoding($str, "auto", true) == '') ? $text : $encoded_data;
return $data;
}
ManHunter
(22.02.2009 в 04:22):
Kulesh, зачем мне тут лекция по программированию? Попробуй выполнить свой код на такой строке:
$str=iconv("windows-1251","utf-8","хуй") ."хуй";
Фактически результирующая строка $str НЕ является юникодом, но при этом пройдет твою проверку и не пройдет мою. Причину объяснять надо или сам найдешь свою ошибку? И использование тернарного оператора при одном условии - дурной тон. Разверни свой код, посмотри что он выполняет:
if (iconv("utf-8","windows-1251",$str)=="") {
$str=$str;
}
else {
$str=iconv("utf-8","windows-1251",$str);
}
Не многовато ли лишних движений в виде ненужного присваивания и двойного вызова одной и той же функции?
$str=iconv("windows-1251","utf-8","хуй") ."хуй";
Фактически результирующая строка $str НЕ является юникодом, но при этом пройдет твою проверку и не пройдет мою. Причину объяснять надо или сам найдешь свою ошибку? И использование тернарного оператора при одном условии - дурной тон. Разверни свой код, посмотри что он выполняет:
if (iconv("utf-8","windows-1251",$str)=="") {
$str=$str;
}
else {
$str=iconv("utf-8","windows-1251",$str);
}
Не многовато ли лишних движений в виде ненужного присваивания и двойного вызова одной и той же функции?
Kulesh
(21.02.2009 в 16:40):
is_unicode не везде работает
Я приминил более, как я считаю, быстрый способ избежать её использования.
Вместо куска кода:
if (is_unicode($str)) {
$str=iconv("utf-8","windows-1251",$str);
}
можно воткнуть:
$str = iconv("utf-8","windows-1251",$str)==''?$str:iconv( "utf-8","windows-1251",$str);
Здесь используется тернарный оператор, он должен быть знаком всем, кто имел дело с С-подобным языком. Поскольку такой оператор всего один. Это условный оператор, предназначеный для выбора одного из двух значений в зависимости от третьего:
$a?$b:$c
выражение примет значение $b, если $a имеет значение true, и получает значение $c, если $a имеет значение false.
Я приминил более, как я считаю, быстрый способ избежать её использования.
Вместо куска кода:
if (is_unicode($str)) {
$str=iconv("utf-8","windows-1251",$str);
}
можно воткнуть:
$str = iconv("utf-8","windows-1251",$str)==''?$str:iconv( "utf-8","windows-1251",$str);
Здесь используется тернарный оператор, он должен быть знаком всем, кто имел дело с С-подобным языком. Поскольку такой оператор всего один. Это условный оператор, предназначеный для выбора одного из двух значений в зависимости от третьего:
$a?$b:$c
выражение примет значение $b, если $a имеет значение true, и получает значение $c, если $a имеет значение false.
Добавить комментарий
Заполните форму для добавления комментария