Subversion Repositories php_library

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
38 rodolico 1
<?php
2
   require "DBDatabase.class.php";
3
 
4
   class DBQuery {
5
      public $query;          // the query to be processed
6
      public $rowsAffected;   // the number of rows 1) affectd by an insert, update or delete or 2) returned by a select
7
      public $lastInsertKey;  // the value of the last row inserted (mysql only)
8
      public $returnData;     // an array that contains the data retrieved by a query (select only)
9
      public $columnMetaData; // an array that contains the meta data from the query
10
      public $useAssociativeArray;   // if true, $returnData is an array of associative array, with the column names being the key fields
11
      public $showErrors;     // if true, will return errors to STDOUT
12
      public $error;          // set to last error returned
13
      public $logFile;        // if set to a fully qualified file, will write queries to that file
14
      public $auditTable;     // if set to a table name, all queries are written to it
15
 
16
      public function __construct( $query ) {
17
         $this->query = $query;
18
         $this->rowsAffected = 0;
19
         $this->lastInsertKey = '';
20
         $this->returnData = array();
21
         $this->columnMetaData = array();
22
         $this->useAssociativeArray = true;
23
         $this->showErrors = true;
24
         $this->error = '';
25
      }
26
 
27
 
28
      /* 
29
         function actually executes the query, populating the members with the results
30
         returns true if no errors, false if errors (see $this->error for code)
31
      */
32
      function run {
33
         // print "<pre>In Query database\n---------------------\n$query\n---------------------\n</pre>";
34
         if ($logFile) printLog( $query );
35
         if ($auditTable) audit( $query );
36
         $result = @mysql_query($this->query);
37
         if( mysql_errno() ) {
38
            $this->error = 'MYSQL ERROR #'.mysql_errno().' : <small>' . mysql_error(). "</small><br><VAR>$query</VAR>";
39
            if ( $this->showErrors ) echo($this->error);
40
            return false;
41
         } // if
42
         if( preg_match ( '/^\s*select/i', $this->query ) ) { // this is a select statement
43
            $this->rowsAffected = @mysql_num_rows($result);
44
            $this->columnMetaData = array();
45
            while ($i++ < mysql_num_fields( $result )) {
46
               $meta = mysql_fetch_field ( $result );
47
               //objectDebugScreen($meta);
48
               $this->columnMetaData[] = array('name' => $meta->name, 'length' => $meta->max_length, 'numeric' => $meta->numeric, 'type' => $meta->type );
49
            }
50
            if( ! $this->rowsAffected ) return;
51
            $returnData = array();
52
            for( $i = 0; $i < $count; $i++ ) {
53
               $returnData[] = $useAssociativeArray ? mysql_fetch_assoc($result) : mysql_fetch_row($result);
54
            }
55
            mysql_free_result($result);
56
         } else { // not a select statement
57
            $this->rowsAffected = mysql_affected_rows();
58
            $this->lastInsertKey = mysql_insert_id();
59
         }
60
         return true;
61
      } // function run
62
 
63
      // function returns the first column of the first row of data returned from query
64
      // or null no value returned
65
      function getOneDBValue( $sql ) {
66
         $save = $this->useAssociativeArray;
67
         $useAssociativeArray = false;
68
         $this->run();
69
         $useAssociativeArray = $save;
70
         return $this->rowsAffected ? $this->returnData[0][0] : null;
71
      }
72
 
73
   function countNumberOfRows ( $sql ) {
74
         $save = $this->useAssociativeArray;
75
         $useAssociativeArray = false;
76
         $this->run();
77
         $useAssociativeArray = $save;
78
         return $this->rowsAffected;
79
   }
80
 
81
      function makeWhereClause ($conditions, $joinedBy = 'and') {
82
         $joinedBy = " $joinedBy "; // make sure there are spaces around it
83
         $whereClause = ' where ' . implode ( $joinedBy, $conditions );
84
         return $whereClause;
85
      }
86
 
87
      /* 
88
         values is an associative array of name/value pairs
89
         function will replace all items of the form <$name> with its values (the less than and greater than symbols around the key)
90
      */
91
      function insertValuesIntoQuery( $values ) {
92
         foreach ( $values as $name => $value ) {
93
            $this->query = search_replace_string($this->query, "<$name>", $value );
94
         }
95
      }
96
 
97
      /*
98
         Function takes an SQL statement and converts it to an HTML table.
99
         Return Value: HTML table representation of the query
100
         Parameters:
101
            $sql    A valid SQL query to run
102
            $format An optional array of format strings (suitable for printf) for each column (empty strings ignored)
103
            $makeTableDef  If True, the resulting HTML has the <table></table> tags; otherwise starts with header
104
            $append   Arbitrary string that is appended as a single column to each row
105
 
106
            NOTE ON $append
107
               $append may optionally contain variables of the form %colname%, which will be replaced
108
               with values from the current row. $colname is taken from the META data from the query, thus
109
               the query select foo from bar would have a meta of header of foo for column 0.
110
               $append is searched for strings of form %foo% in that case, and the current value of column
111
               foo replaces the tag %foo%.
112
               %foo% is ignored if foo is not a valid column name in a query.
113
               thus, a query such as select zip,city,state from zip_codes and a string of Hello %city% I'm glad
114
               you are in %State% will not replace the second as State is not a column of this query (it is case
115
               sensitive). Also, beware of items like select zip,concat(state,', ', city) from zip_codes. It is
116
               much better to rewrite that as select zip,concat(state,', ', city) mytown from zip_codes.
117
 
118
               If you don't know what all that means, get a book on SQL
119
      */
120
      function queryToTable ( $format = '', $makeTableDef = true, $append='' ) {
121
         //print "\n\n$this->query\n\n";
122
         $tdTextDefinition = '<td valign=' . HTML_QUOTE_CHAR . 'top' . HTML_QUOTE_CHAR . '>';
123
         $tdNumberDefinition = '<td valign=' . HTML_QUOTE_CHAR .'top' . HTML_QUOTE_CHAR . 'align=' . HTML_QUOTE_CHAR . 'right' . HTML_QUOTE_CHAR . '>';
124
         $html = '';
125
         $save = $this->useAssociativeArray;
126
         $useAssociativeArray = false; // temporarily turn off associative arrays
127
         $this->run();
128
         if ( $this->rowsAffected ) { // we returned at least one row
129
            $meta = $result['meta'];
130
            // Build the searchFor array for $append
131
            $searchFor = array();
132
            foreach ( $meta as $field ) {
133
               $searchFor[] = '%' . $field['name'] . '%';
134
            }
135
            $info = $result['data'];
136
            unset ($result);
137
            /* special condition where only one row is returned. In that case, $info is not an array
138
            of associations, but a simple association. In this case, we need to convert it
139
            */
140
            if (count($info[0]) == 1) { // convert from association to single row array of associations
141
               $temp = array();
142
               foreach ($info as $column => $value) {
143
                  $temp[0][$column] = $value;
144
               } // foreach
145
               $info = $temp;
146
            }
147
            if (count($format) > 0 ) { // we have some formats, so let's do it the hard, slow way
148
               for ( $row = 0; $row < count($info); $row++) {
149
                  $rows[$row] = '';
150
                  for ( $column = 0; $column < count($info[$row]); $column++  ) {
151
                     $rows[$row] .= strlen($format[$column]) && isset($info[$row][$column])> 0 ?
152
                                    ( $tdNumberDefinition . sprintf($format[$column],$info[$row][$column]) . '</td>')
153
                                    : ($tdTextDefinition . $info[$row][$column] . '</td>');
154
                  } // for $column
155
                  /*
156
                     let's append some stuff to the row if it exists.
157
                     We will take the array of SearchFor containing the column names
158
                     and the array of values from this row, then look for matches and replace them
159
                     with the correct values. Note, the column names in $append should have percent
160
                     signs appended and prepended, thus a column name of joe would be %joe% in %append
161
                  */
162
                  if (strlen($append) > 0) { // let's append some stuff to the row
163
                     $rows[$row] .= $tdTextDefinition . str_replace ( $searchFor, $info[$row], $append ) . '</td>';
164
                  }
165
               } // for $row
166
            } else { // no formatting, so we just slam the stuff together
167
               for ( $row = 0; $row < count($info); $row++) {
168
                  $currentValue = $tdTextDefinition . implode( '</td>' . $tdTextDefinition, $info[$row]) . '</td>';
169
                  if (strlen($append) > 0) { // see explaination in if part of this structure
170
                     $currentValue  .= $tdTextDefinition . str_replace ( $searchFor, $info[$row], $append ) . '</td>';
171
                  }
172
                  $rows[] = $currentValue;
173
               }
174
            }
175
            // ok, let's get the field headers from the table
176
            $html .= '<tr>';
177
            foreach ( $meta as $field ) {
178
               $html .= '<th>' . $field['name'] . '</th>';
179
            }
180
            $html .= '</tr>';
181
            // we now have all the info, so let's make it into a table
182
            $html .= '<tr>' . implode('</tr><tr>', $rows ) . '</tr>';
183
 
184
            if ( $makeTableDef ) { // they want the <table> def, so let's give it to them
185
               $html = '<table border=' . HTML_QUOTE_CHAR . '1' . HTML_QUOTE_CHAR . '>' . $html . '</table>';
186
            } // if ( $makeTableDef
187
         } // if ( $info = queryDatabase($this->query,0) )
188
         // print '<pre>';  print_r ($info); print '</pre>';
189
         $useAssociativeArray = $save;
190
         return $html;
191
      }
192
 
193
      /*
194
         function executes a query, then returns an array containing only the values of the first
195
         field in the return as the keys to an associative array. NOTE: any duplicates will be
196
         discarded. This is useful when you simply want to know if a value exists, ie if you
197
         are building an html select from a query, and a separate query needs to hold the
198
         values that are currently selected
199
      */
200
 
201
      function valuesToKeys () {
202
         $returnValue = array();
203
         $save = $this->useAssociativeArray;
204
         $useAssociativeArray = false; // temporarily turn off associative arrays
205
         $this->run();
206
         if ( $this->rowsAffected ) { // we returned at least one row
207
            foreach ( $info as $key => $value ) { // only thing I know to do is iterate
208
               $returnValue[$this->returnData[0]] = true;
209
            }
210
         } // if
211
         $useAssociativeArray = $save;
212
         return $returnValue;
213
      }
214
 
215
      /* this function will take the result of an SQL query that returns at least two columns.
216
         The first column becomes the keys in an associative array, and the second column
217
         becomes the value.
218
 
219
         Note, because it is an associative array, duplicates of the first column will only contain
220
         the last value.
221
      */
222
 
223
      function ColumnColumnArray () {
224
         $returnValue = array();
225
         $save = $this->useAssociativeArray;
226
         $useAssociativeArray = false; // temporarily turn off associative arrays
227
         $this->run();
228
         if ( $this->rowsAffected ) { // we returned at least one row
229
            foreach ( $info as $key => $value ) { // only thing I know to do is iterate
230
               $returnValue[$this->returnData[0]] = $this->returnData[1];
231
            }
232
         } // if
233
         $useAssociativeArray = $save;
234
         return $returnValue;
235
      }
236
 
237
 
238
      /* the first returned column becomes the value, the second becomes the display element
239
         if $selectedFieldsQuery is begins with 'select', items matching that query will be selected
240
         if  $selectedFieldsQuery is any other value, it is assumed to be the value of the first column
241
 
242
      */
243
      function htmlSelect ( $selectedFieldsQuery = '' ) {
244
         $html = '';
245
         $selectedFields = array();
246
         if strlen( $selectedFieldsQuery ) {
247
            if (  preg_match ( '/^\s*select/i', $selectedFieldsQuery ) ) { // They passed in a query
248
               if (strlen($selectedFieldsQuery) ) {
249
                  $subSet = new DBQuery($selectedFieldsQuery);
250
                  $subSet->run();
251
                  $selectedFields = $subSet->sqlValuesToKeys();
252
               }
253
            } else { // assume the passed in a value
254
               $selectedFields[$selectedFieldsQuery] = 1;
255
            }
256
         }
257
         $save = $this->useAssociativeArray;
258
         $useAssociativeArray = false; // temporarily turn off associative arrays
259
         $this->run();
260
         if ( $this->rowsAffected ) { // we returned at least one row
261
            foreach ($this->returnData as $rowNumber => $value )
262
               $html .= '<option value="' . $value[0] . '"';
263
               if ( $selectedFields[$value[0]] ) {
264
                  $html .= ' selected';
265
               }
266
               $html .= '>' . $value[1] . '</option>';
267
            }
268
         }
269
         $useAssociativeArray = $save;
270
         return $html;
271
      }
