Symfony
Installation
1
composer require botbye/botbye-php-sdk
Configuration
Wire the standalone BotbyePhishingClient as a Symfony service. Phishing is separate from the evaluate BotbyeClient, is identified by a public, browser-safe clientKey, and only needs a PSR-18 HTTP client and a PSR-17 request factory (no server key, no stream factory). Wired as a singleton service, on first use it makes a one-off, process-wide-guarded, best-effort server-integration init handshake that reports this server-side integration to BotBye; it is non-blocking.
Getting clientKey
clientKey is the public, browser-safe identifier of your phishing project. It travels in the asset URL path, so it is safe to expose — no secret token and no Base64 encoding are required.
Find it on the Get Started screen of your phishing project in the BotBye dashboard.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# config/services.yaml
services:
_defaults:
autowire: true
autoconfigure: true
# PSR-17 Factory
Nyholm\Psr7\Factory\Psr17Factory: ~
# PSR-18 HTTP Client
botbye.http_client:
class: Symfony\Component\HttpClient\Psr18Client
Botbye\Phishing\BotbyePhishingConfig:
arguments:
$endpoint: 'https://verify.botbye.com'
$clientKey: '<public-client-key>'
Botbye\Phishing\BotbyePhishingClient:
arguments:
$config: '@Botbye\Phishing\BotbyePhishingConfig'
$httpClient: '@botbye.http_client'
$requestFactory: '@Nyholm\Psr7\Factory\Psr17Factory'
Usage
Anti-phishing needs two routes on your own origin: an SVG route — the URL your client code passes to getCatcher({ url }) — and a PNG route that the SVG references. The paths are arbitrary, so name them like ordinary static assets and let the route decide the format. A path that spells out the vendor or the feature (/api/phishing/…) is what a copied page is searched for and stripped of, and a format query param on the pixel URL reads the same way.
On the SVG route, pass innerPngUrl — the absolute URL of your PNG route: the returned SVG embeds it as its tracking pixel. It is required: the SVG catcher takes it as a constructor argument, so an SVG asset without one does not compile, and a blank one is rejected on the spot rather than reaching the wire. Build that URL from your own host — image_id is owned by the SDK and is not read from the forwarded query. skipExecution defaults to true, the script-less SVG; pass false only for browsers predating crossorigin on svg <image> (Chrome 118, Firefox 114, Safari 17.2), where the script-driven variant is the one that still reports.
These examples forward no query: format, image_id and executable are set by the call itself, and only module_name / module_version pass through from the browser's pixel query — which a catcher mounted on your own routes never receives.
If you would rather not read the request yourself, bind it once: BotbyePhishingClient::withExtractor($config, $httpClient, $requestFactory, $extractor) — where $extractor maps your request to a BotbyePhishingRequestInfo ($origin, $referer, $query) — and call fetchCatcher(BotbyePhishingCatcher::svg(…), $request), passing the request where the $origin header value would go. The extractor is then the only thing that reads the request — headers and query alike.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?php
namespace App\Controller;
use Botbye\Phishing\BotbyePhishingClient;
use Botbye\Phishing\BotbyePhishingCatcher;
use Botbye\Phishing\BotbyePhishingResponse;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class PhishingController extends AbstractController
{
// Absolute URL of your PNG route — the SVG catcher references it as innerPngUrl.
private const PNG_CATCHER_URL = 'https://your-site.example/your-image-route.png';
public function __construct(
private BotbyePhishingClient $phishing
) {
}
#[Route('/your-image-route.svg', methods: ['GET'])]
public function svg(Request $request): Response
{
return $this->relay($this->phishing->fetchCatcher(
BotbyePhishingCatcher::svg(self::PNG_CATCHER_URL),
$request->headers->get('Origin'),
$request->headers->get('Referer'),
));
}
#[Route('/your-image-route.png', methods: ['GET'])]
public function png(Request $request): Response
{
return $this->relay($this->phishing->fetchCatcher(
BotbyePhishingCatcher::png(),
$request->headers->get('Origin'),
$request->headers->get('Referer'),
));
}
private function relay(BotbyePhishingResponse $res): Response
{
if ($res->error !== null) {
return new Response($res->error->message, 502);
}
$contentType = $res->headers['Content-Type'] ?? 'image/png';
return new Response($res->body, $res->status, ['Content-Type' => $contentType]);
}
}
Settings
Configuration parameters for phishing integration:
| Setting | Description | Required | Default Value |
|---|---|---|---|
| endpoint | Host of the phishing API | no | https://verify.botbye.com |
| clientKey | Public client-key of your phishing project | yes | - |