Skip to content
← Back to Functions
Code

Private Data Redactor

Redacts passwords, tokens, API keys, emails, phone numbers, and card-like values from logs.

Function signature

ogRedactSensitiveData(payload, extra_keys = array(), depth = 0)

Categories

  • Security

Parameters

payloadString or array payload to redact.extra_keysAdditional sensitive key fragments.depthCurrent recursion depth.

Return value

Short public-safe status message.

  • payload

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.
 */

/**
 * Redacts passwords, tokens, API keys, emails, phone numbers, and card-like values from logs.
 *
 * Primary use case: Safe logs and debug outputs.
 * Typical inputs: array or string payload, redaction rules.
 * Typical output: redacted payload.
 *
 * Implementation note: Make rules recursive and configurable.
 *
 * @param mixed $payload String or array payload to redact.
 * @param array $extra_keys Additional sensitive key fragments.
 * @param int $depth Current recursion depth.
 * @return array Structured redaction result.
 */
function ogRedactSensitiveData($payload, $extra_keys = array(), $depth = 0) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array('payload' => '')
	);

	if (!is_array($extra_keys)) {
		$extra_keys = array();
	}

	$depth = (int)$depth;
	if ($depth > 10) {
		$result['message'] = 'Maximum redaction depth reached.';
		$result['data']['payload'] = '[redacted-depth-limit]';
		return $result;
	}

	$default_keys = array('password', 'passwd', 'pass', 'token', 'secret', 'api_key', 'apikey', 'authorization', 'cookie', 'csrf', 'card', 'cvv');
	$keys = array_merge($default_keys, $extra_keys);
	$redacted = $payload;

	if (is_array($redacted)) {
		foreach ($redacted as $key => $value) {
			$lower_key = strtolower((string)$key);
			$is_sensitive_key = false;
			foreach ($keys as $sensitive_key) {
				$sensitive_key = strtolower((string)$sensitive_key);
				if (!empty($sensitive_key) && strpos($lower_key, $sensitive_key) !== false) {
					$is_sensitive_key = true;
				}
			}

			if ($is_sensitive_key) {
				$redacted[$key] = '[redacted]';
			} elseif (is_array($value)) {
				$child = ogRedactSensitiveData($value, $extra_keys, $depth + 1);
				$redacted[$key] = $child['data']['payload'];
			} elseif (is_scalar($value)) {
				$child = ogRedactSensitiveData((string)$value, $extra_keys, $depth + 1);
				$redacted[$key] = $child['data']['payload'];
			}
		}
	} else {
		$redacted = (string)$redacted;
		$redacted = preg_replace('/(password|passwd|token|secret|api[_-]?key)\s*[:=]\s*[^\s,&]+/i', '$1=[redacted]', $redacted);
		$redacted = preg_replace('/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i', '[redacted-email]', $redacted);
		$redacted = preg_replace('/\b(?:\+?1[-.\s]?)?(?:\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4})\b/', '[redacted-phone]', $redacted);
		$redacted = preg_replace('/\b(?:[0-9][ -]*?){13,19}\b/', '[redacted-card]', $redacted);
	}

	$result['success'] = true;
	$result['message'] = 'Sensitive data redacted.';
	$result['data'] = array('payload' => $redacted);

	return $result;
}