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
 
34 rodolico 16
   define(REVISION, '2.17');
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
   }
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=''>";
34 rodolico 781
            } elseif ($columnDef['type'] == 'datetime') {
782
               $value = $columnDef['default'];
783
               if ( $columnDef['required'] and ! $value ) {
784
                  $value = date('Y-m-d');
785
               }
786
               $result .= "<input type='text' name='$fieldName' size='$displayWidth' maxlength='$maxWidth' value='$value'>";
17 rodolico 787
            } elseif ($columnDef['type'] == 'password') {
788
               $result .= "<input type='text' name='$fieldName' size='$displayWidth' maxlength='$maxWidth' value=''>";
789
            } elseif ( $columnDef['type'] == 'text' ) {
790
               $width = $columnDef['width'] ? $columnDef['width'] : MAX_INPUT_FIELD_DISPLAY;
791
               $rows = $columnDef['height'] or DEFAULT_TEXTAREA_HEIGHT;
792
               $result .= "<textarea name='$fieldName' rows='$rows' cols='$width'>" . $existingValue . "</textarea>";
793
            } elseif ( $columnDef['type'] == 'file' ) {
794
               $result .= "<input type='file' name='$fieldName' value=''>";
795
            } elseif ( $columnDef['type']  == 'lookup' ) {
796
               $result .= "<select name='$fieldName'>";
797
               $result .= makeDropDown ( $columnDef['table'], $columnDef['keyfield'], $columnDef['display_field'], ( $default ? $default : 0 ) );
798
               $result .= "</select>";
799
            } elseif ( $columnDef['type']  == 'bool' ) {
800
               $result .= "<input type='radio' name='$fieldName' value='1'";
801
               $result .= ">True<input type='radio' name='$fieldName' value='0'";
802
               $result .= " checked>False";
803
            } else {
804
               $result .= "<input type='text' name='$fieldName' value=''>";
805
            }
806
         }
807
         return $result;
808
   }
809
 
1 rodolico 810
   function addData ( $tableInfo ) {
811
      $maxFileSize = min(HumanReadable2Number(MAX_UPLOAD_FILE_SIZE),HumanReadable2Number(ini_get("upload_max_filesize")));
812
      $result = '';
813
      $result .= "<p><form enctype='multipart/form-data' action='" . $_SERVER['PHP_SELF'] . "' method='post'>";
814
      $result .= "<input type='hidden' name='currentdb' value='" . $tableInfo['table name'] . "' />";
815
      $result .= "<input type='hidden' name='MAX_FILE_SIZE' value='$maxFileSize' />";
816
      $result .= '<table border="1">';
817
      foreach ($tableInfo['field info'] as $field => $value) {
818
         $displayName = $value['display name'] ? $value['display name'] : $field; 
819
         $result .= "<tr><td valign='top'>$displayName";
820
         if ( $value['type'] == 'file' ) {
821
            $result .= "<br><font size='-2'>Max Size " . Number2HumanReadable($maxFileSize) . "</font>";
822
         }
823
         $result .= "</td><td>";
17 rodolico 824
         $result .= makeAddFieldHTML ( $value, $field );
825
 
1 rodolico 826
         $result .= "</td></tr>\n";
827
      }
828
      // process any multi selects we may have
829
      if ($tableInfo['complex join']) { 
830
         foreach ($tableInfo['complex join'] as $table => $value) {
831
            $result .= '<tr><td>' . $table . '</td><td>';
832
            $result .= makeMultiSelect( $tableInfo['table name'], $tableInfo['key field'], $id, $value);
833
            $result .= '</td></tr>';
834
         } // foreach
835
      } // if
836
      $result .= "<tr><td colspan='2' align='center'><input type='submit' /></td></tr>
837
      <input type=hidden name='mode' value='added' /> 
838
      <input type=hidden name='id' value='"; 
839
      $result .= $id; 
840
      $result .= "'></table></form> <p>"; 
841
      return $result;
842
   }
843
 
844
  function saveFilesUploaded( $fieldName ) {
845
     $result = '';
846
     $uploaddir =  $_SERVER['DOCUMENT_ROOT'] . IMAGE_DIRECTORY;
847
     $result = fixFileName( basename($_FILES[$fieldName]['name']) );
848
     if (! move_uploaded_file($_FILES[$fieldName]['tmp_name'], $uploaddir . $result)) {
849
       $result = '';
850
   }
851
     return $result;
852
  }
853
 
854
 
