Skip to content
← Back to Functions
Code

Safe Delete Planner

Plans deletes with dependency checks, confirmation text, and preview counts.

Function signature

ogPlanSafeDelete(table, key_field, key_value, options = array())

Categories

  • Database Integrity

Parameters

tableTable name from an approved allowlist.key_fieldKey field to delete by.key_valueKey value to bind.optionsOptional allowed tables/fields and dependency counts. Recognized keys: `allowed_fields`, `allowed_tables`, `dependency_count`.

Return value

Public-safe status string returned by the function.

  • 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 procedural mysqli prepared execution where SQL plans are returned; validate file paths, MIME policies, and permissions before file or download workflows.

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

/**
 * Plans a guarded DELETE operation with table, key, and dependency checks.
 *
 * This function does not execute deletion. It returns the SQL plan and confirmation data.
 *
 * @param string $table Table name from an approved allowlist.
 * @param string $key_field Key field to delete by.
 * @param mixed $key_value Key value to bind.
 * @param array $options Optional allowed tables/fields and dependency counts.
 * @return array Safe delete plan.
 */
function ogPlanSafeDelete($table, $key_field, $key_value, $options = array()) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

	$table = trim((string)$table);
	$key_field = trim((string)$key_field);
	if (empty($table) || !preg_match('/^[a-zA-Z0-9_]+$/', $table)) {
		$result['message'] = 'Invalid table name.';
		return $result;
	}
	if (empty($key_field) || !preg_match('/^[a-zA-Z0-9_]+$/', $key_field)) {
		$result['message'] = 'Invalid key field.';
		return $result;
	}

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

	if (!empty($options['allowed_tables']) && is_array($options['allowed_tables'])) {
		if (!in_array($table, $options['allowed_tables'], true)) {
			$result['message'] = 'Table is not allowlisted.';
			return $result;
		}
	}
	if (!empty($options['allowed_fields']) && is_array($options['allowed_fields'])) {
		if (!in_array($key_field, $options['allowed_fields'], true)) {
			$result['message'] = 'Key field is not allowlisted.';
			return $result;
		}
	}

	$dependency_count = 0;
	if (isset($options['dependency_count'])) {
		$dependency_count = (int)$options['dependency_count'];
	}
	if ($dependency_count > 0) {
		$result['message'] = 'Delete blocked by dependencies.';
		$result['data'] = array('dependency_count' => $dependency_count);
		return $result;
	}

	$type = 's';
	if (is_int($key_value)) {
		$type = 'i';
	} elseif (is_float($key_value)) {
		$type = 'd';
	}

	$sql = 'DELETE FROM `' . $table . '` WHERE `' . $key_field . '` = ? LIMIT 1';
	$result['success'] = true;
	$result['message'] = 'Safe delete plan built.';
	$result['data'] = array(
		'sql' => $sql,
		'types' => $type,
		'params' => array($key_value),
		'confirmation' => 'Delete one row from ' . $table . ' where ' . $key_field . ' matches the provided value.'
	);

	return $result;
}