Форум программистов, компьютерный форум, киберфорум
PHP для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/8: Рейтинг темы: голосов - 8, средняя оценка - 4.75
1 / 1 / 1
Регистрация: 25.10.2016
Сообщений: 83

Определение местонахождения клиента по IP и создание счетчика для сайта

25.10.2016, 19:42. Показов 1570. Ответов 1

Студворк — интернет-сервис помощи студентам
Здравствуйте уважаемые форумчане!
Создав свой сайт, я добавил на него счетчик посещений с какого-то сервиса (что то типа qoo...) он работал с JS. и частенько обновлялся. И я не мог посмотреть сколько в действительности было посетителей на сайте. Так же я хотел знать с каких IP адресов ко мне заходят, а так же к какой стране этот IP относится. Что бы не создавать велосипед решил погулять на форумах. нашел много разной информации в том числе и про SxGeo. Мне понравился данный вариант так как там можно сразу узнать и страну и город. Так как я только начинаю изучать PHP и таких людей наверно много я решил выложить данную статью. Только не кусочек кода отвечающий за определение страны<habracut/> и города, а полностью рабочий код. И так начнем.
Для начала необходимо создать таблицу в БД куда будут заноситься данные о посетителях. У меня все поля кроме id, идут с типом varchar 255 и сравнением utf8_general_ci, для id тип int 10 атрибут UNSIGNED и конечно же A/I. Теперь создадим конфигурационный файл в котором запишем параметры подключения к нашей БД. И наконец скачиваем SxGeo.php и SxGeoCity.dat с сайта sypexgeo.net ссылки на оба файла: <a href="https://sypexgeo.net/files/SxGeo22_API.zip"></a>
<a href="https://sypexgeo.net/files/SxGeoCity_utf8.zip"></a>
В SxGeo.php на 55 строке при обращении к библиотеке необходимо заменить название файла с SxGeo.dat на SxGeoCity.dat. Все, подготовительные работы окончены.
Создаем файл stats.php (название файла на ваш выбор) и в нем устанавливаем соединение с нашей БД.
PHP
1
2
3
4
5
6
7
8
9
10
11
<?php
include_once ('config.php');
include_once ('SxGeo.php'); 
$mysqli = new mysqli($server, $user, $pswd, $db);
if ($mysqli->connect_errno) {
printf("Не удалось подключиться: %s\n", $mysqli->connect_error);
exit();}
$mysqli -> select_db($db) or die ("Невозможно открыть $db");
if (!$mysqli->set_charset("utf8")) {
    printf("Ошибка при загрузке набора символов utf8: %s\n", $mysqli->error);
    exit();}
Теперь через функцию getRealIpAddr() получаем ip клиента
PHP
1
2
3
4
5
6
7
public function getRealIpAddr() {
    if (!empty($_SERVER['HTTP_CLIENT_IP']))        // Определяем IP
    { $ip=$_SERVER['HTTP_CLIENT_IP']; }
    elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
    { $ip=$_SERVER['HTTP_X_FORWARDED_FOR']; }
    else { $ip=$_SERVER['REMOTE_ADDR']; }
    return $ip;}
