Skip to content
← Back to Functions
Code

Unsubscribe Link Builder

Creates signed unsubscribe links for mail categories.

Function signature

ogCreateUnsubscribeLink(input = array(), options = array())

Categories

  • Email and Messaging

Parameters

inputStructured workflow input array documented by this helper.optionsOptional documented policy controls for the helper.

Return value

Public-safe status string returned by the function for controller branching or logging.

  • success
  • message
  • data

Compatibility

Existing function name, slug, path, and call order preserved; advertised metadata corrected to the actual source behavior.

Minimum PHP version: 7.4

Security notes

Use caller-owned allowlists and context-specific escaping; validate file paths, routes, email tokens, cart totals, discount rules, and tax-region rules before production use.

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 signed unsubscribe links for mail categories.
 *
 * Primary use case: Marketing/compliance email.
 * Typical inputs: email id, category, secret, ttl.
 * Typical output: signed URL.
 *
 * Implementation note: Avoid exposing raw email addresses in links.
 *
 * @param array $input Structured input values for this helper contract.
 * @param array $options Optional policy and formatting controls.
 * @return array Structured result data with success, message, and data keys.
 */
function ogCreateUnsubscribeLink($input = array(), $options = array()) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

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

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

	$subscriber_id = '';
	if (!empty($input['subscriber_id'])) {
		$subscriber_id = preg_replace('/[^a-zA-Z0-9_-]/', '', (string)$input['subscriber_id']);
	}
	$category = 'all';
	if (!empty($input['category'])) {
		$category = preg_replace('/[^a-zA-Z0-9_-]/', '', (string)$input['category']);
	}
	$base_url = '';
	if (!empty($input['base_url'])) {
		$base_url = trim((string)$input['base_url']);
	}
	$secret = '';
	if (!empty($options['secret'])) {
		$secret = (string)$options['secret'];
	}
	$ttl_seconds = 2592000;
	if (!empty($options['ttl_seconds'])) {
		$ttl_seconds = (int)$options['ttl_seconds'];
	}

	if (empty($subscriber_id) || empty($base_url) || empty($secret)) {
		$result['message'] = 'Subscriber ID, base URL, and secret are required.';
		return $result;
	}
	if ($ttl_seconds < 3600) {
		$ttl_seconds = 3600;
	}

	$expires_at = time() + $ttl_seconds;
	$payload = $subscriber_id . '|' . $category . '|' . $expires_at;
	$signature = hash_hmac('sha256', $payload, $secret);
	$query = 'sid=' . rawurlencode($subscriber_id) . '&cat=' . rawurlencode($category) . '&exp=' . $expires_at . '&sig=' . rawurlencode($signature);
	if (strpos($base_url, '?') === false) {
		$separator = '?';
	} else {
		$separator = '&';
	}

	$result['success'] = true;
	$result['message'] = 'Signed unsubscribe link created.';
	$result['data'] = array(
		'url' => $base_url . $separator . $query,
		'expires_at' => $expires_at,
		'signature' => $signature
	);

	return $result;
}