Subversion Repositories php_library

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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