Projekt

Obecné

Profil

Stáhnout (51 KB) Statistiky
| Větev: | Tag: | Revize:
1
<?php
2
	/**
3
	 * Class to hold various commonly used functions
4
	 *
5
	 * $Id: Misc.php,v 1.113.2.3 2005/11/19 09:17:23 chriskl Exp $
6
	 */
7
	 
8
	class Misc {
9
		// Tracking string to include in HREFs 
10
		var $href;
11
		// Tracking string to include in forms
12
		var $form;
13
		
14
		/* Constructor */
15
		function Misc() {
16
		}
17

    
18
		/** 
19
		 * Checks if dumps are properly set up
20
		 * @param $all (optional) True to check pg_dumpall, false to just check pg_dump
21
		 * @return True, dumps are set up, false otherwise
22
		 */
23
		function isDumpEnabled($all = false) {
24
			$info = $this->getServerInfo();
25
			return !empty($info[$all ? 'pg_dumpall_path' : 'pg_dump_path']);
26
		}
27

    
28
		/**
29
		 * Sets the href tracking variable
30
		 */
31
		function setHREF() {
32
			$this->href = $this->getHREF();
33
		}
34
		
35
		/**
36
		 * Get a href query string, excluding objects below the given object type (inclusive)
37
		 */
38
		function getHREF($exclude_from = null) {
39
			$href = '';
40
			if (isset($_REQUEST['server']) && $exclude_from != 'server') {
41
				$href .= 'server=' . urlencode($_REQUEST['server']);
42
				if (isset($_REQUEST['database']) && $exclude_from != 'database') {
43
					$href .= '&amp;database=' . urlencode($_REQUEST['database']);
44
					if (isset($_REQUEST['schema']) && $exclude_from != 'schema') {
45
						$href .= '&amp;schema=' . urlencode($_REQUEST['schema']);
46
					}
47
				}
48
			}
49
			return $href;
50
		}
51

    
52
		/**
53
		 * Sets the form tracking variable
54
		 */
55
		function setForm() {
56
			$this->form = '';
57
			if (isset($_REQUEST['server'])) {
58
				$this->form .= "<input type=\"hidden\" name=\"server\" value=\"" . htmlspecialchars($_REQUEST['server']) . "\" />\n";
59
				if (isset($_REQUEST['database'])) {
60
					$this->form .= "<input type=\"hidden\" name=\"database\" value=\"" . htmlspecialchars($_REQUEST['database']) . "\" />\n";
61
					if (isset($_REQUEST['schema'])) {
62
						$this->form .= "<input type=\"hidden\" name=\"schema\" value=\"" . htmlspecialchars($_REQUEST['schema']) . "\" />\n";
63
					}
64
				}
65
			}
66
		}
67

    
68
		/**
69
		 * Render a value into HTML using formatting rules specified
70
		 * by a type name and parameters.
71
		 *
72
		 * @param $str The string to change
73
		 *
74
		 * @param $type Field type (optional), this may be an internal PostgreSQL type, or:
75
		 *			yesno    - same as bool, but renders as 'Yes' or 'No'.
76
		 *			pre      - render in a <pre> block.
77
		 *			nbsp     - replace all spaces with &nbsp;'s
78
		 *			verbatim - render exactly as supplied, no escaping what-so-ever.
79
		 *			callback - render using a callback function supplied in the 'function' param.
80
		 *
81
		 * @param $params Type parameters (optional), known parameters:
82
		 *			null     - string to display if $str is null, or set to TRUE to use a default 'NULL' string,
83
		 *			           otherwise nothing is rendered.
84
		 *			clip     - if true, clip the value to a fixed length, and append an ellipsis...
85
		 *			cliplen  - the maximum length when clip is enabled (defaults to $conf['max_chars'])
86
		 *			ellipsis - the string to append to a clipped value (defaults to $lang['strellipsis'])
87
		 *			tag      - an HTML element name to surround the value.
88
		 *			class    - a class attribute to apply to any surrounding HTML element.
89
		 *			align    - an align attribute ('left','right','center' etc.)
90
		 *			true     - (type='bool') the representation of true.
91
		 *			false    - (type='bool') the representation of false.
92
		 *			function - (type='callback') a function name, accepts args ($str, $params) and returns a rendering.
93
		 *			lineno   - prefix each line with a line number.
94
		 *			map      - an associative array.
95
		 *
96
		 * @return The HTML rendered value
97
		 */
98
		function printVal($str, $type = null, $params = array()) {
99
			global $lang, $conf, $data;
100
			
101
			// Shortcircuit for a NULL value
102
			if (is_null($str))
103
				return isset($params['null'])
104
						? ($params['null'] === true ? '<i>NULL</i>' : $params['null'])
105
						: '';
106
			
107
			if (isset($params['map']) && isset($params['map'][$str])) $str = $params['map'][$str];
108
			
109
			// Clip the value if the 'clip' parameter is true.
110
			if (isset($params['clip']) && $params['clip'] === true) {
111
				$maxlen = isset($params['cliplen']) && is_integer($params['cliplen']) ? $params['cliplen'] : $conf['max_chars'];
112
				$ellipsis = isset($params['ellipsis']) ? $params['ellipsis'] : $lang['strellipsis'];
113
				if (strlen($str) > $maxlen) {
114
					$str = substr($str, 0, $maxlen-1) . $ellipsis;
115
				}
116
			}
117

    
118
			$out = '';
119
			
120
			switch ($type) {
121
				case 'int2':
122
				case 'int4':
123
				case 'int8':
124
				case 'float4':
125
				case 'float8':
126
				case 'money':
127
				case 'numeric':
128
				case 'oid':
129
				case 'xid':
130
				case 'cid':
131
				case 'tid':
132
					$align = 'right';
133
					$out = nl2br(htmlspecialchars($str));
134
					break;
135
				case 'yesno':
136
					if (!isset($params['true'])) $params['true'] = $lang['stryes'];
137
					if (!isset($params['false'])) $params['false'] = $lang['strno'];
138
					// No break - fall through to boolean case.
139
				case 'bool':
140
				case 'boolean':
141
					if (is_bool($str)) $str = $str ? 't' : 'f';
142
					switch ($str) {
143
						case 't':
144
							$out = (isset($params['true']) ? $params['true'] : $lang['strtrue']);
145
							$align = 'center';
146
							break;
147
						case 'f':
148
							$out = (isset($params['false']) ? $params['false'] : $lang['strfalse']);
149
							$align = 'center';
150
							break;
151
						default:
152
							$out = htmlspecialchars($str);
153
					}
154
					break;
155
				case 'bytea':
156
					$out = $data->escapeBytea($str);
157
					break;
158
				case 'pre':
159
					$tag = 'pre';
160
					$out = htmlspecialchars($str);
161
					break;
162
				case 'prenoescape':
163
					$tag = 'pre';
164
					$out = $str;
165
					break;
166
				case 'nbsp':
167
					$out = nl2br(str_replace(' ', '&nbsp;', htmlspecialchars($str)));
168
					break;
169
				case 'verbatim':
170
					$out = $str;
171
					break;
172
				case 'callback':
173
					$out = $params['function']($str, $params);
174
					break;
175
				default:
176
					// If the string contains at least one instance of >1 space in a row, a tab
177
					// character, a space at the start of a line, or a space at the start of
178
					// the whole string then render within a pre-formatted element (<pre>).
179
					if (preg_match('/(^ |  |\t|\n )/m', $str)) {
180
						$tag = 'pre';
181
						$class = 'data';
182
						$out = htmlspecialchars($str);
183
					} else {
184
						$out = nl2br(htmlspecialchars($str));
185
					}
186
			}
187
			
188
			if (isset($params['class'])) $class = $params['class'];
189
			if (isset($params['align'])) $align = $params['align'];
190
			
191
			if (!isset($tag) && (isset($class) || isset($align))) $tag = 'div';
192
			
193
			if (isset($tag)) {
194
				$alignattr = isset($align) ? " align=\"{$align}\"" : '';
195
				$classattr = isset($class) ? " class=\"{$class}\"" : '';				
196
				$out = "<{$tag}{$alignattr}{$classattr}>{$out}</{$tag}>";
197
			}
198

    
199
			// Add line numbers if 'lineno' param is true
200
			if (isset($params['lineno']) && $params['lineno'] === true) {
201
				$lines = explode("\n", $str);
202
				$num = count($lines);
203
				if ($num > 0) {
204
					$temp = "<table>\n<tr><td class=\"{$class}\" style=\"vertical-align: top; padding-right: 10px;\"><pre class=\"{$class}\">";
205
					for ($i = 1; $i <= $num; $i++) {
206
						$temp .= $i . "\n";
207
					}
208
					$temp .= "</pre></td><td class=\"{$class}\" style=\"vertical-align: top;\">{$out}</td></tr></table>\n";
209
					$out = $temp;
210
				}
211
				unset($lines);
212
			}
213

    
214
			return $out;
215
		}
216

    
217
		/**
218
		 * A function to recursively strip slashes.  Used to
219
		 * enforce magic_quotes_gpc being off.
220
		 * @param &var The variable to strip
221
		 */
222
		function stripVar(&$var) {
223
			if (is_array($var)) {
224
				foreach($var as $k => $v) {
225
					$this->stripVar($var[$k]);
226
				}		
227
			}
228
			else
229
				$var = stripslashes($var);	
230
		}
231
		
232
		/**
233
		 * Print out the page heading and help link
234
		 * @param $title Title, already escaped
235
		 * @param $help (optional) The identifier for the help link
236
		 */
237
		function printTitle($title, $help = null) {
238
			global $data, $lang;
239
			
240
			echo "<h2>";
241
			$this->printHelp($title, $help);
242
			echo "</h2>\n";
243
		}
244
		
245
		/**
246
		 * Print out a message
247
		 * @param $msg The message to print
248
		 */
249
		function printMsg($msg) {
250
			if ($msg != '') echo "<p class=\"message\">{$msg}</p>\n";
251
		}
252

    
253
		/**
254
		 * Creates a database accessor
255
		 */
256
		function getDatabaseAccessor($database, $server_id = null) {
257
			global $lang, $conf, $misc;
258
			
259
			$server_info = $this->getServerInfo($server_id);
260

    
261
			// Perform extra security checks if this config option is set
262
			if ($conf['extra_login_security']) {
263
				// Disallowed logins if extra_login_security is enabled.
264
				// These must be lowercase.
265
				$bad_usernames = array('pgsql', 'postgres', 'root', 'administrator');
266
				
267
				$username = strtolower($server_info['username']);
268
				
269
				if ($server_info['password'] == '' || in_array($username, $bad_usernames)) {
270
					unset($_SESSION['webdbLogin'][$_REQUEST['server']]);
271
					$msg = $lang['strlogindisallowed'];
272
					include('./login.php');
273
					exit;
274
				}
275
			}
276
			
277
			// Create the connection object and make the connection
278
			$_connection = new Connection(
279
				$server_info['host'],
280
				$server_info['port'],
281
				$server_info['username'],
282
				$server_info['password'],
283
				$database
284
			);
285

    
286
			// Get the name of the database driver we need to use.
287
			// The description of the server is returned in $platform.
288
			$_type = $_connection->getDriver($platform);
289
			if ($_type === null) {
290
				printf($lang['strpostgresqlversionnotsupported'], $postgresqlMinVer);
291
				exit;
292
			}
293
			$this->setServerInfo('platform', $platform, $server_id);
294
			
295
			// Create a database wrapper class for easy manipulation of the
296
			// connection.
297
			include_once('./classes/database/' . $_type . '.php');
298
			$data =& new $_type($_connection->conn);
299
			$data->platform = $_connection->platform;
300

    
301
			return $data;
302
		}
303

    
304

    
305
		/**
306
		 * Prints the page header.  If global variable $_no_output is
307
		 * set then no header is drawn.
308
		 * @param $title The title of the page
309
		 * @param $script script tag
310
		 */
311
		function printHeader($title = '', $script = null) {
312
			global $appName, $lang, $_no_output, $conf;
313

    
314
			if (!isset($_no_output)) {
315
				header("Content-Type: text/html; charset=" . $lang['appcharset']);
316
				// Send XHTML headers, or regular HTML headers
317
				if (isset($conf['use_xhtml']) && $conf['use_xhtml']) {
318
					echo "<?xml version=\"1.0\" encoding=\"", htmlspecialchars($lang['appcharset']), "\"?>\n";
319
					echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-Transitional.dtd\">\n";
320
					echo "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"{$lang['applocale']}\" lang=\"{$lang['applocale']}\"";
321
					if (strcasecmp($lang['applangdir'], 'ltr') != 0) echo " dir=\"", htmlspecialchars($lang['applangdir']), "\"";
322
					echo ">\n";
323
				} else {
324
					echo "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
325
					echo "<html lang=\"{$lang['applocale']}\"";
326
					if (strcasecmp($lang['applangdir'], 'ltr') != 0) echo " dir=\"", htmlspecialchars($lang['applangdir']), "\"";
327
					echo ">\n";
328
				}
329
				echo "<head>\n";
330
				echo "<title>", htmlspecialchars($appName);
331
				if ($title != '') echo " - {$title}";
332
				echo "</title>\n";
333
				echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset={$lang['appcharset']}\" />\n";
334
				
335
				// Theme
336
				echo "<link rel=\"stylesheet\" href=\"themes/{$conf['theme']}/global.css\" type=\"text/css\" />\n";
337
				if ($script) echo "{$script}\n";
338
				echo "</head>\n";
339
			}
340
		}
341

    
342
		/**
343
		 * Prints the page footer
344
		 * @param $doBody True to output body tag, false otherwise
345
		 */
346
		function printFooter($doBody = true) {
347
			global $_reload_browser, $_reload_drop_database;
348

    
349
			if ($doBody) {
350
				if (isset($_reload_browser)) $this->printReload(false);
351
				elseif (isset($_reload_drop_database)) $this->printReload(true);
352
				echo "</body>\n";
353
			}
354
			echo "</html>\n";
355
		}
356

    
357
		/**
358
		 * Prints the page body.
359
		 * @param $doBody True to output body tag, false otherwise
360
		 * @param $bodyClass - name of body class
361
		 */
362
		function printBody($bodyClass = '', $doBody = true ) {
363
			global $_no_output;			
364

    
365
			if (!isset($_no_output)) {
366
				if ($doBody) {
367
					$bodyClass = htmlspecialchars($bodyClass);
368
					echo "<body", ($bodyClass == '' ? '' : " class=\"{$bodyClass}\"");
369
					echo ">\n";
370
				}
371
			}
372
		}
373

    
374
		/**
375
		 * Outputs JavaScript code that will reload the browser
376
		 * @param $database True if dropping a database, false otherwise
377
		 */
378
		function printReload($database) {
379
			echo "<script type=\"text/javascript\">\n";
380
			if ($database)
381
				echo "\tparent.frames.browser.location.href=\"browser.php\";\n";
382
			else
383
				echo "\tparent.frames.browser.location.reload();\n";
384
			echo "</script>\n";
385
		}
386

    
387
		/**
388
		 * Display navigation tabs
389
		 * @param $tabs An associative array of tabs definitions, see printNav() for an example.
390
		 * @param $activetab The name of the tab to be highlighted.
391
		 */
392
		function printTabs($tabs, $activetab) {
393
			global $misc, $conf, $data, $lang;
394
			
395
			if (is_string($tabs)) {
396
				switch ($tabs) {
397
					case 'database':
398
					case 'schema':
399
						if ($data->hasSchemas() === false) {
400
							$this->printTabs($this->getNavTabs('database'), $activetab);
401
							$this->printTabs($this->getNavTabs('schema'), $activetab);
402
							$_SESSION['webdbLastTab']['database'] = $activetab;
403
							return;
404
						}
405
					default:
406
						$_SESSION['webdbLastTab'][$tabs] = $activetab;
407
						$tabs = $this->getNavTabs($tabs);
408
				}
409
			}
410
			
411
			echo "<table class=\"tabs\"><tr>\n";
412
			
413
			# FIXME: don't count hidden tags
414
			$width = round(100 / count($tabs)).'%';
415
			
416
			foreach ($tabs as $tab_id => $tab) {
417
				$active = ($tab_id == $activetab) ? ' active' : '';
418
				
419
				if (!isset($tab['hide']) || $tab['hide'] !== true) {
420
					$tablink = "<a" . $this->printActionUrl($tab, $_REQUEST, 'href') . ">{$tab['title']}</a>";
421
					
422
					echo "<td width=\"{$width}\" class=\"tab{$active}\">";
423
					
424
					if (isset($tab['help']))
425
						$this->printHelp($tablink, $tab['help']);
426
					else
427
						echo $tablink;
428
					
429
					echo "</td>\n";
430
				}
431
			}
432
			
433
			echo "</tr></table>\n";
434
		}
435

    
436
		/**
437
		 * Retreive the tab info for a specific tab bar.
438
		 * @param $section The name of the tab bar.
439
		 */
440
		function getNavTabs($section) {
441
			global $data, $lang, $conf, $slony;
442

    
443
			$hide_advanced = ($conf['show_advanced'] === false);
444
			
445
			switch ($section) {
446
				case 'root':
447
					return array (
448
						'intro' => array (
449
							'title' => $lang['strintroduction'],
450
							'url'   => "intro.php",
451
						),
452
						'servers' => array (
453
							'title' => $lang['strservers'],
454
							'url'   => "servers.php",
455
						),
456
					);
457

    
458
				case 'server':
459
					$server_info = $this->getServerInfo();
460
					$hide_users = !$data->isSuperUser($server_info['username']);
461
					return array (
462
						'databases' => array (
463
							'title' => $lang['strdatabases'],
464
							'url'   => 'all_db.php',
465
							'urlvars' => array('subject' => 'server'),
466
							'help'  => 'pg.database',
467
						),
468
						'users' => array (
469
							'title' => $lang['strusers'],
470
							'url'   => 'users.php',
471
							'urlvars' => array('subject' => 'server'),
472
							'hide'  => $hide_users,
473
							'help'  => 'pg.user',
474
						),
475
						'groups' => array (
476
							'title' => $lang['strgroups'],
477
							'url'   => 'groups.php',
478
							'urlvars' => array('subject' => 'server'),
479
							'hide'  => $hide_users,
480
							'help'  => 'pg.group',
481
						),
482
						'account' => array (
483
							'title' => $lang['straccount'],
484
							'url'   => 'users.php',
485
							'urlvars' => array('subject' => 'server', 'action' => 'account'),
486
							'hide'  => !$hide_users,
487
							'help'  => 'pg.user',
488
						),
489
						'tablespaces' => array (
490
							'title' => $lang['strtablespaces'],
491
							'url'   => 'tablespaces.php',
492
							'urlvars' => array('subject' => 'server'),
493
							'hide'  => (!$data->hasTablespaces()),
494
							'help'  => 'pg.tablespace',
495
						),
496
						'export' => array (
497
							'title' => $lang['strexport'],
498
							'url'   => 'all_db.php',
499
							'urlvars' => array('subject' => 'server', 'action' => 'export'),
500
							'hide'  => (!$this->isDumpEnabled()),
501
						),
502
						'reports' => array (
503
							'title' => $lang['strreports'],
504
							'url'   => 'reports.php',
505
							'urlvars' => array('subject' => 'server'),
506
							'hide' => !$conf['show_reports']
507
						),
508
					);
509

    
510
				case 'database':				
511
					$tabs = array (
512
						'schemas' => array (
513
							'title' => $lang['strschemas'],
514
							'url'   => 'schemas.php',
515
							'urlvars' => array('subject' => 'database'),
516
							'hide'  => (!$data->hasSchemas()),
517
							'help'  => 'pg.schema',
518
						),
519
						'sql' => array (
520
							'title' => $lang['strsql'],
521
							'url'   => 'database.php',
522
							'urlvars' => array('subject' => 'database', 'action' => 'sql'),
523
							'help'  => 'pg.sql',
524
							'tree'  => false,
525
						),
526
						'find' => array (
527
							'title' => $lang['strfind'],
528
							'url'   => 'database.php',
529
							'urlvars' => array('subject' => 'database', 'action' => 'find'),
530
							'tree'  => false,
531
						),
532
						'variables' => array (
533
							'title' => $lang['strvariables'],
534
							'url'   => 'database.php',
535
							'urlvars' => array('subject' => 'database', 'action' => 'variables'),
536
							'hide'  => (!$data->hasVariables()),
537
							'help'  => 'pg.variable',
538
							'tree'  => false,
539
						),
540
						'processes' => array (
541
							'title' => $lang['strprocesses'],
542
							'url'   => 'database.php',
543
							'urlvars' => array('subject' => 'database', 'action' => 'processes'),
544
							'hide'  => (!$data->hasProcesses()),
545
							'help'  => 'pg.process',
546
							'tree'  => false,
547
						),
548
						'admin' => array (
549
							'title' => $lang['stradmin'],
550
							'url'   => 'database.php',
551
							'urlvars' => array('subject' => 'database', 'action' => 'admin'),
552
							'tree'  => false,
553
						),
554
						'privileges' => array (
555
							'title' => $lang['strprivileges'],
556
							'url'   => 'privileges.php',
557
							'urlvars' => array('subject' => 'database'),
558
							'hide'  => (!isset($data->privlist['database'])),
559
							'help'  => 'pg.privilege',
560
							'tree'  => false,
561
						),
562
						'languages' => array (
563
							'title' => $lang['strlanguages'],
564
							'url'   => 'languages.php',
565
							'urlvars' => array('subject' => 'database'),
566
							'hide'  => $hide_advanced,
567
							'help'  => 'pg.language',
568
						),
569
						'casts' => array (
570
							'title' => $lang['strcasts'],
571
							'url'   => 'casts.php',
572
							'urlvars' => array('subject' => 'database'),
573
							'hide'  => ($hide_advanced || !$data->hasCasts()),
574
							'help'  => 'pg.cast',
575
						),
576
						'slony' => array (
577
							'title' => 'Slony',
578
							'url'   => 'plugin_slony.php',
579
							'urlvars' => array('subject' => 'database', 'action' => 'clusters_properties'),
580
							'hide'  => !isset($slony),
581
							'help'  => '',
582
						),
583
						'export' => array (
584
							'title' => $lang['strexport'],
585
							'url'   => 'database.php',
586
							'urlvars' => array('subject' => 'database', 'action' => 'export'),
587
							'hide'  => (!$this->isDumpEnabled()),
588
							'tree'  => false,
589
						),
590
					);
591
					return $tabs;
592
				case 'schema':
593
					return array (
594
						'tables' => array (
595
							'title' => $lang['strtables'],
596
							'url'   => 'tables.php',
597
							'urlvars' => array('subject' => 'schema'),
598
							'help'  => 'pg.table',
599
							'icon'  => 'tables',
600
						),
601
						'views' => array (
602
							'title' => $lang['strviews'],
603
							'url'   => 'views.php',
604
							'urlvars' => array('subject' => 'schema'),
605
							'help'  => 'pg.view',
606
							'icon'  => 'views',
607
						),
608
						'sequences' => array (
609
							'title' => $lang['strsequences'],
610
							'url'   => 'sequences.php',
611
							'urlvars' => array('subject' => 'schema'),
612
							'help'  => 'pg.sequence',
613
							'icon'  => 'sequences',
614
						),
615
						'functions' => array (
616
							'title' => $lang['strfunctions'],
617
							'url'   => 'functions.php',
618
							'urlvars' => array('subject' => 'schema'),
619
							'help'  => 'pg.function',
620
							'icon'  => 'functions',
621
						),
622
						'domains' => array (
623
							'title' => $lang['strdomains'],
624
							'url'   => 'domains.php',
625
							'urlvars' => array('subject' => 'schema'),
626
							'hide'  => (!$data->hasDomains()),
627
							'help'  => 'pg.domain',
628
							'icon'  => 'domains',
629
						),
630
						'aggregates' => array (
631
							'title' => $lang['straggregates'],
632
							'url'   => 'aggregates.php',
633
							'urlvars' => array('subject' => 'schema'),
634
							'hide'  => $hide_advanced,
635
							'help'  => 'pg.aggregate',
636
							'icon'  => 'functions',
637
						),
638
						'types' => array (
639
							'title' => $lang['strtypes'],
640
							'url'   => 'types.php',
641
							'urlvars' => array('subject' => 'schema'),
642
							'hide'  => $hide_advanced,
643
							'help'  => 'pg.type',
644
							'icon'  => 'types',
645
						),
646
						'operators' => array (
647
							'title' => $lang['stroperators'],
648
							'url'   => 'operators.php',
649
							'urlvars' => array('subject' => 'schema'),
650
							'hide'  => $hide_advanced,
651
							'help'  => 'pg.operator',
652
							'icon'  => 'operators',
653
						),
654
						'opclasses' => array (
655
							'title' => $lang['stropclasses'],
656
							'url'   => 'opclasses.php',
657
							'urlvars' => array('subject' => 'schema'),
658
							'hide'  => $hide_advanced,
659
							'help'  => 'pg.opclass',
660
							'icon'  => 'operators',
661
						),
662
						'conversions' => array (
663
							'title' => $lang['strconversions'],
664
							'url'   => 'conversions.php',
665
							'urlvars' => array('subject' => 'schema'),
666
							'hide'  => ($hide_advanced || !$data->hasConversions()),
667
							'help'  => 'pg.conversion',
668
							'icon'  => 'types',
669
						),
670
						'privileges' => array (
671
							'title' => $lang['strprivileges'],
672
							'url'   => 'privileges.php',
673
							'urlvars' => array('subject' => 'schema'),
674
							'hide'  => (!$data->hasSchemas()),
675
							'help'  => 'pg.privilege',
676
							'tree'  => false,
677
						),
678
					);
679

    
680
				case 'table':
681
					return array (
682
						'columns' => array (
683
							'title' => $lang['strcolumns'],
684
							'url'   => 'tblproperties.php',
685
							'urlvars' => array('subject' => 'table', 'table' => field('table')),
686
						),
687
						'indexes' => array (
688
							'title' => $lang['strindexes'],
689
							'url'   => 'indexes.php',
690
							'urlvars' => array('subject' => 'table', 'table' => field('table')),
691
							'help'  => 'pg.index',
692
						),
693
						'constraints' => array (
694
							'title' => $lang['strconstraints'],
695
							'url'   => 'constraints.php',
696
							'urlvars' => array('subject' => 'table', 'table' => field('table')),
697
							'help'  => 'pg.constraint',
698
						),
699
						'triggers' => array (
700
							'title' => $lang['strtriggers'],
701
							'url'   => 'triggers.php',
702
							'urlvars' => array('subject' => 'table', 'table' => field('table')),
703
							'help'  => 'pg.trigger',
704
						),
705
						'rules' => array (
706
							'title' => $lang['strrules'],
707
							'url'   => 'rules.php',
708
							'urlvars' => array('subject' => 'table', 'table' => field('table')),
709
							'help'  => 'pg.rule',
710
						),
711
						'info' => array (
712
							'title' => $lang['strinfo'],
713
							'url'   => 'info.php',
714
							'urlvars' => array('subject' => 'table', 'table' => field('table')),
715
						),
716
						'privileges' => array (
717
							'title' => $lang['strprivileges'],
718
							'url'   => 'privileges.php',
719
							'urlvars' => array('subject' => 'table', 'table' => field('table')),
720
							'help'  => 'pg.privilege',
721
						),
722
						'import' => array (
723
							'title' => $lang['strimport'],
724
							'url'   => 'tblproperties.php',
725
							'urlvars' => array('subject' => 'table', 'table' => field('table'), 'action' => 'import'),
726
						),
727
						'export' => array (
728
							'title' => $lang['strexport'],
729
							'url'   => 'tblproperties.php',
730
							'urlvars' => array('subject' => 'table', 'table' => field('table'), 'action' => 'export'),
731
						),
732
					);
733
				
734
				case 'view':
735
					return array (
736
						'columns' => array (
737
							'title' => $lang['strcolumns'],
738
							'url'   => 'viewproperties.php',
739
							'urlvars' => array('subject' => 'view', 'view' => field('view')),
740
						),
741
						'definition' => array (
742
							'title' => $lang['strdefinition'],
743
							'url'   => 'viewproperties.php',
744
							'urlvars' => array('subject' => 'view', 'view' => field('view'), 'action' => 'definition'),
745
						),
746
						'rules' => array (
747
							'title' => $lang['strrules'],
748
							'url'   => 'rules.php',
749
							'urlvars' => array('subject' => 'view', 'view' => field('view')),
750
							'help'  => 'pg.rule',
751
						),
752
						'privileges' => array (
753
							'title' => $lang['strprivileges'],
754
							'url'   => 'privileges.php',
755
							'urlvars' => array('subject' => 'view', 'view' => field('view')),
756
							'help'  => 'pg.privilege',
757
						),
758
						'export' => array (
759
							'title' => $lang['strexport'],
760
							'url'   => 'viewproperties.php',
761
							'urlvars' => array('subject' => 'view', 'view' => field('view'), 'action' => 'export'),
762
						),
763
					);
764
				
765
				case 'function':
766
					return array (
767
						'definition' => array (
768
							'title' => $lang['strdefinition'],
769
							'url'   => 'functions.php',
770
							'urlvars' => array(
771
									'subject' => 'function',
772
									'function' => field('function'),
773
									'function_oid' => field('function_oid'),
774
									'action' => 'properties',
775
								),
776
						),
777
						'privileges' => array (
778
							'title' => $lang['strprivileges'],
779
							'url'   => 'privileges.php',
780
							'urlvars' => array(
781
									'subject' => 'function',
782
									'function' => field('function'),
783
									'function_oid' => field('function_oid'),
784
								),
785
						),
786
					);
787
				
788
				case 'popup':
789
					return array (
790
						'sql' => array (
791
							'title' => $lang['strsql'],
792
							'url'   => 'sqledit.php',
793
							'urlvars' => array('subject' => 'schema', 'action' => 'sql'),
794
							'help'  => 'pg.sql',
795
						),
796
						'find' => array (
797
							'title' => $lang['strfind'],
798
							'url'   => 'sqledit.php',
799
							'urlvars' => array('subject' => 'schema', 'action' => 'find'),
800
						),
801
					);
802
				
803
				case 'slony_cluster':
804
					return array (
805
						'properties' => array (
806
							'title' => $lang['strproperties'],
807
							'url'   => 'plugin_slony.php',
808
							'urlvars' => array(
809
									'subject' => 'slony_cluster',
810
									'action' => 'cluster_properties',
811
									'slony_cluster' => field('slony_cluster')
812
								),
813
							'help'  => '',
814
						),
815
						'nodes' => array (
816
							'title' => $lang['strnodes'],
817
							'url'   => 'plugin_slony.php',
818
							'urlvars' => array(
819
									'subject' => 'slony_cluster',
820
									'action' => 'nodes_properties',
821
									'slony_cluster' => field('slony_cluster')
822
								),
823
							'help'  => '',
824
						),
825
						'sets' => array (
826
							'title' => $lang['strrepsets'],
827
							'url'   => 'plugin_slony.php',
828
							'urlvars' => array(
829
									'subject' => 'slony_cluster',
830
									'action' => 'sets_properties',
831
									'slony_cluster' => field('slony_cluster')
832
								),
833
							'help'  => '',
834
						),
835
					);
836
					
837
				default:
838
					return array();
839
			}
840
		}
841

    
842
		/**
843
		 * Get the URL for the last active tab of a particular tab bar.
844
		 */
845
		function getLastTabURL($section) {
846
			global $data;
847
			
848
			switch ($section) {
849
				case 'database':
850
				case 'schema':
851
					if ($data->hasSchemas() === false) {
852
						$section = 'database';
853
						$tabs = array_merge($this->getNavTabs('schema'), $this->getNavTabs('database'));
854
						break;
855
					}
856
				default:
857
					$tabs = $this->getNavTabs($section);
858
			}
859
			
860
			if (isset($_SESSION['webdbLastTab'][$section]) && isset($tabs[$_SESSION['webdbLastTab'][$section]]))
861
				$tab = $tabs[$_SESSION['webdbLastTab'][$section]];
862
			else
863
				$tab = reset($tabs);
864
			
865
			return isset($tab['url']) ? $tab['url'] : null;
866
		}
867

    
868
		function printTopbar() {
869
			global $lang, $conf, $appName, $appVersion, $appLangFiles;
870
			
871
			$server_info = $this->getServerInfo();
872
			
873
			echo "<div class=\"topbar\"><table width=\"100%\"><tr><td>";
874
			
875
			if ($server_info && isset($server_info['platform']) && isset($server_info['username'])) {
876
				echo sprintf($lang['strtopbar'],
877
					'<span class="platform">'.htmlspecialchars($server_info['platform']).'</span>',
878
					'<span class="host">'.htmlspecialchars($server_info['host']).'</span>',
879
					'<span class="port">'.htmlspecialchars($server_info['port']).'</span>',
880
					'<span class="username">'.htmlspecialchars($server_info['username']).'</span>',
881
					'<span class="date">'.date($lang['strtimefmt']).'</span>');
882
			} else {
883
				echo "<span class=\"appname\">$appName</span> <span class=\"version\">$appVersion</span>";
884
			}
885
			
886
			echo "</td>";
887

    
888
			if (isset($_REQUEST['server'])) {
889
				$url = "sqledit.php?{$this->href}&amp;action=";
890
				
891
				$window_id = htmlspecialchars('sqledit:'.$_REQUEST['server']);
892
				
893
				echo "<td align=\"right\">";
894

    
895
				echo "<a class=\"toplink\" href=\"{$url}sql\" target=\"sqledit\" onclick=\"window.open('{$url}sql','{$window_id}','toolbar=no,width=600,height=400,resizable=yes,scrollbars=no').focus(); return false;\">{$lang['strsql']}</a> | ";
896
				
897
				echo "<a class=\"toplink\" href=\"{$url}find\" target=\"sqledit\" onclick=\"window.open('{$url}find','{$window_id}','toolbar=no,width=600,height=400,resizable=yes,scrollbars=no').focus(); return false;\">{$lang['strfind']}</a> | ";
898
				
899
				echo "<a class=\"toplink\" href=\"servers.php?action=logout&amp;logoutServer=".htmlspecialchars($server_info['host']).":".htmlspecialchars($server_info['port'])."\">{$lang['strlogout']}</a>";
900
				
901
				echo "</td>";
902
			}
903
/*
904
			echo "<td align=\"right\" width=\"1%\">";
905
			
906
			echo "<form method=\"get\"><select name=\"language\" onchange=\"this.form.submit()\">\n";
907
			$language = isset($_SESSION['webdbLanguage']) ? $_SESSION['webdbLanguage'] : 'english';
908
			foreach ($appLangFiles as $k => $v) {
909
				echo "<option value=\"{$k}\"",
910
					($k == $language) ? ' selected="selected"' : '',
911
					">{$v}</option>\n";
912
			}
913
			echo "</select>\n";
914
			echo "<noscript><input type=\"submit\" value=\"Set Language\"></noscript>\n";
915
			foreach ($_GET as $key => $val) {
916
				if ($key == 'language') continue;
917
				echo "<input type=\"hidden\" name=\"$key\" value=\"", htmlspecialchars($val), "\" />\n";
918
			}
919
			echo "</form>\n";
920
			
921
			echo "</td>";
922
*/
923
			echo "</tr></table></div>\n";
924
		}
925
		
926
		/**
927
		 * Display a bread crumb trail.
928
		 */
929
		function printTrail($trail = array()) {
930
			global $lang;
931
			
932
			$this->printTopbar();
933
			
934
			if (is_string($trail)) {
935
				$trail = $this->getTrail($trail);
936
			}
937
			
938
			echo "<div class=\"trail\"><table><tr>";
939
			
940
			foreach ($trail as $crumb) {
941
				echo "<td>";
942
				$crumblink = "<a";
943
				
944
				if (isset($crumb['url']))
945
					$crumblink .= ' href="' . $this->printVal($crumb['url'], 'nbsp') . '"';
946
				
947
				if (isset($crumb['title']))
948
					$crumblink .= " title=\"{$crumb['title']}\"";
949
				
950
				$crumblink .= ">" . htmlspecialchars($crumb['text']) . "</a>";
951
				
952
				if (isset($crumb['help']))
953
					$this->printHelp($crumblink, $crumb['help']);
954
				else
955
					echo $crumblink;
956
				
957
				echo "{$lang['strseparator']}";
958
				echo "</td>";
959
			}
960
			
961
			echo "</tr></table></div>\n";
962
		}
963

    
964
		/**
965
		 * Create a bread crumb trail of the object hierarchy.
966
		 * @param $object The type of object at the end of the trail.
967
		 */
968
		function getTrail($subject = null) {
969
			global $lang, $conf, $data, $appName;
970
			
971
			$trail = array();
972
			$vars = '';
973
			$done = false;
974
			
975
			$trail['root'] = array(
976
				'text'  => $appName,
977
				'url'   => 'redirect.php?subject=root',
978
			);
979
			
980
			if ($subject == 'root') $done = true;
981
			
982
			if (!$done) {
983
				$vars = 'server='.urlencode($_REQUEST['server']).'&';
984
				$server_info = $this->getServerInfo();
985
				$trail['server'] = array(
986
					'title' => $lang['strserver'],
987
					'text'  => $server_info['desc'],
988
					'url'   => "redirect.php?subject=server&{$vars}",
989
					'help'  => 'pg.server'
990
				);
991
			}
992
			if ($subject == 'server') $done = true;
993
			
994
			if (isset($_REQUEST['database']) && !$done) {
995
				$vars .= 'database='.urlencode($_REQUEST['database']).'&';
996
				$trail['database'] = array(
997
					'title' => $lang['strdatabase'],
998
					'text'  => $_REQUEST['database'],
999
					'url'   => "redirect.php?subject=database&{$vars}",
1000
					'help'  => 'pg.database'
1001
				);
1002
			}
1003
			if ($subject == 'database') $done = true;
1004
			
1005
			if (isset($_REQUEST['schema']) && !$done) {
1006
				$vars .= 'schema='.urlencode($_REQUEST['schema']).'&';
1007
				$trail['schema'] = array(
1008
					'title' => $lang['strschema'],
1009
					'text'  => $_REQUEST['schema'],
1010
					'url'   => "redirect.php?subject=schema&{$vars}",
1011
					'help'  => 'pg.schema'
1012
				);
1013
			}
1014
			if ($subject == 'schema') $done = true;
1015
			
1016
			if (isset($_REQUEST['slony_cluster']) && !$done) {
1017
				$vars .= 'slony_cluster='.urlencode($_REQUEST['slony_cluster']).'&';
1018
				$trail['slony_cluster'] = array(
1019
					'title' => 'Slony Cluster',
1020
					'text'  => $_REQUEST['slony_cluster'],
1021
					'url'   => "redirect.php?subject=slony_cluster&{$vars}",
1022
					'help'  => 'sl.cluster'
1023
				);
1024
			}
1025
			if ($subject == 'slony_cluster') $done = true;
1026
			
1027
			if (isset($_REQUEST['table']) && !$done) {
1028
				$vars .= "subject=table&table=".urlencode($_REQUEST['table']);
1029
				$trail['table'] = array(
1030
					'title' => $lang['strtable'],
1031
					'text'  => $_REQUEST['table'],
1032
					'url'   => "redirect.php?{$vars}",
1033
					'help'  => 'pg.table'
1034
				);
1035
			} elseif (isset($_REQUEST['view']) && !$done) {
1036
				$vars .= "subject=view&view=".urlencode($_REQUEST['view']);
1037
				$trail['view'] = array(
1038
					'title' => $lang['strview'],
1039
					'text'  => $_REQUEST['view'],
1040
					'url'   => "redirect.php?{$vars}",
1041
					'help'  => 'pg.view'
1042
				);
1043
			}
1044
			if ($subject == 'table' || $subject == 'view') $done = true;
1045
			
1046
			if (!$done && !is_null($subject)) {
1047
				switch ($subject) {
1048
					case 'function':
1049
						$vars .= "{$subject}_oid=".urlencode($_REQUEST[$subject.'_oid']).'&';
1050
						$vars .= "subject={$subject}&{$subject}=".urlencode($_REQUEST[$subject]);
1051
						$trail[$subject] = array(
1052
							'title' => $lang['str'.$subject],
1053
							'text'  => $_REQUEST[$subject],
1054
							'url'   => "redirect.php?{$vars}",
1055
							'help'  => 'pg.function'
1056
						);
1057
						break;
1058
					case 'slony_node':
1059
						$vars .= 'no_id='.urlencode($_REQUEST['no_id']).'&no_name='.urlencode($_REQUEST['no_name']);
1060
						$trail[$subject] = array(
1061
							'title' => 'Slony Node',
1062
							'text'  => $_REQUEST['no_name'],
1063
							'url'   => "redirect.php?{$vars}",
1064
							'help'  => 'sl.'.$subject
1065
						);
1066
						break;
1067
					case 'slony_set':
1068
						$vars .= "{$subject}_id=".urlencode($_REQUEST[$subject]).'&';
1069
						$vars .= "subject={$subject}&{$subject}=".urlencode($_REQUEST[$subject]);
1070
						$trail[$subject] = array(
1071
							'title' => $lang['str'.$subject],
1072
							'text'  => $_REQUEST[$subject],
1073
							'url'   => "redirect.php?{$vars}",
1074
							'help'  => 'sl.'.$subject
1075
						);
1076
						break;
1077
					default:
1078
						if (isset($_REQUEST[$subject])) {
1079
							$trail[$_REQUEST[$subject]] = array(
1080
								'title' => $lang['str'.$subject],
1081
								'text'  => $_REQUEST[$subject],
1082
								'help'  => 'pg.'.$subject	
1083
							);
1084
						}
1085
				}
1086
			}
1087
			
1088
			return $trail;
1089
		}
1090

    
1091
		/**
1092
		 * Do multi-page navigation.  Displays the prev, next and page options.
1093
		 * @param $page the page currently viewed
1094
		 * @param $pages the maximum number of pages
1095
		 * @param $url the url to refer to with the page number inserted
1096
		 * @param $max_width the number of pages to make available at any one time (default = 20)
1097
		 */
1098
		function printPages($page, $pages, $url, $max_width = 20) {
1099
			global $lang;
1100

    
1101
			$window = 10;
1102

    
1103
			if ($page < 0 || $page > $pages) return;
1104
			if ($pages < 0) return;
1105
			if ($max_width <= 0) return;
1106

    
1107
			if ($pages > 1) {
1108
				echo "<center><p>\n";
1109
				if ($page != 1) {
1110
					$temp = str_replace('%s', 1, $url);
1111
					echo "<a class=\"pagenav\" href=\"{$temp}\">{$lang['strfirst']}</a>\n";
1112
					$temp = str_replace('%s', $page - 1, $url);
1113
					echo "<a class=\"pagenav\" href=\"{$temp}\">{$lang['strprev']}</a>\n";
1114
				}
1115
				
1116
				if ($page <= $window) { 
1117
					$min_page = 1; 
1118
					$max_page = min(2 * $window, $pages); 
1119
				}
1120
				elseif ($page > $window && $pages >= $page + $window) { 
1121
					$min_page = ($page - $window) + 1; 
1122
					$max_page = $page + $window; 
1123
				}
1124
				else { 
1125
					$min_page = ($page - (2 * $window - ($pages - $page))) + 1; 
1126
					$max_page = $pages; 
1127
				}
1128
				
1129
				// Make sure min_page is always at least 1
1130
				// and max_page is never greater than $pages
1131
				$min_page = max($min_page, 1);
1132
				$max_page = min($max_page, $pages);
1133
				
1134
				for ($i = $min_page; $i <= $max_page; $i++) {
1135
					$temp = str_replace('%s', $i, $url);
1136
					if ($i != $page) echo "<a class=\"pagenav\" href=\"{$temp}\">$i</a>\n";
1137
					else echo "$i\n";
1138
				}
1139
				if ($page != $pages) {
1140
					$temp = str_replace('%s', $page + 1, $url);
1141
					echo "<a class=\"pagenav\" href=\"{$temp}\">{$lang['strnext']}</a>\n";
1142
					$temp = str_replace('%s', $pages, $url);
1143
					echo "<a class=\"pagenav\" href=\"{$temp}\">{$lang['strlast']}</a>\n";
1144
				}
1145
				echo "</p></center>\n";
1146
			}
1147
		}		
1148

    
1149
		/**
1150
		 * Displays link to the context help.
1151
		 * @param $str   - the string that the context help is related to (already escaped) 
1152
		 * @param $help  - help section identifier
1153
		 */
1154
		function printHelp($str, $help) {
1155
			global $lang, $data;
1156
			
1157
			echo $str;
1158
			if ($help) {
1159
				echo "<a class=\"help\" href=\"";
1160
				echo htmlspecialchars("help.php?help=".urlencode($help)."&server=".urlencode($_REQUEST['server']));
1161
				echo "\" title=\"{$lang['strhelp']}\" target=\"phppgadminhelp\">{$lang['strhelpicon']}</a>";
1162
			}
1163
		}
1164
	
1165
		/** 
1166
		 * Outputs JavaScript to set default focus
1167
		 * @param $object eg. forms[0].username
1168
		 */
1169
		function setFocus($object) {
1170
			echo "<script type=\"text/javascript\">\n";
1171
			echo "<!--\n";
1172
			echo "   document.{$object}.focus();\n";
1173
			echo "-->\n";
1174
			echo "</script>\n";
1175
		}
1176
		
1177
		/**
1178
		 * Outputs JavaScript to set the name of the browser window.
1179
		 * @param $name the window name
1180
		 * @param $addServer if true (default) then the server id is
1181
		 *        attached to the name.
1182
		 */
1183
		function setWindowName($name, $addServer = true) {
1184
			echo "<script type=\"text/javascript\">\n<!--\n";
1185
			echo "   window.name = '{$name}", ($addServer ? ':'.htmlspecialchars($_REQUEST['server']) : ''), "';\n";
1186
			echo "-->\n</script>\n";
1187
		}
1188

    
1189
		/**
1190
		 * Converts a PHP.INI size variable to bytes.  Taken from publically available
1191
		 * function by Chris DeRose, here: http://www.php.net/manual/en/configuration.directives.php#ini.file-uploads
1192
		 * @param $strIniSize The PHP.INI variable
1193
		 * @return size in bytes, false on failure
1194
		 */
1195
		function inisizeToBytes($strIniSize) {
1196
			// This function will take the string value of an ini 'size' parameter,
1197
			// and return a double (64-bit float) representing the number of bytes
1198
			// that the parameter represents. Or false if $strIniSize is unparseable.
1199
			$a_IniParts = array();
1200

    
1201
			if (!is_string($strIniSize))
1202
				return false;
1203

    
1204
			if (!preg_match ('/^(\d+)([bkm]*)$/i', $strIniSize,$a_IniParts))
1205
				return false;
1206

    
1207
			$nSize = (double) $a_IniParts[1];
1208
			$strUnit = strtolower($a_IniParts[2]);
1209

    
1210
			switch($strUnit) {
1211
				case 'm':
1212
					return ($nSize * (double) 1048576);
1213
				case 'k':
1214
					return ($nSize * (double) 1024);
1215
				case 'b':
1216
				default:
1217
					return $nSize;
1218
			}
1219
		}
1220

    
1221
		/**
1222
		 * Display a URL given an action associative array.
1223
		 * @param $action An associative array of the follow properties:
1224
		 *			'url'  => The first part of the URL (before the ?)
1225
		 *			'urlvars' => Associative array of (URL variable => field name)
1226
		 *						these are appended to the URL
1227
		 *			'urlfn' => Function to apply to URL before display
1228
		 * @param $fields Field data from which 'urlfield' and 'vars' are obtained.
1229
		 * @param $attr If supplied then the URL will be quoted and prefixed with
1230
		 *				'$attr='.
1231
		 */
1232
		function printActionUrl(&$action, &$fields, $attr = null) {
1233
			$url = value($action['url'], $fields);
1234
			
1235
			if ($url === false) return '';
1236
			
1237
			if (!empty($action['urlvars'])) {
1238
				$urlvars = value($action['urlvars'], $fields);
1239
			} else {
1240
				$urlvars = array();
1241
			}
1242
			
1243
			if (isset($urlvars['subject'])) {
1244
				$subject = value($urlvars['subject'], $fields);
1245
				if (isset($_REQUEST['server']) && $subject != 'root') {
1246
					$urlvars['server'] = $_REQUEST['server'];
1247
					if (isset($_REQUEST['database']) && $subject != 'server') {
1248
						$urlvars['database'] = $_REQUEST['database'];
1249
						if (isset($_REQUEST['schema']) && $subject != 'database') {
1250
							$urlvars['schema'] = $_REQUEST['schema'];
1251
						}
1252
					}
1253
				}
1254
			}
1255
			
1256
			$sep = '?';
1257
			foreach ($urlvars as $var => $varfield) {
1258
				$url .= $sep . value_url($var, $fields) . '=' . value_url($varfield, $fields);
1259
				$sep = '&';
1260
			}
1261
			
1262
			$url = htmlentities($url);
1263
			
1264
			if ($attr !== null && $url != '')
1265
				return ' '.$attr.'="'.$url.'"';
1266
			else
1267
				return $url;
1268
		}
1269

    
1270
		function getRequestVars($subject = '') {
1271
			$v = array();
1272
			if (!empty($subject))
1273
				$v['subject'] = $subject;
1274
			if (isset($_REQUEST['server']) && $subject != 'root') {
1275
				$v['server'] = $_REQUEST['server'];
1276
				if (isset($_REQUEST['database']) && $subject != 'server') {
1277
					$v['database'] = $_REQUEST['database'];
1278
					if (isset($_REQUEST['schema']) && $subject != 'database') {
1279
						$v['schema'] = $_REQUEST['schema'];
1280
					}
1281
				}
1282
			}
1283
			return $v;
1284
		}
1285
		
1286
		function printUrlVars(&$vars, &$fields) {
1287
			foreach ($vars as $var => $varfield) {
1288
				echo "{$var}=", urlencode($fields[$varfield]), "&amp;";
1289
			}
1290
		}
1291
		
1292
		/**
1293
		 * Display a table of data.
1294
		 * @param $tabledata A set of data to be formatted, as returned by $data->getDatabases() etc.
1295
		 * @param $columns   An associative array of columns to be displayed:
1296
		 *			$columns = array(
1297
		 *				column_id => array(
1298
		 *					'title' => Column heading,
1299
		 *					'field' => Field name for $tabledata->f[...],
1300
		 *					'help'  => Help page for this column,
1301
		 *				), ...
1302
		 *			);
1303
		 * @param $actions   Actions that can be performed on each object:
1304
		 *			$actions = array(
1305
		 *				action_id => array(
1306
		 *					'title' => Action heading,
1307
		 *					'url'   => Static part of URL,
1308
		 *					'vars'  => Associative array of (URL variable => field name),
1309
		 *				), ...
1310
		 *			);
1311
		 * @param $nodata    (optional) Message to display if data set is empty.
1312
		 * @param $pre_fn    (optional) Name of a function to call for each row,
1313
		 *					 it will be passed two params: $rowdata and $actions,
1314
		 *					 it may be used to derive new fields or modify actions.
1315
		 *					 It can return an array of actions specific to the row,
1316
		 *					 or if nothing is returned then the standard actions are used.
1317
		 *					 (see functions.php and constraints.php for examples)
1318
		 */
1319
		function printTable(&$tabledata, &$columns, &$actions, $nodata = null, $pre_fn = null) {
1320
			global $data, $conf, $misc;
1321
			global $PHP_SELF;
1322

    
1323
			if ($tabledata->recordCount() > 0) {
1324
				
1325
				// Remove the 'comment' column if they have been disabled
1326
				if (!$conf['show_comments']) {
1327
					unset($columns['comment']);
1328
				}
1329

    
1330
				// Apply the 'properties' action to the first column
1331
				// and remove it from the action list.
1332
				// (Remove this section to keep the 'Properties' button instead of links)
1333
				if (isset($actions['properties'])) {
1334
					reset($columns);
1335
					$first_column = key($columns);
1336
					$columns[$first_column]['url'] = $actions['properties']['url'];
1337
					$columns[$first_column]['vars'] = $actions['properties']['vars'];
1338
					unset($actions['properties']);
1339
				}
1340
				
1341
				if (isset($columns['comment'])) {
1342
					// Uncomment this for clipped comments.
1343
					// TODO: This should be a user option.
1344
					//$columns['comment']['params']['clip'] = true;
1345
				}
1346
				
1347
				echo "<table>\n";
1348
				echo "<tr>\n";
1349
				// Display column headings
1350
				foreach ($columns as $column_id => $column) {
1351
					switch ($column_id) {
1352
						case 'actions':
1353
							echo "<th class=\"data\" colspan=\"", count($actions), "\">{$column['title']}</th>\n";
1354
							break;
1355
						default:
1356
							echo "<th class=\"data\">";
1357
							if (isset($column['help']))
1358
								$this->printHelp($column['title'], $column['help']);
1359
							else
1360
								echo $column['title'];
1361
							echo "</th>\n";
1362
							break;
1363
					}
1364
				}
1365
				echo "</tr>\n";
1366
				
1367
				// Display table rows
1368
				$i = 0;
1369
				while (!$tabledata->EOF) {
1370
					$id = ($i % 2) + 1;
1371
					
1372
					unset($alt_actions);
1373
					if (!is_null($pre_fn)) $alt_actions = $pre_fn($tabledata, $actions);
1374
					if (!isset($alt_actions)) $alt_actions =& $actions;
1375
					
1376
					echo "<tr>\n";
1377
					
1378
					foreach ($columns as $column_id => $column) {
1379
					
1380
						// Apply default values for missing parameters
1381
						if (isset($column['url']) && !isset($column['vars'])) $column['vars'] = array();
1382
						
1383
						switch ($column_id) {
1384
							case 'actions':
1385
								foreach ($alt_actions as $action) {
1386
									if (isset($action['disable']) && $action['disable'] === true) {
1387
										echo "<td class=\"data{$id}\"></td>";
1388
									} else {
1389
										echo "<td class=\"opbutton{$id}\">";
1390
										echo "<a href=\"{$action['url']}";
1391
										$misc->printUrlVars($action['vars'], $tabledata->f);
1392
										echo "\">{$action['title']}</a></td>";
1393
									}
1394
								}
1395
								break;
1396
							default;
1397
								echo "<td class=\"data{$id}\">";
1398
								if (isset($tabledata->f[$column['field']])) {
1399
									if (isset($column['url'])) {
1400
										echo "<a href=\"{$column['url']}";
1401
										$misc->printUrlVars($column['vars'], $tabledata->f);
1402
										echo "\">";
1403
									}
1404
								
1405
									$type = isset($column['type']) ? $column['type'] : null;
1406
									$params = isset($column['params']) ? $column['params'] : array();
1407
									echo $misc->printVal($tabledata->f[$column['field']], $type, $params);
1408
								}
1409
								
1410
								if (isset($column['url'])) echo "</a>";
1411

    
1412
								echo "</td>\n";
1413
								break;
1414
						}
1415
					}
1416
					echo "</tr>\n";
1417
					
1418
					$tabledata->moveNext();
1419
					$i++;
1420
				}
1421
				
1422
				echo "</table>\n";
1423
				
1424
				return true;
1425
			} else {
1426
				if (!is_null($nodata)) {
1427
					echo "<p>{$nodata}</p>\n";
1428
				}
1429
				return false;
1430
			}
1431
		}
1432
		
1433
		/** Produce XML data for the browser tree
1434
		 * @param $treedata A set of records to populate the tree.
1435
		 * @param $attrs Attributes for tree items
1436
		 *        'text' - the text for the tree node
1437
		 *        'icon' - an icon for node
1438
		 *        'openIcon' - an alternative icon when the node is expanded
1439
		 *        'toolTip' - tool tip text for the node
1440
		 *        'action' - URL to visit when single clicking the node
1441
		 *        'branch' - URL for child nodes (tree XML)
1442
		 *        'expand' - the action to return XML for the subtree
1443
		 *        'nodata' - message to display when node has no children
1444
		 *        'nohead' - suppress headers and opening <tree> tag
1445
		 *        'nofoot' - suppress closing </tree> tag
1446
		 */
1447
		function printTreeXML(&$treedata, &$attrs) {
1448
			global $conf, $lang;
1449
			
1450
			if (!isset($attrs['nohead']) || $attrs['nohead'] === false) {
1451
				header("Content-Type: text/xml");
1452
				header("Cache-Control: no-cache");
1453
				
1454
				echo "<?xml version=\"1.0\"?>\n";
1455
				
1456
				echo "<tree>\n";
1457
			}
1458
			
1459
			if ($treedata->recordCount() > 0) {
1460
				while (!$treedata->EOF) {
1461
					$rec =& $treedata->f;
1462
					
1463
					echo "<tree";
1464
					echo value_xml_attr('text', $attrs['text'], $rec);
1465
					echo value_xml_attr('action', $attrs['action'], $rec);
1466
					echo value_xml_attr('src', $attrs['branch'], $rec);
1467
					
1468
					$icon = $this->icon(value($attrs['icon'], $rec));
1469
					echo value_xml_attr('icon', $icon, $rec);
1470
					
1471
					if (!empty($attrs['openIcon'])) {
1472
						$icon = $this->icon(value($attrs['openIcon'], $rec));
1473
					}
1474
					echo value_xml_attr('openIcon', $icon, $rec);
1475
					
1476
					echo value_xml_attr('toolTip', $attrs['toolTip'], $rec);
1477
					
1478
					echo "/>\n";
1479
					
1480
					$treedata->moveNext();
1481
				}
1482
			} else {
1483
				$msg = isset($attrs['nodata']) ? $attrs['nodata'] : $lang['strnoobjects'];
1484
				echo "<tree text=\"{$msg}\" onaction=\"this.parentNode.reload()\" icon=\"", $this->icon('error'), "\"/>\n";
1485
			}
1486
			
1487
			if (!isset($attrs['nofoot']) || $attrs['nofoot'] === false) {
1488
				echo "</tree>\n";
1489
			}
1490
		}
1491
		
1492
		function adjustTabsForTree(&$tabs) {
1493
			include_once('./classes/ArrayRecordSet.php');
1494
			
1495
			foreach ($tabs as $i => $tab) {
1496
				if ((isset($tab['hide']) && $tab['hide'] === true) || (isset($tab['tree']) && $tab['tree'] === false)) {
1497
					unset($tabs[$i]);
1498
				}
1499
			}
1500
			return new ArrayRecordSet($tabs);
1501
		}
1502
		
1503
		function icon($icon) {
1504
			global $conf;
1505
			$path = "images/themes/{$conf['theme']}/{$icon}";
1506
			if (file_exists($path.'.png')) return $path.'.png';
1507
			if (file_exists($path.'.gif')) return $path.'.gif';
1508
			$path = "images/themes/default/{$icon}";
1509
			if (file_exists($path.'.png')) return $path.'.png';
1510
			if (file_exists($path.'.gif')) return $path.'.gif';
1511
			return '';
1512
		}
1513
		
1514
		/**
1515
		 * Function to escape command line parameters
1516
		 * @param $str The string to escape
1517
		 * @return The escaped string
1518
		 */
1519
		function escapeShellArg($str) {
1520
			global $data, $lang;
1521
			
1522
			if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
1523
				// Due to annoying PHP bugs, shell arguments cannot be escaped
1524
				// (command simply fails), so we cannot allow complex objects
1525
				// to be dumped.
1526
				if (ereg('^[_.[:alnum:]]+$', $str))
1527
					return $str;
1528
				else {
1529
					echo $lang['strcannotdumponwindows'];
1530
					exit;
1531
				}				
1532
			}
1533
			else	
1534
				return escapeshellarg($str);
1535
		}
