Repository navigation
Bugfix Issue 1897 KeywordsEdit Array DoAction TypeError
github-actions[bot] edited this page Oct 11, 2026
·
1 revision
Issue: GET /lib/keywords/keywordsEdit.php?doAction[]=x answered HTTP 500 with a blank
body while the scalar control ?doAction=x answered the normal 302. This is the
array-shaped twin of #1886 (planMilestonesEdit.php), #1731 (reqMgrSystemEdit.php) and the
#1738 root-cause class (array-typed input parameter handed to a string-typed PHP function).

Chain on the pre-fix revision:
-
lib/keywords/keywordsEdit.php:34—testlinkInitPage($db)authenticates the session and returns; the crash is after the auth gate, so any authenticated user can reach it. -
lib/keywords/keywordsEdit.php:66—$doAction = isset($_REQUEST['doAction']) ? trim($_REQUEST['doAction']) : '';
isset()is true for?doAction[]=x(a non-null array), so the array is passed totrim(). -
trim()declaresstring $string, so PHP 8 throwsTypeError: trim(): Argument #1 ($string) must be of type string, array given. Uncaught → HTTP 500, blank body. - Lines 82 (
in_array($doAction, ...)) and 158 (switch ($doAction)) are never reached.
keyword / notes were already hardened two lines below (lib/keywords/keywordsEdit.php:68-73,
the is_array() casts) — doAction was the one read left unguarded in the file.
Mirror the #1886 remedy (planMilestonesEdit.php:66): an is_scalar() guard that ignores a
non-scalar action so the request falls through to the normal GET redirect.
$doAction = isset($_REQUEST['doAction']) && is_scalar($_REQUEST['doAction'])
? trim((string)$_REQUEST['doAction']) : '';Why this method:
- Minimal — one guarded read, no control-flow change.
-
Behaviour-preserving for scalars —
trim((string)$x)is exactly the legacytrim($x)for every scalar (keeps the whitespace trim that theswitchonedit/cflrelies on), so thedo_create/do_update/do_delete/do_cflwrite paths and theedit/cflGET dispatchers are byte-for-byte unchanged. - Alternatives rejected: casting blindly (
(string)$_REQUEST['doAction']) would turn an array into the string"Array"and let it flow into the switch/in_array; rejecting with a dedicated HTTP 400 error page is more code than the legacy shim's graceful redirect needs and diverges from the sibling files' established pattern.
-
lib/keywords/keywordsEdit.php(1 guarded read, +7/−1 with comment). -
docs/Bugfix-Issue-1897-KeywordsEdit-Array-DoAction-TypeError.md(mirror). - this wiki page +
issue-1897-keywordsedit-redirect.png. -
tmp/TLU_Test_Cases.md—Regression — Issue #1897suite.
-
Pre-fix (branch before the edit):
?doAction[]=x→ HTTP 500;?doAction=x→ 302; the exact expression isolated on the CLI reproducestrim(): Argument #1 ($string) must be of type string, array given. -
Post-fix:
-
?doAction[]=x→ 302 togui/templates/keywords/keywordsEdit.html?mode=create&tproject_id=…(byte-identical to the scalar control). -
?doAction=x→ 302mode=create;?doAction=edit&id=999→ 302mode=edit;?doAction=cfl&tcversion_id=5→ 302mode=cfl. - POST
doAction[]=do_create&keyword=x→ 302 (safe, no write); POSTdoAction=do_create&tproject_id=1(project fixture) → 303, keyword row created;eventsshows only the auditlog_level=16rows, 0 new Error/Warning. - Browser (chrome-devtools, admin session):
?doAction[]=x&tproject_id=1lands on the modern Keyword Management popup, 0 console errors. -
php -l lib/keywords/keywordsEdit.php→ no syntax errors.
-
- Regression suite
Regression — Issue #1897(12 cases) 12/12 PASS; suite gate 7/7 (TLU_REQUIRE_SUITE="Issue #1897" bash ai/verify_test_suites.sh). - No user-facing string added → no i18n bundle touched.
- #1731 (
reqMgrSystemEdit.php), #1738 (array-typed input parameter root cause), #1886/#1894 (planMilestonesEdit.php), and the shim-hardening family (#1892listTestCases.php, #1893searchMgmt.php). - A grep for the same shape (
trim($_REQUEST[...])with a bareisset()) still finds other legacy reads such aslib/project/projectView.php:53andlib/functions/common.php:1725; those are separate screens, out of scope here, and belong to their own tickets.