| 1 |
<?php |
|---|
| 2 |
/*********************************************************************** |
|---|
| 3 |
* Utilities to make it easier to do a database update |
|---|
| 4 |
* |
|---|
| 5 |
* do_query() writes to a log file when an update is applied, |
|---|
| 6 |
* and refuses to apply an update listed in the log file. |
|---|
| 7 |
* Supports multiple database queries per update function. |
|---|
| 8 |
* |
|---|
| 9 |
* For backward compatibility you can put the names of updates you have |
|---|
| 10 |
* applied by hand in the log file, without the timestamp. |
|---|
| 11 |
* |
|---|
| 12 |
* Eric Myers <myers@spy-hill.net> - 5 August 2008 |
|---|
| 13 |
* @(#) $Id: $ |
|---|
| 14 |
\***********************************************************************/ |
|---|
| 15 |
|
|---|
| 16 |
// Updates are recorded in the log file once they are successfully applied. |
|---|
| 17 |
// We only need to locate the log file once. |
|---|
| 18 |
// |
|---|
| 19 |
$config_xml = get_config(); |
|---|
| 20 |
$config_vars = parse_element($config_xml,"<config>"); |
|---|
| 21 |
$log_dir = trim(parse_element($config_vars,"<log_dir>")); |
|---|
| 22 |
#echo "Log directory: $log_dir \n"; |
|---|
| 23 |
if( !file_exists($log_dir) || !is_dir($log_dir) ){ |
|---|
| 24 |
die("Log file directory '$log_dir' cannot be found.\n"); |
|---|
| 25 |
} |
|---|
| 26 |
$log_file = $log_dir ."/db_update.log"; |
|---|
| 27 |
#echo "Log file: $log_file \n"; |
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 |
$prev_caller=""; // name of previously attempted update |
|---|
| 31 |
$update_number=0; // to count multiple queries per update |
|---|
| 32 |
|
|---|
| 33 |
|
|---|
| 34 |
// This function finds the name of the function which is applying the update. |
|---|
| 35 |
// |
|---|
| 36 |
function called_by($n=2){ |
|---|
| 37 |
$x = debug_backtrace(); // requires PHP 4.3.0 or newer |
|---|
| 38 |
$y = $x[$n]; |
|---|
| 39 |
return $y['function']; |
|---|
| 40 |
} |
|---|
| 41 |
|
|---|
| 42 |
|
|---|
| 43 |
// Set descriptive text for the update. |
|---|
| 44 |
// This is optional, but better than comments since it goes to log. |
|---|
| 45 |
// |
|---|
| 46 |
function description($text){ |
|---|
| 47 |
global $update_desc; |
|---|
| 48 |
$update_desc = $text; |
|---|
| 49 |
} |
|---|
| 50 |
function describe($text){// alternate name |
|---|
| 51 |
description($text); |
|---|
| 52 |
} |
|---|
| 53 |
|
|---|
| 54 |
|
|---|
| 55 |
// Execute an SQL query to do the update. |
|---|
| 56 |
// First check the log to see if we already did it. |
|---|
| 57 |
// If not, do the update, and log it. |
|---|
| 58 |
// |
|---|
| 59 |
function do_query($query) { |
|---|
| 60 |
global $prev_caller, $update_number; |
|---|
| 61 |
global $update_desc; // descriptive text for the update |
|---|
| 62 |
global $log_file; |
|---|
| 63 |
|
|---|
| 64 |
$caller = called_by(); // name of the update function which called us |
|---|
| 65 |
|
|---|
| 66 |
if( $caller == $prev_caller ){ // another query for same update? |
|---|
| 67 |
$update_number++; |
|---|
| 68 |
} |
|---|
| 69 |
else { |
|---|
| 70 |
$prev_caller = $caller; |
|---|
| 71 |
$update_number = 1; |
|---|
| 72 |
} |
|---|
| 73 |
$query_tag = "$caller($update_number)"; |
|---|
| 74 |
|
|---|
| 75 |
// Unix name of person who applied the update, for the log |
|---|
| 76 |
// |
|---|
| 77 |
$userinfo = posix_getpwuid(posix_getuid()); |
|---|
| 78 |
$username = $userinfo['name']; |
|---|
| 79 |
|
|---|
| 80 |
// Has this update already been applied? |
|---|
| 81 |
// |
|---|
| 82 |
if( file_exists($log_file) ){ |
|---|
| 83 |
if( $fh = fopen($log_file,'r') ){ |
|---|
| 84 |
while( $line = fgets($fh) ){ |
|---|
| 85 |
$n = strpos($line, $query_tag); |
|---|
| 86 |
if( $n !== FALSE && $n < 60) {// ignores description text |
|---|
| 87 |
echo "$query_tag has ALREADY been applied. \n"; |
|---|
| 88 |
fclose($fh); |
|---|
| 89 |
return FALSE; |
|---|
| 90 |
} |
|---|
| 91 |
// Allow for just update name by itself to block update |
|---|
| 92 |
$n = strpos($line, $caller); |
|---|
| 93 |
if( ($n !== FALSE) && ($n < 25)){// only name by itself, no timestamp |
|---|
| 94 |
if($update_number==1){// but only flag the first query |
|---|
| 95 |
echo "$caller has ALREADY been applied. \n"; |
|---|
| 96 |
} |
|---|
| 97 |
fclose($fh); |
|---|
| 98 |
return FALSE; |
|---|
| 99 |
} |
|---|
| 100 |
} |
|---|
| 101 |
} |
|---|
| 102 |
} |
|---|
| 103 |
|
|---|
| 104 |
// Try to apply the update. If successful, write it to the log file. |
|---|
| 105 |
// |
|---|
| 106 |
$result = mysql_query($query); |
|---|
| 107 |
#$result = true; // Debugging |
|---|
| 108 |
if( !$result ){// TODO: better test for SQL errors? |
|---|
| 109 |
die("$query_tag failed! \n".mysql_error()); |
|---|
| 110 |
} |
|---|
| 111 |
else { |
|---|
| 112 |
echo "$query_tag applied. \n"; |
|---|
| 113 |
if( !$fd=fopen($log_file, 'a') ){ |
|---|
| 114 |
die("CANNOT WRITE $query_tag TO LOG FILE $log_file\n"); |
|---|
| 115 |
} |
|---|
| 116 |
else { |
|---|
| 117 |
fwrite($fd, gmdate('c'). " $query_tag "); |
|---|
| 118 |
if( $username ) fwrite($fd, "by $username "); |
|---|
| 119 |
fwrite($fd,"$update_desc\n"); |
|---|
| 120 |
fclose($fd); |
|---|
| 121 |
$update_desc=""; // clear the description text for next item |
|---|
| 122 |
} |
|---|
| 123 |
} |
|---|
| 124 |
} |
|---|
| 125 |
|
|---|
| 126 |
$cvs_version_tracker[]= //Generated automatically - do not edit |
|---|
| 127 |
"\$Id: $"; |
|---|
| 128 |
?> |
|---|