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] : '' ); |
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 |
$db_host = ( $regs[4] ? $regs[4] : '' ); |
91 |
$is_persistent = ( $regs[1] ? 1 : 0 ); |
92 |
//echo "Connecting: [ $db_name ][ $dbh_user ][ $db_host ]<br>\n"; |
93 |
} |
94 |
|
95 |
$this->is_persistent = $is_persistent; |
96 |
|
97 |
//Select the database type. |
98 |
if( eregi( "^mysql$", $db_type )){ |
99 |
$db_type = 'mysql'; //perl string for this database. |
100 |
} else if( eregi( "informix", $db_type )){ |
101 |
$db_type = 'Informix'; |
102 |
} else if( eregi( "sybase", $db_type )){ |
103 |
$db_type = 'sybase'; |
104 |
} else if (eregi( "Pg", $db_type )){ |
105 |
$db_type = 'Pg'; |
106 |
} |
107 |
$this->db_type = $db_type; |
108 |
|
109 |
|
110 |
//Include the file only if we have not already read it. |
111 |
if( ! $GLOBALS['classDBD'.$db_type."_read"] ){ |
112 |
include( 'class.DBD::'.$db_type ); |
113 |
} |
114 |
|
115 |
//Check to see if we could read it... |
116 |
if( ! $GLOBALS['classDBD'.$db_type."_read"] ){ |
117 |
echo "Error: No DBD for $db_type.<br>\n"; |
118 |
$this->errstr = "Error: No DBD driver for '$db_type'."; |
119 |
return; |
120 |
} |
121 |
|
122 |
//Track the connections. The reason for doing this is that |
123 |
// if the user tries (at least with MySQL_* functions) to |
124 |
// connecto to a mysql database with the same arguments |
125 |
// then mysql_connect will return the same connection handle. |
126 |
// This is a problem when the user tries to select two different |
127 |
// MySQL databases using the same host, user, and password. |
128 |
//$GLOBALS[classDBI_connectiontrack] = array( ); |
129 |
if( $GLOBALS[classDBI_connectiontrack] |
130 |
[$db_type][$db_host][$db_user][$db_passwd] |
131 |
&& |
132 |
$GLOBALS[classDBI_connectiontrack] |
133 |
[$db_type][$db_host][$db_user][$db_passwd] != $db_name ){ |
134 |
echo "<B>DBI Warning:</B> You are trying to connect to two different ", |
135 |
$db_type," databases with the same host, user, and password. ", |
136 |
"This will probably give you unexpected results. ", |
137 |
"Expect problems.", |
138 |
"<br>\n"; |
139 |
} |
140 |
|
141 |
$DBD_class = 'DBD_'.$db_type; |
142 |
$this->DBD = new $DBD_class; |
143 |
|
144 |
//Originally, I was going to have the sub class set the variables |
145 |
// in this class but when you do something like $class1 = $class2, |
146 |
// PHP makes a copy of the class so changes to class2 will not |
147 |
// be shown in class1. For this reason, functions will need to be |
148 |
// fully parameterized and the value of DBD->errstr will have to be |
149 |
// copied after the call. |
150 |
|
151 |
//Note that the arg list for the DBD connect is different than that |
152 |
// of this connect. |
153 |
$conn = $this->DBD->DBD_connect( $db_name, $db_host, |
154 |
$db_user, $db_passwd, |
155 |
$this->is_persistent ); |
156 |
|
157 |
if( !$conn ){ |
158 |
$this->errstr = $this->DBD->errstr; |
159 |
return; |
160 |
} |
161 |
|
162 |
$GLOBALS[classDBI_connectiontrack] |
163 |
[$db_type][$db_host][$db_user][$db_passwd] = $db_name; |
164 |
|
165 |
$this->dbh = $conn; |
166 |
return( $this ); |
167 |
}//end connect function |
168 |
|
169 |
|
170 |
function disconnect( ){ |
171 |
if( $this->DBD ){ |
172 |
$this->DBD->disconnect( ); |
173 |
} |
174 |
}//end disconnect function |
175 |
|
176 |
|
177 |
function exit_on_fail( $yesno = '' ){ |
178 |
//Should the program stop if a query fails? |
179 |
// This is partially implemented. |
180 |
if( $yesno != '' ){ |
181 |
$this->DBD->exit_on_fail = $yesno; |
182 |
} |
183 |
return( $this->DBD->exit_on_fail ); |
184 |
} |
185 |
|
186 |
|
187 |
function prepare( $query ){ |
188 |
//Does nothing but save the query. Be sure we call the |
189 |
// prepare of the DBD object. Otherwise |
190 |
// we get conflicts if we try to have more than one |
191 |
// database handle. |
192 |
if( ! $this->dbh ){ return; } |
193 |
$sth = $this->DBD->prepare( $query ); |
194 |
$this->errstr = $this->DBD->errstr; |
195 |
return( $sth ); |
196 |
}//end dbh prepare fn |
197 |
|
198 |
|
199 |
//do is a reserved word so I have to name this something else. |
200 |
function dbh_do( $query ){ |
201 |
//run the query and return the number of affected rows. |
202 |
$rows = $this->DBD->dbh_do( $query ); |
203 |
$this->errstr = $this->DBD->errstr; |
204 |
if( $rows == 0 ){ $rows = '0E0'; } |
205 |
return( $rows ); |
206 |
}//end fn do |
207 |
|
208 |
|
209 |
function insert_id( ){ |
210 |
//Get the last serial number from an insert. |
211 |
return( $this->DBD->insert_id( )); |
212 |
}//end fn insert_id |
213 |
|
214 |
function quote( $string ){ |
215 |
return( $this->DBD->quote( $string )); |
216 |
} |
217 |
|
218 |
}//end DBI class |
219 |
|
220 |
//Print out warnings if the user gets duplicate connections. |
221 |
$GLOBALS[classDBI_connectiontrack] = array( ); |