Subversion Repositories php_library

Rev

Rev 55 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 rodolico 1
<?php
2
 
3
/*
4
   Copyright 2007
5
   Daily Data, Inc.
6
   All rights reserved
7
   Description:
8
      Library of routines for TimeTracker
9
 
10
   Revision History:
11
   Revision 10 - 20090115 - R. W. Rodolico
12
   Modified editData routine to grab display query from table definition if key field not defined in complex join definition
13
 
14
*/
15
 
58 rodolico 16
   const REVISION = '2.18';
17
   const HTML_QUOTE_CHAR = '"' ;
18
   const CONSTANT_NO_VALUE_DROPDOWN = '--------' ;
1 rodolico 19
 
58 rodolico 20
 
21
   // following field types are numeric (with length)
22
   const NUMERICS = [
23
         'BIT'=> 16,
24
         'TINYINT'=> 1,
25
         'BOOL'=> 1,
26
         'SMALLINT'=> 2,
27
         'MEDIUMINT'=> 9,
28
         'INTEGER'=> 3,
29
         'BIGINT'=> 8,
30
         'SERIAL'=> 8,
31
         'FLOAT'=> 4,
32
         'DOUBLE'=> 5,
33
         'DECIMAL'=> 246,
34
         'NUMERIC'=> 246,
35
         'FIXED'=> 246
36
      ];
37
   // the following are the type names which are dates (with length)
38
   const DATES = [
39
         'DATE'=> 10,
40
         'DATETIME'=> 12,
41
         'TIMESTAMP'=> 7,
42
         'TIME'=> 11,
43
         'YEAR'=> 13
44
      ];
45
 
46
 
1 rodolico 47
   $LOGIN_PAGE = 'login.html';
48
 
49
   function getParameter( $parameterName, $default = '' ) {
50
      if (isset($_POST[$parameterName])) {
51
         return $_POST[$parameterName];
52
      }
53
      if (isset($_GET[$parameterName])) {
54
         return $_GET[$parameterName];
55
      }
56
      return $default;
57
   }
58
 
59
   function printLog ( $string ) {
60
      if ( 0 ) {
61
         $fh = fopen('/tmp/queryDatabaseExtended.sql', 'a');
62
         fwrite($fh, $string . "\n");
63
         fclose($fh);
64
      }
65
   }   
66
 
67
   function whoami () {
68
      $output = '';
69
      $i = queryDatabase("select concat(surname,', ',given_name) name from worker where worker_id = " . $_SESSION['effective_worker_id']);
70
      $output .= $i;
71
      if ( $_SESSION['effective_worker_id'] != $_SESSION['worker_id']) {
72
         $i = queryDatabase("select concat(surname,', ',given_name) name from worker where worker_id = " . $_SESSION['worker_id']);
73
         $output .= " ($i)";
74
      }
75
      return $output;
76
   }
77
 
78
   function logOut() {
79
      unset( $_SESSION['user'] );
80
      redirectPage($LOGIN_PAGE,array('message'=>'Logged Out, please log back in to continue'));
81
   }
82
 
83
   function objectDebugScreen ( $obj ) {
84
      print '<pre>';
85
      print_r ($obj);
86
      print "</pre>\n";
87
   }
88
 
89
 
90
/*   function verifyLogin( $loginID, $password ) {
91
      if ( strlen($loginID) > 10 ) {
92
         $loginID = substr($loginID,1,10);
93
      }
94
 
95
      $sql = "select count(*) numRows, min(worker_id) worker_id from login where username = " .
96
              makeSafeSQLValue($loginID) . ' and pass = md5(' . makeSafeSQLValue($password) . ") and enabled = 'Y'";
97
      $info = queryDatabase( $sql );
98
      if ( $info[0]['numRows'] == 1 ) {
99
         $_SESSION['worker_id'] = ($info[0]['worker_id'] ? $info[0]['worker_id'] : -1); // keep track of the current worker
100
         $_SESSION['effective_worker_id'] = $info[0]['worker_id']; // This allows superusers to enter info as if they were a different worker
101
         $_SESSION['user'] = $loginID;
102
         $sql = "select permission_id from user_permission where username ='" . $_SESSION['user'] . "'";
103
         $info = queryDatabase( $sql );
104
         for ( $i = 0; $i < count($info); $i++ ) {
105
            $permission[$info[$i]['permission_id']] = true;
106
         }
107
         $_SESSION['permission'] = $permission;
108
         validateDatabaseVersion();
109
         redirectPage('user_menu.html');
110
      } else {
111
         return false;
112
      }
113
   }
114
*/
115
   function makeSafeSQLValue ( $value, $type='S' ) {
58 rodolico 116
      global $databaseConnection;
42 rodolico 117
      if (strlen($value) == 0) { // simply set any empty values to null
118
         return 'null';
119
      }
58 rodolico 120
      //if(get_magic_quotes_gpc()) {
121
      //     $value = stripslashes($value);
122
      // }
123
      $value = mysqli_real_escape_string( $databaseConnection,$value );
1 rodolico 124
      if (($type == 'S') and strlen($value)  > 0) { // put quotes around strings
125
         $value = "'" . $value . "'";
28 rodolico 126
      } elseif ($type == 'D') {
4 rodolico 127
         if ( $result = strtotime( $value ) ) {
29 rodolico 128
            $value = Date( 'Y-m-d', $result);
3 rodolico 129
         } else {
130
            $value = '0000-00-00';
131
         }
132
         $value = "'" . $value . "'";
27 rodolico 133
      } elseif ($type == 'DT') {
134
         if ( $result = strtotime( $value ) ) {
135
            $value = Date( 'Y-m-d H:i:s', $result);
136
         } else {
137
            $value = '0000-00-00';
138
         }
139
         $value = "'" . $value . "'";
1 rodolico 140
      }
141
      return $value;
142
   }
4 rodolico 143
 
1 rodolico 144
 
145
/*
146
   creates audit trail of modifications to the database
147
*/ 
148
   function audit ($sql ) {
149
      return ;
150
      $query = 'insert into _audit (_audit.user_id,_audit.sql) values ( ' . $_SESSION['worker_id'] . ', ' . makeSafeSQLValue($sql) . ')';
58 rodolico 151
      doSQL( $query );
152
      #mysql_query( $query );
153
      #if( mysql_errno() ) {
154
      #   $error = 'MYSQL ERROR #'.mysql_errno().' : <small>' . mysql_error(). "</small><br><VAR>$query</VAR>";
155
      #   echo($error);
156
      #}
1 rodolico 157
   }
158
 
159
 
160
   /*
161
      Taken from comments at http://www.php.net/manual/en/function.mysql-query.php
162
      function originally named 'q'
163
      $r = q('Select id,foo FROM blah');
164
      echo $r[0]['id']; // first row, field 'id'
165
 
166
      // for single field single row selects
167
      // only the value is returned
168
      $count = q('SELECT count(*) from blah');
169
      // $count is the number
170
 
171
      Returns affected_rows and/or insert_id for anything other than select's.
172
      If you dont want field name keys then pass 0 for second parameter.
173
 
174
      For a query returning multiple rows, will return an associative array
175
         return['data'] contains an two dimensional array of all data received from the query
176
         return['meta']
177
            array of associative arrays. Each row in the array corresponds to a column in the query return
178
            Each array row contains the following:
179
               'name'   name of the column
180
               'length' maximum width of the column FOR THIS QUERY
181
               'numeric'true if the column is numeric
182
               'type'   type of the column (database dependant)
183
 
184
   */
58 rodolico 185
 
186
   /* Modified for mysqli. Uses a global variable, $databaseConnection, which must exist */
1 rodolico 187
 
58 rodolico 188
   function queryDatabaseExtended($query,$assoc=1,$showErrors=true) {
189
      global $databaseConnection;
1 rodolico 190
      // print "<pre>In Query database\n---------------------\n$query\n---------------------\n</pre>";
191
      printLog( $query );
55 rodolico 192
      // we use the @ symbol to suppress warnings and errors when calling mysql_query
58 rodolico 193
      $r = @mysqli_query($databaseConnection,$query);
194
      if( mysqli_errno($databaseConnection) ) {
195
         $error = 'MYSQL ERROR #'.mysqli_errno($databaseConnection).' : <small>' . mysqli_error($databaseConnection). "</small><br><VAR>$query</VAR>";
1 rodolico 196
         if ( $showErrors ) echo($error);
197
         return FALSE;
198
      }
199
      if( ! preg_match ( '/^\s*select/i', $query ) ) {
58 rodolico 200
         $f = array( 'affected_rows' => mysqli_affected_rows($databaseConnection),'insert_id' => mysqli_insert_id($databaseConnection));
1 rodolico 201
         // create audit trail
202
         audit($query);
203
         return $f;
204
      }
58 rodolico 205
      $count = @mysqli_num_rows($r);
1 rodolico 206
      $fieldMeta = array();
58 rodolico 207
      $i = 0;
208
      while ($i++ < mysqli_num_fields($r)) {
209
         $meta = mysqli_fetch_field ( $r );
1 rodolico 210
         //objectDebugScreen($meta);
58 rodolico 211
         $fieldMeta[] = array('name' => $meta->name, 'length' => $meta->max_length, 'numeric' => array_key_exists( $meta->type, NUMERICS ), 'date' => array_key_exists( $meta->type, DATES ), 'type' => $meta->type );
1 rodolico 212
      }
213
      if( ! $count ) return '';
214
      $all = array();
215
      for( $i = 0; $i < $count; $i++ ) {
58 rodolico 216
        if( $assoc ) $f = mysqli_fetch_assoc($r);
217
        else $f = mysqli_fetch_row($r);
1 rodolico 218
        $all[] = $f;
219
      }
58 rodolico 220
      mysqli_free_result($r);
1 rodolico 221
      return array( 'meta' => $fieldMeta, 'data' => $all, 'count' => $count);
222
   } // function queryDatabaseExtended