855
  function makeDropDown ( $table, $index_field, $display_field = '', $keyvalue = '' ) {
856
     /*
857
       this executes a query on $table (using $index_field and $display_field), then
858
       uses the result to populate a list of <option> tags suitable for inclusion in
859
       a <SELECT>. If $index_field for a row equals $keyvalue, that option has its
860
       SELECT paramter turned on
861
     */
862
     $returnValue = '';
863
     if ( $display_field ) { // they are passing in a table, index field, display field and key value
864
        $sql = "select $index_field,$display_field from $table";
865
     } else { // in the two parameter form, first parameter is query, second is keyvalue
866
        $sql = $table; 
867
        $keyvalue = $index_field;
868
     }
869
     $data = queryDatabaseExtended($sql);
13 rodolico 870
     if ( ! $data ) {
871
        $returnValue = '<option>No Values Found</option>\n';
872
     } else {
873
         $index_field = $data['meta'][0]['name'];
874
         $display_field = $data['meta'][1]['name'];
875
         foreach ($data['data'] as $info) {
876
            $returnValue .= "<option value='" . $info[$index_field] . "'";
877
            if ( $info[$index_field] == $keyvalue ) { 
878
               $returnValue .= ' selected' ; 
879
            }
880
            $returnValue .= '>' . $info[$display_field] . "</option>\n";
881
         }
1 rodolico 882
     }
883
     return $returnValue;
884
  }
885
 
886
  function makeMultiSelect ( $thisTable, $thisKeyfield, $thisValue, $multiSelectDefinition ){
887
      /*
888
         This is some funky code that creates a multi select box for when the current table has a one to many relationship
889
         with another table through an intermediate table, ie professionals joined to projects through an intermediate table,
890
         professionals_projects.
891
 
892
         It creates a query of the form
893
            select dislayfield, keyfield, nullfield
894
            from foreign_table left outer join
895
                  (this_table join joining_table on join_condition)
896
                  on join_condition
897
            where this_table.keyfield = this_record_id;
898
 
899
         Display Field generally comes from the foreign table, as does keyfield. A multi select box is created which contains
900
         the keyfield as the value and the display field displayed. If nullfield is not null, the item is option is selected.
901
 
902
         The following real world example may help:
903
            table professionals
904
                professionals_id (key field)
905
                name             (the name of the professional)
906
            table projects (the current one being edited)
907
                projects_id      (key field)
908
                other stuff
909
            table projects_professionals
910
               projects_id       (fk into projects)
911
               professionals_id   (fk into professionals)
912
         A query such as
913
            select professionals.professionals_id, professionals.name, professionals_projects.projects_id
914
            from professionals left outer join
915
                  (projects join professionals_projects on projects.project_id = professionals_projects.projects_id)
916
                  on professionals.professionals_id = professionals_projects.professionals_id
917
            where projects.project_id = $id;
918
         would return a row for every entry in the professionals table, but with a null value in the projects_id
919
         column if there was no matching entry in the professionals_projects table. This can be used to build
920
         the select
921
      */
922
      if ($thisValue) {
923
         // first build the query
924
         $sql = 'select ';
925
         $sql .= $multiSelectDefinition['values table']['table name'] . '.' . $multiSelectDefinition['values table']['display field'] . ',' ;
926
         $sql .= $multiSelectDefinition['values table']['table name'] . '.' . $multiSelectDefinition['values table']['key field'] . ', ' ;
927
         $sql .= $multiSelectDefinition['null field'] . ' ';
928
         $sql .= 'from ' . $multiSelectDefinition['values table']['table name'] . ' left outer join (';
929
         $sql .= $thisTable . ' join ' . $multiSelectDefinition['join table']['table name'] . ' on ';
930
         $sql .= $multiSelectDefinition['join table']['join condition'] . ') on ';
931
         $sql .= $multiSelectDefinition['values table']['join condition'] . " where $thisTable.$thisKeyfield  = $thisValue";
932
      } else {
933
         $sql = 'select ';
934
         $sql .= $multiSelectDefinition['values table']['table name'] . '.' . $multiSelectDefinition['values table']['display field'] . ',' ;
935
         $sql .= $multiSelectDefinition['values table']['table name'] . '.' . $multiSelectDefinition['values table']['key field'] . ', ' ;
936
         $sql .= ' null ';
937
         $sql .= 'from ' . $multiSelectDefinition['values table']['table name'];
938
      }
939
      print "<pre>$sql</pre>";
940
      // now, run it
941
      $result = "\n<SELECT name='" . $multiSelectDefinition['values table']['table name'] . "[]' multiple>\n";
942
      $data = queryDatabaseExtended($sql);
943
      foreach ( $data['data'] as $info ) {
944
      #$data = mysql_query( $sql ) or die(mysql_error());
945
      #while ( $info = mysql_fetch_array( $data ) ) {
946
         /*
947
            we will refer to fields by number due to the inconsistency of labeling returned rows, ie the query may
948
            request table.fieldname or simply fieldname, but the result set will always call it simply fieldname
949
            since we control the query, we know that field 0 is the display name, field 1 is the keyfield and
950
            field 2 is the field that will be null or not
951
         */
952
         $result .= "<option value=" . $info[1] ;
953
         if ($info[2]) { $result .= " selected"; }
954
         $result .= '>' . $info[0] . "</option>\n";
955
      } // while
956
      $result .= "</SELECT>\n";
957
      return $result;
958
  }
