Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 459 lines (426 sloc) 17.552 kB
2c445a8 Extensibility basics
jakubvrana authored
1 <?php
c64c4fd Adminer class
jakubvrana authored
2 class Adminer {
d24ad78 Select boxes customization
jakubvrana authored
3 var $functions = array("char_length", "from_unixtime", "hex", "lower", "round", "sec_to_time", "time_to_sec", "unix_timestamp", "upper");
4 var $grouping = array("avg", "count", "distinct", "group_concat", "max", "min", "sum"); // distinct is short for COUNT(DISTINCT)
5 var $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "REGEXP", "IN", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL");
c64c4fd Adminer class
jakubvrana authored
6
7 /** Name in title and navigation
8 * @return string
9 */
10 function name() {
11 return lang('Adminer');
12 }
13
14 /** Connection parameters
15 * @return array ($server, $username, $password)
16 */
17 function credentials() {
18 return array($_GET["server"], $_SESSION["usernames"][$_GET["server"]], $_SESSION["passwords"][$_GET["server"]]);
19 }
20
21 /** Identifier of selected database
22 * @return string
23 */
24 function database() {
25 // should be used everywhere instead of $_GET["db"]
26 return $_GET["db"];
27 }
28
29 /** Print login form
30 * @param string
31 * @return null
32 */
33 function loginForm($username) {
2faa08c Customize login and login form
jakubvrana authored
34 ?>
0205440 HTML whitespace
jakubvrana authored
35 <table cellspacing="0">
36 <tr><th><?php echo lang('Server'); ?><td><input name="server" value="<?php echo htmlspecialchars($_GET["server"]); ?>">
37 <tr><th><?php echo lang('Username'); ?><td><input name="username" value="<?php echo htmlspecialchars($username); ?>">
38 <tr><th><?php echo lang('Password'); ?><td><input type="password" name="password">
39 </table>
2faa08c Customize login and login form
jakubvrana authored
40 <?php
41 }
c64c4fd Adminer class
jakubvrana authored
42
43 /** Authorize the user
44 * @param string
45 * @param string
46 * @return bool
47 */
48 function login($login, $password) {
49 return true;
97b8c7b Display images in Editor
jakubvrana authored
50 }
c64c4fd Adminer class
jakubvrana authored
51
52 /** Table caption used in navigation and headings
53 * @param array result of SHOW TABLE STATUS
54 * @return string
55 */
56 function tableName($tableStatus) {
57 return htmlspecialchars($tableStatus["Name"]);
58 }
59
60 /** Field caption used in select and edit
61 * @param array single field returned from fields()
62 * @return string
63 */
64 function fieldName($field) {
65 return '<span title="' . htmlspecialchars($field["full_type"]) . '">' . htmlspecialchars($field["field"]) . '</span>';
66 }
67
68 /** Links after select heading
69 * @param array result of SHOW TABLE STATUS
70 * @return string
71 */
72 function selectLinks($tableStatus) {
73 global $SELF;
74 return '<a href="' . htmlspecialchars($SELF) . 'table=' . urlencode($_GET['select']) . '">' . lang('Table structure') . '</a>';
75 }
76
77 /** Find backward keys for table
78 * @param string
79 * @return array $return[$target_table][$key_name][$target_column] = $source_column;
80 */
81 function backwardKeys($table) {
82 return array();
83 }
84
85 /** Query printed in select before execution
86 * @param string query to be executed
87 * @return string
88 */
89 function selectQuery($query) {
90 global $SELF;
91 // it would be nice if $query can be passed by reference and printed value would be returned but call_user() doesn't allow reference parameters
92 return "<p><code class='jush-sql'>" . htmlspecialchars($query) . "</code> <a href='" . htmlspecialchars($SELF) . "sql=" . urlencode($query) . "'>" . lang('Edit') . "</a>\n";
93 }
94
95 /** Description of a row in a table
96 * @param string
97 * @return string SQL expression, empty string for no description
98 */
99 function rowDescription($table) {
100 return "";
101 }
102
103 /** Get descriptions of selected data
104 * @param array all data to print
105 * @param array
106 * @return array
107 */
108 function rowDescriptions($rows, $foreignKeys) {
109 return $rows;
110 }
111
112 /** Value printed in select table
113 * @param string escaped value to print
114 * @param string link to foreign key
115 * @param array single field returned from fields()
116 * @return string
117 */
118 function selectVal($val, $link, $field) {
119 $return = ($field["type"] == "char" ? "<code>$val</code>" : $val);
120 if (ereg('blob|binary', $field["type"]) && !is_utf8($val)) {
121 $return = lang('%d byte(s)', strlen($val));
4921235 Hide edit functions in Editor
jakubvrana authored
122 }
c64c4fd Adminer class
jakubvrana authored
123 return ($link ? "<a href=\"$link\">$return</a>" : $return);
124 }
125
d24ad78 Select boxes customization
jakubvrana authored
126 /** Print columns box in select
127 * @param array result of selectColumnsProcess()
128 * @param array selectable columns
129 * @return null
130 */
131 function selectColumnsPrint($select, $columns) {
132 echo '<fieldset><legend><a href="#fieldset-select" onclick="return !toggle(\'fieldset-select\');">' . lang('Select') . "</a></legend><div id='fieldset-select'" . ($select ? "" : " class='hidden'") . ">\n";
133 $i = 0;
134 $fun_group = array(lang('Functions') => $this->functions, lang('Aggregation') => $this->grouping);
135 foreach ($select as $key => $val) {
136 $val = $_GET["columns"][$key];
137 echo "<div><select name='columns[$i][fun]'><option>" . optionlist($fun_group, $val["fun"]) . "</select>";
138 echo "<select name='columns[$i][col]'><option>" . optionlist($columns, $val["col"], true) . "</select></div>\n";
139 $i++;
140 }
141 echo "<div><select name='columns[$i][fun]' onchange='this.nextSibling.onchange();'><option>" . optionlist($fun_group) . "</select>";
142 echo "<select name='columns[$i][col]' onchange='select_add_row(this);'><option>" . optionlist($columns, null, true) . "</select></div>\n";
143 echo "</div></fieldset>\n";
144 }
145
146 /** Print search box in select
147 * @param array result of selectSearchProcess()
148 * @param array selectable columns
149 * @param array
150 * @return null
151 */
152 function selectSearchPrint($where, $columns, $indexes) {
153 echo '<fieldset><legend><a href="#fieldset-search" onclick="return !toggle(\'fieldset-search\');">' . lang('Search') . "</a></legend><div id='fieldset-search'" . ($where ? "" : " class='hidden'") . ">\n";
154 foreach ($indexes as $i => $index) {
155 if ($index["type"] == "FULLTEXT") {
156 echo "(<i>" . implode("</i>, <i>", array_map('htmlspecialchars', $index["columns"])) . "</i>) AGAINST";
157 echo ' <input name="fulltext[' . $i . ']" value="' . htmlspecialchars($_GET["fulltext"][$i]) . '">';
158 echo "<label><input type='checkbox' name='boolean[$i]' value='1'" . (isset($_GET["boolean"][$i]) ? " checked='checked'" : "") . ">" . lang('BOOL') . "</label>";
159 echo "<br>\n";
160 }
161 }
162 $i = 0;
163 foreach ((array) $_GET["where"] as $val) {
164 if (strlen("$val[col]$val[val]") && in_array($val["op"], $this->operators)) {
165 echo "<div><select name='where[$i][col]'><option value=''>" . lang('(anywhere)') . optionlist($columns, $val["col"], true) . "</select>";
166 echo "<select name='where[$i][op]'>" . optionlist($this->operators, $val["op"]) . "</select>";
167 echo "<input name='where[$i][val]' value=\"" . htmlspecialchars($val["val"]) . "\"></div>\n";
168 $i++;
169 }
170 }
171 echo "<div><select name='where[$i][col]' onchange='select_add_row(this);'><option value=''>" . lang('(anywhere)') . optionlist($columns, null, true) . "</select>";
172 echo "<select name='where[$i][op]'>" . optionlist($this->operators) . "</select>";
173 echo "<input name='where[$i][val]'></div>\n";
174 echo "</div></fieldset>\n";
175 }
176
177 /** Print order box in select
178 * @param array result of selectOrderProcess()
179 * @param array selectable columns
180 * @param array
181 * @return null
182 */
183 function selectOrderPrint($order, $columns, $indexes) {
184 echo '<fieldset><legend><a href="#fieldset-sort" onclick="return !toggle(\'fieldset-sort\');">' . lang('Sort') . "</a></legend><div id='fieldset-sort'" . ($order ? "" : " class='hidden'") . ">\n";
185 $i = 0;
186 foreach ((array) $_GET["order"] as $key => $val) {
187 if (isset($columns[$val])) {
188 echo "<div><select name='order[$i]'><option>" . optionlist($columns, $val, true) . "</select>";
189 echo "<label><input type='checkbox' name='desc[$i]' value='1'" . (isset($_GET["desc"][$key]) ? " checked='checked'" : "") . ">" . lang('descending') . "</label></div>\n";
190 $i++;
191 }
192 }
193 echo "<div><select name='order[$i]' onchange='select_add_row(this);'><option>" . optionlist($columns, null, true) . "</select>";
194 echo "<label><input type='checkbox' name='desc[$i]' value='1'>" . lang('descending') . "</label></div>\n";
195 echo "</div></fieldset>\n";
196 }
197
198 /** Print limit box in select
199 * @param string result of selectLimitProcess()
200 * @return null
201 */
202 function selectLimitPrint($limit) {
203 echo "<fieldset><legend>" . lang('Limit') . "</legend><div>"; // <div> for easy styling
204 echo "<input name='limit' size='3' value=\"" . htmlspecialchars($limit) . "\">";
205 echo "</div></fieldset>\n";
206 }
207
208 /** Print text length box in select
209 * @param string result of selectLengthProcess()
210 * @return null
211 */
212 function selectLengthPrint($text_length) {
213 if (isset($text_length)) {
214 echo "<fieldset><legend>" . lang('Text length') . "</legend><div>";
215 echo '<input name="text_length" size="3" value="' . htmlspecialchars($text_length) . '">';
216 echo "</div></fieldset>\n";
217 }
218 }
219
220 /** Print action box in select
221 * @return null
222 */
223 function selectActionPrint() {
224 echo "<fieldset><legend>" . lang('Action') . "</legend><div>";
225 echo "<input type='submit' value='" . lang('Select') . "'>";
226 echo "</div></fieldset>\n";
227 }
228
229 /** Process columns box in select
230 * @param array selectable columns
231 * @return array (array(select_expressions), array(group_expressions))
232 */
233 function selectColumnsProcess($columns, $indexes) {
234 $select = array(); // select expressions, empty for *
235 $group = array(); // expressions without aggregation - will be used for GROUP BY if an aggregation function is used
236 foreach ((array) $_GET["columns"] as $key => $val) {
237 if ($val["fun"] == "count" || (isset($columns[$val["col"]]) && (!$val["fun"] || in_array($val["fun"], $this->functions) || in_array($val["fun"], $this->grouping)))) {
238 $select[$key] = apply_sql_function($val["fun"], (isset($columns[$val["col"]]) ? idf_escape($val["col"]) : "*"));
239 if (!in_array($val["fun"], $this->grouping)) {
240 $group[] = $select[$key];
241 }
242 }
243 }
244 return array($select, $group);
245 }
246
247 /** Process search box in select
248 * @param array
249 * @param array
250 * @return array expressions to join by AND
251 */
252 function selectSearchProcess($indexes, $fields) {
253 global $dbh;
254 $return = array();
255 foreach ($indexes as $i => $index) {
256 if ($index["type"] == "FULLTEXT" && strlen($_GET["fulltext"][$i])) {
257 $return[] = "MATCH (" . implode(", ", array_map('idf_escape', $index["columns"])) . ") AGAINST (" . $dbh->quote($_GET["fulltext"][$i]) . (isset($_GET["boolean"][$i]) ? " IN BOOLEAN MODE" : "") . ")";
258 }
259 }
260 foreach ((array) $_GET["where"] as $val) {
261 if (strlen("$val[col]$val[val]") && in_array($val["op"], $this->operators)) {
262 if ($val["op"] == "AGAINST") {
263 $return[] = "MATCH (" . idf_escape($val["col"]) . ") AGAINST (" . $dbh->quote($val["val"]) . " IN BOOLEAN MODE)";
264 } else {
265 $in = process_length($val["val"]);
266 $cond = " $val[op]" . (ereg('NULL$', $val["op"]) ? "" : (ereg('IN$', $val["op"]) ? " (" . (strlen($in) ? $in : "NULL") . ")" : " " . $dbh->quote($val["val"])));
267 if (strlen($val["col"])) {
268 $return[] = idf_escape($val["col"]) . $cond;
269 } else {
270 // find anywhere
271 $cols = array();
272 foreach ($fields as $name => $field) {
273 if (is_numeric($val["val"]) || !ereg('int|float|double|decimal', $field["type"])) {
274 $cols[] = $name;
275 }
276 }
277 $return[] = ($cols ? "(" . implode("$cond OR ", array_map('idf_escape', $cols)) . "$cond)" : "0");
278 }
279 }
280 }
281 }
282 return $return;
283 }
284
285 /** Process order box in select
286 * @param array
287 * @param array result of selectColumnsProcess()
288 * @param array
289 * @return array expressions to join by comma
290 */
291 function selectOrderProcess($columns, $select, $indexes) {
292 $return = array();
293 foreach ((array) $_GET["order"] as $key => $val) {
294 if (isset($columns[$val]) || in_array($val, $select, true)) {
295 $return[] = idf_escape($val) . (isset($_GET["desc"][$key]) ? " DESC" : "");
296 }
297 }
298 return $return;
299 }
300
301 /** Process limit box in select
302 * @return string expression to use in LIMIT, will be escaped
303 */
304 function selectLimitProcess() {
305 return (isset($_GET["limit"]) ? $_GET["limit"] : "30");
306 }
307
308 /** Process length box in select
309 * @return string number of characters to shorten texts, will be escaped
310 */
311 function selectLengthProcess() {
312 return (isset($_GET["text_length"]) ? $_GET["text_length"] : "100");
313 }
314
c64c4fd Adminer class
jakubvrana authored
315 /** Print extra text in the end of a select form
316 * @param array fields holding e-mails
317 * @return null
318 */
d24ad78 Select boxes customization
jakubvrana authored
319 function selectExtraPrint($emailFields) {
c64c4fd Adminer class
jakubvrana authored
320 }
321
322 /** Process extras in select form
323 * @param array AND conditions
324 * @return bool true if processed, false to process other parts of form
325 */
326 function selectExtraProcess($where) {
327 return false;
328 }
329
330 /** Query printed after execution in the message
331 * @param string executed query
332 * @return string
333 */
334 function messageQuery($query) {
335 global $SELF;
336 $id = "sql-" . count($_SESSION["messages"]);
337 $_SESSION["history"][$_GET["server"]][$_GET["db"]][] = $query;
338 return " <a href='#$id' onclick=\"return !toggle('$id');\">" . lang('SQL command') . "</a><div id='$id' class='hidden'><pre class='jush-sql'>" . htmlspecialchars($query) . '</pre><a href="' . htmlspecialchars($SELF . 'sql=&history=' . (count($_SESSION["history"][$_GET["server"]][$_GET["db"]]) - 1)) . '">' . lang('Edit') . '</a></div>';
339 }
340
341 /** Functions displayed in edit form
342 * @param array single field from fields()
343 * @return array
344 */
345 function editFunctions($field) {
346 $return = array("");
347 if (!isset($_GET["default"])) {
348 if (ereg('char|date|time', $field["type"])) {
349 $return = (ereg('char', $field["type"]) ? array("", "md5", "sha1", "password", "uuid") : array("", "now")); //! JavaScript for disabling maxlength
4921235 Hide edit functions in Editor
jakubvrana authored
350 }
c64c4fd Adminer class
jakubvrana authored
351 if (!isset($_GET["call"]) && (isset($_GET["select"]) || where($_GET))) {
352 // relative functions
353 if (ereg('int|float|double|decimal', $field["type"])) {
354 $return = array("", "+", "-");
355 }
356 if (ereg('date', $field["type"])) {
357 $return[] = "+ interval";
358 $return[] = "- interval";
359 }
360 if (ereg('time', $field["type"])) {
361 $return[] = "addtime";
362 $return[] = "subtime";
363 }
4921235 Hide edit functions in Editor
jakubvrana authored
364 }
365 }
c64c4fd Adminer class
jakubvrana authored
366 if ($field["null"] || isset($_GET["default"])) {
367 array_unshift($return, "NULL");
368 }
369 return (isset($_GET["select"]) ? array("orig" => lang('original')) : array()) + $return;
4921235 Hide edit functions in Editor
jakubvrana authored
370 }
c64c4fd Adminer class
jakubvrana authored
371
372 /** Get options to display edit field
373 * @param string table name
374 * @param array single field from fields()
375 * @return array options for <select> or empty to display <input>
376 */
377 function editInput($table, $field) {
378 return false;
4921235 Hide edit functions in Editor
jakubvrana authored
379 }
c64c4fd Adminer class
jakubvrana authored
380
381 /** Process sent input
382 * @param string field name
383 * @param array single field from fields()
384 * @return string expression to use in a query
385 */
386 function processInput($name, $field) {
387 global $dbh;
388 $idf = bracket_escape($name);
389 $function = $_POST["function"][$idf];
390 $value = $_POST["fields"][$idf];
391 $return = $dbh->quote($value);
392 if (ereg('^(now|uuid)$', $function)) {
393 $return = "$function()";
394 } elseif (ereg('^[+-]$', $function)) {
395 $return = idf_escape($name) . " $function $return";
396 } elseif (ereg('^[+-] interval$', $function)) {
397 $return = idf_escape($name) . " $function " . (preg_match("~^([0-9]+|'[0-9.: -]') [A-Z_]+$~i", $value) ? $value : $return);
398 } elseif (ereg('^(addtime|subtime)$', $function)) {
399 $return = "$function(" . idf_escape($name) . ", $return)";
400 } elseif (ereg('^(md5|sha1|password)$', $function)) {
401 $return = "$function($return)";
402 } elseif (ereg('date|time', $field["type"]) && $value == "CURRENT_TIMESTAMP") {
403 $return = $value;
404 }
405 return $return;
a78c941 Empty value in Editor as NULL
jakubvrana authored
406 }
c64c4fd Adminer class
jakubvrana authored
407
408 /** Prints navigation after Adminer title
409 * @param string can be "auth" if there is no database connection or "db" if there is no database selected
410 * @return null
411 */
412 function navigation($missing) {
413 global $SELF, $dbh;
414 if ($missing != "auth") {
415 ob_flush();
416 flush();
417 $databases = get_databases();
418 ?>
b95f24e Editor: User friendly data editor
jakubvrana authored
419 <form action="" method="post">
420 <p>
421 <a href="<?php echo htmlspecialchars($SELF); ?>sql="><?php echo lang('SQL command'); ?></a>
422 <a href="<?php echo htmlspecialchars($SELF); ?>dump=<?php echo urlencode(isset($_GET["table"]) ? $_GET["table"] : $_GET["select"]); ?>"><?php echo lang('Dump'); ?></a>
ace55ed HTML instead of XHTML
jakubvrana authored
423 <input type="hidden" name="token" value="<?php echo $_SESSION["tokens"][$_GET["server"]]; ?>">
424 <input type="submit" name="logout" value="<?php echo lang('Logout'); ?>">
d2ba593 Browsers interpret <form><p></form> as <form><p></form></p>
jakubvrana authored
425 </p>
b95f24e Editor: User friendly data editor
jakubvrana authored
426 </form>
427 <form action="">
ace55ed HTML instead of XHTML
jakubvrana authored
428 <p><?php if (strlen($_GET["server"])) { ?><input type="hidden" name="server" value="<?php echo htmlspecialchars($_GET["server"]); ?>"><?php } ?>
b95f24e Editor: User friendly data editor
jakubvrana authored
429 <?php if ($databases) { ?>
ace55ed HTML instead of XHTML
jakubvrana authored
430 <select name="db" onchange="this.form.submit();"><option value="">(<?php echo lang('database'); ?>)<?php echo optionlist($databases, $_GET["db"]); ?></select>
b95f24e Editor: User friendly data editor
jakubvrana authored
431 <?php } else { ?>
ace55ed HTML instead of XHTML
jakubvrana authored
432 <input name="db" value="<?php echo htmlspecialchars($_GET["db"]); ?>">
b95f24e Editor: User friendly data editor
jakubvrana authored
433 <?php } ?>
ace55ed HTML instead of XHTML
jakubvrana authored
434 <?php if (isset($_GET["sql"])) { ?><input type="hidden" name="sql" value=""><?php } ?>
435 <?php if (isset($_GET["schema"])) { ?><input type="hidden" name="schema" value=""><?php } ?>
436 <?php if (isset($_GET["dump"])) { ?><input type="hidden" name="dump" value=""><?php } ?>
437 <input type="submit" value="<?php echo lang('Use'); ?>"<?php echo ($databases ? " class='hidden'" : ""); ?>>
d2ba593 Browsers interpret <form><p></form> as <form><p></form></p>
jakubvrana authored
438 </p>
b95f24e Editor: User friendly data editor
jakubvrana authored
439 </form>
440 <?php
c64c4fd Adminer class
jakubvrana authored
441 if ($missing != "db" && strlen($_GET["db"])) {
442 $result = $dbh->query("SHOW TABLES");
443 if (!$result->num_rows) {
444 echo "<p class='message'>" . lang('No tables.') . "\n";
445 } else {
446 echo "<p>\n";
447 while ($row = $result->fetch_row()) {
448 echo '<a href="' . htmlspecialchars($SELF) . 'select=' . urlencode($row[0]) . '">' . lang('select') . '</a> ';
449 echo '<a href="' . htmlspecialchars($SELF) . 'table=' . urlencode($row[0]) . '">' . $this->tableName(array("Name" => $row[0])) . "</a><br>\n"; //! Adminer::table_name may work with full table status
450 }
b95f24e Editor: User friendly data editor
jakubvrana authored
451 }
c64c4fd Adminer class
jakubvrana authored
452 $result->free();
453 echo '<p><a href="' . htmlspecialchars($SELF) . 'create=">' . lang('Create new table') . "</a>\n";
b95f24e Editor: User friendly data editor
jakubvrana authored
454 }
455 }
456 }
c64c4fd Adminer class
jakubvrana authored
457
2c445a8 Extensibility basics
jakubvrana authored
458 }
Something went wrong with that request. Please try again.