Standardized the diagnosis code searching in the Rules admin GUI
[openemr.git] / library / sql.inc
blobe1e7e00d1137ba4b7bfd815c5f544978f6195aec
1 <?php
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)
12         {
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);
20             return $retval;
21         }
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.
26         function _insertid()
27         {
28             $rs=$this->ExecuteNoLog("SELECT LAST_INSERT_ID()");
29             $ret=reset($rs->fields);
30             $rs->close();
31             return $ret;
32         }
34         function ExecuteNoLog($sql,$inputarr=false)
35         {
36             return parent::Execute($sql,$inputarr);
37         }
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'");
49   if (!$success_flag) {
50    error_log("PHP custom error: from openemr library/sql.inc  - Unable to set up UTF8 encoding with mysql database: ".$database->ErrorMsg(), 0);
51   }
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>";
63   } else {
64     echo "Check that you can ping the server '$host'.<p>";
65   }//if local
66   HelpfulDie("Could not connect to server!", mysql_error($GLOBALS['dbh']));
67   exit;
68 }//if no connection
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
74 //   not use binding.
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());
89     }
90     return $recordset;
91   }
92   else {
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']));
98     }
99     auditSQLEvent($statement, TRUE, $binds);
100     return $resource;
101   }
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());
115     }
116     return $recordset;
117   }
118   else {
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']));
123     }
124     return $resource;
125   }
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
138     if ($r === FALSE)
139       return false;
140     if ($r->EOF)
141       return false;
142     //ensure it's an object (ie. is set)
143     if (!is_object($r))
144       return false;
145     return $r->FetchRow();
146   }
147   else {
148     //treat as a mysql_query resource
149     if ($r == FALSE)
150       return false;
151     return mysql_fetch_array($r, MYSQL_ASSOC);
152   }
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
159 //   insert.
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());
168   }
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,
180 //     if applicable.
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
183 //     does not work.
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 );
192     }
193     else {
194       $recordset = $GLOBALS['adodb']['db']->Execute( $statement );
195     }
196     if ($recordset === FALSE) {
197       HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
198     }
199     if ($recordset->EOF)
200      return FALSE;
201     $rez = $recordset->FetchRow();
202     if ($rez == FALSE)
203       return FALSE;
204     return $rez;
205   }
206   else {
207     // run mysql_query to bypass the audit engine if error
208     //   in query.
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
213     if ($rez == FALSE)
214       return FALSE;
215     return $rez;
216   }
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.
222  */
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());
229   }
232 // Function that will safely return the last
233 //   ID inserted, and accounts for
234 //   the audit engine.
235 function getSqlLastID() {
236   if ($GLOBALS['lastidado'] >0) {
237     return $GLOBALS['lastidado'];
238   }
239   else {
240     return $GLOBALS['adodb']['db']->Insert_ID();
241   }
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'];
252   }
253   return $field_list;
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();
268   }
269   else {
270     //treat as a mysql_query resource
271     return mysql_num_rows($r);
272   }
275 //fmg: Much more helpful that way...
276 function HelpfulDie ($statement, $sqlerr='')
278   echo "<p><p><font color='red'>ERROR:</font> $statement<p>";
279   if ($sqlerr) {
280     echo "Error: <font color='red'>$sqlerr</font><p>";
281   }//if error
282   exit;
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
299 //   not use binding.
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());
310     return $recordset;
311   }
312   else {
313     $resource = mysql_query($statement, $GLOBALS['dbh']) or
314       HelpfulDie("query failed: $statement", mysql_error($GLOBALS['dbh']));
315     return $resource;
316   }
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.
350 function sqlClose()
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());
355   return $closed;
358 // DEPRECATED FUNCTION
359 function get_db() {
360   return $GLOBALS['adodb']['db'];