959
 
17 rodolico 960
   function makeEditFieldHTML ($columnDef, $existingValue, $fieldName ) {
961
         if ( $columnDef['readonly'] ) {
962
            $result .= $existingValue;
1 rodolico 963
         } else {
17 rodolico 964
            if ( $columnDef['type']  == 'string' ) {
965
               $maxWidth = $columnDef['width'] or MAX_INPUT_FIELD_DISPLAY;
1 rodolico 966
               $displayWidth = $maxWidth < MAX_INPUT_FIELD_DISPLAY ? $maxWidth : MAX_INPUT_FIELD_DISPLAY;
17 rodolico 967
               $result .= "<input type='text' name='$fieldName' size='$displayWidth' maxlength='$maxWidth' value='" . $existingValue . "'>";
968
            } elseif ( $columnDef['type'] == 'password') {
969
               $maxWidth = $columnDef['width'] or MAX_INPUT_FIELD_DISPLAY;
1 rodolico 970
               $displayWidth = $maxWidth < MAX_INPUT_FIELD_DISPLAY ? $maxWidth : MAX_INPUT_FIELD_DISPLAY;
17 rodolico 971
               $result .= "<input type='text' name='$fieldName' size='$displayWidth' maxlength='$maxWidth' value=''>";
972
            } elseif ( $columnDef['type'] == 'text' ) {
973
               $width = $columnDef['width'] ? $columnDef['width'] : MAX_INPUT_FIELD_DISPLAY;
974
               $rows = $columnDef['height'] or DEFAULT_TEXTAREA_HEIGHT;
975
               $result .= "<textarea name='$fieldName' rows='$rows' cols='$width'>" . $existingValue . "</textarea>";
976
            } elseif ( $columnDef['type'] == 'file' ) {
977
               $result .= "<input type='hidden' name='MAX_FILE_SIZE' value=value'" . MAX_UPLOAD_FILE_SIZE . "' />";
978
               if ( $columnDef['filetype'] == 'picture' ) {
979
                  $result .= "<img src='" . IMAGE_DIRECTORY . $existingValue . "' height='" . EDIT_IMAGE_HEIGHT . "' alt='Image'>";
1 rodolico 980
               }
981
               $result .= "<br>";
17 rodolico 982
               $result .= "<input type='file' name='$fieldName' value='" . $existingValue . "'>";
983
            } elseif ( $columnDef['type']  == 'lookup' ) {
984
               $result .= "<select name='$fieldName'>";
985
               if ( $columnDef['null_ok'] ) {
1 rodolico 986
                  $result .= '<option value="' . CONSTANT_NO_VALUE_DROPDOWN . '">' . CONSTANT_NO_VALUE_DROPDOWN . '</option>';
987
               }
17 rodolico 988
               if ($columnDef['query']) { // they want to pass a query, so we'll do that. Query has key in first column, display in second
989
                  $result .= makeDropDown ($columnDef['query'], $existingValue );
1 rodolico 990
               } else { // no query, so we give the table name, keyfield, and display field
17 rodolico 991
                  $result .= makeDropDown ( $columnDef['table'], $columnDef['keyfield'], $columnDef['display_field'], $existingValue );
1 rodolico 992
               } 
993
               $result .= "</select>";
17 rodolico 994
            } elseif ( $columnDef['type']  == 'bool' ) {
995
               $result .= "<input type='radio' name='$fieldName' value='1'";
996
               if ( $existingValue ) {
1 rodolico 997
                  $result .= ' checked';
998
               }
17 rodolico 999
               $result .= ">True<input type='radio' name='$fieldName' value='0'";
1000
               if ( ! $existingValue ) {
1 rodolico 1001
                  $result .= ' checked';
1002
               }
1003
               $result .= ">False";
1004
            } else {
17 rodolico 1005
               $result .= "<input type='text' name='$fieldName' value='" . $existingValue . "'>";
1 rodolico 1006
            }
1007
         }
17 rodolico 1008
         return $result;
1009
   }
1010
 
