spamtroll / php-sdk
PHP SDK for the Spamtroll spam detection API.
Requires
- php: >=8.0
- ext-curl: *
- ext-json: *
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.58
- peckphp/peck: ^0.1
- pestphp/pest: ^2.34
- pestphp/pest-plugin-arch: ^2.7
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^1.11
- phpstan/phpstan-strict-rules: ^1.6
- phpunit/phpunit: ^10.5
README
Zero-dependency PHP client for the Spamtroll spam detection API.
Drop it into a WordPress plugin, an IPS Community Suite application, a
framework app, or a plain PHP script — the core SDK has no runtime
dependencies beyond ext-curl and ext-json. Host platforms can swap in
their own HTTP transport (so WP calls go through wp_remote_* and respect
admin filters, IPS calls go through \IPS\Http\Url) by implementing one
interface.
Requirements
- PHP 8.0 or newer
ext-curl,ext-json
Installation
composer require spamtroll/php-sdk
Without Composer (e.g. a bundled plugin), drop src/ somewhere in your
project and include the fallback autoloader:
require_once __DIR__ . '/path/to/spamtroll-php-sdk/autoload.php';
Quick start
use Spamtroll\Sdk\Client; use Spamtroll\Sdk\Request\CheckSpamRequest; $client = new Client('your-api-key'); $response = $client->checkSpam( new CheckSpamRequest( content: $comment, source: CheckSpamRequest::SOURCE_COMMENT, ipAddress: $_SERVER['REMOTE_ADDR'] ?? null, username: $author, email: $authorEmail, ) ); if ($response->isSpam()) { // block } elseif ($response->getSpamScore() >= 0.4) { // moderate }
Configuration
use Spamtroll\Sdk\Client; use Spamtroll\Sdk\ClientConfig; $config = new ClientConfig( baseUrl: 'https://api.spamtroll.io/api/v1', timeout: 5, maxRetries: 3, retryBaseDelayMs: 500, userAgent: 'my-plugin/1.0 spamtroll-php-sdk/' . \Spamtroll\Sdk\Version::VERSION, scoreDenominator: 30.0, ); $client = new Client('your-api-key', $config);
What the fields mean
| Field | Default | Notes |
|---|---|---|
baseUrl |
https://api.spamtroll.io/api/v1 |
Trailing slash stripped. |
timeout |
5 |
Per-request seconds (connect + read). |
maxRetries |
3 |
Total attempts, not retries. First attempt counts. |
retryBaseDelayMs |
500 |
Backoff: attempt * base ms before attempt 2+. Set 0 to disable (tests). |
userAgent |
spamtroll-php-sdk/{version} |
Host integrations should prepend their own identifier. |
scoreDenominator |
30.0 |
Maps raw API score (0…∞) to normalized 0.0–1.0 via min(1, raw / denominator). |
Score normalization
The backend scores on an open-ended additive scale. A raw score of 15 is
"definitely spam", 30 is "twice the spam threshold". The SDK normalizes
via min(1.0, raw / scoreDenominator):
| Raw | Normalized (denominator 30) |
|---|---|
| 0 | 0.00 |
| 7.5 | 0.25 |
| 15 | 0.50 |
| 22.5 | 0.75 |
| 30+ | 1.00 |
Use getSpamScore() for the 0–1 value and getRawSpamScore() for the raw
number if you need to display the native scale.
Custom HTTP adapter
use Spamtroll\Sdk\Client; use Spamtroll\Sdk\Http\HttpClientInterface; use Spamtroll\Sdk\Http\HttpResponse; use Spamtroll\Sdk\Exception\ConnectionException; use Spamtroll\Sdk\Exception\TimeoutException; final class MyHttpClient implements HttpClientInterface { public function send(string $method, string $url, array $headers, ?string $body, int $timeout): HttpResponse { // Translate connection/timeout failures into // ConnectionException / TimeoutException. // 4xx/5xx are NOT errors here — return them via HttpResponse. } } $client = new Client('your-api-key', null, new MyHttpClient());
WordPress and IPS integrations ship adapters that delegate to
wp_remote_* and \IPS\Http\Url respectively, so platform-level filters
(proxy, SSL overrides, request inspection) still apply.
Error handling
The SDK throws when something prevents a meaningful response:
| Exception | When |
|---|---|
NotConfiguredException |
Empty API key. |
AuthenticationException |
HTTP 401 — invalid API key. |
ConnectionException |
Connection failure after all retries. |
TimeoutException |
Timeout after all retries (extends ConnectionException). |
ServerException |
HTTP 5xx after all retries. |
SpamtrollException |
Base for all SDK exceptions. Catch this if you want a single fail-open path. |
Non-fatal error responses — HTTP 429, other 4xx — are returned as a
Response with success === false and an error message, so the caller
can decide whether to back off or log.
Documentation
- Installation — requirements, Composer + manual install.
- Usage — every Client method, request fields, examples.
- Configuration —
ClientConfigfield-by-field, environment-specific recommendations. - HTTP adapters — interface contract, reference adapters for WordPress / IPS / Guzzle.
- Error handling — exception hierarchy, fail-open patterns.
- Response schema —
CheckSpamResponsegetters, score normalisation, envelope handling. - Contributing — local setup, quality gate, release checklist.
Development
composer install composer qa # cs-fixer + phpstan + peck + pest composer test # tests only composer test:coverage # tests with coverage composer lint:fix # auto-format
See docs/CONTRIBUTING.md for the full quality
gate, including the aspell dependency required by composer peck.
License
MIT — see LICENSE.