|
|
@@ -54,6 +54,13 @@ function aliasFirstExisting(PDO $pdo, string $table, array $candidates, string $
|
|
|
return "'' AS `$alias`";
|
|
|
}
|
|
|
|
|
|
+/** Abort if $table is not a safe da_* or da_*_stages identifier. */
|
|
|
+function validate_table_name(string $table): void {
|
|
|
+ if (!preg_match('/\Ada_[a-z0-9_]+\z/', $table)) {
|
|
|
+ http_response_code(500);
|
|
|
+ exit("Invalid table name");
|
|
|
+ }
|
|
|
+}
|
|
|
function h($s) { return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
|
|
|
function council_name_from_key(string $k): string {
|
|
|
$base = preg_replace('/^da_/', '', $k);
|
|
|
@@ -73,6 +80,7 @@ function days_left(?string $ymd): ?int {
|
|
|
return (int)$today->diff($d)->format('%r%a');
|
|
|
}
|
|
|
function tableHasColumn(PDO $pdo, string $table, string $col): bool {
|
|
|
+ validate_table_name($table);
|
|
|
$q = $pdo->prepare("SHOW COLUMNS FROM `{$table}` LIKE ?");
|
|
|
$q->execute([$col]);
|
|
|
return (bool)$q->fetch();
|
|
|
@@ -114,6 +122,7 @@ $stagesByRef = [];
|
|
|
foreach ($tables as $t) {
|
|
|
$stageT = $t . '_stages';
|
|
|
if (!tableExists($pdo, $stageT)) continue;
|
|
|
+ validate_table_name($stageT);
|
|
|
|
|
|
// Pull everything (small tables) – adjust/WHERE if needed
|
|
|
$st2 = $pdo->query("SELECT * FROM `{$stageT}`");
|
|
|
@@ -184,6 +193,7 @@ foreach ($tables as $t) {
|
|
|
$cols[] = tableHasColumn($pdo, $t, 'document_url') ? "COALESCE(document_url,'') AS document_url" : "'' AS document_url";
|
|
|
$cols[] = tableHasColumn($pdo, $t, 'local_document_url') ? "COALESCE(local_document_url,'') AS local_document_url" : "'' AS local_document_url";
|
|
|
|
|
|
+ validate_table_name($t);
|
|
|
$selects[] = "SELECT ".implode(", ", $cols)." FROM `{$t}`";
|
|
|
}
|
|
|
$sql = "SELECT * FROM (".implode(" UNION ALL ", $selects).") AS x";
|