1011
   function editData ( $tableInfo, $id ) {
1012
      $maxFileSize = min(HumanReadable2Number(MAX_UPLOAD_FILE_SIZE),HumanReadable2Number(ini_get("upload_max_filesize")));
1013
 
1014
      $sql = "SELECT * FROM " . $tableInfo['table name'] . " where " . $tableInfo['key field'] . " = $id";
1015
 
1016
      // $result =  "<pre>$sql</pre><br />";
1017
      $result .= "<p><form enctype='multipart/form-data' action='" . $_SERVER['PHP_SELF'] . "' method='post'>"; 
1018
      $result .= "<input type='hidden' name='currentdb' value='" . $tableInfo['table name'] . "' />";
1019
      $result .= "<input type='hidden' name='MAX_FILE_SIZE' value='$maxFileSize' />";
1020
      $result .= '<table border="1">';
1021
      $data = queryDatabaseExtended($sql);
1022
      $info = $data['data'][0];
1023
      foreach ($tableInfo['field info'] as $field => $value) {
1024
         $displayName = $value['display name'] ? $value['display name'] : $field; 
1025
         $result .= "<tr><td valign='top'>$displayName";
1026
         if ( $value['type'] == 'file' ) {
1027
            $result .= "<br><font size='-2'>Max Size " . Number2HumanReadable($maxFileSize) . "</font>";
1028
         }
1029
         $result .= "</td><td>";
1030
         $result .= makeEditFieldHTML ($value, $info[$field], $field );
1 rodolico 1031
         $result .= "</td></tr>\n";
1032
      }
1033
 
1034
      global $DATABASE_DEFINITION;
1035
      // process any multi selects we may have
1036
      if ($tableInfo['complex join']) { 
1037
         foreach ($tableInfo['complex join'] as $table => $value) {
1038
            if ($value['values table']['key field']) {
1039
               $valueQuery = 'select ' . $value['values table']['key field'] . ',' . $value['values table']['display field'] . ' from ' . $value['values table']['table name'];
1040
            } else {
1041
               $valueQuery = $DATABASE_DEFINITION[$value['values table']['table name']]['display query'];
1042
            }
1043
            $selectedFieldsQuery = 'select ' .  $value['join table']['values link'] .  ' from ' .  $value['join table']['table name'] . ' where ' . $value['join table']['my link'] . " = $id";
1044
            $result .= "<tr><td>$table</td><td>\n";
1045
            $result .= "\n<SELECT name='" . $value['values table']['table name'] . "[]' multiple>";
1046
            $result .= queryToSelect( $valueQuery, $selectedFieldsQuery);
1047
            $result .= '</select>';
1048
            $result .= '</td></tr>';
1049
         } // foreach
1050
      } // if
1051
 
17 rodolico 1052
     if ( $tableInfo['child tables'] ) { // process any children tables we may have
1053
        foreach ( $tableInfo['child tables'] as $table => $value ) {
1054
           $idColumn = $thisTableDef['key field']; // figure out which is the keyfield for the child table
1055
           // now, let's figure out what the key is that links the two. If parent key is defined, use it. Otherwise, look
1056
           // for a column with the same name our our key field
1057
           $parentKeyColumn = $value['parent key'] ? $value['parent key'] : $tableInfo['key field'];
1058
           // $result .= "Parent Key Column is $parentKeyColumn\n<br>";
1059
           $result .= "<tr><td colspan='2'>\n";
1060
           $result .= editDataTable( $DATABASE_DEFINITION[$table],    // the definition of the sub-table
1061
                                     "$parentKeyColumn=$id",          // the condition for limiting the sub-table
1062
                                     array( $parentKeyColumn => $id ) // the columns to pre-populate and mark read-only
1063
                                   );
1064
           $result .= "</td></tr>\n";
1065
        } // foreach
1066
     } // if
1 rodolico 1067
 
16 rodolico 1068
 
1 rodolico 1069
      $result .= "<tr><td colspan='2' align='center'><input type='submit' /></td></tr> 
1070
      <input type=hidden name='mode' value='edited'> 
1071
      <input type=hidden name='id' value='"; 
1072
      $result .= $id; 
1073
      $result .= "'> 
1074
      </table> 
17 rodolico 1075
      </form>";
1 rodolico 1076
      return $result;
1077
   } // editData
1078
 
17 rodolico 1079
   /* 
1080
      function will create a table with all rows and columns from the database inside it, ready for editing.
1081
      It will limit the rows shown based on $whereClause, and not allow editing of columns listed in $defaultValues
1082
      One "empty" row will be included for adding. This row will have $defaultValues filled in with $defaultValues
1083
      and will be marked read-only also.
18 rodolico 1084
      The INPUT tags created will be of the form fieldname concated with some special stuff to allow updateData and insertData
1085
      to find them. See documentation for additional information
17 rodolico 1086
   */
1087
 