1536

    
1537
		/**
1538
		 * Function to escape command line programs
1539
		 * @param $str The string to escape
1540
		 * @return The escaped string
1541
		 */
1542
		function escapeShellCmd($str) {
1543
			global $data;
1544
			
1545
			if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
1546
				$data->fieldClean($str);
1547
				return '"' . $str . '"';
1548
			}
1549
			else	
1550
				return escapeshellcmd($str);
1551
		}
1552
		
1553
		/**
1554
		 * Get list of servers
1555
		 * @param $recordset return as RecordSet suitable for printTable if true,
1556
		 *                   otherwise just return an array.
1557
		 */
1558
		function getServers($recordset = false) {
1559
			global $conf;
1560
			
1561
			$srvs = isset($_SESSION['webdbLogin']) && is_array($_SESSION['webdbLogin']) ? $_SESSION['webdbLogin'] : array();
1562

    
1563
			foreach($conf['servers'] as $idx => $info) {
1564
				$server_id = $info['host'].':'.$info['port'];
1565
				
1566
				if (!isset($srvs[$server_id])) {
1567
					$srvs[$server_id] = $info;
1568
				}
1569
				$srvs[$server_id]['id'] = $server_id;
1570
			}
1571
			
1572
			function _cmp_desc($a, $b) {
1573
				return strcmp($a['desc'], $b['desc']);
1574
			}
1575
			uasort($srvs, '_cmp_desc');
1576
			
1577
			if ($recordset) {
1578
				include_once('./classes/ArrayRecordSet.php');
1579
				return new ArrayRecordSet($srvs);
1580
			}
1581
			return $srvs;
1582
		}
