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