first commit
This commit is contained in:
Executable
+178
@@ -0,0 +1,178 @@
|
||||
<?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);
|
||||
?>
|
||||
Reference in New Issue
Block a user