<?php
/*
* phpMyVisites : website statistics and audience measurements
* Copyright (C) 2002 - 2006
* http://www.phpmyvisites.net/
* phpMyVisites is free software (license GNU/GPL)
* Authors : phpMyVisites team
*/
// $Id: Archive.class.php 102 2006-10-01 16:28:30Z matthieu_ $
$GLOBALS['test'] = ", sum(case total_pages when 1 then 1 else 0 end) as onepage," .
" sum(total_pages) as sumpage, count(*) as s, sum(total_time) as sumtime";
require_once INCLUDE_PATH."/core/include/Date.class.php";
require_once INCLUDE_PATH."/core/include/Str.class.php";
require_once INCLUDE_PATH."/core/include/Archive.functions.php";
require_once INCLUDE_PATH."/core/include/functions.php";
/**
* Base class used by other ArchiveClass to assign some standard attributes
*
*/
class Archive
{
/**
* @var object Site
*/
var $site;
/**
* @var array fieldName => fieldValue to save in database
*/
var $toRecord; // array 'field_name' => value to record
/**
* @var int Current idarchives of the archive process
*/
var $idArchives;
/**
* @var int State of the current archive process (Must be DB_ARCHIVES_*)
*/
var $state; // DB_x
/**
* @var object Date
*/
var $date;
var $date2;
/**
* @var int Type of the current archive period (Must be DB_ARCHIVES_PERIOD_*)
*/
var $periodType;
// int value
/**
* @var array integer arrays to sum conserving keys array( 3, 4, 6 );
*/
var $intValuesToSum;
// key => int value
var $arrayOneDimToSum;
// key => array('pmv_sum' => X, 'iddetail1' => Y, 'iddetail2' => Z);
var $arrayPmvSumToSum;
var $arrayIntToSum;
var $archiveOk; // flag to known if finished, used when using current archive twice
/**
* @var string literal date corresponding to $this->date
*/
var $literalDate;
/**
* @param object $site
*/
function Archive($site)
{
$this->site = $site;
$this->state = DB_ARCHIVES_DONE;
$this->toRecord = array();
$this->archiveOk = false;
$this->intValuesToSum = array(
'nb_vis', 'nb_pag', 'nb_uniq_pag', 'nb_vis_1pag', 'sum_vis_lth',
'nb_direct', 'nb_search_engine', 'nb_site', 'nb_newsletter', 'nb_partner',
'nb_vis_returning', 'nb_pag_returning', 'nb_vis_1pag_returning', 'sum_vis_lth_returning'
);
// key => int value
$this->arrayOneDimToSum = array(
'vis_st', 'vis_lt', 'pag_st', 'pag_lt', 'vis_lth', 'vis_nb_pag',
'vis_country', 'vis_continent', 'vis_provider', 'vis_config', 'vis_os', 'vis_browser', 'vis_browser_type',
'vis_resolution', 'vis_plugin',
'vis_newsletter',
'vis_nb_vis'
);
// key => array('pmv_sum' => X, 'iddetail1' => Y, 'iddetail2' => Z);
$this->arrayPmvSumToSum = array(
'vis_search_engine', 'vis_keyword', 'vis_site', 'vis_partner'
);
$this->arrayIntToSum = array(
'int_lt', 'int_st', 'int_referer_type', 'int_search_engine', 'int_keyword', 'int_site', 'int_partner',
'int_newsletter', 'int_country', 'int_continent', 'int_os', 'int_browser', 'int_resolution'
);
}
/**
* Update database, set var state
*/
function updateDbState()
{
updateLine(
T_ARCHIVES,
array( 'done' => $this->state, 'idarchives' => $this->idArchives),
'idarchives');
}
/**
* saves var toRecord values in the database, serializing arrays
*/
function saveDb()
{
if(
// day + simple day archive, means array empty, do NOT compress
// ($this->periodType === DB_ARCHIVES_PERIOD_DAY && !CURRENT_DAY_SIMPLE_ARCHIVE)
// ||
// ($this->periodType !== DB_ARCHIVES_PERIOD_DAY && !CURRENT_PERIOD_SIMPLE_ARCHIVE)
COMPRESS_DB_DATA
&& function_exists('gzcompress'))
{
$this->toRecord['compressed'] = 1;
}
else
{
$this->toRecord['compressed'] = 0;
}
/*
print("<pre>");
var_dump($this->toRecord);
print("<br><br><br>");
*/
foreach($this->toRecord as $fieldName => $a_value)
{
if(is_array($a_value))
{
$a_value = databaseEscape(compress(serialize($a_value), $this->toRecord['compressed']));
}
//print("<br>update $fieldName data = ".strlen(serialize($a_value)));
updateLine(
T_ARCHIVES,
array( $fieldName => $a_value, 'idarchives' => $this->idArchives),
'idarchives');
}
$this->updateDbState();
}
/**
* set periodType
*
* @param int $type
*/
function setPeriodType($type)
{
$this->periodType = $type;
}
function getLiteralDate()
{
return $this->literalDate;
}
function setLiteralDate()
{
switch($this->periodType)
{
case DB_ARCHIVES_PERIOD_DAY:
$typeDateDisplay = 1;
break;
case DB_ARCHIVES_PERIOD_WEEK:
$typeDateDisplay = 6;
break;
case DB_ARCHIVES_PERIOD_MONTH:
$typeDateDisplay = 4;
break;
case DB_ARCHIVES_PERIOD_YEAR:
$typeDateDisplay = 11;
break;
}
$this->literalDate = getDateDisplay($typeDateDisplay, $this->date);
}
/**
* init the database, inserting a new row for the current archive process
* assigns var idArchives
*
* @return true
*/
function initDb()
{
$r2 = query("INSERT INTO ".T_ARCHIVES." (idsite, done, period, date1, date2)" .
" VALUES (".$this->site->getId().", " .
" ". DB_ARCHIVES_FAIL."," .
$this->periodType .", ".
" '".$this->date->get()."'," .
" '".$this->date2->get()."')"
);
$this->idArchives = mysql_insert_id();
return true;
}
function deleteOldRecords()
{
// delete failed archives
// delete temp archives older than today
// date2 <> yesterday because of monthly and weekly archive for months/week not finished yet
// once on 10 calls
if( time() % 10 == 0 )
{
$r = query("SELECT max(idarchives)
FROM ".T_ARCHIVES
);
$r = mysql_fetch_row($r);
// max id - 50 is the max id we want to delete, else it would be dangerous
$maxId = (int)$r[0] - 100;
if($maxId > 1)
{
// we delete only old tries for archived
// because if someone asked for an archive 10min ago, we don't delete it!
$query = "DELETE FROM ".T_ARCHIVES."
WHERE (done = ".DB_ARCHIVES_FAIL."
OR done = ".DB_ARCHIVES_TEMP.")
AND date1 <> '".date("Y-m-d")."'
AND date2 <> '".date("Y-m-d")."'
AND date2 <> '".date("Y-m-d", time()-86400)."'
AND idarchives < $maxId
";
$r = query($query);
//print("deleted records= ".mysql_affected_rows() ."<br> $query <br>");
}
}
if( time() % 30 == 0)
{
$r = query("OPTIMIZE TABLE ".T_ARCHIVES);
$r = query("OPTIMIZE TABLE ".T_VISIT);
}
// delete doubled archives
// delete for days
// double archive is when concat(idsite, date1) is the same
// for period = DB_DAYS and done = DONE
//$this->deleteDoubleArchives(true);
// delete for other period than days (week/month/year)
// double archive is when concat(idsite, date1, date2) is the same
// for period <> DB_DAYS and done = DONE
$this->deleteDoubleArchives(false);
}
function deleteDoubleArchives( $dayPeriod )
{
if($dayPeriod)
{
$concatSQL = 'CONCAT( idsite , period, date1)';
$periodTest = '=';
}
else
{
$concatSQL = 'CONCAT( idsite , period, date1, date2)';
$periodTest = '<>';
}
$r = query("SELECT count(*) as c, idsite, date1, date2, $concatSQL as ac
FROM ".T_ARCHIVES."
WHERE period ".$periodTest." ".DB_ARCHIVES_PERIOD_DAY."
AND done = ".DB_ARCHIVES_DONE."
GROUP BY ac
HAVING c > 1"
);
while($l = mysql_fetch_assoc($r))
{
//print($l['c'] . ": ". $l['idsite']." for date " . $l['date1']."<>".$l['date2']." ( ".$l['ac'].")<br>");
$concatToLookFor = $l['ac'];
// for the date select the archives to keep
$r2 = query("SELECT idarchives as id
FROM ".T_ARCHIVES."
WHERE $concatSQL = '".$concatToLookFor."'
AND done = ".DB_ARCHIVES_DONE."
ORDER BY idarchives DESC
LIMIT 1");
$l2 = mysql_fetch_assoc($r2);
$idToKeep = $l2['id'];
$query = "DELETE
FROM ".T_ARCHIVES."
WHERE $concatSQL = '".$concatToLookFor."'
AND idarchives <> $idToKeep
AND done = ".DB_ARCHIVES_DONE."
";
$r3 = query($query);
}
}
/**
* offset the date, considering the date of the first log record for the current site
* and considering today date. It gives a date which is between these 2 dates.
*
* @param object $o_date
*/
function offsetDate($o_date, $minDay = null)
{
$o_dateR = new Date($o_date->get());
if(is_null($minDay))
$minDay = $this->site->getMinDay();
// Manage with future
if($o_date->getTimestamp() > time())
{
$o_dateR = new Date(getDateFromTimestamp(time()));
}
// manage with past
if($o_date->getTimestamp() < $minDay->getTimestamp())
{
$o_dateR = $minDay;
}
return $o_dateR;
}
/**
* Returns limit of the period periodType containing $s_date
* Works with weeks, month, years, and misc periods (in this case, minDate is the first day where there are logs)
*
* @param string $s_date
*/
function getPeriodDatesLimit($s_date)
{
// objects
$date = new Date($s_date);
$minDate = $this->site->getMinDay();
$date = $this->offsetDate($date);
//print("MinDate is ".$minDate->get()."<br>Date asked is $s_date<br>Date after Offset is ".$date->get()."<br>");
switch ($this->periodType)
{
case DB_ARCHIVES_PERIOD_MONTH:
// detect min day for the month
// if the minimum date month is different, we surely take the whole month
if($minDate->getMonth() == $date->getMonth()
&& $minDate->getYear() == $date->getYear())
{
$minDateForSure = $minDate->get();
}
else
{
$minDateForSure = $date->getYear()."-".$date->getMonth()."-01";
}
// detect max date for the month
// if month asked is the current month then max day is today, else its the last day of the month
if($date->getMonth() == date("m") && $date->getYear() == date("Y")) // >= because if month in future, take today
{
// if today is the first day of the month, don't say
// "yesterday is the last day of the month"
// but "today is the only day of the month"
if( date("j",time() ) == 1)
{
$maxDateForSure = getDateFromTimestamp(time());
}
else
{
$maxDateForSure = getDateFromTimestamp(time()-86400);
}
}
else
{
$maxDateForSure = $date->getYear()."-".$date->getMonth()."-".date("t", $date->getTimestamp());
}
break;
case DB_ARCHIVES_PERIOD_WEEK:
$time = $date->getTimestamp();
// detect beginning of the week
while(date("W", $time-86400) == $date->getWeek()
&& $time-86400 >= $minDate->getTimestamp()
)
{
$time -= 86400;
}
$minDateForSure = getDateFromTimestamp($time);
// end of week
while(date("W", $time+86400) == $date->getWeek()
&& $time+86400 <= time()
)
{
$time += 86400;
}
$maxDateForSure = getDateFromTimestamp($time);
break;
case DB_ARCHIVES_PERIOD_MISC_PERIOD:
$minDateForSure = $minDate->get();
$maxDateForSure = $date->get();
break;
case DB_ARCHIVES_PERIOD_YEAR:
// min is minDate if year common
if($date->getYear() == date("Y", $minDate->getYear()))
{
$minDateForSure = $minDate->get();
}
else
{
$minDateForSure = $date->getYear()."-01-01";
}
// max date is today if year is current year
if($date->getYear() == date("Y"))
{
$maxDateForSure = getDateFromTimestamp(time());
}
else
{
$maxDateForSure = $date->getYear()."-12-31";
}
break;
default:
break;
}
$this->date = new Date($minDateForSure);
$this->date2 = new Date($maxDateForSure);
//print("max=$maxDateForSure <br> ".$this->date->get().",". $this->date2->get()."<br>");
$this->date = $this->offsetDate($this->date);
$this->date2 = $this->offsetDate($this->date2);
}
function sortAndLimitToRecord()
{
$doNotSort = array('vis_st', 'vis_lt', 'pag_st', 'pag_lt', 'vis_lth', 'vis_nb_pag', 'vis_nb_vis');
foreach ($this->arrayOneDimToSum as $name)
{
if( !in_array($name, $doNotSort))
{
arsort($this->toRecord[$name]);
}
$this->toRecord[$name] = getArrayOffsetLimit($this->toRecord[$name], 0, MAX_DISTINCT_ELEMENTS);
}
foreach($this->arrayPmvSumToSum as $name)
{
uasort($this->toRecord[$name], "sortingPmv");
$this->toRecord[$name] = getArrayOffsetLimit($this->toRecord[$name], 0, MAX_DISTINCT_ELEMENTS);
}
foreach($this->arrayIntToSum as $name)
{
uasort($this->toRecord[$name], "sortingInterest");
$this->toRecord[$name] = getArrayOffsetLimit($this->toRecord[$name], 0, MAX_DISTINCT_INTEREST_ELEMENTS);
}
}
}
?>