Skip to content

Data Unit Converter — PHP source

Convert between digital data units - B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. Switch between decimal (1000) and binary (1024) bases, runs entirely in your browser.

This is the PHP implementation — the same logic the interactive tool runs, in a shareable, citable form.

<?php
/**
 * data-unit-converter — polyglot showcase port (PHP).
 *
 * Pure digital-data unit conversion for the Data Unit Converter tool on
 * CosmoDev (dev.cosmolabs.org). Ported from the canonical TypeScript source at
 * src/lib/dataUnits.ts so the tool page can display the same logic across six
 * languages.
 *
 * Supports B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. Decimal base = 1000 (KB, MB, GB,
 * TB); binary base = 1024 (KiB, MiB, GiB, TiB). Pure + deterministic.
 * convert_data returns NAN for non-finite input, unknown units, or an invalid
 * base — it never throws.
 *
 * Self-contained: standard library only, no external dependencies (no Composer
 * packages).
 *
 * License/usage: display source — part of CosmoDev's polyglot tool pages.
 */

namespace CosmoDev\DataUnitConverter;

/**
 * Units available under each base, ordered smallest (B) to largest. The UI
 * uses this to populate the per-base unit pickers. Keys are the numeric base.
 */
const UNITS = [
    1000 => ['B', 'KB', 'MB', 'GB', 'TB'],
    1024 => ['B', 'KiB', 'MiB', 'GiB', 'TiB'],
];

/**
 * Power-of-base rank for each unit: B is rank 0, each prefix step adds 1.
 * KB and KiB are both rank 1 — the unit picks the rank, the base decides
 * whether a rank means ×1000 or ×1024.
 */
const EXPONENT = [
    'B'   => 0,

    'KB'  => 1, 'MB'  => 2, 'GB'  => 3, 'TB'  => 4,
    'KiB' => 1, 'MiB' => 2, 'GiB' => 3, 'TiB' => 4,
];

/**
 * Convert a value between two digital-data units under the given base.
 *
 * Strategy: reduce to bytes via value × base^fromExp, then divide by
 * base^toExp. Returns NAN for non-finite input, unknown units, or an invalid
 * base — never throws (mirrors the TypeScript contract).
 *
 * @param float|int|string $value     Magnitude to convert. Loose typing lets us
 *                                    accept numeric strings the way the JS
 *                                    caller would; non-numeric becomes NAN.
 * @param string           $fromUnit  Source unit symbol.
 * @param string           $toUnit    Target unit symbol.
 * @param int              $base      Conversion base: 1000 or 1024.
 *
 * @return float Converted value, or NAN on invalid input.
 */
function convert_data($value, string $fromUnit, string $toUnit, int $base): float
{
    // Coerce incoming scalars to float; reject anything that isn't numeric.
    if (!is_numeric($value)) {
        return NAN;
    }
    $value = (float) $value;

    // Reject Inf/NaN early so they don't propagate through the multiplication.
    if (!is_finite($value)) {
        return NAN;
    }
    // Only the two canonical bases are valid; anything else is a caller bug.
    if ($base !== 1000 && $base !== 1024) {
        return NAN;
    }

    // Unknown unit symbols index into null; treat as invalid. The ?? NAN
    // default preserves the TS dictionary-miss behavior.
    $fromExp = EXPONENT[$fromUnit] ?? null;
    $toExp = EXPONENT[$toUnit] ?? null;
    if ($fromExp === null || $toExp === null) {
        return NAN;
    }

    return ($value * $base ** $fromExp) / $base ** $toExp;
}

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 →