DIR : /home/kozerus/public_html/zc/adam/includes/classes/WhosOnline.php
/home/kozerus/public_html/zc/adam/includes/classes
<?php
/**
* @copyright Copyright 2003-2021 Zen Cart Development Team
* @license http://www.zen-cart.com/license/2_0.txt GNU Public License V2.0
* @version $Id: mc12345678 2021 Jan 03 Modified in v1.5.7c $
*/
class WhosOnline extends base
{
/* @var int seconds when considered inactive - 180 default = 3 minutes */
protected $timer_inactive_threshold = 180;
/* @var int seconds til dead, ie: considered dead after this long since last click; default 540 seconds = 9 minutes */
protected $timer_dead_threshold = 540;
/* @var int purge after how many seconds? default= 1200 = 20 minutes */
protected $timer_remove_threshold = 1200;
protected $total_sessions = 0;
protected $duplicates = 0;
protected $unique_sessions = 0;
protected $whos_online = [];
protected $user_array = [0 => 0, 1 => 0, 2 => 0, 3 => 0];
protected $guest_array = [0 => 0, 1 => 0, 2 => 0, 3 => 0];
protected $spider_array = [0 => 0, 1 => 0, 2 => 0, 3 => 0];
protected $statsCacheLastCalculatedAt = 0;
public function __construct($forceRebuild = false, $skip_gc = false)
{
if (defined('WHOIS_TIMER_REMOVE')) $this->timer_remove_threshold = WHOIS_TIMER_REMOVE;
if (defined('WHOIS_TIMER_INACTIVE')) $this->timer_inactive_threshold = WHOIS_TIMER_INACTIVE;
if (defined('WHOIS_TIMER_DEAD')) $this->timer_dead_threshold = WHOIS_TIMER_DEAD;
// normally we get rid of expired data
if (!$skip_gc) {
$this->doGarbageCollection();
}
// normally we don't retrieve all data on instantiation; passing true skips the statsCache check
if ($forceRebuild) {
$this->retrieve();
}
}
public function getTimerInactive()
{
return (int)$this->timer_inactive_threshold;
}
public function getTimerDead()
{
return (int)$this->timer_dead_threshold;
}
public function getUniques()
{
return (int)$this->unique_sessions;
}
public function getDuplicates()
{
return (int)$this->duplicates;
}
public function getTotalSessions()
{
return (int)$this->total_sessions;
}
public function retrieve($selectedView = '', $sessionToInspect = '', $exclude_spiders = false, $exclude_admins = true)
{
switch ($selectedView) {
case "full_name-desc":
$order = "full_name DESC, LPAD(ip_address,11,'0')";
break;
case "full_name":
$order = "full_name, LPAD(ip_address,11,'0')";
break;
case "ip_address":
$order = "ip_address, session_id";
break;
case "ip_address-desc":
$order = "ip_address DESC, session_id";
break;
case "time_last_click-desc":
$order = "time_last_click DESC, LPAD(ip_address,11,'0')";
break;
case "time_last_click":
$order = "time_last_click, LPAD(ip_address,11,'0')";
break;
case "time_entry-desc":
$order = "time_entry DESC, LPAD(ip_address,11,'0')";
break;
case "time_entry":
$order = "time_entry, LPAD(ip_address,11,'0')";
break;
case "last_page_url-desc":
$order = "last_page_url DESC, LPAD(ip_address,11,'0')";
break;
case "last_page_url":
$order = "last_page_url, LPAD(ip_address,11,'0')";
break;
case "session_id":
$order = "session_id, ip_address";
break;
case "session_id-desc":
$order = "session_id DESC, ip_address";
break;
default:
$order = "time_entry, LPAD(ip_address,11,'0')";
}
$where = '';
if ($exclude_spiders) {
$where = "WHERE session_id != '' ";
}
if ($exclude_admins) {
$where .= ($where == '') ? " WHERE " : " AND ";
$where .= "ip_address != '' AND ip_address NOT IN ('" . implode("','", preg_split('/[\s,]/', zen_db_input(EXCLUDE_ADMIN_IP_FOR_MAINTENANCE) . ',' . zen_db_input($_SERVER['REMOTE_ADDR']))) . "') ";
}
$sql = "SELECT customer_id, full_name, ip_address, time_entry, time_last_click, last_page_url, session_id, host_address, user_agent, s.value as session_data
FROM " . TABLE_WHOS_ONLINE . " w
LEFT OUTER JOIN " . TABLE_SESSIONS . " s ON (s.sesskey = w.session_id)
:where:
ORDER BY :orderby:";
global $db;
$sql = $db->bindVars($sql, ':where:', $where, 'passthru');
$sql = $db->bindVars($sql, ':orderby:', $order, 'passthru');
$results = $db->Execute($sql);
$ip_array = [];
$sessionInspectAll = false; // Limit the session inspection to just the one $sessionToInspect
// make the first entry show cart by default
if (empty($sessionToInspect) && !$results->EOF) {
$sessionToInspect = $results->fields['session_id']; // uses the fields array because we're not iterating the array yet
$sessionInspectAll = true; // No specific session was requested, so make all available.
}
foreach ($results as $result) {
if ($sessionInspectAll === true) {
$sessionToInspect = $result['session_id'];
}
$result['time_online'] = (time() - $result['time_entry']);
$result['is_a_bot'] = empty($result['session_id']);
$result['time_since_last_click'] = $this->getHumanFriendlyTimeSince($result['time_last_click']);
$result['status_code'] = $this->getStatusCode($result); // depends on having the 'time_last_click' and 'session_data' from the query
$result['icon_image'] = $this->getImageForStatus($result['status_code']);
$result['icon_class'] = $this->getIconClassForStatus($result['status_code']);
// if a session_id has been passed, we inspect it now to save re-querying and re-processing
$result['cart'] = null;
if (!empty($sessionToInspect) && $sessionToInspect === $result['session_id']) {
$result['cart'] = $this->inspectSessionCart($result['session_id'], $result['session_data']);
}
unset($result['session_data']);
$this->whos_online[$result['session_id']] = $result;
// track duplicate IPs
if (in_array($result['ip_address'], $ip_array)) {
$this->duplicates++;
} else {
$ip_array[] = $result['ip_address'];
}
}
if (empty($this->duplicates)) {
$this->duplicates = 0;
}
$this->total_sessions = $results->RecordCount();
$this->unique_sessions = $this->total_sessions - $this->duplicates;
$this->calculateStats();
return $this->whos_online;
}
public function getImageForStatus($status_code = 0)
{
switch ($status_code) {
case 3:
return zen_image(DIR_WS_IMAGES . 'icon_status_red_light.gif');
case 2:
return zen_image(DIR_WS_IMAGES . 'icon_status_red.gif');
case 1:
return zen_image(DIR_WS_IMAGES . 'icon_status_yellow.gif');
default:
case 0:
return zen_image(DIR_WS_IMAGES . 'icon_status_green.gif');
}
}
// future-use CSS classes for icons
public function getIconClassForStatus($status_code = 0)
{
switch ($status_code) {
case 3:
return 'wo-inactive-empty';
case 2:
return 'wo-active-empty';
case 1:
return 'wo-inactive-not-empty';
default:
case 0:
return 'wo-active-not-empty';
}
}
public function getStats()
{
if ($this->statsCacheLastCalculatedAt < (time() - 15)) {
$this->retrieve();
}
return ['user_array' => $this->user_array, 'guest_array' => $this->guest_array, 'spider_array' => $this->spider_array];
}
protected function getHumanFriendlyTimeSince($timestamp_of_last_click)
{
$diff_in_seconds = (time() - $timestamp_of_last_click);
return gmdate('H:i:s', $diff_in_seconds);
}
protected function getStatusCode($data)
{
$xx_mins_ago_long = (time() - (int)$this->timer_inactive_threshold);
// empty session data means definitely no cart (or not parseable, so we treat as empty)
if (empty($data['session_data'])) {
if ($data['time_last_click'] < $xx_mins_ago_long) {
return 3;
}
return 2;
}
$chk_cart_status = base64_decode($data['session_data']);
// lookup how many rows are in the shopping cart contents array
if (preg_match('/shoppingCart":\d*:{s:\d*:"(contents)";a:(\d*):/', $chk_cart_status, $matches)) {
$rows_in_cart = $matches[2];
}
if (empty($rows_in_cart)) {
if ($data['time_last_click'] < $xx_mins_ago_long) {
return 3; // empty inactive
}
return 2; // empty active
}
if ($rows_in_cart > 0) {
if ($data['time_last_click'] < $xx_mins_ago_long) {
return 1; // not-empty, inactive
}
return 0; // not-empty, active
}
}
protected function calculateStats()
{
foreach ($this->whos_online as $session) {
if (empty($session['session_id'])) {
$this->spider_array[$session['status_code']]++;
} else {
if ($session['full_name'] === "¥Guest") {
$this->guest_array[$session['status_code']]++;
} else {
$this->user_array[$session['status_code']]++;
}
}
}
}
/**
* Remove expired entries
*/
public function doGarbageCollection()
{
global $db;
$xx_mins_ago_dead = (time() - (int)$this->timer_dead_threshold);
$xx_mins_ago = (time() - (int)$this->timer_remove_threshold);
$db->Execute("DELETE FROM " . TABLE_WHOS_ONLINE . "
WHERE time_last_click < '" . $xx_mins_ago . "'
OR (time_entry=time_last_click
AND time_last_click < '" . $xx_mins_ago_dead . "')");
}
/**
* @param string $session_id
* @param string $session_data
* @return array|null
*/
protected function inspectSessionCart($session_id = '', $session_data = '')
{
// we need at least one of these parameters
if (empty($session_id) && empty($session_data)) return null;
// or we can pass in the already-queried session data
if (empty($session_data)) {
$result = $GLOBALS['db']->Execute("
SELECT value as session_data
FROM " . TABLE_SESSIONS . "
WHERE sesskey = '" . zen_db_input($session_id) . "'");
$session_data = $result->EOF === false ? trim($result->fields['session_data']) : '';
}
if (strpos($session_data, 'cart|O') == 0) {
$session_data = base64_decode($session_data);
}
if (strpos($session_data, 'cart|O') == 0) {
$session_data = '';
}
if (empty($session_data)) {
return null;
}
$extracted_data = [];
$fields_to_extract = [
'language' => 'language_name',
'languages_id' => 'language_id',
'languages_code' => 'language_code',
'customers_ip_address' => 'customer_ip',
'customers_host_address' => 'customer_hostname',
'customers_email_address' => 'customers_email_address',
'customer_default_address_id' => 'address_default_id',
'billto' => 'address_billing_id',
'sendto' => 'address_delivery_id',
'customer_country_id' => 'customer_country_id',
'customer_zone_id' => 'customer_zone_id',
'shipping_weight' => 'shipping_weight',
'shipping' => 'shipping',
'payment' => 'payment',
'cot_gv' => 'cot_gv',
'cart_errors' => 'cart_errors',
'comments' => 'checkout_comments',
];
$adminSession = session_encode();
$backupSessionArray = $_SESSION;
if (session_decode($session_data) !== false) {
$cart = $_SESSION['cart'];
$currency = $_SESSION['currency'];
if (is_object($cart) && isset($currency)) {
$extracted_data['products'] = $cart->get_products();
$extracted_data['total'] = $GLOBALS['currencies']->format($cart->show_total(), true, $currency);
$extracted_data['cartObject'] = $cart;
$extracted_data['currency_code'] = $currency;
$extracted_data['cartID'] = $_SESSION['cartID'];
}
foreach($fields_to_extract as $field => $as) {
if (isset($_SESSION[$field])) {
$extracted_data[$as] = $_SESSION[$field];
}
}
}
// protect against tampering
$_SESSION = $backupSessionArray;
foreach($_SESSION as $key => $value) {
if (!isset($backupSessionArray[$key])) {
unset($_SESSION[$key]);
}
}
session_decode($adminSession);
unset($adminSession, $backupSessionArray);
return $extracted_data;
}
}
//
koh5_pano
Drag mouse to navigate.
Navigation
- Left/Right Mouse drag: Changes camera heading.
- Up/Sown Mouse drag: Changes camera pitch.
- Scroll wheel: Changes camera field of view.
- I-Key: Displays Info panel with canvas size, image size and FPS.
17.Aug.2010, Martin Wengenmayer