Skip to content
← Back to Functions
Code

Content Security Policy Builder

Creates a strict but configurable CSP header from approved local and external service sources.

Function signature

ogBuildContentSecurityPolicy(directives = array(), options = array())

Categories

  • Security

Parameters

directivesDirective map such as default-src => array('\'self\'').optionsOptional flags such as allow_inline_style. Recognized keys: `allow_inline_style`.

Return value

Short public-safe status message.

  • header
  • directives

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, and caller-owned allowlists before use; keep secrets 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.
 */

/**
 * Builds a Content-Security-Policy header value from explicit directives.
 *
 * Sources are sanitized conservatively. Use this to assemble a policy string;
 * the controller should send it with header('Content-Security-Policy: ...').
 *
 * @param array $directives Directive map such as default-src => array('\'self\'').
 * @param array $options Optional flags such as allow_inline_style.
 * @return array CSP header value and directive map.
 */
function ogBuildContentSecurityPolicy($directives = array(), $options = array()) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

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

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

	$policy = array(
		'default-src' => array('\'self\''),
		'base-uri' => array('\'self\''),
		'object-src' => array('\'none\''),
		'frame-ancestors' => array('\'self\'')
	);

	foreach ($directives as $directive => $sources) {
		$directive = strtolower(trim((string)$directive));
		if (!preg_match('/^[a-z0-9-]+$/', $directive)) {
			continue;
		}

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

		$clean_sources = array();
		foreach ($sources as $source) {
			$source = trim((string)$source);
			if (empty($source)) {
				continue;
			}
			if (preg_match('/^[a-z0-9:\/\.\*\-\'\s]+$/i', $source)) {
				$clean_sources[] = $source;
			}
		}

		if (!empty($clean_sources)) {
			$policy[$directive] = array_values(array_unique($clean_sources));
		}
	}

	if (!empty($options['allow_inline_style'])) {
		if (empty($policy['style-src'])) {
			$policy['style-src'] = array('\'self\'');
		}
		if (!in_array('\'unsafe-inline\'', $policy['style-src'], true)) {
			$policy['style-src'][] = '\'unsafe-inline\'';
		}
	}

	$parts = array();
	foreach ($policy as $directive => $sources) {
		$parts[] = $directive . ' ' . implode(' ', $sources);
	}

	$header_value = implode('; ', $parts);
	$result['success'] = true;
	$result['message'] = 'Content Security Policy built.';
	$result['data'] = array(
		'header' => $header_value,
		'directives' => $policy
	);

	return $result;
}