2020-01-20 11:28:25 +00:00
|
|
|
|
<?php
|
|
|
|
|
if (!file_exists(__DIR__ . '/config.php')) {
|
|
|
|
|
die("ERROR: Millions not installed.");
|
|
|
|
|
}
|
|
|
|
|
$config = require 'config.php';
|
|
|
|
|
$pdo = new MyPDO('sqlite:' . __DIR__ . '/' . $config['database']);
|
|
|
|
|
|
|
|
|
|
$site = false;
|
2020-02-04 10:36:20 +00:00
|
|
|
|
$error = false;
|
2020-01-20 11:28:25 +00:00
|
|
|
|
|
|
|
|
|
if (!empty($_GET['for'])) {
|
|
|
|
|
$site = $pdo->run('SELECT * FROM sites WHERE host=?', [$_GET['for']])->fetch();
|
2020-02-04 10:36:20 +00:00
|
|
|
|
|
|
|
|
|
if ($site && $site['stats_public']==0) {
|
|
|
|
|
if (!isset($_GET['key']) || $_GET['key']!=$site['stats_key']) {
|
|
|
|
|
// we need password
|
|
|
|
|
$site = false;
|
|
|
|
|
$error = 'These stats are locked. You need to provide right ?key in URL.';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-20 11:28:25 +00:00
|
|
|
|
if ($site) {
|
|
|
|
|
|
|
|
|
|
$labels = $visits = $uniques = [];
|
2020-01-20 14:56:52 +00:00
|
|
|
|
for ($d=14; $d>=0; $d--) {
|
2020-01-20 11:28:25 +00:00
|
|
|
|
$labels[date('Y-m-d', strtotime('-'.$d.'days'))] = date('Dd', strtotime('-'.$d.'days'));
|
|
|
|
|
$visits[date('Y-m-d', strtotime('-'.$d.'days'))] = 0;
|
|
|
|
|
$uniques[date('Y-m-d', strtotime('-'.$d.'days'))] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$last14days = $pdo->run('SELECT date(datetime(ts, \'unixepoch\')) as date, COUNT(*) as visits
|
|
|
|
|
FROM visits
|
|
|
|
|
WHERE site_id=:site_id AND date>=:date_min AND date<=:date_max
|
|
|
|
|
GROUP BY date', [':site_id'=>$site['id'], ':date_min'=>date('Y-m-d', strtotime('-14 days')), ':date_max'=>date('Y-m-d')]);
|
|
|
|
|
foreach ($last14days as $stat) {
|
|
|
|
|
$visits[$stat['date']] = (int) $stat['visits'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$last14daysUniq = $pdo->run('SELECT date(datetime(ts, \'unixepoch\')) as date, COUNT(*) as visits
|
|
|
|
|
FROM visits
|
|
|
|
|
WHERE site_id=:site_id AND is_unique=1 AND date>=:date_min AND date<=:date_max
|
|
|
|
|
GROUP BY date', [':site_id'=>$site['id'], ':date_min'=>date('Y-m-d', strtotime('-14 days')), ':date_max'=>date('Y-m-d')]);
|
|
|
|
|
foreach ($last14daysUniq as $stat) {
|
|
|
|
|
$uniques[$stat['date']] = (int) $stat['visits'];
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-20 14:56:52 +00:00
|
|
|
|
$totalVisits = $pdo->run('SELECT COUNT(*) FROM visits WHERE site_id=?', [$site['id']])->fetchColumn();
|
|
|
|
|
$byPaths = $pdo->run('SELECT path, COUNT(*) as visits
|
|
|
|
|
FROM visits
|
|
|
|
|
WHERE site_id=?
|
|
|
|
|
GROUP BY path
|
2020-02-04 10:47:28 +00:00
|
|
|
|
ORDER BY visits DESC LIMIT 10', [$site['id']])->fetchAll();
|
2020-01-20 14:56:52 +00:00
|
|
|
|
$byBrowsers = $pdo->run('SELECT browser, COUNT(*) as visits
|
|
|
|
|
FROM visits
|
2020-02-04 10:47:28 +00:00
|
|
|
|
WHERE site_id=? AND is_bot!=1
|
2020-01-20 14:56:52 +00:00
|
|
|
|
GROUP BY browser
|
|
|
|
|
ORDER BY visits DESC', [$site['id']])->fetchAll();
|
|
|
|
|
$byPlatforms = $pdo->run('SELECT platform, COUNT(*) as visits
|
|
|
|
|
FROM visits
|
2020-02-04 10:47:28 +00:00
|
|
|
|
WHERE site_id=? AND is_bot!=1
|
2020-01-20 14:56:52 +00:00
|
|
|
|
GROUP BY platform
|
|
|
|
|
ORDER BY visits DESC', [$site['id']])->fetchAll();
|
|
|
|
|
$byRefs = $pdo->run('SELECT ref, COUNT(*) as visits
|
|
|
|
|
FROM visits
|
|
|
|
|
WHERE site_id=? AND ref!=""
|
|
|
|
|
GROUP BY ref
|
|
|
|
|
ORDER BY visits DESC', [$site['id']])->fetchAll();
|
|
|
|
|
|
2020-02-04 10:47:28 +00:00
|
|
|
|
$byBots = $pdo->run('SELECT browser, COUNT(*) as visits
|
|
|
|
|
FROM visits
|
|
|
|
|
WHERE site_id=? AND is_bot=1
|
|
|
|
|
GROUP BY browser
|
|
|
|
|
ORDER BY visits DESC', [$site['id']])->fetchAll();
|
|
|
|
|
|
2020-01-20 14:56:52 +00:00
|
|
|
|
|
2020-01-20 11:31:04 +00:00
|
|
|
|
} else {
|
2020-02-04 11:00:52 +00:00
|
|
|
|
if (!$error) {
|
|
|
|
|
$error = 'We do not track this site.';
|
|
|
|
|
}
|
2020-01-20 11:28:25 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$sites = $pdo->run('SELECT host, label, COUNT(*) AS visits, stats_public
|
|
|
|
|
FROM visits
|
|
|
|
|
INNER JOIN sites ON visits.site_id=sites.id
|
|
|
|
|
GROUP BY site_id
|
|
|
|
|
ORDER BY visits DESC');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
?><!DOCTYPE html>
|
|
|
|
|
<html lang="cs">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<title>stats <?php if ($site) echo ' - ' . $site['label']; ?></title>
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
|
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/yegor256/tacit@gh-pages/tacit-css-1.5.1.min.css"/>
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.js"></script>
|
2020-01-20 14:56:52 +00:00
|
|
|
|
<style>
|
|
|
|
|
.progress { display: block; width: 100%; height: 5px; background-color: lightgrey; }
|
|
|
|
|
.progress > div { background-color: green; height: 5px; }
|
|
|
|
|
</style>
|
2020-01-20 11:28:25 +00:00
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<section>
|
|
|
|
|
<a href="stats.php">Millions web counter</a>:
|
|
|
|
|
<?php if ($site) { ?>
|
|
|
|
|
<h1><?php echo $site['label']; ?></h1>
|
|
|
|
|
<canvas id="canvas"></canvas>
|
|
|
|
|
<script>
|
|
|
|
|
window.chartColors = {
|
|
|
|
|
red: 'rgb(255, 99, 132)',
|
|
|
|
|
orange: 'rgb(255, 159, 64)',
|
|
|
|
|
yellow: 'rgb(255, 205, 86)',
|
|
|
|
|
green: 'rgb(75, 192, 192)',
|
|
|
|
|
blue: 'rgb(54, 162, 235)',
|
|
|
|
|
purple: 'rgb(153, 102, 255)',
|
|
|
|
|
grey: 'rgb(201, 203, 207)'
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var color = Chart.helpers.color;
|
|
|
|
|
var barChartData = {
|
|
|
|
|
labels: <?php echo json_encode(array_values($labels)); ?>,
|
|
|
|
|
datasets: [{
|
|
|
|
|
label: 'Total visitors',
|
|
|
|
|
backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
|
|
|
|
|
borderColor: window.chartColors.red,
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
fill: false,
|
|
|
|
|
lineTension: 0,
|
|
|
|
|
data: <?php echo json_encode(array_values($visits)); ?>
|
|
|
|
|
}, {
|
|
|
|
|
label: 'Unique visitors',
|
|
|
|
|
backgroundColor: color(window.chartColors.blue).alpha(0.5).rgbString(),
|
|
|
|
|
borderColor: window.chartColors.blue,
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
fill: false,
|
|
|
|
|
lineTension: 0,
|
|
|
|
|
data: <?php echo json_encode(array_values($uniques)); ?>
|
|
|
|
|
}]
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
window.onload = function() {
|
|
|
|
|
var ctx = document.getElementById('canvas').getContext('2d');
|
|
|
|
|
window.myBar = new Chart(ctx, {
|
|
|
|
|
type: 'line',
|
|
|
|
|
data: barChartData,
|
|
|
|
|
options: {
|
|
|
|
|
responsive: true,
|
|
|
|
|
legend: {
|
|
|
|
|
position: 'top',
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
</script>
|
2020-01-20 14:56:52 +00:00
|
|
|
|
|
|
|
|
|
|
2020-01-20 11:28:25 +00:00
|
|
|
|
<?php
|
2020-01-20 14:56:52 +00:00
|
|
|
|
if (count($byPaths)) {
|
2020-02-04 10:47:28 +00:00
|
|
|
|
echo '<h2>Top '.count($byPaths).' visited pages</h2>';
|
2020-01-20 14:56:52 +00:00
|
|
|
|
foreach ($byPaths as $page) {
|
|
|
|
|
echo '<div><a href="//' . $site['host'] . $page['path'] . '">'.$page['path'].'</a>';
|
2020-02-04 10:52:44 +00:00
|
|
|
|
echo ' ' . $page['visits'] . '× - ' . pct($page['visits'], $totalVisits) . '%<div class="progress"><div style="width: '.pct($page['visits'], $totalVisits).'%"></div></div>';
|
2020-01-20 14:56:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (count($byBrowsers)) {
|
|
|
|
|
echo '<h2>Top browsers</h2>';
|
|
|
|
|
foreach ($byBrowsers as $page) {
|
|
|
|
|
echo '<div>'.$page['browser'].'';
|
2020-02-04 10:52:44 +00:00
|
|
|
|
echo ' ' . $page['visits'] . '× - ' . pct($page['visits'], $totalVisits) . '%<div class="progress"><div style="width: '.pct($page['visits'], $totalVisits).'%"></div></div>';
|
2020-01-20 14:56:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (count($byPlatforms)) {
|
|
|
|
|
echo '<h2>Top platforms</h2>';
|
|
|
|
|
foreach ($byPlatforms as $page) {
|
|
|
|
|
echo '<div>'.$page['platform'];
|
2020-02-04 10:52:44 +00:00
|
|
|
|
echo ' ' . $page['visits'] . '× - ' . pct($page['visits'], $totalVisits) . '%<div class="progress"><div style="width: '.pct($page['visits'], $totalVisits).'%"></div></div>';
|
2020-01-20 14:56:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (count($byRefs)) {
|
|
|
|
|
echo '<h2>Top references</h2>';
|
|
|
|
|
foreach ($byRefs as $page) {
|
|
|
|
|
echo '<div>'.$page['ref'];
|
2020-02-04 10:52:44 +00:00
|
|
|
|
echo ' ' . $page['visits'] . '× - ' . pct($page['visits'], $totalVisits) . '%<div class="progress"><div style="width: '.pct($page['visits'], $totalVisits).'%"></div></div>';
|
2020-01-20 14:56:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-04 10:47:28 +00:00
|
|
|
|
if (count($byBots)) {
|
|
|
|
|
echo '<h2>Top bots</h2>';
|
|
|
|
|
foreach ($byBots as $page) {
|
|
|
|
|
echo '<div>'.$page['browser'];
|
2020-02-04 10:52:44 +00:00
|
|
|
|
echo ' ' . $page['visits'] . '× - ' . pct($page['visits'], $totalVisits) . '%<div class="progress"><div style="width: '.pct($page['visits'], $totalVisits).'%"></div></div>';
|
2020-02-04 10:47:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-20 14:56:52 +00:00
|
|
|
|
?>
|
|
|
|
|
|
|
|
|
|
<?php
|
2020-01-20 11:28:25 +00:00
|
|
|
|
|
2020-02-04 10:36:20 +00:00
|
|
|
|
} elseif ($error) {
|
|
|
|
|
echo '<br><strong>'.$error.'</strong>';
|
2020-01-20 11:28:25 +00:00
|
|
|
|
} else {
|
|
|
|
|
echo '<table><tr><th>Site</th><th>domain</th><th>#visits</th></tr>';
|
|
|
|
|
foreach ($sites as $site) {
|
|
|
|
|
echo '<tr><td>'.$site['label'].'</td><td>'.$site['host'].'</td><td>';
|
|
|
|
|
if ($site['stats_public']) echo '<a href="stats.php?for=' . $site['host'] . '">';
|
|
|
|
|
echo $site['visits'];
|
|
|
|
|
if ($site['stats_public']) echo '</a>';
|
|
|
|
|
echo '</td></tr>';
|
|
|
|
|
}
|
|
|
|
|
echo '</table>';
|
|
|
|
|
}
|
|
|
|
|
?>
|
2020-01-20 15:27:50 +00:00
|
|
|
|
<hr>
|
|
|
|
|
<a href="/">about/privacy policy</a>
|
2020-01-20 11:28:25 +00:00
|
|
|
|
</section>
|
2020-01-20 14:56:52 +00:00
|
|
|
|
|
2020-01-20 11:28:25 +00:00
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
class MyPDO extends PDO
|
|
|
|
|
{
|
|
|
|
|
public function __construct($dsn, $username = NULL, $password = NULL, $options = [])
|
|
|
|
|
{
|
|
|
|
|
$default_options = [
|
|
|
|
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
|
|
|
|
PDO::ATTR_EMULATE_PREPARES => false,
|
|
|
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
|
|
|
];
|
|
|
|
|
$options = array_replace($default_options, $options);
|
|
|
|
|
parent::__construct($dsn, $username, $password, $options);
|
|
|
|
|
}
|
|
|
|
|
public function run($sql, $args = NULL)
|
|
|
|
|
{
|
|
|
|
|
if (!$args)
|
|
|
|
|
{
|
|
|
|
|
return $this->query($sql);
|
|
|
|
|
}
|
|
|
|
|
$stmt = $this->prepare($sql);
|
|
|
|
|
$stmt->execute($args);
|
|
|
|
|
return $stmt;
|
|
|
|
|
}
|
2020-01-20 14:56:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function pct($of, $total){
|
|
|
|
|
$p1 = $total / 100;
|
|
|
|
|
return round($of / $p1);
|
2020-01-20 11:28:25 +00:00
|
|
|
|
}
|