Subversion Repositories php_library

Rev

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