Bugfix Issue 564 GetOptions EWarning Unserialize - sebiboga/testlink-upgraded GitHub Wiki
Bugfix — Issue #564: E_WARNING spam from unserialize() in testproject::getOptions()
Symptom
Every page load that resolves the current test project emits 1–5 Event Viewer rows:
E_WARNING unserialize(): Error at offset 0 of 1 bytes - in testproject.class.php - Line 3897
This happens when testprojects.options holds a non-serialized scalar value (e.g. "0" from a SQL migration or import).
Root cause
testproject::getOptions() (lib/functions/testproject.class.php:3897) calls unserialize($rs[0]['options']) without checking whether the value is a valid serialized string. PHP 8.x promotes the old E_NOTICE to E_WARNING, and tlLogger records it to the events table.
Why it breaks now: PHP 8 upgrade. The same code was silent under PHP 7.
Fix
Guard unserialize() in getOptions():
- Check the raw value is a string, non-empty, and starts with a valid serialized type token (
O,a,s,i,d,b,N,R). - If not, return
(object)[]— callers already handle empty objects safely. - After
unserialize(), check forfalsereturn and fall back to(object)[].
File changed: lib/functions/testproject.class.php (lines 3894–3903)
Before:
if (null == $rs || count($rs) <=0) {
return (object)[];
}
return unserialize($rs[0]['options']);
After:
if (null == $rs || count($rs) <=0) {
return (object)[];
}
$raw = $rs[0]['options'];
if (!is_string($raw) || $raw === '' || !in_array($raw[0], ['O','a','s','i','d','b','N','R'], true)) {
return (object)[];
}
$obj = unserialize($raw);
return $obj !== false ? $obj : (object)[];
Blast radius
Same unguarded unserialize() pattern exists at lines 239 and 433 (parseTestProjectRecordset) — those are also vulnerable but out of scope for this minimal fix.
Regression matrix
| Scenario | Before fix | After fix |
|---|---|---|
options = "0" |
E_WARNING × 5 | 0 warnings |
options = "" |
E_WARNING × 1 | 0 warnings |
options = NULL |
(handled by count check) | 0 warnings |
| Valid serialized options | Works | Works |
| Non-existent project | Returns (object)[] |
Returns (object)[] |