Skip to content
← Back to Functions
Code

Bulk Action Validator

Validates selected IDs, action name, CSRF, and permission before bulk admin actions.

Function signature

ogValidateBulkActionRequest(post_data = array(), policy = array())

Categories

  • Security

Parameters

post_dataPOST-derived request data already selected by the caller for bulk-action validation.policyCaller-approved workflow policy for the ecommerce, admin, privacy, or export decision.

Return value

Public-safe status string returned by the function for explicit 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 admin actions, export fields, privacy plans, cache keys, templates, settings, routes, and ecommerce policies 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.
 */

/**
 * Validates selected IDs, action name, CSRF token, and role before a bulk admin action.
 *
 * This function returns a validated request plan. It does not execute deletes,
 * updates, exports, or any other destructive work.
 *
 * @param array $post_data Submitted POST-style data.
 * @param array $policy Allowed actions, roles, max IDs, and CSRF settings.
 * @return array Validated bulk action request or errors.
 */
function ogValidateBulkActionRequest($post_data = array(), $policy = array()) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

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

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

	$allowed_actions = array();
	if (!empty($policy['allowed_actions']) && is_array($policy['allowed_actions'])) {
		$allowed_actions = $policy['allowed_actions'];
	}

	$allowed_roles = array('admin');
	if (!empty($policy['allowed_roles']) && is_array($policy['allowed_roles'])) {
		$allowed_roles = $policy['allowed_roles'];
	}

	$max_ids = 100;
	if (!empty($policy['max_ids'])) {
		$max_ids = (int)$policy['max_ids'];
	}
	if ($max_ids < 1) {
		$max_ids = 1;
	}

	$errors = array();
	$action = '';
	if (!empty($post_data['action'])) {
		$action = trim((string)$post_data['action']);
	}

	$user_role = '';
	if (!empty($post_data['user_role'])) {
		$user_role = trim((string)$post_data['user_role']);
	}

	if (empty($action) || !in_array($action, $allowed_actions, true)) {
		$errors[] = 'Bulk action is not allowed.';
	}

	if (empty($user_role) || !in_array($user_role, $allowed_roles, true)) {
		$errors[] = 'User role is not allowed for this bulk action.';
	}

	if (!empty($policy['csrf_token'])) {
		$expected = (string)$policy['csrf_token'];
		$submitted = '';
		if (!empty($post_data['csrf_token'])) {
			$submitted = (string)$post_data['csrf_token'];
		}
		if (empty($submitted) || !hash_equals($expected, $submitted)) {
			$errors[] = 'Invalid request token.';
		}
	}

	$ids = array();
	if (!empty($post_data['selected_ids']) && is_array($post_data['selected_ids'])) {
		foreach ($post_data['selected_ids'] as $id) {
			$id = (int)$id;
			if ($id > 0 && !in_array($id, $ids, true)) {
				$ids[] = $id;
			}
		}
	}

	if (empty($ids)) {
		$errors[] = 'No valid IDs were selected.';
	}

	if (count($ids) > $max_ids) {
		$errors[] = 'Too many IDs were selected.';
	}

	$result['success'] = empty($errors);
	if (empty($errors)) {
		$result['message'] = 'Bulk action request validated.';
	} else {
		$result['message'] = 'Bulk action request failed validation.';
	}
	$result['data'] = array(
		'action' => $action,
		'user_role' => $user_role,
		'selected_ids' => $ids,
		'errors' => $errors
	);

	return $result;
}