Broken Asset Finder
Scans templates/content for asset references and reports missing local files.
Function signature
ogFindBrokenAssetReferences(base_path, documents = array(), options = array())
Categories
- File and Upload Safety
Parameters
base_pathApproved root directory used to keep path operations contained.documentsStructured documents data supplied by the caller.optionsOptional policy, formatting, or behavior controls for this helper.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.
*/
/**
* Scans templates/content for asset references and reports missing local files.
*
* Primary use case: Deployment audits.
* Typical inputs: file paths, document contents.
* Typical output: missing asset report.
*
* Implementation note: Do not fetch remote URLs in this helper.
*
* @return array Structured result data with success, message, and data keys.
*/
function ogFindBrokenAssetReferences($base_path, $documents = array(), $options = array()) {
$result = array(
'success' => false,
'message' => '',
'data' => array()
);
$base_path = (string)$base_path;
if (!is_array($documents)) {
$result['message'] = 'Documents must be an array.';
return $result;
}
if (!is_array($options)) {
$options = array();
}
$base_real = realpath($base_path);
if ($base_real === false || !is_dir($base_real)) {
$result['message'] = 'Asset base path is invalid.';
return $result;
}
$missing = array();
$found = array();
$references = array();
foreach ($documents as $document_name => $content) {
$content = (string)$content;
$matches = array();
preg_match_all('/(?:src|href)=([\"\'])([^\"\']+)\1|url\(([\"\']?)([^\)\"\']+)\3\)/i', $content, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$reference = '';
if (!empty($match[2])) {
$reference = trim($match[2]);
} elseif (!empty($match[4])) {
$reference = trim($match[4]);
}
if (empty($reference)) {
continue;
}
if (preg_match('/^(https?:)?\/\//i', $reference) || strpos($reference, 'data:') === 0 || strpos($reference, '#') === 0) {
continue;
}
$clean_reference = strtok($reference, '?');
$clean_reference = strtok($clean_reference, '#');
$clean_reference = '/' . ltrim($clean_reference, '/');
$references[] = $clean_reference;
$local_path = $base_real . str_replace('/', DIRECTORY_SEPARATOR, $clean_reference);
$real_path = realpath($local_path);
if ($real_path === false || strpos($real_path, $base_real) !== 0 || !is_file($real_path)) {
$missing[] = array('document' => (string)$document_name, 'reference' => $clean_reference);
} else {
$found[] = $clean_reference;
}
}
}
$result['success'] = true;
$result['message'] = 'Asset reference scan completed.';
$result['data'] = array(
'reference_count' => count($references),
'found_count' => count(array_unique($found)),
'missing_count' => count($missing),
'missing' => $missing
);
return $result;
}