223
 
224
 
32 rodolico 225
   // function returns the first column of the first row of data returned from query
226
   // or null no value returned
227
   function getOneDBValue( $sql ) {
228
      $data = queryDatabaseExtended( $sql, false ); // get the query results into a standard array
229
      return $data['count'] ? $data['data'][0][0] : null;
230
   }
231
 
1 rodolico 232
  function countNumberOfRows ( $sql ) {
233
     $count = queryDatabaseExtended("select count(*) numRows from ($sql) test");
234
     return $count['data'][0]['numRows'];
235
  }
236
 
237
   function makeWhereClause ($conditions) {
238
      $whereClause = ' where ' . implode (' and ', $conditions );
239
      return $whereClause;
240
   }
241
 
242
   function insertValuesIntoQuery( $query, $values ) {
243
      foreach ( $values as $name => $value ) {
244
         $query = search_replace_string($query, "<$name>", $value );
245
      }
246
      return $query;
247
   }
248
 
249
/*
250
   function showUserMenu () {
251
      $permission = $_SESSION['permission'];
252
      // objectDebugScreen($_SESSION['permission']);
253
      // print "Effective User = " . $_SESSION['effective_worker_id'];
254
      $result = '<ul>';
255
      if ( $permission[1] ) {
256
         $result .= '<li><a href="timesheet_input.html">Add/Enter Time Sheet/Expenses</a></li>';
257
         $result .= '<li><A href="edit_personal.html">Edit Personal Data</A></li>';
258
         $result .= '<li><A href="view_personal_payroll.html">View Past Payroll</A></li>';
259
         $result .= '<li><a href="docs/user_manual.html" target="_blank">User Manual (in separate window)</a></li>';
260
      }
261
      if ( $permission[2]) {
262
         $result .= '<li><a href="create_invoice.html">Create Invoice</a></li>';
263
         $result .= '<li><a href="view_invoice.html">View Invoices</a></li>';
264
      }
265
      if ( $permission[3]) {
266
         $result .= '<li><a href="create_payroll.html">Create Payroll</a></li>';
267
         $result .= '<li>View Payroll</li>';
268
         $result .= '<li><a href="docs/payroll_manual.html" target="_blank">Payroll Manual (in separate window)</a></li>';
269
      }
270
      if ( $permission[4]) {
271
         $result .= '<li>Create Worker</li>';
272
         $result .= '<li>View Worker</li>';
273
      }
274
      if ( $permission[5]) {
275
         $result .= '<li>Add Client</li>';
276
      }
277
      if ( $permission[6]) {
278
         $result .= '<li>Add Project</li>';
279
      }
280
      if ( $permission[7]) {
281
         $result .= '<li><A href="reports.html">View Payroll Reports</A></li>';
282
      }
283
      if ( $permission[8] ) {
284
         $result .= '<li><A href="becomeuser.html">Become another User</A></li>';
285
      }
286
      $result .= "<li><a href='/common-cgi/contact_us.php' target='_blank'>Submit Bug Report or Enhancement Request</a>";
287
      $result .= "<li><a href='viewBugz.html' >View Bugs or Enhancments Request</a>";
288
      $result .= "<li><a href='login.html?command=logout'>Log Out</a></ul>";
289
      return $result;
290
   }
291
 
292
   function getProjectName( $projectID ) {
293
      $sql = "select concat(client.name,' - ', project.project_name) project_name
294
              from project join client on project.client_id = client.client_id
295
              where project.project_id = $projectID
296
             ";
297
      return queryDatabase( $sql );
298
   }
299
 
300
 
301
   function getExpenseReason( $expenseReasonID ) {
302
      $sql ="select description
303
             from expense_reason
304
             where expense_reason_id = $expenseReasonID
305
            ";
306
      return queryDatabase( $sql );
307
   }
308
*/
309
 
310
   function addDateRange ( $dateStart, $dateEnd ) {
311
      $dateWhere = array();
312
      if ( strlen($dateStart) > 0 ) {
313
       array_push($dateWhere, "start_time >= '$dateStart'" );
314
      }
315
      if ( strlen($dateEnd) > 0 ) {
316
         array_push($dateWhere, "end_time <= '$dateEnd'");
317
      }
318
      return $dateWhere;
319
   }
320
 
321
   function search_replace_string($string, $searchFor, $replaceWith ) {
322
      $string = str_replace ( $searchFor, $replaceWith, $string );
323
      return $string;
324
   }
41 rodolico 325
 
326
   /* 
327
      simple function that breaks a multi line variable apart into an array of lines
328
      removes any blank lines or trailing newlines
329
   */
330
   function textArea2Array ( $textarea ) {
331
      $results = preg_replace("/[\r\n]+/", "\n", $textarea ); // convert any combinations of \r and \n to one \n
332
      $results = preg_replace("/\n$/", "", $results ); // remove any trailing newlines
333
      return explode( "\n", $results );
334
   }
1 rodolico 335
 
336
   /*
337
      Function takes an SQL statement and converts it to an HTML table.
338
      Return Value: HTML table representation of the query
339
      Parameters:
340
         $sql    A valid SQL query to run
341
         $format An optional array of format strings (suitable for printf) for each column (empty strings ignored)
342
         $makeTableDef  If True, the resulting HTML has the <table></table> tags; otherwise starts with header
343
         $append   Arbitrary string that is appended as a single column to each row
344
 
345
         NOTE ON $append
346
            $append may optionally contain variables of the form %colname%, which will be replaced
347
            with values from the current row. $colname is taken from the META data from the query, thus
348
            the query select foo from bar would have a meta of header of foo for column 0.
349
            $append is searched for strings of form %foo% in that case, and the current value of column
350
            foo replaces the tag %foo%.
351
            %foo% is ignored if foo is not a valid column name in a query.
352
            thus, a query such as select zip,city,state from zip_codes and a string of Hello %city% I'm glad
353
            you are in %State% will not replace the second as State is not a column of this query (it is case
354
            sensitive). Also, beware of items like select zip,concat(state,', ', city) from zip_codes. It is
355
            much better to rewrite that as select zip,concat(state,', ', city) mytown from zip_codes.
356
 
357
            If you don't know what all that means, get a book on SQL
358
   */
359
   function queryToTable ( $sql, $format = '', $makeTableDef = true, $append='' ) {
360
      //print "\n\n$sql\n\n";
361
      $tdTextDefinition = '<td valign=' . HTML_QUOTE_CHAR . 'top' . HTML_QUOTE_CHAR . '>';
362
      $tdNumberDefinition = '<td valign=' . HTML_QUOTE_CHAR .'top' . HTML_QUOTE_CHAR . 'align=' . HTML_QUOTE_CHAR . 'right' . HTML_QUOTE_CHAR . '>';
363
      $rows = array();
364
      $html = '';
365
      $fields;
366
      $info = array();
367
      if ( $result = queryDatabaseExtended($sql,0) ) {
368
         $meta = $result['meta'];
369
         // Build the searchFor array for $append
370
         $searchFor = array();
371
         foreach ( $meta as $field ) {
372
            $searchFor[] = '%' . $field['name'] . '%';
373
         }
374
         $info = $result['data'];
375
         unset ($result);
376
         /* special condition where only one row is returned. In that case, $info is not an array
377
           of associations, but a simple association. In this case, we need to convert it
378
         */
379
         if (count($info[0]) == 1) { // convert from association to single row array of associations
380
            $temp = array();
381
            foreach ($info as $column => $value) {
382
               $temp[0][$column] = $value;
383
            } // foreach
384
            $info = $temp;
385
         }
386
         if (count($format) > 0 ) { // we have some formats, so let's do it the hard, slow way
387
            for ( $row = 0; $row < count($info); $row++) {
388
               $rows[$row] = '';
389
               for ( $column = 0; $column < count($info[$row]); $column++  ) {
390
                  $rows[$row] .= strlen($format[$column]) && isset($info[$row][$column])> 0 ?
391
                                  ( $tdNumberDefinition . sprintf($format[$column],$info[$row][$column]) . '</td>')
392
                                  : ($tdTextDefinition . $info[$row][$column] . '</td>');
393
               } // for $column
394
               /*
395
                  let's append some stuff to the row if it exists.
396
                  We will take the array of SearchFor containing the column names
397
                  and the array of values from this row, then look for matches and replace them
398
                  with the correct values. Note, the column names in $append should have percent
399
                  signs appended and prepended, thus a column name of joe would be %joe% in %append
400
               */
401
               if (strlen($append) > 0) { // let's append some stuff to the row
402
                  $rows[$row] .= $tdTextDefinition . str_replace ( $searchFor, $info[$row], $append ) . '</td>';
403
               }
404
            } // for $row
405
         } else { // no formatting, so we just slam the stuff together
406
            for ( $row = 0; $row < count($info); $row++) {
407
               $currentValue = $tdTextDefinition . implode( '</td>' . $tdTextDefinition, $info[$row]) . '</td>';
408
               if (strlen($append) > 0) { // see explaination in if part of this structure
409
                  $currentValue  .= $tdTextDefinition . str_replace ( $searchFor, $info[$row], $append ) . '</td>';
410
               }
411
               $rows[] = $currentValue;
412
            }
413
         }
414
         // ok, let's get the field headers from the table
415
         $html .= '<tr>';
416
         foreach ( $meta as $field ) {
417
            $html .= '<th>' . $field['name'] . '</th>';
418
         }
419
         $html .= '</tr>';
420
         // we now have all the info, so let's make it into a table
421
         $html .= '<tr>' . implode('</tr><tr>', $rows ) . '</tr>';
422
 
423
         if ( $makeTableDef ) { // they want the <table> def, so let's give it to them
424
            $html = '<table border=' . HTML_QUOTE_CHAR . '1' . HTML_QUOTE_CHAR . '>' . $html . '</table>';
425
         } // if ( $makeTableDef
426
      } // if ( $info = queryDatabase($sql,0) )
427
      // print '<pre>';  print_r ($info); print '</pre>';
428
      return $html;
429
   }
430
 
431
   /*
432
      function executes a query, then returns an array containing only the values of the first
433
      field in the return as the keys to an associative array. NOTE: any duplicates will be
434
      discarded. This is useful when you simply want to know if a value exists, ie if you
435
      are building an html select from a query, and a separate query needs to hold the
436
      values that are currently selected
437
   */
438
 
439
   function sqlValuesToKeys ($sql) {
440
      $returnValue = array();
441
      if ( $info = queryDatabaseExtended($sql,0) ) { // note we are turning off the associative array here
442
         $info = $info['data'];
443
         foreach ( $info as $key => $value ) { // only thing I know to do is iterate
444
            $returnValue[$value[0]] = true;
445
         }
446
      } // if
447
      return $returnValue;
448
   }
449
 
450
   /* this function will take the result of an SQL query that returns at least two columns.
451
      The first column becomes the keys in an associative array, and the second column
452
      becomes the value.
453
 
454
      Note, because it is an associative array, duplicates of the first column will only contain
455
      the last value.
456
   */
457
 
458
   function sqlColumnColumnArray ( $sql ) {
459
      $returnValue = array();
460
      if ( $info = queryDatabaseExtended($sql,0) ) { // note we are turning off the associative array here
461
         $info = $info['data'];
462
         foreach ( $info as $key => $value ) { // only thing I know to do is iterate
463
            $returnValue[$value[0]] = $value[1];
464
         }
465
      } // if
466
      return $returnValue;
467
   }
468
 
469
 
470
   /* the first returned column becomes the value, the second becomes the display element
471
   */
472
   function queryToSelect ( $sql, $selectedFieldsQuery = '' ) {
473
      $selectedFields = array();
474
      if (  preg_match ( '/^\s*select/i', $selectedFieldsQuery ) ) { // They passed in a query
475
         if (strlen($selectedFieldsQuery) ) {
476
            $selectedFields = sqlValuesToKeys($selectedFieldsQuery);
477
         }
478
      } else { // assume the passed in a value
479
         $selectedFields[$selectedFieldsQuery] = 1;
480
      }
481
      $info = queryDatabaseExtended( $sql, false );
22 rodolico 482
      if ($info['count'] == 0) { // we had no entries
483
         return '';
484
      }
1 rodolico 485
      $info = $info['data'];
486
      $html = '';
487
      for ( $i = 0; $i < count($info); $i++ ) {
488
         $html .= '<option value="' . $info[$i][0] . '"';
489
         if ( $selectedFields[$info[$i][0]] ) {
490
            $html .= ' selected';
491
         }
492
         $html .= '>' . $info[$i][1] . '</option>';
493
      }
494
      return $html;
495
   }
496
 
497
   /* function will take a query and turn it into a series of check boxes. It must contain
498
      two columns, with the first becoming the the name of the checkbox
499
      and the second becoming the displayed value. an optional third column will be used
500
      to match if the $checkedValuesQuery is used.
501
      if $checkedValuesQuery is not empty, it will be run to see what boxes need to be
502
      checked by being compared to the third column of the $sql query.
503
      $htmlBefore will be placed before each check box, and $htmlAfter will be placed after
504
      each checkbox.
505
 
506
      if $tableColumns is set to a number, the checkboxes will be embedded in a group of
507
      <tr></tr>, each containing table columns of $tableColumns width. In this case, $htmlBefore
508
      will have <td> prepended and $htmlAfter will have </td> appended, meaning any passed
509
      values will be INSIDE of the td. NOTE: the <table></table> tags are NOT put in.
510
 
511
      NOTE: currently, using the table stuff will leave a dangling row with 0 elements if
512
      the number of elements equal the number of columns.
513
   */
514
 
515
   function queryToCheckBoxes ( $sql, $checkedValuesQuery = '', $htmlBefore = '', $htmlAfter = '', $table_columns='' ) {
516
      $html = '';
517
      if ($table_columns) {
518
         $htmlBefore = '<td>' . $htmlBefore;
519
         $htmlAfter .= '</td>';
520
         $html .= '<tr>';
521
      }
522
      $numColumns = 0;
523
      $checkBoxes = queryDatabaseExtended( $sql,0 );
524
      $selectedFields = array();
525
      if (strlen($checkedValuesQuery) ) {
526
         $selectedFields = sqlValuesToKeys($checkedValuesQuery);
527
      }
528
      foreach ($checkBoxes['data'] as $row => $values) {
529
         if ($table_columns && ++$numColumns == $table_columns) {
530
            $html .= '</tr><tr>';
531
            $numColumns = 0;
532
         }
533
         //objectDebugScreen($row);
534
         $html .= $htmlBefore . '<input type="checkbox" name="' . $values[0] . '"';
535
         if ( $selectedFields[$values[2]] ) {
536
            $html .= ' checked';
537
         }
538
         $html .= '>' . $values[1] . $htmlAfter;
539
         //<INPUT type="checkbox" checked name="temp">
540
      } // foreach
541
      $html .= '</tr>';
542
      return $html;
543
   }
544
 
545
   function makeMoney( $value ) {
546
      return sprintf( '%0.2f', $value );
547
   }
548
 
549
   function queryToCSV ( $sql ) {
550
      $rows = array();
551
      $CSV = '';
552
      $info = array();
553
      if ( $result = queryDatabaseExtended($sql,0) ) {
554
         $meta = $result['meta'];
555
         //objectDebugScreen($result);
556
         $info = $result['data'];
557
         unset ($result);
558
         $headers = array();
559
         foreach ( $meta as $field ) {
560
            $headers[] = $field['name'];
561
         } // foreach
562
         $rows[] = implode("\t", $headers);
563
         /* special condition where only one row is returned. In that case, $info is not an array
564
           of associations, but a simple association. In this case, we need to convert it
565
         */
566
         if (count($info[0]) == 1) { // convert from association to single row array of associations
567
            $temp = array();
568
            foreach ($info as $column => $value) {
569
               $temp[0][$column] = $value;
570
            } // foreach
571
            $info = $temp;
572
         }
573
         for ( $row = 0; $row < count($info); $row++) {
574
            $rows[] = implode("\t", $info[$row]);
575
         }
576
         // we now have all the info, so let's make it into a table
577
         $CSV .= implode("\n", $rows );
578
      } // if ( $info = queryDatabase($sql,0) )
579
      // print '<pre>';  print_r ($info); print '</pre>';
580
      return $CSV;
581
   }
582
 
583
 
584
/* This function should only be run once, when the original data has been ported from the other system */
585
function normalizeTime () {
586
   //queryDatabase('update time_tracker set payroll_id = null where start_time > 20070101');
587
   $info = queryDatabase('select * from payroll where payroll_date >= 20070101 order by worker_id,payroll_date');
588
   for ( $i = 0; $i < count($info); $i++) {
589
      $payroll_id = $info[$i]['payroll_id'];
590
      $workerID = $info[$i]['worker_id'];
591
      $payroll_date = $info[$i]['payroll_date'];
592
      queryDatabase("update time_tracker set time_tracker.payroll_id = $payroll_id where payroll_id is null and worker_id = $workerID and start_time <= '$payroll_date'");
593
      queryDatabase("update expense set payroll_id = $payroll_id where payroll_id is null and worker_id = $workerID and expense_date <= 'payroll_date'");
594
   }
595
}
596
/*
597
   redirects to a different page (ie, sends out a location header)
598
   $page is required
599
   $parameters can be blank but, if they are not, they are a URL encoded string
600
   $path defaults to current uri if it is not passed in
601
   $host defaults to current server name if not passed in
602
*/
43 rodolico 603
function redirectPage ( $page,$parameters=array(),$path='',$host='', $protocol='') {
1 rodolico 604
   $params = '';
605
   if ( strlen($host) == 0 ) $host = $_SERVER['HTTP_HOST'];
606
   if ( strlen($path) == 0 ) $path = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
607
   if ( count($parameters) > 0 ) {
608
      foreach ($parameters as $var => $value ) {
11 rodolico 609
         $params[] = $var . '=' . rawurlencode($value);
1 rodolico 610
      }
11 rodolico 611
      $params = '?' . implode( '&', $params );
1 rodolico 612
   }
43 rodolico 613
   if ( ! $protocol ) {
45 rodolico 614
      $protocol = isset($_SERVER['HTTPS']) ? "https:" : "http:";
43 rodolico 615
   }
616
   $location = $protocol . '//' . $host . $path . '/' . $page . $params;
44 rodolico 617
   header("Location: $location", true);
1 rodolico 618
   exit;
619
}
620
 
621
   function FileErrorMessage ( $errorCode ) {
622
      switch ($errorCode) {
623
         case 1:
624
             return("The uploaded file exceeds the upload_max_filesize directive (" . ini_get("upload_max_filesize") . ") in php.ini.");
625
         case 2:
626
             return("The uploaded file exceeds the MAX_FILE_SIZE directive (" . MAX_UPLOAD_FILE_SIZE . ").");
627
         case 3:
628
             return("The uploaded file was only partially uploaded.");
629
         case 4:
630
             return("No file was uploaded.");
631
         case 6:
632
             return("Missing a temporary folder.");
633
         case 7:
634
             return("Failed to write file to disk");
635
         default:
636
             return("Unknown File Error");
637
      }
638
   }
639
 
640
  /* this function will clean up nasty stuff on the uploaded file name before
641
     allowing it to be used to store the file to disk.
642
     It removes any non-alphanumerics, underscores, periods and dashes
643
  */
644
 
645
  function fixFileName ( $filename ) {
646
     $filename = strtolower( $filename );
647
     $filename = preg_replace('/\s+/', '_', $filename); // convert all spaces to underscore
648
     $filename = preg_replace( '/[^a-z0-9._-]/', '', $filename );
649
     return $filename;
650
  }
651
 
652
 
653
   /* function will take a hash, and return the hash with the values modified
654
      to the form $key$delimiter$value
655
      thus, a hash 'col1'=>'value1', 'col2'=>'value2' would return
656
      col1=>'col1=value1', col2=>'col2=value2'
657
      This is useful for creating an update or where clause, as the user can have
658
      a hash of conditions (or updates to make), call this function, then
659
      implode. Thus, in the above case, if we wanted to have a where clause
660
      we could say implode( ' and ', makeEqualsFromHash($conditions) ) and
661
      get col1=value1 and col2=value2 as the result.
662
   */
663
   function makeEqualsFromHash( $hash, $delimiter='=' ) {
664
      foreach ( $hash as $key => $value ) {
54 rodolico 665
         $hash[$key] = $key . $delimiter . $value ? $value : 'null';
1 rodolico 666
      }
667
      return $hash;
668
   }
669
 
670
   /*
671
      function will takes fieldList, a hash of column names and values, and either
672
      updates or inserts depending upon whether the record exists.
673
      It will do a query by taking $existsColumns to determine if the record exists.
674
         ($existsColumns is another hash of column names and values) As a convenience,
675
         if $existsColumns is empty, or the value is empty, will assume an insert
676
      If record exists
677
         creates an update out of $fieldList
678
      else
679
         creates an insert out of $fieldList
680
      then, executes the query
681
      Returns the value of lastInsert on insert
682
 
683
      NOTE: if the key field(s) are not automatically created on insert, they
684
      must be included in $fieldList also.
685
   */
686
   function addOrUpdate ( $tableName, $existsColumns, $fieldList ) {
687
      $sql = '';
688
      $insert = true;
689
      // assume we will have a whereClause
690
      $whereClause = true;
691
      // are there any null values?
692
      foreach($existsColumns as $key => $value) {
693
         if (strlen($value) == 0) {
694
            $whereClause = false;
695
         }
696
      }
697
      if ($whereClause and count($existsColumns) ) {
698
         $whereClause = implode(' and ', makeEqualsFromHash($existsColumns) );
699
         $result = queryDatabaseExtended( "select * from $tableName where $whereClause" );
700
         if ($result['count'] == 1) {
701
            $insert = false;
702
         }
703
      }
704
      if ($insert) { // we must be adding a record, so do an insert
705
         $sql = "insert into $tableName(";
706
         $sql .= implode(',',array_keys($fieldList) );
707
         $sql .= ') values (';
708
         $sql .= implode(',', $fieldList);
709
         $sql .= ')';
710
         $result = queryDatabaseExtended($sql);
711
         return ($result['insert_id']);
712
      } else { // must be a true update
713
         $sql = "update $tableName set " . implode(',',makeEqualsFromHash($fieldList) ) . " where $whereClause" ;
714
         queryDatabaseExtended( $sql );
715
      }
716
   }
717
 
718
   /* function generates a random password. Shamelessly stolen from
719
       http://www.laughing-buddha.net/jon/php/password/
720
   */
721
 
722
   function generatePassword ($length = 8) {
723
     // start with a blank password
724
     $password = "";
725
     // define possible characters
726
     $possible = "0123456789bcdfghjkmnpqrstvwxyz"; 
727
     // set up a counter
728
     $i = 0; 
729
     // add random characters to $password until $length is reached
730
     while ($i < $length) { 
731
        // pick a random character from the possible ones
732
        $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
733
        // we don't want this character if it's already in the password
734
        if (!strstr($password, $char)) { 
735
          $password .= $char;
736
          $i++;
737
        }
738
      }
739
      // done!
740
      return $password;
741
   }
742
 
743
   function showDateWithNulls( $date, $prompt='' ) {
744
      if ( is_null($date) or $date == '0000-00-00' ) {
745
        return $prompt;
746
      } else {
747
          return $date;
748
      }
749
   } // function showDateWithNulls
750
 
751
 
752
// functions merged from previous version
753
 
754
 
755
   // Quote variable to make safe
15 rodolico 756
   function makeQuerySafe ( $fieldValue, $canBeNull = false ) {
757
      if ( $canBeNull && strlen($fieldValue) == 0 ) { // if empty string and it can be null
758
         return 'NULL';  // just return null
759
      }
1 rodolico 760
      // Stripslashes
761
      if (get_magic_quotes_gpc()) {
762
         $fieldValue = stripslashes($fieldValue);
763
      }
764
      // Quote if not a number or a numeric string
765
      if (!is_numeric($value)) {
766
         $fieldValue = "'" . mysql_real_escape_string($fieldValue) . "'";
767
      }
768
      return $fieldValue;
769
   }
770
 
771
 
772
   function HumanReadable2Number ( $hr ) {
773
      $hr = strtolower($hr);
774
      $num = $hr;
775
      if ( preg_match('/([0-9]+)([tgmk])/', $hr ,$matches) ) {
776
         $num = $matches[1];
777
         $modifier = $matches[2];
778
         if ($modifier == 'g') { 
779
            $num *= 1024 * 1024 * 1024; 
780
         } elseif ($modifier == 'm' ) { 
781
            $num *= 1024 * 1024; 
782
         } elseif ($modifier == 'k' ) { 
783
            $num *= 1024;
784
         } else { 
785
            return "Unable to decipher the number $hr"; 
786
         }
787
      }
788
      return $num;
789
   }
790
 
791
   function Number2HumanReadable( $num ) {
792
      if ( $num > 1024 * 1024 * 1024 ) {
793
         return round( $num / (1024*1024 * 1024) ) . 'G';
794
      } elseif ( $num > 1024 * 1024 ) {
795
         return round( $num / (1024*1024) ) . 'M';
796
      } elseif ( $num > 1024 ) {
797
         return round( $num / 1024 ) . 'k';
798
      } else {
799
         return $num . " bytes";
800
      }
801
   }
802
 
803
   function doSQL( $sql ) {
804
      // print '<pre>' . "$sql\n" . '</pre>';
33 rodolico 805
      return queryDatabaseExtended($sql);
1 rodolico 806
      #mysql_query ($sql);
807
   }
808
 
809
   function deleteData ( $tableInfo, $id ) {
810
      $sql = 'delete from ' . $tableInfo['table name'] . ' where ' . $tableInfo['key field'] . " = $id";
811
      queryDatabaseExtended($sql);
812
      #mysql_query ($sql);
813
      return '';
814
   }
815
 
17 rodolico 816
 
817
   function makeAddFieldHTML ( $columnDef, $fieldName, $defaults = array() ) {
818
         if ( $columnDef['readonly'] ) {
819
            $result .= 'null';
820
         } else {
821
            if ( $defaults[$fieldName] ) {
822
               $default = $defaults[$fieldName];
823
            }
824
            if ( $columnDef['type']  == 'string' ) {
825
               $maxWidth = $columnDef['width'] or MAX_INPUT_FIELD_DISPLAY;
826
               $displayWidth = $maxWidth < MAX_INPUT_FIELD_DISPLAY ? $maxWidth : MAX_INPUT_FIELD_DISPLAY;
827
               $result .= "<input type='text' name='$fieldName' size='$displayWidth' maxlength='$maxWidth' value=''>";
34 rodolico 828
            } elseif ($columnDef['type'] == 'datetime') {
35 rodolico 829
               $value = '';
830
               if ($columnDef['default'] != 'null') {
831
                  $value = $columnDef['default'];
832
                  if ( $columnDef['required'] and ! $value ) {
833
                     $value = date('Y-m-d');
834
                  }
34 rodolico 835
               }
836
               $result .= "<input type='text' name='$fieldName' size='$displayWidth' maxlength='$maxWidth' value='$value'>";
17 rodolico 837
            } elseif ($columnDef['type'] == 'password') {
838
               $result .= "<input type='text' name='$fieldName' size='$displayWidth' maxlength='$maxWidth' value=''>";
839
            } elseif ( $columnDef['type'] == 'text' ) {
840
               $width = $columnDef['width'] ? $columnDef['width'] : MAX_INPUT_FIELD_DISPLAY;
841
               $rows = $columnDef['height'] or DEFAULT_TEXTAREA_HEIGHT;
842
               $result .= "<textarea name='$fieldName' rows='$rows' cols='$width'>" . $existingValue . "</textarea>";
843
            } elseif ( $columnDef['type'] == 'file' ) {
844
               $result .= "<input type='file' name='$fieldName' value=''>";
845
            } elseif ( $columnDef['type']  == 'lookup' ) {
846
               $result .= "<select name='$fieldName'>";
847
               $result .= makeDropDown ( $columnDef['table'], $columnDef['keyfield'], $columnDef['display_field'], ( $default ? $default : 0 ) );
848
               $result .= "</select>";
849
            } elseif ( $columnDef['type']  == 'bool' ) {
850
               $result .= "<input type='radio' name='$fieldName' value='1'";
851
               $result .= ">True<input type='radio' name='$fieldName' value='0'";
852
               $result .= " checked>False";
35 rodolico 853
            } elseif ( $columnDef['type']  == 'datetime' ) {
854
 
17 rodolico 855
            } else {
856
               $result .= "<input type='text' name='$fieldName' value=''>";
857
            }
858
         }
859
         return $result;
860
   }
861
 
1 rodolico 862
   function addData ( $tableInfo ) {
863
      $maxFileSize = min(HumanReadable2Number(MAX_UPLOAD_FILE_SIZE),HumanReadable2Number(ini_get("upload_max_filesize")));
864
      $result = '';
865
      $result .= "<p><form enctype='multipart/form-data' action='" . $_SERVER['PHP_SELF'] . "' method='post'>";
866
      $result .= "<input type='hidden' name='currentdb' value='" . $tableInfo['table name'] . "' />";
867
      $result .= "<input type='hidden' name='MAX_FILE_SIZE' value='$maxFileSize' />";
868
      $result .= '<table border="1">';
869
      foreach ($tableInfo['field info'] as $field => $value) {
870
         $displayName = $value['display name'] ? $value['display name'] : $field; 
871
         $result .= "<tr><td valign='top'>$displayName";
872
         if ( $value['type'] == 'file' ) {
873
            $result .= "<br><font size='-2'>Max Size " . Number2HumanReadable($maxFileSize) . "</font>";
874
         }
875
         $result .= "</td><td>";
17 rodolico 876
         $result .= makeAddFieldHTML ( $value, $field );
877
 
1 rodolico 878
         $result .= "</td></tr>\n";
879
      }
880
      // process any multi selects we may have
881
      if ($tableInfo['complex join']) { 
882
         foreach ($tableInfo['complex join'] as $table => $value) {
883
            $result .= '<tr><td>' . $table . '</td><td>';
884
            $result .= makeMultiSelect( $tableInfo['table name'], $tableInfo['key field'], $id, $value);
885
            $result .= '</td></tr>';
886
         } // foreach
887
      } // if
888
      $result .= "<tr><td colspan='2' align='center'><input type='submit' /></td></tr>
889
      <input type=hidden name='mode' value='added' /> 
890
      <input type=hidden name='id' value='"; 
891
      $result .= $id; 
892
      $result .= "'></table></form> <p>"; 
893
      return $result;
894
   }
895
 
896
  function saveFilesUploaded( $fieldName ) {
897
     $result = '';
898
     $uploaddir =  $_SERVER['DOCUMENT_ROOT'] . IMAGE_DIRECTORY;
899
     $result = fixFileName( basename($_FILES[$fieldName]['name']) );
900
     if (! move_uploaded_file($_FILES[$fieldName]['tmp_name'], $uploaddir . $result)) {
901
       $result = '';
902
   }
903
     return $result;
904
  }
905
 
906
 
907
  function makeDropDown ( $table, $index_field, $display_field = '', $keyvalue = '' ) {
908
     /*
909
       this executes a query on $table (using $index_field and $display_field), then
910
       uses the result to populate a list of <option> tags suitable for inclusion in
911
       a <SELECT>. If $index_field for a row equals $keyvalue, that option has its
912
       SELECT paramter turned on
913
     */
914
     $returnValue = '';
915
     if ( $display_field ) { // they are passing in a table, index field, display field and key value
916
        $sql = "select $index_field,$display_field from $table";
917
     } else { // in the two parameter form, first parameter is query, second is keyvalue
918
        $sql = $table; 
919
        $keyvalue = $index_field;
920
     }
921
     $data = queryDatabaseExtended($sql);
13 rodolico 922
     if ( ! $data ) {
923
        $returnValue = '<option>No Values Found</option>\n';
924
     } else {
925
         $index_field = $data['meta'][0]['name'];
926
         $display_field = $data['meta'][1]['name'];
927
         foreach ($data['data'] as $info) {
928
            $returnValue .= "<option value='" . $info[$index_field] . "'";
929
            if ( $info[$index_field] == $keyvalue ) { 
930
               $returnValue .= ' selected' ; 
931
            }
932
            $returnValue .= '>' . $info[$display_field] . "</option>\n";
933
         }
1 rodolico 934
     }
935
     return $returnValue;
936
  }
937
 
938
  function makeMultiSelect ( $thisTable, $thisKeyfield, $thisValue, $multiSelectDefinition ){
939
      /*
940
         This is some funky code that creates a multi select box for when the current table has a one to many relationship
941
         with another table through an intermediate table, ie professionals joined to projects through an intermediate table,
942
         professionals_projects.
943
 
944
         It creates a query of the form
945
            select dislayfield, keyfield, nullfield
946
            from foreign_table left outer join
947
                  (this_table join joining_table on join_condition)
948
                  on join_condition
949
            where this_table.keyfield = this_record_id;
950
 
951
         Display Field generally comes from the foreign table, as does keyfield. A multi select box is created which contains
952
         the keyfield as the value and the display field displayed. If nullfield is not null, the item is option is selected.
953
 
954
         The following real world example may help:
955
            table professionals
956
                professionals_id (key field)
957
                name             (the name of the professional)
958
            table projects (the current one being edited)
959
                projects_id      (key field)
960
                other stuff
961
            table projects_professionals
962
               projects_id       (fk into projects)
963
               professionals_id   (fk into professionals)
964
         A query such as
965
            select professionals.professionals_id, professionals.name, professionals_projects.projects_id
966
            from professionals left outer join
967
                  (projects join professionals_projects on projects.project_id = professionals_projects.projects_id)
968
                  on professionals.professionals_id = professionals_projects.professionals_id
969
            where projects.project_id = $id;
970
         would return a row for every entry in the professionals table, but with a null value in the projects_id
971
         column if there was no matching entry in the professionals_projects table. This can be used to build
972
         the select
973
      */
974
      if ($thisValue) {
975
         // first build the query
976
         $sql = 'select ';
977
         $sql .= $multiSelectDefinition['values table']['table name'] . '.' . $multiSelectDefinition['values table']['display field'] . ',' ;
978
         $sql .= $multiSelectDefinition['values table']['table name'] . '.' . $multiSelectDefinition['values table']['key field'] . ', ' ;
979
         $sql .= $multiSelectDefinition['null field'] . ' ';
980
         $sql .= 'from ' . $multiSelectDefinition['values table']['table name'] . ' left outer join (';
981
         $sql .= $thisTable . ' join ' . $multiSelectDefinition['join table']['table name'] . ' on ';
982
         $sql .= $multiSelectDefinition['join table']['join condition'] . ') on ';
983
         $sql .= $multiSelectDefinition['values table']['join condition'] . " where $thisTable.$thisKeyfield  = $thisValue";
984
      } else {
985
         $sql = 'select ';
986
         $sql .= $multiSelectDefinition['values table']['table name'] . '.' . $multiSelectDefinition['values table']['display field'] . ',' ;
987
         $sql .= $multiSelectDefinition['values table']['table name'] . '.' . $multiSelectDefinition['values table']['key field'] . ', ' ;
988
         $sql .= ' null ';
989
         $sql .= 'from ' . $multiSelectDefinition['values table']['table name'];
990
      }
991
      print "<pre>$sql</pre>";
992
      // now, run it
993
      $result = "\n<SELECT name='" . $multiSelectDefinition['values table']['table name'] . "[]' multiple>\n";
994
      $data = queryDatabaseExtended($sql);
995
      foreach ( $data['data'] as $info ) {
996
      #$data = mysql_query( $sql ) or die(mysql_error());
997
      #while ( $info = mysql_fetch_array( $data ) ) {
998
         /*
999
            we will refer to fields by number due to the inconsistency of labeling returned rows, ie the query may
1000
            request table.fieldname or simply fieldname, but the result set will always call it simply fieldname
1001
            since we control the query, we know that field 0 is the display name, field 1 is the keyfield and
1002
            field 2 is the field that will be null or not
1003
         */
1004
         $result .= "<option value=" . $info[1] ;
1005
         if ($info[2]) { $result .= " selected"; }
1006
         $result .= '>' . $info[0] . "</option>\n";
1007
      } // while
1008
      $result .= "</SELECT>\n";
1009
      return $result;
1010
  }
