3 include_once(dirname(__FILE__) . "/sqlconf.php");
4 require_once(dirname(__FILE__) . "/adodb/adodb.inc.php");
5 require_once(dirname(__FILE__) . "/adodb/drivers/adodb-mysql.inc.php");
7 include_once(dirname(__FILE__) . "/log.inc");
9 class ADODB_mysql_log extends ADODB_mysql
11 function Execute($sql,$inputarr=false)
13 $retval= parent::Execute($sql,$inputarr);
14 // Kevin Yeh(kevin.y@integralemr.com)
15 // Stash the insert ID into lastidado so it doesn't get clobbered when
16 // we insert into the audit log
17 $GLOBALS['lastidado']=$this->Insert_ID();
18 $outcome= ($retval === false) ? false : true;
19 auditSQLEvent($sql,$outcome);
23 // Kevin Yeh(kevin.y@integralemr.com)
24 // Need to override this method to prevent infinite recursion with execute
25 // when trying to retrieve the last insert id.
28 $rs=$this->ExecuteNoLog("SELECT LAST_INSERT_ID()");
29 $ret=reset($rs->fields);
34 function ExecuteNoLog($sql,$inputarr=false)
36 return parent::Execute($sql,$inputarr);
39 if (!defined('ADODB_FETCH_ASSOC')) define('ADODB_FETCH_ASSOC', 2);
40 $database = NewADOConnection("mysql_log"); // Use the subclassed driver which logs execute events
42 $database->PConnect($host, $login, $pass, $dbase);
43 $GLOBALS['adodb']['db'] = $database;
44 $GLOBALS['dbh'] = $database->_connectionID;
46 // Modified 5/2009 by BM for UTF-8 project ---------
47 if (!$disable_utf8_flag) {
48 $success_flag = $database->Execute("SET NAMES 'utf8'");
50 error_log("PHP custom error: from openemr library/sql.inc - Unable to set up UTF8 encoding with mysql database: ".$database->ErrorMsg(), 0);
54 // set up associations in adodb calls (not sure why above define
55 // command does not work)
56 $GLOBALS['adodb']['db']->SetFetchMode(ADODB_FETCH_ASSOC);
58 //fmg: This makes the login screen informative when no connection can be made
59 if (!$GLOBALS['dbh']) {
60 //try to be more helpful
61 if ($host == "localhost") {
62 echo "Check that mysqld is running.<p>";
64 echo "Check that you can ping the server '$host'.<p>";
66 HelpfulDie("Could not connect to server!", mysql_error($GLOBALS['dbh']));
71 // Function that will allow use of the adodb binding
72 // feature to prevent sql-injection. Will continue to
73 // be compatible with previous function calls that do
75 // If use adodb binding, then will return a recordset object.
76 // If do not use binding, then will return a resource object.
77 // The sqlFetchArray() function should be used to
78 // utilize the return object (it will accept both recordset
79 // and resource objects).
80 function sqlStatement($statement, $binds=NULL )
82 if (is_array($binds)) {
83 // Use adodb Execute with binding and return a recordset.
84 // Note that the auditSQLEvent function is embedded
85 // in the adodb Execute command.
86 $recordset = $GLOBALS['adodb']['db']->Execute( $statement, $binds );
87 if ($recordset === FALSE) {
88 HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
93 // Use mysql_query and return a resource.
94 $resource = mysql_query($statement, $GLOBALS['dbh']);
95 if ($resource === FALSE) {
96 auditSQLEvent($statement, FALSE);
97 HelpfulDie("query failed: $statement", mysql_error($GLOBALS['dbh']));
99 auditSQLEvent($statement, TRUE);
104 // Function that will allow use of the adodb binding
105 // feature to prevent sql-injection.
106 // It will act upon the object returned from the
107 // sqlStatement() function (and sqlQ() function).
108 // It will automatically figure out if the input
109 // object is a recordset or a resource.
110 function sqlFetchArray($r)
112 if (!is_resource($r)) {
113 //treat as an adodb recordset
118 //ensure it's an object (ie. is set)
121 return $r->FetchRow();
124 //treat as a mysql_query resource
127 return mysql_fetch_array($r, MYSQL_ASSOC);
131 // Function that will allow use of the adodb binding
132 // feature to prevent sql-injection.
133 // This function is specialized for insert functions
134 // and will return the last id generated from the
136 function sqlInsert($statement, $binds=array())
138 //Run a adodb execute
139 // Note the auditSQLEvent function is embedded in the
140 // adodb Execute function.
141 $recordset = $GLOBALS['adodb']['db']->Execute($statement, $binds);
142 if ($recordset === FALSE) {
143 HelpfulDie("insert failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
145 // Return the correct last id generated using function
146 // that is safe with the audit engine.
147 return getSqlLastID();
150 // Function that will allow use of the adodb binding
151 // feature to prevent sql-injection.
152 // This function is specialized for simply returning
153 // the first row of a query as an associative array.
154 // The $status_or_binds parameter can do following:
155 // FALSE or an array() - Run adodb Execute with binding,
157 // TRUE - run mysql_query for a specific case in the audit engine
158 // (library/log.inc) to skip auditing and reporting if the query
160 function sqlQuery($statement, $status_or_binds=FALSE)
162 if ((is_array($status_or_binds)) || ($status_or_binds === FALSE)) {
163 // run the adodb Execute function
164 // Note the auditSQLEvent function is embedded in the
165 // adodb Execute function.
166 if (is_array($status_or_binds)) {
167 $recordset = $GLOBALS['adodb']['db']->Execute( $statement, $status_or_binds );
170 $recordset = $GLOBALS['adodb']['db']->Execute( $statement );
172 if ($recordset === FALSE) {
173 HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
177 $rez = $recordset->FetchRow();
183 // run mysql_query to bypass the audit engine if error
185 $resource = mysql_query($statement, $GLOBALS['dbh']);
186 auditSQLEvent($statement, TRUE);
187 //$rez = @mysql_fetch_array($query, MYSQL_ASSOC);
188 $rez = @mysql_fetch_array($resource, MYSQL_ASSOC); //Replace $query with $resource to calculate correct checksum
195 // ViSolve: Create a seperate function for audit log calls.
196 /* Kevin Yeh (kevin.y@integralemr.com) 12/13/2011
197 * This allows us to insert a row in the log table that doesn't log its own actions.
199 function sqlInsertClean_audit($statement)
202 $ret = $GLOBALS['adodb']['db']->ExecuteNoLog($statement);
203 if ($ret === FALSE) {
204 HelpfulDie("insert failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
208 // Function that will safely return the last
209 // ID inserted, and accounts for
211 function getSqlLastID() {
212 if ($GLOBALS['lastidado'] >0) {
213 return $GLOBALS['lastidado'];
216 return $GLOBALS['adodb']['db']->Insert_ID();
220 // Function that will return an array listing
221 // of columns that exist in a table.
222 function sqlListFields($table) {
223 $sql = "SHOW COLUMNS FROM ". mysql_real_escape_string($table);
224 $resource = sqlQ($sql);
225 $field_list = array();
226 while($row = mysql_fetch_array($resource)) {
227 $field_list[] = $row['Field'];
232 // Function that will allow use of the adodb binding
233 // feature to prevent sql-injection.
234 // It will act upon the object returned from the
235 // sqlStatement() function (and sqlQ() function).
236 // It will automatically figure out if the input
237 // object is a recordset or a resource.
238 // It will return the number of rows.
239 function sqlNumRows($r)
241 if (!is_resource($r)) {
242 //treat as an adodb recordset
243 return $r->RecordCount();
246 //treat as a mysql_query resource
247 return mysql_num_rows($r);
251 //fmg: Much more helpful that way...
252 function HelpfulDie ($statement, $sqlerr='')
254 echo "<p><p><font color='red'>ERROR:</font> $statement<p>";
256 echo "Error: <font color='red'>$sqlerr</font><p>";
261 function generate_id () {
262 $database = $GLOBALS['adodb']['db'];
263 return $database->GenID("sequences");
266 // Does not fully incorporate the audit engine, so
267 // recommend not using this function (if bind is set,
268 // then will get logged, however if bind is not set,
269 // then will not get logged).
270 // Function that will allow use of the adodb binding
271 // feature to prevent sql-injection.
272 // Function that will allow use of the adodb binding
273 // feature to prevent sql-injection. Will continue to
274 // be compatible with previous function calls that do
276 // If use adodb binding, then will return a recordset object.
277 // If do not use binding, then will return a resource object.
278 // The sqlFetchArray() function should be used to
279 // utilize the return object (it will accept both recordset
280 // and resource objects).
281 function sqlQ($statement, $binds=NULL )
283 if (is_array($binds)) {
284 $recordset = $GLOBALS['adodb']['db']->Execute( $statement, $binds ) or
285 HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
289 $resource = mysql_query($statement, $GLOBALS['dbh']) or
290 HelpfulDie("query failed: $statement", mysql_error($GLOBALS['dbh']));
295 // DEPRECATED FUNCTION
297 // Function that will allow use of the adodb binding
298 // feature to prevent sql-injection.
299 // A simple wrapper for the sqlInsert() function.
300 function idSqlStatement($statement , $binds=NULL )
302 return sqlInsert($statement, $binds);
305 // DEPRECATED FUNCTION
307 // Function that will allow use of the adodb binding
308 // feature to prevent sql-injection.
309 // A simple wrapper for the sqlInsert() function.
310 function sqlInsertClean($statement, $binds=NULL )
312 return sqlInsert($statement, $binds);
315 // DEPRECATED FUNCTION
316 function sqlConnect($login,$pass,$dbase,$host,$port = '3306')
318 $GLOBALS['dbh'] = $database->_connectionID;
319 return $GLOBALS['dbh'];
322 // DEPRECATED FUNCTION
324 // Function to close the connection. PHP does
325 // this automatically, so not needed.
328 //----------Close our mysql connection
329 $closed = $GLOBALS['adodb']['db']->close or
330 HelpfulDie("could not disconnect from mysql server link", $GLOBALS['adodb']['db']->ErrorMsg());
334 // DEPRECATED FUNCTION
336 return $GLOBALS['adodb']['db'];