1088
   function editDataTable ( $tableInfo, $whereClause, $defaultValues = '') {
1089
      // print "<pre>"; print_r( $defaultValues ); print "</pre>\n";
1090
      $idColumn = $tableInfo['key field'];
1091
      $sql = "SELECT * FROM " . $tableInfo['table name'] . ($whereClause ? " where $whereClause" : '');
1092
      $data = queryDatabaseExtended($sql);
1093
      // Now, create a table to display this child
1094
      // we will create a single td, that colspans everything else, and put the table into it
1095
      // simultaneously, let's create a blank line so the user can fill it in
1096
      $blankLine = '';
1097
      $result .= "<table border='1'>\n";
1098
      $result .= "<caption>" . ( $tableInfo['display name'] ? $tableInfo['display name'] : $tableInfo['table name'] ) . "</caption>\n";
1099
      $result .= "<thead bgcolor='lightGray'><tr>\n";
18 rodolico 1100
      // 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
1101
      // with this.
1102
      $key = CHILD_KEY_DELIMITER . CHILD_KEY_TAG . CHILD_KEY_DELIMITER . $tableInfo['table name'] . CHILD_KEY_DELIMITER . CHILD_KEY_INSERT_TAG;
17 rodolico 1103
      foreach ( $tableInfo['field info'] as $column => $value ) {
1104
         if ( $column == $idColumn ) { continue; } // we assume the $idColumn is auto-populated
1105
         if ( $defaultValues[$column] ) {  // this is one of the read-only fields
18 rodolico 1106
            $blankLine .= "<input type='hidden' name='" . $column . $key . "' value='$defaultValues[$column]'>\n";
17 rodolico 1107
         } else {
1108
            $result .= '<th>';
1109
            $result .= $value['display name'] ? $value['display name'] : $column;
1110
            $result .= '</th>';
18 rodolico 1111
            $blankLine .= '<td>' . makeAddFieldHTML ( $value, $column . $key ) . '</td>';
17 rodolico 1112
         }
1113
      }
1114
      $result .= "</tr></thead>\n";
1115
      $result .= '<tr>' . $blankLine . '</tr>';
1116
      // ok, we have a pretty header, now let's do all the actual data
1117
      if ($data) { // if we have some data to display
1118
         foreach ( $data['data'] as $info ) {
1119
               $result .= '<tr>';
18 rodolico 1120
               // create a special key so updateData will be able to recognize these rows.
1121
               $key = CHILD_KEY_DELIMITER . CHILD_KEY_TAG . CHILD_KEY_DELIMITER . $tableInfo['table name'] . CHILD_KEY_DELIMITER . $info[$idColumn];
17 rodolico 1122
               foreach ($tableInfo['field info'] as $field => $value) {
1123
                  if ( $field == $idColumn ) { continue; }
1124
                  if ( $defaultValues[$field] ) { // if this is the linkage to the parent, don't change it. But, we need it for the post.
1125
                     $result .= "<input type='hidden' name='" . $field . $key . "' value='$defaultValues[$field]'>\n";
1126
                  } else {
1127
                     $result .= "<td>";
1128
                     $result .= makeEditFieldHTML ($value, $info[$field], $field . $key );
1129
                     $result .= "</td>\n";
1130
                  }
1131
               }
1132
               $result .= '</tr>';
1133
         } 
1134
      }
1135
      $result .= "</table><!--save--></td></tr>\n";
1136
      return $result;
1137
   }
1138
 
1139
 
1140
 
1 rodolico 1141
   function makeList( $currentDB, $sql, $display_list, $keyfield ) {
1142
     $result = '';
1143
     #$data = mysql_query($sql) or die(mysql_error()); 
1144
     $result .= "<table cellpadding=3>";
1145
     $result .= '<tr>';
1146
     foreach ($display_list as $field ) {
1147
        $result .= "<th>" . $field . "</th> "; 
1148
     }
1149
     $result .= "</tr>\n";
1150
     $result .= "<td colspan=5 align=right><a href=" .$_SERVER['PHP_SELF']. "?currentdb=$currentDB&mode=add>Add</a></td>";
1151
      $data = queryDatabaseExtended($sql);
1152
      foreach ( $data['data'] as $info ) {
1153
#     while($info = mysql_fetch_array( $data ))  {
1154
        $result .= '<tr>';
1155
        foreach ($display_list as $field ) {
1156
           $result .= "<td>" . $info[$field] . "</td> "; 
1157
        }
1158
        $result .= "<td><a href=" . $_SERVER['PHP_SELF'] . "?id=" . $info[$keyfield] .  "&currentdb=$currentDB&mode=edit>Edit</a></td>"; 
1159
        $result .= "<td><a href=" .$_SERVER['PHP_SELF']. "?id=" . $info[$keyfield] . "&currentdb=$currentDB&mode=remove>Remove</a></td></tr>";
1160
     } 
1161
     $result .= "</table>"; 
1162
     return $result;
1163
   }