272
 
273
      /* function will take a query and turn it into a series of check boxes. It must contain
274
         two columns, with the first becoming the the name of the checkbox
275
         and the second becoming the displayed value. an optional third column will be used
276
         to match if the $checkedValuesQuery is used.
277
         if $checkedValuesQuery is not empty, it will be run to see what boxes need to be
278
         checked by being compared to the third column of the $sql query.
279
         $htmlBefore will be placed before each check box, and $htmlAfter will be placed after
280
         each checkbox.
281
 
282
         if $tableColumns is set to a number, the checkboxes will be embedded in a group of
283
         <tr></tr>, each containing table columns of $tableColumns width. In this case, $htmlBefore
284
         will have <td> prepended and $htmlAfter will have </td> appended, meaning any passed
285
         values will be INSIDE of the td. NOTE: the <table></table> tags are NOT put in.
286
 
287
         NOTE: currently, using the table stuff will leave a dangling row with 0 elements if
288
         the number of elements equal the number of columns.
289
      */
290
 
291
      function htmlCheckBoxes ( $checkedValuesQuery = '', $htmlBefore = '', $htmlAfter = '', $table_columns='' ) {
292
         $html = '';
293
         if ($table_columns) {
294
            $htmlBefore = '<td>' . $htmlBefore;
295
            $htmlAfter .= '</td>';
296
            $html .= '<tr>';
297
         }
298
         $numColumns = 0;
299
         $checkBoxes = queryDatabaseExtended( $sql,0 );
300
         $selectedFields = array();
301
         if (strlen($checkedValuesQuery) ) {
302
            $subSet = new DBQuery($selectedFieldsQuery);
303
            $subSet->run();
304
            $selectedFields = $subSet->sqlValuesToKeys();
305
         }
306
         $save = $this->useAssociativeArray;
307
         $useAssociativeArray = false; // temporarily turn off associative arrays
308
         foreach ($this->returnData as $row => $values) {
309
            if ($table_columns && ++$numColumns == $table_columns) {
310
               $html .= '</tr><tr>';
311
               $numColumns = 0;
312
            }
313
            //objectDebugScreen($row);
314
            $html .= $htmlBefore . '<input type="checkbox" name="' . $values[0] . '"';
315
            if ( $selectedFields[$values[2]] ) {
316
               $html .= ' checked';
317
            }
318
            $html .= '>' . $values[1] . $htmlAfter;
319
            //<INPUT type="checkbox" checked name="temp">
320
         } // foreach
321
         $html .= '</tr>';
322
         $useAssociativeArray = $save;
323
         return $html;
324
      }
