Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 871 lines (812 sloc) 25.809 kb
667bfec Decomposition
jakubvrana authored
1 <?php
9a176b0 Comments
jakubvrana authored
2 /** Get database connection
3 * @return Min_DB
4 */
64d616c Rename get_dbh to connection
jakubvrana authored
5 function connection() {
6 // can be used in customization, $connection is minified
7 global $connection;
8 return $connection;
c64c4fd Adminer class
jakubvrana authored
9 }
10
9a176b0 Comments
jakubvrana authored
11 /** Unescape database identifier
12 * @param string text inside ``
13 * @return string
14 */
667bfec Decomposition
jakubvrana authored
15 function idf_unescape($idf) {
a29ac72 Improve drivers
jakubvrana authored
16 $last = substr($idf, -1);
17 return str_replace($last . $last, $last, substr($idf, 1, -1));
667bfec Decomposition
jakubvrana authored
18 }
19
5e01a62 Prepare for SQLite
jakubvrana authored
20 /** Escape string to use inside ''
21 * @param string
22 * @return string
23 */
24 function escape_string($val) {
7e644b4 @vrana Save bytes ($connection->quote shortcut)
authored
25 return substr(q($val), 1, -1);
5e01a62 Prepare for SQLite
jakubvrana authored
26 }
27
72f4d9e @vrana Function parse_str respects magic_quotes_gpc (bug #3034575)
authored
28 /** Disable magic_quotes_gpc
29 * @param array e.g. (&$_GET, &$_POST, &$_COOKIE)
30 * @return null modified in place
31 */
32 function remove_slashes($process) {
33 if (get_magic_quotes_gpc()) {
34 while (list($key, $val) = each($process)) {
35 foreach ($val as $k => $v) {
36 unset($process[$key][$k]);
37 if (is_array($v)) {
38 $process[$key][stripslashes($k)] = $v;
39 $process[] = &$process[$key][stripslashes($k)];
40 } else {
41 $process[$key][stripslashes($k)] = ($filter ? $v : stripslashes($v));
42 }
43 }
44 }
45 }
46 }
47
9a176b0 Comments
jakubvrana authored
48 /** Escape or unescape string to use inside form []
49 * @param string
50 * @param bool
51 * @return string
52 */
667bfec Decomposition
jakubvrana authored
53 function bracket_escape($idf, $back = false) {
64ba924 Comments
jakubvrana authored
54 // escape brackets inside name="x[]"
73e8631 Move stuff to functions.inc.php
jakubvrana authored
55 static $trans = array(':' => ':1', ']' => ':2', '[' => ':3');
667bfec Decomposition
jakubvrana authored
56 return strtr($idf, ($back ? array_flip($trans) : $trans));
57 }
58
9a176b0 Comments
jakubvrana authored
59 /** Escape for HTML
60 * @param string
61 * @return string
62 */
689699a Shortcut for htmlspecialchars
jakubvrana authored
63 function h($string) {
64 return htmlspecialchars($string, ENT_QUOTES);
65 }
66
9a176b0 Comments
jakubvrana authored
67 /** Escape for TD
68 * @param string
69 * @return string
70 */
c196985 Function nbsp
jakubvrana authored
71 function nbsp($string) {
7352c28 Replace strlen() by != ""
jakubvrana authored
72 return (trim($string) != "" ? h($string) : "&nbsp;");
c196985 Function nbsp
jakubvrana authored
73 }
74
3f5b683 Reintegrate sqlite branch
jakubvrana authored
75 /** Convert \n to <br>
76 * @param string
77 * @return string
78 */
79 function nl_br($string) {
80 return str_replace("\n", "<br>", $string); // nl2br() uses XHTML before PHP 5.3
81 }
82
6b30cfa Separate checkbox
jakubvrana authored
83 /** Generate HTML checkbox
84 * @param string
85 * @param string
86 * @param bool
87 * @param string
88 * @param string
89 * @return string
90 */
91 function checkbox($name, $value, $checked, $label = "", $onclick = "") {
c4fe12a Clickable labels in IE6
jakubvrana authored
92 static $id = 0;
93 $id++;
3f5b683 Reintegrate sqlite branch
jakubvrana authored
94 $return = "<input type='checkbox'" . ($name ? " name='$name' value='" . h($value) . "'" : "") . ($checked ? " checked" : "") . ($onclick ? " onclick=\"$onclick\"" : "") . " id='checkbox-$id'>";
7352c28 Replace strlen() by != ""
jakubvrana authored
95 return ($label != "" ? "<label for='checkbox-$id'>$return" . h($label) . "</label>" : $return);
6b30cfa Separate checkbox
jakubvrana authored
96 }
97
9a176b0 Comments
jakubvrana authored
98 /** Generate list of HTML options
99 * @param array array of strings or arrays (creates optgroup)
100 * @param mixed
101 * @param bool always use array keys for value="", otherwise only string keys are used
102 * @return string
103 */
1e4d11e Select from foreign keys in Editor
jakubvrana authored
104 function optionlist($options, $selected = null, $use_keys = false) {
667bfec Decomposition
jakubvrana authored
105 $return = "";
106 foreach ($options as $k => $v) {
107 if (is_array($v)) {
689699a Shortcut for htmlspecialchars
jakubvrana authored
108 $return .= '<optgroup label="' . h($k) . '">';
667bfec Decomposition
jakubvrana authored
109 }
ced9de9 Create single column foreign key in table structure
jakubvrana authored
110 foreach ((is_array($v) ? $v : array($k => $v)) as $key => $val) {
cb6d36c HTML instead of XHTML
jakubvrana authored
111 $return .= '<option' . ($use_keys || is_string($key) ? ' value="' . h($key) . '"' : '') . (($use_keys || is_string($key) ? (string) $key : $val) === $selected ? ' selected' : '') . '>' . h($val);
667bfec Decomposition
jakubvrana authored
112 }
113 if (is_array($v)) {
114 $return .= '</optgroup>';
115 }
116 }
117 return $return;
118 }
119
098b74b Move function
jakubvrana authored
120 /** Generate HTML radio list
121 * @param string
122 * @param array
123 * @param string
124 * @param string true for no onchange, false for radio
125 * @return string
126 */
127 function html_select($name, $options, $value = "", $onchange = true) {
128 if ($onchange) {
129 return "<select name='" . h($name) . "'" . (is_string($onchange) ? " onchange=\"$onchange\"" : "") . ">" . optionlist($options, $value) . "</select>";
130 }
131 $return = "";
132 foreach ($options as $key => $val) {
133 $return .= "<label><input type='radio' name='" . h($name) . "' value='" . h($key) . "'" . ($key == $value ? " checked" : "") . ">" . h($val) . "</label>";
134 }
135 return $return;
136 }
137
a93bc19 @vrana Create confirm function
authored
138 /** Get onclick confirmation
139 * @param string JavaScript expression
b7cd652 @vrana No AJAX in drop table, drop database and logout
authored
140 * @param bool stop event propagation
a93bc19 @vrana Create confirm function
authored
141 * @return string
142 */
b7cd652 @vrana No AJAX in drop table, drop database and logout
authored
143 function confirm($count = "", $stop = false) {
144 return " onclick=\"" . ($stop ? "eventStop(event); " : "") . "return confirm('" . lang('Are you sure?') . ($count ? " (' + $count + ')" : "") . "');\"";
a93bc19 @vrana Create confirm function
authored
145 }
146
28f21aa @vrana Escape JavaScript strings (bug #3093243)
authored
147 /** Escape string for JavaScript apostrophes
148 * @param string
149 * @return string
150 */
151 function js_escape($string) {
152 return addcslashes($string, "\r\n'\\/"); // slash for <script>
153 }
154
3f5b683 Reintegrate sqlite branch
jakubvrana authored
155 /** Get INI boolean value
156 * @param string
157 * @return bool
158 */
159 function ini_bool($ini) {
160 $val = ini_get($ini);
161 return (eregi('^(on|true|yes)$', $val) || (int) $val); // boolean values set by php_value are strings
162 }
163
f30fd12 @vrana Work without session.use_cookies (bug #3138640)
authored
164 /** Check if SID is neccessary
165 * @return bool
166 */
167 function sid() {
876af58 @vrana Fix sid function
authored
168 static $return;
169 if (!isset($return)) { // restart_session() defines SID
170 $return = (SID && !($_COOKIE && ini_bool("session.use_cookies"))); // $_COOKIE - don't pass SID with permanent login
171 }
172 return $return;
f30fd12 @vrana Work without session.use_cookies (bug #3138640)
authored
173 }
174
175 /** Shortcut for $connection->quote($string)
176 * @param string
177 * @return string
178 */
7e644b4 @vrana Save bytes ($connection->quote shortcut)
authored
179 function q($string) {
180 global $connection;
181 return $connection->quote($string);
182 }
183
9a176b0 Comments
jakubvrana authored
184 /** Get list of values from database
185 * @param string
186 * @param mixed
187 * @return array
188 */
0bd864e Allow specifying column in get_vals
jakubvrana authored
189 function get_vals($query, $column = 0) {
64d616c Rename get_dbh to connection
jakubvrana authored
190 global $connection;
7769f2c Separate get_vals
jakubvrana authored
191 $return = array();
64d616c Rename get_dbh to connection
jakubvrana authored
192 $result = $connection->query($query);
b84252f Display SQLite compile options
jakubvrana authored
193 if (is_object($result)) {
49f7886 SHOW DATABASES can be revoked
jakubvrana authored
194 while ($row = $result->fetch_row()) {
0bd864e Allow specifying column in get_vals
jakubvrana authored
195 $return[] = $row[$column];
49f7886 SHOW DATABASES can be revoked
jakubvrana authored
196 }
7769f2c Separate get_vals
jakubvrana authored
197 }
198 return $return;
199 }
200
3f5b683 Reintegrate sqlite branch
jakubvrana authored
201 /** Get keys from first column and values from second
202 * @param string
203 * @param Min_DB
204 * @return array
205 */
206 function get_key_vals($query, $connection2 = null) {
207 global $connection;
208 if (!is_object($connection2)) {
209 $connection2 = $connection;
210 }
211 $return = array();
212 $result = $connection2->query($query);
e26b186 @vrana Avoid fatal error (bug #3110257)
authored
213 if (is_object($result)) {
214 while ($row = $result->fetch_row()) {
215 $return[$row[0]] = $row[1];
216 }
3f5b683 Reintegrate sqlite branch
jakubvrana authored
217 }
218 return $return;
219 }
220
b0d637b @vrana Avoid fatal errors
authored
221 /** Get all rows of result
222 * @param string
223 * @return array associative
224 */
96544ba @vrana Report errors in get_rows()
authored
225 function get_rows($query, $connection2 = null, $error = "<p class='error'>") {
b0d637b @vrana Avoid fatal errors
authored
226 global $connection;
227 if (!is_object($connection2)) {
228 $connection2 = $connection;
229 }
230 $return = array();
231 $result = $connection2->query($query);
232 if (is_object($result)) { // can return true
233 while ($row = $result->fetch_assoc()) {
234 $return[] = $row;
235 }
850d1aa @vrana Report errors only
authored
236 } elseif (!$result && $connection->error && $error && defined("PAGE_HEADER")) {
96544ba @vrana Report errors in get_rows()
authored
237 echo $error . error() . "\n";
b0d637b @vrana Avoid fatal errors
authored
238 }
239 return $return;
240 }
241
9a176b0 Comments
jakubvrana authored
242 /** Find unique identifier of a row
243 * @param array
244 * @param array result of indexes()
35ec64c Link COUNT(*) result to listing
jakubvrana authored
245 * @return array
9a176b0 Comments
jakubvrana authored
246 */
35ec64c Link COUNT(*) result to listing
jakubvrana authored
247 function unique_array($row, $indexes) {
720f5fc Restructure indexes
jakubvrana authored
248 foreach ($indexes as $index) {
4b3d569 Save bytes
jakubvrana authored
249 if (ereg("PRIMARY|UNIQUE", $index["type"])) {
720f5fc Restructure indexes
jakubvrana authored
250 $return = array();
251 foreach ($index["columns"] as $key) {
64ba924 Comments
jakubvrana authored
252 if (!isset($row[$key])) { // NULL is ambiguous
720f5fc Restructure indexes
jakubvrana authored
253 continue 2;
667bfec Decomposition
jakubvrana authored
254 }
35ec64c Link COUNT(*) result to listing
jakubvrana authored
255 $return[$key] = $row[$key];
667bfec Decomposition
jakubvrana authored
256 }
720f5fc Restructure indexes
jakubvrana authored
257 return $return;
667bfec Decomposition
jakubvrana authored
258 }
259 }
260 $return = array();
261 foreach ($row as $key => $val) {
26c9d64 Fix long SQL query crash (bug #2839231)
jakubvrana authored
262 if (!preg_match('~^(COUNT\\((\\*|(DISTINCT )?`(?:[^`]|``)+`)\\)|(AVG|GROUP_CONCAT|MAX|MIN|SUM)\\(`(?:[^`]|``)+`\\))$~', $key)) { //! columns looking like functions
35ec64c Link COUNT(*) result to listing
jakubvrana authored
263 $return[$key] = $val;
988a29f Don't use aggregation functions in unique_idf
jakubvrana authored
264 }
430034c Cottage homework
jakubvrana authored
265 }
266 return $return;
267 }
268
9a176b0 Comments
jakubvrana authored
269 /** Create SQL condition from parsed query string
270 * @param array parsed query string
271 * @return string
272 */
9ea3112 Mandatory $where in where()
jakubvrana authored
273 function where($where) {
1a8d7f1 @vrana Use LIKE for text comparison in MS SQL (bug #3088222)
authored
274 global $jush;
430034c Cottage homework
jakubvrana authored
275 $return = array();
341362a Driver specific INSERT INTO
jakubvrana authored
276 foreach ((array) $where["where"] as $key => $val) {
66ff153 Use bracket_escape function
jakubvrana authored
277 $return[] = idf_escape(bracket_escape($key, 1)) // 1 - back
1a8d7f1 @vrana Use LIKE for text comparison in MS SQL (bug #3088222)
authored
278 . (ereg('\\.', $val) || $jush == "mssql" ? " LIKE " . exact_value(addcslashes($val, "%_")) : " = " . exact_value($val)) // LIKE because of floats, but slow with ints, in MS SQL because of text
66ff153 Use bracket_escape function
jakubvrana authored
279 ; //! enum and set
341362a Driver specific INSERT INTO
jakubvrana authored
280 }
281 foreach ((array) $where["null"] as $key) {
282 $return[] = idf_escape($key) . " IS NULL";
667bfec Decomposition
jakubvrana authored
283 }
c16c57b E-mail sending
jakubvrana authored
284 return implode(" AND ", $return);
667bfec Decomposition
jakubvrana authored
285 }
286
9a176b0 Comments
jakubvrana authored
287 /** Create SQL condition from query string
288 * @param string
289 * @return string
290 */
0cd2afb Remove single item clone
jakubvrana authored
291 function where_check($val) {
292 parse_str($val, $check);
72f4d9e @vrana Function parse_str respects magic_quotes_gpc (bug #3034575)
authored
293 remove_slashes(array(&$check));
0cd2afb Remove single item clone
jakubvrana authored
294 return where($check);
295 }
296
9a176b0 Comments
jakubvrana authored
297 /** Create query string where condition from value
298 * @param int condition order
299 * @param string column identifier
300 * @param string
301 * @return string
186c058 Utilize where_link function
jakubvrana authored
302 * @return string
9a176b0 Comments
jakubvrana authored
303 */
186c058 Utilize where_link function
jakubvrana authored
304 function where_link($i, $column, $value, $operator = "=") {
8062648 @vrana Use IS NULL operator for null value in where_link function
authored
305 return "&where%5B$i%5D%5Bcol%5D=" . urlencode($column) . "&where%5B$i%5D%5Bop%5D=" . urlencode((isset($value) ? $operator : "IS NULL")) . "&where%5B$i%5D%5Bval%5D=" . urlencode($value);
c42c46a Table relations
jakubvrana authored
306 }
307
319cba4 Save e-mail from to cookie
jakubvrana authored
308 /** Set cookie valid for 1 month
309 * @param string
310 * @param string
311 * @return bool
312 */
313 function cookie($name, $value) {
2cec758 @vrana Direct links from HTTPS to HTTP
authored
314 global $HTTPS;
3f5b683 Reintegrate sqlite branch
jakubvrana authored
315 $params = array(
316 $name,
317 (ereg("\n", $value) ? "" : $value), // HTTP Response Splitting protection in PHP < 5.1.2
318 time() + 2592000, // 2592000 - 30 days
319 preg_replace('~\\?.*~', '', $_SERVER["REQUEST_URI"]),
320 "",
2cec758 @vrana Direct links from HTTPS to HTTP
authored
321 $HTTPS
3f5b683 Reintegrate sqlite branch
jakubvrana authored
322 );
c2334db Secure cookies
jakubvrana authored
323 if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
324 $params[] = true; // HttpOnly
325 }
326 return call_user_func_array('setcookie', $params);
319cba4 Save e-mail from to cookie
jakubvrana authored
327 }
328
f9a2023 Improve concurrency
jakubvrana authored
329 /** Restart stopped session
330 * @return null
331 */
332 function restart_session() {
3f5b683 Reintegrate sqlite branch
jakubvrana authored
333 if (!ini_bool("session.use_cookies")) {
f9a2023 Improve concurrency
jakubvrana authored
334 session_start();
335 }
336 }
337
3f5b683 Reintegrate sqlite branch
jakubvrana authored
338 /** Get session variable for current server
339 * @param string
340 * @return mixed
341 */
342 function &get_session($key) {
343 return $_SESSION[$key][DRIVER][SERVER][$_GET["username"]];
344 }
345
346 /** Set session variable for current server
347 * @param string
348 * @param mixed
349 * @return mixed
350 */
351 function set_session($key, $val) {
352 $_SESSION[$key][DRIVER][SERVER][$_GET["username"]] = $val; // used also in auth.inc.php
353 }
354
605b093 @vrana List authentications
authored
355 /** Get authenticated URL
356 * @param string
357 * @param string
358 * @param string
359 * @return string
360 */
361 function auth_url($driver, $server, $username) {
362 global $drivers;
363 preg_match('~([^?]*)\\??(.*)~', remove_from_uri(implode("|", array_keys($drivers)) . "|username|" . session_name()), $match);
364 return "$match[1]?"
f30fd12 @vrana Work without session.use_cookies (bug #3138640)
authored
365 . (sid() ? SID . "&" : "")
605b093 @vrana List authentications
authored
366 . ($driver != "server" || $server != "" ? urlencode($driver) . "=" . urlencode($server) . "&" : "")
367 . "username=" . urlencode($username)
368 . ($match[2] ? "&$match[2]" : "")
369 ;
370 }
371
390e38b @vrana Load long texts for inline-edit by AJAX
authored
372 /** Find whether it is an AJAX request
373 * @return bool
374 */
375 function is_ajax() {
fdea197 @vrana Simplify AJAX redirect
authored
376 return ($_SERVER["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest");
390e38b @vrana Load long texts for inline-edit by AJAX
authored
377 }
378
9a176b0 Comments
jakubvrana authored
379 /** Send Location header and exit
9bb1909 Fix Save and continue edit
jakubvrana authored
380 * @param string null to only set a message
9a176b0 Comments
jakubvrana authored
381 * @param string
382 * @return null
383 */
430034c Cottage homework
jakubvrana authored
384 function redirect($location, $message = null) {
385 if (isset($message)) {
be49e08 Improve session restarting
jakubvrana authored
386 restart_session();
a379bde @vrana Save bytes
authored
387 $_SESSION["messages"][preg_replace('~^[^?]*~', '', (isset($location) ? $location : $_SERVER["REQUEST_URI"]))][] = $message;
430034c Cottage homework
jakubvrana authored
388 }
de24145 @vrana Clear POST with AJAX redirect
authored
389 if (isset($location)) {
b535853 @vrana Full AJAX only with pushState to work correctly with history
authored
390 if ($location == "") {
391 $location = ".";
392 }
fdea197 @vrana Simplify AJAX redirect
authored
393 header((is_ajax() ? "X-AJAX-Redirect" : "Location") . ": $location");
38894b2 @vrana Send all forms by AJAX
authored
394 exit;
9bb1909 Fix Save and continue edit
jakubvrana authored
395 }
430034c Cottage homework
jakubvrana authored
396 }
397
9a176b0 Comments
jakubvrana authored
398 /** Execute query and redirect if successful
399 * @param string
400 * @param string
401 * @param string
402 * @param bool
403 * @param bool
404 * @param bool
405 * @return bool
406 */
748ee83 Print SQL command with multiple queries
jakubvrana authored
407 function query_redirect($query, $location, $message, $redirect = true, $execute = true, $failed = false) {
64d616c Rename get_dbh to connection
jakubvrana authored
408 global $connection, $error, $adminer;
f9a2023 Improve concurrency
jakubvrana authored
409 if ($execute) {
410 $failed = !$connection->query($query);
411 }
10bdbed Save queries to history
jakubvrana authored
412 $sql = "";
413 if ($query) {
c64c4fd Adminer class
jakubvrana authored
414 $sql = $adminer->messageQuery($query);
10bdbed Save queries to history
jakubvrana authored
415 }
748ee83 Print SQL command with multiple queries
jakubvrana authored
416 if ($failed) {
c1130ed Simplify SQL syntax errors everywhere
jakubvrana authored
417 $error = error() . $sql;
c48a017 Print SQL query by error
jakubvrana authored
418 return false;
f91b2c4 Print SQL query by message
jakubvrana authored
419 }
c48a017 Print SQL query by error
jakubvrana authored
420 if ($redirect) {
421 redirect($location, $message . $sql);
422 }
423 return true;
f91b2c4 Print SQL query by message
jakubvrana authored
424 }
425
9a176b0 Comments
jakubvrana authored
426 /** Execute and remember query
d06de55 @vrana Use DELIMITER in history
authored
427 * @param string null to return remembered queries, end with ';' to use DELIMITER
9a176b0 Comments
jakubvrana authored
428 * @return Min_Result
429 */
748ee83 Print SQL command with multiple queries
jakubvrana authored
430 function queries($query = null) {
64d616c Rename get_dbh to connection
jakubvrana authored
431 global $connection;
748ee83 Print SQL command with multiple queries
jakubvrana authored
432 static $queries = array();
433 if (!isset($query)) {
64ba924 Comments
jakubvrana authored
434 // return executed queries without parameter
d06de55 @vrana Use DELIMITER in history
authored
435 return implode("\n", $queries);
748ee83 Print SQL command with multiple queries
jakubvrana authored
436 }
d06de55 @vrana Use DELIMITER in history
authored
437 $queries[] = (ereg(';$', $query) ? "DELIMITER ;;\n$query;\nDELIMITER ;" : "$query;");
64d616c Rename get_dbh to connection
jakubvrana authored
438 return $connection->query($query);
748ee83 Print SQL command with multiple queries
jakubvrana authored
439 }
440
f9bb1c5 @vrana Introduce apply_queries function
authored
441 /** Apply command to all array items
442 * @param string
443 * @param array
444 * @param callback
445 * @return bool
446 */
447 function apply_queries($query, $tables, $escape = 'table') {
448 foreach ($tables as $table) {
449 if (!queries("$query " . $escape($table))) {
450 return false;
451 }
452 }
453 return true;
454 }
455
dbdd40a Introduce queries_redirect function
jakubvrana authored
456 /** Redirect by remembered queries
457 * @param string
458 * @param string
459 * @param bool
52b9820 @vrana Comment
authored
460 * @return bool
dbdd40a Introduce queries_redirect function
jakubvrana authored
461 */
462 function queries_redirect($location, $message, $redirect) {
463 return query_redirect(queries(), $location, $message, $redirect, false, !$redirect);
464 }
465
9a176b0 Comments
jakubvrana authored
466 /** Remove parameter from query string
467 * @param string
468 * @return string
469 */
d41d446 remove_from_uri()
jakubvrana authored
470 function remove_from_uri($param = "") {
483d7dc Remove session_name() only without SID (bug #2910681)
jakubvrana authored
471 return substr(preg_replace("~(?<=[?&])($param" . (SID ? "" : "|" . session_name()) . ")=[^&]*&~", '', "$_SERVER[REQUEST_URI]&"), 0, -1);
d41d446 remove_from_uri()
jakubvrana authored
472 }
473
9a176b0 Comments
jakubvrana authored
474 /** Generate page number for pagination
475 * @param int
476 * @return string
477 */
bd25295 Don't redirect from last page
jakubvrana authored
478 function pagination($page, $current) {
6585b23 @vrana Generic AJAX links
authored
479 return " " . ($page == $current ? $page + 1 : '<a href="' . h(remove_from_uri("page") . ($page ? "&page=$page" : "")) . '">' . ($page + 1) . "</a>");
1456283 Pages on last page
jakubvrana authored
480 }
481
3e9b1ba Don't store files in hidden fields
jakubvrana authored
482 /** Get file contents from $_FILES
9a176b0 Comments
jakubvrana authored
483 * @param string
484 * @param bool
3e9b1ba Don't store files in hidden fields
jakubvrana authored
485 * @return mixed int for error, string otherwise
9a176b0 Comments
jakubvrana authored
486 */
25f01d3 Compress export and import
jakubvrana authored
487 function get_file($key, $decompress = false) {
488 $file = $_FILES[$key];
489 if (!$file || $file["error"]) {
490 return $file["error"];
430034c Cottage homework
jakubvrana authored
491 }
9ff10f8 @vrana Parse UTF-16 and UTF-8 BOM in all text uploads
authored
492 $return = file_get_contents($decompress && ereg('\\.gz$', $file["name"]) ? "compress.zlib://$file[tmp_name]"
0a2d81d Bzip2 import
jakubvrana authored
493 : ($decompress && ereg('\\.bz2$', $file["name"]) ? "compress.bzip2://$file[tmp_name]"
494 : $file["tmp_name"]
495 )); //! may not be reachable because of open_basedir
9ff10f8 @vrana Parse UTF-16 and UTF-8 BOM in all text uploads
authored
496 if ($decompress) {
497 if (function_exists("iconv") && ereg("^\xFE\xFF|^\xFF\xFE", $return, $regs)) {
498 $return = iconv("utf-16", "utf-8", $return);
499 } else { // not ternary operator to save memory
500 $return = ereg_replace("^\xEF\xBB\xBF", "", $return); // UTF-8 BOM
501 }
502 }
503 return $return;
430034c Cottage homework
jakubvrana authored
504 }
505
9a176b0 Comments
jakubvrana authored
506 /** Determine upload error
507 * @param int
508 * @return string
509 */
e2a03c0 Show upload_max_filesize
jakubvrana authored
510 function upload_error($error) {
511 $max_size = ($error == UPLOAD_ERR_INI_SIZE ? ini_get("upload_max_filesize") : null); // post_max_size is checked in index.php
b2a7c7a Execute SQL file stored on server disk
jakubvrana authored
512 return ($error ? lang('Unable to upload a file.') . ($max_size ? " " . lang('Maximum allowed file size is %sB.', $max_size) : "") : lang('File does not exist.'));
e2a03c0 Show upload_max_filesize
jakubvrana authored
513 }
514
9a176b0 Comments
jakubvrana authored
515 /** Generate class for odd rows
516 * @param string return this for odd rows, empty to reset counter
517 * @return string
518 */
519 function odd($return = ' class="odd"') {
4e5b126 Highlight odd and hover rows
jakubvrana authored
520 static $i = 0;
9a176b0 Comments
jakubvrana authored
521 if (!$return) { // reset counter
1b97f48 Reset odd() for each result
jakubvrana authored
522 $i = -1;
4e5b126 Highlight odd and hover rows
jakubvrana authored
523 }
9a176b0 Comments
jakubvrana authored
524 return ($i++ % 2 ? $return : '');
4e5b126 Highlight odd and hover rows
jakubvrana authored
525 }
526
c313dd8 @vrana Deferred operations by AJAX instead of JS (doesn't require sending token...
authored
527 /** Print one row in JSON object
528 * @param string or "" to close the object
529 * @param string
530 * @return null
531 */
532 function json_row($key, $val = null) {
533 static $first = true;
534 if ($first) {
535 echo "{";
536 }
537 if ($key != "") {
be58b9c @vrana Escape \n in JSON
authored
538 echo ($first ? "" : ",") . "\n\t\"" . addcslashes($key, "\r\n\"\\") . '": ' . (isset($val) ? '"' . addcslashes($val, "\r\n\"\\") . '"' : 'undefined');
c313dd8 @vrana Deferred operations by AJAX instead of JS (doesn't require sending token...
authored
539 $first = false;
540 } else {
541 echo "\n}\n";
542 $first = true;
543 }
544 }
545
9a176b0 Comments
jakubvrana authored
546 /** Check whether the string is in UTF-8
547 * @param string
548 * @return bool
549 */
017ffb5 Better UTF-8 detection
jakubvrana authored
550 function is_utf8($val) {
64ba924 Comments
jakubvrana authored
551 // don't print control chars except \t\r\n
017ffb5 Better UTF-8 detection
jakubvrana authored
552 return (preg_match('~~u', $val) && !preg_match('~[\\0-\\x8\\xB\\xC\\xE-\\x1F]~', $val));
553 }
554
1315537 @vrana No error for big text length (bug #264133)
authored
555 /** Create repeat pattern for preg
556 * @param string
557 * @param int
558 * @return string
559 */
560 function repeat_pattern($pattern, $length) {
561 // fix for Compilation failed: number too big in {} quantifier
562 return str_repeat("$pattern{0,65535}", $length / 65535) . "$pattern{0," . ($length % 65535) . "}"; // can create {0,0} which is OK
563 }
564
9a176b0 Comments
jakubvrana authored
565 /** Shorten UTF-8 string
566 * @param string
567 * @param int
568 * @param string
569 * @return string escaped string with appended ...
570 */
cd07584 Save SQL query to history
jakubvrana authored
571 function shorten_utf8($string, $length = 80, $suffix = "") {
1315537 @vrana No error for big text length (bug #264133)
authored
572 if (!preg_match("(^(" . repeat_pattern("[\t\r\n -\x{FFFF}]", $length) . ")($)?)u", $string, $match)) { // ~s causes trash in $match[2] under some PHP versions, (.|\n) is slow
573 preg_match("(^(" . repeat_pattern("[\t\r\n -~]", $length) . ")($)?)", $string, $match);
95764b0 Shorten binary strings
jakubvrana authored
574 }
687b3fd @vrana Replace <strong> by <b> and <em> by <i>
authored
575 return h($match[1]) . $suffix . (isset($match[2]) ? "" : "<i>...</i>");
02a851c Shorten texts in PHP
jakubvrana authored
576 }
3920ebb Remove InnoDB table comment in Tables and views
jakubvrana authored
577
9a176b0 Comments
jakubvrana authored
578 /** Generate friendly URL
579 * @param string
580 * @return string
581 */
8251896 Downloaded file name
jakubvrana authored
582 function friendly_url($val) {
64ba924 Comments
jakubvrana authored
583 // used for blobs and export
8251896 Downloaded file name
jakubvrana authored
584 return preg_replace('~[^a-z0-9_]~i', '-', $val);
585 }
586
9a176b0 Comments
jakubvrana authored
587 /** Print hidden fields
588 * @param array
589 * @param array
590 * @return null
591 */
820c882 Bulk clone
jakubvrana authored
592 function hidden_fields($process, $ignore = array()) {
5d7071a Choose language through option-list
jakubvrana authored
593 while (list($key, $val) = each($process)) {
594 if (is_array($val)) {
595 foreach ($val as $k => $v) {
596 $process[$key . "[$k]"] = $v;
597 }
598 } elseif (!in_array($key, $ignore)) {
689699a Shortcut for htmlspecialchars
jakubvrana authored
599 echo '<input type="hidden" name="' . h($key) . '" value="' . h($val) . '">';
5d7071a Choose language through option-list
jakubvrana authored
600 }
601 }
602 }
61640ee Move common functions
jakubvrana authored
603
3f5b683 Reintegrate sqlite branch
jakubvrana authored
604 /** Print hidden fields for GET forms
605 * @return null
606 */
607 function hidden_fields_get() {
f30fd12 @vrana Work without session.use_cookies (bug #3138640)
authored
608 echo (sid() ? '<input type="hidden" name="' . session_name() . '" value="' . h(session_id()) . '">' : '');
3f5b683 Reintegrate sqlite branch
jakubvrana authored
609 echo (SERVER !== null ? '<input type="hidden" name="' . DRIVER . '" value="' . h(SERVER) . '">' : "");
610 echo '<input type="hidden" name="username" value="' . h($_GET["username"]) . '">';
611 }
612
9a176b0 Comments
jakubvrana authored
613 /** Find out foreign keys for each column
614 * @param string
615 * @return array array($col => array())
616 */
1e4d11e Select from foreign keys in Editor
jakubvrana authored
617 function column_foreign_keys($table) {
753909e @vrana Support for virtual foreign keys
authored
618 global $adminer;
1e4d11e Select from foreign keys in Editor
jakubvrana authored
619 $return = array();
753909e @vrana Support for virtual foreign keys
authored
620 foreach ($adminer->foreignKeys($table) as $foreign_key) {
1e4d11e Select from foreign keys in Editor
jakubvrana authored
621 foreach ($foreign_key["source"] as $val) {
622 $return[$val][] = $foreign_key;
623 }
624 }
625 return $return;
626 }
627
3f5b683 Reintegrate sqlite branch
jakubvrana authored
628 /** Print enum input field
629 * @param string "radio"|"checkbox"
630 * @param string
631 * @param array
632 * @param mixed int|string|array
684e70d @vrana Search for empty enum
authored
633 * @param string
3f5b683 Reintegrate sqlite branch
jakubvrana authored
634 * @return null
635 */
684e70d @vrana Search for empty enum
authored
636 function enum_input($type, $attrs, $field, $value, $empty = null) {
c068206 @vrana Use $adminer->editVal in enum_input function
authored
637 global $adminer;
3f5b683 Reintegrate sqlite branch
jakubvrana authored
638 preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
684e70d @vrana Search for empty enum
authored
639 $return = (isset($empty) ? "<label><input type='$type'$attrs value='$empty'" . ((is_array($value) ? in_array($empty, $value) : $value === 0) ? " checked" : "") . "><i>" . lang('empty') . "</i></label>" : "");
3f5b683 Reintegrate sqlite branch
jakubvrana authored
640 foreach ($matches[1] as $i => $val) {
641 $val = stripcslashes(str_replace("''", "'", $val));
642 $checked = (is_int($value) ? $value == $i+1 : (is_array($value) ? in_array($i+1, $value) : $value === $val));
c068206 @vrana Use $adminer->editVal in enum_input function
authored
643 $return .= " <label><input type='$type'$attrs value='" . ($i+1) . "'" . ($checked ? ' checked' : '') . '>' . h($adminer->editVal($val, $field)) . '</label>';
3f5b683 Reintegrate sqlite branch
jakubvrana authored
644 }
fe06908 @vrana Allow redefining editInput for enum (bug #3048711)
authored
645 return $return;
3f5b683 Reintegrate sqlite branch
jakubvrana authored
646 }
647
9a176b0 Comments
jakubvrana authored
648 /** Print edit input field
649 * @param array one field from fields()
650 * @param mixed
651 * @param string
652 * @return null
653 */
1e4d11e Select from foreign keys in Editor
jakubvrana authored
654 function input($field, $value, $function) {
e672694 @vrana Rename $driver to $jush
authored
655 global $types, $adminer, $jush;
689699a Shortcut for htmlspecialchars
jakubvrana authored
656 $name = h(bracket_escape($field["field"]));
61640ee Move common functions
jakubvrana authored
657 echo "<td class='function'>";
9f69d7a @vrana MS SQL: Do not update AI value
authored
658 $reset = ($jush == "mssql" && $field["auto_increment"]);
659 if ($reset && !$_POST["save"]) {
660 $function = null;
661 }
662 $functions = (isset($_GET["select"]) || $reset ? array("orig" => lang('original')) : array()) + $adminer->editFunctions($field);
454c80f @vrana Save bytes
authored
663 $attrs = " name='fields[$name]'";
61640ee Move common functions
jakubvrana authored
664 if ($field["type"] == "enum") {
fe06908 @vrana Allow redefining editInput for enum (bug #3048711)
authored
665 echo nbsp($functions[""]) . "<td>" . $adminer->editInput($_GET["edit"], $field, $attrs, $value);
61640ee Move common functions
jakubvrana authored
666 } else {
9903946 Use original values in Editor multi edit
jakubvrana authored
667 $first = 0;
668 foreach ($functions as $key => $val) {
669 if ($key === "" || !$val) {
670 break;
671 }
672 $first++;
673 }
28f21aa @vrana Escape JavaScript strings (bug #3093243)
authored
674 $onchange = ($first ? " onchange=\"var f = this.form['function[" . js_escape($name) . "]']; if ($first > f.selectedIndex) f.selectedIndex = $first;\"" : "");
454c80f @vrana Save bytes
authored
675 $attrs .= $onchange;
622845b @vrana Disable maxlength with edit functions
authored
676 echo (count($functions) > 1 ? html_select("function[$name]", $functions, !isset($function) || in_array($function, $functions) || isset($functions[$function]) ? $function : "", "functionChange(this);") : nbsp(reset($functions))) . '<td>';
a561252 Use distinct name for blob inputs
jakubvrana authored
677 $input = $adminer->editInput($_GET["edit"], $field, $attrs, $value); // usage in call is without a table
7352c28 Replace strlen() by != ""
jakubvrana authored
678 if ($input != "") {
e1abcda Treat tinyint(1) as boolean
jakubvrana authored
679 echo $input;
1e4d11e Select from foreign keys in Editor
jakubvrana authored
680 } elseif ($field["type"] == "set") { //! 64 bits
26c9d64 Fix long SQL query crash (bug #2839231)
jakubvrana authored
681 preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
61640ee Move common functions
jakubvrana authored
682 foreach ($matches[1] as $i => $val) {
683 $val = stripcslashes(str_replace("''", "'", $val));
684 $checked = (is_int($value) ? ($value >> $i) & 1 : in_array($val, explode(",", $value), true));
045bce3 @vrana Use editVal for set values
authored
685 echo " <label><input type='checkbox' name='fields[$name][$i]' value='" . (1 << $i) . "'" . ($checked ? ' checked' : '') . "$onchange>" . h($adminer->editVal($val, $field)) . '</label>';
61640ee Move common functions
jakubvrana authored
686 }
5a73c01 @vrana Treat binary type as hex
authored
687 } elseif (ereg('blob|bytea|raw|file', $field["type"]) && ini_bool("file_uploads")) {
a561252 Use distinct name for blob inputs
jakubvrana authored
688 echo "<input type='file' name='fields-$name'$onchange>";
375a5c8 @vrana Non-MySQL binary types
authored
689 } elseif (ereg('text|lob', $field["type"])) {
071e6a2 @vrana Work in IE8
authored
690 echo "<textarea " . ($jush != "sqlite" || ereg("\n", $value) ? "cols='50' rows='12'" : "cols='30' rows='1' style='height: 1.2em;'") . "$attrs onkeydown='return textareaKeydown(this, event);'>" . h($value) . '</textarea>'; // 1.2em - line-height
61640ee Move common functions
jakubvrana authored
691 } else {
692 // int(3) is only a display hint
5002b89 @vrana Big numbers without E
authored
693 $maxlength = (!ereg('int', $field["type"]) && preg_match('~^(\\d+)(,(\\d+))?$~', $field["length"], $match) ? ((ereg("binary", $field["type"]) ? 2 : 1) * $match[1] + ($match[3] ? 1 : 0) + ($match[2] && !$field["unsigned"] ? 1 : 0)) : ($types[$field["type"]] ? $types[$field["type"]] + ($field["unsigned"] ? 0 : 1) : 0));
5a73c01 @vrana Treat binary type as hex
authored
694 echo "<input value='" . h($value) . "'" . ($maxlength ? " maxlength='$maxlength'" : "") . (ereg('char|binary', $field["type"]) && $maxlength > 20 ? " size='40'" : "") . "$attrs>";
61640ee Move common functions
jakubvrana authored
695 }
696 }
697 }
698
9a176b0 Comments
jakubvrana authored
699 /** Process edit input field
700 * @param one field from fields()
701 * @return string
702 */
a0def47 Date localization
jakubvrana authored
703 function process_input($field) {
7e644b4 @vrana Save bytes ($connection->quote shortcut)
authored
704 global $adminer;
a0def47 Date localization
jakubvrana authored
705 $idf = bracket_escape($field["field"]);
61640ee Move common functions
jakubvrana authored
706 $function = $_POST["function"][$idf];
707 $value = $_POST["fields"][$idf];
3f5b683 Reintegrate sqlite branch
jakubvrana authored
708 if ($field["type"] == "enum") {
709 if ($value == -1) {
710 return false;
711 }
712 if ($value == "") {
713 return "NULL";
714 }
04eccba @vrana Allow bigger numbers under 32 bits
authored
715 return +$value;
3f5b683 Reintegrate sqlite branch
jakubvrana authored
716 }
717 if ($field["auto_increment"] && $value == "") {
718 return null;
719 }
720 if ($function == "orig") {
61640ee Move common functions
jakubvrana authored
721 return false;
3f5b683 Reintegrate sqlite branch
jakubvrana authored
722 }
723 if ($function == "NULL") {
61640ee Move common functions
jakubvrana authored
724 return "NULL";
3f5b683 Reintegrate sqlite branch
jakubvrana authored
725 }
726 if ($field["type"] == "set") {
4cead56 Edit default values directly in table creation
jakubvrana authored
727 return array_sum((array) $value);
3f5b683 Reintegrate sqlite branch
jakubvrana authored
728 }
5a73c01 @vrana Treat binary type as hex
authored
729 if (ereg('blob|bytea|raw|file', $field["type"]) && ini_bool("file_uploads")) {
a561252 Use distinct name for blob inputs
jakubvrana authored
730 $file = get_file("fields-$idf");
61640ee Move common functions
jakubvrana authored
731 if (!is_string($file)) {
732 return false; //! report errors
733 }
7e644b4 @vrana Save bytes ($connection->quote shortcut)
authored
734 return q($file);
61640ee Move common functions
jakubvrana authored
735 }
3f5b683 Reintegrate sqlite branch
jakubvrana authored
736 return $adminer->processInput($field, $value, $function);
61640ee Move common functions
jakubvrana authored
737 }
738
db07325 Search in all tables
jakubvrana authored
739 /** Print results of search in all tables
740 * @uses $_GET["where"][0]
741 * @uses $_POST["tables"]
742 * @return null
743 */
744 function search_tables() {
745 global $adminer, $connection;
dfa6cbf @vrana Show tables overview in Editor
authored
746 $_GET["where"][0]["op"] = "LIKE %%";
747 $_GET["where"][0]["val"] = $_POST["query"];
db07325 Search in all tables
jakubvrana authored
748 $found = false;
749 foreach (table_status() as $table => $table_status) {
750 $name = $adminer->tableName($table_status);
751 if (isset($table_status["Engine"]) && $name != "" && (!$_POST["tables"] || in_array($table, $_POST["tables"]))) {
ee3e045 @vrana Separate $where in limit function
authored
752 $result = $connection->query("SELECT" . limit("1 FROM " . table($table), " WHERE " . implode(" AND ", $adminer->selectSearchProcess(fields($table), array())), 1));
782921b @vrana Finish SQLite
authored
753 if ($result->fetch_row()) {
db07325 Search in all tables
jakubvrana authored
754 if (!$found) {
755 echo "<ul>\n";
756 $found = true;
757 }
758 echo "<li><a href='" . h(ME . "select=" . urlencode($table) . "&where[0][op]=" . urlencode($_GET["where"][0]["op"]) . "&where[0][val]=" . urlencode($_GET["where"][0]["val"])) . "'>" . h($name) . "</a>\n";
759 }
760 }
761 }
762 echo ($found ? "</ul>" : "<p class='message'>" . lang('No tables.')) . "\n";
763 }
764
8ab6fff @vrana Centralize dump_headers
authored
765 /** Send headers for export
766 * @param string
767 * @param bool
768 * @return string extension
769 */
770 function dump_headers($identifier, $multi_table = false) {
771 global $adminer;
772 $return = $adminer->dumpHeaders($identifier, $multi_table);
773 $output = $_POST["output"];
774 if ($output != "text") {
775 header("Content-Disposition: attachment; filename=" . ($identifier != "" ? friendly_url($identifier) : "dump") . ".$return" . ($output != "file" && !ereg('[^0-9a-z]', $output) ? ".$output" : ""));
776 }
777 session_write_close();
778 return $return;
779 }
780
9a176b0 Comments
jakubvrana authored
781 /** Print CSV row
782 * @param array
783 * @return null
784 */
61640ee Move common functions
jakubvrana authored
785 function dump_csv($row) {
786 foreach ($row as $key => $val) {
e225d22 @vrana TSV export and import (bug #3097657)
authored
787 if (preg_match("~[\"\n,;\t]~", $val) || $val === "") {
61640ee Move common functions
jakubvrana authored
788 $row[$key] = '"' . str_replace('"', '""', $val) . '"';
789 }
790 }
02d6b90 @vrana CR+LF in CSV export
authored
791 echo implode(($_POST["format"] == "csv" ? "," : ($_POST["format"] == "tsv" ? "\t" : ";")), $row) . "\r\n";
61640ee Move common functions
jakubvrana authored
792 }
c16c57b E-mail sending
jakubvrana authored
793
9a176b0 Comments
jakubvrana authored
794 /** Apply SQL function
795 * @param string
796 * @param string escaped column identifier
797 * @return string
798 */
e331067 Move apply_sql_function
jakubvrana authored
799 function apply_sql_function($function, $column) {
3f5b683 Reintegrate sqlite branch
jakubvrana authored
800 return ($function ? ($function == "unixepoch" ? "DATETIME($column, '$function')" : ($function == "count distinct" ? "COUNT(DISTINCT " : strtoupper("$function(")) . "$column)") : $column);
e331067 Move apply_sql_function
jakubvrana authored
801 }
802
4ba2d85 @vrana Allow permanent login without customization
authored
803 /** Read password from file adminer.key in temporary directory or create one
804 * @return string or false if the file can not be created
805 */
806 function password_file() {
807 $dir = ini_get("upload_tmp_dir"); // session_save_path() may contain other storage path
808 if (!$dir) {
809 if (function_exists('sys_get_temp_dir')) {
810 $dir = sys_get_temp_dir();
811 } else {
812 $filename = @tempnam("", ""); // @ - temp directory can be disabled by open_basedir
813 if (!$filename) {
814 return false;
815 }
816 $dir = dirname($filename);
817 unlink($filename);
818 }
819 }
820 $filename = "$dir/adminer.key";
821 $return = @file_get_contents($filename); // @ - can not exist
822 if ($return) {
823 return $return;
824 }
825 $fp = @fopen($filename, "w"); // @ - can have insufficient rights //! is not atomic
826 if ($fp) {
827 $return = md5(uniqid(mt_rand(), true));
828 fwrite($fp, $return);
829 fclose($fp);
830 }
831 return $return;
832 }
833
9a176b0 Comments
jakubvrana authored
834 /** Check whether the string is e-mail address
835 * @param string
836 * @return bool
837 */
1cf374b @vrana Rename functions (avoid conflict with WordPress)
authored
838 function is_mail($email) {
c16c57b E-mail sending
jakubvrana authored
839 $atom = '[-a-z0-9!#$%&\'*+/=?^_`{|}~]'; // characters of local-name
840 $domain = '[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])'; // one domain component
28e1dd2 Allow multiple e-mails
jakubvrana authored
841 $pattern = "$atom+(\\.$atom+)*@($domain?\\.)+$domain";
842 return preg_match("(^$pattern(,\\s*$pattern)*\$)i", $email);
c16c57b E-mail sending
jakubvrana authored
843 }
dc667ea Hide select export and import
jakubvrana authored
844
bc78866 Link URLs in select
jakubvrana authored
845 /** Check whether the string is URL address
846 * @param string
2cec758 @vrana Direct links from HTTPS to HTTP
authored
847 * @return string "http", "https" or ""
bc78866 Link URLs in select
jakubvrana authored
848 */
849 function is_url($string) {
2cec758 @vrana Direct links from HTTPS to HTTP
authored
850 $domain = '[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])'; // one domain component //! IDN
5002b89 @vrana Big numbers without E
authored
851 return (preg_match("~^(https?)://($domain?\\.)+$domain(:\\d+)?(/.*)?(\\?.*)?(#.*)?\$~i", $string, $match) ? strtolower($match[1]) : ""); //! restrict path, query and fragment characters
bc78866 Link URLs in select
jakubvrana authored
852 }
853
dc667ea Hide select export and import
jakubvrana authored
854 /** Print header for hidden fieldset (close by </div></fieldset>)
855 * @param string
856 * @param string
857 * @param bool
858 * @return null
859 */
860 function print_fieldset($id, $legend, $visible = false) {
861 echo "<fieldset><legend><a href='#fieldset-$id' onclick=\"return !toggle('fieldset-$id');\">$legend</a></legend><div id='fieldset-$id'" . ($visible ? "" : " class='hidden'") . ">\n";
862 }
94a2be5 Highlight current links
jakubvrana authored
863
8ad4809 @vrana Use class="active" instead of <b>
authored
864 /** Return class='active' if $bold is true
94a2be5 Highlight current links
jakubvrana authored
865 * @param bool
866 * @return string
867 */
8ad4809 @vrana Use class="active" instead of <b>
authored
868 function bold($bold) {
869 return ($bold ? " class='active'" : "");
94a2be5 Highlight current links
jakubvrana authored
870 }
Something went wrong with that request. Please try again.