64 (+1)

Counter@PHP

Использование счетчиков для анализа посещаемости сайта
Общие принципы функционирования и типы счетчиков
Создание сложных текстовых и графических счетчиков

Поиск по сайтуДля желающих написать письмоПослать ссылку другуВерсия для распечатки




Часть III

Счетчик на несколько страниц

Как сделать простой счетчик, мы теперь знаем, но что если мы хотим обсчитывать сразу несколько страниц? Ведь интересно знать, какая страничка на сайте самая популярная, а какая наоборот. Счетчик, который мы только что написали, для этих целей не подходит, т.к. умеет обсчитывать только одну страницу. А значит, нам нужно модифицировать предыдущий скрипт таким образом, чтобы одним фрагментом кода можно было обсчитывать любое количество страничек.

Для того чтобы обсчитывать несколько страничек, нам необходимо для каждой из них завести свой отдельный счетчик. Будем все счетчики хранить в одном файле - по одной записи на каждую страницу. Большая часть работы нами уже проделана, и нужно только модифицировать часть кода, ответственную за загрузку информации из файла и за сохранение информации в файле. Но давайте сначала, как и в предыдущих случаях, сформулируем алгоритм работы нового счетчика:

  1. Прочитать файл в построчный массив, хранящий информацию о счетчиках;
  2. Найти нужную строку и прочитать содержимое счетчика;
  3. Увеличить значение счетчика (как общего, так и счетчика за сегодня)
  4. Обновить в построчном массиве содержимое строки, относящейся к текущей странице;
  5. Сохранить построчный массив, хранящий информацию о счетчиках;
  6. Вывести на печать значение счетчика, относящегося к текущей странице.

Вначале разберемся с функцией чтения информации из файла. До сих пор я использовал стандартную функцию чтения информации из файла fread(), но теперь нам больше подойдет функция file(), которая просто читает содержимое любого файла и сохраняет его в массиве - по одной строке в каждой ячейке. То есть именно то, что нам и нужно! В качестве параметра ей передается путь к файлу, который нужно прочитать. Никаких дополнительных действий по получению дескриптора файла, его открытию, закрытию и прочего делать не нужно. По этой причине PHP-код для чтения информации о счетчиках из файла будет исключительно компактным:

<?

// Имя файла, в котором хранится счетчик
$file_counter = "counter.txt";

// Читаем информацию о счетчиках в построчный массив
$counters = @file($file_counter);

?>

Обратите внимание, что, в отличие от предыдущих счетчиков, я уже не проверяю наличие в системе файла с данными, т.к. это делает сама функция file(). В случае, если файл отсутствует, данная функция просто вернет пустую строку и выведет на экран сообщение об ошибке. Нам, в данном случае, это сообщение не нужно, поэтому мы подавляем его при помощи символа "@", указанного перед названием функции. Кстати, этот прием можно использовать и для подавления печати любых других сообщений в вызываемых функциях.

В связи с тем, что нам теперь необходимо обсчитывать несколько страничек, в дополнение к уже имеющимся переменным (общий счетчик, счетчик за сегодня и дата последнего посещения) добавим еще одну, в которой будет храниться URL странички. Теперь для того, чтобы найти в массиве счетчиков нужный, необходимо просто просмотреть весь массив построчно и найти такую запись, у которой значение переменной $counter["url"] совпадает с URL текущей страницы.

<?

// Флаг нахождения нужной записи
$flag = 0;

// Проверяем, обсчитывалась ли эта страничка ранее
reset($counters);    
while (list($key, $value) = each($counters)) {

    // Распаковываем строку записи в массив с параметрами счетчика
    $temp_counter = explode(" | ", trim($value));
    $counter = array(
        "url"   => $temp_counter[0],
        "total" => $temp_counter[1],
        "today" => $temp_counter[2],
        "date"  => $temp_counter[3]
    );
    
    // Проверяем, совпадает ли адрес счетчика с адресом текущей страницы
    if ($counter["url"] == $REQUEST_URI) {

        // Если совпадает, значит, мы нашли нужный счетчик
        $flag = 1;
        break;
    }
}

?>

Данный код требует некоторых пояснений. Во-первых, каким образом можно обойти все элементы массива? А во-вторых, как среди них найти нужный? Как я уже говорил ранее, в PHP используются ассоциативные массивы. При этом в качестве индекса в них может выступать любое число или строка. Более того, записи в ассоциативном массиве могут повторяться. Для того чтобы просмотреть все записи в ассоциативном массиве, используется следующий вариант цикла:

<?

reset($array);    
while (list($key, $value) = each($array)) {

    // Здесь делаем с элементом массива то, что нам нужно
}

?>

В первой строке вызывается функция reset(), которая позиционирует внутренний указатель ассоциативного массива на первый элемент. Это гарантирует, что мы начинаем обход массива с начала. Далее запускается цикл while(), в качестве параметра которого используется конструкция:

list($key, $value) = each($array)

Функция each() читает очередной элемент массива и затем автоматически увеличивает внутренний указатель массива таким образом, чтобы он показывал на следующий элемент. Как только все элементы массива будут исчерпаны, функция each() вернет false и цикл завершится.

Для присвоения значений сразу нескольким переменным используется конструкция list(). В данном случае функция each() возвращает два значения: ключ и собственно элемент массива. Причем именно в таком порядке. Эти значения мы и присваиваем переменным $key и $value соответственно. Другими словами, после этой операции, в переменной $key будет храниться номер строки, а в переменной $value - сама строка.

После того как строка была прочитана, мы, уже знакомым нам способом, распаковываем ее в массив, описывающий счетчик:

