> /var/log/square_refresh.log 2>&1 * Optionally add a daily threshold sweep as a safety net against any lapse: * 15 3 * * * /usr/bin/php /path/to/square/refresh_tokens.php --days=7 >> /var/log/square_refresh.log 2>&1 * * Exit codes: 0 = all good (or dry-run), 1 = one or more refreshes failed. */ if (PHP_SAPI !== 'cli') { http_response_code(403); header('Content-Type: text/plain'); echo "refresh_tokens.php is a CLI script and must not be run over HTTP.\n"; exit(1); } // Optional app logging, if these helpers are on the include path. Wrapped so the // script also runs standalone (e.g. from a bare cron environment). if (file_exists(__DIR__ . '/../include/logging-functions.php')) { require_once __DIR__ . '/../include/logging-functions.php'; if (function_exists('startLog')) startLog('square-refresh-cron'); } require_once __DIR__ . '/lib/SquareClient.php'; require_once __DIR__ . '/lib/MerchantStore.php'; $config = require __DIR__ . '/config.php'; // ── Parse flags ────────────────────────────────────────────────────────────── $opts = getopt('', ['days::', 'force', 'dry-run', 'school::', 'help']); if (isset($opts['help'])) { fwrite(STDOUT, "Usage: php refresh_tokens.php [--days=N] [--force] [--dry-run] [--school=\"Name\"]\n"); exit(0); } $thresholdDays = isset($opts['days']) ? max(0, (int)$opts['days']) : 5; $force = isset($opts['force']); $dryRun = isset($opts['dry-run']); $onlySchool = isset($opts['school']) ? (string)$opts['school'] : null; $ts = date('c'); fwrite(STDOUT, "[$ts] Square token refresh starting" . " (days=$thresholdDays" . ($force ? ", force" : "") . ($dryRun ? ", dry-run" : "") . ($onlySchool ? ", school=\"$onlySchool\"" : "") . ")\n"); try { $client = new SquareClient($config); $store = new MerchantStore($config); } catch (Throwable $e) { fwrite(STDERR, "FATAL: " . $e->getMessage() . "\n"); exit(1); } // record_num => name. Keyed by the unique record_num so same-named schools are // each refreshed (a name-keyed sweep would refresh only the first of them). $schools = $store->connectedSchoolNums(); if ($onlySchool !== null) { $schools = array_filter($schools, fn($name) => $name === $onlySchool); } if (empty($schools)) { fwrite(STDOUT, "No connected schools to process.\n"); exit(0); } $counts = ['refreshed' => 0, 'skipped' => 0, 'would_refresh' => 0, 'failed' => 0, 'no_refresh_token' => 0, 'not_connected' => 0]; foreach ($schools as $schoolNum => $school) { $result = $store->ensureFreshToken($school, $client, [ 'threshold_days' => $thresholdDays, 'force' => $force, 'dry_run' => $dryRun, 'school_num' => $schoolNum, ]); $action = $result['action'] ?? 'failed'; $counts[$action] = ($counts[$action] ?? 0) + 1; $line = sprintf(" %-16s %s (#%d)", $action, $school, $schoolNum); if (!empty($result['expires_at'])) $line .= " (expires {$result['expires_at']})"; if (!empty($result['detail'])) $line .= " — {$result['detail']}"; fwrite(STDOUT, $line . "\n"); } $ts = date('c'); fwrite(STDOUT, "[$ts] Done. " . "refreshed={$counts['refreshed']} skipped={$counts['skipped']} " . "would_refresh={$counts['would_refresh']} failed={$counts['failed']} " . "no_refresh_token={$counts['no_refresh_token']} not_connected={$counts['not_connected']}\n"); // Non-zero exit if anything failed, so cron / monitoring can alert. exit($counts['failed'] > 0 ? 1 : 0);