Skip to content
← Back to Functions
Code

Search Highlight Builder

Builds safe highlighted snippets for matched search terms.

Function signature

ogBuildSearchHighlights(content, terms = array(), max_length = 220)

Categories

  • Search and Discovery

Parameters

contentSource content.termsTerms to highlight.max_lengthMaximum excerpt length.

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

/**
 * Builds safe highlighted snippets for matched search terms.
 *
 * Content is escaped before highlight markup is added. Search terms are escaped and
 * applied conservatively to avoid scriptable output.
 *
 * @param string $content Source content.
 * @param array $terms Terms to highlight.
 * @param int $max_length Maximum excerpt length.
 * @return array Highlighted search excerpt.
 */
function ogBuildSearchHighlights($content, $terms = array(), $max_length = 220) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

	$content = trim(strip_tags((string)$content));
	$max_length = (int)$max_length;
	if ($max_length < 40) {
		$max_length = 40;
	}
	if (empty($content)) {
		$result['message'] = 'Content is required.';
		return $result;
	}

	$excerpt = $content;
	if (strlen($excerpt) > $max_length) {
		$excerpt = substr($excerpt, 0, $max_length);
		$last_space = strrpos($excerpt, ' ');
		if ($last_space !== false) {
			$excerpt = substr($excerpt, 0, $last_space);
		}
		$excerpt = rtrim($excerpt, ' .,;:-') . '...';
	}

	$safe_excerpt = htmlspecialchars($excerpt, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
	$clean_terms = array();
	foreach ((array)$terms as $term) {
		$term = trim((string)$term);
		if (strlen($term) < 2) {
			continue;
		}
		$clean_terms[] = $term;
	}

	usort($clean_terms, function($a, $b) {
		return strlen($b) - strlen($a);
	});

	foreach ($clean_terms as $term) {
		$escaped_term = preg_quote(htmlspecialchars($term, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '/');
		if (!empty($escaped_term)) {
			$safe_excerpt = preg_replace('/(' . $escaped_term . ')/i', '<mark>$1</mark>', $safe_excerpt);
		}
	}

	$result['success'] = true;
	$result['message'] = 'Search highlight excerpt built.';
	$result['data'] = array(
		'excerpt' => $safe_excerpt,
		'plain_excerpt' => $excerpt,
		'terms_used' => $clean_terms
	);

	return $result;
}