1011
 
17 rodolico 1012
   function makeEditFieldHTML ($columnDef, $existingValue, $fieldName ) {
1013
         if ( $columnDef['readonly'] ) {
1014
            $result .= $existingValue;
1 rodolico 1015
         } else {
17 rodolico 1016
            if ( $columnDef['type']  == 'string' ) {
1017
               $maxWidth = $columnDef['width'] or MAX_INPUT_FIELD_DISPLAY;
1 rodolico 1018
               $displayWidth = $maxWidth < MAX_INPUT_FIELD_DISPLAY ? $maxWidth : MAX_INPUT_FIELD_DISPLAY;
17 rodolico 1019
               $result .= "<input type='text' name='$fieldName' size='$displayWidth' maxlength='$maxWidth' value='" . $existingValue . "'>";
1020
            } elseif ( $columnDef['type'] == 'password') {
1021
               $maxWidth = $columnDef['width'] or MAX_INPUT_FIELD_DISPLAY;
1 rodolico 1022
               $displayWidth = $maxWidth < MAX_INPUT_FIELD_DISPLAY ? $maxWidth : MAX_INPUT_FIELD_DISPLAY;
17 rodolico 1023
               $result .= "<input type='text' name='$fieldName' size='$displayWidth' maxlength='$maxWidth' value=''>";
1024
            } elseif ( $columnDef['type'] == 'text' ) {
1025
               $width = $columnDef['width'] ? $columnDef['width'] : MAX_INPUT_FIELD_DISPLAY;
1026
               $rows = $columnDef['height'] or DEFAULT_TEXTAREA_HEIGHT;
1027
               $result .= "<textarea name='$fieldName' rows='$rows' cols='$width'>" . $existingValue . "</textarea>";
1028
            } elseif ( $columnDef['type'] == 'file' ) {
1029
               $result .= "<input type='hidden' name='MAX_FILE_SIZE' value=value'" . MAX_UPLOAD_FILE_SIZE . "' />";
1030
               if ( $columnDef['filetype'] == 'picture' ) {
1031
                  $result .= "<img src='" . IMAGE_DIRECTORY . $existingValue . "' height='" . EDIT_IMAGE_HEIGHT . "' alt='Image'>";
1 rodolico 1032
               }
1033
               $result .= "<br>";
17 rodolico 1034
               $result .= "<input type='file' name='$fieldName' value='" . $existingValue . "'>";
1035
            } elseif ( $columnDef['type']  == 'lookup' ) {
1036
               $result .= "<select name='$fieldName'>";
1037
               if ( $columnDef['null_ok'] ) {
1 rodolico 1038
                  $result .= '<option value="' . CONSTANT_NO_VALUE_DROPDOWN . '">' . CONSTANT_NO_VALUE_DROPDOWN . '</option>';
1039
               }
17 rodolico 1040
               if ($columnDef['query']) { // they want to pass a query, so we'll do that. Query has key in first column, display in second
1041
                  $result .= makeDropDown ($columnDef['query'], $existingValue );
1 rodolico 1042
               } else { // no query, so we give the table name, keyfield, and display field
17 rodolico 1043
                  $result .= makeDropDown ( $columnDef['table'], $columnDef['keyfield'], $columnDef['display_field'], $existingValue );
1 rodolico 1044
               } 
1045
               $result .= "</select>";
17 rodolico 1046
            } elseif ( $columnDef['type']  == 'bool' ) {
1047
               $result .= "<input type='radio' name='$fieldName' value='1'";
1048
               if ( $existingValue ) {
1 rodolico 1049
                  $result .= ' checked';
1050
               }
17 rodolico 1051
               $result .= ">True<input type='radio' name='$fieldName' value='0'";
1052
               if ( ! $existingValue ) {
1 rodolico 1053
                  $result .= ' checked';
1054
               }
1055
               $result .= ">False";
1056
            } else {
17 rodolico 1057
               $result .= "<input type='text' name='$fieldName' value='" . $existingValue . "'>";
1 rodolico 1058
            }
1059
         }
17 rodolico 1060
         return $result;
1061
   }
1062
 
1063
   function editData ( $tableInfo, $id ) {
1064
      $maxFileSize = min(HumanReadable2Number(MAX_UPLOAD_FILE_SIZE),HumanReadable2Number(ini_get("upload_max_filesize")));
1065
 
1066
      $sql = "SELECT * FROM " . $tableInfo['table name'] . " where " . $tableInfo['key field'] . " = $id";
1067
 
1068
      // $result =  "<pre>$sql</pre><br />";
1069
      $result .= "<p><form enctype='multipart/form-data' action='" . $_SERVER['PHP_SELF'] . "' method='post'>"; 
1070
      $result .= "<input type='hidden' name='currentdb' value='" . $tableInfo['table name'] . "' />";
1071
      $result .= "<input type='hidden' name='MAX_FILE_SIZE' value='$maxFileSize' />";
1072
      $result .= '<table border="1">';
1073
      $data = queryDatabaseExtended($sql);
1074
      $info = $data['data'][0];
1075
      foreach ($tableInfo['field info'] as $field => $value) {
1076
         $displayName = $value['display name'] ? $value['display name'] : $field; 
1077
         $result .= "<tr><td valign='top'>$displayName";
1078
         if ( $value['type'] == 'file' ) {
1079
            $result .= "<br><font size='-2'>Max Size " . Number2HumanReadable($maxFileSize) . "</font>";
1080
         }
1081
         $result .= "</td><td>";
1082
         $result .= makeEditFieldHTML ($value, $info[$field], $field );
1 rodolico 1083
         $result .= "</td></tr>\n";
1084
      }
1085
 
1086
      global $DATABASE_DEFINITION;
1087
      // process any multi selects we may have
1088
      if ($tableInfo['complex join']) { 
1089
         foreach ($tableInfo['complex join'] as $table => $value) {
1090
            if ($value['values table']['key field']) {
1091
               $valueQuery = 'select ' . $value['values table']['key field'] . ',' . $value['values table']['display field'] . ' from ' . $value['values table']['table name'];
1092
            } else {
1093
               $valueQuery = $DATABASE_DEFINITION[$value['values table']['table name']]['display query'];
1094
            }
1095
            $selectedFieldsQuery = 'select ' .  $value['join table']['values link'] .  ' from ' .  $value['join table']['table name'] . ' where ' . $value['join table']['my link'] . " = $id";
1096
            $result .= "<tr><td>$table</td><td>\n";
1097
            $result .= "\n<SELECT name='" . $value['values table']['table name'] . "[]' multiple>";
1098
            $result .= queryToSelect( $valueQuery, $selectedFieldsQuery);
1099
            $result .= '</select>';
1100
            $result .= '</td></tr>';
1101
         } // foreach
1102
      } // if
1103
 
17 rodolico 1104
     if ( $tableInfo['child tables'] ) { // process any children tables we may have
1105
        foreach ( $tableInfo['child tables'] as $table => $value ) {
1106
           $idColumn = $thisTableDef['key field']; // figure out which is the keyfield for the child table
1107
           // now, let's figure out what the key is that links the two. If parent key is defined, use it. Otherwise, look
1108
           // for a column with the same name our our key field
1109
           $parentKeyColumn = $value['parent key'] ? $value['parent key'] : $tableInfo['key field'];
1110
           // $result .= "Parent Key Column is $parentKeyColumn\n<br>";
1111
           $result .= "<tr><td colspan='2'>\n";
1112
           $result .= editDataTable( $DATABASE_DEFINITION[$table],    // the definition of the sub-table
1113
                                     "$parentKeyColumn=$id",          // the condition for limiting the sub-table
1114
                                     array( $parentKeyColumn => $id ) // the columns to pre-populate and mark read-only
1115
                                   );
1116
           $result .= "</td></tr>\n";
1117
        } // foreach
1118
     } // if
1 rodolico 1119
 
16 rodolico 1120
 
1 rodolico 1121
      $result .= "<tr><td colspan='2' align='center'><input type='submit' /></td></tr> 
1122
      <input type=hidden name='mode' value='edited'> 
1123
      <input type=hidden name='id' value='"; 
1124
      $result .= $id; 
1125
      $result .= "'> 
1126
      </table> 
17 rodolico 1127
      </form>";
1 rodolico 1128
      return $result;
1129
   } // editData
1130
 
17 rodolico 1131
   /* 
1132
      function will create a table with all rows and columns from the database inside it, ready for editing.
1133
      It will limit the rows shown based on $whereClause, and not allow editing of columns listed in $defaultValues
1134
      One "empty" row will be included for adding. This row will have $defaultValues filled in with $defaultValues
1135
      and will be marked read-only also.
18 rodolico 1136
      The INPUT tags created will be of the form fieldname concated with some special stuff to allow updateData and insertData
1137
      to find them. See documentation for additional information
17 rodolico 1138
   */
1139
 
