PHPackages                             cartograph/minecraft-slp - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. cartograph/minecraft-slp

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

cartograph/minecraft-slp
========================

Minecraft Server List Ping protocol implementation in PHP, with composable packet DTOs for custom flows.

v1.2.0(3w ago)03MITPHPPHP ^8.5CI passing

Since May 8Pushed 3w agoCompare

[ Source](https://github.com/cartographgg/minecraft-slp)[ Packagist](https://packagist.org/packages/cartograph/minecraft-slp)[ Docs](https://github.com/cartographgg/minecraft-slp)[ RSS](/packages/cartograph-minecraft-slp/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (3)Dependencies (5)Versions (4)Used By (0)

 [![Cartograph Logo](cartograph-logo.png)](cartograph-logo.png)

Minecraft SLP
=============

[](#minecraft-slp)

A pure-PHP library for issuing Minecraft Server List Ping (SLP) requests, with a managed connection lifecycle and composable packet DTOs for custom protocol flows.

[![Packagist Version](https://camo.githubusercontent.com/7d1ba4135f2985e11b825a02513f7cbcc4dff0e7fc8824343df58324c89aa7eb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f636172746f67726170682f6d696e6563726166742d736c702e737667)](https://packagist.org/packages/cartograph/minecraft-slp)[![Total Downloads](https://camo.githubusercontent.com/19a55adbb41fd4eb9abc66635faae15a6e819c0cf1caa9e447099531f32148a7/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f636172746f67726170682f6d696e6563726166742d736c702e737667)](https://packagist.org/packages/cartograph/minecraft-slp)[![PHP Version](https://camo.githubusercontent.com/4a7289878db8d46f39a93a8e5970d910186b240eb3747a2780898c81c827a482/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f636172746f67726170682f6d696e6563726166742d736c702e737667)](https://packagist.org/packages/cartograph/minecraft-slp)[![License](https://camo.githubusercontent.com/9ca1dd1c033e8b943a7a4e582b15c74db993a7aa0e5f04d993714a228828a1e1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f636172746f67726170682f6d696e6563726166742d736c702e737667)](LICENSE.md)

Features
--------

[](#features)

- **One-call ping**: `Pinger::ping()` runs the standard handshake, status, ping/pong, and JSON decode in a single managed exchange
- **Custom flows**: `Pinger::execute()` runs a caller-supplied closure inside the same lifecycle (resolve, connect, close, exception translation), so verification handshakes and other non-standard flows reuse the same plumbing
- **Raw access**: `Pinger::open()` returns the opened `ExecutionContext`for callers that need full control over the connection lifetime
- **Sealed result type**: every flow returns `Success` or `Failure`(a sealed `PingOutcome`); SLP-protocol errors become `Failure`, domain exceptions thrown inside `execute()` propagate to the caller
- **Vanilla and Forge decoding**: the status JSON is parsed into typed result objects, with automatic detection of the 1.13+ `forgeData` and 1.7-1.12 `modinfo` shapes
- **Latency measurement**: optional Ping/Pong round-trip via an injectable `Clock` seam, so tests can pin exact latency values
- **SRV-aware resolution**: looks up `_minecraft._tcp.` first, falls back to A records, and shortcuts when the input is already an IP literal
- **Composable packets**: each packet (Handshake, StatusRequest, StatusResponse, Ping, Pong) is a small DTO with `encode()` / `decode()`, usable directly without going through `Pinger`
- **PHPStan level max** with full generic annotations on `Connection`, `Success`, and `Pinger::execute()`

Requirements
------------

[](#requirements)

- PHP 8.5 or newer

No extensions are required; the library uses PHP's built-in `stream_socket_client` for TCP I/O.

Installation
------------

[](#installation)

Install via Composer:

```
composer require cartograph/minecraft-slp
```

Quick start
-----------

[](#quick-start)

Ask a Minecraft server for its status and inspect the result:

```
use Cartograph\SLP\Failure;
use Cartograph\SLP\Pinger;
use Cartograph\SLP\Success;

$pinger  = new Pinger();
$outcome = $pinger->ping('hypixel.net');

if ($outcome instanceof Success) {
    echo $outcome->result->players->online; // e.g. 47892
    echo $outcome->result->version->name;   // e.g. "Requires MC 1.8 / 1.21"
}

if ($outcome instanceof Failure) {
    echo $outcome->type->value;             // e.g. "timeout"
}
```

That's a complete, runnable example. The `Pinger` constructor wires up sensible production defaults (system DNS, real TCP sockets, monotonic clock); no fixtures or setup required.

Concepts
--------

[](#concepts)

The Server List Ping protocol is the small TCP exchange Minecraft clients use to populate the multiplayer server list. The flow is:

1. Client opens a TCP connection to the server's port (default 25565)
2. Client sends a **Handshake** packet declaring its protocol version and the address it believes it is connecting to
3. Client sends an empty **StatusRequest**
4. Server replies with a **StatusResponse** containing a JSON document describing the server (version, players, MOTD, mods, favicon)
5. Client may optionally send a **Ping** with an arbitrary 64-bit token; the server echoes it back as a **Pong** so the client can compute round-trip latency

This library reads, writes, and orchestrates that exchange. The high-level entry point is `Pinger`; the low-level building blocks (the packet DTOs, the `Connection` interface, the `Resolver` and `Transport`seams) are public so callers can compose custom flows without forking the library.

Every flow returns a `PingOutcome`: either `Success` carrying the decoded result, or `Failure` carrying an `ErrorType` and the original exception. SLP-protocol errors (DNS resolution, connection refused, timeout, malformed framing, malformed JSON) are caught and converted to `Failure`. Domain-specific exceptions thrown inside `Pinger::execute()`propagate to the caller unchanged.

Usage
-----

[](#usage)

### Standard ping

[](#standard-ping)

`Pinger::ping()` performs the full Handshake, StatusRequest, StatusResponse, optional Ping/Pong, and JSON decode in one call.

```
use Cartograph\SLP\Pinger;
use Cartograph\SLP\Success;

$outcome = new Pinger()->ping('play.example.com');

if ($outcome instanceof Success) {
    $result = $outcome->result;

    echo $result->version->name;               // "1.21.1"
    echo $result->players->online;             //  42
    echo $result->description->plainText;      // "Welcome to Example"
    echo $result->latencyMs ?? 'no measurement'; // 73
}
```

The optional `port`, `protocolVersion`, and `timeout` arguments override the defaults (25565, `-1`, and 3.0 seconds respectively).

### Custom flows

[](#custom-flows)

`Pinger::execute()` runs a caller-supplied closure inside the same managed lifecycle as `ping()`. The library handles DNS resolution, the connection lifecycle, and exception translation; the closure runs the packets it needs and returns whatever the caller wants.

```
use Cartograph\SLP\ExecutionContext;
use Cartograph\SLP\Packet\Handshake;
use Cartograph\SLP\Packet\NextState;
use Cartograph\SLP\Packet\StatusRequest;
use Cartograph\SLP\Packet\StatusResponse;
use Cartograph\SLP\Pinger;
use Cartograph\SLP\Success;

$pinger = new Pinger();

$outcome = $pinger->execute('play.example.com', function (ExecutionContext $ctx) use ($token): string {
    $ctx->connection->send(new Handshake(
        protocolVersion: $ctx->protocolVersion,
        serverAddress:   "verify-{$token}.{$ctx->endpoint->host}",
        serverPort:      $ctx->endpoint->port,
        nextState:       NextState::Status,
    ));
    $ctx->connection->send(new StatusRequest());

    return $ctx->connection->receive(StatusResponse::class)->json;
});

if ($outcome instanceof Success) {
    // $outcome->result is whatever the closure returned (a string here)
}
```

SLP-protocol errors (DNS failure, connect refused, timeout, malformed JSON, unexpected packet) become `Failure`. Domain exceptions thrown inside the closure propagate to the caller, and the connection is closed either way.

### Raw connection access

[](#raw-connection-access)

`Pinger::open()` returns the opened `ExecutionContext` and hands the connection lifetime to the caller. Useful for long-lived inspection or multiple non-standard exchanges over a single connection.

```
use Cartograph\SLP\Packet\Handshake;
use Cartograph\SLP\Packet\NextState;
use Cartograph\SLP\Packet\StatusRequest;
use Cartograph\SLP\Packet\StatusResponse;
use Cartograph\SLP\Pinger;

$ctx = new Pinger()->open('play.example.com');
try {
    $ctx->connection->send(new Handshake(-1, $ctx->endpoint->host, $ctx->endpoint->port, NextState::Status));
    $ctx->connection->send(new StatusRequest());
    $status = $ctx->connection->receive(StatusResponse::class);
} finally {
    $ctx->connection->close();
}
```

`open()` throws `DnsException` on resolution failure and `TransportException` on connect failure rather than wrapping them in a `Failure` outcome.

### Customising the resolver, transport, decoder, or clock

[](#customising-the-resolver-transport-decoder-or-clock)

The `Pinger` constructor takes four collaborators, each an interface defaulting to a production implementation:

```
use Cartograph\SLP\JsonStatusDecoder;
use Cartograph\SLP\Pinger;
use Cartograph\SLP\Resolver\DnsResolver;
use Cartograph\SLP\Transport\SocketTransport;

$pinger = new Pinger(
    resolver:  new DnsResolver(),       // hostname/IP resolution (uses system DNS)
    transport: new SocketTransport(),   // opens real TCP sockets
    decoder:   new JsonStatusDecoder(), // parses StatusResponse JSON
);
```

Tests substitute `InMemoryTransport`, fake `DnsLookup` implementations, and a fake `Clock`; production code can swap any of the four for custom behaviour (cached DNS, an alternative socket library, a logging decoder).

Class overview
--------------

[](#class-overview)

All classes live under the `Cartograph\SLP` namespace. The public surface splits into entry points, result types, and protocol primitives.

### Entry point

[](#entry-point)

ClassMethodReturns`Pinger``ping(string, ...)``Success|Failure``Pinger``execute(string, Closure, ...)``Success|Failure` (closure return)`Pinger``open(string, ...)``ExecutionContext` (caller closes)### Result types

[](#result-types)

ClassHolds`PingOutcome`sealed parent of `Success` and `Failure``Success``result: T` (templated)`Failure``type: ErrorType`, `previous: ?Throwable``Result\PingResult`version, players, description, favicon, latency, extras`Result\ForgePingResult``base: PingResult`, `forgeData: ForgeData``Result\Version``name`, `protocol``Result\Players``online`, `max`, `sample: list``Result\Sample``name`, `uuid``Result\Description``raw` (string or component tree), `plainText``Result\ForgeData``fmlNetworkVersion`, `mods`, `channels``ErrorType`enum: `Dns`, `Refused`, `Timeout`, `ProtocolError`, `Other`### Protocol primitives

[](#protocol-primitives)

ClassRole`Packet\Packet`interface implemented by every wire-level packet`Packet\Handshake`client → server, first packet of any exchange`Packet\StatusRequest`client → server, empty body`Packet\StatusResponse`server → client, JSON body`Packet\Ping`client → server, latency token`Packet\Pong`server → client, echoed token`Packet\NextState`enum: `Status`, `Login``Connection\Connection`interface for framed packet streams`Connection\StreamConnection`implementation backed by a PHP stream resource`Connection\BufferConnection`in-memory implementation for tests`Resolver\Resolver`interface: address → `Endpoint``Resolver\DnsResolver`default; SRV with A-record fallback`Resolver\Endpoint`resolved IP + port`Transport\Transport`interface: open a `Connection` to a host/port`Transport\SocketTransport`real TCP via `stream_socket_client``Transport\InMemoryTransport`canned `Connection`s for tests`StatusDecoder`interface: parses StatusResponse JSON into result objects`JsonStatusDecoder`default `StatusDecoder` implementation`Clock`interface: monotonic millisecond clock`MonotonicClock`default `Clock` backed by `hrtime()`Compatibility
-------------

[](#compatibility)

This library targets the **Java Edition** SLP protocol.

- **Minecraft Java 1.7 and newer**: the modern packet-based handshake used by every release since 1.7
- **Forge variants**: 1.13+ `forgeData` and 1.7-1.12 `modinfo` blocks surface as `ForgePingResult`
- **Resolution**: SRV records under `_minecraft._tcp.` plus A records, and a shortcut for IP literals

The legacy 1.6 SLP variant and Bedrock Edition's UDP-based ping protocol are not supported.

Contributing
------------

[](#contributing)

Bug reports, feature requests, and pull requests are welcome at [github.com/cartographgg/minecraft-slp](https://github.com/cartographgg/minecraft-slp). See [`CONTRIBUTING.md`](CONTRIBUTING.md) for development setup and the required checks (tests, static analysis, code style, and mutation testing). Each check has a Composer script: `composer test`, `composer static`, `composer style`, and `composer mutation`.

License
-------

[](#license)

Released under the [MIT License](LICENSE.md). © Cartograph contributors.

---

Maintained as part of [Cartograph](https://cartograph.gg), a Minecraft server directory and monitoring platform. The library is self-contained and has no Cartograph-specific behaviour; use it anywhere you need to issue SLP requests from PHP.

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance95

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~6 days

Total

3

Last Release

21d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/469515?v=4)[Ollie Read](/maintainers/ollieread)[@ollieread](https://github.com/ollieread)

---

Top Contributors

[![ollieread](https://avatars.githubusercontent.com/u/469515?v=4)](https://github.com/ollieread "ollieread (4 commits)")

---

Tags

minecraftminecraft-javaminecraft-serverphppingprotocolserver-list-pingslpprotocolminecraftslpserver-list-ping

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/cartograph-minecraft-slp/health.svg)

```
[![Health](https://phpackages.com/badges/cartograph-minecraft-slp/health.svg)](https://phpackages.com/packages/cartograph-minecraft-slp)
```

###  Alternatives

[xpaw/php-minecraft-query

PHP library to query Minecraft servers

744104.7k3](/packages/xpaw-php-minecraft-query)[thedudeguy/rcon

Simple Rcon class for php.

16162.6k1](/packages/thedudeguy-rcon)[spirit55555/php-minecraft

Useful PHP classes for Minecraft

6825.5k](/packages/spirit55555-php-minecraft)[d3strukt0r/votifier-client

Simple Tool to send vote request to a server which has the Votifier plugin.

1624.3k](/packages/d3strukt0r-votifier-client)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
