Subversion Repositories eFlore/Applications.cel

Rev

Rev 419 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
419 aurelien 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.188 2006-09-08 16:30:31 michal 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 MySQL
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
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
 
153
	// Predefined variables
154
	var $comp_ops  = array('<'=>'<','<='=>'<=','='=>'=','>='=>'>=','>'=>'>');
155
	var $sql_aggrs = array(
156
			'sum'   => 'Total',
157
			'avg'   => 'Average',
158
			'min'   => 'Minimum',
159
			'max'   => 'Maximum',
160
			'count' => 'Count');
161
	var $page_types = array(
162
			'L' => 'list',
163
			'F' => 'filter',
164
			'A' => 'add',
165
			'V' => 'view',
166
			'C' => 'change',
167
			'P' => 'copy',
168
			'D' => 'delete'
169
			);
170
	var $default_buttons = array(
171
			'L' => array('<<','<','add','view','change','copy','delete','>','>>','goto','goto_combo'),
172
			'F' => array('<<','<','add','view','change','copy','delete','>','>>','goto','goto_combo'),
173
			'A' => array('save','more','cancel'),
174
			'C' => array('save','more','cancel'),
175
			'P' => array('save', 'cancel'),
176
			'D' => array('save','cancel'),
177
			'V' => array('change','cancel')
178
			);
179
	// }}}
180
 
181
	/*
182
	 * column specific functions
183
	 */
184
 
185
	function col_has_sql($k)    { return isset($this->fdd[$k]['sql']); }
186
	function col_has_sqlw($k)   { return isset($this->fdd[$k]['sqlw']) && !$this->virtual($k); }
187
	function col_has_values($k) { return isset($this->fdd[$k]['values']) || isset($this->fdd[$k]['values2']); }
188
	function col_has_php($k)    { return isset($this->fdd[$k]['php']); }
189
	function col_has_URL($k)    { return isset($this->fdd[$k]['URL'])
190
		|| isset($this->fdd[$k]['URLprefix']) || isset($this->fdd[$k]['URLpostfix']); }
191
	function col_has_multiple($k)
192
	{ return $this->col_has_multiple_select($k) || $this->col_has_checkboxes($k); }
193
	function col_has_multiple_select($k)
194
	{ return $this->fdd[$k]['select'] == 'M' && ! $this->fdd[$k]['values']['table']; }
195
	function col_has_checkboxes($k)
196
	{ return $this->fdd[$k]['select'] == 'C' && ! $this->fdd[$k]['values']['table']; }
197
	function col_has_radio_buttons($k)
198
	{ return $this->fdd[$k]['select'] == 'O' && ! $this->fdd[$k]['values']['table']; }
199
	function col_has_datemask($k)
200
	{ return isset($this->fdd[$k]['datemask']) || isset($this->fdd[$k]['strftimemask']); }
201
 
202
	/*
203
	 * functions for indicating whether navigation style is enabled
204
     */
205
 
206
	function nav_buttons()       { return stristr($this->navigation, 'B'); }
207
	function nav_text_links()    { return stristr($this->navigation, 'T'); }
208
	function nav_graphic_links() { return stristr($this->navigation, 'G'); }
209
	function nav_up()            { return (stristr($this->navigation, 'U') && !($this->buttons[$this->page_type]['up'] === false)); }
210
	function nav_down()          { return (stristr($this->navigation, 'D') && !($this->buttons[$this->page_type]['down'] === false)); }
211
 
212
	/*
213
	 * functions for indicating whether operations are enabled
214
	 */
215
 
216
	function add_enabled()    { return stristr($this->options, 'A'); }
217
	function change_enabled() { return stristr($this->options, 'C'); }
218
	function delete_enabled() { return stristr($this->options, 'D'); }
219
	function filter_enabled() { return stristr($this->options, 'F'); }
220
	function view_enabled()   { return stristr($this->options, 'V'); }
221
	function copy_enabled()   { return stristr($this->options, 'P') && $this->add_enabled(); }
222
	function tabs_enabled()   { return $this->display['tabs'] && count($this->tabs) > 0; }
223
	function hidden($k)       { return stristr($this->fdd[$k]['input'],'H'); }
224
	function password($k)     { return stristr($this->fdd[$k]['input'],'W'); }
225
	function readonly($k)     { return stristr($this->fdd[$k]['input'],'R') || $this->virtual($k);     }
226
	function virtual($k)      { return stristr($this->fdd[$k]['input'],'V') && $this->col_has_sql($k); }
227
 
228
	function add_operation()    { return $this->operation == $this->labels['Add']    && $this->add_enabled();    }
229
	function change_operation() { return $this->operation == $this->labels['Change'] && $this->change_enabled(); }
230
	function copy_operation()   { return $this->operation == $this->labels['Copy']   && $this->copy_enabled();   }
231
	function delete_operation() { return $this->operation == $this->labels['Delete'] && $this->delete_enabled(); }
232
	function view_operation()   { return $this->operation == $this->labels['View']   && $this->view_enabled();   }
233
	function filter_operation() { return $this->fl && $this->filter_enabled() && $this->list_operation(); }
234
	function list_operation()   { /* covers also filtering page */ return ! $this->change_operation()
235
										&& ! $this->add_operation()    && ! $this->copy_operation()
236
										&& ! $this->delete_operation() && ! $this->view_operation(); }
237
	function next_operation()	{ return ($this->navop == $this->labels['Next']) || ($this->navop == '>'); }
238
	function prev_operation()	{ return ($this->navop == $this->labels['Prev']) || ($this->navop == '<'); }
239
	function first_operation()	{ return ($this->navop == $this->labels['First']) || ($this->navop == '<<'); }
240
	function last_operation()	{ return ($this->navop == $this->labels['Last']) || ($this->navop == '>>'); }
241
	function clear_operation()	{ return $this->sw == $this->labels['Clear'];  }
242
 
243
	function add_canceled()    { return $this->canceladd    == $this->labels['Cancel']; }
244
	function view_canceled()   { return $this->cancelview   == $this->labels['Cancel']; }
245
	function change_canceled() { return $this->cancelchange == $this->labels['Cancel']; }
246
	function copy_canceled()   { return $this->cancelcopy   == $this->labels['Cancel']; }
247
	function delete_canceled() { return $this->canceldelete == $this->labels['Cancel']; }
248
 
249
	function is_values2($k, $val = 'X') /* {{{ */
250
	{
251
		return $val === null ||
252
			(isset($this->fdd[$k]['values2']) && !isset($this->fdd[$k]['values']['table']));
253
	} /* }}} */
254
 
255
	function processed($k) /* {{{ */
256
	{
257
		if ($this->virtual($k)) {
258
			return false;
259
		}
260
		$options = @$this->fdd[$k]['options'];
261
		if (! isset($options)) {
262
			return true;
263
		}
264
		return
265
			($this->saveadd    == $this->labels['Save']  && stristr($options, 'A')) ||
266
			($this->moreadd    == $this->labels['More']  && stristr($options, 'A')) ||
267
			($this->savechange == $this->labels['Save']  && stristr($options, 'C')) ||
268
			($this->morechange == $this->labels['Apply'] && stristr($options, 'C')) ||
269
			($this->savecopy   == $this->labels['Save']  && stristr($options, 'P')) ||
270
			($this->savedelete == $this->labels['Save']  && stristr($options, 'D'));
271
	} /* }}} */
272
 
273
	function displayed($k) /* {{{ */
274
	{
275
		if (is_numeric($k)) {
276
			$k = $this->fds[$k];
277
		}
278
		$options = @$this->fdd[$k]['options'];
279
		if (! isset($options)) {
280
			return true;
281
		}
282
		return
283
			($this->add_operation()    && stristr($options, 'A')) ||
284
			($this->view_operation()   && stristr($options, 'V')) ||
285
			($this->change_operation() && stristr($options, 'C')) ||
286
			($this->copy_operation()   && stristr($options, 'P')) ||
287
			($this->delete_operation() && stristr($options, 'D')) ||
288
			($this->filter_operation() && stristr($options, 'F')) ||
289
			($this->list_operation()   && stristr($options, 'L'));
290
	} /* }}} */
291
 
292
	function debug_var($name, $val) /* {{{ */
293
	{
294
		if (is_array($val) || is_object($val)) {
295
			echo "<pre>$name\n";
296
			ob_start();
297
			//print_r($val);
298
			var_dump($val);
299
			$content = ob_get_contents();
300
			ob_end_clean();
301
			echo htmlspecialchars($content);
302
			echo "</pre>\n";
303
		} else {
304
			echo 'debug_var()::<i>',htmlspecialchars($name),'</i>';
305
			echo '::<b>',htmlspecialchars($val),'</b>::',"<br />\n";
306
		}
307
	} /* }}} */
308
 
309
	function myquery($qry, $line = 0, $debug = 0) /* {{{ */
310
	{
311
		global $debug_query;
312
		if ($debug_query || $debug) {
313
			$line = intval($line);
314
			echo '<h4>MySQL query at line ',$line,'</h4>',htmlspecialchars($qry),'<hr />',"\n";
315
		}
316
		if (isset($this->db)) {
317
			$ret = @mysql_db_query($this->db, $qry, $this->dbh);
318
		} else {
319
			$ret = @mysql_query($qry, $this->dbh);
320
		}
321
		if (! $ret) {
322
			echo '<h4>MySQL error ',mysql_errno($this->dbh),'</h4>';
323
			echo htmlspecialchars(mysql_error($this->dbh)),'<hr />',"\n";
324
		}
325
		return $ret;
326
	} /* }}} */
327
 
328
	function make_language_labels($language) /* {{{ */
329
	{
330
		// just try the first language and variant
331
		// this isn't content-negotiation rfc compliant
332
		$language = strtoupper($language);
333
 
334
		// try the full language w/ variant
335
		$file = $this->dir['lang'].'PME.lang.'.$language.'.inc';
336
 
337
		if (! file_exists($file)) {
338
			// try the language w/o variant
339
			$file = $this->dir['lang'].'PME.lang.'.substr($language,0,2).'.inc';
340
		}
341
		if (! file_exists($file)) {
342
			// default to classical English
343
			$file = $this->dir['lang'].'PME.lang.EN.inc';
344
		}
345
		$ret = @include($file);
346
		if (! is_array($ret)) {
347
			return $ret;
348
		}
349
		$small = array(
350
				'Search' => 'v',
351
				'Hide'   => '^',
352
				'Clear'  => 'X',
353
				'Query'  => htmlspecialchars('>'));
354
		if ((!$this->nav_text_links() && !$this->nav_graphic_links())
355
				|| !isset($ret['Search']) || !isset($ret['Query'])
356
				|| !isset($ret['Hide'])   || !isset($ret['Clear'])) {
357
			foreach ($small as $key => $val) {
358
				$ret[$key] = $val;
359
			}
360
		}
361
		return $ret;
362
	} /* }}} */
363
 
364
	function set_values($field_num, $prepend = null, $append = null, $strict = false) /* {{{ */
365
	{
366
		return (array) $prepend + (array) $this->fdd[$field_num]['values2']
367
			+ (isset($this->fdd[$field_num]['values']['table']) || $strict
368
					? $this->set_values_from_table($field_num, $strict)
369
					: array())
370
			+ (array) $append;
371
	} /* }}} */
372
 
373
	function set_values_from_table($field_num, $strict = false) /* {{{ */
374
	{
375
		$db    = &$this->fdd[$field_num]['values']['db'];
376
		$table = &$this->fdd[$field_num]['values']['table'];
377
		$key   = &$this->fdd[$field_num]['values']['column'];
378
		$desc  = &$this->fdd[$field_num]['values']['description'];
379
		$dbp   = isset($db) ? "$db." : $this->dbp;
380
		$qparts['type'] = 'select';
381
		if ($table) {
382
			$qparts['select'] = 'DISTINCT '.$table.'.'.$key;
383
			if ($desc && is_array($desc) && is_array($desc['columns'])) {
384
				$qparts['select'] .= ',CONCAT('; // )
385
				$num_cols = sizeof($desc['columns']);
386
				if (isset($desc['divs'][-1])) {
387
					$qparts['select'] .= '"'.addslashes($desc['divs'][-1]).'",';
388
				}
389
				foreach ($desc['columns'] as $key => $val) {
390
					if ($val) {
391
						$qparts['select'] .= 'IFNULL('.$val.',"")';
392
						if ($desc['divs'][$key]) {
393
							$qparts['select'] .= ',"'.addslashes($desc['divs'][$key]).'"';
394
						}
395
						$qparts['select'] .= ',';
396
					}
397
				}
398
				$qparts['select']{strlen($qparts['select']) - 1} = ')';
399
				$qparts['select'] .= ' AS PMEalias'.$field_num;
400
				$qparts['orderby'] = 'PMEalias'.$field_num;
401
			} else if ($desc && is_array($desc)) {
402
				// TODO
403
			} else if ($desc) {
404
				$qparts['select'] .= ','.$table.'.'.$desc;
405
				$qparts['orderby'] = $desc;
406
			} else if ($key) {
407
				$qparts['orderby'] = $key;
408
			}
409
			$qparts['from'] = "$dbp$table";
410
			$ar = array(
411
					'table'       => $table,
412
					'column'      => $column,
413
					'description' => $desc);
414
			$qparts['where'] = $this->substituteVars($this->fdd[$field_num]['values']['filters'], $ar);
415
			if ($this->fdd[$field_num]['values']['orderby']) {
416
				$qparts['orderby'] = $this->substituteVars($this->fdd[$field_num]['values']['orderby'], $ar);
417
			}
418
		} else { /* simple value extraction */
419
			$key = &$this->fds[$field_num];
420
			$this->virtual($field_num) && $key = $this->fqn($field_num);
421
			$qparts['select']  = 'DISTINCT '.$key.' AS PMEkey';
422
			$qparts['orderby'] = 'PMEkey';
423
			$qparts['from']    = $this->dbp.$this->tb;
424
		}
425
		$values = array();
426
		$res    = $this->myquery($this->get_SQL_query($qparts), __LINE__);
427
		while ($row = @mysql_fetch_array($res, MYSQL_NUM)) {
428
			$values[$row[0]] = $desc ? $row[1] : $row[0];
429
		}
430
		return $values;
431
	} /* }}} */
432
 
433
	function fqn($field, $dont_desc = false, $dont_cols = false) /* {{{ */
434
	{
435
		is_numeric($field) || $field = array_search($field, $this->fds);
436
		// if read SQL expression exists use it
437
		if ($this->col_has_sql($field))
438
			return $this->fdd[$field]['sql'];
439
		// on copy/change always use simple key retrieving
440
		if ($this->add_operation()
441
				|| $this->copy_operation()
442
				|| $this->change_operation()) {
443
				$ret = 'PMEtable0.'.$this->fds[$field];
444
		} else {
445
			if ($this->fdd[$this->fds[$field]]['values']['description'] && ! $dont_desc) {
446
				$desc = &$this->fdd[$this->fds[$field]]['values']['description'];
447
				if (is_array($desc) && is_array($desc['columns'])) {
448
					$ret      = 'CONCAT('; // )
449
					$num_cols = sizeof($desc['columns']);
450
					if (isset($desc['divs'][-1])) {
451
						$ret .= '"'.addslashes($desc['divs'][-1]).'",';
452
					}
453
					foreach ($desc['columns'] as $key => $val) {
454
						if ($val) {
455
							$ret .= 'PMEjoin'.$field.'.'.$val;
456
							if ($desc['divs'][$key]) {
457
								$ret .= ',"'.addslashes($desc['divs'][$key]).'"';
458
							}
459
							$ret .= ',';
460
						}
461
					}
462
					$ret{strlen($ret) - 1} = ')';
463
				} else if (is_array($desc)) {
464
					// TODO
465
				} else {
466
					$ret = 'PMEjoin'.$field.'.'.$this->fdd[$this->fds[$field]]['values']['description'];
467
				}
468
			// TODO: remove me
469
			} elseif (0 && $this->fdd[$this->fds[$field]]['values']['column'] && ! $dont_cols) {
470
				$ret = 'PMEjoin'.$field.'.'.$this->fdd[$this->fds[$field]]['values']['column'];
471
			} else {
472
				$ret = 'PMEtable0.'.$this->fds[$field];
473
			}
474
			// TODO: not neccessary, remove me!
475
			if (is_array($this->fdd[$this->fds[$field]]['values2'])) {
476
			}
477
		}
478
		return $ret;
479
	} /* }}} */
480
 
481
	function get_SQL_query($parts) /* {{{ */
482
	{
483
		foreach ($parts as $k => $v) {
484
			$parts[$k] = trim($parts[$k]);
485
		}
486
		switch ($parts['type']) {
487
			case 'select':
488
				$ret  = 'SELECT ';
489
				if ($parts['DISTINCT'])
490
					$ret .= 'DISTINCT ';
491
				$ret .= $parts['select'];
492
				$ret .= ' FROM '.$parts['from'];
493
				if ($parts['where'] != '')
494
					$ret .= ' WHERE '.$parts['where'];
495
				if ($parts['groupby'] != '')
496
					$ret .= ' GROUP BY '.$parts['groupby'];
497
				if ($parts['having'] != '')
498
					$ret .= ' HAVING '.$parts['having'];
499
				if ($parts['orderby'] != '')
500
					$ret .= ' ORDER BY '.$parts['orderby'];
501
				if ($parts['limit'] != '')
502
					$ret .= ' LIMIT '.$parts['limit'];
503
				if ($parts['procedure'] != '')
504
					$ret .= ' PROCEDURE '.$parts['procedure'];
505
				break;
506
			case 'update':
507
				$ret  = 'UPDATE '.$parts['table'];
508
				$ret .= ' SET '.$parts['fields'];
509
				if ($parts['where'] != '')
510
					$ret .= ' WHERE '.$parts['where'];
511
				break;
512
			case 'insert':
513
				$ret  = 'INSERT INTO '.$parts['table'];
514
				$ret .= ' VALUES '.$parts['values'];
515
				break;
516
			case 'delete':
517
				$ret  = 'DELETE FROM '.$parts['table'];
518
				if ($parts['where'] != '')
519
					$ret .= ' WHERE '.$parts['where'];
520
				break;
521
			default:
522
				die('unknown query type');
523
				break;
524
		}
525
		return $ret;
526
	} /* }}} */
527
 
528
	function get_SQL_column_list() /* {{{ */
529
	{
530
		$fields = array();
531
		for ($k = 0; $k < $this->num_fds; $k++) {
532
			if (! $this->displayed[$k] && $k != $this->key_num) {
533
				continue;
534
			}
535
			$fields[] = $this->fqn($k).' AS qf'.$k;
536
			if ($this->col_has_values($k)) {
537
				$fields[] = $this->fqn($k, true, true).' AS qf'.$k.'_idx';
538
			}
539
			if ($this->col_has_datemask($k)) {
540
				$fields[] = 'UNIX_TIMESTAMP('.$this->fqn($k).') AS qf'.$k.'_timestamp';
541
			}
542
		}
543
		return join(',', $fields);
544
	} /* }}} */
545
 
546
	function get_SQL_join_clause() /* {{{ */
