Корпоративный интернет-счётчик
Аннотация
В данной статье рассказывается как создать интернет-счётчик для корпоративного портала.
Задача
Счётчик должен вести подробную информацию о посетителях: адрес откуда пришёл посетитель, адрес страницы, IP-адрес посетителя, дата, браузер пользователя, операционная система.
По IP-адресу можно определить страну и регион откуда пришёл посетитель.
Кроме того мы должны иметь возможность просматривать статистику посещений по дням, количество новых посетителей (и их IP-адреса), количество уникальних посетителей (и их IP-адреса), самые лучшие ссылки на на нашу интернет-страницу, самые популярные страницы и т.п..
Схема выполнения
Для начала, рассмотрим схему выполнения счётчика.
1. Пользователь из интернет (Пользователь1, Пользователь2, Пользователь3) заходит на нашу интернет-страницу, расположенную на сервере провайдера.
2. На интернет-странице выполняется код на PHP, который определяет IP-адрес пользователя, URL откуда пришёл, URL страницы, браузер и операционную систему пользователя. Эти данные программа передаёт на корпоративный интернет-сервер.
3. На корпоративном интернет-сервере вызывается хранимая процедура InterBase для передачи данных о пользователе и получении статистической информации для интернет-страницы.
4. Статистически данные передаются в программу на Интернет-странице и выводятся для посетителя.
Со временем, администратор подключается к Interbase-серверу с помощью клиенской программы (написанной на Delphi) и обрабатывает информацию.
Примечание: Корпоративный сервер и InterBase-сервер можно совместить, но тогда уменьшается уровень защиты информации. Так как зная пароль и имя пользователя можно будет подключиться к базе данных из интернет.
Структура базы данных
Теперь создадим структуру базы данных.
Таблица Project предназначена для хранения названия проекта. Таким образом,мы можем создавать сколько угодно счётчиков.
В таблице CountData накапливается информация о посетителях:
URLFrom – откуда пришёл посетитель,
URLCurr – какую страницу посетили,
DateHint – дата (без времени) когда посетили,
FullDate – полная дата,
IPUser – IP-адрес посетителя,
Browser – браузер,
SystemUser – операционная система пользователя,
SystemVer – версия операционной системы,
CompName – название компьютера посетителя.
В таблице IPTable хранятся адреса уникальных IP-адресов.
Скрипт базы данных
Сгенерируем скрипт базы данных по данной структуре:
CREATE TABLE CountData (
CountDataID INTEGER NOT NULL,
ProjID INTEGER,
URLFrom VARCHAR(1024),
URLCurr VARCHAR(1024),
DateHint DATE,
FullDate DATE,
IPUser VARCHAR(15),
Browser VARCHAR(255),
SystemUser VARCHAR(255),
SystemVer VARCHAR(255)
);
CREATE INDEX IF318CountData ON CountData
(
ProjID
);
CREATE INDEX ak_IP ON CountData
(
IPUser
);
CREATE INDEX ak_DateHint ON CountData
(
DateHint
);
ALTER TABLE CountData
ADD CONSTRAINT PKCountData PRIMARY KEY (CountDataID);
CREATE TABLE IPTable (
IPUser VARCHAR(15) NOT NULL,
DateAdd DATE
);
CREATE INDEX akDateAdd ON IPTable
(
DateAdd
);
ALTER TABLE IPTable
ADD CONSTRAINT PKIPTable PRIMARY KEY (IPUser);
CREATE TABLE Project (
ProjID INTEGER NOT NULL,
ProjName VARCHAR(255),
Comment BLOB SUB_TYPE 1
);
ALTER TABLE Project
ADD CONSTRAINT PKProject PRIMARY KEY (ProjID);
ALTER TABLE CountData
ADD CONSTRAINT Project_CountData
FOREIGN KEY (ProjID)
REFERENCES Project;
CREATE EXCEPTION ERWIN_PARENT_INSERT_RESTRICT "Cannot INSERT Parent table because Child table exists.";
CREATE EXCEPTION ERWIN_PARENT_UPDATE_RESTRICT "Cannot UPDATE Parent table because Child table exists.";
CREATE EXCEPTION ERWIN_PARENT_DELETE_RESTRICT "Cannot DELETE Parent table because Child table exists.";
CREATE EXCEPTION ERWIN_CHILD_INSERT_RESTRICT "Cannot INSERT Child table because Parent table does not exist.";
CREATE EXCEPTION ERWIN_CHILD_UPDATE_RESTRICT "Cannot UPDATE Child table because Parent table does not exist.";
CREATE EXCEPTION ERWIN_CHILD_DELETE_RESTRICT "Cannot DELETE Child table because Parent table does not exist.";
SET TERM ^;
CREATE TRIGGER tI_CountData FOR CountData AFTER INSERT AS
DECLARE VARIABLE numrows INTEGER;
BEGIN
select count(*)
from Project
where
NEW.ProjID = Project.ProjID into numrows;
IF (
NEW.ProjID is not null and
numrows = 0
) THEN
BEGIN
EXCEPTION ERWIN_CHILD_INSERT_RESTRICT;
END
END ^
CREATE TRIGGER tU_CountData FOR CountData AFTER UPDATE AS
DECLARE VARIABLE numrows INTEGER;
BEGIN
select count(*)
from Project
where
NEW.ProjID = Project.ProjID into numrows;
IF (
NEW.ProjID is not null and
numrows = 0
) THEN
BEGIN
EXCEPTION ERWIN_CHILD_UPDATE_RESTRICT;
END
END ^
CREATE TRIGGER tD_Project FOR Project AFTER DELETE AS
DECLARE VARIABLE numrows INTEGER;
BEGIN
select count(*)
from CountData
where
CountData.ProjID = OLD.ProjID into numrows;
IF (numrows > 0) THEN
BEGIN
EXCEPTION ERWIN_PARENT_DELETE_RESTRICT;
END
END ^
CREATE TRIGGER tU_Project FOR Project AFTER UPDATE AS
DECLARE VARIABLE numrows INTEGER;
BEGIN
IF
(OLD.ProjID <> NEW.ProjID) THEN
BEGIN
update CountData
set
CountData.ProjID = NEW.ProjID
where
CountData.ProjID = OLD.ProjID;
END
END ^
Триггера и хранимые процедуры
Уникальные IP-адреса
Уникальные IP-адреса будут фиксироваться автоматически базой данных. Для этого мы напишем пару триггеров.
Триггер вставки уникальных IP-адресов:
CREATE TRIGGER RTI_COUNTDATA FOR COUNTDATA BEFORE INSERT POSITION 0 AS
DECLARE VARIABLE CNT INTEGER;
BEGIN
NEW.COUNTDATAID=GEN_ID(GCountDataID,1);
NEW.DATEHINT="TODAY";
NEW.FULLDATE="NOW";
SELECT COUNT(*)
FROM IPTABLE
WHERE (IPUSER=NEW.IPUSER)
AND(PROJID=NEW.PROJID)
INTO CNT;
IF (CNT=0) THEN
INSERT INTO IPTABLE (IPUSER, PROJID)
VALUES (NEW.IPUSER, NEW.PROJID);
END
^
Триггер заполнения даты уникального IP-адреса:
CREATE TRIGGER RTI_IPTABLE FOR IPTABLE BEFORE INSERT POSITION 0 AS
BEGIN
NEW.DATEADD="TODAY";
END
Регистрация пользователя в базе данных
Теперь создадим хранимую процедуру для регистрации пользователя в базе данных и получения статистической информации о посещениях.
/*********************************************/
/* Процедура регистрации посетителя интернет странички */
/*********************************************/
CREATE PROCEDURE PROC_COUNT_DATA
(PROJID INTEGER,
URLFROM VARCHAR(1024),
URLCURR VARCHAR(1024),
IPUSER VARCHAR(15),
BROWSER VARCHAR(255),
SYSTEMUSER VARCHAR(255),
SYSTEMVER VARCHAR(255),
COMPNAME VARCHAR(255)
)
RETURNS (
MINDATE DATE, /* Дата установки счётчика */
NUMBER_ZAGRUZK INTEGER, /* Количество загрузок */
NUMBER_UN_ZAGRUZK INTEGER, /* Количество уникальных загрузок */
NUMBER_ZAGR_DATE INTEGER, /* Количество загрузок сегодня */
NUMBER_ZAGR_UN_DATE INTEGER) /* Количество уникальных загрузок */
AS
BEGIN
INSERT INTO COUNTDATA (PROJID, URLFROM, URLCURR, IPUSER,
BROWSER, SYSTEMUSER, SYSTEMVER, COMPNAME)
VALUES (:PROJID, :URLFROM, :URLCURR, :IPUSER,
:BROWSER, :SYSTEMUSER, :SYSTEMVER, :COMPNAME);
/* Время установки счётчика */
SELECT MIN(DATEHINT)
FROM COUNTDATA
INTO :MINDATE;
IF (MINDATE IS NULL) THEN MINDATE="TODAY";
/* Колчичество загрузок */
SELECT COUNT(*)
FROM COUNTDATA
INTO :NUMBER_ZAGRUZK;
/* Количество уникальных загрузок */
SELECT COUNT(*)
FROM IPTABLE
INTO :NUMBER_UN_ZAGRUZK;
/* Колчичество загрузок сегодня */
SELECT COUNT(*)
FROM COUNTDATA
WHERE DATEHINT="TODAY"
INTO :NUMBER_ZAGR_DATE;
/* Количество уникальных загрузок сегодня */
SELECT COUNT(*)
FROM IPTABLE
WHERE DATEADD="TODAY"
INTO :NUMBER_ZAGR_UN_DATE;
SUSPEND;
END
^
Расшифруем передаваемые поля процедуре:
PROJID – ID проекта (счётчика),
URLFROM – откуда пришли,
URLCURR – куда пришли,
IPUSER – IP-адрес пользователя,
BROWSER - браузер,
SYSTEMUSER – операционная система пользователя,
SYSTEMVER – версия операционной системы пользователя,
COMPNAME – название компьютера.
Процедура возвращает статистическую информацию:
MINDATE - дата установки счётчика,
NUMBER_ZAGRUZK INTEGER – общее количество загрузок,
NUMBER_UN_ZAGRUZK INTEGER – общее количество уникальных загрузок,
NUMBER_ZAGR_DATE INTEGER - количество загрузок за сегодня,
NUMBER_ZAGR_UN_DATE INTEGER) - Количество уникальных загрузок за сегодня.
Получение списка повторных посетителей
Хранимая процедура для получения списка повторных посетителей
/*****************************************/
/* Процедура для извлечения повторных посетителей */
/*****************************************/
CREATE PROCEDURE POVTOR_POSETIT
(PROJID INTEGER,
DATEOT DATE,
DATEDO DATE
)
RETURNS (
IPUSER VARCHAR(15)
)
AS
BEGIN
FOR SELECT C.IPUSER
FROM COUNTDATA C
WHERE (C.DATEHINT>=:DATEOT)
AND(C.DATEHINT<=:DATEDO)
AND(C.PROJID>=:PROJID)
AND(C.IPUSER NOT IN (SELECT IT.IPUSER
FROM IPTABLE IT
WHERE (IT.DATEADD>=:DATEOT)
AND(IT.DATEADD<=:DATEDO)
AND(IT.PROJID=:PROJID)
))
GROUP BY C.IPUSER
INTO :IPUSER
DO
BEGIN
SUSPEND;
END
END
^
Процедуре мы передаём диапазон за который хотим посмотреть статистику, а она возвращает IP-адреса пользователей, которые повторно посетили наш сайт.
Статистика посещений по дням
Хранимая процедура для расчёты статистики посещений по дням:
/*****************************************/
/* Статистика посещений по дням */
/*****************************************/
CREATE PROCEDURE STAT_DAY
(PROJID INTEGER,
DATEOT DATE,
DATEDO DATE
)
RETURNS (
DATE_POSETIT DATE, /* Дата посещения */
KOL_POSESCH INTEGER,/* Количество посещений */
KOL_UNIKALN INTEGER, /* Количество уникальных загрузок */
KOL_POVTORN_POSET INTEGER /* Количество повторных посетителей */
)
AS
BEGIN
FOR SELECT DATEHINT
FROM COUNTDATA
WHERE (PROJID=:PROJID)
AND(DATEHINT>=:DATEOT)
AND(DATEHINT<=:DATEDO)
GROUP BY DATEHINT
INTO :DATE_POSETIT
DO
BEGIN
/* Колчичество загрузок */
SELECT COUNT(*)
FROM COUNTDATA
WHERE DATEHINT=:DATE_POSETIT
INTO :KOL_POSESCH;
/* Количество уникальных загрузок */
SELECT COUNT(*)
FROM IPTABLE
WHERE DATEADD=:DATE_POSETIT
INTO :KOL_UNIKALN;
SELECT COUNT(*)
FROM POVTOR_POSETIT(:PROJID, :DATE_POSETIT, :DATE_POSETIT)
INTO KOL_POVTORN_POSET;
SUSPEND;
END
END
^
Лучшие ссылки на сайт
Хранимая процедура для получения лучших ссылок на сайт
/**************************************/
/* Лучшая ссылка на наш сайт */
/**************************************/
CREATE PROCEDURE BEST_LINK
(PROJID INTEGER,
DATEOT DATE,
DATEDO DATE
)
RETURNS (
URLFROM VARCHAR(1024),
COUNT_URLS INTEGER
)
AS
BEGIN
FOR SELECT URLFROM, COUNT(*) COUNT_URLS
FROM COUNTDATA
where (PROJID=:PROJID)
And(DATEHINT>=:DateOt)
And(DATEHINT<=:DateDo)
GROUP BY URLFROM
INTO :URLFROM, :COUNT_URLS
DO
BEGIN
SUSPEND;
END
END
^
Лучшая интернет-страница
Хранимая процедура для получения статистики по посещаемости наших страниц:
/*************************************/
/* Лучшая наша страничка */
/*************************************/
CREATE PROCEDURE BEST_PAGE
(PROJID INTEGER,
DATEOT DATE,
DATEDO DATE
)
RETURNS (
URLCURR VARCHAR(1024),
COUNT_URLS INTEGER
)
AS
BEGIN
FOR SELECT URLCURR, COUNT(*) COUNT_URLS
FROM COUNTDATA
where (PROJID=:PROJID)
And(DATEHINT>=:DateOt)
And(DATEHINT<=:DateDo)
GROUP BY URLCURR
INTO :URLCURR, :COUNT_URLS
DO
BEGIN
SUSPEND;
END
END
^
На нашем сервере
(код на PHP)
Прежде всего, необходимо настроить Apache на нашем сервере. Как его устанавливать и настраивать Вы можете во многочисленных статьях интернета.
Скрипт для подключения к нашей базе данных InterBase, передачи информации о пользователе и получения статистической информации.
acounter.php
<?php
/*include("config.php");*/
include "classdb.php3";
class acounter {
var $config = array();
var $conn;
var $dbname;
var $dbuser;
var $dbpass;
var $NUMBER_ZAGRUZK;
var $NUMBER_UN_ZAGRUZK;
var $NUMBER_ZAGR_DATE;
var $NUMBER_ZAGR_UN_DATE;
var $MINDATE;
var $okrugl;
function acounter () {
/*Подключение к БД*/
include "config.php";
$this->okrugl = $okrugl;
$this->dbname = $dbname;
$this->dbuser = $dbuser;
$this->dbpass = $dbpass;
$this->conn=ibase_connect($this->dbname,$this->dbuser,
$this->dbpass);
/* URL to the digitset */
$this->config['img'] = "http://MySite.com.ua/MyCounter/digits/";
/* URL to the animated digitset */
$this->config['animated_img'] = "http://MySite.com.ua/MyCounter/digits_ani/";
/* How many digits to show */
$this->config['pad'] = 6;
/* digit width and height */
$this->config['width'] = 16;
$this->config['height'] = 22;
/* timeout (minutes) */
$this->config['block_time'] = 15;
}
//Получает количество записей в таблице CountData(количество посещений)
function ibase_fetch_array($res) {
return get_object_vars(ibase_fetch_object($res));
}
function ibase_num_rows($query) {
$i=0;
while (ibase_fetch_row($query)){
$i++;}
return $i;
}
function GetCounterValue() {
$sqlExpr="select * from CountData";
$sth = ibase_query($this->conn,$sqlExpr);
$CounterValue=$this->ibase_num_rows($sth);
return $CounterValue;
}
//
function InsertData($ip='',$urlFrom='',$urlCurr='',$host='') {
//Beru vid brausera, versiu brauzera, platformu mashini;
$info=getenv("HTTP_USER_AGENT");
// $urlFrom=getenv("HTTP_REFERER");
$Gateway=getenv("GATEWAY_INTERFACE");
$Connect=getenv("SERVER_PROTOCOL");
//Beru ip-adres;
// $ip = getenv("REMOTE_ADDR");
$db = new CConnectionIBase();
$sqlExpr="SELECT * FROM PROC_COUNT_DATA(1, '".$urlFrom."'
, '".$urlCurr."', '".$ip."', '', '".$info."', '','".$host."')";
$sth = ibase_query($this->conn,$sqlExpr);
$mas=$this->ibase_fetch_array($sth);
$this->NUMBER_ZAGRUZK = $mas[NUMBER_ZAGRUZK];
$this->NUMBER_UN_ZAGRUZK = $mas[NUMBER_UN_ZAGRUZK];
$this->NUMBER_ZAGR_DATE = $mas[NUMBER_ZAGR_DATE];
$this->NUMBER_ZAGR_UN_DATE = $mas[NUMBER_ZAGR_UN_DATE];
$this->MINDATE = $mas[MINDATE];
}
function create_output($ip='',$urlFrom='',$urlCurr='',$host='') {
$this->InsertData($ip,$urlFrom,$urlCurr,$host);
//Vivogu Col. zagruzok
$html_output = "<table cellpadding=\"0\" cellspacing=
\"0\" border=\"0\"><tr>\n";
$html_output .="<font size='1' color='#0000FF'>
Всего загрузок:</font></tr>\n<tr align=\"center\">\n";
$html_output .= "<font size='3' color='#800080'>
<b>".sprintf($this->okrugl,$this->NUMBER_ZAGRUZK)."</b></font>";
$html_output .= "</tr></table>\n";
//Vivogu col. unikalnih zagruzok
$html_output .= "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\"><tr>\n";
$html_output .="<font size='1' color='#0000FF'>
Всего уникальных загрузок:</font></tr>\n<tr align=\"center\">\n";
$html_output .= "<font size='3' color='#800080'>
<b>".sprintf($this->okrugl,$this->NUMBER_UN_ZAGRUZK).
"</b></font>";
$html_output .= "</tr></table>\n";
//Vivogu col. zagruzok segodnia
$html_output .= "<table cellpadding=\"0\"
cellspacing=\"0\" border=\"0\"><tr>\n";
$html_output .="<font size='1' color='#0000FF'>
Загрузок за день:</font></tr>\n<tr align=\"center\">\n";
$html_output .= "<font size='3' color='#800080'>
<b>".sprintf($this->okrugl,$this->NUMBER_ZAGR_DATE).
"</b></font>";
$html_output .= "</tr></table>\n";
//Vivogu col. unikalnih zagruzok segodnia
$html_output .= "<table cellpadding=\"0\"
cellspacing=\"0\" border=\"0\"><tr>\n";
$html_output .="<font size='1' color='#0000FF'>
Уникальных загрузок за день:</font></tr>\n
<tr align=\"center\">\n";
$html_output .= "<p align='center'><font size='3' color='#800080'><b>".sprintf($this->okrugl,$this
->NUMBER_ZAGR_UN_DATE)."</b></font></p>";
$html_output .= "</tr></table>\n";
//Vivogu datu ustanovki schetchika
$html_output .= "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\"><tr>\n";
$html_output .="<font size='1' color='#0000FF'>
Дата установки счётчика:</font></tr>\n<tr align=\"center\">\n";
$str=substr($this->MINDATE,0,10);
$html_output .= "<font size='1' color='#800080'>".$str."</font>";
$html_output .= "</tr></table>\n";
return $html_output;
}
}
?>
classdb.php3
<?php
//-------------------------------------------------------------
class CConnection {
var $err_logon = "Can't connect to database %s!";
var $descriptor = 0; // database descriptor
var $result; // result array
var $countRow = 0; // number of records in result array
var $countField = 0; // number of fields in result array
// Clears result array. For internal use.
function freeQuery() {
unset($this->result);
$this->countRow = 0;
$this->countField = 0;
}
// Returns content of specified cell of result array or null if $col or
// $row is wrong.
// $col can to hold the field name or field index
function getData($col, $row) {
if ((0 <= $row) && ($row < $this->countRow)) {
if (!is_string($col)) {
reset($this->result);
for ($fno = 0; $fno < $col; $fno++) next($this->result);
$col = current($this->result);
return $col[$row];
} else return $this->result[strtoupper($col)][$row];
} else return null;
}
// Returns field name by field index or empty string if $col is wrong
function getFieldName($col) {
if (is_integer($col) && (0 <= $col) && ($col < $this->countField)) {
reset($this->result);
for ($fno = 0; $fno < $col; $fno++) next($this->result);
list($key, $val) = each($this->result);
return $key;
} else return "";
}
}
//----------------------------------------------------------------------
class CConnectionIBase extends CConnection {
// Constructor. Creates class.
function CConnectionIBase() {}
// Opens specified database.
// Returns database descriptor.
function open($database, $username = "sysdba",
$password = "masterkey", $charset="WIN1251") {
$this->close();
$this->descriptor = ibase_connect($database,
$username, $password, $charset);
return $this->descriptor;
}
// Closes current database connection
function close() {
if ($this->descriptor) {
$this->freeQuery();
ibase_close($this->descriptor);
$this->descriptor = 0;
}
}
// Prepares data to storing in BLOBs. Used in query & execute functions
// Returns query statement descriptor
function execCode($code, $blobs=0) {
$statement = 0;
$this->freeQuery();
if ($this->descriptor) {
$cmd = "$"."statement = ibase_query("."$".
"this->descriptor, "."$"."code";
if (is_array($blobs) && count($blobs)) {
reset($blobs);
$fno = 0;
while (list($key, $val) = each($blobs)) {
$finfo[$fno] = array("blob_id" =>
ibase_blob_create(), "blob_str" => "");
if (is_string($val)) ibase_blob_add($finfo[$fno]["blob_id"], $val);
else ibase_blob_add($finfo[$fno]["blob_id"],
"Not supported yet, sorry");
$finfo[$fno]["blob_str"] = ibase_blob_close($finfo[$fno]["blob_id"]);
$cmd = $cmd.", $"."finfo[$fno][\"blob_str\"]";
$fno++;
}
}
$cmd = $cmd.");";
eval($cmd);
}
return $statement;
}
// Executes SELECT statement and fills result array by dataset contents
// Returns number of records placed to result array
function query($code, $blobs=0) {
if ($statement = $this->execCode($code, $blobs)) {
while ($row = ibase_fetch_row($statement)) {
while(list($fno, $val) = each($row)) {
// Getting information about fields existing in current row
if ($this->countField < count($row)) $this->countField = count($row);
$finfo = ibase_field_info($statement, $fno);
$fname = $finfo["alias"];
$ftype = $finfo["type"];
unset($finfo);
if (!strcmp($ftype, "BLOB")) {
// Getting data from BLOB field
if (($finfo = ibase_blob_info($val)) &&
($finfo["length"] > 0) &&
($val = ibase_blob_open($val))) {
$blob = ibase_blob_get($val, $finfo["length"]);
ibase_blob_close($val);
} else $blob = "";
$this->result[$fname][$this->countRow] = $blob;
unset($blob);
} else {
// Getting data from another field
if (isset($val)) {
if (is_string($val))
$this->result[$fname][$this->countRow] = trim($val);
else $this->result[$fname][$this->countRow] = $val;
} else $this->result[$fname][$this->countRow] = "";
}
}
$this->countRow++;
// Cleaning temporary variables
unset($row);
unset($fno);
unset($val);
unset($finfo);
unset($fname);
unset($ftype);
}
ibase_free_result($statement);
unset($statement);
}
return $this->countRow;
}
// Executes INSERT, DELETE or UPDATE statements. Result array is empty.
// Returns nonzero if all OK
function execute($code, $blobs=0) {
if ($statement = $this->execCode($code, $blobs)) {
@ibase_free_result($statement);
return 1;
}
return 0;
}
// Commits current transaction
function commit() { ibase_commit(); }
// Rollbacks current transaction
function rollback() { ibase_rollback(); }
}
//------------------------------------------------------------------
class CConnectionOCI extends CConnection {
function CConnectionOCI() {}
function open($database = "", $username = "system",
$password = "manager") {
$this->close();
if (($database) && strlen($database))
$this->descriptor = OCILogon($username, $password, $database);
else $this->descriptor = OCILogon($username, $password);
return $this->descriptor;
}
function close() {
if ($this->descriptor) {
$this->freeQuery();
OCILogOff($this->descriptor);
$this->descriptor = 0;
}
}
function query($code) {
$this->freeQuery();
if ($this->descriptor) {
if ($code && ($statement = OCIParse($this->descriptor, $code))) {
OCIExecute($statement, OCI_DEFAULT);
$this->countRow = OCIFetchStatement($statement, $this->result);
$this->countField = count($this->result);
OCIFreeStatement($statement);
}
}
return $this->countRow;
}
function execute($code, $blob=0) {
$res = 0;
$this->freeQuery();
if ($this->descriptor) {
if ($code) {
if ($blob) $lob = OCINewDescriptor($this->descriptor, OCI_D_LOB);
if ($statement = OCIParse($this->descriptor, $code)) {
if ($blob) OCIBindByName($statement, ":blob", &$lob, -1,
OCI_B_CLOB);
OCIExecute($statement, OCI_DEFAULT);
if ($lob) {
if ($lob->save($blob)) $res = 1;
OCIFreeDescriptor($lob);
} else $res = 1;
OCIFreeStatement($statement);
}
}
}
return $res;
}
function commit() {
if ($this->descriptor) OCICommit($this->descriptor);
}
function rollback() {
if ($this->descriptor) OCIRollback($this->descriptor);
}
}
//----------------------------------------------------------------------
?>
Файл для конфигурирования счётчика:
config.php
<?
$dbname = "Server:C:\DataBase\Counter.GDB";
$dbuser = "SYSDBA";
$dbpass = "masterkey";
$okrugl = "%07s";
?>
$dbname – название базы данных,
$dbuser- имя пользователя InterBase,
$dbpass – пароль,
$okrugl – количество цифр в счётчики (например, 0000012).
Файл, который вызывается из интернет-страницы:
test.php
<?php
include_once "acounter.php";
$ani_counter = new acounter();
echo $ani_counter->create_output($_GET["ip"],$_GET["urlFrom"]
,$_GET["urlCurr"],$_GET["host"]);
?>
На интернет-странице (код на PHP)
Эта часть находится на сервере провайдера (там, где находится наша интернет-страница).
Создаём скрипт для определения данных о пользователе:
Counter.inc
<?php
// phpinfo();
//Beru vid brausera, versiu brauzera, platformu mashini;
$info=getenv("HTTP_USER_AGENT");
$urlFrom=getenv("HTTP_REFERER");
$urlCurr=$_SERVER["REQUEST_URI"];
$host=getenv("HTTP_HOST");
//Beru ip-adres;
$ip = getenv("REMOTE_ADDR");
readfile('http://client70.ukrtelebud.com.ua/
RudjukCounter/test.php?ip='.
$ip.'&urlFrom='.$urlFrom.'&urlCurr='.$urlCurr.'&host='.$host);
// readfile('http://MySite.com.ua/MyCounter/test.php?ip='
.$ip.'&urlFrom='.$urlFrom);
// readfile('http://MySite.com.ua/MyCounter/test.php')
?>
На самой интернет-странице прописываем скрипт, который и будет запускать весь счётчик:
<?php
include ("counter_inc.php")
?>
Примечание: Для того, чтобы счётчик работал корректно необходимо файлы интернет-страницы называть с расширением php, а не htm.
Клиентская часть
Саму обработку статистических данных удобнее всего сделать на Delphi.
Реализацию на Delphi я оставляю читателю, приведу лишь SQL-запросы для получения необходимых данных.
SQL-запросы
Получение подробной информации о посетителях:
select *
from COUNTDATA
where (PROJID=:PROJID)
And(DATEHINT>=:DateOt)
And(DATEHINT<=:DateDo)
ORDER BY COUNTDATAID
Статистика по дням:
SELECT *
FROM STAT_DAY(:ProjID, :DateOt, :DateDo) ORDER BY DATE_POSETIT
Лучшие ссылки на интернет-страницу:
SELECT *
FROM BEST_LINK(:ProjID, :DateOt, :DateDo)
ORDER BY COUNT_URLS DESC
Лучшие интернет-страницы:
SELECT *
FROM BEST_PAGE(:ProjID, :DateOt, :DateDo) ORDER BY COUNT_URLS DESC
Уникальные IP-адреса:
select *
from IPTable
where (ProjID=:ProjID)
And(DateAdd>=:DateOt)
And(DateAdd<=:DateDo)
IP-адреса повторных посетителей:
SELECT *
FROM POVTOR_POSETIT(:ProjID, :DateOt, :DateDo) ORDER BY IPUSER
Вот что получилось
Получение подробной информации о посетителях:
Статистика по дням:
Лучшие ссылки:
Лучшие страницы:
Уникальные IP-адреса:
Повторные IP-адреса:
Заключение
В программе есть ряд неточностей, а так же не определяются страны по IP-адресу. Эти задачи я оставляю за читателями.
Скачать текст Php-программ и SQL-скрипты Вы можете на http://old.rudjuk.kiev.ua/downloads/InetCounter/InetCounter.exe
Авторы: Рудюк С.А
Лутай Д.А.
|