<?

// Распаковываем строку записи в массив с параметрами счетчика
$temp_counter = explode(" | ", trim($value));
$counter = array(
    "url"   => $temp_counter[0],
    "total" => $temp_counter[1],
    "today" => $temp_counter[2],
    "date"  => $temp_counter[3]
);

?>

Отметьте только, что, во-первых, перед тем как распаковывать строку, я удаляю символ конца строки "\r\n" при помощи функции trim(). Символы конца строк у нас появляются в момент сохранения нескольких счетчиков в одном файле. Ориентируясь по ним, мы впоследствии и можем разбить файл на отдельные строки. Но перед тем как распаковывать данные, нам необходимо концы строк удалить, а иначе переменная будет содержать лишние символы. Во-вторых, не забудьте, что у нас появилась новая переменная для каждого счетчика, и поэтому конструкция формирования массива несколько расширилась. При этом критично соблюдать порядок элементов массива, т.к. именно в таком порядке данные будут храниться в файле.


Нахождение нужного счетчика



Осталось разобраться с вопросом, а каким образом можно определить адрес текущей странички? Дело в том, что при любом запросе странички посылаются также и данные, описывающие эту страничку, а также ряд других системных переменных. Для того чтобы увидеть список этих переменных, в PHP существует очень полезная функция phpinfo(), которая при своем вызове выводит на печать табличку со всеми переменными окружения и их значениями. Вы можете создать простой файл с названием phpinfo.php, в котором написать вызов данной функции:

<?
    phpinfo();
?>

В данном случае нам необходимо знать, что адрес текущей странички хранится в глобальной переменной $REQUEST_URI. Именно ее мы и будем использовать при нахождении нужного счетчика. Данный фрагмент кода уже был приведен выше, но я его продублирую здесь:

<?

// Флаг нахождения нужной записи
$flag = 0;

...
    // Проверяем, совпадает ли адрес счетчика с адресом текущей страницы
    if ($counter["url"] == $REQUEST_URI) {

        // Если совпадает, значит, мы нашли нужный счетчик
        $flag = 1;
        break;
    }
...

?>

Далее я опускаю весь код, который увеличивает счетчики и обновляет дату последнего обращения к страничке, т.к. он полностью совпадает с тем, что мы разобрали ранее. Продолжим с того момента, когда нам нужно упаковать скорректированный счетчик обратно в строку и сохранить изменения в файле.

Итак, у нас есть массив, содержащий параметры счетчика, и следующим шагом нам необходимо его вернуть обратно в массив всех счетчиков. В случае если мы корректируем значение странички, которая ранее обсчитывалась, нам необходимо изменить именно ту строку, в которой находилось описание этой странички. Как же ее найти? Это несложно, т.к. ее номер после нахождения хранится в переменной $key. А следовательно, необходимый нам код будет выглядеть следующим образом:

<?

// Формируем обновленную строку в массиве счетчиков
$counters[$key] = implode(" | ", $counter);

?>

В случае же, если страница ранее не обсчитывалась, нам необходимо предварительно создать нужное описание счетчика. После чего добавить его к общему массиву счетчиков:

<?

// Формируем новый массив с параметрами счетчика
$counter = array(
    "url"   => $REQUEST_URI,
    "total" => 1,
    "today" => 1,
    "date"  => $current_date
);

// Формируем новую строку с описанием счетчика и добавляем ее в массив
$counters[] = implode(" | ", $counter);

?>

Осталось сохранить обновленные данные в файле. Сохранять нужно будет построчно все элементы общего массива счетчиков, т.к. измениться могла любая строка. Равно как могли добавиться и новые строки. И главное, нужно не забыть добавить в конце каждого сохраняемого элемента массива признак конца строки. Я об этом уже упоминал ранее. Полный код, ответственный за сохранение массива счетчиков, будет выглядеть следующим образом:

<?

// Открываем файл для записи
$fp = fopen($file_counter, "w");

// Сохраняем обновленный массив счетчиков
reset($counters);    
while (list($key, $value) = each($counters)) {
    fwrite($fp, trim($value)."\r\n");
}

// Закрываем файл
fclose($fp);

?>

Подключение счетчика к нескольким страницам



Ну что же, счетчик у нас написан, и осталось подключить его ко всем страничкам, которые мы хотим обсчитывать. Но как лучше всего это сделать? Не размещать же на каждой из них громоздкий код? Разумеется, нет. Достаточно преобразовать разобранный выше код в функцию, вынести ее в отдельный файл и подключить ко всем страничкам. Печать же значения счетчика можно осуществить, вызывая функцию, которую можно назвать, скажем, print_counter(). Таким образом, любая страничка, которую мы хотим обсчитывать, будет иметь следующую структуру:

<?
    // Подключаем внешние скрипты
    require("counter.php");
?>
<html>
<head>
<title>Обсчитываемая страничка</title>
</head>

<body>

<h1>Обсчитываемая страничка</h1>

<? print_counter(); ?>

</body>
</html>

Подключение внешних PHP-файлов делается при помощи функции require(), и это очень удобно. Пока у нас во внешнем файле находится только одна функция, но ведь их может быть и гораздо больше! Данный механизм позволяет создать удобную файловую структуру для поддержки сложных проектов.


Часть 1Часть 2Часть 3 - ее Вы читаете сейчасЧасть 4


Свои мнения, пожелания и вопросы по выпускам Вы можете присылать по адресу mike@cherry-design.ru.
Я оставляю за собой право цитировать письма, пришедшие по вышеуказанному адресу.
Copyright © 2001-2008 Михаил Мельников. Перепечатка без разрешения запрещена.