audit lastiddao fixes
[openemr.git] / library / sql.inc
blob61812069236befb007a0be455486468b5653ee0d
1 <?php
3 include_once(dirname(__FILE__) . "/sqlconf.php");
4 require_once(dirname(__FILE__) . "/adodb/adodb.inc.php");
5 include_once(dirname(__FILE__) . "/log.inc");
7 if (!defined('ADODB_FETCH_ASSOC')) define('ADODB_FETCH_ASSOC', 2);
8 $database = NewADOConnection("mysql");
9 $database->PConnect($host, $login, $pass, $dbase);
11 // Modified 5/2009 by BM for UTF-8 project ---------
12 if (!$disable_utf8_flag) {
13  $success_flag = $database->Execute("SET NAMES 'utf8'");
14   if (!$success_flag) {
15    error_log("PHP custom error: from openemr library/sql.inc  - Unable to set up UTF8 encoding with mysql database: ".$database->ErrorMsg(), 0);
16   }
18 // -------------------------------------------------
20 $GLOBALS['adodb']['db'] = $database;
21 $GLOBALS['dbh'] = $database->_connectionID;
23 // set up associations in adodb calls (not sure why above define
24 //  command does not work)
25 $GLOBALS['adodb']['db']->SetFetchMode(ADODB_FETCH_ASSOC);
27 //fmg: This makes the login screen informative when no connection can be made
28 if (!$GLOBALS['dbh']) {
29   //try to be more helpful
30   if ($host == "localhost") {
31     echo "Check that mysqld is running.<p>";
32   } else {
33     echo "Check that you can ping the server '$host'.<p>";
34   }//if local
35   HelpfulDie("Could not connect to server!", mysql_error($GLOBALS['dbh']));
36   exit;
37 }//if no connection
39 // Function that will allow use of the adodb binding
40 //   feature to prevent sql-injection. Will continue to
41 //   be compatible with previous function calls that do
42 //   not use binding.
43 // If use adodb binding, then will return a recordset object.
44 // If do not use binding, then will return a resource object.
45 // The sqlFetchArray() function should be used to
46 //   utilize the return object (it will accept both recordset
47 //   and resource objects).
48 function sqlStatement($statement, $binds=NULL )
50   if (is_array($binds)) {
51     // Use adodb Execute with binding and return a recordset.
52     //   Note that the auditSQLEvent function is embedded
53     //    in the adodb Execute command.
54     $recordset = $GLOBALS['adodb']['db']->Execute( $statement, $binds );
55     if ($recordset === FALSE) {
56       HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
57     }
58     return $recordset;
59   }
60   else {
61     // Use mysql_query and return a resource.
62     $resource = mysql_query($statement, $GLOBALS['dbh']);
63     if ($resource === FALSE) {
64       auditSQLEvent($statement, FALSE);
65       HelpfulDie("query failed: $statement", mysql_error($GLOBALS['dbh']));
66     }
67     auditSQLEvent($statement, TRUE);
68     return $resource;
69   }
72 // Function that will allow use of the adodb binding
73 //   feature to prevent sql-injection.
74 // It will act upon the object returned from the 
75 //   sqlStatement() function (and sqlQ() function).
76 // It will automatically figure out if the input
77 //   object is a recordset or a resource.
78 function sqlFetchArray($r)
80   if (!is_resource($r)) {
81     //treat as an adodb recordset
82     if ($r === FALSE)
83       return false;
84     if ($r->EOF)
85       return false;
86     //ensure it's an object (ie. is set)
87     if (!is_object($r))
88       return false;
89     return $r->FetchRow();
90   }
91   else {
92     //treat as a mysql_query resource
93     if ($r == FALSE)
94       return false;
95     return mysql_fetch_array($r, MYSQL_ASSOC);
96   }
99 // Function that will allow use of the adodb binding
100 //   feature to prevent sql-injection.
101 // This function is specialized for insert functions
102 //   and will return the last id generated from the
103 //   insert.
104 function sqlInsert($statement, $binds=array())
106   //Run a adodb execute
107   // Note the auditSQLEvent function is embedded in the
108   //   adodb Execute function.
109   $recordset = $GLOBALS['adodb']['db']->Execute($statement, $binds);
110   if ($recordset === FALSE) {
111     HelpfulDie("insert failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
112   }
113   // Return the correct last id generated using function
114   //   that is safe with the audit engine.
115   return getSqlLastID();
118 // Function that will allow use of the adodb binding
119 //   feature to prevent sql-injection.
120 // This function is specialized for simply returning
121 //   the first row of a query as an associative array.
122 // The $status_or_binds parameter can do following:
123 //   FALSE or an array() - Run adodb Execute with binding,
124 //     if applicable.
125 //   TRUE - run mysql_query for a specific case in the audit engine
126 //     (library/log.inc) to skip auditing and reporting if the query
127 //     does not work.
128 function sqlQuery($statement, $status_or_binds=FALSE)
130   if ((is_array($status_or_binds)) || ($status_or_binds === FALSE)) {
131     // run the adodb Execute function
132     //   Note the auditSQLEvent function is embedded in the
133     //     adodb Execute function.
134     if (is_array($status_or_binds)) {
135       $recordset = $GLOBALS['adodb']['db']->Execute( $statement, $status_or_binds );
136     }
137     else {
138       $recordset = $GLOBALS['adodb']['db']->Execute( $statement );
139     }
140     if ($recordset === FALSE) {
141       HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
142     }
143     if ($recordset->EOF)
144      return FALSE;
145     $rez = $recordset->FetchRow();
146     if ($rez == FALSE)
147       return FALSE;
148     return $rez;
149   }
150   else {
151     // run mysql_query to bypass the audit engine if error
152     //   in query.
153     $resource = mysql_query($statement, $GLOBALS['dbh']);
154     auditSQLEvent($statement, TRUE);
155    //$rez = @mysql_fetch_array($query, MYSQL_ASSOC);
156     $rez = @mysql_fetch_array($resource, MYSQL_ASSOC); //Replace $query with $resource to calculate correct checksum
157     if ($rez == FALSE)
158       return FALSE;
159     return $rez;
160   }
163 // ViSolve: Create a seperate function for audit log calls.
164 // The audit calls are handled through separate function.
165 // Before the audit calls are executed, the mysql_insert_id() is stored in GLOBALS['lastiddao']
166 //  and used in the relevant places, i.e in the mysql adodb driver files..
167 // Note:  This GLOBAL variable gets its value only when the audit is enabled.
168 function sqlInsertClean_audit($statement)
170   // Get the mysql_insert_id() before the execution of the log statement
171  //$lastid=mysql_insert_id($GLOBALS['dbh']);
172  //$GLOBALS['lastidado']=$lastid;
173 // when audit is enabled and $GLOBALS['lastidado'] is not set, then set the GLOBALS irrespective of dbh and adodb handlers.
175 // ViCarePlus :: Fix for Audit logging Issue :: Sep 24,2010 .
176 // Issue:: The LAST_INSERT_ID of the audit log table overrides the value in the $GLOBALS['lastidado'] variable. 
177 //         In a single transaction, when more than one query is being executed, this issue happens. 
178 // Fix: This code has been taken care by the function auditSQLEvent() in log.inc file
179 //  if ($GLOBALS['lastidado'] > 0)
180 //      { /* do nothing */ }
181 //        else {
182 //                 $lastid=mysql_insert_id($GLOBALS['dbh']);
183 //                 $GLOBALS['lastidado']=$lastid;
184 //        }
186   //----------run a mysql insert, return the last id generated
187   $ret = mysql_query($statement, $GLOBALS['dbh']);
188   if ($ret === FALSE) {
189     HelpfulDie("insert failed: $statement", mysql_error($GLOBALS['dbh']));
190   }
193 // Function that will safely return the last
194 //   ID inserted, and accounts for
195 //   the audit engine.
196 function getSqlLastID() {
197   if ($GLOBALS['lastidado'] >0) {
198     return $GLOBALS['lastidado'];
199   }
200   else {
201     return $GLOBALS['adodb']['db']->Insert_ID();
202   }
205 // Function that will return an array listing
206 //   of columns that exist in a table.
207 function sqlListFields($table) {
208   $sql = "SHOW COLUMNS FROM ". mysql_real_escape_string($table);
209   $resource = sqlQ($sql);
210   $field_list = array();
211   while($row = mysql_fetch_array($resource)) {
212     $field_list[] = $row['Field'];
213   }
214   return $field_list;
217 // Function that will allow use of the adodb binding
218 //   feature to prevent sql-injection.
219 // It will act upon the object returned from the
220 //   sqlStatement() function (and sqlQ() function).
221 // It will automatically figure out if the input
222 //   object is a recordset or a resource.
223 // It will return the number of rows.
224 function sqlNumRows($r)
226   if (!is_resource($r)) {
227     //treat as an adodb recordset
228     return $r->RecordCount();
229   }
230   else {
231     //treat as a mysql_query resource
232     return mysql_num_rows($r);
233   }
236 //fmg: Much more helpful that way...
237 function HelpfulDie ($statement, $sqlerr='')
239   echo "<p><p><font color='red'>ERROR:</font> $statement<p>";
240   if ($sqlerr) {
241     echo "Error: <font color='red'>$sqlerr</font><p>";
242   }//if error
243   exit;
246 function generate_id () {
247   $database = $GLOBALS['adodb']['db'];
248   return $database->GenID("sequences");
251 // Does not fully incorporate the audit engine, so
252 //   recommend not using this function (if bind is set,
253 //   then will get logged, however if bind is not set,
254 //   then will not get logged).  
255 // Function that will allow use of the adodb binding
256 //   feature to prevent sql-injection.
257 // Function that will allow use of the adodb binding
258 //   feature to prevent sql-injection. Will continue to
259 //   be compatible with previous function calls that do
260 //   not use binding.
261 // If use adodb binding, then will return a recordset object.
262 // If do not use binding, then will return a resource object.
263 // The sqlFetchArray() function should be used to
264 //   utilize the return object (it will accept both recordset
265 //   and resource objects).
266 function sqlQ($statement, $binds=NULL )
268   if (is_array($binds)) {
269     $recordset = $GLOBALS['adodb']['db']->Execute( $statement, $binds ) or
270       HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
271     return $recordset;
272   }
273   else {
274     $resource = mysql_query($statement, $GLOBALS['dbh']) or
275       HelpfulDie("query failed: $statement", mysql_error($GLOBALS['dbh']));
276     return $resource;
277   }
280 // DEPRECATED FUNCTION
282 // Function that will allow use of the adodb binding
283 //   feature to prevent sql-injection.
284 // A simple wrapper for the sqlInsert() function.
285 function idSqlStatement($statement , $binds=NULL )
287   return sqlInsert($statement, $binds);
290 // DEPRECATED FUNCTION
292 // Function that will allow use of the adodb binding
293 //   feature to prevent sql-injection.
294 // A simple wrapper for the sqlInsert() function.
295 function sqlInsertClean($statement, $binds=NULL )
297   return sqlInsert($statement, $binds);
300 // DEPRECATED FUNCTION
301 function sqlConnect($login,$pass,$dbase,$host,$port = '3306')
303   $GLOBALS['dbh'] = $database->_connectionID;
304   return $GLOBALS['dbh'];
307 // DEPRECATED FUNCTION
309 // Function to close the connection. PHP does
310 //   this automatically, so not needed.
311 function sqlClose()
313   //----------Close our mysql connection
314   $closed = $GLOBALS['adodb']['db']->close or
315     HelpfulDie("could not disconnect from mysql server link", $GLOBALS['adodb']['db']->ErrorMsg());
316   return $closed;
319 // DEPRECATED FUNCTION
320 function get_db() {
321   return $GLOBALS['adodb']['db'];
324 // DEPRECATED FUNCTION
325 function sqlLastID() {
326   return mysql_insert_id($GLOBALS['dbh']);