Ticket #715: db_update_util.php

File db_update_util.php, 4.1 KB (added by Eric Myers, 16 years ago)

Modified do_query() to keep a log of applied database updates.

Line 
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";
23if( !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//
36function 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//
46function description($text){
47    global $update_desc;
48    $update_desc = $text;
49}
50function 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//
59function 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?>