Subversion Repositories php_library

Rev

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