timeline: updated to latest live versions after crux.nu server rebuild
* rss generator: minor updates for XML output formatting and PHP log warnings * cacher: replaced flyspray task caching with gitea issues caching
This commit is contained in:
parent
ce1382a482
commit
e78df72edd
@ -1,23 +1,24 @@
|
||||
<?php
|
||||
# global config
|
||||
$limit = 40;
|
||||
$dbfile = '/home/crux/timeline/timeline.db';
|
||||
|
||||
if (isset($_GET['limit'])) {
|
||||
# global config
|
||||
$limit = 40;
|
||||
$dbfile = '/home/crux/timeline/timeline.db';
|
||||
|
||||
if (isset($_GET['limit'])) {
|
||||
$limit = intval($_GET['limit']);
|
||||
}
|
||||
}
|
||||
|
||||
$dbc = new SQLite3($dbfile);
|
||||
$dbc = new SQLite3($dbfile);
|
||||
|
||||
$sql = "SELECT DISTINCT * FROM events ORDER BY event_tstamp DESC LIMIT $limit";
|
||||
$res = $dbc->query($sql);
|
||||
if (!$res) die ("Query error: $last_cached_sql");
|
||||
$sql = "SELECT DISTINCT * FROM events ORDER BY event_tstamp DESC LIMIT $limit";
|
||||
$res = $dbc->query($sql);
|
||||
if (!$res) die ("Query error: $last_cached_sql");
|
||||
|
||||
header ("Content-type: text/xml");
|
||||
$timeline = '<?xml version="1.0"?>'."\n";
|
||||
$timeline .= '<rss version="2.0"><channel><title>CRUX timeline</title><description>CRUX: timeline (commits, tasks, wiki edits)</description><link>http://crux.nu</link>';
|
||||
header ("Content-type: text/xml");
|
||||
$timeline = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<rss version=\"2.0\">\n\n<channel>\n";
|
||||
$timeline .= " <title>CRUX timeline</title>\n <description>CRUX: timeline (commits, issues, wiki edits)</description>\n <link>http://crux.nu</link>\n";
|
||||
|
||||
while ($evt =& $res->fetchArray()) {
|
||||
while ($evt = $res->fetchArray()) {
|
||||
#print_r($evt); # uncomment for debug
|
||||
|
||||
$url = $evt['event_url'];
|
||||
@ -46,14 +47,9 @@ while ($evt =& $res->fetchArray()) {
|
||||
$titlenotes = ": ".substr($notes,0,40)."...";
|
||||
}
|
||||
}
|
||||
$timeline .= "
|
||||
<item>
|
||||
<title>$description$titlenotes</title>
|
||||
<description>$notes</description>
|
||||
<link>$url</link>
|
||||
</item>\n";
|
||||
}
|
||||
$timeline .= "</channel></rss>\n";
|
||||
echo $timeline;
|
||||
$timeline .= " <item>\n <title>$description$titlenotes</title>\n <description>$notes</description>\n <link>$url</link>\n </item>\n";
|
||||
}
|
||||
$timeline .= "</channel>\n</rss>\n";
|
||||
echo $timeline;
|
||||
|
||||
?>
|
||||
|
@ -99,7 +99,7 @@ function GetEvents() {
|
||||
}
|
||||
|
||||
$timeline .= "</table>\n";
|
||||
$timeline .= '<br><form method="post" action="pmwiki.php?n=Main.Timeline">Show the latest <input size="4" type="text" name="days" value="'.$days.'"> days <input type="submit" value="Show"></form>'."\n";
|
||||
$timeline .= '<br><form method="post" action="Timeline">Show the latest <input size="4" type="text" name="days" value="'.$days.'"> days <input type="submit" value="Show"></form>'."\n";
|
||||
|
||||
return $timeline;
|
||||
}
|
||||
|
@ -1,27 +1,35 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
/* Caches the timeline events into a sqlite db */
|
||||
/*
|
||||
Caches timeline events from git, gitea issues, and pmwiki
|
||||
into a SQLite3 database.
|
||||
*/
|
||||
|
||||
/**************** Configuration ***********************/
|
||||
|
||||
// database config lives in another file:
|
||||
require_once("tlcacher_config.php");
|
||||
/* configuration */
|
||||
require_once('tlcacher_config.php');
|
||||
|
||||
// Detailed flyspray task URL
|
||||
$task_url="https://crux.nu/bugs/?do=details&task_id=%s";
|
||||
// server timezone
|
||||
$tz = new DateTimeZone("Europe/Stockholm");
|
||||
|
||||
// Gitweb commit URL
|
||||
$git_url = "https://crux.nu/gitweb/?p=%s.git;a=commitdiff;h=%s";
|
||||
// append ":branch" to the repo name to restrict logs to 'branch'
|
||||
// $git_repos = array("ports/core:3.3", "ports/opt:3.3","ports/xorg:3.3","ports/xfce:3.1","ports/compat-32:3.3","tools/pkgutils","system/iso");
|
||||
$git_repos = array("ports/core:3.7", "ports/opt:3.7","ports/xorg:3.7","ports/compat-32:3.7","tools/pkgutils","system/iso");
|
||||
// $git_root = "/home/crux/scm";
|
||||
$git_root = "/home/git/repositories";
|
||||
// gitea base URL
|
||||
$base_url = "https://git.crux.nu";
|
||||
|
||||
// Map git authors to wiki profiles
|
||||
$git_username_map = array(
|
||||
"Per Lidén" => "PerLiden",
|
||||
// gitea commit base URL
|
||||
$git_url = "{$base_url}/%s/commit/%s";
|
||||
|
||||
|
||||
// git repos for which to cache events
|
||||
// append ":branch" to the repo name to restrict logs to 'branch'
|
||||
$git_repos = array("ports/core:3.7", "ports/opt:3.7", "ports/xorg:3.7", "ports/compat-32:3.7", "tools/pkgutils", "system/iso");
|
||||
|
||||
// path to git repositories on disk
|
||||
$git_root = "/home/gitea/git";
|
||||
|
||||
// Map git authors to wiki profiles
|
||||
$git_username_map = array(
|
||||
"Per Lidén" => "PerLiden",
|
||||
"Matt Housh" => "MattHoush",
|
||||
"Juergen Daubert" => "JuergenDaubert",
|
||||
"Johannes Winkelmann" => "JohannesWinkelmann",
|
||||
@ -29,10 +37,10 @@ $git_username_map = array(
|
||||
"Jason Thomas Dolan" => "JasonThomasDolan",
|
||||
"Jukka Heino" => "JukkaHeino",
|
||||
"Tilman Sauerbeck" => "TilmanSauerbeck",
|
||||
"Simon Gloßner" => "SimonGloßner",
|
||||
"Simon Gloßner" => "SimonGloßner",
|
||||
"Nick Steeves" => "NickSteeves",
|
||||
"Antti Nykänen" => "AnttiNykänen",
|
||||
"Antti Nykanen" => "AnttiNykänen",
|
||||
"Antti Nykänen" => "AnttiNykänen",
|
||||
"Antti Nykanen" => "AnttiNykänen",
|
||||
"Jose V Beneyto" => "JoseVBeneyto",
|
||||
"JoseVBeneyto" => "JoseVBeneyto",
|
||||
"Lucas Hazel" => "LucasHazel",
|
||||
@ -40,44 +48,43 @@ $git_username_map = array(
|
||||
"Fredrik Rinnestam" => "FredrikRinnestam",
|
||||
"Danny Rawlins" => "DannyRawlins",
|
||||
"Tim Biermann" => "TimBiermann",
|
||||
);
|
||||
);
|
||||
|
||||
// Path of the recent changes pmwiki file
|
||||
$wiki_file = '/var/www/htdocs/wiki.d/Site.AllRecentChanges';
|
||||
// Path of the recent changes pmwiki file
|
||||
$wiki_file = '/var/www/pmwiki/wiki.d/Site.AllRecentChanges';
|
||||
|
||||
// Event: cache_id, tstamp, type(icon), date, time, user, url, description, notes
|
||||
$events = array();
|
||||
// Event: cache_id, tstamp, type(icon), date, time, user, url, description, notes
|
||||
$events = array();
|
||||
|
||||
/**************** Last cached events *******************/
|
||||
/**************** Last cached events *******************/
|
||||
|
||||
$dbc = new SQLite3($dbfilec);
|
||||
|
||||
$dbc = new SQLite3($dbfilec);
|
||||
|
||||
print("Fetching last cached flyspray event.");
|
||||
$last_cached_sql = "select cache_id from events where event_type like 'task%' order by cache_id desc limit 1";
|
||||
$res = $dbc->query($last_cached_sql);
|
||||
if (!$res) die ("Query error: $last_cached_sql");
|
||||
$row = $res->fetchArray(SQLITE3_ASSOC);
|
||||
if (!$row) {
|
||||
print("Fetching last cached gitea issues event.");
|
||||
$last_cached_sql = "SELECT cache_id FROM events WHERE event_type LIKE 'task%' ORDER BY cache_id DESC LIMIT 1";
|
||||
$res = $dbc->query($last_cached_sql);
|
||||
if (!$res) die ("Query error: $last_cached_sql");
|
||||
$row = $res->fetchArray(SQLITE3_ASSOC);
|
||||
if (!$row) {
|
||||
$last_task = 0;
|
||||
} else {
|
||||
} else {
|
||||
$last_task = $row['cache_id'];
|
||||
}
|
||||
print(" [$last_task]\n");
|
||||
}
|
||||
print(" [$last_task]\n");
|
||||
|
||||
print("Fetching last cached wiki event.");
|
||||
$last_cached_sql = "select cache_id from events where event_type = 'wiki_changed' order by cache_id desc limit 1";
|
||||
$res = $dbc->query($last_cached_sql);
|
||||
if (!$res) die ("Query error: $last_cached_sql");
|
||||
$row = $res->fetchArray(SQLITE3_ASSOC);
|
||||
if (!$row) {
|
||||
print("Fetching last cached wiki event.");
|
||||
$last_cached_sql = "select cache_id from events where event_type = 'wiki_changed' order by cache_id desc limit 1";
|
||||
$res = $dbc->query($last_cached_sql);
|
||||
if (!$res) die ("Query error: $last_cached_sql");
|
||||
$row = $res->fetchArray(SQLITE3_ASSOC);
|
||||
if (!$row) {
|
||||
$last_wiki = 0;
|
||||
} else {
|
||||
} else {
|
||||
$last_wiki = $row['cache_id'];
|
||||
}
|
||||
print(" [$last_wiki]\n");
|
||||
}
|
||||
print(" [$last_wiki]\n");
|
||||
|
||||
function last_cached_git($repo) {
|
||||
function last_cached_git($repo) {
|
||||
global $dbc;
|
||||
$last_cached_sql = "select cache_id from events where event_type='git_commit_$repo' order by event_tstamp desc limit 1";
|
||||
$res = $dbc->query($last_cached_sql);
|
||||
@ -89,84 +96,177 @@ function last_cached_git($repo) {
|
||||
$last_git = $row['cache_id'];
|
||||
}
|
||||
return $last_git;
|
||||
}
|
||||
|
||||
/**************** Flyspray events ***********************/
|
||||
|
||||
print("\nProcessing flyspray events.\n");
|
||||
|
||||
$sql = 'select history_id, event_date, event_type, user_name, flyspray_history.task_id, item_summary, closure_comment, real_name
|
||||
from flyspray_history
|
||||
join flyspray_users on flyspray_users.user_id = flyspray_history.user_id
|
||||
join flyspray_tasks on flyspray_tasks.task_id = flyspray_history.task_id
|
||||
where history_id > ?';
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$last_task]);
|
||||
|
||||
while ($row =& $stmt->fetch()) {
|
||||
$etype = $row['event_type'];
|
||||
$euser = $row['real_name'];
|
||||
$etid = $row['task_id'];
|
||||
$edate = $row['event_date'];
|
||||
$cache_id = $row['history_id'];
|
||||
$description = "";
|
||||
$date = date("Y-m-d", $edate);
|
||||
$time = date("H:i", $edate);
|
||||
$url = sprintf($task_url,$etid);
|
||||
switch ($etype) {
|
||||
case "1": // new task
|
||||
$icon = "task_opened";
|
||||
$description = "New task [[$url|$etid]] opened by $euser";
|
||||
$notes = $row['item_summary'];
|
||||
break;
|
||||
case "2": // task closed
|
||||
$icon = "task_closed";
|
||||
$description = "Task [[$url|$etid]] closed by $euser";
|
||||
if ($row['closure_comment'] != "" && $row['closure_comment'] != 0) { // weird flyspray!
|
||||
$notes = $row['closure_comment'];
|
||||
} else {
|
||||
$notes = "";
|
||||
}
|
||||
|
||||
|
||||
/* gitea issues */
|
||||
|
||||
print("\nProcessing gitea issues events.\n");
|
||||
|
||||
$pgdbc = pg_connect("host={$dbhost} dbname={$dbname} user={$dbuser} password={$dbpass}")
|
||||
or die ("Failed to connect to database: ". pg_last_error());
|
||||
|
||||
// get issues
|
||||
$query = 'SELECT i.id, i.repo_id, r.owner_name, r.name AS repo_name, i.index, i.is_closed, i.name, u.full_name, i.created_unix, i.updated_unix, i.closed_unix FROM issue AS i JOIN "user" AS u ON i.poster_id = u.id JOIN repository AS r ON r.id = i.repo_id WHERE r.is_private = false';
|
||||
$result = pg_query($query)
|
||||
or die ("Failed to execute issues query: " . pg_last_error());
|
||||
|
||||
$events = array();
|
||||
while ($row = pg_fetch_array($result, null, PGSQL_ASSOC)) {
|
||||
|
||||
// construct date/time from unix timestamp
|
||||
$date_im = date_create_immutable_from_format("U", $row['created_unix'], $tz)->setTimezone($tz);
|
||||
$date = date_format($date_im, 'Y-m-d');
|
||||
$time = date_format($date_im, 'H:i');
|
||||
|
||||
// construct issue URL
|
||||
$issue_url = $base_url . "/" . $row['owner_name'] . "/" . $row['repo_name'] . "/issues/" . $row['index'];
|
||||
|
||||
// construct wiki user
|
||||
$user = $row['full_name'];
|
||||
$userlink = $user;
|
||||
if (array_key_exists($user, $git_username_map)) {
|
||||
$wikiname = $git_username_map[$user];
|
||||
$userlink = "[[~{$wikiname}|{$user}]]";
|
||||
}
|
||||
|
||||
// construct the array wanted by the cacher database schema
|
||||
$events[] = array(
|
||||
"cache_id" => $row['created_unix'],
|
||||
"tstamp" => $row['created_unix'],
|
||||
"icon" => "task_opened",
|
||||
"date" => $date,
|
||||
"time" => $time,
|
||||
"user" => $user,
|
||||
"url" => $issue_url,
|
||||
"description" => "New issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]] opened by {$userlink}",
|
||||
"notes" => $row['name']
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// get comments/events (gitea combines them)
|
||||
$query = 'SELECT c.id, c.issue_id, r.owner_name, r.name AS repo_name, i.index, c.type, c.poster_id, u.full_name, c.created_unix, c.updated_unix, (select c.updated_unix = c.created_unix) AS orig, c.content, c.commit_sha FROM comment AS c LEFT JOIN "user" AS u ON u.id = c.poster_id LEFT JOIN issue AS i ON i.id = c.issue_id LEFT JOIN repository AS r ON r.id = i.repo_id WHERE r.is_private = false';
|
||||
$result = pg_query($query)
|
||||
or die ("Failed to execute comments query: " . pg_last_error());
|
||||
|
||||
//$comments = array();
|
||||
while ($row = pg_fetch_array($result, null, PGSQL_ASSOC)) {
|
||||
|
||||
// construct date/time from unix timestamp
|
||||
$date_im = date_create_immutable_from_format("U", $row['created_unix'], $tz)->setTimezone($tz);
|
||||
$date = date_format($date_im, 'Y-m-d');
|
||||
$time = date_format($date_im, 'H:i');
|
||||
|
||||
// construct issue URL
|
||||
$issue_url = $base_url . '/' . $row['owner_name'] . '/' . $row['repo_name'] . '/issues/' . $row['index'];
|
||||
|
||||
// construct wiki user
|
||||
$user = $row['full_name'];
|
||||
$userlink = $user;
|
||||
if (array_key_exists($user, $git_username_map)) {
|
||||
$wikiname = $git_username_map[$user];
|
||||
$userlink = "[[~{$wikiname}|{$user}]]";
|
||||
}
|
||||
|
||||
// determine the message (description) by the comment type (https://github.com/go-gitea/gitea/blob/main/models/issues/comment.go#L60)
|
||||
$desc = '';
|
||||
switch ($row['type']) {
|
||||
case 0: // comment
|
||||
$desc = "{$userlink} commented on issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]]";
|
||||
break;
|
||||
case "3": // task edited : fields, comments, attachments, ownership, related tasks, etc.
|
||||
case "4":
|
||||
case "5":
|
||||
case "6":
|
||||
case "7":
|
||||
case "8":
|
||||
case "14":
|
||||
case "15":
|
||||
case "16":
|
||||
case "22":
|
||||
case "23":
|
||||
case "24":
|
||||
case "25":
|
||||
$icon = "task_changed";
|
||||
$description = "Task [[$url|$etid]] modified by $euser";
|
||||
$notes = "";
|
||||
case 4: // referenced by commit
|
||||
$shortsha = substr($row['commit_sha'], 0, 7);
|
||||
$desc = "{$userlink} referenced issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]] in commit [[ {$base_url}/{$row['owner_name']}/{$row['repo_name']}/commit/{$row['commit_sha']} | {$shortsha} ]]";
|
||||
break;
|
||||
case 7: // labels changed
|
||||
$desc = "{$userlink} changed label(s) on issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]]";
|
||||
break;
|
||||
case 9: // assignees changed
|
||||
$desc = "{$userlink} changed assignee(s) on issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]]";
|
||||
break;
|
||||
case 28: // PR merge
|
||||
$desc = "{$userlink} merged a pull request for issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]]";
|
||||
break;
|
||||
case 2: // close comment
|
||||
case 29: // PR head branch push
|
||||
default:
|
||||
$desc = "{$userlink} modified issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]]";
|
||||
break;
|
||||
}
|
||||
if ($description !== "") {
|
||||
$events[] = array( 'cache_id' => $cache_id, 'tstamp' => $edate, 'icon' => $icon, 'date' => $date,
|
||||
'time' => $time, 'user' => $euser, 'url'=> $url, 'description' => $description, 'notes' => $notes,);
|
||||
|
||||
// construct the array wanted by the cacher database schema
|
||||
$events[] = array(
|
||||
'cache_id' => $row['created_unix'],
|
||||
'tstamp' => $row['created_unix'],
|
||||
'icon' => 'task_changed',
|
||||
'date' => $date,
|
||||
'time' => $time,
|
||||
'user' => $user,
|
||||
'url' => $issue_url,
|
||||
'description' => $desc,
|
||||
'notes' => ''
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/****************** PmWiki events *********************/
|
||||
|
||||
print("\nProcessing wiki events.\n");
|
||||
// get closures (this is just a list of all issues with status closed in non-private repos)
|
||||
$query = 'SELECT c.id, c.type, c.issue_id, i.repo_id, i.index, r.owner_name, r.name as repo_name, u.full_name, i.closed_unix FROM comment AS c JOIN issue AS i ON c.issue_id = i.id JOIN repository AS r ON r.id = i.repo_id JOIN "user" AS u ON c.poster_id = u.id WHERE c.type = 2 AND r.is_private = false';
|
||||
$result = pg_query($query)
|
||||
or die ("Failed to execute closures query: " . pg_last_Error());
|
||||
|
||||
$lines = file($wiki_file);
|
||||
$chline = "";
|
||||
foreach ($lines as $line) {
|
||||
while ($row = pg_fetch_array($result, null, PGSQL_ASSOC)) {
|
||||
|
||||
// construct date/time from unix timestamp
|
||||
$date_im = date_create_immutable_from_format("U", $row['closed_unix'], $tz)->setTimezone($tz);
|
||||
$date = date_format($date_im, 'Y-m-d');
|
||||
$time = date_format($date_im, 'H:i');
|
||||
|
||||
// construct issue URL
|
||||
$issue_url = $base_url . '/' . $row['owner_name'] . '/' . $row['repo_name'] . '/issues/' . $row['index'];
|
||||
|
||||
// construct wiki user
|
||||
$user = $row['full_name'];
|
||||
$userlink = $user;
|
||||
if (array_key_exists($user, $git_username_map)) {
|
||||
$wikiname = $git_username_map[$user];
|
||||
$userlink = "[[~{$wikiname}|{$user}]]";
|
||||
}
|
||||
|
||||
// construct the array wanted by the cacher database schema
|
||||
$events[] = array(
|
||||
'cache_id' => $row['closed_unix'],
|
||||
'tstamp' => $row['closed_unix'],
|
||||
'icon' => 'task_closed',
|
||||
'date' => $date,
|
||||
'time' => $time,
|
||||
'user' => $user,
|
||||
'url' => $issue_url,
|
||||
"description" => "{$userlink} closed issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]]",
|
||||
'notes' => ''
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// cleanup
|
||||
pg_free_result($result);
|
||||
pg_close($pgdbc);
|
||||
|
||||
|
||||
/****************** PmWiki events *********************/
|
||||
|
||||
print("\nProcessing wiki events.\n");
|
||||
|
||||
$lines = file($wiki_file);
|
||||
$chline = "";
|
||||
foreach ($lines as $line) {
|
||||
$line = urldecode($line);
|
||||
if (substr($line,0,5) == "text=") {
|
||||
$chline = substr($line,7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($chline != "") {
|
||||
if ($chline != "") {
|
||||
$wikiedits = explode("*", $chline);
|
||||
$icon = "wiki_changed";
|
||||
foreach ($wikiedits as $ed) {
|
||||
@ -199,13 +299,13 @@ if ($chline != "") {
|
||||
}
|
||||
//print_r($events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************* Git events ***********************/
|
||||
/******************* Git events ***********************/
|
||||
|
||||
print("\nProcessing git events.\n");
|
||||
print("\nProcessing git events.\n");
|
||||
|
||||
foreach ($git_repos as $repo) {
|
||||
foreach ($git_repos as $repo) {
|
||||
$branch = "";
|
||||
if (strpos($repo, ":") !== FALSE) {
|
||||
$tmp = explode(':', $repo);
|
||||
@ -261,11 +361,11 @@ foreach ($git_repos as $repo) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************** Finally, all events *********************/
|
||||
$sql = 'INSERT INTO events VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
foreach ($events as $evt) {
|
||||
/*************** Finally, all events *********************/
|
||||
$sql = 'INSERT INTO events VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
foreach ($events as $evt) {
|
||||
$stmt = $dbc->prepare($sql);
|
||||
$stmt->bindValue(1, $evt['cache_id'], SQLITE3_TEXT);
|
||||
$stmt->bindValue(2, $evt['tstamp'], SQLITE3_INTEGER);
|
||||
@ -278,6 +378,8 @@ foreach ($events as $evt) {
|
||||
$stmt->bindValue(9, $evt['notes'], SQLITE3_TEXT);
|
||||
$res = $stmt->execute();
|
||||
if (!$res) die ("Query error: $sql"); // this is unfortunately not very useful
|
||||
}
|
||||
}
|
||||
|
||||
// vim: set ts=4 et:
|
||||
|
||||
?>
|
||||
|
Loading…
x
Reference in New Issue
Block a user