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