1 |
<?PHP // -*-Mode: C++;-*- |
2 |
/* |
3 |
Bill Adams (bill<at>evil<dot>inetarena<dot>com) |
4 |
DBI.php3 -- A perl DBI like class. |
5 |
See: http://evil.inetarena.com/php/DBI.php for more info. |
6 |
|
7 |
Licence: LGPL (http://www.gnu.org/). |
8 |
|
9 |
This software is provided "AS IS" with no warrenty either implicit, |
10 |
explicit or otherwise. Use at your own risk. |
11 |
|
12 |
... |
13 |
|
14 |
Notes: |
15 |
|
16 |
o 'do' is called 'dbh_do' in this because 'do' is a reserved word. |
17 |
|
18 |
o Not every function is implemented. |
19 |
|
20 |
|
21 |
28 Mar 2000 baa Fixed the sth function to call the right constructor so |
22 |
. one can have multiple database connections. |
23 |
|
24 |
*/ |
25 |
|
26 |
class DBI { |
27 |
|
28 |
var $db_type = ''; |
29 |
var $dbh = ''; |
30 |
var $DBD; |
31 |
var $errorstr = ''; |
32 |
var $is_persistent; |
33 |
var $exit_on_fail = 0; |
34 |
|
35 |
function parse_dbi_string( $dbi_connect_str ){ |
36 |
|
37 |
if( ereg( "(p)?dbi:(.+):(.+)[;:](host=)?(.+)", $dbi_connect_str, $regs ) || |
38 |
ereg( "(p)?dbi:(.+):(.+)", $dbi_connect_str, $regs )){ |
39 |
$dbi[db_type] = $regs[2]; |
40 |
$dbi[db_name] = $regs[3]; |
41 |
$dbi[db_host] = ( $regs[5] ? $regs[5] : 'localhost' ); |
42 |
$dbi[is_persistent] = ( $regs[1] ? 1 : 0 ); |
43 |
//echo "Connecting: [ ", |
44 |
//$dbi[db_type],"][", |
45 |
//$dbi[db_name],"][", |
46 |
//$dbi[dbh_user], "][", |
47 |
//$dbi[db_host], "]<br>\n"; |
48 |
return( $dbi ); |
49 |
|
50 |
} else { |
51 |
echo "DBI: Invalid Connect String '$dbi_connect_str'.<br>\n"; |
52 |
return; |
53 |
} |
54 |
|
55 |
} |
56 |
|
57 |
function DBI( $dbi_connect_str, $db_user = '', $db_passwd = '' ){ |
58 |
|
59 |
$this->is_persistent = 0; |
60 |
$dbi_info = $this->parse_dbi_string( $dbi_connect_str ); |
61 |
if( ! $dbi_info ){ return; } |
62 |
$this->is_persistent = $db_info[is_persistent]; |
63 |
|
64 |
|
65 |
if( $dbi_info[db_type] != '' ){ |
66 |
$this->connect( $dbi_info[db_type], $dbi_info[db_name], |
67 |
$dbi_info[db_host], |
68 |
$db_user, $db_passwd, |
69 |
$dbi_info[is_persistent] ); |
70 |
} |
71 |
return $this; |
72 |
//Arrg! There is no way to return a false object on the new. |
73 |
// so that means the user will have to check $this->dbh to see if |
74 |
// the connection was made. |
75 |
}//end constructor |
76 |
|
77 |
|
78 |
function connect( $db_type, $db_name, $db_host = '', |
79 |
$db_user = '', $db_passwd = '', |
80 |
$is_persistent = 0 ){ |
81 |
|
82 |
//See if we need to parse the db_type... |
83 |
if( ereg( "(p)?dbi:(.+):(.+)[;:](.+)", $db_type, $regs ) || |
84 |
ereg( "(p)?dbi:(.+):(.+)[;:]?(.+)?", $db_type, $regs )){ |
85 |
$db_user = $db_name; |
86 |
$db_passwd = $db_host; |
87 |
$db_type = $regs[2]; |
88 |
$db_name = $regs[3]; |
89 |
$db_host = ( $regs[4] ? $regs[4] : 'localhost' ); |
90 |
$is_persistent = ( $regs[1] ? 1 : 0 ); |
91 |
//echo "Connecting: [ $db_name ][ $dbh_user ][ $db_host ]<br>\n"; |
92 |
} |
93 |
|
94 |
$this->is_persistent = $is_persistent; |
95 |
|
96 |
//Select the database type. |
97 |
if( eregi( "^mysql$", $db_type )){ |
98 |
$db_type = 'mysql'; //perl string for this database. |
99 |
} else if( eregi( "informix", $db_type )){ |
100 |
$db_type = 'Informix'; |
101 |
} else if( eregi( "sybase", $db_type )){ |
102 |
$db_type = 'sybase'; |
103 |
} else if (eregi( "Pg", $db_type )){ |
104 |
$db_type = 'Pg'; |
105 |
} |
106 |
$this->db_type = $db_type; |
107 |
|
108 |
|
109 |
//Include the file only if we have not already read it. |
110 |
if( ! $GLOBALS['classDBD'.$db_type."_read"] ){ |
111 |
include( 'class.DBD::'.$db_type ); |
112 |
} |
113 |
|
114 |
//Check to see if we could read it... |
115 |
if( ! $GLOBALS['classDBD'.$db_type."_read"] ){ |
116 |
echo "Error: No DBD for $db_type.<br>\n"; |
117 |
$this->errstr = "Error: No DBD driver for '$db_type'."; |
118 |
return; |
119 |
} |
120 |
|
121 |
//Track the connections. The reason for doing this is that |
122 |
// if the user tries (at least with MySQL_* functions) to |
123 |
// connecto to a mysql database with the same arguments |
124 |
// then mysql_connect will return the same connection handle. |
125 |
// This is a problem when the user tries to select two different |
126 |
// MySQL databases using the same host, user, and password. |
127 |
//$GLOBALS[classDBI_connectiontrack] = array( ); |
128 |
if( $GLOBALS[classDBI_connectiontrack] |
129 |
[$db_type][$db_host][$db_user][$db_passwd] |
130 |
&& |
131 |
$GLOBALS[classDBI_connectiontrack] |
132 |
[$db_type][$db_host][$db_user][$db_passwd] != $db_name ){ |
133 |
echo "<B>DBI Warning:</B> You are trying to connect to two different ", |
134 |
$db_type," databases with the same host, user, and password. ", |
135 |
"This will probably give you unexpected results. ", |
136 |
"Expect problems.", |
137 |
"<br>\n"; |
138 |
} |
139 |
|
140 |
$DBD_class = 'DBD_'.$db_type; |
141 |
$this->DBD = new $DBD_class; |
142 |
|
143 |
//Originally, I was going to have the sub class set the variables |
144 |
// in this class but when you do something like $class1 = $class2, |
145 |
// PHP makes a copy of the class so changes to class2 will not |
146 |
// be shown in class1. For this reason, functions will need to be |
147 |
// fully parameterized and the value of DBD->errstr will have to be |
148 |
// copied after the call. |
149 |
|
150 |
//Note that the arg list for the DBD connect is different than that |
151 |
// of this connect. |
152 |
$conn = $this->DBD->DBD_connect( $db_name, $db_host, |
153 |
$db_user, $db_passwd, |
154 |
$this->is_persistent ); |
155 |
|
156 |
if( !$conn ){ |
157 |
$this->errstr = $this->DBD->errstr; |
158 |
return; |
159 |
} |
160 |
|
161 |
$GLOBALS[classDBI_connectiontrack] |
162 |
[$db_type][$db_host][$db_user][$db_passwd] = $db_name; |
163 |
|
164 |
$this->dbh = $conn; |
165 |
return( $this ); |
166 |
}//end connect function |
167 |
|
168 |
|
169 |
function disconnect( ){ |
170 |
if( $this->DBD ){ |
171 |
$this->DBD->disconnect( ); |
172 |
} |
173 |
}//end disconnect function |
174 |
|
175 |
|
176 |
function exit_on_fail( $yesno = '' ){ |
177 |
//Should the program stop if a query fails? |
178 |
// This is partially implemented. |
179 |
if( $yesno != '' ){ |
180 |
$this->DBD->exit_on_fail = $yesno; |
181 |
} |
182 |
return( $this->DBD->exit_on_fail ); |
183 |
} |
184 |
|
185 |
|
186 |
function prepare( $query ){ |
187 |
//Does nothing but save the query. Be sure we call the |
188 |
// prepare of the DBD object. Otherwise |
189 |
// we get conflicts if we try to have more than one |
190 |
// database handle. |
191 |
if( ! $this->dbh ){ return; } |
192 |
$sth = $this->DBD->prepare( $query ); |
193 |
$this->errstr = $this->DBD->errstr; |
194 |
return( $sth ); |
195 |
}//end dbh prepare fn |
196 |
|
197 |
|
198 |
//do is a reserved word so I have to name this something else. |
199 |
function dbh_do( $query ){ |
200 |
//run the query and return the number of affected rows. |
201 |
$rows = $this->DBD->dbh_do( $query ); |
202 |
$this->errstr = $this->DBD->errstr; |
203 |
if( $rows == 0 ){ $rows = '0E0'; } |
204 |
return( $rows ); |
205 |
}//end fn do |
206 |
|
207 |
|
208 |
function insert_id( ){ |
209 |
//Get the last serial number from an insert. |
210 |
return( $this->DBD->insert_id( )); |
211 |
}//end fn insert_id |
212 |
|
213 |
function quote( $string ){ |
214 |
return( $this->DBD->quote( $string )); |
215 |
} |
216 |
|
217 |
}//end DBI class |
218 |
|
219 |
//Print out warnings if the user gets duplicate connections. |
220 |
$GLOBALS[classDBI_connectiontrack] = array( ); |