Defang / Refang — PHP source
Make URLs, IPs, and emails safe to paste by defanging indicators (https:// → hxxps[://], . → [.], @ → [@]) - and reverse refanged text back to its original form. Runs entirely in your browser, with a shareable link to your exact input and mode.
This is the PHP implementation — the same logic the interactive tool runs, in a shareable, citable form.
<?php
/**
* defang-refang — make URLs, IPs, and emails safe to paste (and reverse it).
*
* Language: PHP (8.1+, standard library only)
* Source: CosmoDev polyglot showcase port of the Defang/Refang tool, ported
* from src/lib/defang.ts (the canonical TypeScript implementation)
* and held in lock-step with cli/defang-refang/defang-refang.go.
* License: display source — part of CosmoDev's polyglot tool pages.
*
* Design goals:
* - Pure + deterministic; never throws.
* - Functionally equivalent to the TS / Go reference: same inputs -> same outputs.
* - Self-contained: stdlib only (no Composer packages).
*
* Algorithm: defang() replaces `https://` / `http://` schemes with `hxxps[://]`
* / `hxxp[://]`, then brackets EVERY dot as `[.]` and every at-sign as `[@]` —
* the standard threat-intel indicator-defanging convention. refang() is its
* exact inverse: scheme markers are restored first, then `[.]` / `[@]` are
* unbracketed, so `refang(defang($x)) === $x` for typical URLs, IPs, emails,
* and plain text.
*
* Ordering note: scheme replacements run BEFORE dot/at bracketing so the dots
* and colon inside the resulting `[://]` marker are not themselves re-bracketed
* (which would corrupt the scheme marker). Note that EVERY dot is bracketed, not
* just the domain separator — so defang is NOT idempotent by design: apply it
* once to fresh text. str_replace() replaces every occurrence, matching the
* replaceAll semantics of the TS source one for one.
*/
declare(strict_types=1);
/**
* Defang text so URLs, IPs, and emails are no longer clickable or auto-linked.
*
* Mirrors defang() in src/lib/defang.ts and Defang() in the Go twin, and must
* agree with both on every shared vector. Scheme replacements run first so the
* dots and colon inside the resulting `[://]` marker are not themselves
* re-bracketed. EVERY dot is bracketed, not just the domain separator. Empty
* input returns empty; text with no indicators passes through unchanged.
*
* Each str_replace() is applied in sequence (never an array of search/replace,
* which would change the order-dependent semantics) so the chained-replacement
* algorithm matches the TS source exactly.
*/
function defang(string $text): string
{
$out = str_replace('https://', 'hxxps[://]', $text);
$out = str_replace('http://', 'hxxp[://]', $out);
$out = str_replace('.', '[.]', $out);
$out = str_replace('@', '[@]', $out);
return $out;
}
/**
* Reverse defanging — restore `hxxps[://]` / `hxxp[://]` to real schemes and
* unbracket `[.]` / `[@]`. Mirrors refang() in src/lib/defang.ts and Refang()
* in the Go twin: the exact inverse of defang().
*
* Scheme markers are restored before `[.]` / `[@]` are unbracketed, so a marker
* like `hxxps[://]` reassembles into `https://` rather than being split by an
* earlier dot/at substitution. Empty input returns empty.
*/
function refang(string $text): string
{
$out = str_replace('hxxps[://]', 'https://', $text);
$out = str_replace('hxxp[://]', 'http://', $out);
$out = str_replace('[.]', '.', $out);
$out = str_replace('[@]', '@', $out);
return $out;
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →