Bugfix Issue 1738 Array Typed Parameter Trim TypeError - sebiboga/testlink-upgraded GitHub Wiki
Bugfix: array-shaped value for an input parameter raises an uncaught PHP 8 TypeError through trim() (Issue #1738)
Issue: an array-shaped query/body value (?k[]=x) for an input parameter reaches PHP's
string/number functions and raises an uncaught TypeError → HTTP 500, 0-byte body, zero
events rows (no observable log trail). The shared input layer is used by every TestLink
controller through R_PARAMS() / P_PARAMS() / G_PARAMS(), so one bracketed parameter name is
enough to kill a request from any screen.
Root cause
Chain (each hop file:line, verified on HEAD before the fix):
- PHP materialises
?k[]=x(and?k[][]=x) as an array in$_GET/$_POST/$_REQUEST. lib/functions/inputparameter.class.php:153—fetchParameter()reads the raw value.lib/functions/inputparameter.class.php:162-167— the guard added for #1720 drops an array only when the validation type is a scalar one; it deliberately keeps arrays fortlArrayValidationInfo(ARRAY_INT/ARRAY_STRING_N).lib/functions/inputparameter.class.php:308→tlStringValidationInfo::normalize()→trim()(:330):ltrim()/rtrim()/trim()/tlSubStr()have no type guard.lib/functions/inputparameter.class.php:424→tlIntegerValidationInfo::normalize()→intval(trim($value)): same unguarded shape.lib/functions/inputparameter.class.php:501→tlArrayValidationInfo::normalize()calls the member validator'snormalize(); a nested array element still reaches steps 4/5.TypeError extends Error— it is not anException, so thecatch (Exception)/catch (Throwable)guards at the call sites do not turn it into a graceful message; the failure happens beforetLog(), hence 0eventsrows.
Why it breaks now: on PHP 5/7 trim(array) only emitted a warning and coerced; PHP 8 turns
it into a fatal TypeError. The #1720 fix closed the scalar case one level above the root cause;
the guard the issue itself asked for (in trim()) was never added, so nested array-typed
parameters remained fatal.
Fix (approach)
Add the is_scalar() guard the issue suggested at the three sites that hand a value to PHP's
string/int functions. null is returned for a non-null non-scalar, so the parameter (or the
array member) reads as absent — matching the contract the existing per-screen workarounds
(shimReqScalar() in lib/reqmgrsystems/reqMgrSystemEdit.php, reqSpecEditDropShapedAction() in
lib/requirements/reqSpecEdit.php) already assume.
tlStringValidationInfo::trim()(:330) —if ($value !== null && !is_scalar($value)) return null;before theswitch. Makestrim()itself never fatal for every caller, including direct / out-of-tree construction and array members.tlIntegerValidationInfo::normalize()(:430) — the same guard beforeintval(trim($value)).tlArrayValidationInfo::normalize()(:501) —unset()a non-scalar member so it never reaches the member normalizer (and the member validator never throws a spurious validation error for it).
Why "reads as absent" (null) rather than coercing to '': '' would silently pass the
min/max-length validators; null is what the existing workarounds already return.
Rejected alternatives: a fourth fetch-layer guard (would again miss nested members and any
direct tlInputParameter construction — the duplication the issue already laments); a global
set_exception_handler (too broad for a parameter-shape defect).
Files changed
lib/functions/inputparameter.class.php—is_scalar()guards intlStringValidationInfo::trim(),tlIntegerValidationInfo::normalize()andtlArrayValidationInfo::normalize()(+21 lines).
Verification
php -l lib/functions/inputparameter.class.php→ clean.- Shared-layer CLI matrix: scalar
STRING_N/INT/INT_N/CB_BOOLwith?k[]=x→null(unchanged, already fixed by60b823d8d);ARRAY_INTnested?k[][]=x→TypeError … trim(): Argument #1 … array givenbefore,array()after;ARRAY_STRING_Nnested no longer fatal. - Live HTTP (temporary docroot probe, removed after the test):
?doAction=hi&nested[]=7→ 200{hi,[7]};?doAction[]=x→ 200{null,null};?nested[][]=x→ 200{null,[]};?doAction=++spaced++&nested[]=1&nested[]=2→ 200{"spaced",[1,2]}. No 0-byte 500. eventsrows withlog_level<=2: 0 before → 0 after (no new Error/Warning).- Regression suite
Regression — Issue #1738(14 cases) 14/14 PASS; suite gate 7/7 (bash ai/verify_test_suites.sh). - No user-facing string added → no i18n bundle touched.
Related
- #1720 — the scalar-parameter manifestation of the same defect (fixed at the fetch layer by
60b823d8d/aa53eab6e); this issue completes it at thetrim()root cause. - #1731 (
reqMgrSystemEdit.php), #1732 (listTestCases.php), #1736 (reqSpecEdit.php) — per-screenis_scalar()workarounds for the same shape.