179 lines
5.0 KiB
PHP
Executable File
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);
|
|
?>
|