<?php
/**
* This file implements functions for logging of hits and extracting stats.
*
* NOTE: the refererList() and stats_* functions are not fully functional ATM. I'll transform them into the Hitlog object during the next days. blueyed.
*
* This file is part of the evoCore framework - {@link http://evocore.net/}
* See also {@link https://github.com/b2evolution/b2evolution}.
*
* @license GNU GPL v2 - {@link http://b2evolution.net/about/gnu-gpl-license}
*
* @copyright (c)2003-2020 by Francois Planque - {@link http://fplanque.com/}
* Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
*
* {@internal Origin:
* This file was inspired by N C Young's Referer Script released in
* the public domain on 07/19/2002. {@link http://ncyoung.com/entry/57}.
* See also {@link http://ncyoung.com/demo/referer/}.
* }}
*
* @package evocore
*/
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
/**
* Display hits results table
*/
function hits_results_block( $params = array() )
{
if( ! is_logged_in() )
{ // Only logged in users can access to this function
return;
}
global $blog, $sec_ID;
if( $blog == 0 )
{
if( ! check_user_perm( 'stats', 'view' ) )
{ // Current user has no permission to view all stats (aggregated stats)
return;
}
}
else
{
if( ! check_user_perm( 'stats', 'list', false, $blog ) )
{ // Current user has no permission to view the stats of the selected blog
return;
}
}
/**
* View funcs
*/
load_funcs('sessions/views/_stats_view.funcs.php');
global $blog, $admin_url, $rsc_url;
global $Session, $UserSettings, $DB;
global $datestartinput, $datestart, $datestopinput, $datestop;
global $preset_referer_type, $preset_agent_type;
$tab = param( 'tab', 'string', 'summary', true );
$tab3 = param( 'tab3', 'string', '', true );
switch( $tab )
{
case 'other':
$preset_results_title = T_('Direct browser hits');
$preset_referer_type = 'direct';
$preset_agent_type = 'browser';
$preset_filter_all_url = '?ctrl=stats&tab=referers&blog='.$blog;
$hide_columns = 'referer';
break;
case 'referers':
$preset_results_title = T_('Refered browser hits');
$preset_referer_type = 'referer';
$preset_agent_type = 'browser';
$preset_filter_all_url = '?ctrl=stats&tab=referers&blog='.$blog;
break;
case 'refsearches':
if( $tab3 == 'hits' )
{
$preset_results_title = T_('Search hits');
$preset_referer_type = 'search';
$preset_agent_type = 'browser';
$preset_filter_all_url = '?ctrl=stats&tab=refsearches&tab3=hits&blog='.$blog;
}
break;
}
if( param_date( 'datestartinput', T_('Invalid date'), false, NULL ) !== NULL )
{ // We have a user provided localized date:
memorize_param( 'datestart', 'string', NULL, trim( form_date( $datestartinput ) ) );
memorize_param( 'datestartinput', 'string', NULL, empty( $datestartinput ) ? NULL : date( locale_datefmt(), strtotime( $datestartinput ) ) );
}
else
{ // We may have an automated param transmission date:
param( 'datestart', 'string', '', true );
}
if( param_date( 'datestopinput', T_('Invalid date'), false, NULL ) !== NULL )
{ // We have a user provided localized date:
memorize_param( 'datestop', 'string', NULL, trim( form_date( $datestopinput ) ) );
memorize_param( 'datestopinput', 'string', NULL, empty( $datestopinput ) ? NULL : date( locale_datefmt(), strtotime( $datestopinput ) ) );
}
else
{ // We may have an automated param transmission date:
param( 'datestop', 'string', '', true );
}
$exclude = param( 'exclude', 'integer', 0, true );
$sess_ID = param( 'sess_ID', 'integer', NULL, true );
$remote_IP = param( 'remote_IP', 'string', NULL, true );
$referer_type = isset( $preset_referer_type ) ? $preset_referer_type : param( 'referer_type', 'string', NULL, true );
$agent_type = isset( $preset_agent_type ) ? $preset_agent_type : param( 'agent_type', 'string', NULL, true );
$device = param( 'device', 'string', NULL, true );
$hit_type = param( 'hit_type', 'string', NULL, true );
$reqURI = param( 'reqURI', 'string', NULL, true );
$resp_code = param( 'resp_code', 'integer', NULL, true );
// Create result set:
$SQL = new SQL();
$SQL->SELECT( 'SQL_NO_CACHE hit_ID, sess_ID, sess_device, hit_datetime, hit_type, hit_referer_type, hit_uri, hit_disp, hit_ctrl, hit_action, hit_coll_ID, hit_referer, hit_remote_addr,'
.'user_login, hit_agent_type, blog_shortname, dom_name, goal_name, hit_keyphrase, hit_serprank, hit_response_code, hit_method, hit_agent_ID' );
$SQL->FROM( 'T_hitlog LEFT JOIN T_basedomains ON dom_ID = hit_referer_dom_ID'
.' LEFT JOIN T_sessions ON hit_sess_ID = sess_ID'
.' LEFT JOIN T_blogs ON hit_coll_ID = blog_ID'
.' LEFT JOIN T_users ON sess_user_ID = user_ID'
.' LEFT JOIN T_track__goalhit ON hit_ID = ghit_hit_ID'
.' LEFT JOIN T_track__goal ON ghit_goal_ID = goal_ID' );
$count_SQL = new SQL();
$count_SQL->SELECT( 'SQL_NO_CACHE COUNT(hit_ID)' );
$count_SQL->FROM( 'T_hitlog' );
$operator = ( $exclude ? ' <> ' : ' = ' );
if( ! empty( $sess_ID ) )
{ // We want to filter on the session ID:
$filter = 'hit_sess_ID'.$operator.$sess_ID;
$SQL->WHERE( $filter );
$count_SQL->WHERE( $filter );
}
elseif( ! empty( $remote_IP ) ) // TODO: allow combine
{ // We want to filter on the goal name:
$filter = 'hit_remote_addr'.$operator.$DB->quote( $remote_IP );
$SQL->WHERE( $filter );
$count_SQL->WHERE( $filter );
}
if( ! empty( $referer_type ) )
{
$filter = 'hit_referer_type = '.$DB->quote( $referer_type );
$SQL->WHERE_and( $filter );
$count_SQL->WHERE_and( $filter );
}
if( ! empty( $agent_type ) )
{
$filter = 'hit_agent_type = '.$DB->quote( $agent_type );
$SQL->WHERE_and( $filter );
$count_SQL->WHERE_and( $filter );
}
if( ! empty( $device ) )
{
if( $device == 'other' )
{ // Unknown device
$device = '';
}
$filter = 'sess_device = '.$DB->quote( $device );
$SQL->WHERE_and( $filter );
$count_SQL->WHERE_and( $filter );
$count_SQL->FROM_add( 'LEFT JOIN T_sessions ON hit_sess_ID = sess_ID' );
}
if( ! empty( $hit_type ) )
{
$filter = 'hit_type = '.$DB->quote( $hit_type );
$SQL->WHERE_and( $filter );
$count_SQL->WHERE_and( $filter );
}
if( ! empty( $reqURI ) )
{
$filter = 'hit_uri LIKE '.$DB->quote( $reqURI );
$SQL->WHERE_and( $filter );
$count_SQL->WHERE_and( $filter );
}
if( ! empty( $resp_code ) )
{
$filter = 'hit_response_code = ' .$DB->quote( $resp_code );
$SQL->WHERE_and( $filter );
$count_SQL->WHERE_and( $filter );
}
if( ! empty( $datestart ) )
{
$SQL->WHERE_and( 'hit_datetime >= '.$DB->quote( $datestart.' 00:00:00' ) );
$count_SQL->WHERE_and( 'hit_datetime >= '.$DB->quote( $datestart.' 00:00:00' ) );
}
if( ! empty( $datestop ) )
{
$SQL->WHERE_and( 'hit_datetime <= '.$DB->quote( $datestop.' 23:59:59' ) );
$count_SQL->WHERE_and( 'hit_datetime <= '.$DB->quote( $datestop.' 23:59:59' ) );
}
if( ! empty( $sec_ID ) )
{ // Filter by selected section:
$filter = 'blog_sec_ID = '.$DB->escape( $sec_ID );
$SQL->WHERE_and( $filter );
$count_SQL->FROM_add( 'LEFT JOIN T_blogs ON hit_coll_ID = blog_ID' );
$count_SQL->WHERE_and( $filter );
}
if( ! empty( $blog ) )
{ // Filter by selected collection:
$filter = 'hit_coll_ID = '.$DB->escape( $blog );
$SQL->WHERE_and( $filter );
$count_SQL->WHERE_and( $filter );
}
$resuts_param_prefix = 'hits_';
if( ! empty( $preset_referer_type ) )
{
$resuts_param_prefix = substr( $preset_referer_type, 0, 8 ).'_'.$resuts_param_prefix;
}
$default_order = '--D';
$SQL->ORDER_BY( '*, hit_ID' );
$Results = new Results( $SQL->get(), $resuts_param_prefix, $default_order, $UserSettings->get( 'results_per_page' ), $count_SQL->get(), true, 100000 );
// Initialize Results object
hits_results( $Results, array( 'default_order' => $default_order ) );
if( is_ajax_content() )
{ // init results param by template name
if( !isset( $params[ 'skin_type' ] ) || ! isset( $params[ 'skin_name' ] ) )
{
debug_die( 'Invalid ajax results request!' );
}
$Results->init_params_by_skin( $params[ 'skin_type' ], $params[ 'skin_name' ] );
}
// Display results:
$Results->display();
if( !is_ajax_content() )
{ // Create this hidden div to get a function name for AJAX request
echo '<div id="'.$resuts_param_prefix.'ajax_callback" style="display:none">'.__FUNCTION__.'</div>';
}
}
/**
* Displays keywords used for search leading to this page
*/
function stats_search_keywords( $keyphrase, $length = 45 )
{
global $evo_charset;
if( $keyphrase === NULL || $keyphrase === '' )
{
return '<span class="note">['./* TRANS: "Not Available" */ T_('N/A').']</span>';
}
// Save original string
$keyphrase_orig = $keyphrase;
$keyphrase = strmaxlen( $keyphrase, $length, '...', 'raw' );
// Convert keyword encoding, some charsets are supported only in PHP 4.3.2 and later.
// This fixes encoding problem for Cyrillic keywords
// See http://forums.b2evolution.net/viewtopic.php?t=17431
$keyphrase = htmlentities( $keyphrase, ENT_COMPAT, $evo_charset );
return '<span title="'.format_to_output( $keyphrase_orig, 'htmlattr' ).'">'.$keyphrase.'</span>';
}
/**
* Generate a random ip
*
* @return string ip
*/
function generate_random_ip()
{
return mt_rand( 0, 255 ).'.'.mt_rand( 0, 255 ).'.'.mt_rand( 0, 255 ).'.'.mt_rand( 0, 255 );
}
/**
* Generate fake hit statistics
*
* @param integer the number of days to generate statistics
* @param integer min interval between hits in seconds
* @param integer max interval between hits in seconds
* @param boolean TRUE to display the process dots during generating of the hits
* @return integer count of inserted hits
*/
function generate_hit_stat( $days, $min_interval, $max_interval, $display_process = false )
{
global $baseurlroot, $admin_url, $user_agents, $DB, $htsrv_url, $is_api_request;
load_class( 'items/model/_itemlistlight.class.php', 'ItemListLight' );
load_class( 'sessions/model/_hit.class.php', 'Hit' );
$links = array();
$BlogCache = & get_BlogCache();
$blogs_id = $BlogCache->load_public();
foreach( $blogs_id as $blog_id )
{ // Handle all public blogs:
$listBlog = & $BlogCache->get_by_ID( $blog_id );
if( empty( $listBlog ) )
{
continue;
}
$ItemList = new ItemListLight( $listBlog );
$filters = array();
# This is the list of categories to restrict the linkblog to (cats will be displayed recursively)
# Example: $linkblog_cat = '4,6,7';
$linkblog_cat = '';
# This is the array if categories to restrict the linkblog to (non recursive)
# Example: $linkblog_catsel = array( 4, 6, 7 );
$linkblog_catsel = array(); // $cat_array;
// Compile cat array stuff:
$linkblog_cat_array = array();
$linkblog_cat_modifier = '';
compile_cat_array( $linkblog_cat, $linkblog_catsel, /* by ref */ $linkblog_cat_array, /* by ref */ $linkblog_cat_modifier, $listBlog->ID );
$filters['cat_array'] = $linkblog_cat_array;
$filters['cat_modifier'] = $linkblog_cat_modifier;
$ItemList->set_default_filters( $filters );
// Get the items list of current blog
$ItemList->query();
if( ! $ItemList->result_num_rows )
{ // Nothing to display:
continue;
}
while( $Item = & $ItemList->get_category_group() )
{
// Open new cat:
$Chapter = & $Item->get_main_Chapter();
while( $Item = & $ItemList->get_item() )
{
$links[] = array(
'link' => '/'.$listBlog->siteurl.'/'.$Chapter->get_url_path().$Item->urltitle, // trim( $Chapter->get_permanent_url( NULL ,' ' ) ).
'blog_id' => $blog_id
);
}
}
// add search links for all blogs
$links[] = array(
'link' => url_add_param( '/'.$listBlog->siteurl, 's=$keywords$&disp=search&submit=Search', '&' ),
'blog_id' => $blog_id
);
$links[] = array(
'link' => url_add_param( '/'.$listBlog->siteurl, 'disp=users', '&' ),
'blog_id' => $blog_id,
'disp' => 'users'
);
$links[] = array(
'link' => url_add_param( '/'.$listBlog->siteurl, 'disp=user&user_ID=1', '&' ),
'blog_id' => $blog_id,
'disp' => 'users'
);
$links[] = array(
'link' => url_add_param( '/'.$listBlog->siteurl, 'disp=threads', '&' ),
'blog_id' => $blog_id,
'disp' => 'threads'
);
$links[] = array(
'link' => url_add_param( '/'.$listBlog->siteurl, 'disp=profile', '&' ),
'blog_id' => $blog_id,
'disp' => 'profile'
);
$links[] = array(
'link' => $htsrv_url.'anon_async.php',
'blog_id' => $blog_id
);
$links[] = array(
'link' => '/api/v1/collections/'.$listBlog->urlname.'/posts',
'blog_id' => $blog_id
);
$links[] = array(
'link' => '/api/v1/collections/'.$listBlog->urlname.'/search/post',
'blog_id' => $blog_id
);
$links[] = array(
'link' => '/xmlsrv/xmlrpc.php?blog='.$listBlog->ID,
'blog_id' => $blog_id
);
}
$links[] = array(
'link' => '/api/v1/collections',
);
$links[] = array(
'link' => '/xmlsrv/xmlrpc.php'
);
$referes = array('http://www.fake-referer1.com',
'http://www.fake-referer2.com',
'http://www.fake-referer3.com',
'http://www.fake-referer4.com',
'http://www.fake-referer5.com',
'http://www.fake-referer6.com',
'http://www.fake-referer7.com',
'http://www.fake-referer8.com',
'http://www.fake-referer9.com',
'http://www.mail.google.com/fake/referer',
'http://www.webmail.aol.com/fake/referer',
'http://www.mail.yahoo.com/fake/referer',
'http://bloglines.com/fake/referer',
'http://www.fake-refer-online-casino1.com',
'http://www.fake-refer-online-casino2.com',
'http://www.fake-refer-online-casino3.com',
'http://www.google.com/url?sa=t&rct=j&q=$keywords$&source=web&cd=4',
'http://www.bing.com/search?q=$keywords$&src=IE-SearchBox&FORM=IE8SRC'
);
$devices = array(
'iphone',
'ipad',
'andrtab',
'android',
'berrytab',
'blkberry',
'winphone',
'wince',
'palm',
'gendvice'
);
$request_methods = array( 'GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'unknown' );
$request_methods_count = count( $request_methods ) - 1;
$robots = array();
foreach( $user_agents as $lUserAgent )
{
if( $lUserAgent[0] == 'robot' )
{
$robots[] = $lUserAgent[1];
}
}
$robots_count = count( $robots ) - 1;
$ref_count = count( $referes ) - 1;
$admin_link = array(
'link' => $admin_url,
'blog_id' => NULL
);
$links_count = count( $links );
if( empty( $links_count ) )
{
global $Messages;
$Messages->add( 'Cannot generate statistics without collection links.' );
return;
}
// generate users id array
$users_array = $DB->get_results('
SELECT user_ID
FROM T_users
WHERE user_status IN ( "activated", "autoactivated", "manualactivated" )
LIMIT 10'
, ARRAY_A );
$users_count = count( $users_array );
$devices_count = count( $devices );
if( empty( $users_count ) )
{
$Messages->add( 'Cannot generate statistics without valid users.' );
return;
}
// Calculate the period of testing
$cur_time = time();
$past_time = mktime( date( 'H' ), date( 'i' ), date( 's' ), date( 'm' ), date( 'd' ) - $days, date( 'Y' ) );
$insert_data = '';
$insert_data_count = 0;
// create session array for testing
$sessions = array();
mt_srand( crc32( microtime() ) );
for( $i = 0; $i <= $users_count - 1; $i++ )
{
$sessions[] = array(
'sess_ID' => -1,
'sess_key' => generate_random_key( 32 ),
'sess_start_ts' => 0,
'sess_lastseen_ts' => 0,
'sess_ipaddress' => generate_random_ip(),
'sess_user_ID' => $users_array[$i]['user_ID'],
'sess_device' => $devices[ mt_rand( 0, $devices_count - 1 ) ],
'pervios_link' => '',
'robot' => ''
);
}
// main cycle of generation
//mt_srand(crc32(microtime()));
for( $time_shift = $past_time; $cur_time > $time_shift; $time_shift += mt_rand( $min_interval, $max_interval ) )
{
//mt_srand(crc32(microtime()));
$insert_data_count = $insert_data_count + 1;
$rand_i = mt_rand( 0, $users_count - 1 );
$rand_link = mt_rand( 0, $links_count - 1 );
$cur_session = $sessions[$rand_i];
$rand_request_method = $request_methods[ mt_rand( 0, $request_methods_count - 1 ) ];
if( strstr( $links[$rand_link]['link'], '$keywords$' ) )
{ // check if the current search link is selected randomly.
// If yes, generate search link and add it to DB
//mt_srand(crc32(microtime()+ $time_shift));
$keywords = 'fake search '.mt_rand( 0, 9 );
$links[$rand_link]['link'] = str_replace( '$keywords$', urlencode( $keywords ), $links[$rand_link]['link'] );
if( strstr( $links[$rand_link]['link'], 's=' ) )
{
$links[$rand_link]['s'] = $keywords;
}
}
if( $cur_session['sess_ID'] == -1 )
{ // This session needs initialization:
$cur_session['sess_start_ts'] = $time_shift - 1;
$cur_session['sess_lastseen_ts'] = $time_shift;
$DB->query( 'INSERT INTO T_sessions ( sess_key, sess_start_ts, sess_lastseen_ts, sess_ipaddress, sess_user_ID, sess_device )
VALUES (
'.$DB->quote( $cur_session['sess_key'] ).',
'.$DB->quote( date( 'Y-m-d H:i:s', $cur_session['sess_start_ts'] ) ).',
'.$DB->quote( date( 'Y-m-d H:i:s', $cur_session['sess_lastseen_ts'] ) ).',
'.$DB->quote( $cur_session['sess_ipaddress'] ).',
'.$DB->quote( $cur_session['sess_user_ID'] ).',
'.$DB->quote( $cur_session['sess_device'] ).'
)' );
$cur_session['sess_ID'] = $DB->insert_id;
$sessions[$rand_i] = $cur_session;
// Check if current url is api request:
$is_api_request = ( strpos( $links[$rand_link]['link'], '/api/v1' ) === 0 || strpos( $links[$rand_link]['link'], '/xmlsrv/xmlrpc.php' ) === 0 );
$Test_hit = new Hit( '', $cur_session['sess_ipaddress'], $cur_session['sess_ID'], $cur_session['sess_lastseen_ts'], 1, $links[$rand_link] );
$Test_hit->method = $rand_request_method;
$Test_hit->log();
}
else
{
if( ( $time_shift - $cur_session['sess_lastseen_ts'] ) > 3000 || ! empty( $cur_session['robot'] ) )
{ // This session last updated more than 3000 sec ago. Instead of this session create a new session.
$cur_session = array(
'sess_ID' => -1,
'sess_key' => generate_random_key( 32 ),
'sess_start_ts' => 0,
'sess_lastseen_ts' => 0,
'sess_ipaddress' => generate_random_ip(),
'sess_user_ID' => $users_array[ mt_rand( 0, $users_count - 1 ) ]['user_ID'],
'sess_device' => $devices[ mt_rand( 0, $devices_count - 1 ) ],
'pervios_link' => '',
'robot' => ''
);
$cur_session['sess_start_ts'] = $time_shift - 1;
$cur_session['sess_lastseen_ts'] = $time_shift;
$r_num = mt_rand( 0, 100 );
if( $r_num > 40 )
{ // Create anonymous user and make double insert into hits.
$cur_session['sess_user_ID'] = -1;
$DB->query( 'INSERT INTO T_sessions ( sess_key, sess_start_ts, sess_lastseen_ts, sess_ipaddress, sess_device )
VALUES (
'.$DB->quote( $cur_session['sess_key'] ).',
'.$DB->quote( date( 'Y-m-d H:i:s', $cur_session['sess_start_ts'] ) ).',
'.$DB->quote( date( 'Y-m-d H:i:s', $cur_session['sess_lastseen_ts'] ) ).',
'.$DB->quote( $cur_session['sess_ipaddress'] ).',
'.$DB->quote( $cur_session['sess_device'] ).'
)' );
if( $r_num >= 80 )
{ // Create robot hit
$cur_session['robot'] = $robots[ mt_rand( 0, $robots_count ) ];
}
}
else
{
$DB->query( 'INSERT INTO T_sessions( sess_key, sess_start_ts, sess_lastseen_ts, sess_ipaddress, sess_user_ID, sess_device )
VALUES (
'.$DB->quote( $cur_session['sess_key'] ).',
'.$DB->quote( date( 'Y-m-d H:i:s', $cur_session['sess_start_ts'] ) ).',
'.$DB->quote( date( 'Y-m-d H:i:s', $cur_session['sess_lastseen_ts'] ) ).',
'.$DB->quote( $cur_session['sess_ipaddress'] ).',
'.$DB->quote( $cur_session['sess_user_ID'] ).',
'.$DB->quote( $cur_session['sess_device'] ).'
)' );
}
$cur_session['sess_ID'] = $DB->insert_id;
if( mt_rand( 0, 100 ) > 20 )
{
//$ref_count
$ref_link = $referes[ mt_rand( 0, $ref_count ) ];
if( strstr( $ref_link, '$keywords$' ) )
{ // check if the current search link is selected randomly.
$keywords = 'fake search '.mt_rand( 0, 9 );
$ref_link = str_replace( '$keywords$', urlencode( $keywords ), $ref_link );
}
}
else
{
$ref_link = '';
}
if( $cur_session['sess_user_ID'] == -1 )
{
if( empty( $cur_session['robot'] ) )
{
$link = array(
'link' => '/htsrv/login.php',
'blog_id' => 1
);
// This is NOT api request:
$is_api_request = false;
$Test_hit = new Hit( $ref_link, $cur_session['sess_ipaddress'], $cur_session['sess_ID'], $cur_session['sess_lastseen_ts'], 1, $link );
$Test_hit->method = $rand_request_method;
$Test_hit->log();
$link = array(
'link' => '/htsrv/login.php?redirect_to=fake_stat',
'blog_id' => 1
);
$Test_hit = new Hit( $baseurlroot, $cur_session['sess_ipaddress'], $cur_session['sess_ID'], $cur_session['sess_lastseen_ts'] + 3, 1, $link );
$Test_hit->method = $rand_request_method;
$Test_hit->log();
$cur_session['pervios_link'] = $baseurlroot.$link['link'];
}
else
{
// Check if current url is api request:
$is_api_request = ( strpos( $links[$rand_link]['link'], '/api/v1' ) === 0 || strpos( $links[$rand_link]['link'], '/xmlsrv/xmlrpc.php' ) === 0 );
if( mt_rand( 0, 100 ) < 50 )
{ // robot hit
$Test_hit = new Hit( '', $cur_session['sess_ipaddress'], $cur_session['sess_ID'], $cur_session['sess_lastseen_ts'], 1, $links[$rand_link], $cur_session['robot'] );
}
else
{ // rss/atom hit
$Test_hit = new Hit( '', $cur_session['sess_ipaddress'], $cur_session['sess_ID'], $cur_session['sess_lastseen_ts'], 1, $links[$rand_link], NULL, NULL, 1 );
}
$Test_hit->method = $rand_request_method;
$Test_hit->log();
}
}
else
{
if( mt_rand( 0, 100 ) < 10 )
{ // Test hit to admin page:
// This is NOT api request:
$is_api_request = false;
$Test_hit = new Hit( '', $cur_session['sess_ipaddress'], $cur_session['sess_ID'], $cur_session['sess_lastseen_ts'], 1, $admin_link, NULL, 1 );
$Test_hit->method = $rand_request_method;
$Test_hit->log();
$cur_session['pervios_link'] = $admin_url;
}
else
{
// Check if current url is api request:
$is_api_request = ( strpos( $links[$rand_link]['link'], '/api/v1' ) === 0 || strpos( $links[$rand_link]['link'], '/xmlsrv/xmlrpc.php' ) === 0 );
$Test_hit = new Hit( $ref_link, $cur_session['sess_ipaddress'], $cur_session['sess_ID'], $cur_session['sess_lastseen_ts'], 1, $links[$rand_link] );
$Test_hit->method = $rand_request_method;
$Test_hit->log();
$cur_session['pervios_link'] = $baseurlroot.$links[$rand_link]['link'];
}
}
}
else
{
// Update session
$cur_session['sess_lastseen_ts'] = $time_shift;
// Check if current url is api request:
$is_api_request = ( strpos( $links[$rand_link]['link'], '/api/v1' ) === 0 || strpos( $links[$rand_link]['link'], '/xmlsrv/xmlrpc.php' ) === 0 );
$Test_hit = new Hit( $cur_session['pervios_link'], $cur_session['sess_ipaddress'], $cur_session['sess_ID'], $cur_session['sess_lastseen_ts'], 1, $links[$rand_link] );
$Test_hit->method = $rand_request_method;
$Test_hit->log();
$DB->query( 'UPDATE T_sessions
SET sess_lastseen_ts = '.$DB->quote( date( 'Y-m-d H:i:s', $cur_session['sess_lastseen_ts'] ) ).'
WHERE sess_ID = '.$DB->quote( $cur_session['sess_ID'] ),
'Update session' );
$cur_session['pervios_link'] = $baseurlroot.$links[$rand_link]['link'];
$sessions[$rand_i] = $cur_session;
}
}
if( isset( $Test_hit ) && ! empty( $Test_hit->ID ) && rand( 0, 2 ) == 2 )
{ // Insert sample goal hits per random new Hit:
$DB->query( 'INSERT INTO T_track__goalhit ( ghit_goal_ID, ghit_hit_ID )
SELECT goal_ID, '.$Test_hit->ID.' FROM T_track__goal
ORDER BY RAND()
LIMIT 1' );
}
$sessions[$rand_i] = $cur_session;
if( $display_process )
{
if( $insert_data_count % 100 == 0 )
{ // Display a process of creating by one dot for 100 hits
echo ' .';
evo_flush();
}
}
}
// Reset this back to from test values:
$is_api_request = false;
return $insert_data_count;
}
/**
* Get domain type titles
*
* @param boolean TRUE to escape quotes in titles
* @return array Domain titles
*/
function stats_dom_type_titles( $escape_quotes = false )
{
return array(
'unknown' => $escape_quotes ? TS_('Unknown') : T_('Unknown'),
'normal' => $escape_quotes ? TS_('Referer') : T_('Referer'),
'searcheng' => $escape_quotes ? TS_('Search referer') : T_('Search referer'),
'aggregator' => $escape_quotes ? TS_('Aggregator referer') : T_('Aggregator referer'),
'email' => $escape_quotes ? TS_('Email provider') : T_('Email provider'),
);
}
/**
* Get domain status titles
*
* @param boolean TRUE to escape quotes in titles
* @return array Domain titles
*/
function stats_dom_status_titles( $escape_quotes = false )
{
return array(
'trusted' => $escape_quotes ? TS_('Trusted') : T_('Trusted'),
'unknown' => $escape_quotes ? TS_('Unknown') : T_('Unknown'),
'suspect' => $escape_quotes ? TS_('Suspect') : T_('Suspect'),
'blocked' => $escape_quotes ? TS_('Blocked') : T_('Blocked'),
);
}
/**
* Get status colors of domain
*
* @return array Color values
*/
function stats_dom_status_colors()
{
return array(
'trusted' => '00CC00',
'unknown' => '999999',
'suspect' => 'FFAA00',
'blocked' => 'FF0000',
);
}
/**
* Get array of status icons for domains
*
* @return array Status icons
*/
function stats_dom_status_icons()
{
return array(
'trusted' => get_icon( 'bullet_green', 'imgtag', array( 'title' => aipr_status_title( 'trusted' ) ) ),
'unknown' => get_icon( 'bullet_white', 'imgtag', array( 'title' => aipr_status_title( 'unknown' ) ) ),
'suspect' => get_icon( 'bullet_orange', 'imgtag', array( 'title' => aipr_status_title( 'suspect' ) ) ),
'blocked' => get_icon( 'bullet_red', 'imgtag', array( 'title' => aipr_status_title( 'blocked' ) ) )
);
}
/**
* Get domain type title by value
*
* @param string Domain type value
* @param boolean TRUE to escape quotes in titles
* @return string Domain type title
*/
function stats_dom_type_title( $dom_type, $escape_quotes = false )
{
$dom_type_titles = stats_dom_type_titles( $escape_quotes );
return isset( $dom_type_titles[ $dom_type ] ) ? $dom_type_titles[ $dom_type ] : $dom_type;
}
/**
* Get domain status title by value
*
* @param string Domain status value
* @param boolean TRUE to escape quotes in titles
* @return string Domain status title
*/
function stats_dom_status_title( $dom_status, $escape_quotes = false )
{
$dom_status_titles = stats_dom_status_titles( $escape_quotes );
return isset( $dom_status_titles[ $dom_status ] ) ? $dom_status_titles[ $dom_status ] : $dom_status;
}
/**
* Get domain status color by value
*
* @param string Domain status value
* @return string Domain status color
*/
function stats_dom_status_color( $dom_status )
{
$dom_status_colors = stats_dom_status_colors();
return isset( $dom_status_colors[ $dom_status ] ) ? '#'.$dom_status_colors[ $dom_status ] : 'none';
}
/**
* Get domain status icon by value
*
* @param string Domain status value
* @return string Domain status icon
*/
function stats_dom_status_icon( $dom_status )
{
$dom_status_icons = stats_dom_status_icons();
return isset( $dom_status_icons[ $dom_status ] ) ? $dom_status_icons[ $dom_status ] : '';
}
/**
* Get top existing Domain object by subdomain name
*
* @param string Subdomain name
* @return onject Domain object
*/
function & get_Domain_by_subdomain( $subdomain_name )
{
$DomainCache = & get_DomainCache();
$subdomain_name = explode( '.', $subdomain_name );
// Store in this var top existing domain even with unknown status,
// This domain will be returned when all other subdomains have unknown status:
$first_existing_Domain = NULL;
for( $i = 0; $i < count( $subdomain_name ); $i++ )
{
$domain_name = implode( '.', array_slice( $subdomain_name, $i ) );
$domain_names = array( $domain_name, '.'.$domain_name );
foreach( $domain_names as $domain_name )
{
if( $Domain = & $DomainCache->get_by_name( $domain_name, false, false ) )
{ // If domain exists in DB:
if( $first_existing_Domain === NULL )
{ // Store first top existing domain with any status:
$first_existing_Domain = $Domain;
}
if( $Domain->get( 'status' ) != 'unknown' )
{ // Use this domain because it exists with not unknown status:
return $Domain;
}
}
}
}
// Return either NULL or first top existing domain with unknown status:
return $first_existing_Domain;
}
/**
* Get Domain object by url
*
* @param string URL
* @return onject Domain object
*/
function & get_Domain_by_url( $url )
{
// Exctract domain name from url:
$domain_name = url_part( $url, 'host' );
$Domain = & get_Domain_by_subdomain( $domain_name );
return $Domain;
}
/**
* Get user agent name by ID
*
* @param integer Agent ID
* @param string Agent name or Agent ID if agent is not found
*/
function get_hit_agent_name_by_ID( $agent_ID )
{
global $user_agents;
if( isset( $user_agents[ $agent_ID ] ) && ! empty( $user_agents[ $agent_ID ][2] ) )
{ // Agent is found with given ID
return $user_agents[ $agent_ID ][2];
}
else
{ // No agent, Return ID
return $agent_ID;
}
}
/**
* Extract keyphrases from the hitlog
*
* @param boolean|string TRUE to print out messages, 'cron_job' - to log messages for cron job
* @return integer Number of new inserted key phrases,
* string Error message if the process is already running and not allowed to run
*/
function extract_keyphrase_from_hitlogs( $display_messages = true )
{
global $DB, $Messages, $Timer;
// Set lock name based on the database name, table name and process name
$lock_name = $DB->dbname.'.T_track__keyphrase.extract_keyphrase';
if( $DB->get_var( 'SELECT IS_FREE_LOCK( '.$DB->quote( $lock_name ).' )' ) === '0' )
{ // The "exctract_keyphrase" process is already running on a different request, do not start it again
// Do not translate.
return 'Keyphrase extraction is already in progress in a different process. This new request would duplicate the effort so it is aborted.';
}
$inserted_keyphrases_num = 0;
// Important: If a two or more different simultanious process will arrive to this point at the same time, only one of them will acquire the lock!
// The other processes have to wait until the one who acquired the lock will release it. After that the other process will get it one by one.
// Get lock with a 20 seconds timeout
$DB->get_var( 'SELECT GET_LOCK( '.$DB->quote( $lock_name ).', 20 )' );
// Look for unextracted keyphrases:
$Timer->start( 'extract_keyphrase_number' );
$SQL = new SQL( 'Get number of hitlog records and min/max of hit IDs that have a keyphrase that was not processed yet' );
$SQL->SELECT( 'COUNT( hit_ID ) AS hits_num, COUNT( DISTINCT hit_keyphrase ) AS keyphrases_num, MIN( hit_ID ) as min, MAX( hit_ID ) as max' );
$SQL->FROM( 'T_hitlog' );
$SQL->WHERE( 'hit_keyphrase IS NOT NULL' );
$SQL->WHERE_and( 'hit_keyphrase != ""' );
$SQL->WHERE_and( 'hit_keyphrase_keyp_ID IS NULL' ); // Keyphrase that has not been extracted yet!
$ids = $DB->get_row( $SQL, ARRAY_A );
$Timer->stop( 'extract_keyphrase_number' );
if( $display_messages )
{ // Display info:
$log_message = sprintf( TB_('Number of hitlog records that have a keyphrase that were not processed yet: %d'), intval( $ids['hits_num'] ) );
$log_message .= ' <span class="note">(keyphrases='.$ids['keyphrases_num'].', min='.$ids['min'].', max='.$ids['max'].')('.sprintf( TB_('Time: %s seconds'), $Timer->get_duration( 'extract_keyphrase_number' ) ).')</span>';
if( $display_messages === 'cron_job' )
{ // Log a message for cron job:
cron_log_append( $log_message );
}
else
{ // Print out a message:
echo '<p>'.$log_message.'</p>';
evo_flush();
}
}
if( ! empty( $ids['min'] ) && ! empty( $ids['max'] ) )
{ // Extract keyphrases if needed:
$Timer->start( 'extract_keyphrase_insert' );
// External keyphrases
$sql = 'INSERT INTO T_track__keyphrase(keyp_phrase, keyp_count_refered_searches)
SELECT h.hit_keyphrase, 1
FROM T_hitlog as h
WHERE
(h.hit_ID >= '.$ids['min'].' AND h.hit_ID <= '.$ids['max'].')
AND h.hit_keyphrase IS NOT NULL
AND h.hit_keyphrase != ""
AND h.hit_keyphrase_keyp_ID IS NULL
AND h.hit_referer_type = "search"
ON DUPLICATE KEY UPDATE
T_track__keyphrase.keyp_count_refered_searches = T_track__keyphrase.keyp_count_refered_searches + 1';
$DB->query( $sql, ' Insert/Update external keyphrase' );
// Internal keyphrases
$sql = 'INSERT INTO T_track__keyphrase(keyp_phrase, keyp_count_internal_searches)
SELECT h.hit_keyphrase, 1
FROM T_hitlog as h
WHERE
(h.hit_ID >= '.$ids['min'].' AND h.hit_ID <= '.$ids['max'].')
AND h.hit_keyphrase IS NOT NULL
AND h.hit_keyphrase != ""
AND h.hit_keyphrase_keyp_ID IS NULL
AND h.hit_referer_type != "search"
ON DUPLICATE KEY UPDATE
T_track__keyphrase.keyp_count_internal_searches = T_track__keyphrase.keyp_count_internal_searches + 1';
$DB->query( $sql, 'Insert/Update internal keyphrase' );
$Timer->stop( 'extract_keyphrase_insert' );
if( $display_messages )
{ // Display info:
$log_message = sprintf( TB_('%d key phrases have been inserted or updated.'), intval( $ids['keyphrases_num'] ) );
$log_message .= ' <span class="note">('.sprintf( TB_('Time: %s seconds'), $Timer->get_duration( 'extract_keyphrase_insert' ) ).')</span>';
if( $display_messages === 'cron_job' )
{ // Log a message for cron job:
cron_log_append( $log_message );
}
else
{ // Print out a message:
echo '<p>'.$log_message.'</p>';
evo_flush();
}
}
$chunk = 1000;
$number_of_chunks = ceil( ( $ids['max'] - $ids['min'] ) / $chunk );
if( $display_messages )
{ // Display info:
$log_message = TB_('Updating hit logs table...').' ('.$number_of_chunks.' chunks)';
if( $display_messages === 'cron_job' )
{ // Log a message for cron job:
cron_log_append( $log_message, NULL, '' );
// TODO: We must FORCE writing the log to the DB here
}
else
{ // Print out a message:
echo '<p>'.$log_message;
evo_flush();
}
}
$Timer->start( 'extract_keyphrase_update' );
// TODO: this still takes too much time!
// Let's try updating 1000 lines at a time.
$start = $ids['min'];
$i = 1;
while( $start <= $ids['max'] )
{
$stop = min( $start+$chunk-1, $ids['max'] ); // don't go over max
$log_message = 'Doing chunk #'.$i.' from '.$start.' to '.$stop.'...';
if( $display_messages === 'cron_job' )
{ // Log a message for cron job:
cron_log_append( $log_message );
}
else
{ // Print out a message:
echo '<br/>'.$log_message;
evo_flush();
}
$sql = 'UPDATE T_hitlog as h, T_track__keyphrase as k
SET h.hit_keyphrase_keyp_ID = k.keyp_ID
WHERE h.hit_keyphrase = k.keyp_phrase
AND h.hit_keyphrase != ""
AND ( h.hit_ID >= '.$start.' )
AND ( h.hit_ID <= '.$stop.' )
AND ( h.hit_keyphrase_keyp_ID IS NULL )';
$updated_keyphrases_num = $DB->query( $sql, 'Update hitlogs keyphrase id' );
$log_message = sprintf( TB_('%d records'), $updated_keyphrases_num );
if( $display_messages === 'cron_job' )
{ // Log a message for cron job:
cron_log_append( $log_message );
}
else
{ // Print out a message:
echo $log_message;
}
$start += $chunk;
$i++;
}
$Timer->stop( 'extract_keyphrase_update' );
if( $display_messages )
{ // Display info:
$log_message = 'Finished <span class="note">('.sprintf( TB_('Time: %s seconds'), $Timer->get_duration( 'extract_keyphrase_update' ) ).')</span>';
if( $display_messages === 'cron_job' )
{ // Log a message for cron job:
cron_log_append( $log_message );
}
else
{ // Print out a message:
echo '</p><p>'.$log_message.'</p>';
evo_flush();
}
}
}
$DB->get_var( 'SELECT RELEASE_LOCK( '.$DB->quote( $lock_name ).' )' );
return intval( $ids['keyphrases_num'] );
}
/**
* Parse extra params of goal hit (E.g. 'item_ID=123')
*
* @param string Value of extra params
* @param string
*/
function stats_goal_hit_extra_params( $ghit_params )
{
if( preg_match( '/^item_ID=([0-9]+)$/i', $ghit_params, $matches ) )
{ // Parse item ID
$ItemCache = & get_ItemCache();
if( $Item = & $ItemCache->get_by_ID( intval( $matches[1] ), false, false ) )
{ // Display a link to view with current item title
if( check_user_perm( 'item_post!CURSTATUS', 'edit', false, $Item ) )
{ // Link to admin view
return $Item->get_title( array( 'link_type' => 'admin_view' ) );
}
else
{ // Link to permament url (it is allowed for current post type)
return $Item->get_title();
}
}
}
return htmlspecialchars( $ghit_params );
}
/**
* Display panel with buttons to control a view of hits summary pages:
* - Two buttons to toggle between type of hits summary data(Live or Aggregate)
* - Button to aggregate hits and sessions right now
*
* @param array Diagram columns: key - code of column, value - title of column
*/
function display_hits_summary_panel( $diagram_columns = array() )
{
global $ReqURL;
$hits_summary_mode = get_hits_summary_mode();
$current_url = preg_replace( '/(\?|&)hits_summary_mode=([^&]+|$)/', '', $ReqURL );
echo '<div class="btn-group pull-left">';
// Button to switch to view the live hits:
echo '<a href="'.url_add_param( $current_url, 'hits_summary_mode=live' ).'"'
.' class="btn btn-default'.( $hits_summary_mode == 'live' ? ' active' : '' ).'">'
.T_('Live data')
.'</a>';
// Button to switch to view the aggregated hits data:
echo '<a href="'.url_add_param( $current_url, 'hits_summary_mode=aggregate' ).'"'
.' class="btn btn-default'.( $hits_summary_mode == 'aggregate' ? ' active' : '' ).'">'
.T_('Aggregate data')
.'</a>';
echo '</div>';
if( $hits_summary_mode == 'aggregate' || ! empty( $diagram_columns ) )
{
display_hits_filter_form( 'filter', $diagram_columns, $hits_summary_mode == 'aggregate' );
}
if( check_user_perm( 'stats', 'edit' ) )
{ // Display button to aggregate hits right now only if current user has a permission to edit hits:
echo '<a href="'.url_add_param( $current_url, 'action=aggregate&'.url_crumb( 'aggregate' ) ).'"'
.' class="btn btn-default pull-right">'
.T_('Aggregate Now')
.'</a>';
}
echo '<div class="clear"></div>';
}
function display_hits_filter_form( $mode, $diagram_columns, $display_filter_period = true )
{
global $UserSettings, $tab3;
switch( $mode )
{
case 'filter':
$period_selector_title = T_('Show');
$submit_button_text = T_('Filter');
$prefix = 'agg_';
$action = 'filter_hits_diagram';
$display_filter_diagram_cols = true;
$block_style = '';
$period_options = array(
'last_30_days' => sprintf( T_('Last %d days'), 30 ),
'last_60_days' => sprintf( T_('Last %d days'), 60 ),
'current_month' => T_( 'Current Month to date' ),
'specific_month' => T_( 'Specific Month:' ),
);
$years_length = 20;
break;
case 'compare':
$period_selector_title = T_('Compare to');
$submit_button_text = T_('Compare');
$prefix = 'aggcmp_';
$action = 'compare_hits_diagram';
$display_filter_diagram_cols = false;
$block_style = ' style="padding-left:0"';
$period_options = array(
'prev_30_days' => sprintf( T_('Previous %d days'), 30 ),
'prev_60_days' => sprintf( T_('Previous %d days'), 60 ),
'prev_month' => T_( 'Previous Month' ),
'specific_month' => T_( 'Specific Month:' ),
);
$years_length = 21;
break;
}
echo '<div class="evo_filter_diagram_hits"'.$block_style.'>';
$Form = new Form();
$Form->hidden( 'ctrl', 'stats' );
$Form->hidden( 'from_ctrl', get_param( 'ctrl' ) );
$Form->hidden( 'tab', get_param( 'tab' ) );
$Form->hidden( 'tab3', get_param( 'tab3' ) );
$Form->hidden( 'blog', get_param( 'blog' ) );
$Form->hidden( 'sec_ID', get_param( 'sec_ID' ) );
$Form->hidden( 'action', $action );
$Form->add_crumb( 'filterhitsdiagram' );
$Form->switch_layout( 'none' );
$Form->begin_form();
if( $display_filter_period )
{ // Filter the aggregated data by date period:
$Form->select_input_array( $prefix.'period', $UserSettings->get( $prefix.'period' ), $period_options, $period_selector_title );
$months_years_params = array( 'force_keys_as_values' => true );
if( $UserSettings->get( $prefix.'period' ) != 'specific_month' )
{
$months_years_params['style'] = 'display:none';
}
$months = array();
for( $m = 1; $m <= 12; $m++ )
{
$months[ $m ] = T_( date( 'F', mktime( 0, 0, 0, $m ) ) );
}
$month = $UserSettings->get( $prefix.'month' );
$Form->select_input_array( $prefix.'month', ( empty( $month ) ? date( 'n' ) : $month ), $months, '', NULL, $months_years_params );
$years = array();
for( $y = date( 'Y' ) - $years_length; $y <= date( 'Y' ); $y++ )
{
$years[ $y ] = $y;
}
$year = $UserSettings->get( $prefix.'year' );
$Form->select_input_array( $prefix.'year', ( empty( $year ) ? date( 'Y' ) : $year ), $years, '', NULL, $months_years_params );
echo '<script>
jQuery( "#'.$prefix.'period" ).change( function()
{
if( jQuery( this ).val() == "specific_month" )
{
jQuery( "#'.$prefix.'month, #'.$prefix.'year" ).show();
}
else
{
jQuery( "#'.$prefix.'month, #'.$prefix.'year" ).hide();
}
} );
</script>';
}
if( $display_filter_diagram_cols )
{
$filter_hits_diagram_cols = $UserSettings->get( 'filter_hits_diagram_cols' );
foreach( $diagram_columns as $diagram_column_key => $diagram_column_data )
{ // Filter hits by type:
$Form->checkbox_basic_input( 'filter_types[]',
( ! isset( $filter_hits_diagram_cols[ $tab3 ] ) || empty( $filter_hits_diagram_cols[ $tab3 ] ) || in_array( $diagram_column_key, $filter_hits_diagram_cols[ $tab3 ] ) ), // Is checked?
'<span style="color:#'.$diagram_column_data['color'].'">'.$diagram_column_data['title'].'</span>', // Colored title
array( 'value' => $diagram_column_key ) ); // Value
}
}
$Form->end_form( array( array( 'submit', 'submit', $submit_button_text, 'btn-info' ) ) );
echo '</div>';
if( $mode == 'compare' )
{
echo '<div class="clear"></div>';
}
}
/**
* Get dates for filter the aggregated hits
*
* @param string Data mode: 'aggregate', 'compare'
* @return array Array with two items: 0 - start date, 1 - end date
*/
function get_filter_aggregated_hits_dates( $mode = 'aggregate' )
{
global $DB, $UserSettings;
if( $mode == 'compare' )
{ // Use a filter for comparing data:
$period = $UserSettings->get( 'aggcmp_period' );
}
else
{ // Use a filter for aggregate data:
$period = $UserSettings->get( 'agg_period' );
}
$start_date = $end_date = array(
'm' => date( 'm' ),
'd' => date( 'd' ),
'Y' => date( 'Y' ),
);
switch( $period )
{
case 'prev_60_days':
$start_date['d'] -= 60; // Date of 120 days ago
$end_date['d'] -= 59; // Date of 61 days ago
case 'last_60_days':
$start_date['d'] -= 59; // Date of 60 days ago
$end_date['d'] -= 1; // Yesterday
break;
case 'prev_month':
$start_date['m'] -= 1; // First day of previous month
$end_date['d'] = 1; // Last day of previous month
case 'current_month':
$start_date['d'] = 1; // First day of current month
$end_date['d'] -= 1; // Yesterday
break;
case 'specific_month':
$agg_month = ( $mode == 'compare' ? $UserSettings->get( 'aggcmp_month' ) : $UserSettings->get( 'agg_month' ) );
$agg_year = ( $mode == 'compare' ? $UserSettings->get( 'aggcmp_year' ) : $UserSettings->get( 'agg_year' ) );
if( ! empty( $agg_month ) )
{ // Use month from setting:
$start_date['m'] = $agg_month;
$end_date['m'] = $agg_month + 1;
}
if( ! empty( $agg_year ) )
{ // Use year from setting:
$start_date['Y'] = $end_date['Y'] = $agg_year;
}
$start_date['d'] = 1; // First day of the selected month
$end_date['d'] = 0; // Last day of the selected month
break;
case 'prev_30_days':
$start_date['d'] -= 30; // Date of 60 days ago
$end_date['d'] -= 29; // Date of 31 days ago
case 'last_30_days':
default:
$start_date['d'] -= 29; // Date of 30 days ago
$end_date['d'] -= 1; // Yesterday
break;
}
return array(
date( 'Y-m-d', mktime( 0, 0, 0, $start_date['m'], $start_date['d'], $start_date['Y'] ) ),
date( 'Y-m-d', mktime( 0, 0, 0, $end_date['m'], $end_date['d'], $end_date['Y'] ) )
);
}
/**
* Get dates for filter the aggregated hits
*
* @param array All possible hits diagram columns
* @return array Filtered hits diagram columns
*/
function get_filtered_hits_diagram_columns( $diagram_type, $diagram_columns )
{
global $UserSettings;
if( empty( $diagram_type ) )
{ // Unknown diagram type:
return $diagram_columns;
}
$filter_hits_diagram_cols = $UserSettings->get( 'filter_hits_diagram_cols' );
if( ! isset( $filter_hits_diagram_cols[ $diagram_type ] ) )
{ // No filter is defiend yet:
return $diagram_columns;
}
if( empty( $filter_hits_diagram_cols[ $diagram_type ] ) )
{ // If all options are unchecked then check them all:
return $diagram_columns;
}
$filtered_cols = array();
foreach( $filter_hits_diagram_cols[ $diagram_type ] as $filter_diagram_col )
{
if( isset( $diagram_columns[ $filter_diagram_col ] ) )
{
$filtered_cols[ $filter_diagram_col ] = $diagram_columns[ $filter_diagram_col ];
}
}
return $filtered_cols;
}
/**
* Get mode of hits summary data
*
* @return string Mode: 'live' or 'aggregate'
*/
function get_hits_summary_mode()
{
global $Session;
$hits_summary_mode = $Session->get( 'hits_summary_mode' );
if( empty( $hits_summary_mode ) )
{ // Set mode to display the aggregated data by default:
$hits_summary_mode = 'aggregate';
}
return $hits_summary_mode;
}
/**
* Find the dates without hits and fill them with 0 to display on graph and table
*
* @param array Source hits data
* @param string Start date of hits log in format 'YYYY-mm-dd'
* @param string End date of hits log in format 'YYYY-mm-dd'
* @return array Fixed hits data
*/
// erwin> replaced with a more generic fill_empty_days() in _misc.funcs.php
function fill_empty_hit_days( $hits_data, $start_date, $end_date )
{
$fixed_hits_data = array();
if( empty( $hits_data ) )
{
return $fixed_hits_data;
}
// Get additional fields which must be exist in each array item of new filled empty day below:
$additional_fields = array_diff_key( $hits_data[0], array( 'hits' => 0, 'year' => 0, 'month' => 0, 'day' => 0 ) );
// Check if hits data array contains start and end dates:
$start_date_is_contained = empty( $start_date );
$end_date_is_contained = empty( $end_date );
if( ! $start_date_is_contained || ! $end_date_is_contained )
{
foreach( $hits_data as $hit )
{
$this_date = $hit['year'].'-'.$hit['month'].'-'.$hit['day'];
if( $this_date == $start_date )
{ // The start date is detected:
$start_date_is_contained = true;
}
if( $this_date == $end_date )
{ // The start date is detected:
$end_date_is_contained = true;
}
if( $start_date_is_contained && $end_date_is_contained )
{ // Stop array searching here because we have found the dates:
break;
}
}
}
if( ! $start_date_is_contained )
{ // Add item to array with 0 for start date if stats has no data for the date:
array_push( $hits_data, array(
'hits' => 0,
'year' => date( 'Y', strtotime( $start_date ) ),
'month' => date( 'n', strtotime( $start_date ) ),
'day' => date( 'j', strtotime( $start_date ) ),
) + $additional_fields );
}
if( ! $end_date_is_contained )
{ // Add item to array with 0 for end date if stats has no data for the date:
array_unshift( $hits_data, array(
'hits' => 0,
'year' => date( 'Y', strtotime( $end_date ) ),
'month' => date( 'n', strtotime( $end_date ) ),
'day' => date( 'j', strtotime( $end_date ) ),
) + $additional_fields );
}
foreach( $hits_data as $hit )
{
$this_date = $hit['year'].'-'.$hit['month'].'-'.$hit['day'];
if( isset( $prev_date ) && $prev_date != $this_date )
{ // If hits are from another day:
$prev_time = strtotime( $prev_date ) - 86400;
$this_time = strtotime( $this_date );
if( $prev_time != $this_time )
{ // If previous date is not previous day(it means some day has no hits):
$empty_days = ( $prev_time - $this_time ) / 86400;
for( $d = 0; $d <= $empty_days; $d++ )
{ // Add each empty day to array with 0 hits count:
$empty_day = $prev_time - $d * 86400;
$fixed_hits_data[] = array(
'hits' => 0,
'year' => date( 'Y', $empty_day ),
'month' => date( 'n', $empty_day ),
'day' => date( 'j', $empty_day ),
) + $additional_fields;
}
}
}
$prev_date = $hit['year'].'-'.$hit['month'].'-'.$hit['day'];
$fixed_hits_data[] = $hit;
}
return $fixed_hits_data;
}
/**
* Get full URL from hit URI and collection ID
*
* @param string Hit URI
* @param integer Hit collection ID
* @return string Full hit URL
*/
function get_hit_full_url( $hit_uri, $hit_coll_ID )
{
$hit_host = '';
if( ! empty( $hit_coll_ID ) )
{ // Try to get a collection if it was a hit from collection page:
$BlogCache = & get_BlogCache();
if( $Blog = & $BlogCache->get_by_ID( $hit_coll_ID, false, false ) )
{ // Get collection host:
$hit_host = $Blog->get_baseurl_root();
}
}
return $hit_host.$hit_uri;
}
/**
* Get the search engine parameter definitions.
*
* Based on search engine detections YAML list maintained and used by Matomo - {@link https://github.com/matomo-org/searchengine-and-social-list}
*
* @return array of search engine definitions
*/
function get_search_engine_params()
{
global $search_engine_params, $inc_path;
if( empty( $search_engine_params ) )
{
$search_engine_params = array();
// Load search engine definitions:
$search_engine_definitions = json_decode( file_get_contents( $inc_path.'_ext/matomo/SearchEngines.json' ) );
foreach( $search_engine_definitions as $name => $info )
{
if( empty( $info ) || !is_array( $info ) )
{
continue;
}
foreach( $info as $url_definitions )
{
$url_definitions = (array) $url_definitions;
foreach( $url_definitions['urls'] as $url )
{
$search_engine_data = $url_definitions;
unset( $search_engine_data['urls'] );
$search_engine_data['name'] = $name;
$search_engine_params[$url] = $search_engine_data;
}
}
}
}
return $search_engine_params;
}
?>