Subversion Repositories php_library

Rev

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

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