Следом проверяем не 'бот' ли к нам зашел в гости
PHP
1
2
3
if (strstr($_SERVER['HTTP_USER_AGENT'], 'YandexBot')) {$visitor='YandexBot';} //Выявляем поисковых ботов
elseif (strstr($_SERVER['HTTP_USER_AGENT'], 'Googlebot')) {$visitor='Googlebot';}
else { $visitor=$_SERVER['HTTP_USER_AGENT']; }
и передаем в $ip значение функции getRealIpAddr().
PHP
1
$ip = getRealIpAddr();
Теперь создаем объект SxGeo и определяем город, страну и регион
PHP
1
2
$SxGeo = new SxGeo('SxGeoCity.dat', SXGEO_BATCH | SXGEO_MEMORY);
$result = $SxGeo->getCityFull($ip);
Можете воспользоваться функцией var_export() что бы посмотреть какой массив данных он вам вернет, может Вам понадобиться что то еще, кроме того что я предлагаю. Идем дальше. Выбираем из этого массива значения страны, региона и города. И для освобождения места удаляем объект SxGeo.
PHP
1
2
3
4
$city = $result["city"]["name_ru"];
$region = $result["region"]["name_ru"];
$country = $result["country"]["name_ru"];
unset($SxGeo);
Теперь определяем дату время и страницу сайта на которую заходили.
PHP
1
2
$date = date("H:i:s d.m.Y");        // определяем дату и время события
$host = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];    // определяем страницу сайта
Экранируем специальные символы в строке для использования в SQL выражении и заносим наши данные в таблицу.
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
$ip   = $mysqli->real_escape_string($ip);
$date = $mysqli->real_escape_string($date);
$host  = $mysqli->real_escape_string($host);
$region = $mysqli->real_escape_string($region);
$country = $mysqli->real_escape_string($country);
$city = $mysqli->real_escape_string($city);
$visitor = $mysqli->real_escape_string($visitor);
if ($query = $mysqli -> query("INSERT INTO `pre_visitors` (date, visitor, ip, country, region, city, host) VALUES ('".$date."', '".$visitor."', '".$ip."', '".$country."', '".$region."', '".$city."', '".$host."')")){
    //printf("%d строк вставлено.\n", $mysqli->affected_rows);
}
else{
printf("Errorcode: %d\n", $mysqli->errno);
};
проверку можете включить на время наладки, потом я в ней необходимости не вижу.
Теперь нам нужно взять значения для нашего счетчика посещений. Саму форму счетчика я взял с того же сайта где и сам первый счетчик в divы по вставлял следующие значения:
1) Для тех кто зашел впервые или с другого ip адреса.
PHP
1
2
3
4
if ($result1 = $mysqli -> query("SELECT * FROM `pre_visitors` WHERE (visitor NOT RLIKE  'bot') GROUP BY ip ORDER BY 'id'")){
//printf("%d строк вставлено.\n", $result->affected_rows);
}
$res1 = $result1 -> num_rows;
2) Для всего количества просмотром.
PHP
1
2
3
4
if ($result = $mysqli -> query("SELECT  MAX(id) AS id  FROM `pre_visitors` ORDER BY id")){
//printf("%d строк вставлено.\n", $result->affected_rows);
}
$res = $result -> fetch_array();
ну и закрываем соединение с БД
PHP
1
2
$mysqli -> close();
?>
Кстати незабываем подключить наш файл stats.php к index.php.
Теперь визуализируем нашу таблицу. Создаем файл seestats.php и подключаемся к нашей БД.
PHP
1
2
3
4
5
<?php
include_once ('core/config_class.php');
$mysqli = new mysqli($server, $user, $pswd, $db) or die("Не могу соединиться с MySQL.");
$mysqli -> select_db($db) or die("Не могу подключиться к базе.");
?>
Теперь немного HTML что бы вывести все это на экран. Я еще добавил выбор количества выводимых строк.
HTML5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<html>
    <head>
        <style type='text/css'>
            td.zz {PADDING-LEFT: 3px; FONT-SIZE: 9pt; PADDING-TOP: 2px; FONT-FAMILY: Arial; }
        </style>
    </head>
 
<body>
<center>
    <form action="seestats.php" method="get">
        <select name="visualcount">
            <option value="10" selected></option>
            <option value="50">50</option>
            <option value="100">100</option>
            <option value="250">250</option>
            <option value="500">500</option>
            <option value="1000">1000</option>
        </select>
        <input type="button" value="Запросить">
    </form>
