Files
Site-Web/data/api/minecraft-status.php
T
2026-05-16 11:10:19 +02:00

179 lines
5.0 KiB
PHP
Executable File

<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Cache-Control: no-cache, must-revalidate');
header('Expires: 0');
ini_set('display_errors', 0);
error_reporting(0);
/**
* Minecraft Server List Ping (protocole 1.7+)
* Ref: https://wiki.vg/Server_List_Ping
*/
function pingMinecraftServer(string $host, int $port = 25565, int $timeout = 4): array {
$result = [
'online' => false,
'players' => 0,
'max_players' => 0,
'version' => '',
'motd' => '',
'latency' => null,
];
$start = microtime(true);
$socket = @fsockopen($host, $port, $errno, $errstr, $timeout);
if (!$socket) {
return $result;
}
stream_set_timeout($socket, $timeout);
// ---- Handshake packet (0x00) ----
$hostBytes = $host;
$hostLen = strlen($hostBytes);
$handshakeData = "\x00"; // Packet ID 0x00
$handshakeData .= varInt(47); // Protocol version (47 = 1.8, -1 non-spécifique)
$handshakeData .= varInt($hostLen) . $hostBytes; // Server address
$handshakeData .= pack('n', $port); // Port (unsigned short big-endian)
$handshakeData .= varInt(1); // Next state: 1 = status
fwrite($socket, varInt(strlen($handshakeData)) . $handshakeData);
// ---- Status Request (0x00, longueur 1) ----
fwrite($socket, "\x01\x00");
// ---- Lire la réponse ----
$packetLen = readVarInt($socket);
if ($packetLen <= 0) {
fclose($socket);
return $result;
}
// Lire l'ID du paquet (doit être 0x00)
readVarInt($socket);
// Lire la longueur de la chaîne JSON
$strLen = readVarInt($socket);
if ($strLen <= 0) {
fclose($socket);
return $result;
}
// Lire le JSON
$json = '';
$remaining = $strLen;
while ($remaining > 0 && !feof($socket)) {
$chunk = fread($socket, min($remaining, 4096));
if ($chunk === false || $chunk === '') break;
$json .= $chunk;
$remaining -= strlen($chunk);
}
fclose($socket);
$latency = (int) round((microtime(true) - $start) * 1000);
$data = @json_decode($json, true);
if (!$data) {
return $result;
}
// ---- Extraire le MOTD ----
$motd = '';
if (isset($data['description'])) {
if (is_string($data['description'])) {
$motd = $data['description'];
} elseif (is_array($data['description'])) {
$motd = $data['description']['text'] ?? '';
// Concatener les extras
if (!empty($data['description']['extra']) && is_array($data['description']['extra'])) {
foreach ($data['description']['extra'] as $extra) {
$motd .= $extra['text'] ?? '';
}
}
}
}
// Supprimer les codes couleur §X
$motd = preg_replace('/§[0-9a-fk-orA-FK-OR]/u', '', $motd);
$motd = trim(preg_replace('/\s+/', ' ', $motd));
$result['online'] = true;
$result['players'] = (int) ($data['players']['online'] ?? 0);
$result['max_players'] = (int) ($data['players']['max'] ?? 0);
$result['version'] = $data['version']['name'] ?? '';
$result['motd'] = $motd;
$result['latency'] = $latency;
return $result;
}
/**
* Encode un entier en VarInt Minecraft
*/
function varInt(int $value): string {
$out = '';
do {
$byte = $value & 0x7F;
$value = ($value >> 7) & PHP_INT_MAX; // shift sans signe
if ($value !== 0) $byte |= 0x80;
$out .= chr($byte);
} while ($value !== 0);
return $out;
}
/**
* Lit un VarInt depuis un socket
*/
function readVarInt($socket): int {
$value = 0;
$shift = 0;
do {
$raw = fgetc($socket);
if ($raw === false) return 0;
$byte = ord($raw);
$value |= ($byte & 0x7F) << $shift;
$shift += 7;
if ($shift > 35) break; // sécurité anti-boucle infinie
} while ($byte & 0x80);
return $value;
}
// ======================================================
// Configuration des serveurs à pinger
// ======================================================
$servers = [
[
'name' => 'Serveur MC #1',
'host' => 'nix.roulaise.net',
'port' => 9191,
],
[
'name' => 'Serveur MC #2',
'host' => 'nix.roulaise.net',
'port' => 9292,
],
];
// ======================================================
// Ping tous les serveurs et retourner le résultat JSON
// ======================================================
$results = [];
foreach ($servers as $srv) {
$ping = pingMinecraftServer($srv['host'], $srv['port']);
$results[] = array_merge([
'name' => $srv['name'],
'host' => $srv['host'],
'port' => $srv['port'],
], $ping);
}
echo json_encode([
'success' => true,
'servers' => $results,
'timestamp' => time(),
], JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
?>