Aller au contenu

omnishield/stopforumspam

Omnishield StopForumSpam: are this IP address, this e-mail (sent hashed), this name reported for abuse - the public database's frequency, confidence and last sighting, a threshold of the site's; reports with an API key.

Étage
Fournisseur · Omnishield
Version
1.x
Suite de conformité
branchée, CI non lue
Vérifié en réel
Vérifié en réel
Licence
MIT
composer require omnishield/stopforumspam:1.x-dev

StopForumSpam's public database as an Omnishield list: are this IP address, this e-mail, this name reported for abuse, at a confidence threshold of the site's - and, with a key, a spammer reported back. The gateway calls POST https://api.stopforumspam.org/api to look up (no key; europe.stopforumspam.org and us.stopforumspam.org serve the same) and POST https://www.stopforumspam.com/add to report (an API key). Free for non-commercial use, for the people who submit a form - never as a firewall (the terms, below).

Installation

composer require omnishield/stopforumspam

PHP 8.2 or later, omnisense/omnishield and symfony/http-client (give the factory your application's client, a MockHttpClient in a test). No key to look up; one to report.

Credentials

None to look up. To report, an API key of a StopForumSpam account (api_key); without one, report() is a NotSupportedException and capabilities()->reports is false.

The sources

Written from StopForumSpam's API usage page as it read on 2026-10-07 - the parameters (ip, email, emailhash, username, json, expire, nobadall, notorexit, badtorexit), the JSON answer, the confidence, the regional servers, the submission form (/add) and the terms - and from its answers that day.

Options

Option Type Default Required
threshold number, 0 to 100 50 no the confidence from which a part that appears counts; outside 0..100: InvalidConfigException
send list of ip, email, name, or one comma-separated string [ip, email, name] no what of the visitor is sent - and Capabilities::$reads; another word: InvalidConfigException
hash_email bool true no the e-mail as its MD5 (emailhash), lower-cased and trimmed first; StopForumSpam then normalises nothing (Gmail's dots and +tags): false sends it in clear and catches more
expire int, days null no a sighting older than that does not count (expire, at least 1)
tor string neutral no a Tor exit node: neutral as listed, ignore never counts (even if reported), block always counts - decided here, not by notorexit/badtorexit; another: InvalidConfigException
wildcards bool true no false leaves out StopForumSpam's own lists of hostile domains, names and networks (nobadall)
api_key string null no only to report
base_uri string https://api.stopforumspam.org/api no https://europe.stopforumspam.org/api or https://us.stopforumspam.org/api to stay in a region
report_uri string https://www.stopforumspam.com/add no

new StopforumspamGatewayFactory(?HttpClientInterface $http = null): the application's HTTP client.

Capabilities

is this identity known (ReputationInterface::lookup()) yes: the parts of send
reports with api_key: the gateway's own report(Identity $identity, string $evidence = '')
a score confidence, 0 to 100; frequency
is this token valid, is this content spam no
third party, cookies StopForumSpam; no cookie

The lookup

One POST - so that nothing of the visitor shows in an address a proxy logs - with the parts to send and json. For each part StopForumSpam answers appears, frequency (255 for its own blacklists), lastseen (UTC), confidence (a percentage) and, for an address, torexit, asn, country.

Reputation
known a part appears and its confidence reaches the threshold - or a Tor exit node, with tor: block
frequency the highest of the parts
confidence the highest of the parts that appear
lastSeen the latest sighting
reasons the parts that count: ip, email, name, and tor beside ip for a Tor exit node
data StopForumSpam's answer, part by part (ip, email, name)

Why both conditions: StopForumSpam gives a confidence even when a part no longer appears (seen with expire=1: appears: 0, confidence: 95.29), and an address reported three times months ago appears with a confidence under 1 (1.2.3.4 on 2026-10-07: 0.26).

A part StopForumSpam cannot read ({"error": "invalid ip address"}) is left out, its error in data. {"success": 0, "error": ...} is a ProviderException; no answer, HTTP 5xx or 429 (the rate exceeded) an UnreachableException.

Reporting

$list->report(new Identity($ip, $email, $name), evidence: $whatTheyPosted);

POST https://www.stopforumspam.com/add with username, ip_addr, email, evidence, api_key - all three parts required, StopForumSpam takes nothing less. HTTP 200 is a report taken; any other status a refusal, its reason read from the page's paragraph: 401 and 403 an InvalidKeyException (the key), the others a ProviderException. Without api_key: NotSupportedException, and capabilities()->reports is false.

The terms

From the usage page, 2026-10-07: "Your use of this data and supporting software is non-commercial"; "The data here can be accessed by any commerical system provided that it is used for internal use only"; "API queries are limited to 100,000 per day"; "This API is NOT to be used as a general software firewall. Checking every incoming connection against the API will be treated as a denial of service attack". Data offered as is, without guarantee.

Example

A Tor exit node and a hashed e-mail, StopForumSpam's answer given by a MockHttpClient that prints what is sent, then the same address with tor: ignore (run in omnishield's workspace on 2026-10-26, offline):

<?php

require 'vendor/autoload.php';

use Omnishield\Model\Identity;
use Omnishield\Stopforumspam\StopforumspamGatewayFactory;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;

$http = new MockHttpClient(static function (string $method, string $url, array $options): MockResponse {
    echo $method, ' ', $url, ': ', $options['body'], "\n";

    return new MockResponse(json_encode(['success' => 1,
        'ip' => ['value' => '185.220.101.1', 'appears' => 1, 'frequency' => 91, 'lastseen' => '2026-10-24 21:14:03', 'confidence' => 95.29, 'torexit' => 1],
        'emailhash' => ['value' => md5('someone@example.org'), 'appears' => 0, 'frequency' => 0],
    ]));
});
$list = (new StopforumspamGatewayFactory($http))->create(['threshold' => 50]);
$reputation = $list->lookup(new Identity('185.220.101.1', 'Someone@example.org'));
printf("known: %s, reasons: %s, frequency %d, confidence %.2f, last seen %s\n", var_export($reputation->known, true), implode(', ', $reputation->reasons), $reputation->frequency, $reputation->confidence, $reputation->lastSeen->format(DATE_ATOM));
$ignoring = (new StopforumspamGatewayFactory($http))->create(['tor' => 'ignore', 'send' => 'ip']);
$known = $ignoring->lookup(new Identity('185.220.101.1'))->known;
echo 'tor: ignore -> known: ', var_export($known, true), "\n";
POST https://api.stopforumspam.org/api: ip=185.220.101.1&emailhash=a70eaed09677478b42b11fc7a04f4c87&json=
known: true, reasons: ip, tor, frequency 91, confidence 95.29, last seen 2026-10-24T21:14:03+00:00
POST https://api.stopforumspam.org/api: ip=185.220.101.1&json=
tor: ignore -> known: false

In Symfony:

omnishield:
    gateways:
        reported: { factory: stopforumspam, options: { threshold: 80, send: 'ip,email', api_key: '%env(default::STOPFORUMSPAM_API_KEY)%' } }

Errors

Exception When
UnreachableException no answer, HTTP 5xx, 429 (the daily limit)
ProviderException {"success": 0, "error": ...}; an answer that is not JSON (an HTTP 401 or 403 to a lookup included: the lookup sends no key); a report refused (HTTP other than 200), its reason from the page's paragraph
InvalidKeyException a report answered HTTP 401 or 403: the API key
NotSupportedException report() without api_key
InvalidConfigException an option out of its range; a report without all three parts

An identity with nothing to send (no part of send given) is unknown, and nothing is asked.

Verified, and not

The family's conformance suite (Omnishield\Testing\GatewayContractTests) green on 2026-10-25, offline: Tests/StopforumspamContractTest.php on the recorded answers; an error object in an answer no longer warns (array to string), a refused key on /add (401/403) is an InvalidKeyException
Lookups without a key done on 2026-10-07, against api.stopforumspam.org (bare --live and the recorded answers): the documentation's address, e-mail, hashed e-mail and name (none appears today), a Tor exit node (185.220.101.1: appears, frequency 91, confidence 95.29, torexit), its sighting past expire=1, an address reported long ago (1.2.3.4), a blacklisted e-mail (testing@xrumer.ru: 255, 99.95), a malformed address; europe.stopforumspam.org answers the same
notorexit seen not to work as documented on 2026-10-07: the Tor exit node kept appears: 1 - hence the tor option, decided here
Reporting (/add) not verified in real: no API key. Its request follows the documentation; its answers (200 empty, 403 with a paragraph) too
The 100,000-a-day limit and its 503 not reached

Responsibility

This package is an independent, unofficial client: it is not affiliated with, endorsed by or sponsored by StopForumSpam. It reaches their service on behalf of whoever runs it, and it does not redistribute their data beyond the short excerpts recorded as test fixtures. Its MIT licence covers this package's code only and grants no right to the service or to its data.

Whoever installs and runs this package is responsible for complying with StopForumSpam's terms (stopforumspam.com/legal), for obtaining whatever they require (an account, a key, a licence or subscription, an attribution or a citation, a rate limit to respect), and for any use made of what it returns. The authors publish it free of charge, make no commercial use of it, and accept no liability for how it is used (see the package's LICENSE).

Proposer une modification docs/index.md