Every file under src/ exits outside WordPress (defined('ABSPATH') ||
exit; after the use block, so a direct request no longer prints a fatal
error with the server path); divi-convert-fixture.php gets the WP_CLI
guard the other integration scripts have. A unit test keeps both true;
PSR1 side-effects warning excluded for the guard.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
38 lines
1.3 KiB
PHP
38 lines
1.3 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace LIT\MCP\Integrations\Divi\Compose;
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
/**
|
||
* Removes C0 control characters except tab, LF and CR, and DEL (rulings S32/S32a). Applied to
|
||
* RAW values only, before the marker check and the sanitizer: the WordPress sanitizers keep them
|
||
* (sanitize_text_field keeps NUL; strip_tags reads "<" + VT/FF as a literal "<"), so a strip
|
||
* after sanitizing could build a marker or a tag no check saw. After the sanitizer a changed
|
||
* result of strip() only ever means rejection. Pure PHP.
|
||
*/
|
||
final class ControlChars
|
||
{
|
||
public static function strip(string $value): string
|
||
{
|
||
return (string) preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $value);
|
||
}
|
||
|
||
/**
|
||
* strip() on every string inside $value (keys stay: odd keys are rejected). Ruling S35:
|
||
* AttrWriter::apply() and ShortformWriter::apply() run it once on their raw input, before
|
||
* placeholder resolution and trim – so "{\0{post:title}}" is the placeholder, checked as one,
|
||
* and never literal text that slipped past the placeholder check.
|
||
*/
|
||
public static function stripDeep(mixed $value): mixed
|
||
{
|
||
if (is_string($value)) {
|
||
return self::strip($value);
|
||
}
|
||
|
||
return is_array($value) ? array_map([self::class, 'stripDeep'], $value) : $value;
|
||
}
|
||
}
|