192 lines
6.2 KiB
PHP
Executable File
192 lines
6.2 KiB
PHP
Executable File
<?php
|
|
/*
|
|
*
|
|
* 3. SYS-Level
|
|
*
|
|
*
|
|
*/
|
|
|
|
function get_db_connection($db_host = null, $db_user = null, $db_pass = null, $db_name = null) {
|
|
global $db;
|
|
|
|
// If custom credentials or a custom DB are provided, create a fresh, temporary connection
|
|
if ($db_host !== null || $db_user !== null || $db_pass !== null || $db_name !== null) {
|
|
$host = $db_host ?? DB_HOST;
|
|
$user = $db_user ?? DB_USER;
|
|
$pass = $db_pass ?? DB_PASS;
|
|
$name = $db_name ?? (defined('DB_NAME') ? DB_NAME : '');
|
|
|
|
$dsn_base = "mysql:host=" . $host . ";";
|
|
$dsn_full = $dsn_base . (!empty($name) ? "dbname=" . $name . ";" : "");
|
|
|
|
try {
|
|
return new PDO($dsn_full, $user, $pass);
|
|
} catch (PDOException $e) {
|
|
// MySQL Error 1049 is "Unknown database". If caught, fallback to connection without DB.
|
|
if (strpos($e->getMessage(), '1049') !== false) {
|
|
return new PDO($dsn_base, $user, $pass);
|
|
}
|
|
throw $e; // Re-throw if it's a real connection/auth issue
|
|
}
|
|
}
|
|
|
|
// Otherwise, use or initialize the global connection using constants
|
|
if (!isset($db) || is_null($db)) {
|
|
$dsn_base = "mysql:host=" . DB_HOST . ";";
|
|
$name = defined('DB_NAME') ? DB_NAME : '';
|
|
$dsn_full = $dsn_base . (!empty($name) ? "dbname=" . $name . ";" : "");
|
|
|
|
try {
|
|
$db = new PDO($dsn_full, DB_USER, DB_PASS);
|
|
} catch (PDOException $e) {
|
|
if (strpos($e->getMessage(), '1049') !== false) {
|
|
$db = new PDO($dsn_base, DB_USER, DB_PASS);
|
|
} else {
|
|
throw $e;
|
|
}
|
|
}
|
|
}
|
|
return $db;
|
|
}
|
|
|
|
function sql_read($query, $db_host = null, $db_user = null, $db_pass = null, $db_name = null) {
|
|
$pdo = get_db_connection($db_host, $db_user, $db_pass, $db_name);
|
|
$stmt = $pdo->prepare($query);
|
|
|
|
if ($stmt->execute() === false) {
|
|
return ["status" => "error", "query" => $query];
|
|
}
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
function sql_write($query, $db_host = null, $db_user = null, $db_pass = null, $db_name = null) {
|
|
$pdo = get_db_connection($db_host, $db_user, $db_pass, $db_name);
|
|
$stmt = $pdo->prepare($query);
|
|
|
|
if ($stmt->execute() === false) {
|
|
die("sql error: $query");
|
|
}
|
|
return $stmt->rowCount();
|
|
}
|
|
|
|
function sql($query, $db_host = null, $db_user = null, $db_pass = null, $db_name = null) {
|
|
if (
|
|
stripos(trim($query), "SHOW") === 0
|
|
|| stripos(trim($query), "DESCRIBE") === 0
|
|
|| stripos(trim($query), "SELECT") === 0
|
|
) {
|
|
return sql_read($query, $db_host, $db_user, $db_pass, $db_name);
|
|
} else {
|
|
return sql_write($query, $db_host, $db_user, $db_pass, $db_name);
|
|
}
|
|
}
|
|
|
|
|
|
function runProcess($cmd, $stdin, &$stdout, &$stderr) {
|
|
$descriptorspec = array(
|
|
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
|
|
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
|
|
2 => array("pipe", "w") // stderr is a pipe that the child will write to
|
|
);
|
|
|
|
$process = proc_open($cmd, $descriptorspec, $pipes);
|
|
|
|
if (is_resource($process)) {
|
|
// Write to stdin and close it
|
|
fwrite($pipes[0], $stdin);
|
|
fclose($pipes[0]);
|
|
|
|
// Read the output of the command
|
|
$stdout = stream_get_contents($pipes[1]);
|
|
fclose($pipes[1]);
|
|
|
|
// Read the error output of the command
|
|
$stderr = stream_get_contents($pipes[2]);
|
|
fclose($pipes[2]);
|
|
|
|
// It's important to close all pipes before calling proc_close in order to avoid a deadlock
|
|
$return_value = proc_close($process);
|
|
|
|
return $return_value;
|
|
} else {
|
|
// Return an error code if the process could not be started
|
|
return -1;
|
|
}
|
|
}
|
|
function getTblPrimaryKeyColName($tblName) {
|
|
$dbName = explode(".",$tblName)[0];
|
|
$tblName = explode(".",$tblName)[1];
|
|
|
|
$cols = [];
|
|
foreach(sql("SELECT COLUMN_NAME PksColName FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = '$dbName' AND TABLE_NAME = '$tblName' AND CONSTRAINT_NAME = 'PRIMARY';") as $row)
|
|
$cols[] = $row["PksColName"];
|
|
return $cols;
|
|
}
|
|
|
|
/**
|
|
* Executes a SELECT query and hydrates any foreign key columns with the
|
|
* referenced row data.
|
|
*
|
|
* The query should target a single table (e.g., "SELECT * FROM db.table WHERE …").
|
|
* For each foreign key in that table, an additional key named
|
|
* `<column>_ref` is added to each returned row containing the referenced row
|
|
* from the foreign table.
|
|
*
|
|
* @param string $query SQL SELECT statement for a single table.
|
|
* @return array Result set with hydrated foreign key data.
|
|
*/
|
|
function sql_read_and_hydrate($query) {
|
|
$rows = sql_read($query);
|
|
if (empty($rows)) {
|
|
return $rows;
|
|
}
|
|
|
|
if (!preg_match('/FROM\s+([`\w\.]+)/i', $query, $m)) {
|
|
return $rows; // Unable to determine table
|
|
}
|
|
|
|
$table = str_replace('`', '', $m[1]);
|
|
if (strpos($table, '.') !== false) {
|
|
list($dbName, $tblName) = explode('.', $table, 2);
|
|
} else {
|
|
$dbName = DB_NAME;
|
|
$tblName = $table;
|
|
}
|
|
|
|
$fks = sql_read(
|
|
"SELECT COLUMN_NAME, REFERENCED_TABLE_SCHEMA, REFERENCED_TABLE_NAME, " .
|
|
"REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE " .
|
|
"WHERE TABLE_SCHEMA = '$dbName' AND TABLE_NAME = '$tblName' " .
|
|
"AND REFERENCED_TABLE_NAME IS NOT NULL"
|
|
);
|
|
|
|
if (empty($fks)) {
|
|
return $rows; // no foreign keys
|
|
}
|
|
|
|
foreach ($rows as &$row) {
|
|
foreach ($fks as $fk) {
|
|
$col = $fk['COLUMN_NAME'];
|
|
if (!isset($row[$col])) continue;
|
|
|
|
$val = $row[$col];
|
|
if ($val === null) {
|
|
$row[$col . '_ref'] = null;
|
|
continue;
|
|
}
|
|
|
|
$refTable = $fk['REFERENCED_TABLE_SCHEMA'] . '.' . $fk['REFERENCED_TABLE_NAME'];
|
|
$refCol = $fk['REFERENCED_COLUMN_NAME'];
|
|
$condition = is_numeric($val)
|
|
? "$refCol = $val"
|
|
: "$refCol = '" . str_replace("'", "''", $val) . "'";
|
|
$refRow = sql_read("SELECT * FROM $refTable WHERE $condition LIMIT 1");
|
|
$row[$col . '_ref'] = $refRow[0] ?? null;
|
|
}
|
|
}
|
|
unset($row);
|
|
|
|
return $rows;
|
|
}
|
|
|