koraktor/steam-condenser
Steam Condenser is a PHP library for working with Steam: query game servers via A2S, access Steam Community profiles and data, use the Steam Web API, and convert Steam IDs. It offers a simple object-oriented API for building Steam apps and bots.
Install and pin. The package is on Packagist as koraktor/steam-condenser:
composer require koraktor/steam-condenser
It was last released in March 2015 and the repository is archived, so treat the version you install as frozen. Commit your composer.lock, and expect to patch or fork it rather than receive fixes. It targets PHP 5.3-era code — smoke-test every API you rely on under your current PHP version before building anything on it.
Where to look first
src/SteamCondenser/Servers/ — SourceServer, GoldSrcServer, MasterServer. This is the A2S query layer (info, players, rules) plus RCON.src/SteamCondenser/Community/ — SteamId, WebApi, App, GameAchievement. Profile, friends, games, achievements, and the official Web API wrappers.src/SteamCondenser/Exceptions/ — one base SteamCondenserException with subclasses (SocketException, auth/RCON errors). Catch the base type at your boundary.composer.json — confirms PSR autoloading and the PHP constraint. If namespaces differ from what you expect, check this before copying examples from old blog posts (pre-1.3 releases used global classes like SourceServer, not SteamCondenser\Servers\SourceServer).First use case: a game-server status card. The fastest path to value is querying a Source/GoldSrc server you control:
use SteamCondenser\Servers\SourceServer;
$server = new SourceServer('203.0.113.10:27015');
$server->initialize(); // opens the UDP socket, sends A2S_INFO
$info = $server->getServerInfo(); // serverName, mapName, numberOfPlayers, maxPlayers…
$players = $server->getPlayers(); // Player objects (name, score, duration)
And resolving an identity from the Steam Community:
use SteamCondenser\Community\SteamId;
$id = SteamId::create('76561197960287930'); // or 'STEAM_0:1:1', or a vanity slug
echo $id->getNickname();
$games = $id->getGames(); // requires a public profile
That's the whole onboarding: one socket query, one profile lookup. Everything else is composition.
Wrap the library behind one service. Its namespace/API is unlikely to change (it's archived), but its dependencies — PHP runtime, socket behavior, Steam's HTML — will. A thin wrapper keeps the legacy surface contained and makes testing possible:
namespace App\Services;
use SteamCondenser\Servers\SourceServer;
use SteamCondenser\Exceptions\SteamCondenserException;
class GameServerQuery
{
public function snapshot(string $address): ?array
{
try {
$server = new SourceServer($address);
$server->initialize();
$info = $server->getServerInfo();
return [
'name' => $this->toUtf8($info['serverName']),
'map' => $info['mapName'],
'players' => $info['numberOfPlayers'],
'max' => $info['maxPlayers'],
'queried_at' => now(),
];
} catch (SteamCondenserException $e) {
report($e);
return null; // server offline / firewalled
}
}
}
Never query in the request path. UDP round-trips to a game server, or a scrape of steamcommunity.com, can take seconds and will stall a PHP-FPM worker. Push both to queued jobs (PollGameServer, RefreshSteamProfile), persist snapshots to a table, and let the UI read the last-known state. This also gives you history for trend charts — the library only gives you point-in-time reads.
Cache aggressively on the Community side. getNickname(), getGames(), getFriends(), getAchievements() hit live endpoints. Cache by SteamID64 with a TTL (profiles: hours; ban/owned-games data: a day) via Laravel's Cache facade. For anything covered by the Web API, prefer it over HTML scraping:
use SteamCondenser\Community\WebApi;
WebApi::setApiKey(config('services.steam.key')); // set once per process, e.g. a service provider
WebApi methods like getPlayerSummaries, getOwnedGames, getNewsForApp are structured JSON and far more stable than the Community scrapers.
Use RCON for admin tooling, not the web tier. rconAuth() / rconExec() are useful for a small internal ops CLI or an artisan command (php artisan steam:kick <address> <user>). Keep them out of HTTP handlers and behind authorization.
Design for a swap. With zero dependents and no maintenance, budget for replacing the query layer with raw stream_socket_client A2S packets or a maintained fork. Keep DTOs (your own arrays/classes) at the boundary so the library's Player/SteamId objects never leak into your controllers or Blade views.
Laravel wiring: register the Web API key in a service provider (package predates auto-discovery, so manual registration is expected anyway), put addresses in config/services.php, and model each polled server as an Eloquent record with a last_snapshot JSON column.
SteamCondenserException (not just \Exception), set short timeouts on the job, and mark repeated failures inactive rather than retrying forever.getGames(), getFriends(), and achievements throw or return empty for private profiles — handle that as a normal state, not an error. The HTML-backed methods are also brittle against Steam markup changes and may simply stop working; the Web API equivalents are safer.getRules() is unreliable. Many servers disable A2S_RULES; treat an empty/failed rules response as normal and don't block on it.MasterServer::getServers() is not a dependable way to build a server browser. Query known addresses instead.WebApi::setApiKey() is static/global state. Set it once (service provider or bootstrap) and don't mutate it per request — it's easy to leave unset and get confusing auth failures deep in a call stack.STEAM_X:Y:Z formats, and group vs individual IDs all route through SteamId::create(). Normalize to SteamID64 at your input boundary so downstream code only deals with one format.SourceServer/GoldSrcServer to override query/parse behavior, or reuse the SteamSocket/packet classes if you want to speak A2S yourself. For long-running queue workers, create a fresh server object per query rather than reusing sockets across jobs.How can I help you explore Laravel packages today?