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,$inputarr);
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, $binds);
97 HelpfulDie("query failed: $statement", mysql_error($GLOBALS['dbh']));
99 auditSQLEvent($statement, TRUE, $binds);
104 // Function that is the equivalent of the above
105 // sqlStatement() function, EXCEPT it skips the
106 // audit engine. This function should only be used
107 // in very special situations.
108 function sqlStatementNoLog($statement, $binds=NULL )
110 if (is_array($binds)) {
111 // Use adodb ExecuteNoLog with binding and return a recordset.
112 $recordset = $GLOBALS['adodb']['db']->ExecuteNoLog( $statement, $binds );
113 if ($recordset === FALSE) {
114 HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
119 // Use mysql_query and return a resource.
120 $resource = mysql_query($statement, $GLOBALS['dbh']);
121 if ($resource === FALSE) {
122 HelpfulDie("query failed: $statement", mysql_error($GLOBALS['dbh']));
128 // Function that will allow use of the adodb binding
129 // feature to prevent sql-injection.
130 // It will act upon the object returned from the
131 // sqlStatement() function (and sqlQ() function).
132 // It will automatically figure out if the input
133 // object is a recordset or a resource.
134 function sqlFetchArray($r)
136 if (!is_resource($r)) {
137 //treat as an adodb recordset
142 //ensure it's an object (ie. is set)
145 return $r->FetchRow();
148 //treat as a mysql_query resource
151 return mysql_fetch_array($r, MYSQL_ASSOC);
155 // Function that will allow use of the adodb binding
156 // feature to prevent sql-injection.
157 // This function is specialized for insert functions
158 // and will return the last id generated from the
160 function sqlInsert($statement, $binds=array())
162 //Run a adodb execute
163 // Note the auditSQLEvent function is embedded in the
164 // adodb Execute function.
165 $recordset = $GLOBALS['adodb']['db']->Execute($statement, $binds);
166 if ($recordset === FALSE) {
167 HelpfulDie("insert failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
169 // Return the correct last id generated using function
170 // that is safe with the audit engine.
171 return getSqlLastID();
174 // Function that will allow use of the adodb binding
175 // feature to prevent sql-injection.
176 // This function is specialized for simply returning
177 // the first row of a query as an associative array.
178 // The $status_or_binds parameter can do following:
179 // FALSE or an array() - Run adodb Execute with binding,
181 // TRUE - run mysql_query for a specific case in the audit engine
182 // (library/log.inc) to skip auditing and reporting if the query
184 function sqlQuery($statement, $status_or_binds=FALSE)
186 if ((is_array($status_or_binds)) || ($status_or_binds === FALSE)) {
187 // run the adodb Execute function
188 // Note the auditSQLEvent function is embedded in the
189 // adodb Execute function.
190 if (is_array($status_or_binds)) {
191 $recordset = $GLOBALS['adodb']['db']->Execute( $statement, $status_or_binds );
194 $recordset = $GLOBALS['adodb']['db']->Execute( $statement );
196 if ($recordset === FALSE) {
197 HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
201 $rez = $recordset->FetchRow();
207 // run mysql_query to bypass the audit engine if error
209 $resource = mysql_query($statement, $GLOBALS['dbh']);
210 auditSQLEvent($statement, TRUE, $status_or_binds);
211 //$rez = @mysql_fetch_array($query, MYSQL_ASSOC);
212 $rez = @mysql_fetch_array($resource, MYSQL_ASSOC); //Replace $query with $resource to calculate correct checksum
219 // ViSolve: Create a seperate function for audit log calls.
220 /* Kevin Yeh (kevin.y@integralemr.com) 12/13/2011
221 * This allows us to insert a row in the log table that doesn't log its own actions.
223 function sqlInsertClean_audit($statement)
226 $ret = $GLOBALS['adodb']['db']->ExecuteNoLog($statement);
227 if ($ret === FALSE) {
228 HelpfulDie("insert failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
232 // Function that will safely return the last
233 // ID inserted, and accounts for
235 function getSqlLastID() {
236 if ($GLOBALS['lastidado'] >0) {
237 return $GLOBALS['lastidado'];
240 return $GLOBALS['adodb']['db']->Insert_ID();
244 // Function that will return an array listing
245 // of columns that exist in a table.
246 function sqlListFields($table) {
247 $sql = "SHOW COLUMNS FROM ". mysql_real_escape_string($table);
248 $resource = sqlQ($sql);
249 $field_list = array();
250 while($row = mysql_fetch_array($resource)) {
251 $field_list[] = $row['Field'];
256 // Function that will allow use of the adodb binding
257 // feature to prevent sql-injection.
258 // It will act upon the object returned from the
259 // sqlStatement() function (and sqlQ() function).
260 // It will automatically figure out if the input
261 // object is a recordset or a resource.
262 // It will return the number of rows.
263 function sqlNumRows($r)
265 if (!is_resource($r)) {
266 //treat as an adodb recordset
267 return $r->RecordCount();
270 //treat as a mysql_query resource
271 return mysql_num_rows($r);
275 //fmg: Much more helpful that way...
276 function HelpfulDie ($statement, $sqlerr='')
278 echo "<p><p><font color='red'>ERROR:</font> $statement<p>";
280 echo "Error: <font color='red'>$sqlerr</font><p>";
285 function generate_id () {
286 $database = $GLOBALS['adodb']['db'];
287 return $database->GenID("sequences");
290 // Does not fully incorporate the audit engine, so
291 // recommend not using this function (if bind is set,
292 // then will get logged, however if bind is not set,
293 // then will not get logged).
294 // Function that will allow use of the adodb binding
295 // feature to prevent sql-injection.
296 // Function that will allow use of the adodb binding
297 // feature to prevent sql-injection. Will continue to
298 // be compatible with previous function calls that do
300 // If use adodb binding, then will return a recordset object.
301 // If do not use binding, then will return a resource object.
302 // The sqlFetchArray() function should be used to
303 // utilize the return object (it will accept both recordset
304 // and resource objects).
305 function sqlQ($statement, $binds=NULL )
307 if (is_array($binds)) {
308 $recordset = $GLOBALS['adodb']['db']->Execute( $statement, $binds ) or
309 HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
313 $resource = mysql_query($statement, $GLOBALS['dbh']) or
314 HelpfulDie("query failed: $statement", mysql_error($GLOBALS['dbh']));
319 // DEPRECATED FUNCTION
321 // Function that will allow use of the adodb binding
322 // feature to prevent sql-injection.
323 // A simple wrapper for the sqlInsert() function.
324 function idSqlStatement($statement , $binds=NULL )
326 return sqlInsert($statement, $binds);
329 // DEPRECATED FUNCTION
331 // Function that will allow use of the adodb binding
332 // feature to prevent sql-injection.
333 // A simple wrapper for the sqlInsert() function.
334 function sqlInsertClean($statement, $binds=NULL )
336 return sqlInsert($statement, $binds);
339 // DEPRECATED FUNCTION
340 function sqlConnect($login,$pass,$dbase,$host,$port = '3306')
342 $GLOBALS['dbh'] = $database->_connectionID;
343 return $GLOBALS['dbh'];
346 // DEPRECATED FUNCTION
348 // Function to close the connection. PHP does
349 // this automatically, so not needed.
352 //----------Close our mysql connection
353 $closed = $GLOBALS['adodb']['db']->close or
354 HelpfulDie("could not disconnect from mysql server link", $GLOBALS['adodb']['db']->ErrorMsg());
358 // DEPRECATED FUNCTION
360 return $GLOBALS['adodb']['db'];