1164
 
1165
   /* 
1166
      function is called after information is modified via the editData function above.
1167
      Strictly takes the information from the form, then updates the database.
17 rodolico 1168
      Will add $suffix (if defined) to all field names to get information from form. This allows
1169
      us to process multiple entries of the same data. For example, if we have an HTML table that
1170
      has entries in the form fieldname-id, fieldname will be taken from $tableInfo, and "-id" will
1171
      be appended when getting information from the form.
1 rodolico 1172
   */
17 rodolico 1173
   function updateData( $tableInfo, $id, $suffix = '' ) {
1 rodolico 1174
      $sql = '';    // we will build the resulting SQL here
1175
      $result = '';   // our output string, ie what we will be sending back to the calling routine
1176
      $fileName = ''; // used to store the modified file name, if the field has a file upload
1177
      // for each field in the table definition
1178
      foreach ($tableInfo['field info'] as $field => $value) {
1179
         if ( $value['type'] == 'file' && $_FILES[$field]['name'] ) {
17 rodolico 1180
            $fileName = saveFilesUploaded( $field . $suffix );
1 rodolico 1181
            if ( ! $fileName ) { 
1182
               $result .=  "Error Saving File $field: " . FileErrorMessage($_FILES[$field]['error']) . "\n<br>";
1183
            }
1184
         }
17 rodolico 1185
         if ( isset($_POST[$field . $suffix]) || $_FILES[$field]['name'] ) {
9 rodolico 1186
            if ( $value['type'] == 'password' && strlen($_POST[$field]) == 0 ) { // we don't update passwords unless they put something in
1187
               continue;
1188
            }
1 rodolico 1189
            if ( $sql ) { $sql .= ','; }   // put in a comma if we already have info in the $sql
1190
            $fieldList .= $field;
17 rodolico 1191
            if ( $_POST[ $field . $suffix] ) {
1192
               if ( $_POST[$field . $suffix] == CONSTANT_NO_VALUE_DROPDOWN ) {
1 rodolico 1193
                  $sql .= $field . '= NULL';
1194
               } elseif ($value['type'] == 'password') {
17 rodolico 1195
                  $sql .= $field . '=' . 'md5(' . makeQuerySafe($_POST[$field . $suffix]) . ')';
1 rodolico 1196
               } else {
17 rodolico 1197
                  $sql .= $field . "=" . makeQuerySafe($_POST[$field . $suffix]);
1 rodolico 1198
               }
15 rodolico 1199
            } else { // if no value entered on form, set it to null if possible, otherwise set it to an empty string
1200
               $sql .= $field . "=" . makeQuerySafe($fileName, strtolower($value['default']) == 'null' );
1 rodolico 1201
            }
1202
         }
1203
      }
1204
      // the sql created above needs some stuff added, do that here. We will put the "update" and table name, then
1205
      // limit based upon the id passed in.
1206
      $result = doSQL( 'update '. $tableInfo['table name'] . ' set ' . $sql . " where " . $tableInfo['key field'] . " = $id " );
1207
      if ($tableInfo['complex join']) { // we possibly had a change in the multi table
1208
         foreach ($tableInfo['complex join'] as $table => $value) {
1209
            $result .= doSQL ('delete from ' . $value['join table']['table name'] . ' where ' . $value['join table']['my link'] . '=' . $id );
1210
            $currentItem = $value['values table']['table name'];
17 rodolico 1211
            $items = $_POST[$currentItem . $suffix];
1 rodolico 1212
            $sql = '';
1213
            foreach ( $items as $item => $secondary_key ) {
1214
               $result .= doSQL(
1215
                                 'insert into ' . $value['join table']['table name'] . '(' .
1216
                                 $value['join table']['values link'] . ',' . $value['join table']['my link'] .
1217
                                 ") values ($secondary_key, $id)"
1218
               );
1219
            }
1220
         } // foreach
1221
      } // if
18 rodolico 1222
      // Now, if this table has children, let's see if function editDataTable was used to create a table of children to work with. 
1223
      // if so, we will recursively call ourself to update those tables also.
1224
      if ( $tableInfo['child tables'] ) {
1225
         global $DATABASE_DEFINITION;
1226
         foreach ( $tableInfo['child tables'] as $tableName => $information ) {
1227
            $regex = CHILD_KEY_DELIMITER . CHILD_KEY_TAG . CHILD_KEY_DELIMITER . $tableName . CHILD_KEY_DELIMITER . '(\d+)';
1228
            $processed = array();
1229
            foreach ( $_POST as $parameter => $value) {
1230
               if ( preg_match( "/$regex/", $parameter, $returnValues ) ) {
1231
                  //print_r($returnValues); print "<br />";
1232
                  $keyField = $returnValues[1];
1233
                  if ( ! $processed[$keyField] ) { // found a key we haven't processed yet
1234
                     //print "Would update $tableName using key $keyField<br />\n";
1235
                     //print "<pre>" ; print_r ($DATABASE_DEFINITION[$tableName]); print "</pre>\n";
1236
                     updateData( $DATABASE_DEFINITION[$tableName], // process the row found
1237
                                 $keyField, 
1238
                                 CHILD_KEY_DELIMITER . CHILD_KEY_TAG . CHILD_KEY_DELIMITER . $tableName . CHILD_KEY_DELIMITER . $keyField );
1239
                     $processed[$keyField] = 1; // mark it as processed
1240
                  }
1241
               }
1242
            }
1243
            // now, see if they added any records
1244
            $key = CHILD_KEY_DELIMITER . CHILD_KEY_TAG . CHILD_KEY_DELIMITER . $tableName . CHILD_KEY_DELIMITER . CHILD_KEY_INSERT_TAG;
1245
            foreach ( $DATABASE_DEFINITION[$tableName]['new record indicator'] as $columnName ) {
1246
               if ( $_POST[$columnName . $key] ) { // yes, at least one of them has been changed
1247
                  insertData( $DATABASE_DEFINITION[$tableName], $key );
1248
                  break;
1249
               } // if
1250
            } // foreach
1251
         } // foreach
1252
      } // if
1253
      return true;
1 rodolico 1254
   }
