| 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 | ?> |
|---|