Далее обрабатываем нашу форму, запрашиваем все поля с нашей таблицы исключая ботов и повторяющиеся ip адреса, также запрашиваем MAX id для концовки нашей таблицы.
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$lastid =  isset ($_GET['visualcount']) ? ($_GET['visualcount']) : '10';
if ($query = $mysqli->query("SELECT * FROM `pre_visitors`
WHERE (visitor NOT RLIKE  'bot') 
GROUP BY ip 
ORDER BY 'id' 
DESC LIMIT $lastid")){
    //printf("%d строк получено.\n", $mysqli->affected_rows);
}
else{
printf("Errorcode: %d\n", $mysqli->errno);
};
 
if ($result = $mysqli -> query("SELECT  MAX(id) AS id  FROM `pre_visitors` ORDER BY id")){
//printf("%d строк получено.\n", $result->affected_rows);
}
$num_rows = $query -> num_rows;
$res = $result -> fetch_array();
?>
Создаем таблицу, стили и размеры можете использовать какие вам нравятся.
HTML5
1
2
3
4
5
6
7
8
9
10
11
12
<table width="680" cellspacing="1" cellpadding="1" border="0"
           STYLE="table-layout:fixed">
        <tr align = "center" bgcolor="#eeeeee">
            <td class="zz" width="30"><b>№ п/п</b></td>
            <td class="zz" width="90"><b>Время и дата</b></td>
            <td class="zz" width="500"><b>Данные о посетителе</b></td>
            <td class="zz" width="100"><b>IP/прокси</b></td>
            <td class="zz" width="100"><b>Страна</b></td>
            <td class="zz" width="100"><b>Регион</b></td>
            <td class="zz" width="100"><b>Город</b></td>
            <td class="zz" width="110"><b>Посещенный URL</b></td>
        </tr>
Теперь через цикл заполняем нашу таблицу и закрываем соединение с БД.
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
while($row = $query -> fetch_array()){
    echo '<tr bgcolor="#eeeeee"><td class="zz">'.$row['id'].'</td>';
    echo '<td class="zz">'.$row['date'].'</td>';
    echo '<td class="zz">'.$row['visitor'].'</td>';
    echo '<td class="zz">'.$row['ip'].'</td>';
    echo '<td align = "center" class="zz">'.$row['country'].'</td>';
    echo '<td align = "center" class="zz">'.$row['region'].'</td>';
    echo '<td align = "center" class="zz">'.$row['city'].'</td>';
    echo '<td class="zz">'.$row['host'].'</td></tr>';
}
 
echo '<tr bgcolor="#eeeeee"><td class="zz" colspan = "3" ><b>Количество новых посетителей</b></td>';
echo '<td align = "center"><b>'.$num_rows.'</b></td>';
echo '<td class="zz" colspan = "3" ><b>Общее количество посещений</b></td>';
echo '<td align = "center"><b>'.$res['id'].'</b></td></tr>';
echo '</table>';
echo '</center>';
echo '</body></html>';
$mysqli -> close();
?>
Жаль только что вы будете получать IP прокси-сервера а не реального клиента.

Добавлено через 6 часов 30 минут
Забыл самое главное, что я хотел спросить. Я только начинаю изучать PHP и MySQL. И хотел что бы мне подсказали, может данную структуру можно оптимизировать, может код каряво написан. В общем принимается конструктивная критика, желательно с примерами исправления.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
25.10.2016, 19:42
Ответы с готовыми решениями:

GPS. Определение местонахождения
Пытаюсь получить текущее местонахождение. На устройстве включил GPS. В манифесте прописл: &lt;uses-permission...

Определение местонахождения флешки
Можно ли по флешке узнать IP адрес и местонахождение компа, куда она вставлялась?

Создание клиента сайта
Привет всем, мне нужна помощь в создании клиента сайта, тоесть програмка для андроид девайсов, напривер как Вконтакте и тому подобные, так...

1
Native x86
Эксперт Hardware
 Аватар для quwy
6857 / 3790 / 1025
Регистрация: 13.02.2013
Сообщений: 11,861
25.10.2016, 19:59
Не знаю, в курсе ли вы, но любой подобный код имеет следующие недостатки:

1. База соответствия меняется ежечасно, поэтому:
1a. Нужно заботится о ее обновлении хотя бы раз в сутки.
1b. Дать скрипту возможность обновляться самостоятельно (если он умеет это делать).
1c. Надеяться, что авторам это не надоест и они не бросят всех вообще без обновлений.

2. Базы эти очень приблизительные:
2a. Надеяться на то, что правильно будет определена страна, можно примерно на 95%
2b. Город правильно определяется примерно в 60-70% случаев.
2c. Информацию точнее города вообще не стоит воспринимать как что-то мало-мальски достоверное.

3. Кроме прокси-серверов существуют VPN и TOR, что делает определение хоть чего-нибудь по IP невозможным, поэтому кроме адреса для локализации сайтов нужно использовать другие методы:
3a. Принимаемые языки в заголовке Accept-Language.
3b. Язык браузера в заголовке User-Agent.
3c. Информацию об операционной системе, полученную через JavaScript.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
25.10.2016, 19:59
Помогаю со студенческими работами здесь

Определение местонахождения с помощью Google API
Кто разбирается с google api под xamarin, помогите определить местонахождение. Карту подключил, но с местонахождением проблемы, не могу...

Список городов и определение местонахождения по координатам
Всем доброго времени суток! Подскажите, где можно найти акутуальный на текущий день, обновляемый список городов России и стран СНГ и как...

Определение местонахождения (название населенного пункта)
Всем привет. Мне надо реалозовать местонахождение планшета на карте, только мне надо получить не координаты, и название населенного пункта....

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

Определение номера этажа и подъезда местонахождения квартиры
Помогите пожалуйста решить задачу. Есть задачка. Пользователь вводит количество этажей, подъездов в доме, и также номер квартиры. Нужно...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
2
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru