Statistiques
| Branche: | Révision :

root / src / phpMyEdit.class.php @ a9b72d88

Historique | Voir | Annoter | Télécharger (118,13 ko)

1
<?php
2

    
3
/*
4
 * phpMyEdit - instant MySQL table editor and code generator
5
 *
6
 * phpMyEdit.class.php - main table editor class definition file
7
 * ____________________________________________________________
8
 *
9
 * Copyright (c) 1999-2002 John McCreesh <jpmcc@users.sourceforge.net>
10
 * Copyright (c) 2001-2002 Jim Kraai <jkraai@users.sourceforge.net>
11
 * Versions 5.0 and higher developed by Ondrej Jombik <nepto@php.net>
12
 * Copyright (c) 2002-2006 Platon Group, http://platon.sk/
13
 * All rights reserved.
14
 *
15
 * See README file for more information about this software.
16
 * See COPYING file for license information.
17
 *
18
 * Download the latest version from
19
 * http://platon.sk/projects/phpMyEdit/
20
 */
21

    
22
/* $Platon: phpMyEdit/phpMyEdit.class.php,v 1.204 2007-09-16 12:57:07 nepto Exp $ */
23

    
24
/*  This is a generic table editing program. The table and fields to be
25
        edited are defined in the calling program.
26

27
        This program works in three passes.
28
        * Pass 1 (the last part of the program) displays the selected SQL
29
          table in a scrolling table on the screen. Radio buttons are used to
30
          select a record for editing or deletion. If the user chooses Add,
31
          Change, Copy, View or Delete buttons.
32
        * Pass 2 starts, displaying the selected record. If the user chooses
33
          the Save button from this screen.
34
        * Pass 3 processes the update and the display returns to the
35
          original table view (Pass 1).
36
*/
37

    
38
class phpMyEdit_timer /* {{{ */
39
{
40
        var $startTime;
41
        var $started;
42

    
43
        function phpMyEdit_timer($start = true)
44
        {
45
                $this->started = false;
46
                if ($start) {
47
                        $this->start();
48
                }
49
        }
50

    
51
        function start()
52
        {
53
                $startMtime      = explode(' ', microtime());
54
                $this->startTime = (double) $startMtime[0] + (double) $startMtime[1];
55
                $this->started   = true;
56
        }
57

    
58
        function end($iterations = 1)
59
        {
60
                // get the time, check whether the timer was started later
61
                $endMtime = explode(' ', microtime());
62
                if ($this->started) {
63
                        $endTime = (double)($endMtime[0])+(double)($endMtime[1]);
64
                        $dur = $endTime - $this->startTime;
65
                        $avg = 1000 * $dur / $iterations;
66
                        $avg = round(1000 * $avg) / 1000;
67
                        return $avg;
68
                } else {
69
                        return 'phpMyEdit_timer ERROR: timer not started';
70
                }
71
        }
72
} /* }}} */
73

    
74
if (! function_exists('array_search')) { /* {{{ */
75
        function array_search($needle, $haystack)
76
        {
77
                foreach ($haystack as $key => $value) {
78
                        if ($needle == $value)
79
                                return $key;
80
                }
81
                return false;
82
        }
83
} /* }}} */
84

    
85
if (! function_exists('realpath')) { /* {{{ */
86
        function realpath($path)
87
        {
88
                return $path;
89
        }
90
} /* }}} */
91

    
92
class phpMyEdit
93
{
94
        // Class variables {{{
95

    
96
        // Database handling
97
        var $hn;                // hostname
98
        var $un;                // user name
99
        var $pw;                // password
100
        var $tb;                // table
101
        var $db;                // database
102
        var $dbp;                // database with point and delimiters
103
        var $dbh;                // database handle
104
        var $close_dbh;        // if database handle should be closed
105

    
106
        // Record manipulation
107
        var $key;                // name of field which is the unique key
108
        var $key_num;        // number of field which is the unique key
109
        var $key_type;        // type of key field (int/real/string/date etc.)
110
        var $key_delim;        // character used for key value quoting
111
        var $rec;                // number of record selected for editing
112
        var $inc;                // number of records to display
113
        var $fm;                // first record to display
114
        var $fl;                // is the filter row displayed (boolean)
115
        var $fds;                // sql field names
116
        var $fdn;                // sql field names => $k
117
        var $num_fds;        // number of fields
118
        var $options;        // options for users: ACDFVPI
119
        var $fdd;                // field definitions
120
        var $qfn;                // value of all filters used during the last pass
121
        var $sfn;                // sort field number (- = descending sort order)
122
        var $cur_tab;        // current selected tab
123

    
124
        // Operation
125
        var $navop;                // navigation buttons/operations
126
        var $sw;                // filter display/hide/clear button
127
        var $operation;        // operation to do: Add, Change, Delete
128
        var $saveadd;
129
        var $moreadd;
130
        var $canceladd;
131
        var $savechange;
132
        var $morechange;
133
        var $cancelchange;
134
        var $savecopy;
135
        var $cancelcopy;
136
        var $savedelete;
137
        var $canceldelete;
138
        var $cancelview;
139

    
140
        // Additional features
141
        var $labels;                // multilingual labels
142
        var $cgi;                        // CGI variable features array
143
        var $js;                        // JS configuration array
144
        var $dhtml;                        // DHTML configuration array
145
        var $url;                        // URL array
146
        var $message;                // informational message to print
147
        var $notify;                // change notification e-mail adresses
148
        var $logtable;                // name of optional logtable
149
        var $navigation;        // navigation style
150
        var $tabs;                        // TAB names
151
        var $timer = null;        // phpMyEdit_timer object
152
        var $sd; var $ed;        // sql start and end delimiters '`' in case of MySQL
153

    
154
        // Predefined variables
155
        var $comp_ops  = array('<'=>'<','<='=>'<=','='=>'=','>='=>'>=','>'=>'>');
156
        var $sql_aggrs = array(
157
                        'sum'   => 'Total',
158
                        'avg'   => 'Average',
159
                        'min'   => 'Minimum',
160
                        'max'   => 'Maximum',
161
                        'count' => 'Count');
162
        var $page_types = array(
163
                        'L' => 'list',
164
                        'F' => 'filter',
165
                        'A' => 'add',
166
                        'V' => 'view',
167
                        'C' => 'change',
168
                        'P' => 'copy',
169
                        'D' => 'delete'
170
                        );
171
        var $default_buttons = array(
172
                        'L' => array('<<','<','add','view','change','copy','delete','>','>>','goto','goto_combo'),
173
                        'F' => array('<<','<','add','view','change','copy','delete','>','>>','goto','goto_combo'),
174
                        'A' => array('save','more','cancel'),
175
                        'C' => array('save','more','cancel'),
176
                        'P' => array('save', 'cancel'),
177
                        'D' => array('save','cancel'),
178
                        'V' => array('change','cancel')
179
                        );
180
        // }}}
181

    
182
        /*
183
         * column specific functions
184
         */
185

    
186
        function col_has_sql($k)    { return isset($this->fdd[$k]['sql']); }
187
        function col_has_sqlw($k)   { return isset($this->fdd[$k]['sqlw']) && !$this->virtual($k); }
188
        function col_has_values($k) { return isset($this->fdd[$k]['values']) || isset($this->fdd[$k]['values2']); }
189
        function col_has_php($k)    { return isset($this->fdd[$k]['php']); }
190
        function col_has_URL($k)    { return isset($this->fdd[$k]['URL'])
191
                || isset($this->fdd[$k]['URLprefix']) || isset($this->fdd[$k]['URLpostfix']); }
192
        function col_has_multiple($k)
193
        { return $this->col_has_multiple_select($k) || $this->col_has_checkboxes($k); }
194
        function col_has_multiple_select($k)
195
        { return $this->fdd[$k]['select'] == 'M' && ! $this->fdd[$k]['values']['table']; }
196
        function col_has_checkboxes($k)
197
        { return $this->fdd[$k]['select'] == 'C' && ! $this->fdd[$k]['values']['table']; }
198
        function col_has_radio_buttons($k)
199
        { return $this->fdd[$k]['select'] == 'O' && ! $this->fdd[$k]['values']['table']; }
200
        function col_has_datemask($k)
201
        { return isset($this->fdd[$k]['datemask']) || isset($this->fdd[$k]['strftimemask']); }
202

    
203
        /*
204
         * functions for indicating whether navigation style is enabled
205
     */
206

    
207
        function nav_buttons()       { return stristr($this->navigation, 'B'); }
208
        function nav_text_links()    { return stristr($this->navigation, 'T'); }
209
        function nav_graphic_links() { return stristr($this->navigation, 'G'); }
210
        function nav_up()            { return (stristr($this->navigation, 'U') && !($this->buttons[$this->page_type]['up'] === false)); }
211
        function nav_down()          { return (stristr($this->navigation, 'D') && !($this->buttons[$this->page_type]['down'] === false)); }
212

    
213
        /*
214
         * functions for indicating whether operations are enabled
215
         */
216

    
217
        function add_enabled()    { return stristr($this->options, 'A'); }
218
        function change_enabled() { return stristr($this->options, 'C'); }
219
        function delete_enabled() { return stristr($this->options, 'D'); }
220
        function filter_enabled() { return stristr($this->options, 'F'); }
221
        function view_enabled()   { return stristr($this->options, 'V'); }
222
        function copy_enabled()   { return stristr($this->options, 'P') && $this->add_enabled(); }
223
        function tabs_enabled()   { return $this->display['tabs'] && count($this->tabs) > 0; }
224
        function hidden($k)       { return stristr($this->fdd[$k]['input'],'H'); }
225
        function password($k)     { return stristr($this->fdd[$k]['input'],'W'); }
226
        function readonly($k)     { return stristr($this->fdd[$k]['input'],'R') || $this->virtual($k);     }
227
        function virtual($k)      { return stristr($this->fdd[$k]['input'],'V') && $this->col_has_sql($k); }
228

    
229
        function add_operation()    { return $this->operation == $this->labels['Add']    && $this->add_enabled();    }
230
        function change_operation() { return $this->operation == $this->labels['Change'] && $this->change_enabled(); }
231
        function copy_operation()   { return $this->operation == $this->labels['Copy']   && $this->copy_enabled();   }
232
        function delete_operation() { return $this->operation == $this->labels['Delete'] && $this->delete_enabled(); }
233
        function view_operation()   { return $this->operation == $this->labels['View']   && $this->view_enabled();   }
234
        function filter_operation() { return $this->fl && $this->filter_enabled() && $this->list_operation(); }
235
        function list_operation()   { /* covers also filtering page */ return ! $this->change_operation()
236
                                                                                && ! $this->add_operation()    && ! $this->copy_operation()
237
                                                                                && ! $this->delete_operation() && ! $this->view_operation(); }
238
        function next_operation()        { return ($this->navop == $this->labels['Next']) || ($this->navop == '>'); }
239
        function prev_operation()        { return ($this->navop == $this->labels['Prev']) || ($this->navop == '<'); }
240
        function first_operation()        { return ($this->navop == $this->labels['First']) || ($this->navop == '<<'); }
241
        function last_operation()        { return ($this->navop == $this->labels['Last']) || ($this->navop == '>>'); }
242
        function clear_operation()        { return $this->sw == $this->labels['Clear'];  }
243

    
244
        function add_canceled()    { return $this->canceladd    == $this->labels['Cancel']; }
245
        function view_canceled()   { return $this->cancelview   == $this->labels['Cancel']; }
246
        function change_canceled() { return $this->cancelchange == $this->labels['Cancel']; }
247
        function copy_canceled()   { return $this->cancelcopy   == $this->labels['Cancel']; }
248
        function delete_canceled() { return $this->canceldelete == $this->labels['Cancel']; }
249

    
250
        function is_values2($k, $val = 'X') /* {{{ */
251
        {
252
                return $val === null ||
253
                        (isset($this->fdd[$k]['values2']) && !isset($this->fdd[$k]['values']['table']));
254
        } /* }}} */
255

    
256
        function processed($k) /* {{{ */
257
        {
258
                if ($this->virtual($k)) {
259
                        return false;
260
                }
261
                $options = @$this->fdd[$k]['options'];
262
                if (! isset($options)) {
263
                        return true;
264
                }
265
                return
266
                        ($this->saveadd    == $this->labels['Save']  && stristr($options, 'A')) ||
267
                        ($this->moreadd    == $this->labels['More']  && stristr($options, 'A')) ||
268
                        ($this->savechange == $this->labels['Save']  && stristr($options, 'C')) ||
269
                        ($this->morechange == $this->labels['Apply'] && stristr($options, 'C')) ||
270
                        ($this->savecopy   == $this->labels['Save']  && stristr($options, 'P')) ||
271
                        ($this->savedelete == $this->labels['Save']  && stristr($options, 'D'));
272
        } /* }}} */
273

    
274
        function displayed($k) /* {{{ */
275
        {
276
                if (is_numeric($k)) {
277
                        $k = $this->fds[$k];
278
                }
279
                $options = @$this->fdd[$k]['options'];
280
                if (! isset($options)) {
281
                        return true;
282
                }
283
                return
284
                        ($this->add_operation()    && stristr($options, 'A')) ||
285
                        ($this->view_operation()   && stristr($options, 'V')) ||
286
                        ($this->change_operation() && stristr($options, 'C')) ||
287
                        ($this->copy_operation()   && stristr($options, 'P')) ||
288
                        ($this->delete_operation() && stristr($options, 'D')) ||
289
                        ($this->filter_operation() && stristr($options, 'F')) ||
290
                        ($this->list_operation()   && stristr($options, 'L'));
291
        } /* }}} */
292
        
293
        function debug_var($name, $val) /* {{{ */
294
        {
295
                if (is_array($val) || is_object($val)) {
296
                        echo "<pre>$name\n";
297
                        ob_start();
298
                        //print_r($val);
299
                        var_dump($val);
300
                        $content = ob_get_contents();
301
                        ob_end_clean();
302
                        echo htmlspecialchars($content);
303
                        echo "</pre>\n";
304
                } else {
305
                        echo 'debug_var()::<i>',htmlspecialchars($name),'</i>';
306
                        echo '::<b>',htmlspecialchars($val),'</b>::',"<br />\n";
307
                }
308
        } /* }}} */
309

    
310
        /*
311
         * sql functions
312
     */
313
        function sql_connect() /* {{{ */
314
        {
315
                $this->dbh = @ini_get('allow_persistent')
316
                        ? @mysql_pconnect($this->hn, $this->un, $this->pw)
317
                        : @mysql_connect($this->hn, $this->un, $this->pw);
318
        } /* }}} */
319
                
320

    
321
        function sql_disconnect() /* {{{ */
322
        {
323
                if ($this->close_dbh) {
324
                        @mysql_close($this->dbh);
325
                        $this->dbh = null;
326
                }
327
        } /* }}} */
328

    
329
        function sql_fetch(&$res, $type = 'a') /* {{{ */
330
        {
331
                if($type == 'n') $type = MYSQL_NUM;
332
                else $type = MYSQL_ASSOC;
333
                return @mysql_fetch_array($res, $type);
334
        } /* }}} */
335

    
336
        function sql_free_result(&$res) /* {{{ */
337
        {
338
                return @mysql_free_result($res);
339
        } /* }}} */
340

    
341
        function sql_affected_rows(&$dbh) /* {{{ */
342
        {
343
                return @mysql_affected_rows($dbh);
344
        } /* }}} */
345

    
346
        function sql_field_len(&$res,$field) /* {{{ */
347
        {
348
                return @mysql_field_len($res, $field);
349
        } /* }}} */
350

    
351
        function sql_insert_id() /* {{{ */
352
        {
353
                return mysql_insert_id($this->dbh);
354
        } /* }}} */
355

    
356
        function sql_limit($start, $more) /* {{{ */
357
        {
358
                return ' LIMIT '.$start.', '.$more.' ';
359
        } /* }}} */
360

    
361
        function sql_delimiter() /* {{{ */
362
        {
363
                $this->sd = '`'; $this->ed='`';
364
                return $this->sd;
365
        } /* }}} */
366

    
367

    
368
        function myquery($qry, $line = 0, $debug = 0) /* {{{ */
369
        {
370
                global $debug_query;
371
                if ($debug_query || $debug) {
372
                        $line = intval($line);
373
                        echo '<h4>MySQL query at line ',$line,'</h4>',htmlspecialchars($qry),'<hr size="1" />',"\n";
374
                }
375
                if (isset($this->db)) {
376
                        $ret = @mysql_db_query($this->db, $qry, $this->dbh);
377
                } else {
378
                        $ret = @mysql_query($qry, $this->dbh);
379
                }
380
                if (! $ret) {
381
                        echo '<h4>MySQL error ',mysql_errno($this->dbh),'</h4>';
382
                        echo htmlspecialchars(mysql_error($this->dbh)),'<hr size="1" />',"\n";
383
                }
384
                return $ret;
385
        } /* }}} */
386

    
387
        /* end of sql functions */ 
388

    
389
        function make_language_labels($language) /* {{{ */
390
        {
391
                // just try the first language and variant
392
                // this isn't content-negotiation rfc compliant
393
                $language = strtoupper($language);
394

    
395
                // try the full language w/ variant
396
                $file = $this->dir['lang'].'PME.lang.'.$language.'.inc';
397
                while (! file_exists($file)) {
398
                        $pos = strrpos($language, '-');
399
                        if ($pos === false) {
400
                                $file = $this->dir['lang'].'PME.lang.EN.inc';
401
                                break;
402
                        }
403
                        $language = substr($language, 0, $pos);
404
                        $file = $this->dir['lang'].'PME.lang.'.$language.'.inc';
405
                }
406
                $ret = @include($file);
407
                if (! is_array($ret)) {
408
                        return $ret;
409
                }
410
                $small = array(
411
                                'Search' => 'v',
412
                                'Hide'   => '^',
413
                                'Clear'  => 'X',
414
                                'Query'  => htmlspecialchars('>'));
415
                if ((!$this->nav_text_links() && !$this->nav_graphic_links())
416
                                || !isset($ret['Search']) || !isset($ret['Query'])
417
                                || !isset($ret['Hide'])   || !isset($ret['Clear'])) {
418
                        foreach ($small as $key => $val) {
419
                                $ret[$key] = $val;
420
                        }
421
                }
422
                return $ret;
423
        } /* }}} */
424

    
425
        function set_values($field_num, $prepend = null, $append = null, $strict = false) /* {{{ */
426
        {
427
                return (array) $prepend + (array) $this->fdd[$field_num]['values2']
428
                        + (isset($this->fdd[$field_num]['values']['table']) || $strict
429
                                        ? $this->set_values_from_table($field_num, $strict)
430
                                        : array())
431
                        + (array) $append;
432
        } /* }}} */
433

    
434
        function set_values_from_table($field_num, $strict = false) /* {{{ */
435
        {
436
                $db    = &$this->fdd[$field_num]['values']['db'];
437
                $table = $this->sd.$this->fdd[$field_num]['values']['table'].$this->ed;
438
                $key   = &$this->fdd[$field_num]['values']['column'];
439
                $desc  = &$this->fdd[$field_num]['values']['description'];
440
                $dbp   = isset($db) ? $this->sd.$db.$this->ed.'.' : $this->dbp;
441
                $qparts['type'] = 'select';
442
                if ($table != $this->sd.$this->ed) {
443
                        $qparts['select'] = 'DISTINCT '.$table.'.'.$this->sd.$key.$this->ed;
444
                        if ($desc && is_array($desc) && is_array($desc['columns'])) {
445
                                $qparts['select'] .= ',CONCAT('; // )
446
                                $num_cols = sizeof($desc['columns']);
447
                                if (isset($desc['divs'][-1])) {
448
                                        $qparts['select'] .= '"'.addslashes($desc['divs'][-1]).'",';
449
                                }
450
                                foreach ($desc['columns'] as $key => $val) {
451
                                        if ($val) {
452
                                                $qparts['select'] .= 'IFNULL(CAST('.$this->sd.$val.$this->ed.' AS CHAR),"")';
453
                                                if ($desc['divs'][$key]) {
454
                                                        $qparts['select'] .= ',"'.addslashes($desc['divs'][$key]).'"';
455
                                                }
456
                                                $qparts['select'] .= ',';
457
                                        }
458
                                }
459
                                $qparts['select']{strlen($qparts['select']) - 1} = ')';
460
                                $qparts['select'] .= ' AS '.$this->sd.'PMEalias'.$field_num.$this->ed;
461
                                $qparts['orderby'] = $this->sd.'PMEalias'.$field_num.$this->ed;
462
                        } else if ($desc && is_array($desc)) {
463
                                // TODO
464
                        } else if ($desc) {
465
                                $qparts['select'] .= ','.$table.'.'.$this->sd.$desc.$this->ed;
466
                                $qparts['orderby'] = $this->sd.$desc.$this->ed;
467
                        } else if ($key) {
468
                                $qparts['orderby'] = $this->sd.$key.$this->ed;
469
                        }
470
                        $qparts['from'] = $dbp.$table;
471
                        $ar = array(
472
                                        'table'       => $table,
473
                                        'column'      => $column,
474
                                        'description' => $desc);
475
                        $qparts['where'] = $this->substituteVars($this->fdd[$field_num]['values']['filters'], $ar);
476
                        if ($this->fdd[$field_num]['values']['orderby']) {
477
                                $qparts['orderby'] = $this->substituteVars($this->fdd[$field_num]['values']['orderby'], $ar);
478
                        }
479
                } else { /* simple value extraction */
480
                        $key = &$this->fds[$field_num];
481
                        $this->virtual($field_num) && $key = $this->fqn($field_num);
482
                        $qparts['select']  = 'DISTINCT '.$this->sd.$key.$this->ed.' AS PMEkey';
483
                        $qparts['orderby'] = 'PMEkey';
484
                        $qparts['from']    = $this->dbp.$this->sd.$this->tb.$this->ed;
485
                }
486
                $values = array();
487
                $res    = $this->myquery($this->get_SQL_query($qparts), __LINE__);
488
                while ($row = $this->sql_fetch($res, 'n')) {
489
                        $values[$row[0]] = $desc ? $row[1] : $row[0];
490
                }
491
                return $values;
492
        } /* }}} */
493

    
494
        function fqn($field, $dont_desc = false, $dont_cols = false) /* {{{ */
495
        {
496
                is_numeric($field) || $field = array_search($field, $this->fds);
497
                // if read SQL expression exists use it
498
                if ($this->col_has_sql($field) && !$this->col_has_values($field))
499
                        return $this->fdd[$field]['sql'];
500
                // on copy/change always use simple key retrieving
501
                if ($this->add_operation()
502
                                || $this->copy_operation()
503
                                || $this->change_operation()) {
504
                                $ret = $this->sd.'PMEtable0'.$this->ed.'.'.$this->sd.$this->fds[$field].$this->ed;
505
                } else {
506
                        if ($this->fdd[$this->fds[$field]]['values']['description'] && ! $dont_desc) {
507
                                $desc = &$this->fdd[$this->fds[$field]]['values']['description'];
508
                                if (is_array($desc) && is_array($desc['columns'])) {
509
                                        $ret      = 'CONCAT('; // )
510
                                        $num_cols = sizeof($desc['columns']);
511
                                        if (isset($desc['divs'][-1])) {
512
                                                $ret .= '"'.addslashes($desc['divs'][-1]).'",';
513
                                        }
514
                                        foreach ($desc['columns'] as $key => $val) {
515
                                                if ($val) {
516
                                                        $ret .= 'IFNULL(CAST('.$this->sd.'PMEjoin'.$field.$this->ed.'.'.$this->sd.$val.$this->ed.' AS CHAR),"")';
517
                                                        if ($desc['divs'][$key]) {
518
                                                                $ret .= ',"'.addslashes($desc['divs'][$key]).'"';
519
                                                        }
520
                                                        $ret .= ',';
521
                                                }
522
                                        }
523
                                        $ret{strlen($ret) - 1} = ')';
524
                                } else if (is_array($desc)) {
525
                                        // TODO
526
                                } else {
527
                                        $ret = $this->sd.'PMEjoin'.$field.$this->ed.'.'.$this->sd.$this->fdd[$this->fds[$field]]['values']['description'].$this->ed;
528
                                }
529
                        // TODO: remove me
530
                        } elseif (0 && $this->fdd[$this->fds[$field]]['values']['column'] && ! $dont_cols) {
531
                                $ret = $this->sd.'PMEjoin'.$field.$this->ed.'.'.$this->fdd[$this->fds[$field]]['values']['column'];
532
                        } else {
533
                                $ret = $this->sd.'PMEtable0'.$this->ed.'.'.$this->sd.$this->fds[$field].$this->ed;
534
                        }
535
                        // TODO: not neccessary, remove me!
536
                        if (is_array($this->fdd[$this->fds[$field]]['values2'])) {
537
                        }
538
                }
539
                return $ret;
540
        } /* }}} */
541

    
542
        function get_SQL_main_list_query($qparts) /* {{{ */
543
        {
544
                 return $this->get_SQL_query($qparts);
545
         } /* }}} */
546
 
547

    
548

    
549
        function get_SQL_query($parts) /* {{{ */
550
        {
551
                foreach ($parts as $k => $v) {
552
                        $parts[$k] = trim($parts[$k]);
553
                }
554
                switch ($parts['type']) {
555
                        case 'select':
556
                                $ret  = 'SELECT ';
557
                                if ($parts['DISTINCT'])
558
                                        $ret .= 'DISTINCT ';
559
                                $ret .= $parts['select'];
560
                                $ret .= ' FROM '.$parts['from'];
561
                                if ($parts['where'] != '')
562
                                        $ret .= ' WHERE '.$parts['where'];
563
                                if ($parts['groupby'] != '')
564
                                        $ret .= ' GROUP BY '.$parts['groupby'];
565
                                if ($parts['having'] != '')
566
                                        $ret .= ' HAVING '.$parts['having'];
567
                                if ($parts['orderby'] != '')
568
                                        $ret .= ' ORDER BY '.$parts['orderby'];
569
                                if ($parts['limit'] != '')
570
                                        $ret .= ' '.$parts['limit'];
571
                                if ($parts['procedure'] != '')
572
                                        $ret .= ' PROCEDURE '.$parts['procedure'];
573
                                break;
574
                        case 'update':
575
                                $ret  = 'UPDATE '.$parts['table'];
576
                                $ret .= ' SET '.$parts['fields'];
577
                                if ($parts['where'] != '')
578
                                        $ret .= ' WHERE '.$parts['where'];
579
                                break;
580
                        case 'insert':
581
                                $ret  = 'INSERT INTO '.$parts['table'];
582
                                $ret .= ' VALUES '.$parts['values'];
583
                                break;
584
                        case 'delete':
585
                                $ret  = 'DELETE FROM '.$parts['table'];
586
                                if ($parts['where'] != '')
587
                                        $ret .= ' WHERE '.$parts['where'];
588
                                break;
589
                        default:
590
                                die('unknown query type');
591
                                break;
592
                }
593
                return $ret;
594
        } /* }}} */
595

    
596
        function get_SQL_column_list() /* {{{ */
597
        {
598
                $fields = array();
599
                for ($k = 0; $k < $this->num_fds; $k++) {
600
                        if (! $this->displayed[$k] && $k != $this->key_num) {
601
                                continue;
602
                        }
603
                        $fields[] = $this->fqn($k).' AS '.$this->sd.'qf'.$k.$this->ed; // no delimiters here, or maybe some yes
604
                        if ($this->col_has_values($k)) {
605
                                if($this->col_has_sql($k)) $fields[] = $this->fdd[$k]['sql'].' AS '.$this->sd.'qf'.$k.'_idx'.$this->ed;
606
                                else $fields[] = $this->fqn($k, true, true).' AS '.$this->sd.'qf'.$k.'_idx'.$this->ed;
607
                        }
608
                        if ($this->col_has_datemask($k)) {
609
                                $fields[] = 'UNIX_TIMESTAMP('.$this->fqn($k).') AS '.$this->sd.'qf'.$k.'_timestamp'.$this->ed;
610
                        }
611
                }
612
                return join(',', $fields);
613
        } /* }}} */
614

    
615
        function get_SQL_join_clause() /* {{{ */
616
        {
617
                $main_table  = $this->sd.'PMEtable0'.$this->ed;
618
                $join_clause = $this->sd.$this->tb.$this->ed." AS $main_table";
619
                for ($k = 0, $numfds = sizeof($this->fds); $k < $numfds; $k++) {
620
                        $main_column = $this->fds[$k];
621
                        if($this->fdd[$main_column]['values']['db']) {
622
                                $dbp = $this->sd.$this->fdd[$main_column]['values']['db'].$this->ed.'.';
623
                        } else {
624
                                //$dbp = $this->dbp;
625
                        }
626
                        $table       = $this->sd.$this->fdd[$main_column]['values']['table'].$this->ed;
627
                        $join_column = $this->sd.$this->fdd[$main_column]['values']['column'].$this->ed;
628
                        $join_desc   = $this->sd.$this->fdd[$main_column]['values']['description'].$this->ed;
629
                        if ($join_desc != $this->sd.$this->ed && $join_column != $this->sd.$this->ed) {
630
                                $join_table = $this->sd.'PMEjoin'.$k.$this->ed;
631
                                $ar = array(
632
                                                'main_table'       => $main_table,
633
                                                'main_column'      => $this->sd.$main_column.$this->ed,
634
                                                'join_table'       => $join_table,
635
                                                'join_column'      => $join_column,
636
                                                'join_description' => $join_desc);
637
                                $join_clause .= " LEFT OUTER JOIN $dbp".$table." AS $join_table ON (";
638
                                $join_clause .= isset($this->fdd[$main_column]['values']['join'])
639
                                        ? $this->substituteVars($this->fdd[$main_column]['values']['join'], $ar)
640
                                        : "$join_table.$join_column = $main_table.".$this->sd.$main_column.$this->ed;
641
                                $join_clause .= ')';
642
                        }
643
                }
644
                return $join_clause;
645
        } /* }}} */
646

    
647
        function get_SQL_where_from_query_opts($qp = null, $text = 0) /* {{{ */
648
        {
649
                if ($qp == null) {
650
                        $qp = $this->query_opts;
651
                }
652
                $where = array();
653
                foreach ($qp as $field => $ov) {
654
                        if (is_numeric($field)) {
655
                                $tmp_where = array();
656
                                foreach ($ov as $field2 => $ov2) {
657
                                        $tmp_where[] = sprintf('%s %s %s', $field2, $ov2['oper'], $ov2['value']);
658
                                }
659
                                $where[] = '('.join(' OR ', $tmp_where).')';
660
                        } else {
661
                                if (is_array($ov['value'])) {
662
                                        $tmp_ov_val = '';
663
                                        foreach ($ov['value'] as $ov_val) {
664
                                                strlen($tmp_ov_val) > 0 && $tmp_ov_val .= ' OR ';
665
                                                $tmp_ov_val .= sprintf('FIND_IN_SET("%s",%s)', $ov_val, $field);
666
                                        }
667
                                        $where[] = "($tmp_ov_val)";
668
                                } else {
669
                                        $where[] = sprintf('%s %s %s', $field, $ov['oper'], $ov['value']);
670
                                }
671
                        }
672
                }
673
                // Add any coder specified filters
674
                if (! $text && $this->filters) {
675
                        $where[] = '('.$this->filters.')';
676
                }
677
                if (count($where) > 0) {
678
                        if ($text) {
679
                                return str_replace('%', '*', join(' AND ',$where));
680
                        } else {
681
                                return join(' AND ',$where);
682
                        }
683
                }
684
                return ''; /* empty string */
685
        } /* }}} */
686

    
687
        function gather_query_opts() /* {{{ */
688
        {
689
                $this->query_opts = array();
690
                $this->prev_qfn   = $this->qfn;
691
                $this->qfn        = '';
692
                if ($this->clear_operation()) {
693
                        return;
694
                }
695
                // gathers query options into an array, $this->query_opts
696
                $qo = array();
697
                for ($k = 0; $k < $this->num_fds; $k++) {
698
                        $l    = 'qf'.$k;
699
                        $lc   = 'qf'.$k.'_comp';
700
                        $li   = 'qf'.$k.'_id';
701
                        $m    = $this->get_sys_cgi_var($l);
702
                        $mc   = $this->get_sys_cgi_var($lc);
703
                        $mi   = $this->get_sys_cgi_var($li);
704
                        if (! isset($m) && ! isset($mi)) {
705
                                continue;
706
                        }
707
                        if (is_array($m) || is_array($mi)) {
708
                                if (is_array($mi)) {
709
                                        $m = $mi;
710
                                        $l = $li;
711
                                }
712
                                if (in_array('*', $m)) {
713
                                        continue;
714
                                }
715
                                if ($this->col_has_values($k) && $this->col_has_multiple($k)) {
716
                                        foreach (array_keys($m) as $key) {
717
                                                $m[$key] = addslashes($m[$key]);
718
                                        }
719
                                        $qo[$this->fqn($k)] = array('value' => $m);
720
                                } else {
721
                                        $qf_op = '';
722
                                        foreach (array_keys($m) as $key) {
723
                                                if ($qf_op == '') {
724
                                                        $qf_op   = 'IN';
725
                                                        $qf_val  = '"'.addslashes($m[$key]).'"';
726
                                                        $afilter = ' IN ("'.addslashes($m[$key]).'"'; // )
727
                                                } else {
728
                                                        $afilter = $afilter.',"'.addslashes($m[$key]).'"';
729
                                                        $qf_val .= ',"'.addslashes($m[$key]).'"';
730
                                                }
731
                                                $this->qfn .= '&'.$this->cgi['prefix']['sys'].$l.'['.rawurlencode($key).']='.rawurlencode($m[$key]);
732
                                        }
733
                                        $afilter = $afilter.')';
734
                                        // XXX: $dont_desc and $dont_cols hack
735
                                        $dont_desc = isset($this->fdd[$k]['values']['description']);
736
                                        $dont_cols = isset($this->fdd[$k]['values']['column']);
737
                                        $qo[$this->fqn($k, $dont_desc, $dont_cols)] =
738
                                                array('oper'  => $qf_op, 'value' => "($qf_val)"); // )
739
                                }
740
                        } else if (isset($mi)) {
741
                                if ($mi == '*') {
742
                                        continue;
743
                                }
744
                                if ($this->fdd[$k]['select'] != 'M' && $this->fdd[$k]['select'] != 'D' && $mi == '') {
745
                                        continue;
746
                                }
747
                                $afilter = addslashes($mi);
748
                                $qo[$this->fqn($k, true, true)] = array('oper'  => '=', 'value' => "'$afilter'");
749
                                $this->qfn .= '&'.$this->cgi['prefix']['sys'].$li.'='.rawurlencode($mi);
750
                        } else if (isset($m)) {
751
                                if ($m == '*') {
752
                                        continue;
753
                                }
754
                                if ($this->fdd[$k]['select'] != 'M' && $this->fdd[$k]['select'] != 'D' && $m == '') {
755
                                        continue;
756
                                }
757
                                $afilter = addslashes($m);
758
                                if ($this->fdd[$k]['select'] == 'N') {
759
                                        $mc = in_array($mc, $this->comp_ops) ? $mc : '=';
760
                                        $qo[$this->fqn($k)] = array('oper' => $mc, 'value' => "'$afilter'");
761
                                        $this->qfn .= '&'.$this->cgi['prefix']['sys'].$l .'='.rawurlencode($m);
762
                                        $this->qfn .= '&'.$this->cgi['prefix']['sys'].$lc.'='.rawurlencode($mc);
763
                                } else {
764
                                        $afilter = '%'.str_replace('*', '%', $afilter).'%';
765
                                        $ids  = array();
766
                                        $ar   = array();
767
                                        $ar[$this->fqn($k)] = array('oper' => 'LIKE', 'value' => "'$afilter'");
768
                                        if (is_array($this->fdd[$k]['values2'])) {
769
                                                foreach ($this->fdd[$k]['values2'] as $key => $val) {
770
                                                        if (strlen($m) > 0 && stristr($val, $m)) {
771
                                                                $ids[] = '"'.addslashes($key).'"';
772
                                                        }
773
                                                }
774
                                                if (count($ids) > 0) {
775
                                                        $ar[$this->fqn($k, true, true)]
776
                                                                = array('oper'  => 'IN', 'value' => '('.join(',', $ids).')');
777
                                                }
778
                                        }
779
                                        $qo[] = $ar;
780
                                        $this->qfn .= '&'.$this->cgi['prefix']['sys'].$l.'='.rawurlencode($m);
781
                                }
782
                        }
783
                }
784
                $this->query_opts = $qo;
785
        } /* }}} */
786

    
787
        /*
788
         * Create JavaScripts
789
         */
790

    
791
        function form_begin() /* {{{ */
792
        {
793
                $page_name = htmlspecialchars($this->page_name);
794
                if ($this->add_operation() || $this->change_operation() || $this->copy_operation()
795
                                || $this->view_operation() || $this->delete_operation()) {
796
                        $field_to_tab = array();
797
                        for ($tab = $k = $this->cur_tab = 0; $k < $this->num_fds; $k++) {
798
                                if (isset($this->fdd[$k]['tab'])) {
799
                                        if ($tab == 0 && $k > 0) {
800
                                                $this->tabs[0] = 'PMEtab0';
801
                                                $this->cur_tab = 1;
802
                                                $tab++;
803
                                        }
804
                                        if (is_array($this->fdd[$k]['tab'])) {
805
                                                $this->tabs[$tab] = @$this->fdd[$k]['tab']['name'];
806
                                                $this->fdd[$k]['tab']['default'] && $this->cur_tab = $tab;
807
                                        } else {
808
                                                $this->tabs[$tab] = @$this->fdd[$k]['tab'];
809
                                        }
810
                                        $tab++;
811
                                }
812
                                $field_to_tab[$k] = max(0, $tab - 1);
813
                        }
814
                        if (preg_match('/^'.$this->dhtml['prefix'].'tab(\d+)$/', $this->get_sys_cgi_var('cur_tab'), $parts)) {
815
                                $this->cur_tab = $parts[1];
816
                        }
817
                        if ($this->tabs_enabled()) {
818
                                // initial TAB styles
819
                                echo '<style type="text/css" media="screen">',"\n";
820
                                for ($i = 0; $i < count($this->tabs); $i++) {
821
                                        echo '        #'.$this->dhtml['prefix'].'tab',$i,' { display: ';
822
                                        echo (($i == $this->cur_tab || $this->tabs[$i] == 'PMEtab0' ) ? 'block' : 'none') ,'; }',"\n";
823
                                }
824
                                echo '</style>',"\n";
825
                                // TAB javascripts
826
                                echo '<script type="text/javascript"><!--',"\n\n";
827
                                $css_class_name1 = $this->getCSSclass('tab', $position);
828
                                $css_class_name2 = $this->getCSSclass('tab-selected', $position);
829
                                echo 'var '.$this->js['prefix'].'cur_tab  = "'.$this->dhtml['prefix'].'tab',$this->cur_tab,'";
830

831
function '.$this->js['prefix'].'show_tab(tab_name)
832
{';
833
                                if ($this->nav_up()) {
834
                                        echo '
835
        document.getElementById('.$this->js['prefix'].'cur_tab+"_up_label").className = "',$css_class_name1,'";
836
        document.getElementById('.$this->js['prefix'].'cur_tab+"_up_link").className = "',$css_class_name1,'";
837
        document.getElementById(tab_name+"_up_label").className = "',$css_class_name2,'";
838
        document.getElementById(tab_name+"_up_link").className = "',$css_class_name2,'";';
839
                                }
840
                                if ($this->nav_down()) {
841
                                        echo '
842
        document.getElementById('.$this->js['prefix'].'cur_tab+"_down_label").className = "',$css_class_name1,'";
843
        document.getElementById('.$this->js['prefix'].'cur_tab+"_down_link").className = "',$css_class_name1,'";
844
        document.getElementById(tab_name+"_down_label").className = "',$css_class_name2,'";
845
        document.getElementById(tab_name+"_down_link").className = "',$css_class_name2,'";';
846
                                }
847
                                echo '
848
        document.getElementById('.$this->js['prefix'].'cur_tab).style.display = "none";
849
        document.getElementById(tab_name).style.display = "block";
850
        '.$this->js['prefix'].'cur_tab = tab_name;
851
        document.'.$this->cgi['prefix']['sys'].'form.'.$this->cgi['prefix']['sys'].'cur_tab.value = tab_name;
852
}',"\n\n";
853
                                echo '// --></script>', "\n";
854
                        }
855
                }
856

    
857
                if ($this->add_operation() || $this->change_operation() || $this->copy_operation()) {
858
                        $first_required = true;
859
                        for ($k = 0; $k < $this->num_fds; $k++) {
860
                                if ($this->displayed[$k] && ! $this->readonly($k) && ! $this->hidden($k)
861
                                                && ($this->fdd[$k]['js']['required'] || isset($this->fdd[$k]['js']['regexp']))) {
862
                                        if ($first_required) {
863
                                                 $first_required = false;
864
                                                echo '<script type="text/javascript"><!--',"\n";
865
                                                echo '
866
function '.$this->js['prefix'].'trim(str)
867
{
868
        while (str.substring(0, 1) == " "
869
                        || str.substring(0, 1) == "\\n"
870
                        || str.substring(0, 1) == "\\r")
871
        {
872
                str = str.substring(1, str.length);
873
        }
874
        while (str.substring(str.length - 1, str.length) == " "
875
                        || str.substring(str.length - 1, str.length) == "\\n"
876
                        || str.substring(str.length - 1, str.length) == "\\r")
877
        {
878
                str = str.substring(0, str.length - 1);
879
        }
880
        return str;
881
}
882

883
function '.$this->js['prefix'].'form_control(theForm)
884
{',"\n";
885
                                        }
886
                                        if ($this->col_has_values($k)) {
887
                                                $condition = 'theForm.'.$this->cgi['prefix']['data'].$this->fds[$k].'.selectedIndex == -1';
888
                                                $multiple  = $this->col_has_multiple_select($k);
889
                                        } else {
890
                                                $condition = '';
891
                                                $multiple  = false;
892
                                                if ($this->fdd[$k]['js']['required']) {
893
                                                        $condition = $this->js['prefix'].'trim(theForm.'.$this->cgi['prefix']['data'].$this->fds[$k].'.value) == ""';
894
                                                }
895
                                                if (isset($this->fdd[$k]['js']['regexp'])) {
896
                                                        $condition .= (strlen($condition) > 0 ? ' || ' : '');
897
                                                        $condition .= sprintf('!(%s.test('.$this->js['prefix'].'trim(theForm.%s.value)))',
898
                                                                        $this->fdd[$k]['js']['regexp'], $this->cgi['prefix']['data'].$this->fds[$k]);
899
                                                }
900
                                        }
901

    
902
                                        /* Multiple selects have their name like ''name[]''.
903
                                           It is not possible to work with them directly, because
904
                                           theForm.name[].something will result into JavaScript
905
                                           syntax error. Following search algorithm is provided
906
                                           as a workaround for this.
907
                                         */
908
                                        if ($multiple) {
909
                                                echo '
910
        multiple_select = null;
911
        for (i = 0; i < theForm.length; i++) {
912
                if (theForm.elements[i].name == "',$this->cgi['prefix']['data'].$this->fds[$k],'[]") {
913
                        multiple_select = theForm.elements[i];
914
                        break;
915
                }
916
        }
917
        if (multiple_select != null && multiple_select.selectedIndex == -1) {';
918
                                        } else {
919
                                                echo '
920
        if (',$condition,') {';
921
                                        }
922
                                        echo '
923
                alert("';
924
                                        if (isset($this->fdd[$k]['js']['hint'])) {
925
                                                echo htmlspecialchars($this->fdd[$k]['js']['hint']);
926
                                        } else {
927
                                                echo $this->labels['Please enter'],' ',$this->fdd[$k]['name'],'.';
928
                                        }
929
                                        echo '");';
930
                                        if ($this->tabs_enabled() && $field_to_tab[$k] >= $this->cur_tab) {
931
                                                echo '
932
                '.$this->js['prefix'].'show_tab("'.$this->dhtml['prefix'].'tab',$field_to_tab[$k],'");';
933
                                        }
934
                                        echo '
935
                theForm.',$this->cgi['prefix']['data'].$this->fds[$k],'.focus();
936
                return false;
937
        }',"\n";
938
                                }
939
                        }
940
                        if (! $first_required) {
941
                                echo '
942
        return true;
943
}',"\n\n";
944
                                echo '// --></script>', "\n";
945
                        }
946
                }
947

    
948
                if ($this->filter_operation()) {
949
                                echo '<script type="text/javascript"><!--',"\n";
950
                                echo '
951
function '.$this->js['prefix'].'filter_handler(theForm, theEvent)
952
{
953
        var pressed_key = null;
954
        if (theEvent.which) {
955
                pressed_key = theEvent.which;
956
        } else {
957
                pressed_key = theEvent.keyCode;
958
        }
959
        if (pressed_key == 13) { // enter pressed
960
                theForm.submit();
961
                return false;
962
        }
963
        return true;
964
}',"\n\n";
965
                                echo '// --></script>', "\n";
966
                }
967

    
968
                if ($this->display['form']) {
969
                        echo '<form class="',$this->getCSSclass('form'),'" method="post"';
970
                        echo ' action="',$page_name,'" name="'.$this->cgi['prefix']['sys'].'form">',"\n";
971
                }
972
                return true;
973
        } /* }}} */
974

    
975
        function form_end() /* {{{ */
976
        {
977
                if ($this->display['form']) {
978
                        echo '</form>',"\n";
979
                }
980
        } /* }}} */
981

    
982
        function display_tab_labels($position) /* {{{ */
983
        {
984
                if (! is_array($this->tabs)) {
985
                        return false;
986
                }
987
                echo '<table summary="labels" class="',$this->getCSSclass('tab', $position),'">',"\n";
988
                echo '<tr class="',$this->getCSSclass('tab', $position),'">',"\n";
989
                for ($i = ($this->tabs[0] == 'PMEtab0' ? 1 : 0); $i < count($this->tabs); $i++) {
990
                        $css_class_name = $this->getCSSclass($i != $this->cur_tab ? 'tab' : 'tab-selected', $position);
991
                        echo '<td class="',$css_class_name,'" id="'.$this->dhtml['prefix'].'tab',$i,'_',$position,'_label">';
992
                        echo '<a class="',$css_class_name,'" id="'.$this->dhtml['prefix'].'tab',$i,'_',$position,'_link';
993
                        echo '" href="javascript:'.$this->js['prefix'].'show_tab(\''.$this->dhtml['prefix'].'tab',$i,'\')">';
994
                        echo $this->tabs[$i],'</a></td>',"\n";
995
                }
996
                echo '<td class="',$this->getCSSclass('tab-end', $position),'">&nbsp;</td>',"\n";
997
                echo '</tr>',"\n";
998
                echo '</table>',"\n";
999
        } /* }}} */
1000

    
1001
        /*
1002
         * Display functions
1003
         */
1004

    
1005
        function display_add_record() /* {{{ */
1006
        {
1007
                for ($tab = 0, $k = 0; $k < $this->num_fds; $k++) {
1008
                        if (isset($this->fdd[$k]['tab']) && $this->tabs_enabled() && $k > 0) {
1009
                                $tab++;
1010
                                echo '</table>',"\n";
1011
                                echo '</div>',"\n";
1012
                                echo '<div id="'.$this->dhtml['prefix'].'tab',$tab,'">',"\n";
1013
                                echo '<table class="',$this->getCSSclass('main'),'" summary="',$this->tb,'">',"\n";
1014
                        }
1015
                        if (! $this->displayed[$k]) {
1016
                                continue;
1017
                        }
1018
                        if ($this->hidden($k)) {
1019
                                echo $this->htmlHiddenData($this->fds[$k], $this->fdd[$k]['default']);
1020
                                continue;
1021
                        }
1022
                        $css_postfix    = @$this->fdd[$k]['css']['postfix'];
1023
                        $css_class_name = $this->getCSSclass('input', null, 'next', $css_postfix);
1024
                        $escape                        = isset($this->fdd[$k]['escape']) ? $this->fdd[$k]['escape'] : true;
1025
                        echo '<tr class="',$this->getCSSclass('row', null, true, $css_postfix),'">',"\n";
1026
                        echo '<td class="',$this->getCSSclass('key', null, true, $css_postfix),'">';
1027
                        echo $this->fdd[$k]['name'],'</td>',"\n";
1028
                        echo '<td class="',$this->getCSSclass('value', null, true, $css_postfix),'"';
1029
                        echo $this->getColAttributes($k),">\n";
1030
                        if ($this->col_has_values($k)) {
1031
                                $vals       = $this->set_values($k);
1032
                                $selected   = @$this->fdd[$k]['default'];
1033
                                $multiple   = $this->col_has_multiple($k);
1034
                                $readonly   = $this->readonly($k);
1035
                                $strip_tags = true;
1036
                                //$escape     = true;
1037
                                if ($this->col_has_checkboxes($k) || $this->col_has_radio_buttons($k)) {
1038
                                        echo $this->htmlRadioCheck($this->cgi['prefix']['data'].$this->fds[$k],
1039
                                                        $css_class_name, $vals, $selected, $multiple, $readonly,
1040
                                                        $strip_tags, $escape);
1041
                                } else {
1042
                                        echo $this->htmlSelect($this->cgi['prefix']['data'].$this->fds[$k],
1043
                                                        $css_class_name, $vals, $selected, $multiple, $readonly,
1044
                                                        $strip_tags, $escape);
1045
                                }
1046
                        } elseif (isset ($this->fdd[$k]['textarea'])) {
1047
                                echo '<textarea class="',$css_class_name,'" name="',$this->cgi['prefix']['data'].$this->fds[$k],'"';
1048
                                echo ($this->readonly($k) ? ' disabled' : '');
1049
                                if (intval($this->fdd[$k]['textarea']['rows']) > 0) {
1050
                                        echo ' rows="',$this->fdd[$k]['textarea']['rows'],'"';
1051
                                }
1052
                                if (intval($this->fdd[$k]['textarea']['cols']) > 0) {
1053
                                        echo ' cols="',$this->fdd[$k]['textarea']['cols'],'"';
1054
                                }
1055
                                if (isset($this->fdd[$k]['textarea']['wrap'])) {
1056
                                        echo ' wrap="',$this->fdd[$k]['textarea']['wrap'],'"';
1057
                                } else {
1058
                                        echo ' wrap="virtual"';
1059
                                }
1060
                                echo '>';
1061
                                if($escape) echo htmlspecialchars($this->fdd[$k]['default']);
1062
                                else echo $this->fdd[$k]['default'];
1063
                                echo '</textarea>',"\n";
1064
                        } elseif ($this->col_has_php($k)) {
1065
                                echo include($this->fdd[$k]['php']);
1066
                        } else {
1067
                                // Simple edit box required
1068
                                $len_props = '';
1069
                                $maxlen = intval($this->fdd[$k]['maxlen']);
1070
                                $size   = isset($this->fdd[$k]['size']) ? $this->fdd[$k]['size'] : min($maxlen, 60); 
1071
                                if ($size > 0) {
1072
                                        $len_props .= ' size="'.$size.'"';
1073
                                }
1074
                                if ($maxlen > 0) {
1075
                                        $len_props .= ' maxlength="'.$maxlen.'"';
1076
                                }
1077
                                echo '<input class="',$css_class_name,'" ';
1078
                                echo ($this->password($k) ? 'type="password"' : 'type="text"');
1079
                                echo ($this->readonly($k) ? ' disabled' : '');
1080
                                echo ' name="',$this->cgi['prefix']['data'].$this->fds[$k],'"';
1081
                                echo $len_props,' value="';
1082
                                if($escape) echo htmlspecialchars($this->fdd[$k]['default']);
1083
                            else echo $this->fdd[$k]['default'];
1084
                                echo '" />';
1085
                        }
1086
                        echo '</td>',"\n";
1087
                        if ($this->guidance) {
1088
                                $css_class_name = $this->getCSSclass('help', null, true, $css_postfix);
1089
                                $cell_value     = $this->fdd[$k]['help'] ? $this->fdd[$k]['help'] : '&nbsp;';
1090
                                echo '<td class="',$css_class_name,'">',$cell_value,'</td>',"\n";
1091
                        }
1092
                        echo '</tr>',"\n";
1093
                }
1094
        } /* }}} */
1095

    
1096
        function display_copy_change_delete_record() /* {{{ */
1097
        {
1098
                /*
1099
                 * For delete or change: SQL SELECT to retrieve the selected record
1100
                 */
1101

    
1102
                $qparts['type']   = 'select';
1103
                $qparts['select'] = $this->get_SQL_column_list();
1104
                $qparts['from']   = $this->get_SQL_join_clause();
1105
                $qparts['where']  = '('.$this->fqn($this->key).'='
1106
                        .$this->key_delim.$this->rec.$this->key_delim.')';
1107

    
1108
                $res = $this->myquery($this->get_SQL_query($qparts),__LINE__);
1109
                if (! ($row = $this->sql_fetch($res))) {
1110
                        return false;
1111
                }
1112
                for ($tab = 0, $k = 0; $k < $this->num_fds; $k++) {
1113
                        if (isset($this->fdd[$k]['tab']) && $this->tabs_enabled() && $k > 0) {
1114
                                $tab++;
1115
                                echo '</table>',"\n";
1116
                                echo '</div>',"\n";
1117
                                echo '<div id="'.$this->dhtml['prefix'].'tab',$tab,'">',"\n";
1118
                                echo '<table class="',$this->getCSSclass('main'),'" summary="',$this->tb,'">',"\n";
1119
                        }
1120
                        if (! $this->displayed[$k]) {
1121
                                continue;
1122
                        }
1123
                        if ($this->copy_operation() || $this->change_operation()) {
1124
                                if ($this->hidden($k)) {
1125
                                        if ($k != $this->key_num) {
1126
                                                echo $this->htmlHiddenData($this->fds[$k], $row["qf$k"]);
1127
                                        }
1128
                                        continue;
1129
                                }
1130
                                $css_postfix = @$this->fdd[$k]['css']['postfix'];
1131
                                echo '<tr class="',$this->getCSSclass('row', null, 'next', $css_postfix),'">',"\n";
1132
                                echo '<td class="',$this->getCSSclass('key', null, true, $css_postfix),'">';
1133
                                echo $this->fdd[$k]['name'],'</td>',"\n";
1134
                                /* There are two possibilities of readonly fields handling:
1135
                                   1. Display plain text for readonly timestamps, dates and URLs.
1136
                                   2. Display disabled input field
1137
                                   In all cases particular readonly field will NOT be saved. */
1138
                                if ($this->readonly($k) && ($this->col_has_datemask($k) || $this->col_has_URL($k))) {
1139
                                        echo $this->display_delete_field($row, $k);
1140
                                } elseif ($this->password($k)) {
1141
                                        echo $this->display_password_field($row, $k);
1142
                                } else {
1143
                                        echo $this->display_change_field($row, $k);
1144
                                }
1145
                                if ($this->guidance) {
1146
                                        $css_class_name = $this->getCSSclass('help', null, true, $css_postfix);
1147
                                        $cell_value     = $this->fdd[$k]['help'] ? $this->fdd[$k]['help'] : '&nbsp;';
1148
                                        echo '<td class="',$css_class_name,'">',$cell_value,'</td>',"\n";
1149
                                }
1150
                                echo '</tr>',"\n";
1151
                        } elseif ($this->delete_operation() || $this->view_operation()) {
1152
                                $css_postfix = @$this->fdd[$k]['css']['postfix'];
1153
                                echo '<tr class="',$this->getCSSclass('row', null, 'next', $css_postfix),'">',"\n";
1154
                                echo '<td class="',$this->getCSSclass('key', null, true, $css_postfix),'">';
1155
                                echo $this->fdd[$k]['name'],'</td>',"\n";
1156
                                if ($this->password($k)) {
1157
                                        echo '<td class="',$this->getCSSclass('value', null, true, $css_postfix),'"';
1158
                                        echo $this->getColAttributes($k),'>',$this->labels['hidden'],'</td>',"\n";
1159
                                } else {
1160
                                        $this->display_delete_field($row, $k);
1161
                                }
1162
                                if ($this->guidance) {
1163
                                        $css_class_name = $this->getCSSclass('help', null, true, $css_postfix);
1164
                                        $cell_value     = $this->fdd[$k]['help'] ? $this->fdd[$k]['help'] : '&nbsp;';
1165
                                        echo '<td class="',$css_class_name,'">',$cell_value,'</td>',"\n";
1166
                                }
1167
                                echo '</tr>',"\n";
1168
                        }
1169
                }
1170
        } /* }}} */
1171

    
1172
        function display_change_field($row, $k) /* {{{ */ 
1173
        {
1174
                $css_postfix    = @$this->fdd[$k]['css']['postfix'];
1175
                $css_class_name = $this->getCSSclass('input', null, true, $css_postfix);
1176
                $escape         = isset($this->fdd[$k]['escape']) ? $this->fdd[$k]['escape'] : true;
1177
                echo '<td class="',$this->getCSSclass('value', null, true, $css_postfix),'"';
1178
                echo $this->getColAttributes($k),">\n";
1179
                if ($this->col_has_values($k)) {
1180
                        $vals       = $this->set_values($k);
1181
                        $multiple   = $this->col_has_multiple($k);
1182
                        $readonly   = $this->readonly($k);
1183
                        $strip_tags = true;
1184
                        //$escape     = true;
1185
                        if ($this->col_has_checkboxes($k) || $this->col_has_radio_buttons($k)) {
1186
                                echo $this->htmlRadioCheck($this->cgi['prefix']['data'].$this->fds[$k],
1187
                                                $css_class_name, $vals, $row["qf$k"], $multiple, $readonly,
1188
                                                $strip_tags, $escape);
1189
                        } else {
1190
                                echo $this->htmlSelect($this->cgi['prefix']['data'].$this->fds[$k],
1191
                                                $css_class_name, $vals, $row["qf$k"], $multiple, $readonly,
1192
                                                $strip_tags, $escape);
1193
                        }
1194
                } elseif (isset($this->fdd[$k]['textarea'])) {
1195
                        echo '<textarea class="',$css_class_name,'" name="',$this->cgi['prefix']['data'].$this->fds[$k],'"';
1196
                        echo ($this->readonly($k) ? ' disabled' : '');
1197
                        if (intval($this->fdd[$k]['textarea']['rows']) > 0) {
1198
                                echo ' rows="',$this->fdd[$k]['textarea']['rows'],'"';
1199
                        }
1200
                        if (intval($this->fdd[$k]['textarea']['cols']) > 0) {
1201
                                echo ' cols="',$this->fdd[$k]['textarea']['cols'],'"';
1202
                        }
1203
                        if (isset($this->fdd[$k]['textarea']['wrap'])) {
1204
                                echo ' wrap="',$this->fdd[$k]['textarea']['wrap'],'"';
1205
                        } else {
1206
                                echo ' wrap="virtual"';
1207
                        }
1208
                        echo '>';
1209
                        if($escape) echo htmlspecialchars($row["qf$k"]);
1210
                        else echo $row["qf$k"];
1211
                        echo '</textarea>',"\n";
1212
                } elseif ($this->col_has_php($k)) {
1213
                        echo include($this->fdd[$k]['php']);
1214
                } else {
1215
                        $len_props = '';
1216
                        $maxlen = intval($this->fdd[$k]['maxlen']);
1217
                        $size   = isset($this->fdd[$k]['size']) ? $this->fdd[$k]['size'] : min($maxlen, 60); 
1218
                        if ($size > 0) {
1219
                                $len_props .= ' size="'.$size.'"';
1220
                        }
1221
                        if ($maxlen > 0) {
1222
                                $len_props .= ' maxlength="'.$maxlen.'"';
1223
                        }
1224
                        echo '<input class="',$css_class_name,'" type="text"';
1225
                        echo ($this->readonly($k) ? ' disabled' : '');
1226
                        echo ' name="',$this->cgi['prefix']['data'].$this->fds[$k],'" value="';
1227
                        if($escape) echo htmlspecialchars($row["qf$k"]);
1228
                        else echo $row["qf$k"];
1229
                        echo '"',$len_props,' />',"\n";
1230
                }
1231
                echo '</td>',"\n";
1232
        } /* }}} */
1233

    
1234
        function display_password_field($row, $k) /* {{{ */
1235
        {
1236
                $css_postfix = @$this->fdd[$k]['css']['postfix'];
1237
                echo '<td class="',$this->getCSSclass('value', null, true, $css_postfix),'"';
1238
                echo $this->getColAttributes($k),">\n";
1239
                $len_props = '';
1240
                $maxlen = intval($this->fdd[$k]['maxlen']);
1241
                $size   = isset($this->fdd[$k]['size']) ? $this->fdd[$k]['size'] : min($maxlen, 60); 
1242
                if ($size > 0) {
1243
                        $len_props .= ' size="'.$size.'"';
1244
                }
1245
                if ($maxlen > 0) {
1246
                        $len_props .= ' maxlength="'.$maxlen.'"';
1247
                }
1248
                echo '<input class="',$this->getCSSclass('value', null, true, $css_postfix),'" type="password"';
1249
                echo ($this->readonly($k) ? ' disabled' : '');
1250
                echo ' name="',$this->cgi['prefix']['data'].$this->fds[$k],'" value="';
1251
                echo htmlspecialchars($row["qf$k"]),'"',$len_props,' />',"\n";
1252
                echo '</td>',"\n";
1253
        } /* }}} */
1254

    
1255
        function display_delete_field($row, $k) /* {{{ */
1256
        {
1257
                $css_postfix    = @$this->fdd[$k]['css']['postfix'];
1258
                $css_class_name = $this->getCSSclass('value', null, true, $css_postfix);
1259
                echo '<td class="',$css_class_name,'"',$this->getColAttributes($k),">\n";
1260
                echo $this->cellDisplay($k, $row, $css_class_name);
1261
                echo '</td>',"\n";
1262
        } /* }}} */
1263

    
1264
        /**
1265
         * Returns CSS class name
1266
         */
1267
        function getCSSclass($name, $position  = null, $divider = null, $postfix = null) /* {{{ */
1268
        {
1269
                static $div_idx = -1;
1270
                $elements = array($this->css['prefix'], $name);
1271
                if ($this->page_type && $this->css['page_type']) {
1272
                        if ($this->page_type != 'L' && $this->page_type != 'F') {
1273
                                $elements[] = $this->page_types[$this->page_type];
1274
                        }
1275
                }
1276
                if ($position && $this->css['position']) {
1277
                        $elements[] = $position;
1278
                }
1279
                if ($divider && $this->css['divider']) {
1280
                        if ($divider === 'next') {
1281
                                $div_idx++;
1282
                                if ($this->css['divider'] > 0 && $div_idx >= $this->css['divider']) {
1283
                                        $div_idx = 0;
1284
                                }
1285
                        }
1286
                        $elements[] = $div_idx;
1287
                }
1288
                if ($postfix) {
1289
                        $elements[] = $postfix;
1290
                }
1291
                return join($this->css['separator'], $elements);
1292
        } /* }}} */
1293

    
1294
        /**
1295
         * Returns field cell HTML attributes
1296
         */
1297
        function getColAttributes($k) /* {{{ */
1298
        {
1299
                $colattrs = '';
1300
                if (isset($this->fdd[$k]['colattrs'])) {
1301
                        $colattrs .= ' ';
1302
                        $colattrs .= trim($this->fdd[$k]['colattrs']);
1303
                }
1304
                if (isset($this->fdd[$k]['nowrap'])) {
1305
                        $colattrs .= ' nowrap';
1306
                }
1307
                return $colattrs;
1308
        } /* }}} */
1309

    
1310
        /**
1311
         * Substitutes variables in string
1312
         * (this is very simple but secure eval() replacement)
1313
         */
1314
        function substituteVars($str, $subst_ar) /* {{{ */
1315
        {
1316
                $array = preg_split('/(\\$\w+)/', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
1317
                $count = count($array);
1318
                for ($i = 1; $i < $count; $i += 2) {
1319
                        $key = substr($array[$i], 1);
1320
                        if (isset($subst_ar[$key])) {
1321
                                $array[$i] = $subst_ar[$key];
1322
                        }
1323
                }
1324
                return join('', $array);
1325
        } /* }}} */
1326

    
1327
        /**
1328
         * Print URL
1329
         */
1330
        function urlDisplay($k, $link_val, $disp_val, $css, $key) /* {{{ */
1331
        {
1332
                $escape = isset($this->fdd[$k]['escape']) ? $this->fdd[$k]['escape'] : true;
1333
                $ret  = '';
1334
                $name = $this->fds[$k];
1335
                $page = $this->page_name;
1336
                $url  = $this->cgi['prefix']['sys'].'rec'.'='.$key.'&'.$this->cgi['prefix']['sys'].'fm'
1337
                        .'='.$this->fm.'&'.$this->cgi['prefix']['sys'].'fl'.'='.$this->fl;
1338
                $url .= '&'.$this->cgi['prefix']['sys'].'qfn'.'='.rawurlencode($this->qfn).$this->qfn;
1339
                $url .= '&'.$this->get_sfn_cgi_vars().$this->cgi['persist'];
1340
                $ar   = array(
1341
                                'key'   => $key,
1342
                                'name'  => $name,
1343
                                'link'  => $link_val,
1344
                                'value' => $disp_val,
1345
                                'css'   => $css,
1346
                                'page'  => $page,
1347
                                'url'   => $url
1348
                                );
1349
                $urllink = isset($this->fdd[$k]['URL'])
1350
                        ?  $this->substituteVars($this->fdd[$k]['URL'], $ar)
1351
                        : $link_val;
1352
                $urldisp = isset($this->fdd[$k]['URLdisp'])
1353
                        ?  $this->substituteVars($this->fdd[$k]['URLdisp'], $ar)
1354
                        : $disp_val;
1355
                $target = isset($this->fdd[$k]['URLtarget'])
1356
                        ? 'target="'.htmlspecialchars($this->fdd[$k]['URLtarget']).'" '
1357
                        : '';
1358
                $prefix_found  = false;
1359
                $postfix_found = false;
1360
                $prefix_ar     = @$this->fdd[$k]['URLprefix'];
1361
                $postfix_ar    = @$this->fdd[$k]['URLpostfix'];
1362
                is_array($prefix_ar)  || $prefix_ar  = array($prefix_ar);
1363
                is_array($postfix_ar) || $postfix_ar = array($postfix_ar);
1364
                foreach ($prefix_ar as $prefix) {
1365
                        if (! strncmp($prefix, $urllink, strlen($prefix))) {
1366
                                $prefix_found = true;
1367
                                break;
1368
                        }
1369
                }
1370
                foreach ($postfix_ar as $postfix) {
1371
                        if (! strncmp($postfix, $urllink, strlen($postfix))) {
1372
                                $postfix_found = true;
1373
                                break;
1374
                        }
1375
                }
1376
                $prefix_found  || $urllink = array_shift($prefix_ar).$urllink;
1377
                $postfix_found || $urllink = $urllink.array_shift($postfix_ar);
1378
                if (strlen($urllink) <= 0 || strlen($urldisp) <= 0) {
1379
                        $ret = '&nbsp;';
1380
                } else {
1381
                        if ($escape) {
1382
                                $urldisp = htmlspecialchars($urldisp);
1383
                        }
1384
                        $urllink = htmlspecialchars($urllink);
1385
                        $ret = '<a '.$target.'class="'.$css.'" href="'.$urllink.'">'.$urldisp.'</a>';
1386
                }
1387
                return $ret;
1388
        } /* }}} */
1389

    
1390
        function cellDisplay($k, $row, $css) /* {{{ */
1391
        {
1392
                $escape  = isset($this->fdd[$k]['escape']) ? $this->fdd[$k]['escape'] : true;
1393
                $key_rec = $row['qf'.$this->key_num];
1394
                if (@$this->fdd[$k]['datemask']) {
1395
                        $value = intval($row["qf$k".'_timestamp']);
1396
                        $value = $value ? @date($this->fdd[$k]['datemask'], $value) : '';
1397
                } else if (@$this->fdd[$k]['strftimemask']) {
1398
                        $value = intval($row["qf$k".'_timestamp']);
1399
                        $value = $value ? @strftime($this->fdd[$k]['strftimemask'], $value) : '';
1400
                } else if ($this->is_values2($k, $row["qf$k"])) {
1401
                        $value = $row['qf'.$k.'_idx'];
1402
                        if ($this->fdd[$k]['select'] == 'M') {
1403
                                $value_ar  = explode(',', $value);
1404
                                $value_ar2 = array();
1405
                                foreach ($value_ar as $value_key) {
1406
                                        if (isset($this->fdd[$k]['values2'][$value_key])) {
1407
                                                $value_ar2[$value_key] = $this->fdd[$k]['values2'][$value_key];
1408
                                                $escape = false;
1409
                                        }
1410
                                }
1411
                                $value = join(', ', $value_ar2);
1412
                        } else {
1413
                                if (isset($this->fdd[$k]['values2'][$value])) {
1414
                                        $value  = $this->fdd[$k]['values2'][$value];
1415
                                        $escape = false;
1416
                                }
1417
                        }
1418
                } elseif (isset($this->fdd[$k]['values2'][$row["qf$k"]])) {
1419
                        $value = $this->fdd[$k]['values2'][$row["qf$k"]];
1420
                } else {
1421
                        $value = $row["qf$k"];
1422
                }
1423
                $original_value = $value;
1424
                if (@$this->fdd[$k]['strip_tags']) {
1425
                        $value = strip_tags($value);
1426
                }
1427
                if ($num_ar = @$this->fdd[$k]['number_format']) {
1428
                        if (! is_array($num_ar)) {
1429
                                $num_ar = array($num_ar);
1430
                        }
1431
                        if (count($num_ar) == 1) {
1432
                                list($nbDec) = $num_ar;
1433
                                $value = number_format($value, $nbDec);
1434
                        } else if (count($num_ar) == 3) {
1435
                                list($nbDec, $decPoint, $thSep) = $num_ar;
1436
                                $value = number_format($value, $nbDec, $decPoint, $thSep);
1437
                        }
1438
                }
1439
                if (intval($this->fdd[$k]['trimlen']) > 0 && strlen($value) > $this->fdd[$k]['trimlen']) {
1440
                        $value = ereg_replace("[\r\n\t ]+",' ',$value);
1441
                        $value = substr($value, 0, $this->fdd[$k]['trimlen'] - 3).'...';
1442
                }
1443
                if (@$this->fdd[$k]['mask']) {
1444
                        $value = sprintf($this->fdd[$k]['mask'], $value);
1445
                }
1446
                if ($this->col_has_php($k)) {
1447
                        return include($this->fdd[$k]['php']);
1448
                }
1449
                if ($this->col_has_URL($k)) {
1450
                        return $this->urlDisplay($k, $original_value, $value, $css, $key_rec);
1451
                }
1452
                if (strlen($value) <= 0) {
1453
                        return '&nbsp;';
1454
                }
1455
                if ($escape) {
1456
                        $value = htmlspecialchars($value);
1457
                }
1458
                return nl2br($value);
1459
        } /* }}} */
1460

    
1461
        /**
1462
         * Creates HTML submit input element
1463
         *
1464
         * @param        name                        element name
1465
         * @param        label                        key in the language hash used as label
1466
         * @param        css_class_name        CSS class name
1467
         * @param        js_validation        if add JavaScript validation subroutine to button
1468
         * @param        disabled                if mark the button as disabled
1469
         * @param        js                any extra text in tags
1470
         */
1471
        function htmlSubmit($name, $label, $css_class_name, $js_validation = true, $disabled = false, $js = NULL) /* {{{ */
1472
        {
1473
                // Note that <input disabled> isn't valid HTML, but most browsers support it
1474
                if($disabled == -1) return;
1475
                $markdisabled = $disabled ? ' disabled' : '';
1476
                $ret = '<input'.$markdisabled.' type="submit" class="'.$css_class_name
1477
                        .'" name="'.$this->cgi['prefix']['sys'].ltrim($markdisabled).$name
1478
                        .'" value="'.(isset($this->labels[$label]) ? $this->labels[$label] : $label);
1479
                if ($js_validation) {
1480
                        $ret .= '" onclick="return '.$this->js['prefix'].'form_control(this.form);';
1481
                }
1482
                $ret .='"';
1483
                if(isset($js)) $ret .= ' '.$js;
1484
                $ret .= ' />';
1485
                return $ret;
1486
        } /* }}} */
1487

    
1488
        /**
1489
         * Creates HTML hidden input element
1490
         *
1491
         * @param        name        element name
1492
         * @param        value        value
1493
         */
1494

    
1495
        function htmlHiddenSys($name, $value) /* {{{ */
1496
        {
1497
                return $this->htmlHidden($this->cgi['prefix']['sys'].$name, $value);
1498
        } /* }}} */
1499

    
1500
        function htmlHiddenData($name, $value) /* {{{ */
1501
        {
1502
                return $this->htmlHidden($this->cgi['prefix']['data'].$name, $value);
1503
        } /* }}} */
1504

    
1505
        function htmlHidden($name, $value) /* {{{ */
1506
        {
1507
                return '<input type="hidden" name="'.htmlspecialchars($name)
1508
                        .'" value="'.htmlspecialchars($value).'" />'."\n";
1509
        } /* }}} */
1510

    
1511
        /**
1512
         * Creates HTML select element (tag)
1513
         *
1514
         * @param        name                element name
1515
         * @param        css                        CSS class name
1516
         * @param        kv_array        key => value array
1517
         * @param        selected        selected key (it can be single string, array of
1518
         *                                                keys or multiple values separated by comma)
1519
         * @param        multiple        bool for multiple selection
1520
         * @param        readonly        bool for readonly/disabled selection
1521
         * @param        strip_tags        bool for stripping tags from values
1522
         * @param        escape                bool for HTML escaping values
1523
         * @param        js                string to be in the <select >, ususally onchange='..';
1524
         */
1525
        function htmlSelect($name, $css, $kv_array, $selected = null, /* ...) {{{ */
1526
                        /* booleans: */ $multiple = false, $readonly = false, $strip_tags = false, $escape = true, $js = NULL)
1527
        {
1528
                $ret = '<select class="'.htmlspecialchars($css).'" name="'.htmlspecialchars($name);
1529
                if ($multiple) {
1530
                        $ret  .= '[]" multiple size="'.$this->multiple;
1531
                        if (! is_array($selected) && $selected !== null) {
1532
                                $selected = explode(',', $selected);
1533
                        }
1534
                }
1535
                $ret .= '"'.($readonly ? ' disabled ' : ' ').$js.">\n";
1536
                if (! is_array($selected)) {
1537
                        $selected = $selected === null ? array() : array((string)$selected);
1538
                } else {
1539
                        foreach($selected as $val) $selecte2[]=(string)$val;
1540
                        $selected = $selected2;
1541
                }
1542
                $found = false;
1543
                foreach ($kv_array as $key => $value) {
1544
                        $ret .= '<option value="'.htmlspecialchars($key).'"';
1545
                        if ((! $found || $multiple) && in_array((string)$key, $selected, 1)
1546
                                        || (count($selected) == 0 && ! $found && ! $multiple)) {
1547
                                $ret  .= ' selected="selected"';
1548
                                $found = true;
1549
                        }
1550
                        $strip_tags && $value = strip_tags($value);
1551
                        $escape     && $value = htmlspecialchars($value);
1552
                        $ret .= '>'.$value.'</option>'."\n";
1553
                }
1554
                $ret .= '</select>';
1555
                return $ret;
1556
        } /* }}} */
1557

    
1558
        /**
1559
         * Creates HTML checkboxes or radio buttons
1560
         *
1561
         * @param        name                element name
1562
         * @param        css                        CSS class name
1563
         * @param        kv_array        key => value array
1564
         * @param        selected        selected key (it can be single string, array of
1565
         *                                                keys or multiple values separated by comma)
1566
         * @param        multiple        bool for multiple selection (checkboxes)
1567
         * @param        readonly        bool for readonly/disabled selection
1568
         * @param        strip_tags        bool for stripping tags from values
1569
         * @param        escape                bool for HTML escaping values
1570
         * @param        js                string to be in the <select >, ususally onchange='..';
1571
         */
1572
        function htmlRadioCheck($name, $css, $kv_array, $selected = null, /* ...) {{{ */
1573
                        /* booleans: */ $multiple = false, $readonly = false, $strip_tags = false, $escape = true, $js = NULL)
1574
        {
1575
                $ret = '';
1576
                if ($multiple) {
1577
                        if (! is_array($selected) && $selected !== null) {
1578
                                $selected = explode(',', $selected);
1579
                        }
1580
                }
1581
                if (! is_array($selected)) {
1582
                        $selected = $selected === null ? array() : array($selected);
1583
                }
1584
                $found = false;
1585
                foreach ($kv_array as $key => $value) {
1586
                        $ret .= '<input type="'.($multiple ? 'checkbox' : 'radio').'" name="';
1587
                        $ret .= htmlspecialchars($name).'[]" value="'.htmlspecialchars($key).'"';
1588
                        if ((! $found || $multiple) && in_array((string) $key, $selected, 1)
1589
                                        || (count($selected) == 0 && ! $found && ! $multiple)) {
1590
                                $ret  .= ' checked';
1591
                                $found = true;
1592
                        }
1593
                        if ($readonly) {
1594
                                $ret .= ' disabled';
1595
                        }
1596
                        $strip_tags && $value = strip_tags($value);
1597
                        $escape     && $value = htmlspecialchars($value);
1598
                        $ret .= '>'.$value.'<br>'."\n";
1599
                }
1600
                return $ret;
1601
        } /* }}} */
1602

    
1603
    /**
1604
     * Returns original variables HTML code for use in forms or links.
1605
     *
1606
     * @param   mixed   $origvars       string or array of original varaibles
1607
     * @param   string  $method         type of method ("POST" or "GET")
1608
     * @param   mixed   $default_value  default value of variables
1609
     *                                  if null, empty values will be skipped
1610
     * @return                          get HTML code of original varaibles
1611
     */
1612
    function get_origvars_html($origvars, $method = 'post', $default_value = '') /* {{{ */
1613
    {
1614
        $ret    = '';
1615
        $method = strtoupper($method);
1616
        if ($method == 'POST') {
1617
            if (! is_array($origvars)) {
1618
                $new_origvars = array();
1619
                foreach (explode('&', $origvars) as $param) {
1620
                    $parts = explode('=', $param, 2);
1621
                    if (! isset($parts[1])) {
1622
                        $parts[1] = $default_value;
1623
                    }
1624
                    if (strlen($parts[0]) <= 0) {
1625
                        continue;
1626
                    }
1627
                    $new_origvars[$parts[0]] = $parts[1];
1628
                }
1629
                $origvars =& $new_origvars;
1630
            }
1631
            foreach ($origvars as $key => $val) {
1632
                if (strlen($val) <= 0 && $default_value === null) {
1633
                    continue;
1634
                }
1635
                $key = rawurldecode($key);
1636
                $val = rawurldecode($val);
1637
                $ret .= $this->htmlHidden($key, $val);
1638
            }
1639
        } else if (! strncmp('GET', $method, 3)) {
1640
            if (! is_array($origvars)) {
1641
                $ret .= $origvars;
1642
            } else {
1643
                foreach ($origvars as $key => $val) {
1644
                    if (strlen($val) <= 0 && $default_value === null) {
1645
                        continue;
1646
                    }
1647
                    $ret == '' || $ret .= '&amp;';
1648
                    $ret .= htmlspecialchars(rawurlencode($key));
1649
                    $ret .= '=';
1650
                    $ret .= htmlspecialchars(rawurlencode($val));
1651
                }
1652
            }
1653
            if ($method[strlen($method) - 1] == '+') {
1654
                $ret = "?$ret";
1655
            }
1656
        } else {
1657
            trigger_error('Unsupported Platon::get_origvars_html() method: '
1658
                    .$method, E_USER_ERROR);
1659
        }
1660
        return $ret;
1661
    } /* }}} */
1662

    
1663
        function get_sfn_cgi_vars($alternative_sfn = null) /* {{{ */
1664
        {
1665
                if ($alternative_sfn === null) { // FAST! (cached return value)
1666
                        static $ret = null;
1667
                        $ret == null && $ret = $this->get_sfn_cgi_vars($this->sfn);
1668
                        return $ret;
1669
                }
1670
                $ret = '';
1671
                $i   = 0;
1672
                foreach ($alternative_sfn as $val) {
1673
                        $ret != '' && $ret .= '&';
1674
                        $ret .= rawurlencode($this->cgi['prefix']['sys'].'sfn')."[$i]=".rawurlencode($val);
1675
                        $i++;
1676
                }
1677
                return $ret;
1678
        } /* }}} */
1679

    
1680
        function get_default_cgi_prefix($type) /* {{{ */
1681
        {
1682
                switch ($type) {
1683
                        case 'operation':        return 'PME_op_';
1684
                        case 'sys':                        return 'PME_sys_';
1685
                        case 'data':                return 'PME_data_';
1686
                }
1687
                return '';
1688
        } /* }}} */
1689

    
1690
        function get_sys_cgi_var($name, $default_value = null) /* {{{ */
1691
        {
1692
                if (isset($this)) {
1693
                        return $this->get_cgi_var($this->cgi['prefix']['sys'].$name, $default_value);
1694
                }
1695
                return phpMyEdit::get_cgi_var(phpMyEdit::get_default_cgi_prefix('sys').$name, $default_value);
1696
        } /* }}} */
1697

    
1698
        function get_data_cgi_var($name, $default_value = null) /* {{{ */
1699
        {
1700
                if (isset($this)) {
1701
                        return $this->get_cgi_var($this->cgi['prefix']['data'].$name, $default_value);
1702
                }
1703
                return phpMyEdit::get_cgi_var(phpMyEdit::get_default_cgi_prefix('data').$name, $default_value);
1704
        } /* }}} */
1705

    
1706
    function get_cgi_var($name, $default_value = null) /* {{{ */
1707
    {
1708
                if (isset($this) && isset($this->cgi['overwrite'][$name])) {
1709
                        return $this->cgi['overwrite'][$name];
1710
                }
1711

    
1712
        static $magic_quotes_gpc = null;
1713
        if ($magic_quotes_gpc === null) {
1714
            $magic_quotes_gpc = get_magic_quotes_gpc();
1715
        }
1716
        $var = @$_GET[$name];
1717
        if (! isset($var)) {
1718
            $var = @$_POST[$name];
1719
        }
1720
        if (isset($var)) {
1721
            if ($magic_quotes_gpc) {
1722
                if (is_array($var)) {
1723
                    foreach (array_keys($var) as $key) {
1724
                        $var[$key] = stripslashes($var[$key]);
1725
                    }
1726
                } else {
1727
                    $var = stripslashes($var);
1728
                }
1729
            }
1730
        } else {
1731
            $var = @$default_value;
1732
        }
1733
                if (isset($this) && $var === null && isset($this->cgi['append'][$name])) {
1734
                        return $this->cgi['append'][$name];
1735
                }
1736
        return $var;
1737
    } /* }}} */
1738

    
1739
        function get_server_var($name) /* {{{ */
1740
        {
1741
                if (isset($_SERVER[$name])) {
1742
                        return $_SERVER[$name];
1743
                }
1744
                global $HTTP_SERVER_VARS;
1745
                if (isset($HTTP_SERVER_VARS[$name])) {
1746
                        return $HTTP_SERVER_VARS[$name];
1747
                }
1748
                global $$name;
1749
                if (isset($$name)) {
1750
                        return $$name;
1751
                }
1752
                return null;
1753
        } /* }}} */
1754

    
1755
        /*
1756
         * Debug functions
1757
         */
1758

    
1759
        function print_get_vars ($miss = 'No GET variables found') // debug only /* {{{ */
1760
        {
1761
                // we parse form GET variables
1762
                if (is_array($_GET)) {
1763
                        echo "<p> Variables per GET ";
1764
                        foreach ($_GET as $k => $v) {
1765
                                if (is_array($v)) {
1766
                                        foreach ($v as $akey => $aval) {
1767
                                                // $_GET[$k][$akey] = strip_tags($aval);
1768
                                                // $$k[$akey] = strip_tags($aval);
1769
                                                echo "$k\[$akey\]=$aval   ";
1770
                                        }
1771
                                } else {
1772
                                        // $_GET[$k] = strip_tags($val);
1773
                                        // $$k = strip_tags($val);
1774
                                        echo "$k=$v   ";
1775
                                }
1776
                        }
1777
                        echo '</p>';
1778
                } else {
1779
                        echo '<p>';
1780
                        echo $miss;
1781
                        echo '</p>';
1782
                }
1783
        } /* }}} */
1784

    
1785
        function print_post_vars($miss = 'No POST variables found')  // debug only /* {{{ */
1786
        {
1787
                global $_POST;
1788
                // we parse form POST variables
1789
                if (is_array($_POST)) {
1790
                        echo "<p>Variables per POST ";
1791
                        foreach ($_POST as $k => $v) {
1792
                                if (is_array($v)) {
1793
                                        foreach ($v as $akey => $aval) {
1794
                                                // $_POST[$k][$akey] = strip_tags($aval);
1795
                                                // $$k[$akey] = strip_tags($aval);
1796
                                                echo "$k\[$akey\]=$aval   ";
1797
                                        }
1798
                                } else {
1799
                                        // $_POST[$k] = strip_tags($val);
1800
                                        // $$k = strip_tags($val);
1801
                                        echo "$k=$v   ";
1802
                                }
1803
                        }
1804
                        echo '</p>';
1805
                } else {
1806
                        echo '<p>';
1807
                        echo $miss;
1808
                        echo '</p>';
1809
                }
1810
        } /* }}} */
1811

    
1812
        function print_vars ($miss = 'Current instance variables')  // debug only /* {{{ */
1813
        {
1814
                echo "$miss   ";
1815
                echo 'page_name=',$this->page_name,'   ';
1816
                echo 'hn=',$this->hn,'   ';
1817
                echo 'un=',$this->un,'   ';
1818
                echo 'pw=',$this->pw,'   ';
1819
                echo 'db=',$this->db,'   ';
1820
                echo 'dbp=',$this->dbp,'   ';
1821
                echo 'dbh=',$this->dbh,'   ';
1822
                echo 'tb=',$this->tb,'   ';
1823
                echo 'key=',$this->key,'   ';
1824
                echo 'key_type=',$this->key_type,'   ';
1825
                echo 'inc=',$this->inc,'   ';
1826
                echo 'options=',$this->options,'   ';
1827
                echo 'fdd=',$this->fdd,'   ';
1828
                echo 'fl=',$this->fl,'   ';
1829
                echo 'fm=',$this->fm,'   ';
1830
                echo 'sfn=',htmlspecialchars($this->get_sfn_cgi_vars()),'   ';
1831
                echo 'qfn=',$this->qfn,'   ';
1832
                echo 'sw=',$this->sw,'   ';
1833
                echo 'rec=',$this->rec,'   ';
1834
                echo 'navop=',$this->navop,'   ';
1835
                echo 'saveadd=',$this->saveadd,'   ';
1836
                echo 'moreadd=',$this->moreadd,'   ';
1837
                echo 'canceladd=',$this->canceladd,'   ';
1838
                echo 'savechange=',$this->savechange,'   ';
1839
                echo 'morechange=',$this->morechange,'   ';
1840
                echo 'cancelchange=',$this->cancelchange,'   ';
1841
                echo 'savecopy=',$this->savecopy,'   ';
1842
                echo 'cancelcopy=',$this->cancelcopy,'   ';
1843
                echo 'savedelete=',$this->savedelete,'   ';
1844
                echo 'canceldelete=',$this->canceldelete,'   ';
1845
                echo 'cancelview=',$this->cancelview,'   ';
1846
                echo 'operation=',$this->operation,'   ';
1847
                echo "\n";
1848
        } /* }}} */
1849

    
1850
        /*
1851
         * Display buttons at top and bottom of page
1852
         */
1853
        function display_list_table_buttons($position, $listall = false) /* {{{ */
1854
        {
1855
                if (($but_str = $this->display_buttons($position)) === null)
1856
                        return;
1857
                if($position == 'down') echo '<hr size="1" class="'.$this->getCSSclass('hr', 'down').'" />'."\n";
1858
                echo '<table summary="navigation" class="',$this->getCSSclass('navigation', $position),'">',"\n";
1859
                echo '<tr class="',$this->getCSSclass('navigation', $position),'">',"\n";
1860
                echo '<td class="',$this->getCSSclass('buttons', $position),'">',"\n";
1861
                echo $but_str,'</td>',"\n";
1862
                // Message is now written here
1863
                if (strlen(@$this->message) > 0) {
1864
                        echo '<td class="',$this->getCSSclass('message', $position),'">',$this->message,'</td>',"\n";
1865
                }
1866
                if($this->display['num_pages'] || $this->display['num_records'])
1867
                        echo '<td class="',$this->getCSSclass('stats', $position),'">',"\n";
1868
                if($this->display['num_pages']) {
1869
                        if ($listall) {
1870
                                echo $this->labels['Page'],':&nbsp;1&nbsp;',$this->labels['of'],'&nbsp;1';
1871
                        } else {
1872
                                $current_page = intval($this->fm / $this->inc) + 1;
1873
                                $total_pages  = max(1, ceil($this->total_recs / abs($this->inc)));
1874
                                echo $this->labels['Page'],':&nbsp;',$current_page;
1875
                                echo '&nbsp;',$this->labels['of'],'&nbsp;',$total_pages;
1876
                        }
1877
                }
1878
                if($this->display['num_records'])
1879
                        echo '&nbsp; ',$this->labels['Records'],':&nbsp;',$this->total_recs;
1880
                if($this->display['num_pages'] || $this->display['num_records']) echo '</td>';
1881
                echo '</tr></table>',"\n";
1882
                if($position == 'up') echo '<hr size="1" class="'.$this->getCSSclass('hr', 'up').'" />'."\n";
1883
        } /* }}} */
1884

    
1885
        /*
1886
         * Display buttons at top and bottom of page
1887
         */
1888
        function display_record_buttons($position) /* {{{ */
1889
        {
1890
                if (($but_str = $this->display_buttons($position)) === null)
1891
                        return;
1892
                if ($position == 'down') {
1893
                        if ($this->tabs_enabled()) $this->display_tab_labels('down');
1894
                        echo '<hr size="1" class="',$this->getCSSclass('hr', 'down'),'" />',"\n";
1895
                }
1896
                echo '<table summary="navigation" class="',$this->getCSSclass('navigation', $position),'">',"\n";
1897
                echo '<tr class="',$this->getCSSclass('navigation', $position),'">',"\n";
1898
                echo '<td class="',$this->getCSSclass('buttons', $position),'">',"\n";
1899
                echo $but_str,'</td>',"\n";
1900
                // Message is now written here
1901
                //echo '</td>',"\n";
1902
                if (strlen(@$this->message) > 0) {
1903
                        echo '<td class="',$this->getCSSclass('message', $position),'">',$this->message,'</td>',"\n";
1904
                }
1905
                echo '</tr></table>',"\n";
1906
                if ($position == 'up') {
1907
                        if ($this->tabs_enabled()) $this->display_tab_labels('up');
1908
                        echo '<hr size="1" class="',$this->getCSSclass('hr', 'up'),'" />',"\n";
1909
                }
1910
        } /* }}} */
1911

    
1912
        function display_buttons($position) /* {{{ */
1913
        {
1914
                $nav_fnc = 'nav_'.$position;
1915
                if(! $this->$nav_fnc())
1916
                        return;
1917
                $buttons = (is_array($this->buttons[$this->page_type][$position]))
1918
                        ? $this->buttons[$this->page_type][$position]
1919
                        : $this->default_buttons[$this->page_type];
1920
                foreach ($buttons as $name) {
1921
                        $ret .= $this->display_button($name, $position)."\n";
1922
                }
1923
                return $ret;
1924
        } /* }}} */
1925

    
1926
        function display_button($name, $position = 'up') /* {{{ */
1927
        {
1928
                if (is_array($name)) {
1929
                        if (isset($name['code'])) return $name['code'];
1930
                        return $this->htmlSubmit($name['name'], $name['value'], $name['css'], $name['js_validation'], $name['disabled'], $name['js']);
1931
                }
1932
                $disabled = 1; // show disabled by default
1933
                if ($name[0] == '+') { $name = substr($name, 1); $disabled =  0; } // always show disabled as enabled
1934
                if ($name[0] == '-') { $name = substr($name, 1); $disabled = -1; } // don't show disabled
1935
                if ($name == 'cancel') {
1936
                        return $this->htmlSubmit('cancel'.$this->page_types[$this->page_type], 'Cancel',
1937
                                        $this->getCSSclass('cancel', $position), false);
1938
                }
1939
                if (in_array($name, array('add','view','change','copy','delete'))) {
1940
                        $enabled_fnc = $name.'_enabled';
1941
                        $enabled     = $this->$enabled_fnc();
1942
                        if ($name != 'add' && ! $this->total_recs && strstr('LF', $this->page_type))
1943
                                $enabled = false;
1944
                        return $this->htmlSubmit('operation', ucfirst($name),
1945
                                        $this->getCSSclass($name, $position), false, $enabled ? 0 : $disabled);
1946
                }
1947
                if ($name == 'savedelete') {
1948
                        $enabled     = $this->delete_enabled();
1949
                        $js = 'onclick="return confirm(\''.$this->labels['Delete'].' ?\');"';
1950
                        return $this->htmlSubmit('savedelete', 'Delete',
1951
                                        $this->getCSSclass('save', $position), false, $enabled ? 0 : $disabled, $js);
1952
                }
1953
                if (in_array($name, array('save','more'))) {
1954
                        $validation = true; // if js validation
1955
                        if     ($this->page_type == 'D' && $name == 'save' ) { $value = 'Delete'; $validation = false; }
1956
                        elseif ($this->page_type == 'C' && $name == 'more' ) { $value = 'Apply'; }
1957
                        else $value = ucfirst($name);
1958
                        return $this->htmlSubmit($name.$this->page_types[$this->page_type], $value,
1959
                                        $this->getCSSclass($name, $position), $validation);
1960
                }
1961
                $listall = $this->inc <= 0;
1962
                if ($listall) {
1963
                        $disabledprev = true;
1964
                        $disablednext = true;
1965
                        $total_pages  = 1;
1966
                        $current_page = 1;
1967
                } else {
1968
                        $disabledprev = $this->fm <= 0;
1969
                        $disablednext =  $this->fm + $this->inc >= $this->total_recs;
1970
                        $total_pages  = max(1, ceil($this->total_recs / abs($this->inc)));
1971
                        $current_page = ceil($this->fm / abs($this->inc)); // must + 1
1972
                }
1973
                $disabledfirst = $disabledprev;
1974
                $disabledlast  = $disablednext;
1975
                // some statistics first
1976
                if ($name == 'total_pages') return $total_pages;
1977
                if ($name == 'current_page') return ($current_page+1);
1978
                if ($name == 'total_recs') return ($this->total_recs);
1979
                // now some goto buttons/dropdowns/inputs...
1980
                if ($name == 'goto_text') {
1981
                        $ret = '<input type="text" class="'.$this->getCSSclass('gotopn', $position).'"';
1982
                        $ret .= ' name="'.$this->cgi['prefix']['sys'].'navpn'.$position.'" value="'.($current_page+1).'"';
1983
                        $ret .= ' size="'.(strlen($total_pages)+1).'" maxlength="'.(strlen($total_pages)+1).'"';
1984
                        // TODO some js here.... on enter submit, on click erase ?...
1985
                        $ret .=' oneypress="return PE_filter_handler(this.form, event);" />';
1986
                        return $ret;
1987
                }
1988
                if ($name == 'goto_combo') {
1989
                        $disabledgoto = !($listall || ($disablednext && $disabledprev)) ? '' : ' disabled';
1990
                        if ($disablegoto != '' && $disabled < 0) return;
1991
                        $kv_array = array();
1992
                        for ($i = 0; $i < $total_pages; $i++) {
1993
                                $kv_array[$this->inc * $i] = $i + 1;
1994
                        }
1995
                        // TODO: add onchange="return this.form.submit();" DONE ???
1996
                        return $this->htmlSelect($this->cgi['prefix']['sys'].ltrim($disabledgoto).'navfm'.$position,
1997
                                        $this->getCSSclass('goto', $position), $kv_array, (string)$this->fm, false, $disabledgoto,
1998
                                        false, true, 'onchange="return this.form.submit();"');
1999
                }
2000
                if ($name == 'goto') {
2001
                        return $this->htmlSubmit('navop', 'Go to', $this->getCSSclass('goto', $position),
2002
                                        false, ($listall || ($disablednext && $disabledprev)) ? $disabled : 0);
2003
                }
2004
                if (in_array($name, array('first','prev','next','last','<<','<','>','>>'))) {
2005
                        $disabled_var = 'disabled'.$name;
2006
                        $name2 = $name;
2007
                        if (strlen($name) <= 2) {
2008
                                $nav_values = array('<<' => 'first', '<' => 'prev', '>' => 'next', '>>' => 'last');
2009
                                $disabled_var = 'disabled'.$nav_values[$name];
2010
                                $name2 = $nav_values[$name];
2011
                        }
2012
                        return $this->htmlSubmit('navop', ucfirst($name),
2013
                                        $this->getCSSclass($name2, $position), false, $$disabled_var ? $disabled : 0);
2014
                }
2015
                if(isset($this->labels[$name])) return $this->labels[$name];
2016
                return $name;
2017
        } /* }}} */
2018

    
2019
        function number_of_recs() /* {{{ */
2020
        {
2021
                $count_parts = array(
2022
                                'type'   => 'select',
2023
                                'select' => 'count(*)',
2024
                                'from'   => $this->get_SQL_join_clause(),
2025
                                'where'  => $this->get_SQL_where_from_query_opts());
2026
                $res = $this->myquery($this->get_SQL_main_list_query($count_parts), __LINE__);
2027
                $row = $this->sql_fetch($res, 'n');
2028
                $this->total_recs = $row[0];
2029
        } /* }}} */
2030

    
2031
        /*
2032
         * Table Page Listing
2033
         */
2034
        function list_table() /* {{{ */
2035
        {
2036
                if ($this->fm == '') {
2037
                        $this->fm = 0;
2038
                }
2039
                $this->fm = $this->navfm;
2040
                if ($this->prev_operation()) {
2041
                        $this->fm = $this->fm - $this->inc;
2042
                        if ($this->fm < 0) {
2043
                                $this->fm = 0;
2044
                        }
2045
                }
2046
                if ($this->first_operation()) {
2047
                        $this->fm = 0;
2048
                } // last operation must be performed below, after retrieving total_recs
2049
                if ($this->next_operation()) {
2050
                        $this->fm += $this->inc;
2051
                }
2052
                $this->number_of_recs();
2053
                if ($this->last_operation() || $this->fm > $this->total_recs) { // if goto_text is badly set
2054
                        $this->fm = (int)(($this->total_recs - 1)/$this->inc)*$this->inc;
2055
                }
2056
                // If sort sequence has changed, restart listing
2057
                $this->qfn != $this->prev_qfn && $this->fm = 0;
2058
                if (0) { // DEBUG
2059
                        echo 'qfn vs. prev_qfn comparsion ';
2060
                        echo '[<b>',htmlspecialchars($this->qfn),'</b>]';
2061
                        echo '[<b>',htmlspecialchars($this->prev_qfn),'</b>]<br />';
2062
                        echo 'comparsion <u>',($this->qfn == $this->prev_qfn ? 'proved' : 'failed'),'</u>';
2063
                        echo '<hr size="1" />';
2064
                }
2065
                /*
2066
                 * If user is allowed to Change/Delete records, we need an extra column
2067
                 * to allow users to select a record
2068
                 */
2069
                $select_recs = $this->key != '' &&
2070
                        ($this->change_enabled() || $this->delete_enabled() || $this->view_enabled());
2071
                // Are we doing a listall?
2072
                $listall = $this->inc <= 0;
2073
                /*
2074
                 * Display the SQL table in an HTML table
2075
                 */
2076
                $this->form_begin();
2077
                echo $this->get_origvars_html($this->get_sfn_cgi_vars());
2078
                echo $this->htmlHiddenSys('fl', $this->fl);
2079
                // Display buttons at top and/or bottom of page.
2080
                $this->display_list_table_buttons('up', $listall);
2081
                if ($this->cgi['persist'] != '') {
2082
                        echo $this->get_origvars_html($this->cgi['persist']);
2083
                }
2084
                if (! $this->filter_operation()) {
2085
                        echo $this->get_origvars_html($this->qfn);
2086
                }
2087
                echo $this->htmlHiddenSys('qfn', $this->qfn);
2088
                echo $this->htmlHiddenSys('fm', $this->fm);
2089
                echo '<table class="',$this->getCSSclass('main'),'" summary="',$this->tb,'">',"\n";
2090
                echo '<tr class="',$this->getCSSclass('header'),'">',"\n";
2091
                /*
2092
                 * System (navigation, selection) columns counting
2093
                 */
2094
                $sys_cols  = 0;
2095
                $sys_cols += intval($this->filter_enabled() || $select_recs);
2096
                if ($sys_cols > 0) {
2097
                        $sys_cols += intval($this->nav_buttons()
2098
                                        && ($this->nav_text_links() || $this->nav_graphic_links()));
2099
                }
2100
                /*
2101
                 * We need an initial column(s) (sys columns)
2102
                 * if we have filters, Changes or Deletes enabled
2103
                 */
2104
                if ($sys_cols) {
2105
                        echo '<th class="',$this->getCSSclass('header'),'" colspan="',$sys_cols,'">';
2106
                        if ($this->filter_enabled()) {
2107
                                if ($this->filter_operation()) {
2108
                                        echo $this->htmlSubmit('sw', 'Hide', $this->getCSSclass('hide'), false);
2109
                                        echo $this->htmlSubmit('sw', 'Clear', $this->getCSSclass('clear'), false);
2110
                                } else {
2111
                                        echo $this->htmlSubmit('sw', 'Search', $this->getCSSclass('search'), false);
2112
                                }
2113
                        } else {
2114
                                echo '&nbsp;';
2115
                        }
2116
                        echo '</th>',"\n";
2117
                }
2118
                for ($k = 0; $k < $this->num_fds; $k++) {
2119
                        $fd = $this->fds[$k];
2120
                        if (! $this->displayed[$k]) {
2121
                                continue;
2122
                        }
2123
                        $css_postfix    = @$this->fdd[$k]['css']['postfix'];
2124
                        $css_class_name = $this->getCSSclass('header', null, null, $css_postfix);
2125
                        $fdn = $this->fdd[$fd]['name'];
2126
                        if (! $this->fdd[$fd]['sort'] || $this->password($fd)) {
2127
                                echo '<th class="',$css_class_name,'">',$fdn,'</th>',"\n";
2128
                        } else {
2129
                                // Clicking on the current sort field reverses the sort order
2130
                                $new_sfn = $this->sfn;
2131
                                array_unshift($new_sfn, in_array("$k", $new_sfn, 1) ? "-$k" : $k);
2132
                                echo '<th class="',$css_class_name,'">';
2133
                                echo '<a class="',$css_class_name,'" href="';
2134
                                echo htmlspecialchars($this->page_name.'?'.$this->cgi['prefix']['sys'].'fm'.'=0'
2135
                                                .'&'.$this->cgi['prefix']['sys'].'fl'.'='.$this->fl
2136
                                                .'&'.$this->cgi['prefix']['sys'].'qfn'.'='.rawurlencode($this->qfn).$this->qfn
2137
                                                .'&'.$this->get_sfn_cgi_vars($new_sfn).$this->cgi['persist']);
2138
                                echo '">',$fdn,'</a></th>',"\n";
2139
                        }
2140
                }
2141
                echo '</tr>',"\n";
2142

    
2143
                /*
2144
                 * Prepare the SQL Query from the data definition file
2145
                 */
2146
                $qparts['type']   = 'select';
2147
                $qparts['select'] = $this->get_SQL_column_list();
2148
                // Even if the key field isn't displayed, we still need its value
2149
                if ($select_recs) {
2150
                        if (!in_array ($this->key, $this->fds)) {
2151
                                $qparts['select'] .= ','.$this->fqn($this->key);
2152
                        }
2153
                }
2154
                $qparts['from']  = $this->get_SQL_join_clause();
2155
                $qparts['where'] = $this->get_SQL_where_from_query_opts();
2156
                // build up the ORDER BY clause
2157
                if (isset($this->sfn)) {
2158
                        $sort_fields   = array();
2159
                        $sort_fields_w = array();
2160
                        foreach ($this->sfn as $field) {
2161
                                if ($field[0] == '-') {
2162
                                        $field = substr($field, 1);
2163
                                        $desc  = true;
2164
                                } else {
2165
                                        $field = $field;
2166
                                        $desc  = false;
2167
                                }
2168
                                $sort_field   = $this->fqn($field);
2169
                                $sort_field_w = $this->fdd[$field]['name'];
2170
                                $this->col_has_sql($field) && $sort_field_w .= ' (sql)';
2171
                                if ($desc) {
2172
                                        $sort_field   .= ' DESC';
2173
                                        $sort_field_w .= ' '.$this->labels['descending'];
2174
                                } else {
2175
                                        $sort_field_w .= ' '.$this->labels['ascending'];
2176
                                }
2177
                                $sort_fields[]   = $sort_field;
2178
                                $sort_fields_w[] = $sort_field_w;
2179
                        }
2180
                        if (count($sort_fields) > 0) {
2181
                                $qparts['orderby'] = join(',', $sort_fields);
2182
                        }
2183
                }
2184
                $qparts['limit'] = $listall ? '' : $this->sql_limit($this->fm,$this->inc);
2185

    
2186
                /*
2187
                 * Main list_table() query
2188
                 *
2189
                 * Each row of the HTML table is one record from the SQL query. We must
2190
                 * perform this query before filter printing, because we want to use
2191
                 * $this->sql_field_len() function. We will also fetch the first row to get
2192
                 * the field names.
2193
                 */
2194
                $query = $this->get_SQL_main_list_query($qparts);
2195
                $res   = $this->myquery($query, __LINE__);
2196
                if ($res == false) {
2197
                        $this->error('invalid SQL query', $query);
2198
                        return false;
2199
                }
2200
                $row = $this->sql_fetch($res);
2201

    
2202
                /* FILTER {{{
2203
                 *
2204
                 * Draw the filter and fill it with any data typed in last pass and stored
2205
                 * in the array parameter keyword 'filter'. Prepare the SQL WHERE clause.
2206
                 */
2207
                if ($this->filter_operation()) {
2208
                        // Filter row retrieval
2209
                        $fields     = false;
2210
                        $filter_row = $row;
2211
                        if (! is_array($filter_row)) {
2212
                                unset($qparts['where']);
2213
                                $query = $this->get_SQL_query($qparts);
2214
                                $res   = $this->myquery($query, __LINE__);
2215
                                if ($res == false) {
2216
                                        $this->error('invalid SQL query', $query);
2217
                                        return false;
2218
                                }
2219
                                $filter_row = $this->sql_fetch($res);
2220
                        }
2221
                        /* Variable $fields is used to get index of particular field in
2222
                           result. That index can be passed in example to $this->sql_field_len()
2223
                           function. Use field names as indexes to $fields array. */
2224
                        if (is_array($filter_row)) {
2225
                                $fields = array_flip(array_keys($filter_row));
2226
                        }
2227
                        if ($fields != false) {
2228
                                $css_class_name = $this->getCSSclass('filter');
2229
                                echo '<tr class="',$css_class_name,'">',"\n";
2230
                                echo '<td class="',$css_class_name,'" colspan="',$sys_cols,'">';
2231
                                echo $this->htmlSubmit('filter', 'Query', $this->getCSSclass('query'), false);
2232
                                echo '</td>', "\n";
2233
                                for ($k = 0; $k < $this->num_fds; $k++) {
2234
                                        if (! $this->displayed[$k]) {
2235
                                                continue;
2236
                                        }
2237
                                        $css_postfix      = @$this->fdd[$k]['css']['postfix'];
2238
                                        $css_class_name   = $this->getCSSclass('filter', null, null, $css_postfix);
2239
                                        $this->field_name = $this->fds[$k];
2240
                                        $fd               = $this->field_name;
2241
                                        $this->field      = $this->fdd[$fd];
2242
                                        $l  = 'qf'.$k;
2243
                                        $lc = 'qf'.$k.'_comp';
2244
                                        $li = 'qf'.$k.'_id';
2245
                                        if ($this->clear_operation()) {
2246
                                                $m  = null;
2247
                                                $mc = null;
2248
                                                $mi = null;
2249
                                        } else {
2250
                                                $m  = $this->get_sys_cgi_var($l);
2251
                                                $mc = $this->get_sys_cgi_var($lc);
2252
                                                $mi = $this->get_sys_cgi_var($li);
2253
                                        }
2254
                                        echo '<td class="',$css_class_name,'">';
2255
                                        if ($this->password($k)) {
2256
                                                echo '&nbsp;';
2257
                                        } else if ($this->fdd[$fd]['select'] == 'D' || $this->fdd[$fd]['select'] == 'M') {
2258
                                                // Multiple fields processing
2259
                                                // Default size is 2 and array required for values.
2260
                                                $from_table = ! $this->col_has_values($k) || isset($this->fdd[$k]['values']['table']);
2261
                                                $vals       = $this->set_values($k, array('*' => '*'), null, $from_table);
2262
                                                $selected   = $mi;
2263
                                                $multiple   = $this->col_has_multiple_select($k);
2264
                                                $multiple  |= $this->fdd[$fd]['select'] == 'M';
2265
                                                $readonly   = false;
2266
                                                $strip_tags = true;
2267
                                                $escape     = true;
2268
                                                echo $this->htmlSelect($this->cgi['prefix']['sys'].$l.'_id', $css_class_name,
2269
                                                                $vals, $selected, $multiple, $readonly, $strip_tags, $escape);
2270
                                        } elseif ($this->fdd[$fd]['select'] == 'N' || $this->fdd[$fd]['select'] == 'T') {
2271
                                                $len_props = '';
2272
                                                $maxlen = intval($this->fdd[$k]['maxlen']);
2273
                                                $maxlen > 0 || $maxlen = intval($this->sql_field_len($res, $fields["qf$k"]));
2274
                                                $size = isset($this->fdd[$k]['size']) ? $this->fdd[$k]['size']
2275
                                                        : ($maxlen < 30 ? min($maxlen, 8) : 12);
2276
                                                $len_props .= ' size="'.$size.'"';
2277
                                                $len_props .= ' maxlength="'.$maxlen.'"';
2278
                                                if ($this->fdd[$fd]['select'] == 'N') {
2279
                                                        $mc = in_array($mc, $this->comp_ops) ? $mc : '=';
2280
                                                        echo $this->htmlSelect($this->cgi['prefix']['sys'].$l.'_comp',
2281
                                                                        $css_class_name, $this->comp_ops, $mc);
2282
                                                }
2283
                                                echo '<input class="',$css_class_name,'" value="',htmlspecialchars(@$m);
2284
                                                echo '" type="text" name="'.$this->cgi['prefix']['sys'].'qf'.$k.'"',$len_props;
2285
                                                echo ' onkeypress="return '.$this->js['prefix'].'filter_handler(this.form, event);" />';
2286
                                        } else {
2287
                                                echo '&nbsp;';
2288
                                        }
2289
                                        echo '</td>',"\n";
2290
                                }
2291
                                echo '</tr>',"\n";
2292
                        }
2293
                } // }}}
2294
                
2295
                /*
2296
                 * Display sorting sequence
2297
                 */
2298
                if ($qparts['orderby'] && $this->display['sort']) {
2299
                        $css_class_name = $this->getCSSclass('sortinfo');
2300
                        echo '<tr class="',$css_class_name,'">',"\n";
2301
                        echo '<td class="',$css_class_name,'" colspan="',$sys_cols,'">';
2302
                        echo '<a class="',$css_class_name,'" href="';
2303
                        echo htmlspecialchars($this->page_name
2304
                                        .'?'.$this->cgi['prefix']['sys'].'fl'.'='.$this->fl
2305
                                        .'&'.$this->cgi['prefix']['sys'].'fm'.'='.$this->fm
2306
                                        .'&'.$this->cgi['prefix']['sys'].'qfn'.'='.rawurlencode($this->qfn)
2307
                                        .$this->qfn.$this->cgi['persist']);
2308
                        echo '">',$this->labels['Clear'],'</a></td>',"\n";
2309
                        echo '<td class="',$css_class_name,'" colspan="',$this->num_fields_displayed,'">';
2310
                        echo $this->labels['Sorted By'],': ',join(', ', $sort_fields_w),'</td></tr>',"\n";
2311
                }
2312

    
2313
                /*
2314
                 * Display the current query
2315
                 */
2316

    
2317
                $text_query = $this->get_SQL_where_from_query_opts(null, true);
2318
                if ($text_query != '' && $this->display['query']) {
2319
                        $css_class_name = $this->getCSSclass('queryinfo');
2320
                        echo '<tr class="',$css_class_name,'">',"\n";
2321
                        echo '<td class="',$css_class_name,'" colspan="',$sys_cols,'">';
2322
                        echo '<a class="',$css_class_name,'" href="';
2323
                        echo htmlspecialchars($this->get_server_var('PHP_SELF')
2324
                                        .'?'.$this->cgi['prefix']['sys'].'fl'.'='.$this->fl
2325
                                        .'&'.$this->cgi['prefix']['sys'].'fm'.'='.$this->fm
2326
                                        .'&'.$this->cgi['prefix']['sys'].'qfn'.'='.rawurlencode($this->qfn)
2327
                                        .'&'.$this->get_sfn_cgi_vars().$this->cgi['persist']);
2328
                        echo '">',$this->labels['Clear'],'</a></td>',"\n";
2329
                        echo '<td class="',$css_class_name,'" colspan="',$this->num_fields_displayed,'">';
2330
                        echo $this->labels['Current Query'],': ',htmlspecialchars($text_query),'</td></tr>',"\n";
2331
                }
2332

    
2333
                if ($this->nav_text_links() || $this->nav_graphic_links()) {
2334
                        $qstrparts = array();
2335
                        strlen($this->fl)             > 0 && $qstrparts[] = $this->cgi['prefix']['sys'].'fl'.'='.$this->fl;
2336
                        strlen($this->fm)             > 0 && $qstrparts[] = $this->cgi['prefix']['sys'].'fm'.'='.$this->fm;
2337
                        count($this->sfn)             > 0 && $qstrparts[] = $this->get_sfn_cgi_vars();
2338
                        strlen($this->cgi['persist']) > 0 && $qstrparts[] = $this->cgi['persist'];
2339
                        $qpview      = $qstrparts;
2340
                        $qpcopy      = $qstrparts;
2341
                        $qpchange    = $qstrparts;
2342
                        $qpdelete    = $qstrparts;
2343
                        $qp_prefix   = $this->cgi['prefix']['sys'].'operation'.'='.$this->cgi['prefix']['operation'];
2344
                        $qpview[]    = $qp_prefix.'View';
2345
                        $qpcopy[]    = $qp_prefix.'Copy';
2346
                        $qpchange[]  = $qp_prefix.'Change';
2347
                        $qpdelete[]  = $qp_prefix.'Delete';
2348
                        $qpviewStr   = htmlspecialchars($this->page_name.'?'.join('&',$qpview).$this->qfn);
2349
                        $qpcopyStr   = htmlspecialchars($this->page_name.'?'.join('&',$qpcopy).$this->qfn);
2350
                        $qpchangeStr = htmlspecialchars($this->page_name.'?'.join('&',$qpchange).$this->qfn);
2351
                        $qpdeleteStr = htmlspecialchars($this->page_name.'?'.join('&',$qpdelete).$this->qfn);
2352
                }
2353
                $fetched  = true;
2354
                $first    = true;
2355
                $rowCount = 0;
2356
                while ((!$fetched && ($row = $this->sql_fetch($res)) != false)
2357
                                || ($fetched && $row != false)) {
2358
                        $fetched = false;
2359
                        echo '<tr class="',$this->getCSSclass('row', null, 'next'),'">',"\n";
2360
                        if ($sys_cols) { /* {{{ */
2361
                                $key_rec     = $row['qf'.$this->key_num];
2362
                                $queryAppend = htmlspecialchars('&'.$this->cgi['prefix']['sys'].'rec'.'='.$key_rec);
2363
                                $viewQuery   = $qpviewStr   . $queryAppend;
2364
                                $copyQuery   = $qpcopyStr   . $queryAppend;
2365
                                $changeQuery = $qpchangeStr . $queryAppend;
2366
                                $deleteQuery = $qpdeleteStr . $queryAppend;
2367
                                $viewTitle   = htmlspecialchars($this->labels['View']);
2368
                                $changeTitle = htmlspecialchars($this->labels['Change']);
2369
                                $copyTitle   = htmlspecialchars($this->labels['Copy']);
2370
                                $deleteTitle = htmlspecialchars($this->labels['Delete']);
2371
                                $css_class_name = $this->getCSSclass('navigation', null, true);
2372
                                if ($select_recs) {
2373
                                        if (! $this->nav_buttons() || $sys_cols > 1) {
2374
                                                echo '<td class="',$css_class_name,'">';
2375
                                        }
2376
                                        if ($this->nav_graphic_links()) {
2377
                                                $printed_out = false;
2378
                                                if ($this->view_enabled()) {
2379
                                                        $printed_out = true;
2380
                                                        echo '<a class="',$css_class_name,'" href="',$viewQuery,'"><img class="';
2381
                                                        echo $css_class_name,'" src="',$this->url['images'];
2382
                                                        echo 'pme-view.png" height="15" width="16" border="0" ';
2383
                                                        echo 'alt="',$viewTitle,'" title="',$viewTitle,'" /></a>';
2384
                                                }
2385
                                                if ($this->change_enabled()) {
2386
                                                        $printed_out && print('&nbsp;');
2387
                                                        $printed_out = true;
2388
                                                        echo '<a class="',$css_class_name,'" href="',$changeQuery,'"><img class="';
2389
                                                        echo $css_class_name,'" src="',$this->url['images'];
2390
                                                        echo 'pme-change.png" height="15" width="16" border="0" ';
2391
                                                        echo 'alt="',$changeTitle,'" title="',$changeTitle,'" /></a>';
2392
                                                }
2393
                                                if ($this->copy_enabled()) {
2394
                                                        $printed_out && print('&nbsp;');
2395
                                                        $printed_out = true;
2396
                                                        echo '<a class="',$css_class_name,'" href="',$copyQuery,'"><img class="';
2397
                                                        echo $css_class_name,'" src="',$this->url['images'];
2398
                                                        echo 'pme-copy.png" height="15" width="16" border="0" ';
2399
                                                        echo 'alt="',$copyTitle,'" title="',$copyTitle,'" /></a>';
2400
                                                }
2401
                                                if ($this->delete_enabled()) {
2402
                                                        $printed_out && print('&nbsp;');
2403
                                                        $printed_out = true;
2404
                                                        echo '<a class="',$css_class_name,'" href="',$deleteQuery,'"><img class="';
2405
                                                        echo $css_class_name,'" src="',$this->url['images'];
2406
                                                        echo 'pme-delete.png" height="15" width="16" border="0" ';
2407
                                                        echo 'alt="',$deleteTitle,'" title="',$deleteTitle,'" /></a>';
2408
                                                }
2409
                                        }
2410
                                        if ($this->nav_text_links()) {
2411
                                                if ($this->nav_graphic_links()) {
2412
                                                        echo '<br class="',$css_class_name,'">';
2413
                                                }
2414
                                                $printed_out = false;
2415
                                                if ($this->view_enabled()) {
2416
                                                        $printed_out = true;
2417
                                                        echo '<a href="',$viewQuery,'" title="',$viewTitle,'" class="',$css_class_name,'">V</a>';
2418
                                                }
2419
                                                if ($this->change_enabled()) {
2420
                                                        $printed_out && print('&nbsp;');
2421
                                                        $printed_out = true;
2422
                                                        echo '<a href="',$changeQuery,'" title="',$changeTitle,'" class="',$css_class_name,'">C</a>';
2423
                                                }
2424
                                                if ($this->copy_enabled()) {
2425
                                                        $printed_out && print('&nbsp;');
2426
                                                        $printed_out = true;
2427
                                                        echo '<a href="',$copyQuery,'" title="',$copyTitle,'" class="',$css_class_name,'">P</a>';
2428
                                                }
2429
                                                if ($this->delete_enabled()) {
2430
                                                        $printed_out && print('&nbsp;');
2431
                                                        $printed_out = true;
2432
                                                        echo '<a href="',$deleteQuery,'" title="',$deleteTitle,'" class="',$css_class_name,'">D</a>';
2433
                                                }
2434
                                        }
2435
                                        if (! $this->nav_buttons() || $sys_cols > 1) {
2436
                                                echo '</td>',"\n";
2437
                                        }
2438
                                        if ($this->nav_buttons()) {
2439
                                                echo '<td class="',$css_class_name,'"><input class="',$css_class_name;
2440
                                                echo '" type="radio" name="'.$this->cgi['prefix']['sys'].'rec';
2441
                                                echo '" value="',htmlspecialchars($key_rec),'"';
2442
                                                if (($this->rec == '' && $first) || ($this->rec == $key_rec)) {
2443
                                                        echo ' checked';
2444
                                                        $first = false;
2445
                                                }
2446
                                                echo ' /></td>',"\n";
2447
                                        }
2448
                                } elseif ($this->filter_enabled()) {
2449
                                        echo '<td class="',$css_class_name,'" colspan="',$sys_cols,'">&nbsp;</td>',"\n";
2450
                                }
2451
                        } /* }}} */
2452
                        for ($k = 0; $k < $this->num_fds; $k++) { /* {{{ */
2453
                                $fd = $this->fds[$k];
2454
                                if (! $this->displayed[$k]) {
2455
                                        continue;
2456
                                }
2457
                                $css_postfix    = @$this->fdd[$k]['css']['postfix'];
2458
                                $css_class_name = $this->getCSSclass('cell', null, true, $css_postfix);
2459
                                if ($this->password($k)) {
2460
                                        echo '<td class="',$css_class_name,'">',$this->labels['hidden'],'</td>',"\n";
2461
                                        continue;
2462
                                }
2463
                                echo '<td class="',$css_class_name,'"',$this->getColAttributes($fd),'>';
2464
                                echo $this->cellDisplay($k, $row, $css_class_name);
2465
                                echo '</td>',"\n";
2466
                        } /* }}} */
2467
                        echo '</tr>',"\n";
2468
                }
2469

    
2470
                /*
2471
                 * Display and accumulate column aggregation info, do totalling query
2472
                 * XXX this feature does not work yet!!!
2473
                 */
2474
                // aggregates listing (if any)
2475
                if ($$var_to_total) {
2476
                        // do the aggregate query if necessary
2477
                        //if ($vars_to_total) {
2478
                                $qp = array();
2479
                                $qp['type'] = 'select';
2480
                                $qp['select'] = $aggr_from_clause;
2481
                                $qp['from']   = $this->get_SQL_join_clause();
2482
                                $qp['where']  = $this->get_SQL_where_from_query_opts();
2483
                                $tot_query    = $this->get_SQL_query($qp);
2484
                                $totals_result = $this->myquery($tot_query,__LINE__);
2485
                                $tot_row       = $this->sql_fetch($totals_result);
2486
                        //}
2487
                        $qp_aggr = $qp;
2488
                        echo "\n",'<tr class="TODO-class">',"\n",'<td class="TODO-class">&nbsp;</td>',"\n";
2489
                        /*
2490
                        echo '<td>';
2491
                        echo printarray($qp_aggr);
2492
                        echo printarray($vars_to_total);
2493
                        echo '</td>';
2494
                        echo '<td colspan="'.($this->num_fds-1).'">'.$var_to_total.' '.$$var_to_total.'</td>';
2495
                        */
2496
                        // display the results
2497
                        for ($k=0;$k<$this->num_fds;$k++) {
2498
                                $fd = $this->fds[$k];
2499
                                if (stristr($this->fdd[$fd]['options'],'L') or !isset($this->fdd[$fd]['options'])) {
2500
                                        echo '<td>';
2501
                                        $aggr_var  = 'qf'.$k.'_aggr';
2502
                                        $$aggr_var = $this->get_sys_cgi_var($aggr_var);
2503
                                        if ($$aggr_var) {
2504
                                                echo $this->sql_aggrs[$$aggr_var],': ',$tot_row[$aggr_var];
2505
                                        } else {
2506
                                                echo '&nbsp;';
2507
                                        }
2508
                                        echo '</td>',"\n";
2509
                                }
2510
                        }
2511
                        echo '</tr>',"\n";
2512
                }
2513
                echo '</table>',"\n"; // end of table rows listing
2514
                $this->display_list_table_buttons('down', $listall);
2515
                $this->form_end();
2516
        } /* }}} */
2517

    
2518
        function display_record() /* {{{ */
2519
        {
2520
                // PRE Triggers
2521
                $ret = true;
2522
                if ($this->change_operation()) {
2523
                        $ret &= $this->exec_triggers_simple('update', 'pre');
2524
                        // if PRE update fails, then back to view operation
2525
                        if (! $ret) {
2526
                                $this->operation = $this->labels['View'];
2527
                                $ret = true;
2528
                        }
2529
                }
2530
                if ($this->add_operation() || $this->copy_operation()) {
2531
                        $ret &= $this->exec_triggers_simple('insert', 'pre');
2532
                }
2533
                if ($this->view_operation()) {
2534
                        $ret &= $this->exec_triggers_simple('select', 'pre');
2535
                }
2536
                if ($this->delete_operation()) {
2537
                        $ret &= $this->exec_triggers_simple('delete', 'pre');
2538
                }
2539
                // if PRE insert/view/delete fail, then back to the list
2540
                if ($ret == false) {
2541
                        $this->operation = '';
2542
                        $this->list_table();
2543
                        return;
2544
                }
2545
                $this->form_begin();
2546
                if ($this->cgi['persist'] != '') {
2547
                        echo $this->get_origvars_html($this->cgi['persist']);
2548
                }
2549
                echo $this->get_origvars_html($this->get_sfn_cgi_vars());
2550
                echo $this->get_origvars_html($this->qfn);
2551
                echo $this->htmlHiddenSys('cur_tab', $this->dhtml['prefix'].'tab'.$this->cur_tab);
2552
                echo $this->htmlHiddenSys('qfn', $this->qfn);
2553
                echo $this->htmlHiddenSys('rec', $this->copy_operation() ? '' : $this->rec);
2554
                echo $this->htmlHiddenSys('fm', $this->fm);
2555
                echo $this->htmlHiddenSys('fl', $this->fl);
2556
                $this->display_record_buttons('up');
2557
                if ($this->tabs_enabled()) {
2558
                        echo '<div id="'.$this->dhtml['prefix'].'tab0">',"\n";
2559
                }
2560
                echo '<table class="',$this->getCSSclass('main'),'" summary="',$this->tb,'">',"\n";
2561
                if ($this->add_operation()) {
2562
                        $this->display_add_record();
2563
                } else {
2564
                        $this->display_copy_change_delete_record();
2565
                }
2566
                echo '</table>',"\n";
2567
                 if ($this->tabs_enabled()) {
2568
                echo '</div>',"\n";
2569
                }                
2570
                $this->display_record_buttons('down');
2571

    
2572
                $this->form_end();
2573
        } /* }}} */
2574

    
2575
        /*
2576
         * Action functions
2577
         */
2578

    
2579
        function do_add_record() /* {{{ */
2580
        {
2581
                // Preparing query
2582
                $query       = '';
2583
                $key_col_val = '';
2584
                $newvals     = array();
2585
                for ($k = 0; $k < $this->num_fds; $k++) {
2586
                        if ($this->processed($k)) {
2587
                                $fd = $this->fds[$k];
2588
                                if ($this->readonly($k)) {
2589
                                        $fn = (string) @$this->fdd[$k]['default'];
2590
                                } else {
2591
                                        $fn = $this->get_data_cgi_var($fd);
2592
                                }
2593
                                if ($fd == $this->key) {
2594
                                        $key_col_val = $fn;
2595
                                }
2596
                                $newvals[$fd] = is_array($fn) ? join(',',$fn) : $fn;
2597
                        }
2598
                }
2599
                // Creating array of changed keys ($changed)
2600
                $changed = array_keys($newvals);
2601
                // Before trigger, newvals can be efectively changed
2602
                if ($this->exec_triggers('insert', 'before', $oldvals, $changed, $newvals) == false) {
2603
                        return false;
2604
                }
2605
                // Real query (no additional query in this method)
2606
                foreach ($newvals as $fd => $val) {
2607
                        if ($fd == '') continue;
2608
                        if ($this->col_has_sqlw($this->fdn[$fd])) {
2609
                                $val_as  = addslashes($val);
2610
                                $val_qas = '"'.addslashes($val).'"';
2611
                                $value = $this->substituteVars(
2612
                                                $this->fdd[$this->fdn[$fd]]['sqlw'], array(
2613
                                                        'val_qas' => $val_qas,
2614
                                                        'val_as'  => $val_as,
2615
                                                        'val'     => $val
2616
                                                        ));
2617
                        } else {
2618
                                $value = "'".addslashes($val)."'";
2619
                        }
2620
                        if ($query == '') {
2621
                                $query = 'INSERT INTO '.$this->sd.$this->tb.$this->ed.' ('.$this->sd.$fd.$this->ed.''; // )
2622
                                $query2 = ') VALUES ('.$value.'';
2623
                        } else {
2624
                                $query  .= ', '.$this->sd.$fd.$this->ed.'';
2625
                                $query2 .= ', '.$value.'';
2626
                        }
2627
                }
2628
                $query .= $query2.')';
2629
                $res    = $this->myquery($query, __LINE__);
2630
                $this->message = $this->sql_affected_rows($this->dbh).' '.$this->labels['record added'];
2631
                if (! $res) {
2632
                        return false;
2633
                }
2634
                $this->rec = $this->sql_insert_id();
2635
                // Notify list
2636
                if (@$this->notify['insert'] || @$this->notify['all']) {
2637
                        $this->email_notify(false, $newvals);
2638
                }
2639
                // Note change in log table
2640
                if ($this->logtable) {
2641
                        $query = sprintf('INSERT INTO %s'
2642
                                        .' (updated, user, host, operation, tab, rowkey, col, oldval, newval)'
2643
                                        .' VALUES (NOW(), "%s", "%s", "insert", "%s", "%s", "", "", "%s")',
2644
                                        $this->logtable, addslashes($this->get_server_var('REMOTE_USER')),
2645
                                        addslashes($this->get_server_var('REMOTE_ADDR')), addslashes($this->tb),
2646
                                        addslashes($key_col_val), addslashes(serialize($newvals)));
2647
                        $this->myquery($query, __LINE__);
2648
                }
2649
                // After trigger
2650
                if ($this->exec_triggers('insert', 'after', $oldvals, $changed, $newvals) == false) {
2651
                        return false;
2652
                }
2653
                return true;
2654
        } /* }}} */
2655

    
2656
        function do_change_record() /* {{{ */
2657
        {
2658
                // Preparing queries
2659
                $query_real   = '';
2660
                $query_oldrec = '';
2661
                $newvals      = array();
2662
                $oldvals      = array();
2663
                $changed      = array();
2664
                // Prepare query to retrieve oldvals
2665
                for ($k = 0; $k < $this->num_fds; $k++) {
2666
                        if ($this->processed($k) && !$this->readonly($k)) {
2667
                                $fd = $this->fds[$k];
2668
                                $fn = $this->get_data_cgi_var($fd);
2669
                                $newvals[$this->fds[$k]] = is_array($fn) ? join(',',$fn) : $fn;
2670
                                if ($query_oldrec == '') {
2671
                                        $query_oldrec = 'SELECT '.$this->sd.$fd.$this->ed;
2672
                                } else {
2673
                                        $query_oldrec .= ','.$this->sd.$fd.$this->ed;
2674
                                }
2675
                        }
2676
                }
2677
                $where_part = " WHERE (".$this->sd.$this->key.$this->ed.'='.$this->key_delim.$this->rec.$this->key_delim.')';
2678
                $query_newrec  = $query_oldrec.' FROM ' . $this->tb;
2679
                $query_oldrec .= ' FROM ' . $this->sd.$this->tb.$this->ed . $where_part;
2680
                // Additional query (must go before real query)
2681
                $res     = $this->myquery($query_oldrec, __LINE__);
2682
                $oldvals = $this->sql_fetch($res);
2683
                $this->sql_free_result($res);
2684
                // Creating array of changed keys ($changed)
2685
                foreach ($newvals as $fd => $value) {
2686
                        if ($value != $oldvals[$fd])
2687
                                $changed[] = $fd;
2688
                }
2689
                // Before trigger
2690
                if ($this->exec_triggers('update', 'before', $oldvals, $changed, $newvals) == false) {
2691
                        return false;
2692
                }
2693
                // Build the real query respecting changes to the newvals array
2694
                foreach ($newvals as $fd => $val) {
2695
                        if ($fd == '') continue;
2696
                        if ($this->col_has_sqlw($this->fdn[$fd])) {
2697
                                $val_as  = addslashes($val);
2698
                                $val_qas = '"'.addslashes($val).'"';
2699
                                $value = $this->substituteVars(
2700
                                                $this->fdd[$this->fdn[$fd]]['sqlw'], array(
2701
                                                        'val_qas' => $val_qas,
2702
                                                        'val_as'  => $val_as,
2703
                                                        'val'     => $val
2704
                                                        ));
2705
                        } else {
2706
                                $value = "'".addslashes($val)."'";
2707
                        }
2708
                        if ($query_real == '') {
2709
                                $query_real   = 'UPDATE '.$this->sd.$this->tb.$this->ed.' SET '.$this->sd.$fd.$this->ed.'='.$value;
2710
                        } else {
2711
                                $query_real   .= ','.$this->sd.$fd.$this->ed.'='.$value;
2712
                        }
2713
                }
2714
                $query_real .= $where_part;
2715
                // Real query
2716
                $res = $this->myquery($query_real, __LINE__);
2717
                $this->message = $this->sql_affected_rows($this->dbh).' '.$this->labels['record changed'];
2718
                if (! $res) {
2719
                        return false;
2720
                }
2721
                // Another additional query (must go after real query)
2722
                if (in_array($this->key, $changed)) {
2723
                        $this->rec = $newvals[$this->key]; // key has changed
2724
                }
2725
                $query_newrec .= ' WHERE ('.$this->key.'='.$this->key_delim.$this->rec.$this->key_delim.')';
2726
                $res     = $this->myquery($query_newrec, __LINE__);
2727
                $newvals = $this->sql_fetch($res);
2728
                $this->sql_free_result($res);
2729
                // Creating array of changed keys ($changed)
2730
                $changed = array();
2731
                foreach ($newvals as $fd => $value) {
2732
                        if ($value != $oldvals[$fd])
2733
                                $changed[] = $fd;
2734
                }
2735
                // Notify list
2736
                if (@$this->notify['update'] || @$this->notify['all']) {
2737
                        if (count($changed) > 0) {
2738
                                $this->email_notify($oldvals, $newvals);
2739
                        }
2740
                }
2741
                // Note change in log table
2742
                if ($this->logtable) {
2743
                        foreach ($changed as $key) {
2744
                                $qry = sprintf('INSERT INTO %s'
2745
                                                .' (updated, user, host, operation, tab, rowkey, col, oldval, newval)'
2746
                                                .' VALUES (NOW(), "%s", "%s", "update", "%s", "%s", "%s", "%s", "%s")',
2747
                                                $this->logtable, addslashes($this->get_server_var('REMOTE_USER')),
2748
                                                addslashes($this->get_server_var('REMOTE_ADDR')), addslashes($this->tb),
2749
                                                addslashes($this->rec), addslashes($key),
2750
                                                addslashes($oldvals[$key]), addslashes($newvals[$key]));
2751
                                $this->myquery($qry, __LINE__);
2752
                        }
2753
                }
2754
                // After trigger
2755
                if ($this->exec_triggers('update', 'after', $oldvals, $changed, $newvals) == false) {
2756
                        return false;
2757
                }
2758
                return true;
2759
        } /* }}} */
2760

    
2761
        function do_delete_record() /* {{{ */
2762
        {
2763
                // Additional query
2764
                $query   = 'SELECT * FROM '.$this->sd.$this->tb.$this->ed.' WHERE ('.$this->sd.$this->key.$this->ed.' = '
2765
                                .$this->key_delim.$this->rec.$this->key_delim.')'; // )
2766
                $res     = $this->myquery($query, __LINE__);
2767
                $oldvals = $this->sql_fetch($res);
2768
                $this->sql_free_result($res);
2769
                // Creating array of changed keys ($changed)
2770
                $changed = is_array($oldvals) ? array_keys($oldvals) : array();
2771
                $newvals = array();
2772
                // Before trigger
2773
                if ($this->exec_triggers('delete', 'before', $oldvals, $changed, $newvals) == false) {
2774
                        return false;
2775
                }
2776
                // Real query
2777
                $query = 'DELETE FROM '.$this->tb.' WHERE ('.$this->key.' = '
2778
                                .$this->key_delim.$this->rec.$this->key_delim.')'; // )
2779
                $res = $this->myquery($query, __LINE__);
2780
                $this->message = $this->sql_affected_rows($this->dbh).' '.$this->labels['record deleted'];
2781
                if (! $res) {
2782
                        return false;
2783
                }
2784
                // Notify list
2785
                if (@$this->notify['delete'] || @$this->notify['all']) {
2786
                        $this->email_notify($oldvals, false);
2787
                }
2788
                // Note change in log table
2789
                if ($this->logtable) {
2790
                        $query = sprintf('INSERT INTO %s'
2791
                                        .' (updated, user, host, operation, tab, rowkey, col, oldval, newval)'
2792
                                        .' VALUES (NOW(), "%s", "%s", "delete", "%s", "%s", "%s", "%s", "")',
2793
                                        $this->logtable, addslashes($this->get_server_var('REMOTE_USER')),
2794
                                        addslashes($this->get_server_var('REMOTE_ADDR')), addslashes($this->tb),
2795
                                        addslashes($this->rec), addslashes($key), addslashes(serialize($oldvals)));
2796
                        $this->myquery($query, __LINE__);
2797
                }
2798
                // After trigger
2799
                if ($this->exec_triggers('delete', 'after', $oldvals, $changed, $newvals) == false) {
2800
                        return false;
2801
                }
2802
                return true;
2803
        } /* }}} */
2804

    
2805
        function email_notify($old_vals, $new_vals) /* {{{ */
2806
        {
2807
                if (! function_exists('mail')) {
2808
                        return false;
2809
                }
2810
                if ($old_vals != false && $new_vals != false) {
2811
                        $action  = 'update';
2812
                        $subject = 'Record updated in';
2813
                        $body    = 'An item with '.$this->fdd[$this->key]['name'].' = '
2814
                                .$this->key_delim.$this->rec.$this->key_delim .' was updated in';
2815
                        $vals    = $new_vals;
2816
                } elseif ($new_vals != false) {
2817
                        $action  = 'insert';
2818
                        $subject = 'Record added to';
2819
                        $body    = 'A new item was added into';
2820
                        $vals    = $new_vals;
2821
                } elseif ($old_vals != false) {
2822
                        $action  = 'delete';
2823
                        $subject = 'Record deleted from';
2824
                        $body    = 'An item was deleted from';
2825
                        $vals    = $old_vals;
2826
                } else {
2827
                        return false;
2828
                }
2829
                $addr  = $this->get_server_var('REMOTE_ADDR');
2830
                $user  = $this->get_server_var('REMOTE_USER');
2831
                $body  = 'This notification e-mail was automatically generated by phpMyEdit.'."\n\n".$body;
2832
                $body .= ' table '.$this->tb.' in SQL database '.$this->db.' on '.$this->page_name;
2833
                $body .= ' by '.($user == '' ? 'unknown user' : "user $user").' from '.$addr;
2834
                $body .= ' at '.date('d/M/Y H:i').' with the following fields:'."\n\n";
2835
                $i = 1;
2836
                foreach ($vals as $k => $text) {
2837
                        $name = isset($this->fdd[$k]['name~'])
2838
                                ? $this->fdd[$k]['name~'] : $this->fdd[$k]['name'];
2839
                        if ($action == 'update') {
2840
                                if ($old_vals[$k] == $new_vals[$k]) {
2841
                                        continue;
2842
                                }
2843
                                $body .= sprintf("[%02s] %s (%s)\n      WAS: %s\n      IS:  %s\n",
2844
                                                $i, $name, $k, $old_vals[$k], $new_vals[$k]);
2845
                        } else {
2846
                                $body .= sprintf('[%02s] %s (%s): %s'."\n", $i, $name, $k, $text);
2847
                        }
2848
                        $i++;
2849
                }
2850
                $body    .= "\n--\r\n"; // \r is needed for signature separating
2851
                $body    .= "phpMyEdit\ninstant SQL table editor and code generator\n";
2852
                $body    .= "http://platon.sk/projects/phpMyEdit/\n\n";
2853
                $subject  = @$this->notify['prefix'].$subject.' '.$this->dbp.$this->tb;
2854
                $subject  = trim($subject); // just for sure
2855
                $wrap_w   = intval(@$this->notify['wrap']);
2856
                   $wrap_w > 0 || $wrap_w = 72;
2857
                $from     = (string) @$this->notify['from'];
2858
                $from != '' || $from = 'webmaster@'.strtolower($this->get_server_var('SERVER_NAME'));
2859
                $headers  = 'From: '.$from."\n".'X-Mailer: PHP/'.phpversion().' (phpMyEdit)';
2860
                $body     = wordwrap($body, $wrap_w, "\n", 1);
2861
                $emails   = (array) $this->notify[$action] + (array) $this->notify['all'];
2862
                foreach ($emails as $email) {
2863
                        if (! empty($email)) {
2864
                                mail(trim($email), $subject, $body, $headers);
2865
                        }
2866
                }
2867
                return true;
2868
        } /* }}} */
2869

    
2870
        /*
2871
         * Apply triggers function
2872
         * Run a (set of) trigger(s). $trigger can be an Array or a filename
2873
         * Break and return false as soon as a trigger return false
2874
         * we need a reference on $newvals to be able to change value before insert/update
2875
         */
2876
        function exec_triggers($op, $step, $oldvals, &$changed, &$newvals) /* {{{ */
2877
        {
2878
                if (! isset($this->triggers[$op][$step])) {
2879
                        return true;
2880
                }
2881
                $ret  = true;
2882
                $trig = $this->triggers[$op][$step];
2883
                if (is_array($trig)) {
2884
                        ksort($trig);
2885
                        for ($t = reset($trig); $t !== false && $ret != false; $t = next($trig)) {
2886
                                $ret = include($t);
2887
                        }
2888
                } else {
2889
                        $ret = include($trig);
2890
                }
2891
                return $ret;
2892
        } /* }}} */
2893

    
2894
        function exec_triggers_simple($op, $step) /* {{{ */
2895
        {
2896
                $oldvals = $newvals = $changed = array();
2897
                return $this->exec_triggers($op, $step, $oldvals, $changed, $newvals);
2898
        } /* }}} */
2899
        
2900
        /*
2901
         * Recreate functions
2902
         */
2903
        function recreate_fdd($default_page_type = 'L') /* {{{ */
2904
        {
2905
                // TODO: one level deeper browsing
2906
                $this->page_type = $default_page_type;
2907
                $this->filter_operation() && $this->page_type = 'F';
2908
                $this->view_operation()   && $this->page_type = 'V';
2909
                if ($this->add_operation()
2910
                                || $this->saveadd == $this->labels['Save']
2911
                                || $this->moreadd == $this->labels['More']) {
2912
                        $this->page_type = 'A';
2913
                }
2914
                if ($this->change_operation()
2915
                                || $this->savechange == $this->labels['Save']
2916
                                || $this->morechange == $this->labels['Apply']) {
2917
                        $this->page_type = 'C';
2918
                }
2919
                if ($this->copy_operation() || $this->savecopy == $this->labels['Save']) {
2920
                        $this->page_type = 'P';
2921
                }
2922
                if ($this->delete_operation() || $this->savedelete == $this->labels['Delete']) {
2923
                        $this->page_type = 'D';
2924
                }
2925
                // Restore backups (if exists)
2926
                foreach (array_keys($this->fdd) as $column) {
2927
                        foreach (array_keys($this->fdd[$column]) as $col_option) {
2928
                                if ($col_option[strlen($col_option) - 1] != '~')
2929
                                        continue;
2930

    
2931
                                $this->fdd[$column][substr($col_option, 0, strlen($col_option) - 1)]
2932
                                        = $this->fdd[$column][$col_option];
2933
                                unset($this->fdd[$column][$col_option]);
2934
                        }
2935
                }
2936
                foreach (array_keys($this->fdd) as $column) {
2937
                        foreach (array_keys($this->fdd[$column]) as $col_option) {
2938
                                if (! strchr($col_option, '|')) {
2939
                                        continue;
2940
                                }
2941
                                $col_ar = explode('|', $col_option, 2);
2942
                                if (! stristr($col_ar[1], $this->page_type)) {
2943
                                        continue;
2944
                                }
2945
                                // Make field backups
2946
                                $this->fdd[$column][$col_ar[0] .'~'] = $this->fdd[$column][$col_ar[0]];
2947
                                $this->fdd[$column][$col_option.'~'] = $this->fdd[$column][$col_option];
2948
                                // Set particular field
2949
                                $this->fdd[$column][$col_ar[0]] = $this->fdd[$column][$col_option];
2950
                                unset($this->fdd[$column][$col_option]);
2951
                        }
2952
                }
2953
        } /* }}} */
2954

    
2955
        function recreate_displayed() /* {{{ */
2956
        {
2957
                $field_num            = 0;
2958
                $num_fields_displayed = 0;
2959
                $this->fds            = array();
2960
                $this->fdn            = array();
2961
                $this->displayed      = array();
2962
                $this->guidance       = false;
2963
                foreach (array_keys($this->fdd) as $key) {
2964
                        if (preg_match('/^\d+$/', $key)) { // skipping numeric keys
2965
                                continue;
2966
                        }
2967
                        $this->fds[$field_num] = $key;
2968
                        $this->fdn[$key] = $field_num;
2969
                        /* We must use here displayed() function, because displayed[] array
2970
                           is not created yet. We will simultaneously create that array as well. */
2971
                        if ($this->displayed[$field_num] = $this->displayed($field_num)) {
2972
                                $num_fields_displayed++;
2973
                        }
2974
                        if (is_array(@$this->fdd[$key]['values']) && ! isset($this->fdd[$key]['values']['table'])) {
2975
                                foreach ($this->fdd[$key]['values'] as $val) {
2976
                                        $this->fdd[$key]['values2'][$val] = $val;
2977
                                }
2978
                                unset($this->fdd[$key]['values']);
2979
                        }
2980
                        isset($this->fdd[$key]['help']) && $this->guidance = true;
2981
                        $this->fdd[$field_num] = $this->fdd[$key];
2982
                        $field_num++;
2983
                }
2984
                $this->num_fds              = $field_num;
2985
                $this->num_fields_displayed = $num_fields_displayed;
2986
                $this->key_num              = array_search($this->key, $this->fds);
2987
                /* Adds first displayed column into sorting fields by replacing last
2988
                   array entry. Also remove duplicite values and change column names to
2989
                   their particular field numbers.
2990

2991
                   Note that entries like [0]=>'9' [1]=>'-9' are correct and they will
2992
                   have desirable sorting behaviour. So there is no need to remove them.
2993
                 */
2994
                $this->sfn = array_unique($this->sfn);
2995
                $check_ar = array();
2996
                foreach ($this->sfn as $key => $val) {
2997
                        if (preg_match('/^[-]?\d+$/', $val)) { // skipping numeric keys
2998
                                $val = abs($val);
2999
                                if (in_array($val, $check_ar) || $this->password($val)) {
3000
                                        unset($this->sfn[$key]);
3001
                                } else {
3002
                                        $check_ar[] = $val;
3003
                                }
3004
                                continue;
3005
                        }
3006
                        if ($val[0] == '-') {
3007
                                $val = substr($val, 1);
3008
                                $minus = '-';
3009
                        } else {
3010
                                $minus = '';
3011
                        }
3012
                        if (($val = array_search($val, $this->fds)) === false || $this->password($val)) {
3013
                                unset($this->sfn[$key]);
3014
                        } else {
3015
                                $val = intval($val);
3016
                                if (in_array($val, $check_ar)) {
3017
                                        unset($this->sfn[$key]);
3018
                                } else {
3019
                                        $this->sfn[$key] = $minus.$val;
3020
                                        $check_ar[] = $val;
3021
                                }
3022
                        }
3023
                }
3024
                $this->sfn = array_unique($this->sfn);
3025
                return true;
3026
        } /* }}} */
3027

    
3028
        function backward_compatibility() /* {{{ */
3029
        {
3030
                foreach (array_keys($this->fdd) as $column) {
3031
                        // move ['required'] to ['js']['required']
3032
                        if (! isset($this->fdd[$column]['js']['required']) && isset($this->fdd[$column]['required'])) {
3033
                                $this->fdd[$column]['js']['required'] = $this->fdd[$column]['required'];
3034
                        }
3035
                        // move 'HWR' flags from ['options'] into ['input']
3036
                        if (isset($this->fdd[$column]['options'])) {
3037
                                stristr($this->fdd[$column]['options'], 'H') && $this->fdd[$column]['input'] .= 'H';
3038
                                stristr($this->fdd[$column]['options'], 'W') && $this->fdd[$column]['input'] .= 'W';
3039
                                stristr($this->fdd[$column]['options'], 'R') && $this->fdd[$column]['input'] .= 'R';
3040
                        }
3041
                }
3042
        } /* }}} */
3043

    
3044
        /*
3045
         * Error handling function
3046
         */
3047
        function error($message, $additional_info = '') /* {{{ */
3048
        {
3049
                echo '<h1>phpMyEdit error: ',htmlspecialchars($message),'</h1>',"\n";
3050
                if ($additional_info != '') {
3051
                        echo '<hr size="1" />',htmlspecialchars($additional_info);
3052
                }
3053
                return false;
3054
        } /* }}} */
3055

    
3056
        /*
3057
         * Database connection function
3058
         */
3059
        function connect() /* {{{ */
3060
        {
3061
                if (isset($this->dbh)) {
3062
                        return true;
3063
                }
3064
                if (!isset($this->db)) {
3065
                        $this->error('no database defined');
3066
                        return false;
3067
                }
3068
                if (!isset ($this->tb)) {
3069
                        $this->error('no table defined');
3070
                        return false;
3071
                }
3072
                $this->sql_connect();
3073
                if (!$this->dbh) {
3074
                        $this->error('could not connect to SQL');
3075
                        return false;
3076
                }
3077
                return true;
3078
        } /* }}} */
3079
        
3080
        /*
3081
         * The workhorse
3082
         */
3083
        function execute() /* {{{ */
3084
        {
3085
                //  DEBUG -  uncomment to enable
3086
                /*
3087
                //phpinfo();
3088
                $this->print_get_vars();
3089
                $this->print_post_vars();
3090
                $this->print_vars();
3091
                echo "<pre>query opts:\n";
3092
                echo print_r($this->query_opts);
3093
                echo "</pre>\n";
3094
                echo "<pre>get vars:\n";
3095
                echo print_r($this->get_opts);
3096
                echo "</pre>\n";
3097
                 */
3098

    
3099
                // Let's do explicit quoting - it's safer
3100
                // set_magic_quotes_runtime(0);
3101
                // Checking if language file inclusion was successful
3102
                if (! is_array($this->labels)) {
3103
                        $this->error('could not locate language files', 'searched path: '.$this->dir['lang']);
3104
                        return false;
3105
                }
3106
                // Database connection
3107
                if ($this->connect() == false) {
3108
                        return false;
3109
                }
3110

    
3111
                /*
3112
                 * ======================================================================
3113
                 * Pass 3: process any updates generated if the user has selected
3114
                 * a save or cancel button during Pass 2
3115
                 * ======================================================================
3116
                 */
3117
                // Cancel button - Cancel Triggers
3118
                if ($this->add_canceled() || $this->copy_canceled()) {
3119
                        $this->exec_triggers_simple('insert', 'cancel');
3120
                }
3121
                if ($this->view_canceled()) {
3122
                        $this->exec_triggers_simple('select', 'cancel');
3123
                }
3124
                if ($this->change_canceled()) {
3125
                        $this->exec_triggers_simple('update', 'cancel');
3126
                }
3127
                if ($this->delete_canceled()) {
3128
                        $this->exec_triggers_simple('delete', 'cancel');
3129
                }
3130
                // Save/More Button - database operations
3131
                if ($this->saveadd == $this->labels['Save'] || $this->savecopy == $this->labels['Save']) {
3132
                        $this->add_enabled() && $this->do_add_record();
3133
                        unset($this->saveadd);
3134
                        unset($this->savecopy);
3135
                        $this->recreate_fdd();
3136
                }
3137
                elseif ($this->moreadd == $this->labels['More']) {
3138
                        $this->add_enabled() && $this->do_add_record();
3139
                        $this->operation = $this->labels['Add']; // to force add operation
3140
                        $this->recreate_fdd();
3141
                        $this->recreate_displayed();
3142
                        $this->backward_compatibility();
3143
                }
3144
                elseif ($this->savechange == $this->labels['Save']) {
3145
                        $this->change_enabled() && $this->do_change_record();
3146
                        unset($this->savechange);
3147
                        $this->recreate_fdd();
3148
                }
3149
                elseif ($this->morechange == $this->labels['Apply']) {
3150
                        $this->change_enabled() && $this->do_change_record();
3151
                        $this->operation = $this->labels['Change']; // to force change operation
3152
                        $this->recreate_fdd();
3153
                        $this->recreate_displayed();
3154
                        $this->backward_compatibility();
3155
                }
3156
                elseif ($this->savedelete == $this->labels['Delete']) {
3157
                        $this->delete_enabled() && $this->do_delete_record();
3158
                        unset($this->savedelete);
3159
                        $this->recreate_fdd();
3160
                }
3161

    
3162
                /*
3163
                 * ======================================================================
3164
                 * Pass 2: display an input/edit/confirmation screen if the user has
3165
                 * selected an editing button on Pass 1 through this page
3166
                 * ======================================================================
3167
                 */
3168
                if ($this->add_operation()
3169
                                || $this->change_operation() || $this->delete_operation()
3170
                                || $this->view_operation()   || $this->copy_operation()) {
3171
                        $this->display_record();
3172
                }
3173

    
3174
                /*
3175
                 * ======================================================================
3176
                 * Pass 1 and Pass 3: display the SQL table in a scrolling window on
3177
                 * the screen (skip this step in 'Add More' mode)
3178
                 * ======================================================================
3179
                 */
3180
                else {
3181
                        $this->list_table();
3182
                }
3183

    
3184
                $this->sql_disconnect();
3185
                if ($this->display['time'] && $this->timer != null) {
3186
                        echo $this->timer->end(),' milliseconds';
3187
                }
3188
        } /* }}} */
3189

    
3190
        /*
3191
         * Class constructor
3192
         */
3193
        function phpMyEdit($opts) /* {{{ */
3194
        {
3195
                // Set desirable error reporting level
3196
                $error_reporting = error_reporting(E_ALL & ~E_NOTICE);
3197
                // Database handle variables
3198
                $this->sql_delimiter();
3199
                if (isset($opts['dbh'])) {
3200
                        $this->close_dbh = false;
3201
                        $this->dbh = $opts['dbh'];
3202
                        $this->dbp = '';
3203
                } else {
3204
                        $this->close_dbh = true;
3205
                        $this->dbh = null;
3206
                        $this->dbp = $this->sd.$opts['db'].$this->ed.'.';
3207
                        $this->hn  = $opts['hn'];
3208
                        $this->un  = $opts['un'];
3209
                        $this->pw  = $opts['pw'];
3210
                        $this->db  = $opts['db'];
3211
                }
3212
                $this->tb  = $opts['tb'];
3213
                // Other variables
3214
                $this->key       = $opts['key'];
3215
                $this->key_type  = $opts['key_type'];
3216
                $this->inc       = $opts['inc'];
3217
                $this->options   = $opts['options'];
3218
                $this->fdd       = $opts['fdd'];
3219
                $this->multiple  = intval($opts['multiple']);
3220
                $this->multiple <= 0 && $this->multiple = 2;
3221
                $this->filters   = is_array(@$opts['filters']) ? join(' AND ', $opts['filters']) : @$opts['filters'];
3222
                $this->triggers  = @$opts['triggers'];
3223
                $this->notify    = @$opts['notify'];
3224
                $this->logtable  = @$opts['logtable'];
3225
                $this->page_name = @$opts['page_name'];
3226
                if (! isset($this->page_name)) {
3227
                        $this->page_name = basename($this->get_server_var('PHP_SELF'));
3228
                        isset($this->page_name) || $this->page_name = $this->tb;
3229
                } 
3230
                $this->display['query'] = @$opts['display']['query'];
3231
                $this->display['sort']  = @$opts['display']['sort'];
3232
                $this->display['time']  = @$opts['display']['time'];
3233
                if ($this->display['time']) {
3234
                        $this->timer = new phpMyEdit_timer();
3235
                }
3236
                $this->display['tabs'] = isset($opts['display']['tabs'])
3237
                        ? $opts['display']['tabs'] : true;
3238
                $this->display['form'] = isset($opts['display']['form'])
3239
                        ? $opts['display']['form'] : true;
3240
                $this->display['num_records'] = isset($opts['display']['num_records'])
3241
                        ? $opts['display']['num_records'] : true;
3242
                $this->display['num_pages'] = isset($opts['display']['num_pages'])
3243
                        ? $opts['display']['num_pages'] : true;
3244
                // Creating directory variables
3245
                $this->dir['root'] = dirname(realpath(__FILE__))
3246
                        . (strlen(dirname(realpath(__FILE__))) > 0 ? '/' : '');
3247
                $this->dir['lang'] = $this->dir['root'].'lang/';
3248
                // Creating URL variables
3249
                $this->url['images'] = 'images/';
3250
                isset($opts['url']['images']) && $this->url['images'] = $opts['url']['images'];
3251
                // CSS classes policy
3252
                $this->css = @$opts['css'];
3253
                !isset($this->css['separator']) && $this->css['separator'] = '-';
3254
                !isset($this->css['prefix'])    && $this->css['prefix']    = 'pme';
3255
                !isset($this->css['page_type']) && $this->css['page_type'] = false;
3256
                !isset($this->css['position'])  && $this->css['position']  = false;
3257
                !isset($this->css['divider'])   && $this->css['divider']   = 2;
3258
                $this->css['divider'] = intval(@$this->css['divider']);
3259
                // JS overall configuration
3260
                $this->js = @$opts['js'];
3261
                !isset($this->js['prefix']) && $this->js['prefix'] = 'PME_js_';
3262
                // DHTML overall configuration
3263
                $this->dhtml = @$opts['dhtml'];
3264
                !isset($this->dhtml['prefix']) && $this->dhtml['prefix'] = 'PME_dhtml_';
3265
                // Navigation
3266
                $this->navigation = @$opts['navigation'];
3267
                if (! $this->nav_buttons() && ! $this->nav_text_links() && ! $this->nav_graphic_links()) {
3268
                        $this->navigation .= 'B'; // buttons are default
3269
                }
3270
                if (! $this->nav_up() && ! $this->nav_down()) {
3271
                        $this->navigation .= 'D'; // down position is default
3272
                }
3273
                $this->buttons = $opts['buttons'];
3274
                // Language labels (must go after navigation)
3275
                $this->labels = $this->make_language_labels(isset($opts['language'])
3276
                                ? $opts['language'] : $this->get_server_var('HTTP_ACCEPT_LANGUAGE'));
3277
                // CGI variables
3278
                $this->cgi = @$opts['cgi'];
3279
                $this->cgi['persist'] = '';
3280
                if (@is_array($opts['cgi']['persist'])) {
3281
                        foreach ($opts['cgi']['persist'] as $key => $val) {
3282
                                if (is_array($val)) {
3283
                                        foreach($val as $key2 => $val2) {
3284
                                                $this->cgi['persist'] .= '&'.rawurlencode($key)
3285
                                                        .'['.rawurlencode($key2).']='.rawurlencode($val2);
3286
                                        }
3287
                                } else {
3288
                                        $this->cgi['persist'] .= '&'.rawurlencode($key).'='.rawurlencode($val);
3289
                                }
3290
                        }
3291
                }
3292
                foreach (array('operation', 'sys', 'data') as $type) {
3293
                        if (! isset($this->cgi['prefix'][$type])) {
3294
                                $this->cgi['prefix'][$type] = $this->get_default_cgi_prefix($type);
3295
                        }
3296
                }
3297
                // Sorting variables
3298
                $this->sfn   = $this->get_sys_cgi_var('sfn');
3299
                isset($this->sfn)             || $this->sfn          = array();
3300
                is_array($this->sfn)          || $this->sfn          = array($this->sfn);
3301
                isset($opts['sort_field'])    || $opts['sort_field'] = array();
3302
                is_array($opts['sort_field']) || $opts['sort_field'] = array($opts['sort_field']);
3303
                $this->sfn   = array_merge($this->sfn, $opts['sort_field']);
3304
                // Form variables all around
3305
                $this->fl    = intval($this->get_sys_cgi_var('fl'));
3306
                $this->fm    = intval($this->get_sys_cgi_var('fm'));
3307
//                $old_page = ceil($this->fm / abs($this->inc)) + 1;
3308
                $this->qfn   = $this->get_sys_cgi_var('qfn');
3309
                $this->sw    = $this->get_sys_cgi_var('sw');
3310
                $this->rec   = $this->get_sys_cgi_var('rec', '');
3311
                $this->navop = $this->get_sys_cgi_var('navop');
3312
                $navfmup     = $this->get_sys_cgi_var('navfmup');
3313
                $navfmdown   = $this->get_sys_cgi_var('navfmdown');
3314
                $navpnup     = $this->get_sys_cgi_var('navpnup');
3315
                $navpndown   = $this->get_sys_cgi_var('navpndown');
3316
                if($navfmdown!=NULL && $navfmdown != $this->fm) $this->navfm = $navfmdown;
3317
                elseif($navfmup!=NULL && $navfmup != $this->fm) $this->navfm = $navfmup;
3318
                elseif($navpndown!=NULL && ($navpndown-1)*$this->inc != $this->fm) $this->navfm = ($navpndown-1)*$this->inc;
3319
                elseif($navpnup!=NULL && ($navpnup-1)*$this->inc != $this->fm) $this->navfm = ($navpnup-1)*$this->inc;
3320
                else $this->navfm = $this->fm; 
3321
                $this->operation = $this->get_sys_cgi_var('operation');
3322
                $oper_prefix_len = strlen($this->cgi['prefix']['operation']);
3323
                if (! strncmp($this->cgi['prefix']['operation'], $this->operation, $oper_prefix_len)) {
3324
                        $this->operation = $this->labels[substr($this->operation, $oper_prefix_len)];
3325
                }
3326
                $this->saveadd      = $this->get_sys_cgi_var('saveadd');
3327
                $this->moreadd      = $this->get_sys_cgi_var('moreadd');
3328
                $this->canceladd    = $this->get_sys_cgi_var('canceladd');
3329
                $this->savechange   = $this->get_sys_cgi_var('savechange');
3330
                $this->morechange   = $this->get_sys_cgi_var('morechange');
3331
                $this->cancelchange = $this->get_sys_cgi_var('cancelchange');
3332
                $this->savecopy     = $this->get_sys_cgi_var('savecopy');
3333
                $this->cancelcopy   = $this->get_sys_cgi_var('cancelcopy');
3334
                $this->savedelete   = $this->get_sys_cgi_var('savedelete');
3335
                $this->canceldelete = $this->get_sys_cgi_var('canceldelete');
3336
                $this->cancelview   = $this->get_sys_cgi_var('cancelview');
3337
                // Filter setting
3338
                if (isset($this->sw)) {
3339
                        $this->sw == $this->labels['Search'] && $this->fl = 1;
3340
                        $this->sw == $this->labels['Hide']   && $this->fl = 0;
3341
                        //$this->sw == $this->labels['Clear']  && $this->fl = 0;
3342
                }
3343
                // TAB names
3344
                $this->tabs = array();
3345
                // Setting key_delim according to key_type
3346
                if ($this->key_type == 'real') {
3347
                        /* If 'real' key_type does not work,
3348
                           try change MySQL datatype from float to double */
3349
                        $this->rec = doubleval($this->rec);
3350
                        $this->key_delim = '';
3351
                } elseif ($this->key_type == 'int') {
3352
                        $this->rec = intval($this->rec);
3353
                        $this->key_delim = '';
3354
                } else {
3355
                        $this->key_delim = '"';
3356
                        // $this->rec remains unmodified
3357
                }
3358
                // Specific $fdd modifications depending on performed action
3359
                $this->recreate_fdd();
3360
                // Extract SQL Field Names and number of fields
3361
                $this->recreate_displayed();
3362
                // Issue backward compatibility
3363
                $this->backward_compatibility();
3364
                // Gathering query options
3365
                $this->gather_query_opts();
3366
                // Call to action
3367
                !isset($opts['execute']) && $opts['execute'] = 1;
3368
                $opts['execute'] && $this->execute();
3369
                // Restore original error reporting level
3370
                error_reporting($error_reporting);
3371
        } /* }}} */
3372

    
3373
}
3374

    
3375
/* Modeline for ViM {{{
3376
 * vim:set ts=4:
3377
 * vim600:fdm=marker fdl=0 fdc=0:
3378
 * }}} */
3379

    
3380
?>