Subversion Repositories php_library

Rev

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