itemsPerPage; $offset = ($page - 1) * $limit; $ticks = iterator_to_array(stream_ticks($limit, $offset)); $view = new HomeView(); $tickList = $view->renderTicksSection($config->siteDescription, $ticks, $page, $limit); $vars = [ 'isLoggedIn' => $isLoggedIn, 'config' => $config, 'user' => $user, 'tickList' => $tickList, ]; echo render_template(TEMPLATES_DIR . "/home.php", $vars); } // POST handler // Saves the tick and reloads the homepage public function tick(){ if ($_SERVER['REQUEST_METHOD'] === 'POST' and isset($_POST['tick'])) { // ensure that the session is valid before proceeding if (!validateCsrfToken($_POST['csrf_token'])) { // TODO: maybe redirect to login? Maybe with tick preserved? die('Invalid CSRF token'); } // save the tick save_tick($_POST['tick']); } // get the config $config = Config::load(); // redirect to the index (will show the latest tick if one was sent) header('Location: ' . $config->basePath); exit; } private function stream_ticks(int $limit, int $offset = 0): Generator { $tick_files = glob(TICKS_DIR . '/*/*/*.txt'); usort($tick_files, fn($a, $b) => strcmp($b, $a)); // sort filenames in reverse chronological order $count = 0; foreach ($tick_files as $file) { // read all the ticks from the current file and reverse the order // so the most recent ones are first // // each file is a single day, so we never hold more than // one day's ticks in memory $lines = array_reverse( file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ); // split the path to the current file into the date components $pathParts = explode('/', str_replace('\\', '/', $file)); // assign the different components to the appropriate part of the date $year = $pathParts[count($pathParts) - 3]; $month = $pathParts[count($pathParts) - 2]; $day = pathinfo($pathParts[count($pathParts) - 1], PATHINFO_FILENAME); foreach ($lines as $line) { // just keep skipping ticks until we get to the starting point if ($offset > 0) { $offset--; continue; } // Ticks are pipe-delimited: timestamp|text // But just in case a tick contains a pipe, only split on the first one that occurs $tickParts = explode('|', $line, 2); $time = $tickParts[0]; $tick = $tickParts[1]; // Build the timestamp from the date and time // Ticks are always stored in UTC $timestampUTC = "$year-$month-$day $time"; yield [ 'timestamp' => $timestampUTC, 'tick' => $tick, ]; if (++$count >= $limit) { return; } } } } }