1140
   function editDataTable ( $tableInfo, $whereClause, $defaultValues = '') {
1141
      // print "<pre>"; print_r( $defaultValues ); print "</pre>\n";
1142
      $idColumn = $tableInfo['key field'];
1143
      $sql = "SELECT * FROM " . $tableInfo['table name'] . ($whereClause ? " where $whereClause" : '');
1144
      $data = queryDatabaseExtended($sql);
1145
      // Now, create a table to display this child
1146
      // we will create a single td, that colspans everything else, and put the table into it
1147
      // simultaneously, let's create a blank line so the user can fill it in
1148
      $blankLine = '';
1149
      $result .= "<table border='1'>\n";
1150
      $result .= "<caption>" . ( $tableInfo['display name'] ? $tableInfo['display name'] : $tableInfo['table name'] ) . "</caption>\n";
1151
      $result .= "<thead bgcolor='lightGray'><tr>\n";
18 rodolico 1152
      // create a key for adding a new entry. This is recognized by updateData and insertData. We will tag all INPUT's in the insert row
1153
      // with this.
1154
      $key = CHILD_KEY_DELIMITER . CHILD_KEY_TAG . CHILD_KEY_DELIMITER . $tableInfo['table name'] . CHILD_KEY_DELIMITER . CHILD_KEY_INSERT_TAG;
17 rodolico 1155
      foreach ( $tableInfo['field info'] as $column => $value ) {
1156
         if ( $column == $idColumn ) { continue; } // we assume the $idColumn is auto-populated
1157
         if ( $defaultValues[$column] ) {  // this is one of the read-only fields
18 rodolico 1158
            $blankLine .= "<input type='hidden' name='" . $column . $key . "' value='$defaultValues[$column]'>\n";
17 rodolico 1159
         } else {
1160
            $result .= '<th>';
1161
            $result .= $value['display name'] ? $value['display name'] : $column;
1162
            $result .= '</th>';
18 rodolico 1163
            $blankLine .= '<td>' . makeAddFieldHTML ( $value, $column . $key ) . '</td>';
17 rodolico 1164
         }
1165
      }
1166
      $result .= "</tr></thead>\n";
1167
      $result .= '<tr>' . $blankLine . '</tr>';
1168
      // ok, we have a pretty header, now let's do all the actual data
1169
      if ($data) { // if we have some data to display
1170
         foreach ( $data['data'] as $info ) {
1171
               $result .= '<tr>';
18 rodolico 1172
               // create a special key so updateData will be able to recognize these rows.
1173
               $key = CHILD_KEY_DELIMITER . CHILD_KEY_TAG . CHILD_KEY_DELIMITER . $tableInfo['table name'] . CHILD_KEY_DELIMITER . $info[$idColumn];
17 rodolico 1174
               foreach ($tableInfo['field info'] as $field => $value) {
1175
                  if ( $field == $idColumn ) { continue; }
1176
                  if ( $defaultValues[$field] ) { // if this is the linkage to the parent, don't change it. But, we need it for the post.
1177
                     $result .= "<input type='hidden' name='" . $field . $key . "' value='$defaultValues[$field]'>\n";
1178
                  } else {
1179
                     $result .= "<td>";
1180
                     $result .= makeEditFieldHTML ($value, $info[$field], $field . $key );
1181
                     $result .= "</td>\n";
1182
                  }
1183
               }
1184
               $result .= '</tr>';
1185
         } 
1186
      }
1187
      $result .= "</table><!--save--></td></tr>\n";
1188
      return $result;
1189
   }
1190
 
1191
 
1192
 
1 rodolico 1193
   function makeList( $currentDB, $sql, $display_list, $keyfield ) {
1194
     $result = '';
1195
     #$data = mysql_query($sql) or die(mysql_error()); 
1196
     $result .= "<table cellpadding=3>";
1197
     $result .= '<tr>';
1198
     foreach ($display_list as $field ) {
1199
        $result .= "<th>" . $field . "</th> "; 
1200
     }
1201
     $result .= "</tr>\n";
1202
     $result .= "<td colspan=5 align=right><a href=" .$_SERVER['PHP_SELF']. "?currentdb=$currentDB&mode=add>Add</a></td>";
1203
      $data = queryDatabaseExtended($sql);
1204
      foreach ( $data['data'] as $info ) {
1205
#     while($info = mysql_fetch_array( $data ))  {
1206
        $result .= '<tr>';
1207
        foreach ($display_list as $field ) {
1208
           $result .= "<td>" . $info[$field] . "</td> "; 
1209
        }
1210
        $result .= "<td><a href=" . $_SERVER['PHP_SELF'] . "?id=" . $info[$keyfield] .  "&currentdb=$currentDB&mode=edit>Edit</a></td>"; 
1211
        $result .= "<td><a href=" .$_SERVER['PHP_SELF']. "?id=" . $info[$keyfield] . "&currentdb=$currentDB&mode=remove>Remove</a></td></tr>";
1212
     } 
1213
     $result .= "</table>"; 
1214
     return $result;
1215
   }
1216
 
1217
   /* 
1218
      function is called after information is modified via the editData function above.
1219
      Strictly takes the information from the form, then updates the database.
17 rodolico 1220
      Will add $suffix (if defined) to all field names to get information from form. This allows
1221
      us to process multiple entries of the same data. For example, if we have an HTML table that
1222
      has entries in the form fieldname-id, fieldname will be taken from $tableInfo, and "-id" will
1223
      be appended when getting information from the form.
1 rodolico 1224
   */
17 rodolico 1225
   function updateData( $tableInfo, $id, $suffix = '' ) {
1 rodolico 1226
      $sql = '';    // we will build the resulting SQL here
1227
      $result = '';   // our output string, ie what we will be sending back to the calling routine
1228
      $fileName = ''; // used to store the modified file name, if the field has a file upload
1229
      // for each field in the table definition
1230
      foreach ($tableInfo['field info'] as $field => $value) {
1231
         if ( $value['type'] == 'file' && $_FILES[$field]['name'] ) {
17 rodolico 1232
            $fileName = saveFilesUploaded( $field . $suffix );
1 rodolico 1233
            if ( ! $fileName ) { 
1234
               $result .=  "Error Saving File $field: " . FileErrorMessage($_FILES[$field]['error']) . "\n<br>";
1235
            }
1236
         }
17 rodolico 1237
         if ( isset($_POST[$field . $suffix]) || $_FILES[$field]['name'] ) {
9 rodolico 1238
            if ( $value['type'] == 'password' && strlen($_POST[$field]) == 0 ) { // we don't update passwords unless they put something in
1239
               continue;
1240
            }
1 rodolico 1241
            if ( $sql ) { $sql .= ','; }   // put in a comma if we already have info in the $sql
1242
            $fieldList .= $field;
17 rodolico 1243
            if ( $_POST[ $field . $suffix] ) {
1244
               if ( $_POST[$field . $suffix] == CONSTANT_NO_VALUE_DROPDOWN ) {
1 rodolico 1245
                  $sql .= $field . '= NULL';
1246
               } elseif ($value['type'] == 'password') {
17 rodolico 1247
                  $sql .= $field . '=' . 'md5(' . makeQuerySafe($_POST[$field . $suffix]) . ')';
1 rodolico 1248
               } else {
17 rodolico 1249
                  $sql .= $field . "=" . makeQuerySafe($_POST[$field . $suffix]);
1 rodolico 1250
               }
15 rodolico 1251
            } else { // if no value entered on form, set it to null if possible, otherwise set it to an empty string
54 rodolico 1252
               $sql .= $field . "=" . makeQuerySafe($fileName, $value['default'] === null || strtolower($value['default']) == 'null' );
1 rodolico 1253
            }
1254
         }
1255
      }
1256
      // the sql created above needs some stuff added, do that here. We will put the "update" and table name, then
1257
      // limit based upon the id passed in.
1258
      $result = doSQL( 'update '. $tableInfo['table name'] . ' set ' . $sql . " where " . $tableInfo['key field'] . " = $id " );
1259
      if ($tableInfo['complex join']) { // we possibly had a change in the multi table
1260
         foreach ($tableInfo['complex join'] as $table => $value) {
1261
            $result .= doSQL ('delete from ' . $value['join table']['table name'] . ' where ' . $value['join table']['my link'] . '=' . $id );
1262
            $currentItem = $value['values table']['table name'];
17 rodolico 1263
            $items = $_POST[$currentItem . $suffix];
1 rodolico 1264
            $sql = '';
1265
            foreach ( $items as $item => $secondary_key ) {
1266
               $result .= doSQL(
1267
                                 'insert into ' . $value['join table']['table name'] . '(' .
1268
                                 $value['join table']['values link'] . ',' . $value['join table']['my link'] .
1269
                                 ") values ($secondary_key, $id)"
1270
               );
1271
            }
1272
         } // foreach
1273
      } // if
18 rodolico 1274
      // Now, if this table has children, let's see if function editDataTable was used to create a table of children to work with. 
1275
      // if so, we will recursively call ourself to update those tables also.
1276
      if ( $tableInfo['child tables'] ) {
1277
         global $DATABASE_DEFINITION;
1278
         foreach ( $tableInfo['child tables'] as $tableName => $information ) {
1279
            $regex = CHILD_KEY_DELIMITER . CHILD_KEY_TAG . CHILD_KEY_DELIMITER . $tableName . CHILD_KEY_DELIMITER . '(\d+)';
1280
            $processed = array();
1281
            foreach ( $_POST as $parameter => $value) {
1282
               if ( preg_match( "/$regex/", $parameter, $returnValues ) ) {
1283
                  //print_r($returnValues); print "<br />";
1284
                  $keyField = $returnValues[1];
1285
                  if ( ! $processed[$keyField] ) { // found a key we haven't processed yet
1286
                     //print "Would update $tableName using key $keyField<br />\n";
1287
                     //print "<pre>" ; print_r ($DATABASE_DEFINITION[$tableName]); print "</pre>\n";
1288
                     updateData( $DATABASE_DEFINITION[$tableName], // process the row found
1289
                                 $keyField, 
1290
                                 CHILD_KEY_DELIMITER . CHILD_KEY_TAG . CHILD_KEY_DELIMITER . $tableName . CHILD_KEY_DELIMITER . $keyField );
1291
                     $processed[$keyField] = 1; // mark it as processed
1292
                  }
1293
               }
1294
            }
1295
            // now, see if they added any records
1296
            $key = CHILD_KEY_DELIMITER . CHILD_KEY_TAG . CHILD_KEY_DELIMITER . $tableName . CHILD_KEY_DELIMITER . CHILD_KEY_INSERT_TAG;
1297
            foreach ( $DATABASE_DEFINITION[$tableName]['new record indicator'] as $columnName ) {
1298
               if ( $_POST[$columnName . $key] ) { // yes, at least one of them has been changed
1299
                  insertData( $DATABASE_DEFINITION[$tableName], $key );
1300
                  break;
1301
               } // if
1302
            } // foreach
1303
         } // foreach
1304
      } // if
1305
      return true;
1 rodolico 1306
   }
