Счётчик
Есть проблема, надеюсь, вы поможете её решить!
Написал, счётчик для страниц, а точнее, сколько раз прочитали. В коде, используется функция flock (запирание файла), записывается и считывается информация, из одного файла. Всё работает нормально, одно время, а потом, файл просто обнуляется, а точнее, в нём, остаётся, всего один символ “|”. Суппорт хостинга, говорит, что это, логическая ошибка скрипта!
Плизззз, гляньте, есть ли в коде ошибка! Я уже, 3 недели парюсь!
Вот код:
Код:
<?
if (@$_REQUEST['id'])
{
$file_counter = "base/counter.dat";
$data='';
if (file_exists($file_counter))
{
$fp = fopen($file_counter, "r+");
while (!feof($fp))
{
list($change1,$change2)=explode("|", fgets($fp));
if (@$_REQUEST['id']==$change1)
{
$counter=$change2;
$counter=$counter+1;
if (!feof($fp))
{
$data=$data.$change1.'|'.$counter."\n";
}
else
{
$data=$data.$change1.'|'.$counter;
}
}
else
{
$data=$data.$change1.'|'.$change2;
}
}
}
fclose($fp);
$fp = fopen($file_counter, "a");
flock($fp,LOCK_EX);
if(flock($fp,LOCK_EX)){
ftruncate($fp,0);
fputs($fp, $data);
flock($fp,LOCK_UN);
fclose($fp);
}
}
?>
if (@$_REQUEST['id'])
{
$file_counter = "base/counter.dat";
$data='';
if (file_exists($file_counter))
{
$fp = fopen($file_counter, "r+");
while (!feof($fp))
{
list($change1,$change2)=explode("|", fgets($fp));
if (@$_REQUEST['id']==$change1)
{
$counter=$change2;
$counter=$counter+1;
if (!feof($fp))
{
$data=$data.$change1.'|'.$counter."\n";
}
else
{
$data=$data.$change1.'|'.$counter;
}
}
else
{
$data=$data.$change1.'|'.$change2;
}
}
}
fclose($fp);
$fp = fopen($file_counter, "a");
flock($fp,LOCK_EX);
if(flock($fp,LOCK_EX)){
ftruncate($fp,0);
fputs($fp, $data);
flock($fp,LOCK_UN);
fclose($fp);
}
}
?>
Попытайся сделать лог на эти движения. огда поймёшь причину.
И ещё: откуда в 15й строке берётся $counter?
И вообще, вспоминаю 1998 год, когда я был не очень хорошо ознакомлен с базами данных и порывался написать всё на куче файлов (писал ещё на Perl-3). Именно так, как ты: сидел и сочинял конструкции с делимитерами "|", расчитывал концы строк... Короче - морока.
Мой тебе совет: присмотрись к функции serialize/unserialize. Не так давно уже такого рода простейший счётчик уже обсасывали тут , и там я предложил конструкцию, которая тебя может заинтересовать. Весь твой счётчик уместится в восемь строк и не надо париться три месяца с флоками.
База, мне не подходят, так как, на сервере есть пхп, но нет мускула!
А могли бы Вы, привести пример, как реализовать мой код при помощи serialize/unserialize?
Так как поиск, ничего не дал!
Сегодня опять всё слитело!!!
Цитата:
Originally posted by Фауст
Спасибо! Попробую разобраться с serialize/unserialize.
База, мне не подходят, так как, на сервере есть пхп, но нет мускула!
А могли бы Вы, привести пример, как реализовать мой код при помощи serialize/unserialize?
Так как поиск, ничего не дал!
Спасибо! Попробую разобраться с serialize/unserialize.
База, мне не подходят, так как, на сервере есть пхп, но нет мускула!
А могли бы Вы, привести пример, как реализовать мой код при помощи serialize/unserialize?
Так как поиск, ничего не дал!
Обратитесь пожалуйста к документации и впредь не нужно кричать
Цитата:
Плиззззз, помогите, очень нужно!!!! Проблему никак не решить! Сегодня опять всё слитело!!!
. Как сочтут нужным, Вам ответят.
Цитата:
Originally posted by Фауст
Плиззззз, помогите, очень нужно!!!! Проблему никак не решить!
Сегодня опять всё слитело!!!
Плиззззз, помогите, очень нужно!!!! Проблему никак не решить!
Сегодня опять всё слитело!!!
Что ж так кричать-то? Мы же тоже человеки, мы же тоже в выходные дни и ночи ходим с дитями в зоопарк и пьём пиво... :D
Вот, на скорую руку набросал:
Код:
class PhaustClickCounter
{
/*Основной класс, определяющий свойства и методы счётчиков*/
/*Определим некоторые константы, необходимые просто для работы
и удобства работы*/
/**
* Этот префикс будем ставить в идентификтор счётчиков,
* чтобы PHP понимал, что мы обращаемся к хэшу, а не к
* нумерованному массиву.
*/
const COUNT_PREFIX = "PAGE_";
/** Имя поля, в котором храним время последнего обновления */
const COUNTERS_LASTUPDATE_FIELD = "LAST_UPDATE";
/**
* Имя поля, в которое впишем имя счётчика
* Зачем это нужно? Ну, например для удобства визуальной
* идентификации при просмотре списка счётчиков
*/
const COUNTER_NAME = "COUNTER_NAME";
/** Имя хэша, в котором собраны показания счётчиков для одного OID */
const COUNTERS_HASH_FIELD = "COUNTERS";
/**
* Имена полей счётчиков
*/
const COUNTER_TOTAL = "Total";
const COUNTER_TODAY = "Today";
const COUNTER_MONTH = "Month";
const COUNTER_YEAR = "Year";
/**
* Хэш, с которым мы работаем
* @var Array
*/
protected $countersHash;
/**
* Сюда мы положим содержимое актуального счётчика
* @var Array
*/
public $actualCounter;
/**
* Текущее время, его засекаем в конструкторе
* @var Integer
*/
protected $actualTime;
/**
* По ссылке установим содержимое массива счётчика
*
* @param $arr Array Ссылка на весь массив из файла
* @param String $index Индекс хэша актуального счётчика
*/
protected function SetActualCounter(&$arr, $index){
if(!isset($arr[$index])) $arr[$index] = $this->InitCounter($index);
$this->actualCounter =& $arr[$index];
}
/**
* Инициализация счётчика
* Используем её, если счётчика ещё нет
*
* @param String $index Имя хэша
* @return Array Инициализированный счётчик
*/
private function InitCounter($index){
return array(
self::COUNTER_NAME => "Страница без названия",
self::COUNTERS_LASTUPDATE_FIELD => $this->actualTime,
self::COUNTERS_HASH_FIELD => array(
self::COUNTER_TOTAL => 0,
self::COUNTER_TODAY => 0,
self::COUNTER_MONTH => 0,
self::COUNTER_YEAR => 0
)
);
}
/* Небольшой агрегатор методов */
protected function CalculateCounters(){
/*Просто увеличиваем общий счётчик*/
++$this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_TOTAL];
$this->AnyDay($this->actualTime, $this->actualCounter[self::COUNTERS_LASTUPDATE_FIELD]);
$this->AnyMonth($this->actualTime, $this->actualCounter[self::COUNTERS_LASTUPDATE_FIELD]);
$this->AnyYear($this->actualTime, $this->actualCounter[self::COUNTERS_LASTUPDATE_FIELD]);
$this->actualCounter[self::COUNTERS_LASTUPDATE_FIELD] = $this->actualTime;
}
/*Методы для вычисления переменных счётчикв*/
private function AnyDay($actualTime, $lastTime){
$endOfDay = mktime(23, 59, 59, date("n", $lastTime), date("j", $lastTime), date("Y", $lastTime));
if($actualTime > $endOfDay) $this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_TODAY] = 0;
++$this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_TODAY];
}
private function AnyMonth($actualTime, $lastTime){
$endOfMonth = mktime(23, 59, 59, date("n", $lastTime), date("t", $lastTime), date("Y", $lastTime));
if($actualTime > $endOfMonth) $this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_MONTH] = 0;
++$this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_MONTH];
}
private function AnyYear($actualTime, $lastTime){
$endOfYear = mktime(23, 59, 59, 12, 31, date("Y", $lastTime));
if($actualTime > $endOfYear) $this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_YEAR] = 0;
++$this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_YEAR];
}
}
class PhaustFileClickCounter extends PhaustClickCounter
{
/**
* Собственно, это и есть файл, в котором храним показания счётчиков.
* @var String
*/
private $cFile;
public function __construct($countersFile, $counterOID){
$this->actualTime = time();
$this->cFile = $countersFile;
$this->GetCounters($this->countersHash);
$this->SetActualCounter($this->countersHash, self::COUNT_PREFIX . $counterOID);
$this->CalculateCounters();
$this->SetCounters();
}
/*Определим методы для работы с файлом данных*/
/**
* Метод записывает массив в переменную $countersHash из файла
*/
private function GetCounters(&$arr){
$arr = unserialize($this->IsArrayFile($this->cFile));
if(!is_array($arr)) $arr = array();
}
/**
* Метод записывает массив из переменной $countersHash в файл
*/
private function SetCounters(){
file_put_contents($this->cFile, serialize($this->countersHash));
}
private function IsArrayFile($fileName){
if(!is_file($fileName)){
file_put_contents($fileName, serialize(array()));
}
return file_get_contents($fileName);
}
}
define("COUNTERS_FILE", $_SERVER['DOCUMENT_ROOT']."/cntrs.dat");
if(isset($_GET['cnt'])){
$cnt = new PhaustFileClickCounter(COUNTERS_FILE, $_GET['cnt']);
echo "
<div>Всего: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_TOTAL]}</div>
<div>Сегодня: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_TODAY]}</div>
<div>В этом месяце: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_MONTH]}</div>
<div>В этом году: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_YEAR]}</div>
";
}
{
/*Основной класс, определяющий свойства и методы счётчиков*/
/*Определим некоторые константы, необходимые просто для работы
и удобства работы*/
/**
* Этот префикс будем ставить в идентификтор счётчиков,
* чтобы PHP понимал, что мы обращаемся к хэшу, а не к
* нумерованному массиву.
*/
const COUNT_PREFIX = "PAGE_";
/** Имя поля, в котором храним время последнего обновления */
const COUNTERS_LASTUPDATE_FIELD = "LAST_UPDATE";
/**
* Имя поля, в которое впишем имя счётчика
* Зачем это нужно? Ну, например для удобства визуальной
* идентификации при просмотре списка счётчиков
*/
const COUNTER_NAME = "COUNTER_NAME";
/** Имя хэша, в котором собраны показания счётчиков для одного OID */
const COUNTERS_HASH_FIELD = "COUNTERS";
/**
* Имена полей счётчиков
*/
const COUNTER_TOTAL = "Total";
const COUNTER_TODAY = "Today";
const COUNTER_MONTH = "Month";
const COUNTER_YEAR = "Year";
/**
* Хэш, с которым мы работаем
* @var Array
*/
protected $countersHash;
/**
* Сюда мы положим содержимое актуального счётчика
* @var Array
*/
public $actualCounter;
/**
* Текущее время, его засекаем в конструкторе
* @var Integer
*/
protected $actualTime;
/**
* По ссылке установим содержимое массива счётчика
*
* @param $arr Array Ссылка на весь массив из файла
* @param String $index Индекс хэша актуального счётчика
*/
protected function SetActualCounter(&$arr, $index){
if(!isset($arr[$index])) $arr[$index] = $this->InitCounter($index);
$this->actualCounter =& $arr[$index];
}
/**
* Инициализация счётчика
* Используем её, если счётчика ещё нет
*
* @param String $index Имя хэша
* @return Array Инициализированный счётчик
*/
private function InitCounter($index){
return array(
self::COUNTER_NAME => "Страница без названия",
self::COUNTERS_LASTUPDATE_FIELD => $this->actualTime,
self::COUNTERS_HASH_FIELD => array(
self::COUNTER_TOTAL => 0,
self::COUNTER_TODAY => 0,
self::COUNTER_MONTH => 0,
self::COUNTER_YEAR => 0
)
);
}
/* Небольшой агрегатор методов */
protected function CalculateCounters(){
/*Просто увеличиваем общий счётчик*/
++$this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_TOTAL];
$this->AnyDay($this->actualTime, $this->actualCounter[self::COUNTERS_LASTUPDATE_FIELD]);
$this->AnyMonth($this->actualTime, $this->actualCounter[self::COUNTERS_LASTUPDATE_FIELD]);
$this->AnyYear($this->actualTime, $this->actualCounter[self::COUNTERS_LASTUPDATE_FIELD]);
$this->actualCounter[self::COUNTERS_LASTUPDATE_FIELD] = $this->actualTime;
}
/*Методы для вычисления переменных счётчикв*/
private function AnyDay($actualTime, $lastTime){
$endOfDay = mktime(23, 59, 59, date("n", $lastTime), date("j", $lastTime), date("Y", $lastTime));
if($actualTime > $endOfDay) $this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_TODAY] = 0;
++$this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_TODAY];
}
private function AnyMonth($actualTime, $lastTime){
$endOfMonth = mktime(23, 59, 59, date("n", $lastTime), date("t", $lastTime), date("Y", $lastTime));
if($actualTime > $endOfMonth) $this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_MONTH] = 0;
++$this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_MONTH];
}
private function AnyYear($actualTime, $lastTime){
$endOfYear = mktime(23, 59, 59, 12, 31, date("Y", $lastTime));
if($actualTime > $endOfYear) $this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_YEAR] = 0;
++$this->actualCounter[self::COUNTERS_HASH_FIELD][self::COUNTER_YEAR];
}
}
class PhaustFileClickCounter extends PhaustClickCounter
{
/**
* Собственно, это и есть файл, в котором храним показания счётчиков.
* @var String
*/
private $cFile;
public function __construct($countersFile, $counterOID){
$this->actualTime = time();
$this->cFile = $countersFile;
$this->GetCounters($this->countersHash);
$this->SetActualCounter($this->countersHash, self::COUNT_PREFIX . $counterOID);
$this->CalculateCounters();
$this->SetCounters();
}
/*Определим методы для работы с файлом данных*/
/**
* Метод записывает массив в переменную $countersHash из файла
*/
private function GetCounters(&$arr){
$arr = unserialize($this->IsArrayFile($this->cFile));
if(!is_array($arr)) $arr = array();
}
/**
* Метод записывает массив из переменной $countersHash в файл
*/
private function SetCounters(){
file_put_contents($this->cFile, serialize($this->countersHash));
}
private function IsArrayFile($fileName){
if(!is_file($fileName)){
file_put_contents($fileName, serialize(array()));
}
return file_get_contents($fileName);
}
}
define("COUNTERS_FILE", $_SERVER['DOCUMENT_ROOT']."/cntrs.dat");
if(isset($_GET['cnt'])){
$cnt = new PhaustFileClickCounter(COUNTERS_FILE, $_GET['cnt']);
echo "
<div>Всего: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_TOTAL]}</div>
<div>Сегодня: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_TODAY]}</div>
<div>В этом месяце: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_MONTH]}</div>
<div>В этом году: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_YEAR]}</div>
";
}
Как мог прокомментировал. Думаю, будет понятно.
Код:
if(isset($_GET['cnt'])){
$cnt = new PhaustFileClickCounter(COUNTERS_FILE, $_GET['cnt']);
echo "
<div>Всего: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_TOTAL]}</div>
<div>Сегодня: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_TODAY]}</div>
<div>В этом месяце: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_MONTH]}</div>
<div>В этом году: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_YEAR]}</div>
";
prer($cnt->countersHash);
}
elseif (isset($_GET['showCounters'])){
$cntArray = unserialize(file_get_contents(COUNTERS_FILE));
echo "
<style>
BODY{
font-family: sans-serif;
font-size: 11px;
}
.headerTD{
background-color: #CCC;
font-weight: bold;
text-align: center;
}
.dataTD{
background-color: #FFF;
font-weight: normal;
text-align: right;
}
</style>
";
echo "<table border=0 cellpadding=0 cellspacing=0 align=center width=600><tr><td bgcolor=#000000>";
echo "<table border=0 cellpadding=3 cellspacing=1 width=100%>";
echo "<tr>
<td class=headerTD>OID</td>
<td class=headerTD>Счётчик</td>
<td class=headerTD>За сегодня</td>
<td class=headerTD>За месяц</td>
<td class=headerTD>За год</td>
<td class=headerTD>Всего</td>
</tr>";
foreach($cntArray as $key=>$row){
echo "
<tr>
<td class=dataTD>$key</td>
<td class=dataTD>{$row[PhaustClickCounter::COUNTER_NAME]}</td>
<td class=dataTD> {$row[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_TODAY]}</td>
<td class=dataTD> {$row[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_MONTH]}</td>
<td class=dataTD> {$row[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_YEAR]}</td>
<td class=dataTD> {$row[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_TOTAL]}</td>
</tr>
";
}
echo "</table>";
echo "</td></tr></table>";
}
$cnt = new PhaustFileClickCounter(COUNTERS_FILE, $_GET['cnt']);
echo "
<div>Всего: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_TOTAL]}</div>
<div>Сегодня: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_TODAY]}</div>
<div>В этом месяце: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_MONTH]}</div>
<div>В этом году: {$cnt->actualCounter[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_YEAR]}</div>
";
prer($cnt->countersHash);
}
elseif (isset($_GET['showCounters'])){
$cntArray = unserialize(file_get_contents(COUNTERS_FILE));
echo "
<style>
BODY{
font-family: sans-serif;
font-size: 11px;
}
.headerTD{
background-color: #CCC;
font-weight: bold;
text-align: center;
}
.dataTD{
background-color: #FFF;
font-weight: normal;
text-align: right;
}
</style>
";
echo "<table border=0 cellpadding=0 cellspacing=0 align=center width=600><tr><td bgcolor=#000000>";
echo "<table border=0 cellpadding=3 cellspacing=1 width=100%>";
echo "<tr>
<td class=headerTD>OID</td>
<td class=headerTD>Счётчик</td>
<td class=headerTD>За сегодня</td>
<td class=headerTD>За месяц</td>
<td class=headerTD>За год</td>
<td class=headerTD>Всего</td>
</tr>";
foreach($cntArray as $key=>$row){
echo "
<tr>
<td class=dataTD>$key</td>
<td class=dataTD>{$row[PhaustClickCounter::COUNTER_NAME]}</td>
<td class=dataTD> {$row[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_TODAY]}</td>
<td class=dataTD> {$row[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_MONTH]}</td>
<td class=dataTD> {$row[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_YEAR]}</td>
<td class=dataTD> {$row[PhaustClickCounter::COUNTERS_HASH_FIELD][PhaustClickCounter::COUNTER_TOTAL]}</td>
</tr>
";
}
echo "</table>";
echo "</td></tr></table>";
}
Вобщем, к счётчику обращаемся, как http://domain.name/script.php?cnt=<номер счётчика>, а для просмотра всех - http://domain.name/script.php?showCounters