Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 467 lines (433 sloc) 17.715 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
a0def47 Date localization
jakubvrana authored
113 * @param string HTML-escaped value to print
c64c4fd Adminer class
jakubvrana authored
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
a0def47 Date localization
jakubvrana authored
126 /** Value conversion used in select and edit
127 * @param string
128 * @param array single field returned from fields()
129 * @return
130 */
131 function editVal($val, $field) {
132 return $val;
133 }
134
d24ad78 Select boxes customization
jakubvrana authored
135 /** Print columns box in select
136 * @param array result of selectColumnsProcess()
137 * @param array selectable columns
138 * @return null
139 */
140 function selectColumnsPrint($select, $columns) {
141 echo '<fieldset><legend><a href="#fieldset-select" onclick="return !toggle(\'fieldset-select\');">' . lang('Select') . "</a></legend><div id='fieldset-select'" . ($select ? "" : " class='hidden'") . ">\n";
142 $i = 0;
143 $fun_group = array(lang('Functions') => $this->functions, lang('Aggregation') => $this->grouping);
144 foreach ($select as $key => $val) {
145 $val = $_GET["columns"][$key];
146 echo "<div><select name='columns[$i][fun]'><option>" . optionlist($fun_group, $val["fun"]) . "</select>";
147 echo "<select name='columns[$i][col]'><option>" . optionlist($columns, $val["col"], true) . "</select></div>\n";
148 $i++;
149 }
150 echo "<div><select name='columns[$i][fun]' onchange='this.nextSibling.onchange();'><option>" . optionlist($fun_group) . "</select>";
151 echo "<select name='columns[$i][col]' onchange='select_add_row(this);'><option>" . optionlist($columns, null, true) . "</select></div>\n";
152 echo "</div></fieldset>\n";
153 }
154
155 /** Print search box in select
156 * @param array result of selectSearchProcess()
157 * @param array selectable columns
158 * @param array
159 * @return null
160 */
161 function selectSearchPrint($where, $columns, $indexes) {
162 echo '<fieldset><legend><a href="#fieldset-search" onclick="return !toggle(\'fieldset-search\');">' . lang('Search') . "</a></legend><div id='fieldset-search'" . ($where ? "" : " class='hidden'") . ">\n";
163 foreach ($indexes as $i => $index) {
164 if ($index["type"] == "FULLTEXT") {
165 echo "(<i>" . implode("</i>, <i>", array_map('htmlspecialchars', $index["columns"])) . "</i>) AGAINST";
166 echo ' <input name="fulltext[' . $i . ']" value="' . htmlspecialchars($_GET["fulltext"][$i]) . '">';
167 echo "<label><input type='checkbox' name='boolean[$i]' value='1'" . (isset($_GET["boolean"][$i]) ? " checked='checked'" : "") . ">" . lang('BOOL') . "</label>";
168 echo "<br>\n";
169 }
170 }
171 $i = 0;
172 foreach ((array) $_GET["where"] as $val) {
173 if (strlen("$val[col]$val[val]") && in_array($val["op"], $this->operators)) {
174 echo "<div><select name='where[$i][col]'><option value=''>" . lang('(anywhere)') . optionlist($columns, $val["col"], true) . "</select>";
175 echo "<select name='where[$i][op]'>" . optionlist($this->operators, $val["op"]) . "</select>";
176 echo "<input name='where[$i][val]' value=\"" . htmlspecialchars($val["val"]) . "\"></div>\n";
177 $i++;
178 }
179 }
180 echo "<div><select name='where[$i][col]' onchange='select_add_row(this);'><option value=''>" . lang('(anywhere)') . optionlist($columns, null, true) . "</select>";
181 echo "<select name='where[$i][op]'>" . optionlist($this->operators) . "</select>";
182 echo "<input name='where[$i][val]'></div>\n";
183 echo "</div></fieldset>\n";
184 }
185
186 /** Print order box in select
187 * @param array result of selectOrderProcess()
188 * @param array selectable columns
189 * @param array
190 * @return null
191 */
192 function selectOrderPrint($order, $columns, $indexes) {
193 echo '<fieldset><legend><a href="#fieldset-sort" onclick="return !toggle(\'fieldset-sort\');">' . lang('Sort') . "</a></legend><div id='fieldset-sort'" . ($order ? "" : " class='hidden'") . ">\n";
194 $i = 0;
195 foreach ((array) $_GET["order"] as $key => $val) {
196 if (isset($columns[$val])) {
197 echo "<div><select name='order[$i]'><option>" . optionlist($columns, $val, true) . "</select>";
198 echo "<label><input type='checkbox' name='desc[$i]' value='1'" . (isset($_GET["desc"][$key]) ? " checked='checked'" : "") . ">" . lang('descending') . "</label></div>\n";
199 $i++;
200 }
201 }
202 echo "<div><select name='order[$i]' onchange='select_add_row(this);'><option>" . optionlist($columns, null, true) . "</select>";
203 echo "<label><input type='checkbox' name='desc[$i]' value='1'>" . lang('descending') . "</label></div>\n";
204 echo "</div></fieldset>\n";
205 }
206
207 /** Print limit box in select
208 * @param string result of selectLimitProcess()
209 * @return null
210 */
211 function selectLimitPrint($limit) {
212 echo "<fieldset><legend>" . lang('Limit') . "</legend><div>"; // <div> for easy styling
213 echo "<input name='limit' size='3' value=\"" . htmlspecialchars($limit) . "\">";
214 echo "</div></fieldset>\n";
215 }
216
217 /** Print text length box in select
218 * @param string result of selectLengthProcess()
219 * @return null
220 */
221 function selectLengthPrint($text_length) {
222 if (isset($text_length)) {
223 echo "<fieldset><legend>" . lang('Text length') . "</legend><div>";
224 echo '<input name="text_length" size="3" value="' . htmlspecialchars($text_length) . '">';
225 echo "</div></fieldset>\n";
226 }
227 }
228
229 /** Print action box in select
230 * @return null
231 */
232 function selectActionPrint() {
233 echo "<fieldset><legend>" . lang('Action') . "</legend><div>";
234 echo "<input type='submit' value='" . lang('Select') . "'>";
235 echo "</div></fieldset>\n";
236 }
237
238 /** Process columns box in select
239 * @param array selectable columns
240 * @return array (array(select_expressions), array(group_expressions))
241 */
242 function selectColumnsProcess($columns, $indexes) {
243 $select = array(); // select expressions, empty for *
244 $group = array(); // expressions without aggregation - will be used for GROUP BY if an aggregation function is used
245 foreach ((array) $_GET["columns"] as $key => $val) {
246 if ($val["fun"] == "count" || (isset($columns[$val["col"]]) && (!$val["fun"] || in_array($val["fun"], $this->functions) || in_array($val["fun"], $this->grouping)))) {
247 $select[$key] = apply_sql_function($val["fun"], (isset($columns[$val["col"]]) ? idf_escape($val["col"]) : "*"));
248 if (!in_array($val["fun"], $this->grouping)) {
249 $group[] = $select[$key];
250 }
251 }
252 }
253 return array($select, $group);
254 }
255
256 /** Process search box in select
257 * @param array
258 * @param array
259 * @return array expressions to join by AND
260 */
261 function selectSearchProcess($indexes, $fields) {
262 global $dbh;
263 $return = array();
264 foreach ($indexes as $i => $index) {
265 if ($index["type"] == "FULLTEXT" && strlen($_GET["fulltext"][$i])) {
266 $return[] = "MATCH (" . implode(", ", array_map('idf_escape', $index["columns"])) . ") AGAINST (" . $dbh->quote($_GET["fulltext"][$i]) . (isset($_GET["boolean"][$i]) ? " IN BOOLEAN MODE" : "") . ")";
267 }
268 }
269 foreach ((array) $_GET["where"] as $val) {
270 if (strlen("$val[col]$val[val]") && in_array($val["op"], $this->operators)) {
271 if ($val["op"] == "AGAINST") {
272 $return[] = "MATCH (" . idf_escape($val["col"]) . ") AGAINST (" . $dbh->quote($val["val"]) . " IN BOOLEAN MODE)";
273 } else {
274 $in = process_length($val["val"]);
a0def47 Date localization
jakubvrana authored
275 $cond = " $val[op]" . (ereg('NULL$', $val["op"]) ? "" : (ereg('IN$', $val["op"]) ? " (" . (strlen($in) ? $in : "NULL") . ")" : " " . $this->processInput($fields[$val["col"]], $val["val"])));
d24ad78 Select boxes customization
jakubvrana authored
276 if (strlen($val["col"])) {
277 $return[] = idf_escape($val["col"]) . $cond;
278 } else {
279 // find anywhere
280 $cols = array();
281 foreach ($fields as $name => $field) {
282 if (is_numeric($val["val"]) || !ereg('int|float|double|decimal', $field["type"])) {
283 $cols[] = $name;
284 }
285 }
286 $return[] = ($cols ? "(" . implode("$cond OR ", array_map('idf_escape', $cols)) . "$cond)" : "0");
287 }
288 }
289 }
290 }
291 return $return;
292 }
293
294 /** Process order box in select
295 * @param array
296 * @param array result of selectColumnsProcess()
297 * @param array
298 * @return array expressions to join by comma
299 */
300 function selectOrderProcess($columns, $select, $indexes) {
301 $return = array();
302 foreach ((array) $_GET["order"] as $key => $val) {
303 if (isset($columns[$val]) || in_array($val, $select, true)) {
304 $return[] = idf_escape($val) . (isset($_GET["desc"][$key]) ? " DESC" : "");
305 }
306 }
307 return $return;
308 }
309
310 /** Process limit box in select
311 * @return string expression to use in LIMIT, will be escaped
312 */
313 function selectLimitProcess() {
314 return (isset($_GET["limit"]) ? $_GET["limit"] : "30");
315 }
316
317 /** Process length box in select
318 * @return string number of characters to shorten texts, will be escaped
319 */
320 function selectLengthProcess() {
321 return (isset($_GET["text_length"]) ? $_GET["text_length"] : "100");
322 }
323
c64c4fd Adminer class
jakubvrana authored
324 /** Print extra text in the end of a select form
325 * @param array fields holding e-mails
326 * @return null
327 */
d24ad78 Select boxes customization
jakubvrana authored
328 function selectExtraPrint($emailFields) {
c64c4fd Adminer class
jakubvrana authored
329 }
330
331 /** Process extras in select form
332 * @param array AND conditions
333 * @return bool true if processed, false to process other parts of form
334 */
335 function selectExtraProcess($where) {
336 return false;
337 }
338
339 /** Query printed after execution in the message
340 * @param string executed query
341 * @return string
342 */
343 function messageQuery($query) {
344 global $SELF;
345 $id = "sql-" . count($_SESSION["messages"]);
346 $_SESSION["history"][$_GET["server"]][$_GET["db"]][] = $query;
347 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>';
348 }
349
350 /** Functions displayed in edit form
351 * @param array single field from fields()
352 * @return array
353 */
354 function editFunctions($field) {
355 $return = array("");
356 if (!isset($_GET["default"])) {
357 if (ereg('char|date|time', $field["type"])) {
358 $return = (ereg('char', $field["type"]) ? array("", "md5", "sha1", "password", "uuid") : array("", "now")); //! JavaScript for disabling maxlength
4921235 Hide edit functions in Editor
jakubvrana authored
359 }
c64c4fd Adminer class
jakubvrana authored
360 if (!isset($_GET["call"]) && (isset($_GET["select"]) || where($_GET))) {
361 // relative functions
362 if (ereg('int|float|double|decimal', $field["type"])) {
363 $return = array("", "+", "-");
364 }
365 if (ereg('date', $field["type"])) {
366 $return[] = "+ interval";
367 $return[] = "- interval";
368 }
369 if (ereg('time', $field["type"])) {
370 $return[] = "addtime";
371 $return[] = "subtime";
372 }
4921235 Hide edit functions in Editor
jakubvrana authored
373 }
374 }
c64c4fd Adminer class
jakubvrana authored
375 if ($field["null"] || isset($_GET["default"])) {
376 array_unshift($return, "NULL");
377 }
378 return (isset($_GET["select"]) ? array("orig" => lang('original')) : array()) + $return;
4921235 Hide edit functions in Editor
jakubvrana authored
379 }
c64c4fd Adminer class
jakubvrana authored
380
381 /** Get options to display edit field
382 * @param string table name
383 * @param array single field from fields()
384 * @return array options for <select> or empty to display <input>
385 */
386 function editInput($table, $field) {
387 return false;
4921235 Hide edit functions in Editor
jakubvrana authored
388 }
c64c4fd Adminer class
jakubvrana authored
389
390 /** Process sent input
391 * @param array single field from fields()
a0def47 Date localization
jakubvrana authored
392 * @param string
393 * @param string
c64c4fd Adminer class
jakubvrana authored
394 * @return string expression to use in a query
395 */
a0def47 Date localization
jakubvrana authored
396 function processInput($field, $value, $function = "") {
c64c4fd Adminer class
jakubvrana authored
397 global $dbh;
a0def47 Date localization
jakubvrana authored
398 $name = $field["field"];
c64c4fd Adminer class
jakubvrana authored
399 $return = $dbh->quote($value);
400 if (ereg('^(now|uuid)$', $function)) {
401 $return = "$function()";
402 } elseif (ereg('^[+-]$', $function)) {
403 $return = idf_escape($name) . " $function $return";
404 } elseif (ereg('^[+-] interval$', $function)) {
405 $return = idf_escape($name) . " $function " . (preg_match("~^([0-9]+|'[0-9.: -]') [A-Z_]+$~i", $value) ? $value : $return);
406 } elseif (ereg('^(addtime|subtime)$', $function)) {
407 $return = "$function(" . idf_escape($name) . ", $return)";
408 } elseif (ereg('^(md5|sha1|password)$', $function)) {
409 $return = "$function($return)";
410 } elseif (ereg('date|time', $field["type"]) && $value == "CURRENT_TIMESTAMP") {
411 $return = $value;
412 }
413 return $return;
a78c941 Empty value in Editor as NULL
jakubvrana authored
414 }
c64c4fd Adminer class
jakubvrana authored
415
416 /** Prints navigation after Adminer title
417 * @param string can be "auth" if there is no database connection or "db" if there is no database selected
418 * @return null
419 */
420 function navigation($missing) {
421 global $SELF, $dbh;
422 if ($missing != "auth") {
423 ob_flush();
424 flush();
425 $databases = get_databases();
426 ?>
b95f24e Editor: User friendly data editor
jakubvrana authored
427 <form action="" method="post">
428 <p>
429 <a href="<?php echo htmlspecialchars($SELF); ?>sql="><?php echo lang('SQL command'); ?></a>
430 <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
431 <input type="hidden" name="token" value="<?php echo $_SESSION["tokens"][$_GET["server"]]; ?>">
432 <input type="submit" name="logout" value="<?php echo lang('Logout'); ?>">
d2ba593 Browsers interpret <form><p></form> as <form><p></form></p>
jakubvrana authored
433 </p>
b95f24e Editor: User friendly data editor
jakubvrana authored
434 </form>
435 <form action="">
ace55ed HTML instead of XHTML
jakubvrana authored
436 <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
437 <?php if ($databases) { ?>
ace55ed HTML instead of XHTML
jakubvrana authored
438 <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
439 <?php } else { ?>
ace55ed HTML instead of XHTML
jakubvrana authored
440 <input name="db" value="<?php echo htmlspecialchars($_GET["db"]); ?>">
b95f24e Editor: User friendly data editor
jakubvrana authored
441 <?php } ?>
ace55ed HTML instead of XHTML
jakubvrana authored
442 <?php if (isset($_GET["sql"])) { ?><input type="hidden" name="sql" value=""><?php } ?>
443 <?php if (isset($_GET["schema"])) { ?><input type="hidden" name="schema" value=""><?php } ?>
444 <?php if (isset($_GET["dump"])) { ?><input type="hidden" name="dump" value=""><?php } ?>
445 <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
446 </p>
b95f24e Editor: User friendly data editor
jakubvrana authored
447 </form>
448 <?php
c64c4fd Adminer class
jakubvrana authored
449 if ($missing != "db" && strlen($_GET["db"])) {
450 $result = $dbh->query("SHOW TABLES");
451 if (!$result->num_rows) {
452 echo "<p class='message'>" . lang('No tables.') . "\n";
453 } else {
454 echo "<p>\n";
455 while ($row = $result->fetch_row()) {
456 echo '<a href="' . htmlspecialchars($SELF) . 'select=' . urlencode($row[0]) . '">' . lang('select') . '</a> ';
457 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
458 }
b95f24e Editor: User friendly data editor
jakubvrana authored
459 }
c64c4fd Adminer class
jakubvrana authored
460 $result->free();
461 echo '<p><a href="' . htmlspecialchars($SELF) . 'create=">' . lang('Create new table') . "</a>\n";
b95f24e Editor: User friendly data editor
jakubvrana authored
462 }
463 }
464 }
c64c4fd Adminer class
jakubvrana authored
465
2c445a8 Extensibility basics
jakubvrana authored
466 }
Something went wrong with that request. Please try again.