Subversion Repositories php_library

Rev

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

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