325
 
326
   /*   
327
      function CSV ( $sql ) {
328
         $rows = array();
329
         $CSV = '';
330
         $info = array();
331
         if ( $result = queryDatabaseExtended($sql,0) ) {
332
            $meta = $result['meta'];
333
            //objectDebugScreen($result);
334
            $info = $result['data'];
335
            unset ($result);
336
            $headers = array();
337
            foreach ( $meta as $field ) {
338
               $headers[] = $field['name'];
339
            } // foreach
340
            $rows[] = implode("\t", $headers);
341
            // special condition where only one row is returned. In that case, $info is not an array
342
            //  of associations, but a simple association. In this case, we need to convert it
343
 
344
            if (count($info[0]) == 1) { // convert from association to single row array of associations
345
               $temp = array();
346
               foreach ($info as $column => $value) {
347
                  $temp[0][$column] = $value;
348
               } // foreach
349
               $info = $temp;
350
            }
351
            for ( $row = 0; $row < count($info); $row++) {
352
               $rows[] = implode("\t", $info[$row]);
353
            }
354
            // we now have all the info, so let's make it into a table
355
            $CSV .= implode("\n", $rows );
356
         } // if ( $info = queryDatabase($sql,0) )
357
         // print '<pre>';  print_r ($info); print '</pre>';
358
         return $CSV;
359
      }
360
 
361
   */
362
 
363
   } // class DBQuery
364
 
365
?>