1255
 
1256
   /*
1257
      function is called after addData. This does the actual insert into the database
1258
   */
17 rodolico 1259
   function insertData ( $tableInfo, $suffix = '' ) {
1 rodolico 1260
      $result = '';
1261
      $sql = '';
18 rodolico 1262
      $fieldList = array();
1263
      $valueList = array();
1 rodolico 1264
      $fileName = '';
1265
      foreach ($tableInfo['field info'] as $field => $value) {
1266
         if ( $value['type'] == 'file' && $_FILES[$field]['name'] ) {
1267
            $fileName = saveFilesUploaded( $field );
1268
            if ( ! $fileName ) { 
1269
               $result .=  "Error Saving File $field: " . FileErrorMessage($_FILES[$field]['error']) . "\n<br>";
1270
            }
1271
         }
17 rodolico 1272
         if ( $_POST[$field . $suffix] || $_FILES[$field]['name'] ) {
18 rodolico 1273
            $fieldList[] = $field;
17 rodolico 1274
            if ( $_POST[$field . $suffix] ) {
1 rodolico 1275
               if ( $value['type'] == 'password' ) {
18 rodolico 1276
                  $valueList[] = 'md5(' . makeQuerySafe($_POST[$field . $suffix]) . ')';
1 rodolico 1277
               } else {
18 rodolico 1278
                  $valueList[] = makeQuerySafe($_POST[$field . $suffix]);
1 rodolico 1279
               }
1280
            } else {
18 rodolico 1281
               $valueList[] = makeQuerySafe($fileName);
1 rodolico 1282
            }
18 rodolico 1283
         } elseif ($value['default'] && strtolower($value['default']) != 'null' ) { // we didn't have a value, so if there is a default let's use it.
1284
            $fieldList[] = $field;
1285
            $valueList[] = makeQuerySafe($value['default'] );
1 rodolico 1286
         }
1287
      }
18 rodolico 1288
      $sql = "Insert into " . $tableInfo['table name'] . '(' . implode(',',$fieldList) . ') values (' . implode(',', $valueList) . ')';
1289
      //print "<pre>$sql\n</pre>";
1290
      $result = doSQL( $sql );
1 rodolico 1291
      if ($tableInfo['complex join']) { // we possibly had a change in the multi table
1292
         foreach ($tableInfo['complex join'] as $table => $value) {
1293
            $result .= doSQL ('delete from ' . $value['join table']['table name'] . ' where ' . $value['join table']['my link'] . '=' . $id );
1294
            $currentItem = $value['values table']['table name'];
17 rodolico 1295
            $items = $_POST[$currentItem . $suffix];
1 rodolico 1296
            $sql = '';
1297
            foreach ( $items as $item => $secondary_key ) {
1298
               $result .= doSQL(
1299
                                 'insert into ' . $value['join table']['table name'] . '(' .
1300
                                 $value['join table']['values link'] . ',' . $value['join table']['my link'] .
1301
                                 ") values ($secondary_key, $id)"
1302
               );
1303
            }
1304
         } // foreach
1305
      } // if
1306
      return $result;
1307
   }
1308
 
1309
 
