Admin CSRF Bulk Action Gate
Validates a POSTed CSRF token and a bulk-action selection before an admin controller performs a state-changing operation.
Purpose
Validates a POSTed CSRF token and a bulk-action selection before an admin controller performs a state-changing operation.
Snippet details
ContextSecurityLevelAdvancedCopy-and-paste statusMarked safe after review.Categories
- Security
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.
*/
/**
* Admin CSRF Bulk Action Gate.
*
* Purpose:
* Validates the CSRF token, action name, and selected IDs before a bulk admin
* operation is allowed to continue.
*
* @param array $post_input Sanitized or raw $_POST-style input array.
* @param array $session_state Session array containing the stored CSRF token.
* @param array $allowed_actions Approved bulk action names.
* @param int $max_items Maximum IDs allowed in one request.
* @return array Gate result with action, IDs, and errors.
*/
function ogSnippetAdminCsrfBulkActionGate(array $post_input, array $session_state, array $allowed_actions, int $max_items): array {
$errors = array();
$approved_ids = array();
$selected_action = '';
if ($max_items < 1) {
$max_items = 1;
}
$posted_token = '';
$stored_token = '';
if (isset($post_input['csrf_token']) === true) {
$posted_token = (string) $post_input['csrf_token'];
}
if (isset($session_state['csrf_token']) === true) {
$stored_token = (string) $session_state['csrf_token'];
}
if ($posted_token === '' || $stored_token === '') {
$errors[] = 'Missing CSRF token.';
} elseif (hash_equals($stored_token, $posted_token) === false) {
$errors[] = 'CSRF token mismatch.';
}
if (isset($post_input['bulk_action']) === true) {
$selected_action = trim((string) $post_input['bulk_action']);
}
if ($selected_action === '') {
$errors[] = 'Bulk action is required.';
} elseif (in_array($selected_action, $allowed_actions, true) === false) {
$errors[] = 'Bulk action is not allowed.';
}
if (isset($post_input['selected_ids']) === false || is_array($post_input['selected_ids']) === false) {
$errors[] = 'No item IDs were selected.';
} else {
foreach ($post_input['selected_ids'] as $raw_id) {
$id = filter_var($raw_id, FILTER_VALIDATE_INT);
if ($id !== false && $id > 0) {
$approved_ids[(int) $id] = (int) $id;
}
}
}
$approved_ids = array_values($approved_ids);
if (count($approved_ids) < 1) {
$errors[] = 'No valid item IDs were selected.';
}
if (count($approved_ids) > $max_items) {
$errors[] = 'Too many item IDs were submitted in one request.';
}
return array(
'allowed' => count($errors) === 0,
'action' => $selected_action,
'ids' => $approved_ids,
'errors' => $errors
);
}
$admin_post = array(
'csrf_token' => 'stargate-alpha-token',
'bulk_action' => 'archive',
'selected_ids' => array('101', '102', 'bad-id', '103')
);
$admin_session = array('csrf_token' => 'stargate-alpha-token');
$gate_result = ogSnippetAdminCsrfBulkActionGate($admin_post, $admin_session, array('archive', 'publish'), 25);
if ($gate_result['allowed'] === true) {
echo 'Stargate admin gate approved '.count($gate_result['ids']).' IDs.';
} else {
echo 'Stargate admin gate blocked the request.';
}