Subversion Repositories php_library

Rev

Rev 45 | Rev 54 | 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 ) {
631
         $hash[$key] = $key . $delimiter . $value;
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
         //print "\n$sql\n<br>";
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
1219
               $sql .= $field . "=" . makeQuerySafe($fileName, 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
?>