Subversion Repositories php_library

Rev

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