Repository navigation
Bugfix Issue 1735 reqSpecSearch count null 500
Bug fix — Issue #1735: reqSpecSearch.php:116 count() on an uninitialised $itemSet — HTTP 500 / 0 bytes
The legacy Search → Requirement Specification Results screen
(lib/requirements/reqSpecSearch.php) answered HTTP 500 with a 0-byte body because of
Uncaught TypeError: count(): Argument #1 ($value) must be of type Countable|array, null given
in …/lib/requirements/reqSpecSearch.php:116
$gui->row_qty=count($itemSet); sat outside the only block that assigns $itemSet,
so any state that skips that block makes count(null) a PHP-8 TypeError. On 1.9.20
(PHP 5.x) the same expression was only a warning and still rendered an empty table.
The controller that contained the defect was deleted when this screen was modernized:
-
d1b2a884c— feat(#1825): retire both legacy req-spec search controllers + switch the link (2026-10-04) turnedlib/requirements/reqSpecSearch.phpinto a session-guarded redirect shim; -
7e859c3b9— follow-up hardening.
The screen is now the Dashio page Search Requirement Specifications
backed by api/requirements/index.php (GET /reqspec-search), whose counter is
initialised (:2176 $count = 0;) — count(null) cannot occur — and whose empty
state is the explicit else { $warning = 'no_records_found'; } (:2212-2214), exactly
the behaviour the issue's Expected section asked for.


Current default branch (bce8fb392):
$ curl ... "$BASE/lib/requirements/reqSpecSearch.php"
HTTP 302 size=0 redirect=…/gui/templates/requirements/searchReqSpec.html?tproject_id=1
# XHR flavour
HTTP 405 size=170
{"status":"error","code":"retired_endpoint","message":"This legacy endpoint no longer serves the search results. …"}
$ curl ... "$BASE/api/requirements/index.php/reqspec-search?tproject_id=1"
HTTP 200 {"status":"ok","count":2,"rows":[…],"warning":"" …}
Discrimination — restoring the pre-#1825 controller and probing as a user with no
session project reproduces the 500 (testproject::get_by_id(0) in
reqSpecCommands::__construct, reached from reqSpecSearch.php:34); with a project set
the same pre-fix file reaches count($itemSet) at line 116.
| hop | file:line (pre-#1825) | code |
|---|---|---|
| 1 | reqSpecSearch.php:43 |
$itemSet = null; |
| 2 | reqSpecSearch.php:104 |
if($args->tprojectID) { … } — the only block assigning $itemSet
|
| 3 | reqSpecSearch.php:113 |
$itemSet = $db->fetchRowsIntoMap(…) |
| 4 | reqSpecSearch.php:116 |
$gui->row_qty=count($itemSet); — unconditional → TypeError
|
| reference | status |
|---|---|
lib/requirements/reqSpecSearch.php |
redirect shim only |
gui/templates/{dashio,tl-classic}/requirements/reqSpecSearchForm.tpl:25 |
dead legacy form action (screen no longer rendered; modern action …/reqSpecSearchForm.html, lib/general/frmWorkArea.php:34) |
lib/functions/tlReqMgrSystem.class.php:673, api/requirements/index.php:2095
|
comments only |
Re-patching count($itemSet) would keep a second redundant search implementation alive
behind a page the ASIDE no longer links to; the retirement removes the whole class of
PHP-8 defects from the path.
bash tmp/verify_1735.sh — self-cleaning, creates its own fixture, exits non-zero on any
failure: 15 PASS / 0 FAIL (exit 0) — legacy URL 302/405 (never 500), modern screen 200,
BFF results / filtered count / no_records_found, zero Event-Viewer Error/Warning rows,
and no count($itemSet) in either the shim or the BFF.
- Issue #1629 — the sibling 500 fix that let the request reach this screen's own defect.
- Issue #1825 — the modernization that retired this controller.