| Server IP : 216.238.66.20 / Your IP : 216.73.216.199 Web Server : nginx/1.30.4 System : Linux woropds 5.15.0-187-generic #197-Ubuntu SMP Fri Jul 17 19:17:01 UTC 2026 x86_64 User : root ( 0) PHP Version : 8.2.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /var/www/sweetheart.mx/htdocs/wp-content/plugins/wp-slimstat/src/Helpers/ |
Upload File : |
<?php
namespace SlimStat\Helpers;
// don't load directly.
if (! defined('ABSPATH')) {
header('Status: 403 Forbidden');
header('HTTP/1.1 403 Forbidden');
exit;
}
class DataBuckets
{
private const DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
private $labels = [];
private $prev_labels = [];
private $datasets = ['v1' => [], 'v2' => []];
private $datasetsPrev = ['v1' => [], 'v2' => []];
private $totals;
private $labelFormat;
private $gran;
private $tzOffset;
private $start;
private $end;
private $prevStart;
private $prevEnd;
private $points;
public function __construct(string $labelFormat, string $gran, int $start, int $end, int $prevStart, int $prevEnd, array $totals = [])
{
$wpdb = \wp_slimstat::$wpdb ?? $GLOBALS['wpdb'];
$this->labelFormat = $labelFormat;
$this->gran = $gran;
$this->start = $start;
$this->end = $end;
$this->prevStart = $prevStart;
$this->prevEnd = $prevEnd;
$this->totals = $totals;
$offset_seconds = $wpdb->get_var('SELECT TIMESTAMPDIFF(SECOND, UTC_TIMESTAMP(), NOW())');
$sign = ($offset_seconds < 0) ? '-' : '+';
$abs = abs($offset_seconds);
$h = floor($abs / 3600);
$m = floor(($abs % 3600) / 60);
$tzOffset = sprintf('%s%02d:%02d', $sign, $h, $m);
$this->tzOffset = $tzOffset;
$this->initBuckets();
}
private function initBuckets(): void
{
switch ($this->gran) {
case 'HOUR':
$this->initSeq(3600);
break;
case 'DAY':
$this->initSeq(86400);
break;
case 'WEEK':
$this->initSeqWeek();
break;
case 'MONTH':
$this->initSeqMonth();
break;
case 'YEAR':
$this->initSeqYear();
break;
}
}
private function initSeq(int $interval): void
{
$range = $this->end - $this->start;
$count = (int)ceil($range / $interval);
$time = $this->start;
for ($i = 0; $i < $count; $i++) {
$label = date($this->labelFormat, $time);
$this->labels[] = sprintf("'%s'", $label);
foreach (['v1', 'v2'] as $k) {
$this->datasets[$k][] = 0;
$this->datasetsPrev[$k][] = 0;
}
$time += $interval;
}
$this->points = $count;
}
private function initSeqWeek(): void
{
$start = (new \DateTime())->setTimestamp($this->start);
$end = (new \DateTime())->setTimestamp($this->end);
$startOfWeek = (int) get_option('start_of_week', 1);
// Adjust start to the first day of the week
$firstLabel = $start->format($this->labelFormat);
$this->labels[] = sprintf("'%s'", $firstLabel);
foreach (['v1', 'v2'] as $k) {
$this->datasets[$k][] = 0;
$this->datasetsPrev[$k][] = 0;
}
// Move start to the next week if it is not the start of the week
$start->modify('next ' . (self::DAY_NAMES[$startOfWeek] ?? 'Monday'));
if ($start->getTimestamp() <= $this->start) {
$start->modify('+1 week');
}
// Generate labels for each week
while ($start <= $end) {
$label = $start->format($this->labelFormat);
$this->labels[] = sprintf("'%s'", $label);
foreach (['v1', 'v2'] as $k) {
$this->datasets[$k][] = 0;
$this->datasetsPrev[$k][] = 0;
}
$start->modify('+1 week');
}
$this->points = count($this->labels);
}
private function initSeqMonth(): void
{
$date = (new \DateTime())->setTimestamp($this->start)->modify('first day of this month')->modify('midnight');
$end = (new \DateTime())->setTimestamp($this->end);
while ($date <= $end) {
$label = $date->format($this->labelFormat);
$this->labels[] = sprintf("'%s'", $label);
foreach (['v1', 'v2'] as $k) {
$this->datasets[$k][] = 0;
$this->datasetsPrev[$k][] = 0;
}
$date->modify('+1 month');
}
$this->points = count($this->labels);
}
private function initSeqYear(): void
{
$startYear = (int)date('Y', $this->start);
$endYear = (int)date('Y', $this->end);
for ($y = $startYear; $y <= $endYear; $y++) {
$this->labels[] = sprintf("'%d'", $y);
foreach (['v1', 'v2'] as $k) {
$this->datasets[$k][] = 0;
$this->datasetsPrev[$k][] = 0;
}
}
$this->points = count($this->labels);
}
public function addRow(int $dt, int $v1, int $v2, string $period): void
{
$base = 'current' === $period ? $this->start : $this->prevStart;
$base = strtotime(date('Y-m-d H:i:s', $base));
$dt = strtotime(wp_date('Y-m-d H:i:s', $dt, new \DateTimeZone($this->tzOffset)));
$start = $this->start;
if ('HOUR' === $this->gran) {
$dt = strtotime(date('Y-m-d H:00:00', $dt));
$offset = floor(($dt - $base) / 3600);
} elseif ('DAY' === $this->gran) {
$offset = floor(($dt - $base) / 86400);
} elseif ('MONTH' === $this->gran) {
$start = new \DateTime('@' . $base);
$start = $start->modify('first day of this month')->modify('midnight');
// Guard against invalid/empty $dt
$safeDt = is_numeric($dt) ? $dt : 0;
$target = new \DateTime('@' . $safeDt);
if ($target->getTimestamp() < $start->getTimestamp()) {
$offset = -1;
} else {
$diff = $start->diff($target);
$offset = $diff->y * 12 + $diff->m;
}
} elseif ('WEEK' === $this->gran) {
// Calculate the start-of-week date for both base and dt
// This respects WordPress start_of_week setting instead of using ISO weeks
$baseWeekStart = $this->getWeekStartTimestamp($base);
$dtWeekStart = $this->getWeekStartTimestamp($dt);
// Calculate weeks between the two week start dates
$offset = (int) round(($dtWeekStart - $baseWeekStart) / (7 * 86400));
if ($offset < 0) {
$offset = -1;
}
} elseif ('YEAR' === $this->gran) {
$offset = (new \DateTime('@' . $base))->diff(new \DateTime('@' . $dt))->y;
} else {
$offset = 0; // fallback default
}
// Ensure offset is within bounds
if ($offset >= 0 && $offset < $this->points) {
$target = 'current' === $period ? 'datasets' : 'datasetsPrev';
if (!isset($this->{$target}['v1'][$offset])) {
$this->{$target}['v1'][$offset] = 0;
}
$this->{$target}['v1'][$offset] += $v1;
if (!isset($this->{$target}['v2'][$offset])) {
$this->{$target}['v2'][$offset] = 0;
}
$this->{$target}['v2'][$offset] += $v2;
}
}
public function mapPrevLabels(array $labels, array $params): void
{
$this->prev_labels = array_map(function($label, $index) use ($params) {
$baseTime = $params['previous_start'];
$offset = sprintf('+%s %s', $index, $params['granularity']);
$timestamp = strtotime($offset, $baseTime);
return date($params['data_points_label'], $timestamp);
}, $labels, array_keys($labels));
}
/**
* Get the start-of-week timestamp for a given timestamp.
* Respects WordPress start_of_week setting.
*/
private function getWeekStartTimestamp(int $timestamp): int
{
$startOfWeek = (int) get_option('start_of_week', 1);
$dayOfWeek = (int) date('w', $timestamp); // 0=Sun, 6=Sat
$diff = ($dayOfWeek - $startOfWeek + 7) % 7;
return strtotime(date('Y-m-d', strtotime("-{$diff} days", $timestamp)));
}
private function shiftDatasets(): void
{
foreach (['v1', 'v2'] as $k) {
if (isset($this->datasets[$k][-1])) {
$newKeys = array_map(fn($key) => $key + 1, array_keys($this->datasets[$k]));
$this->datasets[$k] = array_combine($newKeys, array_values($this->datasets[$k]));
ksort($this->datasets[$k]);
if (empty(end($this->datasets[$k]))) {
array_pop($this->datasets[$k]);
}
}
if (isset($this->datasetsPrev[$k][-1])) {
$newKeys = array_map(fn($key) => $key + 1, array_keys($this->datasetsPrev[$k]));
$this->datasetsPrev[$k] = array_combine($newKeys, array_values($this->datasetsPrev[$k]));
ksort($this->datasetsPrev[$k]);
if (empty(end($this->datasetsPrev[$k]))) {
array_pop($this->datasetsPrev[$k]);
}
}
}
}
public function toArray(): array
{
$this->shiftDatasets();
$this->mapPrevLabels($this->labels, [
'data_points_label' => $this->labelFormat,
'granularity' => $this->gran,
'previous_start' => $this->prevStart,
]);
return [
'labels' => $this->labels,
'totals' => $this->totals,
'prev_labels' => $this->prev_labels,
'datasets' => $this->datasets,
'datasets_prev' => $this->datasetsPrev,
'today' => 'WEEK' === $this->gran && $this->getWeekStartTimestamp($this->end) === $this->getWeekStartTimestamp(time()) ? str_replace("'", '', $this->labels[count($this->labels) - 1]) : wp_date($this->labelFormat, time(), wp_timezone()),
'granularity' => $this->gran,
];
}
}