Issue 552 TC Print No Project Context Fix - sebiboga/testlink-upgraded GitHub Wiki
Fixed: requesting the single test case print popup
(lib/testcases/tcPrint.php) with a valid testcase_id while the
session carries no project ($_SESSION['testprojectID'] unset) and the URL
has no tproject_id parameter produced a broken page: HTTP 500 with a
raw debug_print_backtrace() dump instead of the printable test case.
This is the fresh-session deep-link scenario: e.g. a bookmark or an external tool linking straight to
/lib/testcases/tcPrint.php?testcase_id=1002&tcversion_id=2002
The response body was only:
<pre>#0 .../lib/functions/print.inc.php(2326): testproject->get_by_id(0)
#1 .../lib/functions/print.inc.php(951): initStaticRenderTestCaseForPrinting(...)
#2 .../lib/testcases/tcPrint.php(64): renderTestCaseForPrinting(...)
</pre>
plus HTTP status 500. No printable content at all.
-
tcPrint.php::init_args()resolves the project id from$_SESSION['testprojectID'], then falls back to thetproject_idrequest parameter. In the deep-link scenario both are absent, so$args->tproject_idstays0. - The rendering pipeline passes that
0down as$context['tproject_id'];initStaticRenderTestCaseForPrinting()(lib/functions/print.inc.php) calledtestproject::get_by_id($tprojectID)unconditionally. -
testproject::get_by_id()treats a falsy id as fatal:if (null == $id)— and under PHP 8 the loose comparisonnull == 0is true — so it echoed a backtrace and threwException: test project ID, is mandatory, which nothing in the print flow catches → HTTP 500.
A valid test case always belongs to exactly one test project, so there was never a reason to render without resolving it first.
Considered alternatives:
-
Guard
$infoonly (is_null()check around$info['issue_tracker_enabled']) — stops the crash but renders the test case without its project context: wrong prefix source, issue tracker interface silently skipped. Rejected as primary fix. -
Derive the project id from the tree path in
tcPrint.phpand keep a defensive guard in the shared renderer. Chosen: the deep link gets the correct full context (prefix, custom fields, issue tracker), and any other caller that ever passestproject_id=0degrades gracefully instead of throwing.
Changes:
-
lib/testcases/tcPrint.php: after validating the test case node, when$args->tproject_id <= 0derive the owning project fromtree::get_path($args->tcase_id).get_path()excludes the tree root, so element[0]is the child of the root and itsparent_idis the test project id — the exact conventiontestcase::getPrefix()already uses. -
lib/functions/print.inc.php(initStaticRenderTestCaseForPrinting()): callget_by_id()only when$tprojectID > 0, and null-guard$infobefore readingissue_tracker_enabled.
| Scenario | Before | After |
|---|---|---|
| Valid tc, no project context | HTTP 500 + backtrace dump | HTTP 200, correct page FIX-1002
|
| Valid tc directly under project root | same crash | HTTP 200, correct page FIX-1003
|
| Invalid testcase id | clean message (#541) | unchanged |
| Normal browser flow (session has project) | worked | unchanged |
| Event Viewer | n/a | zero new Error/Warning entries |
-
#553 —
tlIssueTracker::getInterfaceObject()array-offset-on-null whenissue_tracker_enabled=1but no tracker linked. -
#554 —
testproject::get_by_id()warns on positive-but-nonexistent ids ($result[0]on null).

