millions/stats.php

298 lines
9.9 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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;
$error = false;
if (!empty($_GET['for'])) {
$site = $pdo->run('SELECT * FROM sites WHERE host=?', [$_GET['for']])->fetch();
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.';
}
}
if ($site) {
if (!empty($_GET['date'])) {
$visits = false;
$totalVisits = $pdo->run('SELECT COUNT(*) FROM visits WHERE site_id=? AND date(ts, "unixepoch")=?', [$site['id'], $_GET['date']])->fetchColumn();
$byPaths = $pdo->run('SELECT path, COUNT(*) as visits
FROM visits
WHERE site_id=? AND date(ts, "unixepoch")=?
GROUP BY path
ORDER BY visits DESC LIMIT 10', [$site['id'], $_GET['date']])->fetchAll();
$byBrowsers = $pdo->run('SELECT browser, COUNT(*) as visits
FROM visits
WHERE site_id=? AND is_bot=0 AND date(ts, "unixepoch")=?
GROUP BY browser
ORDER BY visits DESC', [$site['id'], $_GET['date']])->fetchAll();
$byPlatforms = $pdo->run('SELECT platform, COUNT(*) as visits
FROM visits
WHERE site_id=? AND is_bot=0 AND date(ts, "unixepoch")=?
GROUP BY platform
ORDER BY visits DESC', [$site['id'], $_GET['date']])->fetchAll();
$byRefs = $pdo->run('SELECT ref, COUNT(*) as visits
FROM visits
WHERE site_id=? AND ref!="" AND date(ts, "unixepoch")=?
GROUP BY ref
ORDER BY visits DESC', [$site['id'], $_GET['date']])->fetchAll();
$byBots = $pdo->run('SELECT browser, COUNT(*) as visits
FROM visits
WHERE site_id=? AND is_bot=1 AND date(ts, "unixepoch")=?
GROUP BY browser
ORDER BY visits DESC', [$site['id'], $_GET['date']])->fetchAll();
} else {
$labels = $visits = $uniques = [];
for ($d=14; $d>=0; $d--) {
$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'];
}
$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
ORDER BY visits DESC LIMIT 10', [$site['id']])->fetchAll();
$byBrowsers = $pdo->run('SELECT browser, COUNT(*) as visits
FROM visits
WHERE site_id=? AND is_bot=0
GROUP BY browser
ORDER BY visits DESC', [$site['id']])->fetchAll();
$byPlatforms = $pdo->run('SELECT platform, COUNT(*) as visits
FROM visits
WHERE site_id=? AND is_bot=0
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();
$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();
}
} else {
if (!$error) {
$error = 'We do not track this site.';
}
}
} 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>
<style>
.progress { display: block; width: 100%; height: 5px; background-color: lightgrey; }
.progress > div { background-color: green; height: 5px; }
</style>
</head>
<body>
<section>
<a href="stats.php">Millions web counter</a>:
<?php if ($site) { ?>
<h1><?php echo $site['label']; ?></h1>
<?php if ($visits) { ?>
<canvas id="canvas"></canvas>
<?php foreach ($labels as $ymd=>$label) {
echo '<a href="stats.php?for=' . $site['host'] . '&date=' . $ymd . '">' . $label . '</a> ';
} ?>
<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>
<?php } // if $visits ?>
<?php
if ($totalVisits==0 && !empty($_GET['date'])) {
echo '<p>no visits this day!</p>';
}
if (count($byPaths)) {
echo '<h2>Top '.count($byPaths).' visited pages</h2>';
foreach ($byPaths as $page) {
echo '<div><a href="//' . $site['host'] . $page['path'] . '" rel="nofollow">'.$page['path'].'</a>';
echo ' ' . $page['visits'] . '× - ' . pct($page['visits'], $totalVisits) . '%<div class="progress"><div style="width: '.pct($page['visits'], $totalVisits).'%"></div></div>';
}
}
if (count($byBrowsers)) {
echo '<h2>Top browsers</h2>';
foreach ($byBrowsers as $page) {
echo '<div>'.$page['browser'].'';
echo ' ' . $page['visits'] . '× - ' . pct($page['visits'], $totalVisits) . '%<div class="progress"><div style="width: '.pct($page['visits'], $totalVisits).'%"></div></div>';
}
}
if (count($byPlatforms)) {
echo '<h2>Top platforms</h2>';
foreach ($byPlatforms as $page) {
echo '<div>'.$page['platform'];
echo ' ' . $page['visits'] . '× - ' . pct($page['visits'], $totalVisits) . '%<div class="progress"><div style="width: '.pct($page['visits'], $totalVisits).'%"></div></div>';
}
}
if (count($byRefs)) {
echo '<h2>Top references</h2>';
foreach ($byRefs as $page) {
echo '<div>'.$page['ref'];
echo ' ' . $page['visits'] . '× - ' . pct($page['visits'], $totalVisits) . '%<div class="progress"><div style="width: '.pct($page['visits'], $totalVisits).'%"></div></div>';
}
}
if (count($byBots)) {
echo '<h2>Top bots</h2>';
foreach ($byBots as $page) {
echo '<div>'.$page['browser'];
echo ' ' . $page['visits'] . '× - ' . pct($page['visits'], $totalVisits) . '%<div class="progress"><div style="width: '.pct($page['visits'], $totalVisits).'%"></div></div>';
}
}
?>
<?php
} elseif ($error) {
echo '<br><strong>'.$error.'</strong>';
} 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'] . '" rel="nofollow">';
echo $site['visits'];
if ($site['stats_public']) echo '</a>';
echo '</td></tr>';
}
echo '</table>';
}
?>
<hr>
<a href="/">about/privacy policy</a>
</section>
</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;
}
}
function pct($of, $total){
$p1 = $total / 100;
return round($of / $p1);
}