~/teardowns/TD-031.md
←Back to teardowns
# TD-031MediumRuntime

Code From a PHP Version That Died in 2015

The generated page fatals before it renders a single row

Published Oct 29, 2026

Executive Summary

A products page generated with mysql_connect() and mysql_query() — a function family removed from PHP in 7.0. The code is syntactically fine but targets the PHP of the model's training corpus (a decade of pre-2015 tutorials), not the PHP 8 the project runs. It fatals with 'Call to undefined function mysql_query()' on the first request. The fix is PDO with prepared statements.

The Prompt

“Add a products page that lists products by category from the database.”

The Flaw

mysql_connect(), mysql_query(), and the entire mysql_* family were removed in PHP 7.0 — released in 2015. On any PHP 7 or 8 runtime this file fatals with 'Call to undefined function mysql_query()' before it renders a single product. The model wrote code for the PHP it was trained on: years of tutorials and Stack Overflow answers that still use mysql_*, because those pages were written before the removal and never updated.

Risk & Impact

[Availability] The page is dead on arrival. It passes a syntax check and looks plausible, but the first real request throws a fatal error — and every request after it does the same.

Cost: The feature never worked; the bug survives until someone actually loads the page in the PHP version the project runs.

Code Comparison

❌ Vulnerable (AI generated)

products.phpphp
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
// products.php
$conn = mysql_connect('localhost', 'root', 'secret') or die(mysql_error());
mysql_select_db('shop', $conn);
$cat = $_GET['cat'] ?? '';
$sql = "SELECT * FROM products WHERE category = '" . $cat . "'";
$result = mysql_query($sql, $conn);
while ($row = mysql_fetch_assoc($result)) {
echo '<h2>' . $row['name'] . '</h2>';
}
?>

The Fix

Target the PHP version the project actually runs. Replace the removed mysql_* functions with PDO prepared statements — and pin the runtime in the prompt so the agent never reaches for a dead API.

Prevention

  • [linter] PHPStan or Psalm run against a PHP 8 baseline flag 'function mysql_query not found', so a removed API fails CI instead of shipping.
  • [ci] Boot the app once in CI (or run one smoke request per route) — the fatal surfaces on the first request, before deploy.
  • [manual] Pin the runtime in the prompt (rule 1: 'PHP 8.3, PDO/MySQL') and name the database access layer you expect.

Why This Happened

Root cause: the prompt omitted Rule 1 and Rule 9 — the guardrails that would have caught this. See the full guide →

Sources

Is your codebase vulnerable to this?

Run Diagnostic on My Project →