Skip to content
← Back to Functions
Code

Anomaly Alert Builder

Creates alerts when a metric exceeds expected ranges or changes sharply.

Function signature

ogBuildAnomalyAlerts(values = array(), options = array())

Categories

  • Analytics and Reports

Parameters

valuesNumeric values or rows with value/label keys.optionsOptions: min, max, percent_change_limit. Recognized keys: `max`, `min`, `percent_change_limit`.

Return value

Short public-safe status message.

  • alerts
  • alert_count

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, policy arrays, URLs, signatures, 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.
 */

/**
 * Creates alerts when metric values exceed configured ranges or change sharply.
 *
 * @param array $values Numeric values or rows with value/label keys.
 * @param array $options Options: min, max, percent_change_limit.
 * @return array Anomaly alert list.
 */
function ogBuildAnomalyAlerts($values = array(), $options = array()) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

	if (!is_array($values)) {
		$result['message'] = 'Values must be an array.';
		return $result;
	}

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

	$minimum_limit = null;
	$maximum_limit = null;
	$change_limit = 50;
	if (isset($options['min']) && is_numeric($options['min'])) {
		$minimum_limit = (float)$options['min'];
	}
	if (isset($options['max']) && is_numeric($options['max'])) {
		$maximum_limit = (float)$options['max'];
	}
	if (!empty($options['percent_change_limit']) && is_numeric($options['percent_change_limit'])) {
		$change_limit = (float)$options['percent_change_limit'];
	}

	$alerts = array();
	$previous = null;
	foreach ($values as $index => $row) {
		$label = (string)$index;
		$value = null;
		if (is_array($row)) {
			if (!empty($row['label'])) {
				$label = (string)$row['label'];
			}
			if (isset($row['value']) && is_numeric($row['value'])) {
				$value = (float)$row['value'];
			}
		} elseif (is_numeric($row)) {
			$value = (float)$row;
		}

		if ($value === null) {
			continue;
		}

		if ($minimum_limit !== null && $value < $minimum_limit) {
			$alerts[] = array('label' => $label, 'type' => 'below_minimum', 'value' => $value, 'limit' => $minimum_limit);
		}
		if ($maximum_limit !== null && $value > $maximum_limit) {
			$alerts[] = array('label' => $label, 'type' => 'above_maximum', 'value' => $value, 'limit' => $maximum_limit);
		}
		if ($previous !== null && $previous != 0) {
			$change = (($value - $previous) / abs($previous)) * 100;
			if (abs($change) >= $change_limit) {
				$alerts[] = array('label' => $label, 'type' => 'sharp_change', 'value' => $value, 'percent_change' => $change);
			}
		}
		$previous = $value;
	}

	$result['success'] = true;
	$result['message'] = 'Anomaly alerts built.';
	$result['data'] = array('alerts' => $alerts, 'alert_count' => count($alerts));

	return $result;
}