1583
		
1584
		/**
1585
		 * Get information on a server.
1586
		 * If the parameter isn't supplied then the currently
1587
		 * connected server is returned.
1588
		 * @param $server_id A server identifier (host:port)
1589
		 * @return An associative array of server properties
1590
		 */
1591
		function getServerInfo($server_id = null) {
1592
			global $conf, $_reload_browser;
1593

    
1594
			if ($server_id === null && isset($_REQUEST['server']))
1595
				$server_id = $_REQUEST['server'];
1596
			
1597
			// Check for the server in the logged-in list
1598
			if (isset($_SESSION['webdbLogin'][$server_id]))
1599
				return $_SESSION['webdbLogin'][$server_id];
1600
			
1601
			// Otherwise, look for it in the conf file
1602
			foreach($conf['servers'] as $idx => $info) {
1603
				if ($server_id == $info['host'].':'.$info['port']) {
1604
					// Automatically use shared credentials if available
1605
					if (!isset($info['username']) && isset($_SESSION['sharedUsername'])) {
1606
						$info['username'] = $_SESSION['sharedUsername'];
1607
						$info['password'] = $_SESSION['sharedPassword'];
1608
						$_reload_browser = true;
1609
						$this->setServerInfo(null, $info, $server_id);
1610
					}
1611
					
1612
					return $info;
1613
				}
1614
			}
1615
			
1616
			return null;
1617
		}
1618
		
1619
		/**
1620
		 * Set server information.
1621
		 * @param $key parameter name to set, or null to replace all
1622
		 *             params with the assoc-array in $value.
1623
		 * @param $value the new value, or null to unset the parameter
1624
		 * @param $server_id the server identifier, or null for current
1625
		 *                   server.
1626
		 */
1627
		function setServerInfo($key, $value, $server_id = null)
1628
		{
1629
			if ($server_id === null && isset($_REQUEST['server']))
1630
				$server_id = $_REQUEST['server'];
1631
			
1632
			if ($key === null) {
1633
				if ($value === null)
1634
					unset($_SESSION['webdbLogin'][$server_id]);
1635
				else
1636
					$_SESSION['webdbLogin'][$server_id] = $value;
1637
			} else {
1638
				if ($value === null)
1639
					unset($_SESSION['webdbLogin'][$server_id][$key]);
1640
				else
1641
					$_SESSION['webdbLogin'][$server_id][$key] = $value;
1642
			}
1643
		}
1644
	}
1645
?>
(3-3/5)