In Joomla's content versioning system, Joomla\CMS\Table\ContentHistory::getSha1() is used to compute a normalized SHA-1 hash of a content item's payload to determine if meaningful changes have occurred before inserting a new version in #__history.
When an object payload with nested JSON column data (e.g. params, metadata, images, urls) is passed to ContentHistory::getSha1():
$data = (object) [
'title' => 'Original Article Title',
'modified_by' => 42,
'version' => 3,
'params' => (object) [
'title' => 'Custom Form Header',
'show_title' => 1,
],
];
$historyTable = new \Joomla\CMS\Table\ContentHistory($db);
$contentType = new \Joomla\CMS\Table\ContentType($db);
$hash = $historyTable->getSha1($data, $contentType);5.4-dev / 6.0-dev / 6.1-dev / 6.2-dev
$data should remain intact and immutable without losing its properties (modified_by, version, etc.).$data->params->show_title), keeping data hierarchy intact.$data->title must not be overwritten by sub-properties of nested objects.$object = \is_object($jsonData) ? $jsonData : json_decode($jsonData); operates by reference on the caller's object without cloning, unset($object->$remove) permanently strips properties like modified_by, modified, version, and checked_out from the caller's live object in memory.libraries/src/Table/ContentHistory.php (line 138):
if (\is_object($value)) {
// Go one level down for JSON column values
foreach ($value as $subName => $subValue) {
$object->$subName = \is_int($subValue) || \is_bool($subValue) || $subValue === null ? (string) $subValue : $subValue;
}
}$object->$subName flattens all nested parameters onto the root object, leaving $value un-normalized and overwriting any root properties that share the same key (e.g., if params has a title or alias, $object->title gets overwritten by the parameter value).Joomla 5.4-dev / 6.0-dev / 6.1-dev / 6.2-dev
PHP 8.2 / 8.3 / 8.4
Root Cause:
libraries/src/Table/ContentHistory.php, line 138 should target $value->$subName (or $object->$name->$subName) instead of $object->$subName.$jsonData should be cloned / decoupled before modifying or unsetting properties to prevent mutating the caller's live table/model instances.| Labels |
Added:
No Code Attached Yet
|
||