1310
   function doAdmin() {
1311
      global $DATABASE_DEFINITION;
1312
      foreach ( $DATABASE_DEFINITION as $key => $field ) {
1313
        print '<li><a href=' . $_SERVER['PHP_SELF'] . '?currentdb=' . $field['table name'] . '>' . ($field['display name'] ? $field['display name'] : $field['table name']) . '</a></li>';
1314
      }
1315
      print '</ul>';
1316
 
1317
      $currentDB = $_GET['currentdb'];
1318
      if (! $currentDB ) {
1319
        $currentDB = $_POST['currentdb'];
1320
        if (! $currentDB ) {
1321
            $currentDB = DEFAULT_TABLE;
1322
        }
1323
      }
1324
      $dbDisplayName = $DATABASE_DEFINITION[$currentDB]['display name'] ? $DATABASE_DEFINITION[$currentDB]['display name'] : $currentDB;
1325
      // load our two global parameters, check for get, then post
1326
      $id = $_GET['id'];
1327
      $mode = $_GET['mode'];
1328
      if (! $id ) { $id = $_POST['id']; }
1329
      if (! $mode ) { $mode = $_POST['mode']; }
1330
      $mode = escapeshellcmd( $mode );
1331
      $id = escapeshellcmd( $id );
1332
 
1333
      if ( $mode=="add") {
1334
         Print '<h2>Add $dbDisplayName</h2>';
1335
         print addData( $DATABASE_DEFINITION[$currentDB] );
1336
      } 
1337
 
1338
      if ( $mode=="added") 
1339
      {
1340
        print insertData( $DATABASE_DEFINITION[$currentDB] );
1341
        print "Record Added";
1342
      }
1343
      if ( $mode=="edit") 
1344
      { 
1345
        print "<h2>Edit $dbDisplayName</h2>";
1346
        print editData( $DATABASE_DEFINITION[$currentDB], $id );
1347
      } 
1348
 
1349
      if ( $mode=="edited") { 
1350
      updateData( $DATABASE_DEFINITION[$currentDB], $id );
1351
      Print "$currentDB Updated!<p>";
1352
      }
1353
      if ( $mode=="remove") {
1354
        print deleteData( $DATABASE_DEFINITION[$currentDB], $id );
1355
        Print "$currentDB has been removed <p>";
1356
      }
1357
      Print "<h2>$dbDisplayName</h2><p>";
1358
 
1359
      print makeList( $currentDB, $DATABASE_DEFINITION[$currentDB]['display query'], $DATABASE_DEFINITION[$currentDB]['display columns'], $DATABASE_DEFINITION[$currentDB]['key field'] );
1360
   }
1361
 
1362
/*
1363
   function will encrypt $message using the key whose fingerprint is $key_fingerprint
1364
   in the gpg store in $homedir.
1365
 
1366
   To get the fingerprint of a key, execute
1367
      gpg --homedir $homedir --fingerprint (replacing $homedir with the .gpg directory)
1368
 
1369
   returns the encrypted string, or false if there was an error
1370
 
1371
   Ensure $homedir can be read by the web server
1372
 
1373
   Note, this function requires the PHP interface to gpgme be installed. It is named
1374
   gnupg, and is available with the following command:
1375
      pecl install gnupg (then, install in php.ini as the instructions say)
1376
   Under Debian and Ubuntu, you must have the php dev and gpgme packages installed also
1377
      apt-get install php5-dev libgpgme11-dev libgpg-error-dev libgpgme11
1378
 
1379
  Example:
1380
  print gpg_encrypt_information( '76DDD066339769A61F0FF8EEB9563752960C9534', 
1381
                                 'just a test',
1382
                                 '/home/http/.gnupg' );
1383
 
1384
*/
1385
function gpg_encrypt_information( $key_fingerprint, $message, $gpgdir = '' ) {
1386
  if (strlen($gpgdir) == 0 ) {
1387
     $gpgdir = GPGDIR;
1388
  }
1389
  putenv("GNUPGHOME=$gpgdir");
1390
  $res = gnupg_init();
1391
  //print "$res<br>\n";
1392
  if ( gnupg_addencryptkey($res,$key_fingerprint) ) {
1393
    $enc = gnupg_encrypt($res, $message);
1394
    return $enc;
1395
  } else { // we failed somewhere
1396
    print "Failed to find key in $homedir for key $key_fingerprint<br>\n";
1397
    return false;
1398
  }
1399
} // function gpg_encrypt_information
1400
 
1401
// if worker_id is null and the file we are calling is not login,
1402
// redirect to login
1403
 
1404
/*if ( ! $_SESSION['worker_id'] && basename($_SERVER['PHP_SELF']) != $LOGIN_PAGE) {
1405
   redirectPage($LOGIN_PAGE,array('message'=>'Session Timeout, Please Log In'));
1406
}*/
1407
 
1408
 
1409
?>