Files
SkinbaseNova/scripts/check_inertia.php

160 lines
4.1 KiB
PHP

<?php
declare(strict_types=1);
function usage(): void
{
$script = basename(__FILE__);
fwrite(STDERR, <<<TXT
Usage:
php scripts/{$script} --base=https://skinbase.top /@gregor /categories /wallpapers
php scripts/{$script} https://skinbase.top/@gregor https://skinbase.top/categories
Classifications:
INERTIA_SSR id="app" + data-page + non-empty app HTML
INERTIA_NO_SSR id="app" + data-page + empty app HTML
NOT_INERTIA missing id="app" or missing data-page
TXT);
}
function isAbsoluteUrl(string $value): bool
{
return (bool) preg_match('~^https?://~i', $value);
}
function joinUrl(string $baseUrl, string $path): string
{
return rtrim($baseUrl, '/') . '/' . ltrim($path, '/');
}
function resolveTargets(array $arguments): array
{
$baseUrl = null;
$targets = [];
foreach ($arguments as $argument) {
if (str_starts_with($argument, '--base=')) {
$baseUrl = substr($argument, 7);
continue;
}
if ($argument === '--help' || $argument === '-h') {
usage();
exit(0);
}
$targets[] = $argument;
}
if ($targets === []) {
usage();
exit(1);
}
return array_map(static function (string $target) use ($baseUrl): string {
if (isAbsoluteUrl($target)) {
return $target;
}
if ($baseUrl === null || $baseUrl === '') {
fwrite(STDERR, "Relative path '{$target}' requires --base=...\n");
exit(1);
}
return joinUrl($baseUrl, $target);
}, $targets);
}
function fetchUrl(string $url): array
{
if (function_exists('curl_init')) {
$handle = curl_init($url);
curl_setopt_array($handle, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_TIMEOUT => 20,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_USERAGENT => 'Skinbase Inertia Checker/1.0',
CURLOPT_HEADER => true,
]);
$raw = curl_exec($handle);
if ($raw === false) {
$error = curl_error($handle);
curl_close($handle);
throw new RuntimeException($error !== '' ? $error : 'Unknown cURL error');
}
$status = (int) curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
$headerSize = (int) curl_getinfo($handle, CURLINFO_HEADER_SIZE);
curl_close($handle);
return [
'status' => $status,
'body' => substr($raw, $headerSize),
];
}
$context = stream_context_create([
'http' => [
'method' => 'GET',
'follow_location' => 1,
'max_redirects' => 5,
'timeout' => 20,
'header' => "User-Agent: Skinbase Inertia Checker/1.0\r\n",
'ignore_errors' => true,
],
]);
$body = @file_get_contents($url, false, $context);
if ($body === false) {
$error = error_get_last();
throw new RuntimeException($error['message'] ?? 'HTTP request failed');
}
$headers = $http_response_header ?? [];
$status = 0;
foreach ($headers as $header) {
if (preg_match('~^HTTP/\S+\s+(\d{3})~', $header, $matches)) {
$status = (int) $matches[1];
}
}
return [
'status' => $status,
'body' => $body,
];
}
function classifyHtml(string $html): string
{
$hasApp = str_contains($html, 'id="app"');
$hasDataPage = str_contains($html, 'data-page="');
if (! $hasApp || ! $hasDataPage) {
return 'NOT_INERTIA';
}
if (! preg_match('~<div id="app"[^>]*>(.*?)</div>~si', $html, $matches)) {
return 'INERTIA_UNKNOWN';
}
return trim($matches[1]) === '' ? 'INERTIA_NO_SSR' : 'INERTIA_SSR';
}
$targets = resolveTargets(array_slice($argv, 1));
foreach ($targets as $url) {
try {
$response = fetchUrl($url);
$classification = classifyHtml($response['body']);
printf("%d\t%s\t%s\n", $response['status'], $classification, $url);
} catch (Throwable $exception) {
printf("ERROR\t%s\t%s\n", $exception->getMessage(), $url);
}
}