547
	{
548
		$main_table  = 'PMEtable0';
549
		$join_clause = $this->tb." AS $main_table";
550
		for ($k = 0, $numfds = sizeof($this->fds); $k < $numfds; $k++) {
551
			$main_column = $this->fds[$k];
552
			if($this->fdd[$main_column]['values']['db']) {
553
				$dbp = $this->fdd[$main_column]['values']['db'].'.';
554
			} else {
555
				$dbp = $this->dbp;
556
			}
557
			$table       = @$this->fdd[$main_column]['values']['table'];
558
			$join_column = @$this->fdd[$main_column]['values']['column'];
559
			$join_desc   = @$this->fdd[$main_column]['values']['description'];
560
			if ($join_desc != '' && $join_column != '') {
561
				$join_table = 'PMEjoin'.$k;
562
				$ar = array(
563
						'main_table'       => $main_table,
564
						'main_column'      => $main_column,
565
						'join_table'       => $join_table,
566
						'join_column'      => $join_column,
567
						'join_description' => $join_desc);
568
				$join_clause .= " LEFT OUTER JOIN $dbp$table AS $join_table ON (";
569
				$join_clause .= isset($this->fdd[$main_column]['values']['join'])
570
					? $this->substituteVars($this->fdd[$main_column]['values']['join'], $ar)
571
					: "$join_table.$join_column = $main_table.$main_column";
572
				if (isset($this->fdd[$main_column]['values']['filters'])) {
573
					$join_clause .= ' AND ';
574
					$join_clause .= $this->substituteVars($this->fdd[$main_column]['values']['filters'], $ar);
575
				}
576
				$join_clause .= ')';
577
			}
578
		}
579
		return $join_clause;
580
	} /* }}} */
581
 
582
	function get_SQL_where_from_query_opts($qp = null, $text = 0) /* {{{ */
583
	{
584
		if ($qp == null) {
585
			$qp = $this->query_opts;
586
		}
587
		$where = array();
588
		foreach ($qp as $field => $ov) {
589
			if (is_numeric($field)) {
590
				$tmp_where = array();
591
				foreach ($ov as $field2 => $ov2) {
592
					$tmp_where[] = sprintf('%s %s %s', $field2, $ov2['oper'], $ov2['value']);
593
				}
594
				$where[] = '('.join(' OR ', $tmp_where).')';
595
			} else {
596
				if (is_array($ov['value'])) {
597
					$tmp_ov_val = '';
598
					foreach ($ov['value'] as $ov_val) {
599
						strlen($tmp_ov_val) > 0 && $tmp_ov_val .= ' OR ';
600
						$tmp_ov_val .= sprintf('FIND_IN_SET("%s",%s)', $ov_val, $field);
601
					}
602
					$where[] = "($tmp_ov_val)";
603
				} else {
604
					$where[] = sprintf('%s %s %s', $field, $ov['oper'], $ov['value']);
605
				}
606
			}
607
		}
608
		// Add any coder specified filters
609
		if (! $text && $this->filters) {
610
			$where[] = '('.$this->filters.')';
611
		}
612
		if (count($where) > 0) {
613
			if ($text) {
614
				return str_replace('%', '*', join(' AND ',$where));
615
			} else {
616
				return join(' AND ',$where);
617
			}
618
		}
619
		return ''; /* empty string */
620
	} /* }}} */
621
 
622
	function gather_query_opts() /* {{{ */
623
	{
624
		$this->query_opts = array();
625
		$this->prev_qfn   = $this->qfn;
626
		$this->qfn        = '';
627
		if ($this->clear_operation()) {
628
			return;
629
		}
630
		// gathers query options into an array, $this->query_opts
631
		$qo = array();
632
		for ($k = 0; $k < $this->num_fds; $k++) {
633
			$l    = 'qf'.$k;
634
			$lc   = 'qf'.$k.'_comp';
635
			$li   = 'qf'.$k.'_id';
636
			$m    = $this->get_sys_cgi_var($l);
637
			$mc   = $this->get_sys_cgi_var($lc);
638
			$mi   = $this->get_sys_cgi_var($li);
639
			if (! isset($m) && ! isset($mi)) {
640
				continue;
641
			}
642
			if (is_array($m) || is_array($mi)) {
643
				if (is_array($mi)) {
644
					$m = $mi;
645
					$l = $li;
646
				}
647
				if (in_array('*', $m)) {
648
					continue;
649
				}
650
				if ($this->col_has_values($k) && $this->col_has_multiple($k)) {
651
					foreach (array_keys($m) as $key) {
652
						$m[$key] = addslashes($m[$key]);
653
					}
654
					$qo[$this->fqn($k)] = array('value' => $m);
655
				} else {
656
					$qf_op = '';
657
					foreach (array_keys($m) as $key) {
658
						if ($qf_op == '') {
659
							$qf_op   = 'IN';
660
							$qf_val  = '"'.addslashes($m[$key]).'"';
661
							$afilter = ' IN ("'.addslashes($m[$key]).'"'; // )
662
						} else {
663
							$afilter = $afilter.',"'.addslashes($m[$key]).'"';
664
							$qf_val .= ',"'.addslashes($m[$key]).'"';
665
						}
666
						$this->qfn .= '&'.$this->cgi['prefix']['sys'].$l.'['.rawurlencode($key).']='.rawurlencode($m[$key]);
667
					}
668
					$afilter = $afilter.')';
669
					// XXX: $dont_desc and $dont_cols hack
670
					$dont_desc = isset($this->fdd[$k]['values']['description']);
671
					$dont_cols = isset($this->fdd[$k]['values']['column']);
672
					$qo[$this->fqn($k, $dont_desc, $dont_cols)] =
673
						array('oper'  => $qf_op, 'value' => "($qf_val)"); // )
674
				}
675
			} else if (isset($mi)) {
676
				if ($mi == '*') {
677
					continue;
678
				}
679
				if ($this->fdd[$k]['select'] != 'M' && $this->fdd[$k]['select'] != 'D' && $mi == '') {
680
					continue;
681
				}
682
				$afilter = addslashes($mi);
683
				$qo[$this->fqn($k, true, true)] = array('oper'  => '=', 'value' => "'$afilter'");
684
				$this->qfn .= '&'.$this->cgi['prefix']['sys'].$li.'='.rawurlencode($mi);
685
			} else if (isset($m)) {
686
				if ($m == '*') {
687
					continue;
688
				}
689
				if ($this->fdd[$k]['select'] != 'M' && $this->fdd[$k]['select'] != 'D' && $m == '') {
690
					continue;
691
				}
692
				$afilter = addslashes($m);
693
				if ($this->fdd[$k]['select'] == 'N') {
694
					$mc = in_array($mc, $this->comp_ops) ? $mc : '=';
695
					$qo[$this->fqn($k)] = array('oper' => $mc, 'value' => "'$afilter'");
696
					$this->qfn .= '&'.$this->cgi['prefix']['sys'].$l .'='.rawurlencode($m);
697
					$this->qfn .= '&'.$this->cgi['prefix']['sys'].$lc.'='.rawurlencode($mc);
698
				} else {
699
					$afilter = '%'.str_replace('*', '%', $afilter).'%';
700
					$ids  = array();
701
					$ar   = array();
702
					$ar[$this->fqn($k)] = array('oper' => 'LIKE', 'value' => "'$afilter'");
703
					if (is_array($this->fdd[$k]['values2'])) {
704
						foreach ($this->fdd[$k]['values2'] as $key => $val) {
705
							if (strlen($m) > 0 && stristr($val, $m)) {
706
								$ids[] = '"'.addslashes($key).'"';
707
							}
708
						}
709
						if (count($ids) > 0) {
710
							$ar[$this->fqn($k, true, true)]
711
								= array('oper'  => 'IN', 'value' => '('.join(',', $ids).')');
712
						}
713
					}
714
					$qo[] = $ar;
715
					$this->qfn .= '&'.$this->cgi['prefix']['sys'].$l.'='.rawurlencode($m);
716
				}
717
			}
718
		}
719
		$this->query_opts = $qo;
720
	} /* }}} */
721
 
722
	/*
723
	 * Create JavaScripts
724
	 */
725
 
726
	function form_begin() /* {{{ */
727
	{
728
		$page_name = htmlspecialchars($this->page_name);
729
		if ($this->add_operation() || $this->change_operation() || $this->copy_operation()
730
				|| $this->view_operation() || $this->delete_operation()) {
731
			$field_to_tab = array();
732
			for ($tab = $k = $this->cur_tab = 0; $k < $this->num_fds; $k++) {
733
				if (isset($this->fdd[$k]['tab'])) {
734
					if ($tab == 0 && $k > 0) {
735
						$this->tabs[0] = 'PMEtab0';
736
						$this->cur_tab = 1;
737
						$tab++;
738
					}
739
					if (is_array($this->fdd[$k]['tab'])) {
740
						$this->tabs[$tab] = @$this->fdd[$k]['tab']['name'];
741
						$this->fdd[$k]['tab']['default'] && $this->cur_tab = $tab;
742
					} else {
743
						$this->tabs[$tab] = @$this->fdd[$k]['tab'];
744
					}
745
					$tab++;
746
				}
747
				$field_to_tab[$k] = max(0, $tab - 1);
748
			}
749
			if (preg_match('/^'.$this->dhtml['prefix'].'tab(\d+)$/', $this->get_sys_cgi_var('cur_tab'), $parts)) {
750
				$this->cur_tab = $parts[1];
751
			}
752
			if ($this->tabs_enabled()) {
753
				// initial TAB styles
754
				echo '<style type="text/css" media="screen">',"\n";
755
				for ($i = 0; $i < count($this->tabs); $i++) {
756
					echo '	#'.$this->dhtml['prefix'].'tab',$i,' { display: ';
757
					echo (($i == $this->cur_tab || $this->tabs[$i] == 'PMEtab0' ) ? 'block' : 'none') ,'; }',"\n";
758
				}
759
				echo '</style>',"\n";
760
				// TAB javascripts
761
				echo '<script type="text/javascript"><!--',"\n\n";
762
				$css_class_name1 = $this->getCSSclass('tab', $position);
763
				$css_class_name2 = $this->getCSSclass('tab-selected', $position);
764
				echo 'var '.$this->js['prefix'].'cur_tab  = "'.$this->dhtml['prefix'].'tab',$this->cur_tab,'";
765
 
766
function '.$this->js['prefix'].'show_tab(tab_name)
767
{';
768
				if ($this->nav_up()) {
769
					echo '
770
	document.getElementById('.$this->js['prefix'].'cur_tab+"_up_label").className = "',$css_class_name1,'";
771
	document.getElementById('.$this->js['prefix'].'cur_tab+"_up_link").className = "',$css_class_name1,'";
772
	document.getElementById(tab_name+"_up_label").className = "',$css_class_name2,'";
773
	document.getElementById(tab_name+"_up_link").className = "',$css_class_name2,'";';
774
				}
775
				if ($this->nav_down()) {
776
					echo '
777
	document.getElementById('.$this->js['prefix'].'cur_tab+"_down_label").className = "',$css_class_name1,'";
778
	document.getElementById('.$this->js['prefix'].'cur_tab+"_down_link").className = "',$css_class_name1,'";
779
	document.getElementById(tab_name+"_down_label").className = "',$css_class_name2,'";
780
	document.getElementById(tab_name+"_down_link").className = "',$css_class_name2,'";';
781
				}
782
				echo '
783
	document.getElementById('.$this->js['prefix'].'cur_tab).style.display = "none";
784
	document.getElementById(tab_name).style.display = "block";
785
	'.$this->js['prefix'].'cur_tab = tab_name;
786
	document.'.$this->cgi['prefix']['sys'].'form.'.$this->cgi['prefix']['sys'].'cur_tab.value = tab_name;
787
}',"\n\n";
788
				echo '// --></script>', "\n";
789
			}
790
		}
791
 
792
		if ($this->add_operation() || $this->change_operation() || $this->copy_operation()) {
793
			$first_required = true;
794
			for ($k = 0; $k < $this->num_fds; $k++) {
795
				if ($this->displayed[$k] && ! $this->readonly($k) && ! $this->hidden($k)
796
						&& ($this->fdd[$k]['js']['required'] || isset($this->fdd[$k]['js']['regexp']))) {
797
					if ($first_required) {
798
				 		$first_required = false;
799
						echo '<script type="text/javascript"><!--',"\n";
800
						echo '
801
function '.$this->js['prefix'].'trim(str)
802
{
803
	while (str.substring(0, 1) == " "
804
			|| str.substring(0, 1) == "\\n"
805
			|| str.substring(0, 1) == "\\r")
806
	{
807
		str = str.substring(1, str.length);
808
	}
809
	while (str.substring(str.length - 1, str.length) == " "
810
			|| str.substring(str.length - 1, str.length) == "\\n"
811
			|| str.substring(str.length - 1, str.length) == "\\r")
812
	{
813
		str = str.substring(0, str.length - 1);
814
	}
815
	return str;
816
}
817
 
818
function '.$this->js['prefix'].'form_control(theForm)
819
{',"\n";
820
					}
821
					if ($this->col_has_values($k)) {
822
						$condition = 'theForm.'.$this->cgi['prefix']['data'].$this->fds[$k].'.selectedIndex == -1';
823
						$multiple  = $this->col_has_multiple_select($k);
824
					} else {
825
						$condition = '';
826
						$multiple  = false;
827
						if ($this->fdd[$k]['js']['required']) {
828
							$condition = $this->js['prefix'].'trim(theForm.'.$this->cgi['prefix']['data'].$this->fds[$k].'.value) == ""';
829
						}
830
						if (isset($this->fdd[$k]['js']['regexp'])) {
831
							$condition .= (strlen($condition) > 0 ? ' || ' : '');
832
							$condition .= sprintf('!(%s.test('.$this->js['prefix'].'trim(theForm.%s.value)))',
833
									$this->fdd[$k]['js']['regexp'], $this->cgi['prefix']['data'].$this->fds[$k]);
834
						}
835
					}
836
 
837
					/* Multiple selects have their name like ``name[]''.
838
					   It is not possible to work with them directly, because
839
					   theForm.name[].something will result into JavaScript
840
					   syntax error. Following search algorithm is provided
841
					   as a workaround for this.
842
					 */
843
					if ($multiple) {
844
						echo '
845
	multiple_select = null;
846
	for (i = 0; i < theForm.length; i++) {
847
		if (theForm.elements[i].name == "',$this->cgi['prefix']['data'].$this->fds[$k],'[]") {
848
			multiple_select = theForm.elements[i];
849
			break;
850
		}
851
	}
852
	if (multiple_select != null && multiple_select.selectedIndex == -1) {';
853
					} else {
854
						echo '
855
	if (',$condition,') {';
856
					}
857
					echo '
858
		alert("';
859
					if (isset($this->fdd[$k]['js']['hint'])) {
860
						echo htmlspecialchars($this->fdd[$k]['js']['hint']);
861
					} else {
862
						echo $this->labels['Please enter'],' ',$this->fdd[$k]['name'],'.';
863
					}
864
					echo '");';
865
					if ($this->tabs_enabled() && $field_to_tab[$k] >= $this->cur_tab) {
866
						echo '
867
		'.$this->js['prefix'].'show_tab("'.$this->dhtml['prefix'].'tab',$field_to_tab[$k],'");';
868
					}
869
					echo '
870
		theForm.',$this->cgi['prefix']['data'].$this->fds[$k],'.focus();
871
		return false;
872
	}',"\n";
873
				}
874
			}
875
			if (! $first_required) {
876
				echo '
877
	return true;
878
}',"\n\n";
879
				echo '// --></script>', "\n";
880
			}
881
		}
882
 
883
		if ($this->filter_operation()) {
884
				echo '<script type="text/javascript"><!--',"\n";
885
				echo '
886
function '.$this->js['prefix'].'filter_handler(theForm, theEvent)
887
{
888
	var pressed_key = null;
889
	if (theEvent.which) {
890
		pressed_key = theEvent.which;
891
	} else {
892
		pressed_key = theEvent.keyCode;
893
	}
894
	if (pressed_key == 13) { // enter pressed
895
		theForm.submit();
896
		return false;
897
	}
898
	return true;
899
}',"\n\n";
900
				echo '// --></script>', "\n";
901
		}
902
 
903
		if ($this->display['form']) {
904
			echo '<form class="',$this->getCSSclass('form'),'" method="post"';
905
			echo ' action="',$page_name,'" name="'.$this->cgi['prefix']['sys'].'form">',"\n";
906
		}
907
		return true;
908
	} /* }}} */
909
 
910
	function form_end() /* {{{ */
911
	{
912
		if ($this->display['form']) {
913
			echo '</form>',"\n";
914
		}
915
	} /* }}} */
916
 
917
	function display_tab_labels($position) /* {{{ */
918
	{
919
		if (! is_array($this->tabs)) {
920
			return false;
921
		}
922
		echo '<table summary="labels" class="',$this->getCSSclass('tab', $position),'">',"\n";
923
		echo '<tr class="',$this->getCSSclass('tab', $position),'">',"\n";
924
		for ($i = ($this->tabs[0] == 'PMEtab0' ? 1 : 0); $i < count($this->tabs); $i++) {
925
			$css_class_name = $this->getCSSclass($i != $this->cur_tab ? 'tab' : 'tab-selected', $position);
926
			echo '<td class="',$css_class_name,'" id="'.$this->dhtml['prefix'].'tab',$i,'_',$position,'_label">';
927
			echo '<a class="',$css_class_name,'" id="'.$this->dhtml['prefix'].'tab',$i,'_',$position,'_link';
928
			echo '" href="javascript:'.$this->js['prefix'].'show_tab(\''.$this->dhtml['prefix'].'tab',$i,'\')">';
929
			echo $this->tabs[$i],'</a></td>',"\n";
930
		}
931
		echo '<td class="',$this->getCSSclass('tab-end', $position),'">&nbsp;</td>',"\n";
932
		echo '</tr>',"\n";
933
		echo '</table>',"\n";
934
	} /* }}} */
935
 
936
	/*
937
	 * Display functions
938
	 */
939
 
940
	function display_add_record() /* {{{ */
941
	{
942
		for ($tab = 0, $k = 0; $k < $this->num_fds; $k++) {
943
			if (isset($this->fdd[$k]['tab']) && $this->tabs_enabled() && $k > 0) {
944
				$tab++;
945
				echo '</table>',"\n";
946
				echo '</div>',"\n";
947
				echo '<div id="'.$this->dhtml['prefix'].'tab',$tab,'">',"\n";
948
				echo '<table class="',$this->getCSSclass('main'),'" summary="',$this->tb,'">',"\n";
949
			}
950
			if (! $this->displayed[$k]) {
951
				continue;
952
			}
953
			if ($this->hidden($k)) {
954
				echo $this->htmlHiddenData($this->fds[$k], $this->fdd[$k]['default']);
955
				continue;
956
			}
957
			$css_postfix    = @$this->fdd[$k]['css']['postfix'];
958
			$css_class_name = $this->getCSSclass('input', null, 'next', $css_postfix);
959
			$escape			= isset($this->fdd[$k]['escape']) ? $this->fdd[$k]['escape'] : true;
960
			echo '<tr class="',$this->getCSSclass('row', null, true, $css_postfix),'">',"\n";
961
			echo '<td class="',$this->getCSSclass('key', null, true, $css_postfix),'">';
962
			echo $this->fdd[$k]['name'],'</td>',"\n";
963
			echo '<td class="',$this->getCSSclass('value', null, true, $css_postfix),'"';
964
			echo $this->getColAttributes($k),">\n";
965
			if ($this->col_has_values($k)) {
966
				$vals       = $this->set_values($k);
967
				$selected   = @$this->fdd[$k]['default'];
968
				$multiple   = $this->col_has_multiple($k);
969
				$readonly   = $this->readonly($k);
970
				$strip_tags = true;
971
				//$escape     = true;
972
				if ($this->col_has_checkboxes($k) || $this->col_has_radio_buttons($k)) {
973
					echo $this->htmlRadioCheck($this->cgi['prefix']['data'].$this->fds[$k],
974
							$css_class_name, $vals, $selected, $multiple, $readonly,
975
							$strip_tags, $escape);
976
				} else {
977
					echo $this->htmlSelect($this->cgi['prefix']['data'].$this->fds[$k],
978
							$css_class_name, $vals, $selected, $multiple, $readonly,
979
							$strip_tags, $escape);
980
				}
981
			} elseif (isset ($this->fdd[$k]['textarea'])) {
982
				echo '<textarea class="',$css_class_name,'" name="',$this->cgi['prefix']['data'].$this->fds[$k],'"';
983
				echo ($this->readonly($k) ? ' disabled="disabled"' : '');
984
				if (intval($this->fdd[$k]['textarea']['rows']) > 0) {
985
					echo ' rows="',$this->fdd[$k]['textarea']['rows'],'"';
986
				}
987
				if (intval($this->fdd[$k]['textarea']['cols']) > 0) {
988
					echo ' cols="',$this->fdd[$k]['textarea']['cols'],'"';
989
				}
990
				if (isset($this->fdd[$k]['textarea']['wrap'])) {
991
					echo ' wrap="',$this->fdd[$k]['textarea']['wrap'],'"';
992
				} else {
993
					echo ' wrap="virtual"';
994
				}
995
				echo '>';
996
				if($escape) echo htmlspecialchars($this->fdd[$k]['default']);
997
				else echo $this->fdd[$k]['default'];
998
				echo '</textarea>',"\n";
999
			} elseif ($this->col_has_php($k)) {
1000
				echo include($this->fdd[$k]['php']);
1001
			} else {
1002
				// Simple edit box required
1003
				$size_ml_props = '';
1004
				$maxlen = intval($this->fdd[$k]['maxlen']);
1005
				$size   = isset($this->fdd[$k]['size']) ? $this->fdd[$k]['size'] : min($maxlen, 60);
1006
				$size   && $size_ml_props .= ' size="'.$size.'"';
1007
				$maxlen && $size_ml_props .= ' maxlength="'.$maxlen.'"';
1008
				echo '<input class="',$css_class_name,'" ';
1009
				echo ($this->password($k) ? 'type="password"' : 'type="text"');
1010
				echo ($this->readonly($k) ? ' disabled="disabled"' : '');
1011
				echo ' name="',$this->cgi['prefix']['data'].$this->fds[$k],'"';
1012
				echo $size_ml_props,' value="';
1013
				if($escape) echo htmlspecialchars($this->fdd[$k]['default']);
1014
			    else echo $this->fdd[$k]['default'];
1015
				echo '" />';
1016
			}
1017
			echo '</td>',"\n";
1018
			if ($this->guidance) {
1019
				$css_class_name = $this->getCSSclass('help', null, true, $css_postfix);
1020
				$cell_value     = $this->fdd[$k]['help'] ? $this->fdd[$k]['help'] : '&nbsp;';
1021
				echo '<td class="',$css_class_name,'">',$cell_value,'</td>',"\n";
1022
			}
1023
			echo '</tr>',"\n";
1024
		}
1025
	} /* }}} */
1026
 
1027
	function display_copy_change_delete_record() /* {{{ */
1028
	{
1029
		/*
1030
		 * For delete or change: SQL SELECT to retrieve the selected record
1031
		 */
1032
 
1033
		$qparts['type']   = 'select';
1034
		$qparts['select'] = $this->get_SQL_column_list();
1035
		$qparts['from']   = $this->get_SQL_join_clause();
1036
		$qparts['where']  = '('.$this->fqn($this->key).'='
1037
			.$this->key_delim.$this->rec.$this->key_delim.')';
1038
 
1039
		$res = $this->myquery($this->get_SQL_query($qparts),__LINE__);
1040
		if (! ($row = @mysql_fetch_array($res, MYSQL_ASSOC))) {
1041
			return false;
1042
		}
1043
		for ($tab = 0, $k = 0; $k < $this->num_fds; $k++) {
1044
			if (isset($this->fdd[$k]['tab']) && $this->tabs_enabled() && $k > 0) {
1045
				$tab++;
1046
				echo '</table>',"\n";
1047
				echo '</div>',"\n";
1048
				echo '<div id="'.$this->dhtml['prefix'].'tab',$tab,'">',"\n";
1049
				echo '<table class="',$this->getCSSclass('main'),'" summary="',$this->tb,'">',"\n";
1050
			}
1051
			if (! $this->displayed[$k]) {
1052
				continue;
1053
			}
1054
			if ($this->copy_operation() || $this->change_operation()) {
1055
				if ($this->hidden($k)) {
1056
					if ($k != $this->key_num) {
1057
						echo $this->htmlHiddenData($this->fds[$k], $row["qf$k"]);
1058
					}
1059
					continue;
1060
				}
1061
				$css_postfix = @$this->fdd[$k]['css']['postfix'];
1062
				echo '<tr class="',$this->getCSSclass('row', null, 'next', $css_postfix),'">',"\n";
1063
				echo '<td class="',$this->getCSSclass('key', null, true, $css_postfix),'">';
1064
				echo $this->fdd[$k]['name'],'</td>',"\n";
1065
				/* There are two possibilities of readonly fields handling:
1066
				   1. Display plain text for readonly timestamps, dates and URLs.
1067
				   2. Display disabled input field
1068
				   In all cases particular readonly field will NOT be saved. */
1069
				if ($this->readonly($k) && ($this->col_has_datemask($k) || $this->col_has_URL($k))) {
1070
					echo $this->display_delete_field($row, $k);
1071
				} elseif ($this->password($k)) {
1072
					echo $this->display_password_field($row, $k);
1073
				} else {
1074
					echo $this->display_change_field($row, $k);
1075
				}
1076
				if ($this->guidance) {
1077
					$css_class_name = $this->getCSSclass('help', null, true, $css_postfix);
1078
					$cell_value     = $this->fdd[$k]['help'] ? $this->fdd[$k]['help'] : '&nbsp;';
1079
					echo '<td class="',$css_class_name,'">',$cell_value,'</td>',"\n";
1080
				}
1081
				echo '</tr>',"\n";
1082
			} elseif ($this->delete_operation() || $this->view_operation()) {
1083
				$css_postfix = @$this->fdd[$k]['css']['postfix'];
1084
				echo '<tr class="',$this->getCSSclass('row', null, 'next', $css_postfix),'">',"\n";
1085
				echo '<td class="',$this->getCSSclass('key', null, true, $css_postfix),'">';
1086
				echo $this->fdd[$k]['name'],'</td>',"\n";
1087
				if ($this->password($k)) {
1088
					echo '<td class="',$this->getCSSclass('value', null, true, $css_postfix),'"';
1089
					echo $this->getColAttributes($k),'>',$this->labels['hidden'],'</td>',"\n";
1090
				} else {
1091
					$this->display_delete_field($row, $k);
1092
				}
1093
				if ($this->guidance) {
1094
					$css_class_name = $this->getCSSclass('help', null, true, $css_postfix);
1095
					$cell_value     = $this->fdd[$k]['help'] ? $this->fdd[$k]['help'] : '&nbsp;';
1096
					echo '<td class="',$css_class_name,'">',$cell_value,'</td>',"\n";
1097
				}
1098
				echo '</tr>',"\n";
1099
			}
1100
		}
1101
	} /* }}} */
1102
 
1103
	function display_change_field($row, $k) /* {{{ */
1104
	{
1105
		$css_postfix    = @$this->fdd[$k]['css']['postfix'];
1106
		$css_class_name = $this->getCSSclass('input', null, true, $css_postfix);
1107
		$escape         = isset($this->fdd[$k]['escape']) ? $this->fdd[$k]['escape'] : true;
1108
		echo '<td class="',$this->getCSSclass('value', null, true, $css_postfix),'"';
1109
		echo $this->getColAttributes($k),">\n";
1110
		if ($this->col_has_values($k)) {
1111
			$vals       = $this->set_values($k);
1112
			$multiple   = $this->col_has_multiple($k);
1113
			$readonly   = $this->readonly($k);
1114
			$strip_tags = true;
1115
			//$escape     = true;
1116
			if ($this->col_has_checkboxes($k) || $this->col_has_radio_buttons($k)) {
1117
				echo $this->htmlRadioCheck($this->cgi['prefix']['data'].$this->fds[$k],
1118
						$css_class_name, $vals, $row["qf$k"], $multiple, $readonly,
1119
						$strip_tags, $escape);
1120
			} else {
1121
				echo $this->htmlSelect($this->cgi['prefix']['data'].$this->fds[$k],
1122
						$css_class_name, $vals, $row["qf$k"], $multiple, $readonly,
1123
						$strip_tags, $escape);
1124
			}
1125
		} elseif (isset($this->fdd[$k]['textarea'])) {
1126
			echo '<textarea class="',$css_class_name,'" name="',$this->cgi['prefix']['data'].$this->fds[$k],'"';
1127
			echo ($this->readonly($k) ? ' disabled="disabled"' : '');
1128
			if (intval($this->fdd[$k]['textarea']['rows']) > 0) {
1129
				echo ' rows="',$this->fdd[$k]['textarea']['rows'],'"';
1130
			}
1131
			if (intval($this->fdd[$k]['textarea']['cols']) > 0) {
1132
				echo ' cols="',$this->fdd[$k]['textarea']['cols'],'"';
1133
			}
1134
			if (isset($this->fdd[$k]['textarea']['wrap'])) {
1135
				echo ' wrap="',$this->fdd[$k]['textarea']['wrap'],'"';
1136
			} else {
1137
				echo ' wrap="virtual"';
1138
			}
1139
			echo '>';
1140
			if($escape) echo htmlspecialchars($row["qf$k"]);
1141
			else echo $row["qf$k"];
1142
			echo '</textarea>',"\n";
1143
		} elseif ($this->col_has_php($k)) {
1144
			echo include($this->fdd[$k]['php']);
1145
		} else {
1146
			$size_ml_props = '';
1147
			$maxlen = intval($this->fdd[$k]['maxlen']);
1148
			$size   = isset($this->fdd[$k]['size']) ? $this->fdd[$k]['size'] : min($maxlen, 60);
1149
			$size   && $size_ml_props .= ' size="'.$size.'"';
1150
			$maxlen && $size_ml_props .= ' maxlength="'.$maxlen.'"';
1151
			echo '<input class="',$css_class_name,'" type="text" ';
1152
			echo ($this->readonly($k) ? 'disabled="disabled" ' : '');
1153
			echo 'name="',$this->cgi['prefix']['data'].$this->fds[$k],'" value="';
1154
			if($escape) echo htmlspecialchars($row["qf$k"]);
1155
			else echo $row["qf$k"];
1156
			echo '" />',"\n";
1157
		}
1158
		echo '</td>',"\n";
1159
	} /* }}} */
1160
 
1161
	function display_password_field($row, $k) /* {{{ */
1162
	{
1163
		$css_postfix = @$this->fdd[$k]['css']['postfix'];
1164
		echo '<td class="',$this->getCSSclass('value', null, true, $css_postfix),'"';
1165
		echo $this->getColAttributes($k),">\n";
1166
		$size_ml_props = '';
1167
		$maxlen = intval($this->fdd[$k]['maxlen']);
1168
		$size   = isset($this->fdd[$k]['size']) ? $this->fdd[$k]['size'] : min($maxlen, 60);
1169
		$size   && $size_ml_props .= ' size="'.$size.'"';
1170
		$maxlen && $size_ml_props .= ' maxlength="'.$maxlen.'"';
1171
		echo '<input class="',$this->getCSSclass('value', null, true, $css_postfix),'" type="password" ';
1172
		echo ($this->readonly($k) ? 'disabled="disabled" ' : '');
1173
		echo 'name="',$this->cgi['prefix']['data'].$this->fds[$k],'" value="';
1174
		echo htmlspecialchars($row["qf$k"]),'" ',$size_ml_props,' />',"\n";
1175
		echo '</td>',"\n";
1176
	} /* }}} */
1177
 
1178
	function display_delete_field($row, $k) /* {{{ */
1179
	{
1180
		$css_postfix    = @$this->fdd[$k]['css']['postfix'];
1181
		$css_class_name = $this->getCSSclass('value', null, true, $css_postfix);
1182
		echo '<td class="',$css_class_name,'"',$this->getColAttributes($k),">\n";
1183
		echo $this->cellDisplay($k, $row, $css_class_name);
1184
		echo '</td>',"\n";
1185
	} /* }}} */
1186
 
1187
	/**
1188
	 * Returns CSS class name
1189
	 */
1190
	function getCSSclass($name, $position  = null, $divider = null, $postfix = null) /* {{{ */
1191
	{
1192
		static $div_idx = -1;
1193
		$elements = array($this->css['prefix'], $name);
1194
		if ($this->page_type && $this->css['page_type']) {
1195
			if ($this->page_type != 'L' && $this->page_type != 'F') {
1196
				$elements[] = $this->page_types[$this->page_type];
1197
			}
1198
		}
1199
		if ($position && $this->css['position']) {
1200
			$elements[] = $position;
1201
		}
1202
		if ($divider && $this->css['divider']) {
1203
			if ($divider === 'next') {
1204
				$div_idx++;
1205
				if ($this->css['divider'] > 0 && $div_idx >= $this->css['divider']) {
1206
					$div_idx = 0;
1207
				}
1208
			}
1209
			$elements[] = $div_idx;
1210
		}
1211
		if ($postfix) {
1212
			$elements[] = $postfix;
1213
		}
1214
		return join($this->css['separator'], $elements);
1215
	} /* }}} */
1216
 
1217
	/**
1218
	 * Returns field cell HTML attributes
1219
	 */
1220
	function getColAttributes($k) /* {{{ */
1221
	{
1222
		$colattrs = '';
1223
		if (isset($this->fdd[$k]['colattrs'])) {
1224
			$colattrs .= ' ';
1225
			$colattrs .= trim($this->fdd[$k]['colattrs']);
1226
		}
1227
		if (isset($this->fdd[$k]['nowrap'])) {
1228
			$colattrs .= ' nowrap';
1229
		}
1230
		return $colattrs;
1231
	} /* }}} */
1232
 
1233
	/**
1234
	 * Substitutes variables in string
1235
	 * (this is very simple but secure eval() replacement)
1236
	 */
1237
	function substituteVars($str, $subst_ar) /* {{{ */
1238
	{
1239
		$array = preg_split('/(\\$\w+)/', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
1240
		$count = count($array);
1241
		for ($i = 1; $i < $count; $i += 2) {
1242
			$key = substr($array[$i], 1);
1243
			if (isset($subst_ar[$key])) {
1244
				$array[$i] = $subst_ar[$key];
1245
			}
1246
		}
1247
		return join('', $array);
1248
	} /* }}} */
1249
 
1250
	/**
1251
	 * Print URL
1252
	 */
1253
	function urlDisplay($k, $link_val, $disp_val, $css, $key) /* {{{ */
1254
	{
1255
		$escape = isset($this->fdd[$k]['escape']) ? $this->fdd[$k]['escape'] : true;
1256
		$ret  = '';
1257
		$name = $this->fds[$k];
1258
		$page = $this->page_name;
1259
		$url  = $this->cgi['prefix']['sys'].'rec'.'='.$key.'&'.$this->cgi['prefix']['sys'].'fm'
1260
			.'='.$this->fm.'&'.$this->cgi['prefix']['sys'].'fl'.'='.$this->fl;
1261
		$url .= '&'.$this->cgi['prefix']['sys'].'qfn'.'='.rawurlencode($this->qfn).$this->qfn;
1262
		$url .= '&'.$this->get_sfn_cgi_vars().$this->cgi['persist'];
1263
		$ar   = array(
1264
				'key'   => $key,
1265
				'name'  => $name,
1266
				'link'  => $link_val,
1267
				'value' => $disp_val,
1268
				'css'   => $css,
1269
				'page'  => $page,
1270
				'url'   => $url
1271
				);
1272
		$urllink = isset($this->fdd[$k]['URL'])
1273
			?  $this->substituteVars($this->fdd[$k]['URL'], $ar)
1274
			: $link_val;
1275
		$urldisp = isset($this->fdd[$k]['URLdisp'])
1276
			?  $this->substituteVars($this->fdd[$k]['URLdisp'], $ar)
1277
			: $disp_val;
1278
		$target = isset($this->fdd[$k]['URLtarget'])
1279
			? 'target="'.htmlspecialchars($this->fdd[$k]['URLtarget']).'" '
1280
			: '';
1281
		$prefix_found  = false;
1282
		$postfix_found = false;
1283
		$prefix_ar     = @$this->fdd[$k]['URLprefix'];
1284
		$postfix_ar    = @$this->fdd[$k]['URLpostfix'];
1285
		is_array($prefix_ar)  || $prefix_ar  = array($prefix_ar);
1286
		is_array($postfix_ar) || $postfix_ar = array($postfix_ar);
1287
		foreach ($prefix_ar as $prefix) {
1288
			if (! strncmp($prefix, $urllink, strlen($prefix))) {
1289
				$prefix_found = true;
1290
				break;
1291
			}
1292
		}
1293
		foreach ($postfix_ar as $postfix) {
1294
			if (! strncmp($postfix, $urllink, strlen($postfix))) {
1295
				$postfix_found = true;
1296
				break;
1297
			}
1298
		}
1299
		$prefix_found  || $urllink = array_shift($prefix_ar).$urllink;
1300
		$postfix_found || $urllink = $urllink.array_shift($postfix_ar);
1301
		if (strlen($urllink) <= 0 || strlen($urldisp) <= 0) {
1302
			$ret = '&nbsp;';
1303
		} else {
1304
			if ($escape) {
1305
				$urldisp = htmlspecialchars($urldisp);
1306
			}
1307
			$urllink = htmlspecialchars($urllink);
1308
			$ret = '<a '.$target.'class="'.$css.'" href="'.$urllink.'">'.$urldisp.'</a>';
1309
		}
1310
		return $ret;
1311
	} /* }}} */
1312
 
1313
	function cellDisplay($k, $row, $css) /* {{{ */
1314
	{
1315
		$escape  = isset($this->fdd[$k]['escape']) ? $this->fdd[$k]['escape'] : true;
1316
		$key_rec = $row['qf'.$this->key_num];
1317
		if (@$this->fdd[$k]['datemask']) {
1318
			$value = intval($row["qf$k".'_timestamp']);
1319
			$value = $value ? @date($this->fdd[$k]['datemask'], $value) : '';
1320
		} else if (@$this->fdd[$k]['strftimemask']) {
1321
			$value = intval($row["qf$k".'_timestamp']);
1322
			$value = $value ? @strftime($this->fdd[$k]['strftimemask'], $value) : '';
1323
		} else if ($this->is_values2($k, $row["qf$k"])) {
1324
			$value = $row['qf'.$k.'_idx'];
1325
			if ($this->fdd[$k]['select'] == 'M') {
1326
				$value_ar  = explode(',', $value);
1327
				$value_ar2 = array();
1328
				foreach ($value_ar as $value_key) {
1329
					if (isset($this->fdd[$k]['values2'][$value_key])) {
1330
						$value_ar2[$value_key] = $this->fdd[$k]['values2'][$value_key];
1331
						$escape = false;
1332
					}
1333
				}
1334
				$value = join(', ', $value_ar2);
1335
			} else {
1336
				if (isset($this->fdd[$k]['values2'][$value])) {
1337
					$value  = $this->fdd[$k]['values2'][$value];
1338
					$escape = false;
1339
				}
1340
			}
1341
		} elseif (isset($this->fdd[$k]['values2'][$row["qf$k"]])) {
1342
			$value = $this->fdd[$k]['values2'][$row["qf$k"]];
1343
		} else {
1344
			$value = $row["qf$k"];
1345
		}
1346
		$original_value = $value;
1347
		if (@$this->fdd[$k]['strip_tags']) {
1348
			$value = strip_tags($value);
1349
		}
1350
		if ($num_ar = @$this->fdd[$k]['number_format']) {
1351
			if (! is_array($num_ar)) {
1352
				$num_ar = array($num_ar);
1353
			}
1354
			if (count($num_ar) == 1) {
1355
				list($nbDec) = $num_ar;
1356
				$value = number_format($value, $nbDec);
1357
			} else if (count($num_ar) == 3) {
1358
				list($nbDec, $decPoint, $thSep) = $num_ar;
1359
				$value = number_format($value, $nbDec, $decPoint, $thSep);
1360
			}
1361
		}
1362
		if (intval($this->fdd[$k]['trimlen']) > 0 && strlen($value) > $this->fdd[$k]['trimlen']) {
1363
			$value = ereg_replace("[\r\n\t ]+",' ',$value);
1364
			$value = substr($value, 0, $this->fdd[$k]['trimlen'] - 3).'...';
1365
		}
1366
		if (@$this->fdd[$k]['mask']) {
1367
			$value = sprintf($this->fdd[$k]['mask'], $value);
1368
		}
1369
		if ($this->col_has_php($k)) {
1370
			return include($this->fdd[$k]['php']);
1371
		}
1372
		if ($this->col_has_URL($k)) {
1373
			return $this->urlDisplay($k, $original_value, $value, $css, $key_rec);
1374
		}
1375
		if (strlen($value) <= 0) {
1376
			return '&nbsp;';
1377
		}
1378
		if ($escape) {
1379
			$value = htmlspecialchars($value);
1380
		}
1381
		return nl2br($value);
1382
	} /* }}} */
1383
 
1384
	/**
1385
	 * Creates HTML submit input element
1386
	 *
1387
	 * @param	name			element name
1388
	 * @param	label			key in the language hash used as label
1389
	 * @param	css_class_name	CSS class name
1390
	 * @param	js_validation	if add JavaScript validation subroutine to button
1391
	 * @param	disabled		if mark the button as disabled
1392
	 * @param	js		any extra text in tags
1393
	 */
1394
	function htmlSubmit($name, $label, $css_class_name, $js_validation = true, $disabled = false, $js = NULL) /* {{{ */
1395
	{
1396
		// Note that <input disabled> isn't valid HTML, but most browsers support it
1397
		if($disabled == -1) return;
1398
		$markdisabled = $disabled ? ' disabled="disabled"' : '';
1399
		$ret = '<input'.$markdisabled.' type="submit" class="'.$css_class_name
1400
			.'" name="'.$this->cgi['prefix']['sys'].ltrim($markdisabled).$name
1401
			.'" value="'.(isset($this->labels[$label]) ? $this->labels[$label] : $label);
1402
		if ($js_validation) {
1403
			$ret .= '" onclick="return '.$this->js['prefix'].'form_control(this.form);';
1404
		}
1405
		$ret .='"';
1406
		if(isset($js)) $ret .= ' '.$js;
1407
		$ret .= ' />';
1408
		return $ret;
1409
	} /* }}} */
1410
 
1411
	/**
1412
	 * Creates HTML hidden input element
1413
	 *
1414
	 * @param	name	element name
1415
	 * @param	value	value
1416
	 */
1417
 
1418
	function htmlHiddenSys($name, $value) /* {{{ */
1419
	{
1420
		return $this->htmlHidden($this->cgi['prefix']['sys'].$name, $value);
1421
	} /* }}} */
1422
 
1423
	function htmlHiddenData($name, $value) /* {{{ */
1424
	{
1425
		return $this->htmlHidden($this->cgi['prefix']['data'].$name, $value);
1426
	} /* }}} */
1427
 
1428
	function htmlHidden($name, $value) /* {{{ */
1429
	{
1430
		return '<input type="hidden" name="'.htmlspecialchars($name)
1431
			.'" value="'.htmlspecialchars($value).'" />'."\n";
1432
	} /* }}} */
1433
 
1434
	/**
1435
	 * Creates HTML select element (tag)
1436
	 *
1437
	 * @param	name		element name
1438
	 * @param	css			CSS class name
1439
	 * @param	kv_array	key => value array
1440
	 * @param	selected	selected key (it can be single string, array of
1441
	 *						keys or multiple values separated by comma)
1442
	 * @param	multiple	bool for multiple selection
1443
	 * @param	readonly	bool for readonly/disabled selection
1444
	 * @param	strip_tags	bool for stripping tags from values
1445
	 * @param	escape		bool for HTML escaping values
1446
	 * @param	js		string to be in the <select >, ususally onchange='..';
1447
	 */
1448
	function htmlSelect($name, $css, $kv_array, $selected = null, /* ...) {{{ */
1449
			/* booleans: */ $multiple = false, $readonly = false, $strip_tags = false, $escape = true, $js = NULL)
1450
	{
1451
		$ret = '<select class="'.htmlspecialchars($css).'" name="'.htmlspecialchars($name);
1452
		if ($multiple) {
1453
			$ret  .= '[]" multiple size="'.$this->multiple;
1454
			if (! is_array($selected) && $selected !== null) {
1455
				$selected = explode(',', $selected);
1456
			}
1457
		}
1458
		$ret .= '"'.($readonly ? ' disabled="disabled"' : '').$js.'>'."\n";
1459
		if (! is_array($selected)) {
1460
			$selected = $selected === null ? array() : array($selected);
1461
		}
1462
		$found = false;
1463
		foreach ($kv_array as $key => $value) {
1464
			$ret .= '<option value="'.htmlspecialchars($key).'"';
1465
			if ((! $found || $multiple) && in_array((string) $key, $selected, 1)
1466
					|| (count($selected) == 0 && ! $found && ! $multiple)) {
1467
				$ret  .= ' selected="selected"';
1468
				$found = true;
1469
			}
1470
			$strip_tags && $value = strip_tags($value);
1471
			$escape     && $value = htmlspecialchars($value);
1472
			$ret .= '>'.$value.'</option>'."\n";
1473
		}
1474
		$ret .= '</select>';
1475
		return $ret;
1476
	} /* }}} */
1477
 
1478
	/**
1479
	 * Creates HTML checkboxes or radio buttons
1480
	 *
1481
	 * @param	name		element name
1482
	 * @param	css			CSS class name
1483
	 * @param	kv_array	key => value array
1484
	 * @param	selected	selected key (it can be single string, array of
1485
	 *						keys or multiple values separated by comma)
1486
	 * @param	multiple	bool for multiple selection (checkboxes)
1487
	 * @param	readonly	bool for readonly/disabled selection
1488
	 * @param	strip_tags	bool for stripping tags from values
1489
	 * @param	escape		bool for HTML escaping values
1490
	 * @param	js		string to be in the <select >, ususally onchange='..';
1491
	 */
1492
	function htmlRadioCheck($name, $css, $kv_array, $selected = null, /* ...) {{{ */
1493
			/* booleans: */ $multiple = false, $readonly = false, $strip_tags = false, $escape = true, $js = NULL)
1494
	{
1495
		$ret = '';
1496
		if ($multiple) {
1497
			if (! is_array($selected) && $selected !== null) {
1498
				$selected = explode(',', $selected);
1499
			}
1500
		}
1501
		if (! is_array($selected)) {
1502
			$selected = $selected === null ? array() : array($selected);
1503
		}
1504
		$found = false;
1505
		foreach ($kv_array as $key => $value) {
1506
			$ret .= '<input type="'.($multiple ? 'checkbox' : 'radio').'" name="';
1507
			$ret .= htmlspecialchars($name).'[]" value="'.htmlspecialchars($key).'"';
1508
			if ((! $found || $multiple) && in_array((string) $key, $selected, 1)
1509
					|| (count($selected) == 0 && ! $found && ! $multiple)) {
1510
				$ret  .= ' checked';
1511
				$found = true;
1512
			}
1513
			if ($readonly) {
1514
				$ret .= ' disabled="disabled"';
1515
			}
1516
			$strip_tags && $value = strip_tags($value);
1517
			$escape     && $value = htmlspecialchars($value);
1518
			$ret .= '>'.$value.'<br>'."\n";
1519
		}
1520
		return $ret;
1521
	} /* }}} */
1522
 
1523
    /**
1524
     * Returns original variables HTML code for use in forms or links.
1525
     *
1526
     * @param   mixed   $origvars       string or array of original varaibles
1527
     * @param   string  $method         type of method ("POST" or "GET")
1528
     * @param   mixed   $default_value  default value of variables
1529
     *                                  if null, empty values will be skipped
1530
     * @return                          get HTML code of original varaibles
1531
     */
1532
    function get_origvars_html($origvars, $method = 'post', $default_value = '') /* {{{ */
1533
    {
1534
        $ret    = '';
1535
        $method = strtoupper($method);
1536
        if ($method == 'POST') {
1537
            if (! is_array($origvars)) {
1538
                $new_origvars = array();
1539
                foreach (explode('&', $origvars) as $param) {
1540
                    $parts = explode('=', $param, 2);
1541
                    if (! isset($parts[1])) {
1542
                        $parts[1] = $default_value;
1543
                    }
1544
                    if (strlen($parts[0]) <= 0) {
1545
                        continue;
1546
                    }
1547
                    $new_origvars[$parts[0]] = $parts[1];
1548
                }
1549
                $origvars =& $new_origvars;
1550
            }
1551
            foreach ($origvars as $key => $val) {
1552
                if (strlen($val) <= 0 && $default_value === null) {
1553
                    continue;
1554
                }
1555
                $key = rawurldecode($key);
1556
                $val = rawurldecode($val);
1557
                $ret .= $this->htmlHidden($key, $val);
1558
            }
1559
        } else if (! strncmp('GET', $method, 3)) {
1560
            if (! is_array($origvars)) {
1561
                $ret .= $origvars;
1562
            } else {
1563
                foreach ($origvars as $key => $val) {
1564
                    if (strlen($val) <= 0 && $default_value === null) {
1565
                        continue;
1566
                    }
1567
                    $ret == '' || $ret .= '&amp;';
1568
                    $ret .= htmlspecialchars(rawurlencode($key));
1569
                    $ret .= '=';
1570
                    $ret .= htmlspecialchars(rawurlencode($val));
1571
                }
1572
            }
1573
            if ($method[strlen($method) - 1] == '+') {
1574
                $ret = "?$ret";
1575
            }
1576
        } else {
1577
            trigger_error('Unsupported Platon::get_origvars_html() method: '
1578
                    .$method, E_USER_ERROR);
1579
        }
1580
        return $ret;
1581
    } /* }}} */
1582
 
1583
	function get_sfn_cgi_vars($alternative_sfn = null) /* {{{ */
1584
	{
1585
		if ($alternative_sfn === null) { // FAST! (cached return value)
1586
			static $ret = null;
1587
			$ret == null && $ret = $this->get_sfn_cgi_vars($this->sfn);
1588
			return $ret;
1589
		}
1590
		$ret = '';
1591
		$i   = 0;
1592
		foreach ($alternative_sfn as $val) {
1593
			$ret != '' && $ret .= '&';
1594
			$ret .= rawurlencode($this->cgi['prefix']['sys'].'sfn')."[$i]=".rawurlencode($val);
1595
			$i++;
1596
		}
1597
		return $ret;
1598
	} /* }}} */
1599
 
1600
	function get_default_cgi_prefix($type) /* {{{ */
1601
	{
1602
		switch ($type) {
1603
			case 'operation':	return 'PME_op_';
1604
			case 'sys':			return 'PME_sys_';
1605
			case 'data':		return 'PME_data_';
1606
		}
1607
		return '';
1608
	} /* }}} */
1609
 
1610
	function get_sys_cgi_var($name, $default_value = null) /* {{{ */
1611
	{
1612
		if (isset($this)) {
1613
			return $this->get_cgi_var($this->cgi['prefix']['sys'].$name, $default_value);
1614
		}
1615
		return phpMyEdit::get_cgi_var(phpMyEdit::get_default_cgi_prefix('sys').$name, $default_value);
1616
	} /* }}} */
1617
 
1618
	function get_data_cgi_var($name, $default_value = null) /* {{{ */
1619
	{
1620
		if (isset($this)) {
1621
			return $this->get_cgi_var($this->cgi['prefix']['data'].$name, $default_value);
1622
		}
1623
		return phpMyEdit::get_cgi_var(phpMyEdit::get_default_cgi_prefix('data').$name, $default_value);
1624
	} /* }}} */
1625
 
1626
    function get_cgi_var($name, $default_value = null) /* {{{ */
1627
    {
1628
		if (isset($this) && isset($this->cgi['overwrite'][$name])) {
1629
			return $this->cgi['overwrite'][$name];
1630
		}
1631
 
1632
        static $magic_quotes_gpc = null;
1633
        if ($magic_quotes_gpc === null) {
1634
            $magic_quotes_gpc = get_magic_quotes_gpc();
1635
        }
1636
        $var = @$_GET[$name];
1637
        if (! isset($var)) {
1638
            $var = @$_POST[$name];
1639
        }
1640
        if (isset($var)) {
1641
            if ($magic_quotes_gpc) {
1642
                if (is_array($var)) {
1643
                    foreach (array_keys($var) as $key) {
1644
                        $var[$key] = stripslashes($var[$key]);
1645
                    }
1646
                } else {
1647
                    $var = stripslashes($var);
1648
                }
1649
            }
1650
        } else {
1651
            $var = @$default_value;
1652
        }
1653
		if (isset($this) && $var === null && isset($this->cgi['append'][$name])) {
1654
			return $this->cgi['append'][$name];
1655
		}
1656
        return $var;
1657
    } /* }}} */
1658
 
1659
	function get_server_var($name) /* {{{ */
1660
	{
1661
		if (isset($_SERVER[$name])) {
1662
			return $_SERVER[$name];
1663
		}
1664
		global $HTTP_SERVER_VARS;
1665
		if (isset($HTTP_SERVER_VARS[$name])) {
1666
			return $HTTP_SERVER_VARS[$name];
1667
		}
1668
		global $$name;
1669
		if (isset($$name)) {
1670
			return $$name;
1671
		}
1672
		return null;
1673
	} /* }}} */
1674
 
1675
	/*
1676
	 * Debug functions
1677
	 */
1678
 
1679
	function print_get_vars ($miss = 'No GET variables found') // debug only /* {{{ */
1680
	{
1681
		// we parse form GET variables
1682
		if (is_array($_GET)) {
1683
			echo "<p> Variables per GET ";
1684
			foreach ($_GET as $k => $v) {
1685
				if (is_array($v)) {
1686
					foreach ($v as $akey => $aval) {
1687
						// $_GET[$k][$akey] = strip_tags($aval);
1688
						// $$k[$akey] = strip_tags($aval);
1689
						echo "$k\[$akey\]=$aval   ";
1690
					}
1691
				} else {
1692
					// $_GET[$k] = strip_tags($val);
1693
					// $$k = strip_tags($val);
1694
					echo "$k=$v   ";
1695
				}
1696
			}
1697
			echo '</p>';
1698
		} else {
1699
			echo '<p>';
1700
			echo $miss;
1701
			echo '</p>';
1702
		}
1703
	} /* }}} */
1704
 
1705
	function print_post_vars($miss = 'No POST variables found')  // debug only /* {{{ */
1706
	{
1707
		global $_POST;
1708
		// we parse form POST variables
1709
		if (is_array($_POST)) {
1710
			echo "<p>Variables per POST ";
1711
			foreach ($_POST as $k => $v) {
1712
				if (is_array($v)) {
1713
					foreach ($v as $akey => $aval) {
1714
						// $_POST[$k][$akey] = strip_tags($aval);
1715
						// $$k[$akey] = strip_tags($aval);
1716
						echo "$k\[$akey\]=$aval   ";
1717
					}
1718
				} else {
1719
					// $_POST[$k] = strip_tags($val);
1720
					// $$k = strip_tags($val);
1721
					echo "$k=$v   ";
1722
				}
1723
			}
1724
			echo '</p>';
1725
		} else {
1726
			echo '<p>';
1727
			echo $miss;
1728
			echo '</p>';
1729
		}
1730
	} /* }}} */
1731
 
1732
	function print_vars ($miss = 'Current instance variables')  // debug only /* {{{ */
1733
	{
1734
		echo "$miss   ";
1735
		echo 'page_name=',$this->page_name,'   ';
1736
		echo 'hn=',$this->hn,'   ';
1737
		echo 'un=',$this->un,'   ';
1738
		echo 'pw=',$this->pw,'   ';
1739
		echo 'db=',$this->db,'   ';
1740
		echo 'dbp=',$this->dbp,'   ';
1741
		echo 'dbh=',$this->dbh,'   ';
1742
		echo 'tb=',$this->tb,'   ';
1743
		echo 'key=',$this->key,'   ';
1744
		echo 'key_type=',$this->key_type,'   ';
1745
		echo 'inc=',$this->inc,'   ';
1746
		echo 'options=',$this->options,'   ';
1747
		echo 'fdd=',$this->fdd,'   ';
1748
		echo 'fl=',$this->fl,'   ';
1749
		echo 'fm=',$this->fm,'   ';
1750
		echo 'sfn=',htmlspecialchars($this->get_sfn_cgi_vars()),'   ';
1751
		echo 'qfn=',$this->qfn,'   ';
1752
		echo 'sw=',$this->sw,'   ';
1753
		echo 'rec=',$this->rec,'   ';
1754
		echo 'navop=',$this->navop,'   ';
1755
		echo 'saveadd=',$this->saveadd,'   ';
1756
		echo 'moreadd=',$this->moreadd,'   ';
1757
		echo 'canceladd=',$this->canceladd,'   ';
1758
		echo 'savechange=',$this->savechange,'   ';
1759
		echo 'morechange=',$this->morechange,'   ';
1760
		echo 'cancelchange=',$this->cancelchange,'   ';
1761
		echo 'savecopy=',$this->savecopy,'   ';
1762
		echo 'cancelcopy=',$this->cancelcopy,'   ';
1763
		echo 'savedelete=',$this->savedelete,'   ';
1764
		echo 'canceldelete=',$this->canceldelete,'   ';
1765
		echo 'cancelview=',$this->cancelview,'   ';
1766
		echo 'operation=',$this->operation,'   ';
1767
		echo "\n";
1768
	} /* }}} */
1769
 
1770
	/*
1771
	 * Display buttons at top and bottom of page
1772
	 */
1773
	function display_list_table_buttons($position, $listall = false) /* {{{ */
1774
	{
1775
		if (($but_str = $this->display_buttons($position)) === null)
1776
			return;
1777
		if($position == 'down') echo '<hr class="'.$this->getCSSclass('hr', 'down').'" />'."\n";
1778
		echo '<table summary="navigation" class="',$this->getCSSclass('navigation', $position),'">',"\n";
1779
		echo '<tr class="',$this->getCSSclass('navigation', $position),'">',"\n";
1780
		echo '<td class="',$this->getCSSclass('buttons', $position),'">',"\n";
1781
		echo $but_str,'</td>',"\n";
1782
		// Message is now written here
1783
		if (strlen(@$this->message) > 0) {
1784
			echo '<td class="',$this->getCSSclass('message', $position),'">',$this->message,'</td>',"\n";
1785
		}
1786
		if($this->display['num_pages'] || $this->display['num_records'])
1787
			echo '<td class="',$this->getCSSclass('stats', $position),'">',"\n";
1788
		if($this->display['num_pages']) {
1789
			if ($listall) {
1790
				echo $this->labels['Page'],':&nbsp;1&nbsp;',$this->labels['of'],'&nbsp;1';
1791
			} else {
1792
				$current_page = intval($this->fm / $this->inc) + 1;
1793
				$total_pages  = max(1, ceil($this->total_recs / abs($this->inc)));
1794
				echo $this->labels['Page'],':&nbsp;',$current_page;
1795
				echo '&nbsp;',$this->labels['of'],'&nbsp;',$total_pages;
1796
			}
1797
		}
1798
		if($this->display['num_records'])
1799
			echo '&nbsp; ',$this->labels['Records'],':&nbsp;',$this->total_recs;
1800
		if($this->display['num_pages'] || $this->display['num_records']) echo '</td>';
1801
		echo '</tr></table>',"\n";
1802
		if($position == 'up') echo '<hr class="'.$this->getCSSclass('hr', 'up').'" />'."\n";
1803
	} /* }}} */
1804
 
1805
	/*
1806
	 * Display buttons at top and bottom of page
1807
	 */
1808
	function display_record_buttons($position) /* {{{ */
1809
	{
1810
		if (($but_str = $this->display_buttons($position)) === null)
1811
			return;
1812
		if ($position == 'down') {
1813
			if ($this->tabs_enabled()) $this->display_tab_labels('down');
1814
			echo '<hr class="',$this->getCSSclass('hr', 'down'),'" />',"\n";
1815
		}
1816
		echo '<table summary="navigation" class="',$this->getCSSclass('navigation', $position),'">',"\n";
1817
		echo '<tr class="',$this->getCSSclass('navigation', $position),'">',"\n";
1818
		echo '<td class="',$this->getCSSclass('buttons', $position),'">',"\n";
1819
		echo $but_str,'</td>',"\n";
1820
		// Message is now written here
1821
		//echo '</td>',"\n";
1822
		if (strlen(@$this->message) > 0) {
1823
			echo '<td class="',$this->getCSSclass('message', $position),'">',$this->message,'</td>',"\n";
1824
		}
1825
		echo '</tr></table>',"\n";
1826
		if ($position == 'up') {
1827
			if ($this->tabs_enabled()) $this->display_tab_labels('up');
1828
			echo '<hr class="',$this->getCSSclass('hr', 'up'),'" />',"\n";
1829
		}
1830
	} /* }}} */
1831
 
1832
	function display_buttons($position) /* {{{ */
1833
	{
1834
		$nav_fnc = 'nav_'.$position;
1835
		if(! $this->$nav_fnc())
1836
			return;
1837
		$buttons = (is_array($this->buttons[$this->page_type][$position]))
1838
			? $this->buttons[$this->page_type][$position]
1839
			: $this->default_buttons[$this->page_type];
1840
		foreach ($buttons as $name) {
1841
			$ret .= $this->display_button($name, $position)."\n";
1842
		}
1843
		return $ret;
1844
	} /* }}} */
1845
 
1846
	function display_button($name, $position = 'up') /* {{{ */
1847
	{
1848
		if (is_array($name)) {
1849
			if (isset($name['code'])) return $name['code'];
1850
			return $this->htmlSubmit($name['name'], $name['value'], $name['css'], $name['disabled'], $name['js']);
1851
		}
1852
		$disabled = 1; // show disabled by default
1853
		if ($name[0] == '+') { $name = substr($name, 1); $disabled =  0; } // always show disabled as enabled
1854
		if ($name[0] == '-') { $name = substr($name, 1); $disabled = -1; } // don't show disabled
1855
		if ($name == 'cancel') {
1856
			return $this->htmlSubmit('cancel'.$this->page_types[$this->page_type], 'Cancel',
1857
					$this->getCSSclass('cancel', $position), false);
1858
		}
1859
		if (in_array($name, array('add','view','change','copy','delete'))) {
1860
			$enabled_fnc = $name.'_enabled';
1861
			$enabled     = $this->$enabled_fnc();
1862
			if ($name != 'add' && ! $this->total_recs && strstr('LF', $this->page_type))
1863
				$enabled = false;
1864
			return $this->htmlSubmit('operation', ucfirst($name),
1865
					$this->getCSSclass($name, $position), false, $enabled ? 0 : $disabled);
1866
		}
1867
		if ($name == 'savedelete') {
1868
			$enabled     = $this->delete_enabled();
1869
			$js = 'onclick="return confirm(\''.$this->labels['Delete'].' ?\');"';
1870
			return $this->htmlSubmit('savedelete', 'Delete',
1871
					$this->getCSSclass('save', $position), false, $enabled ? 0 : $disabled, $js);
1872
		}
1873
		if (in_array($name, array('save','more'))) {
1874
			$validation = true; // if js validation
1875
			if     ($this->page_type == 'D' && $name == 'save' ) { $value = 'Delete'; $validation = false; }
1876
			elseif ($this->page_type == 'C' && $name == 'more' ) { $value = 'Apply'; }
1877
			else $value = ucfirst($name);
1878
			return $this->htmlSubmit($name.$this->page_types[$this->page_type], $value,
1879
					$this->getCSSclass($name, $position), $validation);
1880
		}
1881
		$listall = $this->inc <= 0;
1882
		if ($listall) {
1883
			$disabledprev = true;
1884
			$disablednext = true;
1885
			$total_pages  = 1;
1886
			$current_page = 1;
1887
		} else {
1888
			$disabledprev = $this->fm <= 0;
1889
			$disablednext =  $this->fm + $this->inc >= $this->total_recs;
1890
			$total_pages  = max(1, ceil($this->total_recs / abs($this->inc)));
1891
			$current_page = ceil($this->fm / abs($this->inc)); // must + 1
1892
		}
1893
		$disabledfirst = $disabledprev;
1894
		$disabledlast  = $disablednext;
1895
		// some statistics first
1896
		if ($name == 'total_pages') return $total_pages;
1897
		if ($name == 'current_page') return ($current_page+1);
1898
		if ($name == 'total_recs') return ($this->total_recs);
1899
		// now some goto buttons/dropdowns/inputs...
1900
		if ($name == 'goto_text') {
1901
			$ret = '<input type="text" class="'.$this->getCSSclass('gotopn', $position).'"';
1902
			$ret .= ' name="'.$this->cgi['prefix']['sys'].'navpn'.$position.'" value="'.($current_page+1).'"';
1903
			$ret .= ' size="'.(strlen($total_pages)+1).'" maxlength="'.(strlen($total_pages)+1).'"';
1904
			// TODO some js here.... on enter submit, on click erase ?...
1905
			$ret .=' oneypress="return PE_filter_handler(this.form, event);" />';
1906
			return $ret;
1907
		}
1908
		if ($name == 'goto_combo') {
1909
			$disabledgoto = !($listall || ($disablednext && $disabledprev)) ? '' : ' disabled';
1910
			if ($disablegoto != '' && $disabled < 0) return;
1911
			$kv_array = array();
1912
			for ($i = 0; $i < $total_pages; $i++) {
1913
				$kv_array[$this->inc * $i] = $i + 1;
1914
			}
1915
			// TODO: add onchange="return this.form.submit();" DONE ???
1916
			return $this->htmlSelect($this->cgi['prefix']['sys'].ltrim($disabledgoto).'navfm'.$position,
1917
					$this->getCSSclass('goto', $position), $kv_array, (string)$this->fm, false, $disabledgoto,
1918
					false, true, 'onchange="return this.form.submit();"');
1919
		}
1920
		if ($name == 'goto') {
1921
			return $this->htmlSubmit('navop', 'Go to', $this->getCSSclass('goto', $position),
1922
					false, ($listall || ($disablednext && $disabledprev)) ? $disabled : 0);
1923
		}
1924
		if (in_array($name, array('first','prev','next','last','<<','<','>','>>'))) {
1925
			$disabled_var = 'disabled'.$name;
1926
			$name2 = $name;
1927
			if (strlen($name) <= 2) {
1928
				$nav_values = array('<<' => 'first', '<' => 'prev', '>' => 'next', '>>' => 'last');
1929
				$disabled_var = 'disabled'.$nav_values[$name];
1930
				$name2 = $nav_values[$name];
1931
			}
1932
			return $this->htmlSubmit('navop', ucfirst($name),
1933
					$this->getCSSclass($name2, $position), false, $$disabled_var ? $disabled : 0);
1934
		}
1935
		if(isset($this->labels[$name])) return $this->labels[$name];
1936
		return $name;
1937
	} /* }}} */
1938
 
1939
	function number_of_recs() /* {{{ */
1940
	{
1941
		$count_parts = array(
1942
				'type'   => 'select',
1943
				'select' => 'count(*)',
1944
				'from'   => $this->get_SQL_join_clause(),
1945
				'where'  => $this->get_SQL_where_from_query_opts());
1946
		$res = $this->myquery($this->get_SQL_query($count_parts), __LINE__);
1947
		$row = @mysql_fetch_array($res, MYSQL_NUM);
1948
		$this->total_recs = $row[0];
1949
	} /* }}} */
1950
 
1951
	/*
1952
	 * Table Page Listing
1953
	 */
1954
	function list_table() /* {{{ */
1955
	{
1956
		if ($this->fm == '') {
1957
			$this->fm = 0;
1958
		}
1959
		$this->fm = $this->navfm;
1960
		if ($this->prev_operation()) {
1961
			$this->fm = $this->fm - $this->inc;
1962
			if ($this->fm < 0) {
1963
				$this->fm = 0;
1964
			}
1965
		}
1966
		if ($this->first_operation()) {
1967
			$this->fm = 0;
1968
		} // last operation must be performed below, after retrieving total_recs
1969
		if ($this->next_operation()) {
1970
			$this->fm += $this->inc;
1971
		}
1972
		$this->number_of_recs();
1973
		if ($this->last_operation() || $this->fm > $this->total_recs) { // if goto_text is badly set
1974
			$this->fm = (int)(($this->total_recs - 1)/$this->inc)*$this->inc;
1975
		}
1976
		// If sort sequence has changed, restart listing
1977
		$this->qfn != $this->prev_qfn && $this->fm = 0;
1978
		if (0) { // DEBUG
1979
			echo 'qfn vs. prev_qfn comparsion ';
1980
			echo '[<b>',htmlspecialchars($this->qfn),'</b>]';
1981
			echo '[<b>',htmlspecialchars($this->prev_qfn),'</b>]<br />';
1982
			echo 'comparsion <u>',($this->qfn == $this->prev_qfn ? 'proved' : 'failed'),'</u>';
1983
			echo '<hr />';
1984
		}
1985
		/*
1986
		 * If user is allowed to Change/Delete records, we need an extra column
1987
		 * to allow users to select a record
1988
		 */
1989
		$select_recs = $this->key != '' &&
1990
			($this->change_enabled() || $this->delete_enabled() || $this->view_enabled());
1991
		// Are we doing a listall?
1992
		$listall = $this->inc <= 0;
1993
		/*
1994
		 * Display the MySQL table in an HTML table
1995
		 */
1996
		$this->form_begin();
1997
		echo $this->get_origvars_html($this->get_sfn_cgi_vars());
1998
		echo $this->htmlHiddenSys('fl', $this->fl);
1999
		// Display buttons at top and/or bottom of page.
2000
		$this->display_list_table_buttons('up', $listall);
2001
		if ($this->cgi['persist'] != '') {
2002
			echo $this->get_origvars_html($this->cgi['persist']);
2003
		}
2004
		if (! $this->filter_operation()) {
2005
			echo $this->get_origvars_html($this->qfn);
2006
		}
2007
		echo $this->htmlHiddenSys('qfn', $this->qfn);
2008
		echo $this->htmlHiddenSys('fm', $this->fm);
2009
		echo '<table class="',$this->getCSSclass('main'),'" summary="',$this->tb,'">',"\n";
2010
		echo '<tr class="',$this->getCSSclass('header'),'">',"\n";
2011
		/*
2012
		 * System (navigation, selection) columns counting
2013
		 */
2014
		$sys_cols  = 0;
2015
		$sys_cols += intval($this->filter_enabled() || $select_recs);
2016
		if ($sys_cols > 0) {
2017
			$sys_cols += intval($this->nav_buttons()
2018
					&& ($this->nav_text_links() || $this->nav_graphic_links()));
2019
		}
2020
		/*
2021
		 * We need an initial column(s) (sys columns)
2022
		 * if we have filters, Changes or Deletes enabled
2023
		 */
2024
		if ($sys_cols) {
2025
			echo '<th class="',$this->getCSSclass('header'),'" colspan="',$sys_cols,'">';
2026
			if ($this->filter_enabled()) {
2027
				if ($this->filter_operation()) {
2028
					echo $this->htmlSubmit('sw', 'Hide', $this->getCSSclass('hide'), false);
2029
					echo $this->htmlSubmit('sw', 'Clear', $this->getCSSclass('clear'), false);
2030
				} else {
2031
					echo $this->htmlSubmit('sw', 'Search', $this->getCSSclass('search'), false);
2032
				}
2033
			} else {
2034
				echo '&nbsp;';
2035
			}
2036
			echo '</th>',"\n";
2037
		}
2038
		for ($k = 0; $k < $this->num_fds; $k++) {
2039
			$fd = $this->fds[$k];
2040
			if (! $this->displayed[$k]) {
2041
				continue;
2042
			}
2043
			$css_postfix    = @$this->fdd[$k]['css']['postfix'];
2044
			$css_class_name = $this->getCSSclass('header', null, null, $css_postfix);
2045
			$fdn = $this->fdd[$fd]['name'];
2046
			if (! $this->fdd[$fd]['sort'] || $this->password($fd)) {
2047
				echo '<th class="',$css_class_name,'">',$fdn,'</th>',"\n";
2048
			} else {
2049
				// Clicking on the current sort field reverses the sort order
2050
				$new_sfn = $this->sfn;
2051
				array_unshift($new_sfn, in_array("$k", $new_sfn, 1) ? "-$k" : $k);
2052
				echo '<th class="',$css_class_name,'">';
2053
				echo '<a class="',$css_class_name,'" href="';
2054
				echo htmlspecialchars($this->page_name.'?'.$this->cgi['prefix']['sys'].'fm'.'=0'
2055
						.'&'.$this->cgi['prefix']['sys'].'fl'.'='.$this->fl
2056
						.'&'.$this->cgi['prefix']['sys'].'qfn'.'='.rawurlencode($this->qfn).$this->qfn
2057
						.'&'.$this->get_sfn_cgi_vars($new_sfn).$this->cgi['persist']);
2058
				echo '">',$fdn,'</a></th>',"\n";
2059
			}
2060
		}
2061
		echo '</tr>',"\n";
2062
 
2063
		/*
2064
		 * Prepare the SQL Query from the data definition file
2065
		 */
2066
		$qparts['type']   = 'select';
2067
		$qparts['select'] = $this->get_SQL_column_list();
2068
		// Even if the key field isn't displayed, we still need its value
2069
		if ($select_recs) {
2070
			if (!in_array ($this->key, $this->fds)) {
2071
				$qparts['select'] .= ','.$this->fqn($this->key);
2072
			}
2073
		}
2074
		$qparts['from']  = $this->get_SQL_join_clause();
2075
		$qparts['where'] = $this->get_SQL_where_from_query_opts();
2076
		// build up the ORDER BY clause
2077
		if (isset($this->sfn)) {
2078
			$sort_fields   = array();
2079
			$sort_fields_w = array();
2080
			foreach ($this->sfn as $field) {
2081
				if ($field[0] == '-') {
2082
					$field = substr($field, 1);
2083
					$desc  = true;
2084
				} else {
2085
					$field = $field;
2086
					$desc  = false;
2087
				}
2088
				$sort_field   = $this->fqn($field);
2089
				$sort_field_w = $this->fdd[$field]['name'];
2090
				$this->col_has_sql($field) && $sort_field_w .= ' (sql)';
2091
				if ($desc) {
2092
					$sort_field   .= ' DESC';
2093
					$sort_field_w .= ' '.$this->labels['descending'];
2094
				} else {
2095
					$sort_field_w .= ' '.$this->labels['ascending'];
2096
				}
2097
				$sort_fields[]   = $sort_field;
2098
				$sort_fields_w[] = $sort_field_w;
2099
			}
2100
			if (count($sort_fields) > 0) {
2101
				$qparts['orderby'] = join(',', $sort_fields);
2102
			}
2103
		}
2104
		$qparts['limit'] = $listall ? '' : $this->fm.','.$this->inc;
2105
 
2106
		/*
2107
		 * Main list_table() query
2108
		 *
2109
		 * Each row of the HTML table is one record from the SQL query. We must
2110
		 * perform this query before filter printing, because we want to use
2111
		 * mysql_field_len() function. We will also fetch the first row to get
2112
		 * the field names.
2113
		 */
2114
		$query = $this->get_SQL_query($qparts);
2115
		$res   = $this->myquery($query, __LINE__);
2116
		if ($res == false) {
2117
			$this->error('invalid SQL query', $query);
2118
			return false;
2119
		}
2120
		$row = @mysql_fetch_array($res, MYSQL_ASSOC);
2121
 
2122
		/* FILTER {{{
2123
		 *
2124
		 * Draw the filter and fill it with any data typed in last pass and stored
2125
		 * in the array parameter keyword 'filter'. Prepare the SQL WHERE clause.
2126
		 */
2127
		if ($this->filter_operation()) {
2128
			// Filter row retrieval
2129
			$fields     = false;
2130
			$filter_row = $row;
2131
			if (! is_array($filter_row)) {
2132
				unset($qparts['where']);
2133
				$query = $this->get_SQL_query($qparts);
2134
				$res   = $this->myquery($query, __LINE__);
2135
				if ($res == false) {
2136
					$this->error('invalid SQL query', $query);
2137
					return false;
2138
				}
2139
				$filter_row = @mysql_fetch_array($res, MYSQL_ASSOC);
2140
			}
2141
			/* Variable $fields is used to get index of particular field in
2142
			   result. That index can be passed in example to mysql_field_len()
2143
			   function. Use field names as indexes to $fields array. */
2144
			if (is_array($filter_row)) {
2145
				$fields = array_flip(array_keys($filter_row));
2146
			}
2147
			if ($fields != false) {
2148
				$css_class_name = $this->getCSSclass('filter');
2149
				echo '<tr class="',$css_class_name,'">',"\n";
2150
				echo '<td class="',$css_class_name,'" colspan="',$sys_cols,'">';
2151
				echo $this->htmlSubmit('filter', 'Query', $this->getCSSclass('query'), false);
2152
				echo '</td>', "\n";
2153
				for ($k = 0; $k < $this->num_fds; $k++) {
2154
					if (! $this->displayed[$k]) {
2155
						continue;
2156
					}
2157
					$css_postfix      = @$this->fdd[$k]['css']['postfix'];
2158
					$css_class_name   = $this->getCSSclass('filter', null, null, $css_postfix);
2159
					$this->field_name = $this->fds[$k];
2160
					$fd               = $this->field_name;
2161
					$this->field      = $this->fdd[$fd];
2162
					$l  = 'qf'.$k;
2163
					$lc = 'qf'.$k.'_comp';
2164
					$li = 'qf'.$k.'_id';
2165
					if ($this->clear_operation()) {
2166
						$m  = null;
2167
						$mc = null;
2168
						$mi = null;
2169
					} else {
2170
						$m  = $this->get_sys_cgi_var($l);
2171
						$mc = $this->get_sys_cgi_var($lc);
2172
						$mi = $this->get_sys_cgi_var($li);
2173
					}
2174
					echo '<td class="',$css_class_name,'">';
2175
					if ($this->password($k)) {
2176
						echo '&nbsp;';
2177
					} else if ($this->fdd[$fd]['select'] == 'D' || $this->fdd[$fd]['select'] == 'M') {
2178
						// Multiple fields processing
2179
						// Default size is 2 and array required for values.
2180
						$from_table = ! $this->col_has_values($k) || isset($this->fdd[$k]['values']['table']);
2181
						$vals       = $this->set_values($k, array('*' => '*'), null, $from_table);
2182
						$selected   = $mi;
2183
						$multiple   = $this->col_has_multiple_select($k);
2184
						$multiple  |= $this->fdd[$fd]['select'] == 'M';
2185
						$readonly   = false;
2186
						$strip_tags = true;
2187
						$escape     = true;
2188
						echo $this->htmlSelect($this->cgi['prefix']['sys'].$l.'_id', $css_class_name,
2189
								$vals, $selected, $multiple, $readonly, $strip_tags, $escape);
2190
					} elseif ($this->fdd[$fd]['select'] == 'N' || $this->fdd[$fd]['select'] == 'T') {
2191
						$size_ml_props = '';
2192
						$maxlen = intval($this->fdd[$k]['maxlen']);
2193
						$maxlen > 0 || $maxlen = intval(@mysql_field_len($res, $fields["qf$k"]));
2194
						$size = isset($this->fdd[$k]['size']) ? $this->fdd[$k]['size']
2195
							: ($maxlen < 30 ? min($maxlen, 8) : 12);
2196
						$size   && $size_ml_props .= ' size="'.$size.'"';
2197
						$maxlen && $size_ml_props .= ' maxlength="'.$maxlen.'"';
2198
						if ($this->fdd[$fd]['select'] == 'N') {
2199
							$mc = in_array($mc, $this->comp_ops) ? $mc : '=';
2200
							echo $this->htmlSelect($this->cgi['prefix']['sys'].$l.'_comp',
2201
									$css_class_name, $this->comp_ops, $mc);
2202
						}
2203
						echo '<input class="',$css_class_name,'" value="',htmlspecialchars(@$m);
2204
						echo '" type="text" name="'.$this->cgi['prefix']['sys'].'qf'.$k.'"',$size_ml_props;
2205
						echo ' onkeypress="return '.$this->js['prefix'].'filter_handler(this.form, event);" />';
2206
					} else {
2207
						echo '&nbsp;';
2208
					}
2209
					echo '</td>',"\n";
2210
				}
2211
				echo '</tr>',"\n";
2212
			}
2213
		} // }}}
2214
 
2215
		/*
2216
		 * Display sorting sequence
2217
		 */
2218
		if ($qparts['orderby'] && $this->display['sort']) {
2219
			$css_class_name = $this->getCSSclass('sortinfo');
2220
			echo '<tr class="',$css_class_name,'">',"\n";
2221
			echo '<td class="',$css_class_name,'" colspan="',$sys_cols,'">';
2222
			echo '<a class="',$css_class_name,'" href="';
2223
			echo htmlspecialchars($this->page_name
2224
					.'?'.$this->cgi['prefix']['sys'].'fl'.'='.$this->fl
2225
					.'&'.$this->cgi['prefix']['sys'].'fm'.'='.$this->fm
2226
					.'&'.$this->cgi['prefix']['sys'].'qfn'.'='.rawurlencode($this->qfn)
2227
					.$this->qfn.$this->cgi['persist']);
2228
			echo '">',$this->labels['Clear'],'</a></td>',"\n";
2229
			echo '<td class="',$css_class_name,'" colspan="',$this->num_fields_displayed,'">';
2230
			echo $this->labels['Sorted By'],': ',join(', ', $sort_fields_w),'</td></tr>',"\n";
2231
		}
2232
 
2233
		/*
2234
		 * Display the current query
2235
		 */
2236
		$text_query = $this->get_SQL_where_from_query_opts(null, true);
2237
		if ($text_query != '' && $this->display['query']) {
2238
			$css_class_name = $this->getCSSclass('queryinfo');
2239
			echo '<tr class="',$css_class_name,'">',"\n";
2240
			echo '<td class="',$css_class_name,'" colspan="',$sys_cols,'">';
2241
			echo '<a class="',$css_class_name,'" href="';
2242
			echo htmlspecialchars($this->get_server_var('PHP_SELF')
2243
					.'?'.$this->cgi['prefix']['sys'].'fl'.'='.$this->fl
2244
					.'&'.$this->cgi['prefix']['sys'].'fm'.'='.$this->fm
2245
					.'&'.$this->cgi['prefix']['sys'].'qfn'.'='.rawurlencode($this->qfn)
2246
					.'&'.$this->get_sfn_cgi_vars().$this->cgi['persist']);
2247
			echo '">',$this->labels['Clear'],'</a></td>',"\n";
2248
			echo '<td class="',$css_class_name,'" colspan="',$this->num_fields_displayed,'">';
2249
			echo $this->labels['Current Query'],': ',htmlspecialchars($text_query),'</td></tr>',"\n";
2250
		}
2251
 
2252
		if ($this->nav_text_links() || $this->nav_graphic_links()) {
2253
			$qstrparts = array();
2254
			strlen($this->fl)             > 0 && $qstrparts[] = $this->cgi['prefix']['sys'].'fl'.'='.$this->fl;
2255
			strlen($this->fm)             > 0 && $qstrparts[] = $this->cgi['prefix']['sys'].'fm'.'='.$this->fm;
2256
			count($this->sfn)             > 0 && $qstrparts[] = $this->get_sfn_cgi_vars();
2257
			strlen($this->cgi['persist']) > 0 && $qstrparts[] = $this->cgi['persist'];
2258
			$qpview      = $qstrparts;
2259
			$qpcopy      = $qstrparts;
2260
			$qpchange    = $qstrparts;
2261
			$qpdelete    = $qstrparts;
2262
			$qp_prefix   = $this->cgi['prefix']['sys'].'operation'.'='.$this->cgi['prefix']['operation'];
2263
			$qpview[]    = $qp_prefix.'View';
2264
			$qpcopy[]    = $qp_prefix.'Copy';
2265
			$qpchange[]  = $qp_prefix.'Change';
2266
			$qpdelete[]  = $qp_prefix.'Delete';
2267
			$qpviewStr   = htmlspecialchars($this->page_name.'?'.join('&',$qpview).$this->qfn);
2268
			$qpcopyStr   = htmlspecialchars($this->page_name.'?'.join('&',$qpcopy).$this->qfn);
2269
			$qpchangeStr = htmlspecialchars($this->page_name.'?'.join('&',$qpchange).$this->qfn);
2270
			$qpdeleteStr = htmlspecialchars($this->page_name.'?'.join('&',$qpdelete).$this->qfn);
2271
		}
2272
 
2273
		$fetched  = true;
2274
		$first    = true;
2275
		$rowCount = 0;
2276
		while ((!$fetched && ($row = @mysql_fetch_array($res, MYSQL_ASSOC)) != false)
2277
				|| ($fetched && $row != false)) {
2278
			$fetched = false;
2279
			echo '<tr class="',$this->getCSSclass('row', null, 'next'),'">',"\n";
2280
			if ($sys_cols) { /* {{{ */
2281
				$key_rec     = $row['qf'.$this->key_num];
2282
				$queryAppend = htmlspecialchars('&'.$this->cgi['prefix']['sys'].'rec'.'='.$key_rec);
2283
				$viewQuery   = $qpviewStr   . $queryAppend;
2284
				$copyQuery   = $qpcopyStr   . $queryAppend;
2285
				$changeQuery = $qpchangeStr . $queryAppend;
2286
				$deleteQuery = $qpdeleteStr . $queryAppend;
2287
				$viewTitle   = htmlspecialchars($this->labels['View']);
2288
				$changeTitle = htmlspecialchars($this->labels['Change']);
2289
				$copyTitle   = htmlspecialchars($this->labels['Copy']);
2290
				$deleteTitle = htmlspecialchars($this->labels['Delete']);
2291
				$css_class_name = $this->getCSSclass('navigation', null, true);
2292
				if ($select_recs) {
2293
					if (! $this->nav_buttons() || $sys_cols > 1) {
2294
						echo '<td class="',$css_class_name,'">';
2295
					}
2296
					if ($this->nav_graphic_links()) {
2297
						$printed_out = false;
2298
						if ($this->view_enabled()) {
2299
							$printed_out = true;
2300
							echo '<a class="',$css_class_name,'" href="',$viewQuery,'"><img class="';
2301
							echo $css_class_name,'" src="',$this->url['images'];
2302
							echo 'pme-view.png" height="15" width="16" border="0" ';
2303
							echo 'alt="',$viewTitle,'" title="',$viewTitle,'" /></a>';
2304
						}
2305
						if ($this->change_enabled()) {
2306
							$printed_out && print('&nbsp;');
2307
							$printed_out = true;
2308
							echo '<a class="',$css_class_name,'" href="',$changeQuery,'"><img class="';
2309
							echo $css_class_name,'" src="',$this->url['images'];
2310
							echo 'pme-change.png" height="15" width="16" border="0" ';
2311
							echo 'alt="',$changeTitle,'" title="',$changeTitle,'" /></a>';
2312
						}
2313
						if ($this->copy_enabled()) {
2314
							$printed_out && print('&nbsp;');
2315
							$printed_out = true;
2316
							echo '<a class="',$css_class_name,'" href="',$copyQuery,'"><img class="';
2317
							echo $css_class_name,'" src="',$this->url['images'];
2318
							echo 'pme-copy.png" height="15" width="16" border="0" ';
2319
							echo 'alt="',$copyTitle,'" title="',$copyTitle,'" /></a>';
2320
						}
2321
						if ($this->delete_enabled()) {
2322
							$printed_out && print('&nbsp;');
2323
							$printed_out = true;
2324
							echo '<a class="',$css_class_name,'" href="',$deleteQuery,'"><img class="';
2325
							echo $css_class_name,'" src="',$this->url['images'];
2326
							echo 'pme-delete.png" height="15" width="16" border="0" ';
2327
							echo 'alt="',$deleteTitle,'" title="',$deleteTitle,'" /></a>';
2328
						}
2329
					}
2330
					if ($this->nav_text_links()) {
2331
						if ($this->nav_graphic_links()) {
2332
							echo '<br class="',$css_class_name,'">';
2333
						}
2334
						$printed_out = false;
2335
						if ($this->view_enabled()) {
2336
							$printed_out = true;
2337
							echo '<a href="',$viewQuery,'" title="',$viewTitle,'" class="',$css_class_name,'">V</a>';
2338
						}
2339
						if ($this->change_enabled()) {
2340
							$printed_out && print('&nbsp;');
2341
							$printed_out = true;
2342
							echo '<a href="',$changeQuery,'" title="',$changeTitle,'" class="',$css_class_name,'">C</a>';
2343
						}
2344
						if ($this->copy_enabled()) {
2345
							$printed_out && print('&nbsp;');
2346
							$printed_out = true;
2347
							echo '<a href="',$copyQuery,'" title="',$copyTitle,'" class="',$css_class_name,'">P</a>';
2348
						}
2349
						if ($this->delete_enabled()) {
2350
							$printed_out && print('&nbsp;');
2351
							$printed_out = true;
2352
							echo '<a href="',$deleteQuery,'" title="',$deleteTitle,'" class="',$css_class_name,'">D</a>';
2353
						}
2354
					}
2355
					if (! $this->nav_buttons() || $sys_cols > 1) {
2356
						echo '</td>',"\n";
2357
					}
2358
					if ($this->nav_buttons()) {
2359
						echo '<td class="',$css_class_name,'"><input class="',$css_class_name;
2360
						echo '" type="radio" name="'.$this->cgi['prefix']['sys'].'rec';
2361
						echo '" value="',htmlspecialchars($key_rec),'"';
2362
						if (($this->rec == '' && $first) || ($this->rec == $key_rec)) {
2363
							echo ' checked';
2364
							$first = false;
2365
						}
2366
						echo ' /></td>',"\n";
2367
					}
2368
				} elseif ($this->filter_enabled()) {
2369
					echo '<td class="',$css_class_name,'" colspan=',$sys_cols,'>&nbsp;</td>',"\n";
2370
				}
2371
			} /* }}} */
2372
			for ($k = 0; $k < $this->num_fds; $k++) { /* {{{ */
2373
				$fd = $this->fds[$k];
2374
				if (! $this->displayed[$k]) {
2375
					continue;
2376
				}
2377
				$css_postfix    = @$this->fdd[$k]['css']['postfix'];
2378
				$css_class_name = $this->getCSSclass('cell', null, true, $css_postfix);
2379
				if ($this->password($k)) {
2380
					echo '<td class="',$css_class_name,'">',$this->labels['hidden'],'</td>',"\n";
2381
					continue;
2382
				}
2383
				echo '<td class="',$css_class_name,'"',$this->getColAttributes($fd),'>';
2384
				echo $this->cellDisplay($k, $row, $css_class_name);
2385
				echo '</td>',"\n";
2386
			} /* }}} */
2387
			echo '</tr>',"\n";
2388
		}
2389
 
2390
		/*
2391
		 * Display and accumulate column aggregation info, do totalling query
2392
		 * XXX this feature does not work yet!!!
2393
		 */
2394
		// aggregates listing (if any)
2395
		if ($$var_to_total) {
2396
			// do the aggregate query if necessary
2397
			//if ($vars_to_total) {
2398
				$qp = array();
2399
				$qp['type'] = 'select';
2400
				$qp['select'] = $aggr_from_clause;
2401
				$qp['from']   = $this->get_SQL_join_clause();
2402
				$qp['where']  = $this->get_SQL_where_from_query_opts();
2403
				$tot_query    = $this->get_SQL_query($qp);
2404
				$totals_result = $this->myquery($tot_query,__LINE__);
2405
				$tot_row       = @mysql_fetch_array($totals_result, MYSQL_ASSOC);
2406
			//}
2407
			$qp_aggr = $qp;
2408
			echo "\n",'<tr class="TODO-class">',"\n",'<td class="TODO-class">&nbsp;</td>',"\n";
2409
			/*
2410
			echo '<td>';
2411
			echo printarray($qp_aggr);
2412
			echo printarray($vars_to_total);
2413
			echo '</td>';
2414
			echo '<td colspan="'.($this->num_fds-1).'">'.$var_to_total.' '.$$var_to_total.'</td>';
2415
			*/
2416
			// display the results
2417
			for ($k=0;$k<$this->num_fds;$k++) {
2418
				$fd = $this->fds[$k];
2419
				if (stristr($this->fdd[$fd]['options'],'L') or !isset($this->fdd[$fd]['options'])) {
2420
					echo '<td>';
2421
					$aggr_var  = 'qf'.$k.'_aggr';
2422
					$$aggr_var = $this->get_sys_cgi_var($aggr_var);
2423
					if ($$aggr_var) {
2424
						echo $this->sql_aggrs[$$aggr_var],': ',$tot_row[$aggr_var];
2425
					} else {
2426
						echo '&nbsp;';
2427
					}
2428
					echo '</td>',"\n";
2429
				}
2430
			}
2431
			echo '</tr>',"\n";
2432
		}
2433
		echo '</table>',"\n"; // end of table rows listing
2434
		$this->display_list_table_buttons('down', $listall);
2435
		$this->form_end();
2436
	} /* }}} */
2437
 
2438
	function display_record() /* {{{ */
2439
	{
2440
		// PRE Triggers
2441
		$ret = true;
2442
		if ($this->change_operation()) {
2443
			$ret &= $this->exec_triggers_simple('update', 'pre');
2444
			// if PRE update fails, then back to view operation
2445
			if (! $ret) {
2446
				$this->operation = $this->labels['View'];
2447
				$ret = true;
2448
			}
2449
		}
2450
		if ($this->add_operation() || $this->copy_operation()) {
2451
			$ret &= $this->exec_triggers_simple('insert', 'pre');
2452
		}
2453
		if ($this->view_operation()) {
2454
			$ret &= $this->exec_triggers_simple('select', 'pre');
2455
		}
2456
		if ($this->delete_operation()) {
2457
			$ret &= $this->exec_triggers_simple('delete', 'pre');
2458
		}
2459
		// if PRE insert/view/delete fail, then back to the list
2460
		if ($ret == false) {
2461
			$this->operation = '';
2462
			$this->list_table();
2463
			return;
2464
		}
2465
		$this->form_begin();
2466
		if ($this->cgi['persist'] != '') {
2467
			echo $this->get_origvars_html($this->cgi['persist']);
2468
		}
2469
		echo $this->get_origvars_html($this->get_sfn_cgi_vars());
2470
		echo $this->get_origvars_html($this->qfn);
2471
		echo $this->htmlHiddenSys('cur_tab', $this->dhtml['prefix'].'tab'.$this->cur_tab);
2472
		echo $this->htmlHiddenSys('qfn', $this->qfn);
2473
		echo $this->htmlHiddenSys('rec', $this->copy_operation() ? '' : $this->rec);
2474
		echo $this->htmlHiddenSys('fm', $this->fm);
2475
		echo $this->htmlHiddenSys('fl', $this->fl);
2476
		$this->display_record_buttons('up');
2477
		if ($this->tabs_enabled()) {
2478
			echo '<div id="'.$this->dhtml['prefix'].'tab0">',"\n";
2479
		}
2480
		echo '<table class="',$this->getCSSclass('main'),'" summary="',$this->tb,'">',"\n";
2481
		if ($this->add_operation()) {
2482
			$this->display_add_record();
2483
		} else {
2484
			$this->display_copy_change_delete_record();
2485
		}
2486
		echo '</table>',"\n";
2487
 		if ($this->tabs_enabled()) {
2488
		echo '</div>',"\n";
2489
		}
2490
		$this->display_record_buttons('down');
2491
 
2492
		$this->form_end();
2493
	} /* }}} */
2494
 
2495
	/*
2496
	 * Action functions
2497
	 */
2498
 
2499
	function do_add_record() /* {{{ */
2500
	{
2501
		// Preparing query
2502
		$query       = '';
2503
		$key_col_val = '';
2504
		$newvals     = array();
2505
		for ($k = 0; $k < $this->num_fds; $k++) {
2506
			if ($this->processed($k)) {
2507
				$fd = $this->fds[$k];
2508
				if ($this->readonly($k)) {
2509
					$fn = (string) @$this->fdd[$k]['default'];
2510
				} else {
2511
					$fn = $this->get_data_cgi_var($fd);
2512
				}
2513
				if ($fd == $this->key) {
2514
					$key_col_val = $fn;
2515
				}
2516
				$newvals[$fd] = is_array($fn) ? join(',',$fn) : $fn;
2517
			}
2518
		}
2519
		// Creating array of changed keys ($changed)
2520
		$changed = array_keys($newvals);
2521
		// Before trigger, newvals can be efectively changed
2522
		if ($this->exec_triggers('insert', 'before', $oldvals, $changed, $newvals) == false) {
2523
			return false;
2524
		}
2525
		// Real query (no additional query in this method)
2526
		foreach ($newvals as $fd => $val) {
2527
			if ($fd == '') continue;
2528
			if ($this->col_has_sqlw($this->fdn[$fd])) {
2529
				$val_as  = addslashes($val);
2530
				$val_qas = '"'.addslashes($val).'"';
2531
				$value = $this->substituteVars(
2532
						$this->fdd[$this->fdn[$fd]]['sqlw'], array(
2533
							'val_qas' => $val_qas,
2534
							'val_as'  => $val_as,
2535
							'val'     => $val
2536
							));
2537
			} else {
2538
				$value = "'".addslashes($val)."'";
2539
			}
2540
			if ($query == '') {
2541
				$query = 'INSERT INTO `'.$this->tb.'` (`'.$fd.'`'; // )
2542
				$query2 = ') VALUES ('.$value.'';
2543
			} else {
2544
				$query  .= ', `'.$fd.'`';
2545
				$query2 .= ', '.$value.'';
2546
			}
2547
		}
2548
		$query .= $query2.')';
2549
		$res    = $this->myquery($query, __LINE__);
2550
		$this->message = @mysql_affected_rows($this->dbh).' '.$this->labels['record added'];
2551
		if (! $res) {
2552
			return false;
2553
		}
2554
		$this->rec = mysql_insert_id($this->dbh);
2555
		// Notify list
2556
		if (@$this->notify['insert'] || @$this->notify['all']) {
2557
			$this->email_notify(false, $newvals);
2558
		}
2559
		// Note change in log table
2560
		if ($this->logtable) {
2561
			$query = sprintf('INSERT INTO %s'
2562
					.' (updated, user, host, operation, tab, rowkey, col, oldval, newval)'
2563
					.' VALUES (NOW(), "%s", "%s", "insert", "%s", "%s", "", "", "%s")',
2564
					$this->logtable, addslashes($this->get_server_var('REMOTE_USER')),
2565
					addslashes($this->get_server_var('REMOTE_ADDR')), addslashes($this->tb),
2566
					addslashes($key_col_val), addslashes(serialize($newvals)));
2567
			$this->myquery($query, __LINE__);
2568
		}
2569
		// After trigger
2570
		if ($this->exec_triggers('insert', 'after', $oldvals, $changed, $newvals) == false) {
2571
			return false;
2572
		}
2573
		return true;
2574
	} /* }}} */
2575
 
2576
	function do_change_record() /* {{{ */
2577
	{
2578
		// Preparing queries
2579
		$query_real   = '';
2580
		$query_oldrec = '';
2581
		$newvals      = array();
2582
		$oldvals      = array();
2583
		$changed      = array();
2584
		// Prepare query to retrieve oldvals
2585
		for ($k = 0; $k < $this->num_fds; $k++) {
2586
			if ($this->processed($k) && !$this->readonly($k)) {
2587
				$fd = $this->fds[$k];
2588
				$fn = $this->get_data_cgi_var($fd);
2589
				$newvals[$this->fds[$k]] = is_array($fn) ? join(',',$fn) : $fn;
2590
				if ($query_oldrec == '') {
2591
					$query_oldrec = 'SELECT '.$fd;
2592
				} else {
2593
					$query_oldrec .= ','.$fd;
2594
				}
2595
			}
2596
		}
2597
		$where_part = " WHERE (".$this->key.'='.$this->key_delim.$this->rec.$this->key_delim.')';
2598
		$query_newrec  = $query_oldrec.' FROM ' . $this->tb;
2599
		$query_oldrec .= ' FROM ' . $this->tb . $where_part;
2600
		// Additional query (must go before real query)
2601
		$res     = $this->myquery($query_oldrec, __LINE__);
2602
		$oldvals = @mysql_fetch_array($res, MYSQL_ASSOC);
2603
		@mysql_free_result($res);
2604
		// Creating array of changed keys ($changed)
2605
		foreach ($newvals as $fd => $value) {
2606
			if ($value != $oldvals[$fd])
2607
				$changed[] = $fd;
2608
		}
2609
		// Before trigger
2610
		if ($this->exec_triggers('update', 'before', $oldvals, $changed, $newvals) == false) {
2611
			return false;
2612
		}
2613
		// Build the real query respecting changes to the newvals array
2614
		foreach ($newvals as $fd => $val) {
2615
			if ($fd == '') continue;
2616
			if ($this->col_has_sqlw($this->fdn[$fd])) {
2617
				$val_as  = addslashes($val);
2618
				$val_qas = '"'.addslashes($val).'"';
2619
				$value = $this->substituteVars(
2620
						$this->fdd[$this->fdn[$fd]]['sqlw'], array(
2621
							'val_qas' => $val_qas,
2622
							'val_as'  => $val_as,
2623
							'val'     => $val
2624
							));
2625
			} else {
2626
				$value = "'".addslashes($val)."'";
2627
			}
2628
			if ($query_real == '') {
2629
				$query_real   = 'UPDATE '.$this->tb.' SET '.$fd.'='.$value;
2630
			} else {
2631
				$query_real   .= ','.$fd.'='.$value;
2632
			}
2633
		}
2634
		$query_real .= $where_part;
2635
		// Real query
2636
		$res = $this->myquery($query_real, __LINE__);
2637
		$this->message = @mysql_affected_rows($this->dbh).' '.$this->labels['record changed'];
2638
		if (! $res) {
2639
			return false;
2640
		}
2641
		// Another additional query (must go after real query)
2642
		if (in_array($this->key, $changed)) {
2643
			$this->rec = $newvals[$this->key]; // key has changed
2644
		}
2645
		$query_newrec .= ' WHERE ('.$this->key.'='.$this->key_delim.$this->rec.$this->key_delim.')';
2646
		$res     = $this->myquery($query_newrec, __LINE__);
2647
		$newvals = @mysql_fetch_array($res, MYSQL_ASSOC);
2648
		@mysql_free_result($res);
2649
		// Creating array of changed keys ($changed)
2650
		$changed = array();
2651
		foreach ($newvals as $fd => $value) {
2652
			if ($value != $oldvals[$fd])
2653
				$changed[] = $fd;
2654
		}
2655
		// Notify list
2656
		if (@$this->notify['update'] || @$this->notify['all']) {
2657
			if (count($changed) > 0) {
2658
				$this->email_notify($oldvals, $newvals);
2659
			}
2660
		}
2661
		// Note change in log table
2662
		if ($this->logtable) {
2663
			foreach ($changed as $key) {
2664
				$qry = sprintf('INSERT INTO %s'
2665
						.' (updated, user, host, operation, tab, rowkey, col, oldval, newval)'
2666
						.' VALUES (NOW(), "%s", "%s", "update", "%s", "%s", "%s", "%s", "%s")',
2667
						$this->logtable, addslashes($this->get_server_var('REMOTE_USER')),
2668
						addslashes($this->get_server_var('REMOTE_ADDR')), addslashes($this->tb),
2669
						addslashes($this->rec), addslashes($key),
2670
						addslashes($oldvals[$key]), addslashes($newvals[$key]));
2671
				$this->myquery($qry, __LINE__);
2672
			}
2673
		}
2674
		// After trigger
2675
		if ($this->exec_triggers('update', 'after', $oldvals, $changed, $newvals) == false) {
2676
			return false;
2677
		}
2678
		return true;
2679
	} /* }}} */
2680
 
2681
	function do_delete_record() /* {{{ */
2682
	{
2683
		// Additional query
2684
		$query   = 'SELECT * FROM '.$this->tb.' WHERE ('.$this->key.' = '
2685
				.$this->key_delim.$this->rec.$this->key_delim.')'; // )
2686
		$res     = $this->myquery($query, __LINE__);
2687
		$oldvals = @mysql_fetch_array($res, MYSQL_ASSOC);
2688
		@mysql_free_result($res);
2689
		// Creating array of changed keys ($changed)
2690
		$changed = array_keys($oldvals);
2691
		$newvals = array();
2692
		// Before trigger
2693
		if ($this->exec_triggers('delete', 'before', $oldvals, $changed, $newvals) == false) {
2694
			return false;
2695
		}
2696
		// Real query
2697
		$query = 'DELETE FROM '.$this->tb.' WHERE ('.$this->key.' = '
2698
				.$this->key_delim.$this->rec.$this->key_delim.')'; // )
2699
		$res = $this->myquery($query, __LINE__);
2700
		$this->message = @mysql_affected_rows($this->dbh).' '.$this->labels['record deleted'];
2701
		if (! $res) {
2702
			return false;
2703
		}
2704
		// Notify list
2705
		if (@$this->notify['delete'] || @$this->notify['all']) {
2706
			$this->email_notify($oldvals, false);
2707
		}
2708
		// Note change in log table
2709
		if ($this->logtable) {
2710
			$query = sprintf('INSERT INTO %s'
2711
					.' (updated, user, host, operation, tab, rowkey, col, oldval, newval)'
2712
					.' VALUES (NOW(), "%s", "%s", "delete", "%s", "%s", "%s", "%s", "")',
2713
					$this->logtable, addslashes($this->get_server_var('REMOTE_USER')),
2714
					addslashes($this->get_server_var('REMOTE_ADDR')), addslashes($this->tb),
2715
					addslashes($this->rec), addslashes($key), addslashes(serialize($oldvals)));
2716
			$this->myquery($query, __LINE__);
2717
		}
2718
		// After trigger
2719
		if ($this->exec_triggers('delete', 'after', $oldvals, $changed, $newvals) == false) {
2720
			return false;
2721
		}
2722
		return true;
2723
	} /* }}} */
2724
 
2725
	function email_notify($old_vals, $new_vals) /* {{{ */
2726
	{
2727
		if (! function_exists('mail')) {
2728
			return false;
2729
		}
2730
		if ($old_vals != false && $new_vals != false) {
2731
			$action  = 'update';
2732
			$subject = 'Record updated in';
2733
			$body    = 'An item with '.$this->fdd[$this->key]['name'].' = '
2734
				.$this->key_delim.$this->rec.$this->key_delim .' was updated in';
2735
			$vals    = $new_vals;
2736
		} elseif ($new_vals != false) {
2737
			$action  = 'insert';
2738
			$subject = 'Record added to';
2739
			$body    = 'A new item was added into';
2740
			$vals    = $new_vals;
2741
		} elseif ($old_vals != false) {
2742
			$action  = 'delete';
2743
			$subject = 'Record deleted from';
2744
			$body    = 'An item was deleted from';
2745
			$vals    = $old_vals;
2746
		} else {
2747
			return false;
2748
		}
2749
		$addr  = $this->get_server_var('REMOTE_ADDR');
2750
		$user  = $this->get_server_var('REMOTE_USER');
2751
		$body  = 'This notification e-mail was automatically generated by phpMyEdit.'."\n\n".$body;
2752
		$body .= ' table '.$this->tb.' in MySQL database '.$this->db.' on '.$this->page_name;
2753
		$body .= ' by '.($user == '' ? 'unknown user' : "user $user").' from '.$addr;
2754
		$body .= ' at '.date('d/M/Y H:i').' with the following fields:'."\n\n";
2755
		$i = 1;
2756
		foreach ($vals as $k => $text) {
2757
			$name = isset($this->fdd[$k]['name~'])
2758
				? $this->fdd[$k]['name~'] : $this->fdd[$k]['name'];
2759
			if ($action == 'update') {
2760
				if ($old_vals[$k] == $new_vals[$k]) {
2761
					continue;
2762
				}
2763
				$body .= sprintf("[%02s] %s (%s)\n      WAS: %s\n      IS:  %s\n",
2764
						$i, $name, $k, $old_vals[$k], $new_vals[$k]);
2765
			} else {
2766
				$body .= sprintf('[%02s] %s (%s): %s'."\n", $i, $name, $k, $text);
2767
			}
2768
			$i++;
2769
		}
2770
		$body    .= "\n--\r\n"; // \r is needed for signature separating
2771
		$body    .= "phpMyEdit\ninstant MySQL table editor and code generator\n";
2772
		$body    .= "http://platon.sk/projects/phpMyEdit/\n\n";
2773
		$subject  = @$this->notify['prefix'].$subject.' '.$this->dbp.$this->tb;
2774
		$subject  = trim($subject); // just for sure
2775
		$wrap_w   = intval(@$this->notify['wrap']);
2776
	   	$wrap_w > 0 || $wrap_w = 72;
2777
		$from     = (string) @$this->notify['from'];
2778
		$from != '' || $from = 'webmaster@'.strtolower($this->get_server_var('SERVER_NAME'));
2779
		$headers  = 'From: '.$from."\n".'X-Mailer: PHP/'.phpversion().' (phpMyEdit)';
2780
		$body     = wordwrap($body, $wrap_w, "\n", 1);
2781
		$emails   = (array) $this->notify[$action] + (array) $this->notify['all'];
2782
		foreach ($emails as $email) {
2783
			if (! empty($email)) {
2784
				mail(trim($email), $subject, $body, $headers);
2785
			}
2786
		}
2787
		return true;
2788
	} /* }}} */
2789
 
2790
	/*
2791
	 * Apply triggers function
2792
	 * Run a (set of) trigger(s). $trigger can be an Array or a filename
2793
	 * Break and return false as soon as a trigger return false
2794
	 * we need a reference on $newvals to be able to change value before insert/update
2795
	 */
2796
	function exec_triggers($op, $step, $oldvals, &$changed, &$newvals) /* {{{ */
2797
	{
2798
		if (! isset($this->triggers[$op][$step])) {
2799
			return true;
2800
		}
2801
		$ret  = true;
2802
		$trig = $this->triggers[$op][$step];
2803
		if (is_array($trig)) {
2804
			ksort($trig);
2805
			for ($t = reset($trig); $t !== false && $ret != false; $t = next($trig)) {
2806
				$ret = include($t);
2807
			}
2808
		} else {
2809
			$ret = include($trig);
2810
		}
2811
		return $ret;
2812
	} /* }}} */
2813
 
2814
	function exec_triggers_simple($op, $step) /* {{{ */
2815
	{
2816
		$oldvals = $newvals = $changed = array();
2817
		return $this->exec_triggers($op, $step, $oldvals, $changed, $newvals);
2818
	} /* }}} */
2819
 
2820
	/*
2821
	 * Recreate functions
2822
	 */
2823
	function recreate_fdd($default_page_type = 'L') /* {{{ */
2824
	{
2825
		// TODO: one level deeper browsing
2826
		$this->page_type = $default_page_type;
2827
		$this->filter_operation() && $this->page_type = 'F';
2828
		$this->view_operation()   && $this->page_type = 'V';
2829
		if ($this->add_operation()
2830
				|| $this->saveadd == $this->labels['Save']
2831
				|| $this->moreadd == $this->labels['More']) {
2832
			$this->page_type = 'A';
2833
		}
2834
		if ($this->change_operation()
2835
				|| $this->savechange == $this->labels['Save']
2836
				|| $this->morechange == $this->labels['Apply']) {
2837
			$this->page_type = 'C';
2838
		}
2839
		if ($this->copy_operation() || $this->savecopy == $this->labels['Save']) {
2840
			$this->page_type = 'P';
2841
		}
2842
		if ($this->delete_operation() || $this->savedelete == $this->labels['Delete']) {
2843
			$this->page_type = 'D';
2844
		}
2845
		// Restore backups (if exists)
2846
		foreach (array_keys($this->fdd) as $column) {
2847
			foreach (array_keys($this->fdd[$column]) as $col_option) {
2848
				if ($col_option[strlen($col_option) - 1] != '~')
2849
					continue;
2850
 
2851
				$this->fdd[$column][substr($col_option, 0, strlen($col_option) - 1)]
2852
					= $this->fdd[$column][$col_option];
2853
				unset($this->fdd[$column][$col_option]);
2854
			}
2855
		}
2856
		foreach (array_keys($this->fdd) as $column) {
2857
			foreach (array_keys($this->fdd[$column]) as $col_option) {
2858
				if (! strchr($col_option, '|')) {
2859
					continue;
2860
				}
2861
				$col_ar = explode('|', $col_option, 2);
2862
				if (! stristr($col_ar[1], $this->page_type)) {
2863
					continue;
2864
				}
2865
				// Make field backups
2866
				$this->fdd[$column][$col_ar[0] .'~'] = $this->fdd[$column][$col_ar[0]];
2867
				$this->fdd[$column][$col_option.'~'] = $this->fdd[$column][$col_option];
2868
				// Set particular field
2869
				$this->fdd[$column][$col_ar[0]] = $this->fdd[$column][$col_option];
2870
				unset($this->fdd[$column][$col_option]);
2871
			}
2872
		}
2873
	} /* }}} */
2874
 
2875
	function recreate_displayed() /* {{{ */
2876
	{
2877
		$field_num            = 0;
2878
		$num_fields_displayed = 0;
2879
		$this->fds            = array();
2880
		$this->fdn            = array();
2881
		$this->displayed      = array();
2882
		$this->guidance       = false;
2883
		foreach (array_keys($this->fdd) as $key) {
2884
			if (preg_match('/^\d+$/', $key)) { // skipping numeric keys
2885
				continue;
2886
			}
2887
			$this->fds[$field_num] = $key;
2888
			$this->fdn[$key] = $field_num;
2889
			/* We must use here displayed() function, because displayed[] array
2890
			   is not created yet. We will simultaneously create that array as well. */
2891
			if ($this->displayed[$field_num] = $this->displayed($field_num)) {
2892
				$num_fields_displayed++;
2893
			}
2894
			if (is_array(@$this->fdd[$key]['values']) && ! isset($this->fdd[$key]['values']['table'])) {
2895
				foreach ($this->fdd[$key]['values'] as $val) {
2896
					$this->fdd[$key]['values2'][$val] = $val;
2897
				}
2898
				unset($this->fdd[$key]['values']);
2899
			}
2900
			isset($this->fdd[$key]['help']) && $this->guidance = true;
2901
			$this->fdd[$field_num] = $this->fdd[$key];
2902
			$field_num++;
2903
		}
2904
		$this->num_fds              = $field_num;
2905
		$this->num_fields_displayed = $num_fields_displayed;
2906
		$this->key_num              = array_search($this->key, $this->fds);
2907
		/* Adds first displayed column into sorting fields by replacing last
2908
		   array entry. Also remove duplicite values and change column names to
2909
		   their particular field numbers.
2910
 
2911
		   Note that entries like [0]=>'9' [1]=>'-9' are correct and they will
2912
		   have desirable sorting behaviour. So there is no need to remove them.
2913
		 */
2914
		$this->sfn = array_unique($this->sfn);
2915
		$check_ar = array();
2916
		foreach ($this->sfn as $key => $val) {
2917
			if (preg_match('/^[-]?\d+$/', $val)) { // skipping numeric keys
2918
				$val = abs($val);
2919
				if (in_array($val, $check_ar) || $this->password($val)) {
2920
					unset($this->sfn[$key]);
2921
				} else {
2922
					$check_ar[] = $val;
2923
				}
2924
				continue;
2925
			}
2926
			if ($val[0] == '-') {
2927
				$val = substr($val, 1);
2928
				$minus = '-';
2929
			} else {
2930
				$minus = '';
2931
			}
2932
			if (($val = array_search($val, $this->fds)) === false || $this->password($val)) {
2933
				unset($this->sfn[$key]);
2934
			} else {
2935
				$val = intval($val);
2936
				if (in_array($val, $check_ar)) {
2937
					unset($this->sfn[$key]);
2938
				} else {
2939
					$this->sfn[$key] = $minus.$val;
2940
					$check_ar[] = $val;
2941
				}
2942
			}
2943
		}
2944
		$this->sfn = array_unique($this->sfn);
2945
		return true;
2946
	} /* }}} */
2947
 
2948
	function backward_compatibility() /* {{{ */
2949
	{
2950
		foreach (array_keys($this->fdd) as $column) {
2951
			// move ['required'] to ['js']['required']
2952
			if (! isset($this->fdd[$column]['js']['required']) && isset($this->fdd[$column]['required'])) {
2953
				$this->fdd[$column]['js']['required'] = $this->fdd[$column]['required'];
2954
			}
2955
			// move 'HWR' flags from ['options'] into ['input']
2956
			if (isset($this->fdd[$column]['options'])) {
2957
				stristr($this->fdd[$column]['options'], 'H') && $this->fdd[$column]['input'] .= 'H';
2958
				stristr($this->fdd[$column]['options'], 'W') && $this->fdd[$column]['input'] .= 'W';
2959
				stristr($this->fdd[$column]['options'], 'R') && $this->fdd[$column]['input'] .= 'R';
2960
			}
2961
		}
2962
	} /* }}} */
2963
 
2964
	/*
2965
	 * Error handling function
2966
	 */
2967
	function error($message, $additional_info = '') /* {{{ */
2968
	{
2969
		echo '<h1>phpMyEdit error: ',htmlspecialchars($message),'</h1>',"\n";
2970
		if ($additional_info != '') {
2971
			echo '<hr />',htmlspecialchars($additional_info);
2972
		}
2973
		return false;
2974
	} /* }}} */
2975
 
2976
	/*
2977
	 * Database connection function
2978
	 */
2979
	function connect() /* {{{ */
2980
	{
2981
		if (isset($this->dbh)) {
2982
			return true;
2983
		}
2984
		if (!isset($this->db)) {
2985
			$this->error('no database defined');
2986
			return false;
2987
		}
2988
		if (!isset ($this->tb)) {
2989
			$this->error('no table defined');
2990
			return false;
2991
		}
2992
		$this->dbh = @ini_get('allow_persistent')
2993
			? @mysql_pconnect($this->hn, $this->un, $this->pw)
2994
			: @mysql_connect($this->hn, $this->un, $this->pw);
2995
		if (!$this->dbh) {
2996
			$this->error('could not connect to MySQL');
2997
			return false;
2998
		}
2999
		return true;
3000
	} /* }}} */
3001
 
3002
	/*
3003
	 * Database disconnection function
3004
	 */
3005
	function disconnect() /* {{{ */
3006
	{
3007
		if ($this->close_dbh) {
3008
			@mysql_close($this->dbh);
3009
			$this->dbh = null;
3010
		}
3011
	} /* }}} */
3012
 
3013
	/*
3014
	 * The workhorse
3015
	 */
3016
	function execute() /* {{{ */
3017
	{
3018
		//  DEBUG -  uncomment to enable
3019
		/*
3020
		//phpinfo();
3021
		$this->print_get_vars();
3022
		$this->print_post_vars();
3023
		$this->print_vars();
3024
		echo "<pre>query opts:\n";
3025
		echo print_r($this->query_opts);
3026
		echo "</pre>\n";
3027
		echo "<pre>get vars:\n";
3028
		echo print_r($this->get_opts);
3029
		echo "</pre>\n";
3030
		 */
3031
 
3032
		// Let's do explicit quoting - it's safer
3033
		set_magic_quotes_runtime(0);
3034
		// Checking if language file inclusion was successful
3035
		if (! is_array($this->labels)) {
3036
			$this->error('could not locate language files', 'searched path: '.$this->dir['lang']);
3037
			return false;
3038
		}
3039
		// Database connection
3040
		if ($this->connect() == false) {
3041
			return false;
3042
		}
3043
 
3044
		/*
3045
		 * ======================================================================
3046
		 * Pass 3: process any updates generated if the user has selected
3047
		 * a save or cancel button during Pass 2
3048
		 * ======================================================================
3049
		 */
3050
		// Cancel button - Cancel Triggers
3051
		if ($this->add_canceled() || $this->copy_canceled()) {
3052
			$this->exec_triggers_simple('insert', 'cancel');
3053
		}
3054
		if ($this->view_canceled()) {
3055
			$this->exec_triggers_simple('select', 'cancel');
3056
		}
3057
		if ($this->change_canceled()) {
3058
			$this->exec_triggers_simple('update', 'cancel');
3059
		}
3060
		if ($this->delete_canceled()) {
3061
			$this->exec_triggers_simple('delete', 'cancel');
3062
		}
3063
		// Save/More Button - database operations
3064
		if ($this->saveadd == $this->labels['Save'] || $this->savecopy == $this->labels['Save']) {
3065
			$this->add_enabled() && $this->do_add_record();
3066
			unset($this->saveadd);
3067
			unset($this->savecopy);
3068
			$this->recreate_fdd();
3069
		}
3070
		elseif ($this->moreadd == $this->labels['More']) {
3071
			$this->add_enabled() && $this->do_add_record();
3072
			$this->operation = $this->labels['Add']; // to force add operation
3073
			$this->recreate_fdd();
3074
			$this->recreate_displayed();
3075
			$this->backward_compatibility();
3076
		}
3077
		elseif ($this->savechange == $this->labels['Save']) {
3078
			$this->change_enabled() && $this->do_change_record();
3079
			unset($this->savechange);
3080
			$this->recreate_fdd();
3081
		}
3082
		elseif ($this->morechange == $this->labels['Apply']) {
3083
			$this->change_enabled() && $this->do_change_record();
3084
			$this->operation = $this->labels['Change']; // to force change operation
3085
			$this->recreate_fdd();
3086
			$this->recreate_displayed();
3087
			$this->backward_compatibility();
3088
		}
3089
		elseif ($this->savedelete == $this->labels['Delete']) {
3090
			$this->delete_enabled() && $this->do_delete_record();
3091
			unset($this->savedelete);
3092
			$this->recreate_fdd();
3093
		}
3094
 
3095
		/*
3096
		 * ======================================================================
3097
		 * Pass 2: display an input/edit/confirmation screen if the user has
3098
		 * selected an editing button on Pass 1 through this page
3099
		 * ======================================================================
3100
		 */
3101
		if ($this->add_operation()
3102
				|| $this->change_operation() || $this->delete_operation()
3103
				|| $this->view_operation()   || $this->copy_operation()) {
3104
			$this->display_record();
3105
		}
3106
 
3107
		/*
3108
		 * ======================================================================
3109
		 * Pass 1 and Pass 3: display the MySQL table in a scrolling window on
3110
		 * the screen (skip this step in 'Add More' mode)
3111
		 * ======================================================================
3112
		 */
3113
		else {
3114
			$this->list_table();
3115
		}
3116
 
3117
		$this->disconnect();
3118
		if ($this->display['time'] && $this->timer != null) {
3119
			echo $this->timer->end(),' miliseconds';
3120
		}
3121
	} /* }}} */
3122
 
3123
	/*
3124
	 * Class constructor
3125
	 */
3126
	function phpMyEdit($opts) /* {{{ */
3127
	{
3128
		// Set desirable error reporting level
3129
		$error_reporting = error_reporting(E_ALL & ~E_NOTICE);
3130
		// Database handle variables
3131
		if (isset($opts['dbh'])) {
3132
			$this->close_dbh = false;
3133
			$this->dbh = $opts['dbh'];
3134
			$this->dbp = '';
3135
		} else {
3136
			$this->close_dbh = true;
3137
			$this->dbh = null;
3138
			$this->dbp = $opts['db'].'.';
3139
			$this->hn  = $opts['hn'];
3140
			$this->un  = $opts['un'];
3141
			$this->pw  = $opts['pw'];
3142
			$this->db  = $opts['db'];
3143
		}
3144
		$this->tb  = $opts['tb'];
3145
		// Other variables
3146
		$this->key       = $opts['key'];
3147
		$this->key_type  = $opts['key_type'];
3148
		$this->inc       = $opts['inc'];
3149
		$this->options   = $opts['options'];
3150
		$this->fdd       = $opts['fdd'];
3151
		$this->multiple  = intval($opts['multiple']);
3152
		$this->multiple <= 0 && $this->multiple = 2;
3153
		$this->filters   = @$opts['filters'];
3154
		$this->triggers  = @$opts['triggers'];
3155
		$this->notify    = @$opts['notify'];
3156
		$this->logtable  = @$opts['logtable'];
3157
		$this->page_name = @$opts['page_name'];
3158
		if (! isset($this->page_name)) {
3159
			$this->page_name = basename($this->get_server_var('PHP_SELF'));
3160
			isset($this->page_name) || $this->page_name = $this->tb;
3161
		}
3162
		$this->display['query'] = @$opts['display']['query'];
3163
		$this->display['sort']  = @$opts['display']['sort'];
3164
		$this->display['time']  = @$opts['display']['time'];
3165
		if ($this->display['time']) {
3166
			$this->timer = new phpMyEdit_timer();
3167
		}
3168
		$this->display['tabs'] = isset($opts['display']['tabs'])
3169
			? $opts['display']['tabs'] : true;
3170
		$this->display['form'] = isset($opts['display']['form'])
3171
			? $opts['display']['form'] : true;
3172
		$this->display['num_records'] = isset($opts['display']['num_records'])
3173
			? $opts['display']['num_records'] : true;
3174
		$this->display['num_pages'] = isset($opts['display']['num_pages'])
3175
			? $opts['display']['num_pages'] : true;
3176
		// Creating directory variables
3177
		$this->dir['root'] = dirname(realpath(__FILE__))
3178
			. (strlen(dirname(realpath(__FILE__))) > 0 ? '/' : '');
3179
		$this->dir['lang'] = $this->dir['root'].'lang/';
3180
		// Creating URL variables
3181
		$this->url['images'] = 'images/';
3182
		isset($opts['url']['images']) && $this->url['images'] = $opts['url']['images'];
3183
		// CSS classes policy
3184
		$this->css = @$opts['css'];
3185
		!isset($this->css['separator']) && $this->css['separator'] = '-';
3186
		!isset($this->css['prefix'])    && $this->css['prefix']    = 'pme';
3187
		!isset($this->css['page_type']) && $this->css['page_type'] = false;
3188
		!isset($this->css['position'])  && $this->css['position']  = false;
3189
		!isset($this->css['divider'])   && $this->css['divider']   = 2;
3190
		$this->css['divider'] = intval(@$this->css['divider']);
3191
		// JS overall configuration
3192
		$this->js = @$opts['js'];
3193
		!isset($this->js['prefix']) && $this->js['prefix'] = 'PME_js_';
3194
		// DHTML overall configuration
3195
		$this->dhtml = @$opts['dhtml'];
3196
		!isset($this->dhtml['prefix']) && $this->dhtml['prefix'] = 'PME_dhtml_';
3197
		// Navigation
3198
		$this->navigation = @$opts['navigation'];
3199
		if (! $this->nav_buttons() && ! $this->nav_text_links() && ! $this->nav_graphic_links()) {
3200
			$this->navigation .= 'B'; // buttons are default
3201
		}
3202
		if (! $this->nav_up() && ! $this->nav_down()) {
3203
			$this->navigation .= 'D'; // down position is default
3204
		}
3205
		$this->buttons = $opts['buttons'];
3206
		// Language labels (must go after navigation)
3207
		$this->labels = $this->make_language_labels(isset($opts['language'])
3208
				? $opts['language'] : $this->get_server_var('HTTP_ACCEPT_LANGUAGE'));
3209
		// CGI variables
3210
		$this->cgi = @$opts['cgi'];
3211
		$this->cgi['persist'] = '';
3212
		if (@is_array($opts['cgi']['persist'])) {
3213
			foreach ($opts['cgi']['persist'] as $key => $val) {
3214
				if (is_array($val)) {
3215
					foreach($val as $key2 => $val2) {
3216
						$this->cgi['persist'] .= '&'.rawurlencode($key)
3217
							.'['.rawurlencode($key2).']='.rawurlencode($val2);
3218
					}
3219
				} else {
3220
					$this->cgi['persist'] .= '&'.rawurlencode($key).'='.rawurlencode($val);
3221
				}
3222
			}
3223
		}
3224
		foreach (array('operation', 'sys', 'data') as $type) {
3225
			if (! isset($this->cgi['prefix'][$type])) {
3226
				$this->cgi['prefix'][$type] = $this->get_default_cgi_prefix($type);
3227
			}
3228
		}
3229
		// Sorting variables
3230
		$this->sfn   = $this->get_sys_cgi_var('sfn');
3231
		isset($this->sfn)             || $this->sfn          = array();
3232
		is_array($this->sfn)          || $this->sfn          = array($this->sfn);
3233
		isset($opts['sort_field'])    || $opts['sort_field'] = array();
3234
		is_array($opts['sort_field']) || $opts['sort_field'] = array($opts['sort_field']);
3235
		$this->sfn   = array_merge($this->sfn, $opts['sort_field']);
3236
		// Form variables all around
3237
		$this->fl    = intval($this->get_sys_cgi_var('fl'));
3238
		$this->fm    = intval($this->get_sys_cgi_var('fm'));
3239
//		$old_page = ceil($this->fm / abs($this->inc)) + 1;
3240
		$this->qfn   = $this->get_sys_cgi_var('qfn');
3241
		$this->sw    = $this->get_sys_cgi_var('sw');
3242
		$this->rec   = $this->get_sys_cgi_var('rec', '');
3243
		$this->navop = $this->get_sys_cgi_var('navop');
3244
		$navfmup     = $this->get_sys_cgi_var('navfmup');
3245
		$navfmdown   = $this->get_sys_cgi_var('navfmdown');
3246
		$navpnup     = $this->get_sys_cgi_var('navpnup');
3247
		$navpndown   = $this->get_sys_cgi_var('navpndown');
3248
		if($navfmdown!=NULL && $navfmdown != $this->fm) $this->navfm = $navfmdown;
3249
		elseif($navfmup!=NULL && $navfmup != $this->fm) $this->navfm = $navfmup;
3250
		elseif($navpndown!=NULL && ($navpndown-1)*$this->inc != $this->fm) $this->navfm = ($navpndown-1)*$this->inc;
3251
		elseif($navpnup!=NULL && ($navpnup-1)*$this->inc != $this->fm) $this->navfm = ($navpnup-1)*$this->inc;
3252
		else $this->navfm = $this->fm;
3253
		$this->operation = $this->get_sys_cgi_var('operation');
3254
		$oper_prefix_len = strlen($this->cgi['prefix']['operation']);
3255
		if (! strncmp($this->cgi['prefix']['operation'], $this->operation, $oper_prefix_len)) {
3256
			$this->operation = $this->labels[substr($this->operation, $oper_prefix_len)];
3257
		}
3258
		$this->saveadd      = $this->get_sys_cgi_var('saveadd');
3259
		$this->moreadd      = $this->get_sys_cgi_var('moreadd');
3260
		$this->canceladd    = $this->get_sys_cgi_var('canceladd');
3261
		$this->savechange   = $this->get_sys_cgi_var('savechange');
3262
		$this->morechange   = $this->get_sys_cgi_var('morechange');
3263
		$this->cancelchange = $this->get_sys_cgi_var('cancelchange');
3264
		$this->savecopy     = $this->get_sys_cgi_var('savecopy');
3265
		$this->cancelcopy   = $this->get_sys_cgi_var('cancelcopy');
3266
		$this->savedelete   = $this->get_sys_cgi_var('savedelete');
3267
		$this->canceldelete = $this->get_sys_cgi_var('canceldelete');
3268
		$this->cancelview   = $this->get_sys_cgi_var('cancelview');
3269
		// Filter setting
3270
		if (isset($this->sw)) {
3271
			$this->sw == $this->labels['Search'] && $this->fl = 1;
3272
			$this->sw == $this->labels['Hide']   && $this->fl = 0;
3273
			//$this->sw == $this->labels['Clear']  && $this->fl = 0;
3274
		}
3275
		// TAB names
3276
		$this->tabs = array();
3277
		// Setting key_delim according to key_type
3278
		if ($this->key_type == 'real') {
3279
			/* If 'real' key_type does not work,
3280
			   try change MySQL datatype from float to double */
3281
			$this->rec = doubleval($this->rec);
3282
			$this->key_delim = '';
3283
		} elseif ($this->key_type == 'int') {
3284
			$this->rec = intval($this->rec);
3285
			$this->key_delim = '';
3286
		} else {
3287
			$this->key_delim = '"';
3288
			// $this->rec remains unmodified
3289
		}
3290
		// Specific $fdd modifications depending on performed action
3291
		$this->recreate_fdd();
3292
		// Extract SQL Field Names and number of fields
3293
		$this->recreate_displayed();
3294
		// Issue backward compatibility
3295
		$this->backward_compatibility();
3296
		// Gathering query options
3297
		$this->gather_query_opts();
3298
		// Call to action
3299
		!isset($opts['execute']) && $opts['execute'] = 1;
3300
		$opts['execute'] && $this->execute();
3301
		// Restore original error reporting level
3302
		error_reporting($error_reporting);
3303
	} /* }}} */
3304
 
3305
}
3306
 
3307
/* Modeline for ViM {{{
3308
 * vim:set ts=4:
3309
 * vim600:fdm=marker fdl=0 fdc=0:
3310
 * }}} */
3311
 
3312
?>