Files
WP-LIT-MCP/src/Integrations/Divi/BlockTree/Json.php
T
janniclas.loosenandClaude Opus 5.5 b24eb6c3e9 fix(security): no direct HTTP access to plugin PHP files (audit L2, cheap part)
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
2026-09-26 19:32:12 +02:00

79 lines
2.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace LIT\MCP\Integrations\Divi\BlockTree;
use JsonException;
use stdClass;
defined('ABSPATH') || exit;
/**
* JSON of block attributes. PHP arrays cannot tell an empty JSON object from an empty list,
* nor an object with the keys "0", "1", … from a list. decodeObject() therefore keeps such
* objects as stdClass, so a regenerated opener encodes them as {} again (Divi breaks on
* "[]" where it expects "{}" – see its EmptyArrayCorruptionMigration).
*/
final class Json
{
/**
* @return array<string, mixed>|null Null when $json is not a JSON object, or its top level
* is one only nominally (keys "0", "1", … – see the class docblock): re-encoding those
* keys as a PHP array would silently turn the object back into a JSON list.
*/
public static function decodeObject(string $json): ?array
{
try {
$value = json_decode($json, false, 512, JSON_THROW_ON_ERROR);
} catch (JsonException) {
return null;
}
if (! $value instanceof stdClass) {
return null;
}
$keys = get_object_vars($value);
if ($keys !== [] && array_is_list($keys)) {
return null;
}
$converted = self::fromJson($value);
return is_array($converted) ? $converted : [];
}
/** Converts json_decode(…, false) output: objects become arrays unless that would lose their object-ness. */
public static function fromJson(mixed $value): mixed
{
if ($value instanceof stdClass) {
$array = [];
foreach (get_object_vars($value) as $key => $item) {
$array[$key] = self::fromJson($item);
}
return $array === [] || array_is_list($array) ? (object) $array : $array;
}
if (is_array($value)) {
return array_map([self::class, 'fromJson'], $value);
}
return $value;
}
/**
* @throws JsonException When $value cannot be represented as JSON – including a string
* with an invalid UTF-8 byte sequence (JSON_ERROR_UTF8). 2a only ever encodes
* attributes this plugin already decoded from valid block markup, so that never
* happens here; a caller that later encodes user-supplied strings (2b's writers)
* must catch this and map it to a validation error instead of a fatal.
*/
public static function encode(mixed $value): string
{
// phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode -- pure PHP (spec §4.4).
return json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
}
}