Skip to content
← Back to Functions
Code

Currency Amount Parser

Parses currency strings into integer minor units for safe storage and calculations.

Function signature

ogParseCurrencyAmount(amount, scale = 2)

Categories

  • Forms and Validation

Parameters

amountRaw amount such as 12.34, USD 12.34, or -12.34.scaleNumber of decimal places used by the currency.

Return value

Short public-safe status message.

  • amount_minor
  • amount_decimal
  • scale

Compatibility

Existing function name and call order preserved; metadata signature corrected to source.

Minimum PHP version: 7.4

Security notes

Validate request method, identity, permissions, and caller-owned allowlists before use; keep secrets and internal paths out of public output.

Code

<?php

/*
 * Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
 * Free for personal and internal use. Paid project use requires visible credit
 * to Jeffery L. Paris. Corporate use requires a paid license fee unless a
 * separate written license states otherwise.
 */

/**
 * Parses a currency string into integer minor units without using floating point math.
 *
 * This is intended for carts, invoices, import tools, and any place where a display
 * amount must become a safe database value.
 *
 * @param string $amount Raw amount such as 12.34, $12.34, or -12.34.
 * @param int $scale Number of decimal places used by the currency.
 * @return array Parsed amount result with minor units and normalized display value.
 */
function ogParseCurrencyAmount($amount, $scale = 2) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

	$amount = trim((string)$amount);
	$scale = (int)$scale;

	if ($scale < 0) {
		$scale = 2;
	}

	if ($scale > 6) {
		$result['message'] = 'Currency scale is too large.';
		return $result;
	}

	if (empty($amount)) {
		$result['message'] = 'Missing currency amount.';
		return $result;
	}

	$clean_amount = preg_replace('/[^0-9.\-]/', '', $amount);
	if (!preg_match('/^-?[0-9]+(\.[0-9]+)?$/', $clean_amount)) {
		$result['message'] = 'Invalid currency amount.';
		return $result;
	}

	$is_negative = false;
	if (substr($clean_amount, 0, 1) == '-') {
		$is_negative = true;
		$clean_amount = substr($clean_amount, 1);
	}

	$parts = explode('.', $clean_amount, 2);
	$whole_part = $parts[0];
	$decimal_part = '';
	if (!empty($parts[1])) {
		$decimal_part = $parts[1];
	}

	if (strlen($decimal_part) > $scale) {
		$result['message'] = 'Currency amount has too many decimal places.';
		return $result;
	}

	$decimal_part = str_pad($decimal_part, $scale, '0');
	$multiplier = 1;
	$counter = 0;
	while ($counter < $scale) {
		$multiplier = $multiplier * 10;
		$counter++;
	}

	$minor_units = ((int)$whole_part * $multiplier) + (int)$decimal_part;
	if ($is_negative) {
		$minor_units = $minor_units * -1;
	}

	$display = $whole_part;
	if ($scale > 0) {
		$display .= '.' . $decimal_part;
	}
	if ($is_negative) {
		$display = '-' . $display;
	}

	$result['success'] = true;
	$result['message'] = 'Currency amount parsed.';
	$result['data'] = array(
		'minor_units' => $minor_units,
		'scale' => $scale,
		'display' => $display,
		'is_negative' => $is_negative
	);

	return $result;
}