1307
 
1308
   /*
1309
      function is called after addData. This does the actual insert into the database
1310
   */
17 rodolico 1311
   function insertData ( $tableInfo, $suffix = '' ) {
1 rodolico 1312
      $result = '';
1313
      $sql = '';
18 rodolico 1314
      $fieldList = array();
1315
      $valueList = array();
1 rodolico 1316
      $fileName = '';
1317
      foreach ($tableInfo['field info'] as $field => $value) {
35 rodolico 1318
         $canBeNull = (strtolower($value['default']) == 'null');
1 rodolico 1319
         if ( $value['type'] == 'file' && $_FILES[$field]['name'] ) {
1320
            $fileName = saveFilesUploaded( $field );
1321
            if ( ! $fileName ) { 
1322
               $result .=  "Error Saving File $field: " . FileErrorMessage($_FILES[$field]['error']) . "\n<br>";
1323
            }
1324
         }
17 rodolico 1325
         if ( $_POST[$field . $suffix] || $_FILES[$field]['name'] ) {
18 rodolico 1326
            $fieldList[] = $field;
17 rodolico 1327
            if ( $_POST[$field . $suffix] ) {
1 rodolico 1328
               if ( $value['type'] == 'password' ) {
35 rodolico 1329
                  $valueList[] = 'md5(' . makeQuerySafe($_POST[$field . $suffix], $canBeNull) . ')';
1 rodolico 1330
               } else {
35 rodolico 1331
                  $valueList[] = makeQuerySafe($_POST[$field . $suffix], $canBeNull);
1 rodolico 1332
               }
1333
            } else {
35 rodolico 1334
               $valueList[] = makeQuerySafe($fileName, $canBeNull);
1 rodolico 1335
            }
35 rodolico 1336
         } elseif ($value['default'] ) { // we didn't have a value, so if there is a default let's use it.
18 rodolico 1337
            $fieldList[] = $field;
35 rodolico 1338
            $valueList[] = makeQuerySafe($value['default'], $canBeNull );
1 rodolico 1339
         }
1340
      }
18 rodolico 1341
      $sql = "Insert into " . $tableInfo['table name'] . '(' . implode(',',$fieldList) . ') values (' . implode(',', $valueList) . ')';
35 rodolico 1342
      // print "<pre>$sql\n</pre>";
1343
      // return '';
18 rodolico 1344
      $result = doSQL( $sql );
1 rodolico 1345
      if ($tableInfo['complex join']) { // we possibly had a change in the multi table
1346
         foreach ($tableInfo['complex join'] as $table => $value) {
1347
            $result .= doSQL ('delete from ' . $value['join table']['table name'] . ' where ' . $value['join table']['my link'] . '=' . $id );
1348
            $currentItem = $value['values table']['table name'];
17 rodolico 1349
            $items = $_POST[$currentItem . $suffix];
1 rodolico 1350
            $sql = '';
1351
            foreach ( $items as $item => $secondary_key ) {
35 rodolico 1352
               $result .= doSQL( 'insert into ' . $value['join table']['table name'] . '(' .
1 rodolico 1353
                                 $value['join table']['values link'] . ',' . $value['join table']['my link'] .
1354
                                 ") values ($secondary_key, $id)"
1355
               );
1356
            }
1357
         } // foreach
1358
      } // if
1359
      return $result;
1360
   }
35 rodolico 1361
 
1 rodolico 1362
   function doAdmin() {
1363
      global $DATABASE_DEFINITION;
1364
      foreach ( $DATABASE_DEFINITION as $key => $field ) {
1365
        print '<li><a href=' . $_SERVER['PHP_SELF'] . '?currentdb=' . $field['table name'] . '>' . ($field['display name'] ? $field['display name'] : $field['table name']) . '</a></li>';
1366
      }
1367
      print '</ul>';
1368
 
1369
      $currentDB = $_GET['currentdb'];
1370
      if (! $currentDB ) {
1371
        $currentDB = $_POST['currentdb'];
1372
        if (! $currentDB ) {
1373
            $currentDB = DEFAULT_TABLE;
1374
        }
1375
      }
1376
      $dbDisplayName = $DATABASE_DEFINITION[$currentDB]['display name'] ? $DATABASE_DEFINITION[$currentDB]['display name'] : $currentDB;
1377
      // load our two global parameters, check for get, then post
1378
      $id = $_GET['id'];
1379
      $mode = $_GET['mode'];
1380
      if (! $id ) { $id = $_POST['id']; }
1381
      if (! $mode ) { $mode = $_POST['mode']; }
1382
      $mode = escapeshellcmd( $mode );
1383
      $id = escapeshellcmd( $id );
1384
 
1385
      if ( $mode=="add") {
1386
         Print '<h2>Add $dbDisplayName</h2>';
1387
         print addData( $DATABASE_DEFINITION[$currentDB] );
1388
      } 
1389
 
1390
      if ( $mode=="added") 
1391
      {
1392
        print insertData( $DATABASE_DEFINITION[$currentDB] );
1393
        print "Record Added";
1394
      }
1395
      if ( $mode=="edit") 
1396
      { 
1397
        print "<h2>Edit $dbDisplayName</h2>";
1398
        print editData( $DATABASE_DEFINITION[$currentDB], $id );
1399
      } 
1400
 
1401
      if ( $mode=="edited") { 
1402
      updateData( $DATABASE_DEFINITION[$currentDB], $id );
1403
      Print "$currentDB Updated!<p>";
1404
      }
1405
      if ( $mode=="remove") {
1406
        print deleteData( $DATABASE_DEFINITION[$currentDB], $id );
1407
        Print "$currentDB has been removed <p>";
1408
      }
1409
      Print "<h2>$dbDisplayName</h2><p>";
1410
 
1411
      print makeList( $currentDB, $DATABASE_DEFINITION[$currentDB]['display query'], $DATABASE_DEFINITION[$currentDB]['display columns'], $DATABASE_DEFINITION[$currentDB]['key field'] );
1412
   }
1413
 
1414
/*
1415
   function will encrypt $message using the key whose fingerprint is $key_fingerprint
1416
   in the gpg store in $homedir.
1417
 
1418
   To get the fingerprint of a key, execute
1419
      gpg --homedir $homedir --fingerprint (replacing $homedir with the .gpg directory)
1420
 
1421
   returns the encrypted string, or false if there was an error
1422
 
1423
   Ensure $homedir can be read by the web server
1424
 
1425
   Note, this function requires the PHP interface to gpgme be installed. It is named
1426
   gnupg, and is available with the following command:
1427
      pecl install gnupg (then, install in php.ini as the instructions say)
1428
   Under Debian and Ubuntu, you must have the php dev and gpgme packages installed also
1429
      apt-get install php5-dev libgpgme11-dev libgpg-error-dev libgpgme11
1430
 
1431
  Example:
1432
  print gpg_encrypt_information( '76DDD066339769A61F0FF8EEB9563752960C9534', 
1433
                                 'just a test',
1434
                                 '/home/http/.gnupg' );
1435
 
1436
*/
1437
function gpg_encrypt_information( $key_fingerprint, $message, $gpgdir = '' ) {
1438
  if (strlen($gpgdir) == 0 ) {
1439
     $gpgdir = GPGDIR;
1440
  }
1441
  putenv("GNUPGHOME=$gpgdir");
1442
  $res = gnupg_init();
1443
  //print "$res<br>\n";
1444
  if ( gnupg_addencryptkey($res,$key_fingerprint) ) {
1445
    $enc = gnupg_encrypt($res, $message);
1446
    return $enc;
1447
  } else { // we failed somewhere
1448
    print "Failed to find key in $homedir for key $key_fingerprint<br>\n";
1449
    return false;
1450
  }
1451
} // function gpg_encrypt_information
1452
 
1453
// if worker_id is null and the file we are calling is not login,
1454
// redirect to login
1455
 
1456
/*if ( ! $_SESSION['worker_id'] && basename($_SERVER['PHP_SELF']) != $LOGIN_PAGE) {
1457
   redirectPage($LOGIN_PAGE,array('message'=>'Session Timeout, Please Log In'));
1458
}*/
1459
 
1460
 
43 rodolico 1461
?>