Skip to content

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 →