From c16c57b1b115fefc82dd1d5f10c568b93fe2949c Mon Sep 17 00:00:00 2001 From: jakubvrana Date: Sat, 11 Jul 2009 19:45:57 +0000 Subject: [PATCH] E-mail sending Change Adminer class to adminer_ functions.inc.php Unify includes Unify adminer_credentials() Don't use JUSH in Editor Separate identifier and description in breadcrumb Simplify where() git-svn-id: https://adminer.svn.sourceforge.net/svnroot/adminer/trunk@800 7c3ca157-0c34-0410-bff1-cbf682f78f5c --- adminer/download.inc.php | 2 +- adminer/edit.inc.php | 19 +++-- adminer/editing.js | 18 ++++ adminer/functions.js | 16 ---- adminer/include/adminer.inc.php | 136 ++++++++++++++++++++---------- adminer/include/bootstrap.inc.php | 21 ++++- adminer/include/design.inc.php | 21 ++--- adminer/include/editing.inc.php | 2 +- adminer/include/functions.inc.php | 28 +++++- adminer/include/lang.inc.php | 2 +- adminer/include/mysql.inc.php | 4 +- adminer/index.php | 17 +--- adminer/lang/cs.inc.php | 5 ++ adminer/lang/en.inc.php | 1 + adminer/select.inc.php | 55 +++++++++--- adminer/user.inc.php | 2 +- changes.txt | 2 + compile.php | 72 +++++++++------- editor/db.inc.php | 2 +- editor/editing.js | 3 + editor/include/adminer.inc.php | 102 +++++++++++++--------- editor/include/connect.inc.php | 4 +- editor/include/editing.inc.php | 1 + editor/include/export.inc.php | 2 +- editor/index.php | 16 +--- editor/lang/en.inc.php | 1 + lang.php | 2 +- 27 files changed, 350 insertions(+), 206 deletions(-) create mode 100644 editor/include/editing.inc.php diff --git a/adminer/download.inc.php b/adminer/download.inc.php index 8795b01d..355c74cd 100644 --- a/adminer/download.inc.php +++ b/adminer/download.inc.php @@ -1,5 +1,5 @@ result($dbh->query("SELECT " . idf_escape($_GET["field"]) . " FROM " . idf_escape($_GET["download"]) . " WHERE " . implode(" AND ", where($_GET)) . " LIMIT 1")); +echo $dbh->result($dbh->query("SELECT " . idf_escape($_GET["field"]) . " FROM " . idf_escape($_GET["download"]) . " WHERE " . where($_GET) . " LIMIT 1")); exit; // don't output footer diff --git a/adminer/edit.inc.php b/adminer/edit.inc.php index ba634fd3..b5791f68 100644 --- a/adminer/edit.inc.php +++ b/adminer/edit.inc.php @@ -1,5 +1,5 @@ $field) { @@ -10,7 +10,7 @@ foreach ($fields as $name => $field) { if ($_POST && !$error && !isset($_GET["select"])) { $location = ($_POST["insert"] ? $_SERVER["REQUEST_URI"] : $SELF . (isset($_GET["default"]) ? "table=" : "select=") . urlencode($_GET["edit"])); // "insert" to continue edit or insert if (isset($_POST["delete"])) { - query_redirect("DELETE FROM " . idf_escape($_GET["edit"]) . " WHERE " . implode(" AND ", $where) . " LIMIT 1", $location, lang('Item has been deleted.')); + query_redirect("DELETE FROM " . idf_escape($_GET["edit"]) . " WHERE $where LIMIT 1", $location, lang('Item has been deleted.')); } else { $set = array(); foreach ($fields as $name => $field) { @@ -33,13 +33,20 @@ if ($_POST && !$error && !isset($_GET["select"])) { if (isset($_GET["default"])) { query_redirect("ALTER TABLE " . idf_escape($_GET["edit"]) . implode(",", $set), $location, lang('Default values has been set.')); } elseif ($update) { - query_redirect("UPDATE " . idf_escape($_GET["edit"]) . " SET" . implode(",", $set) . "\nWHERE " . implode(" AND ", $where) . " LIMIT 1", $location, lang('Item has been updated.')); + query_redirect("UPDATE " . idf_escape($_GET["edit"]) . " SET" . implode(",", $set) . "\nWHERE $where LIMIT 1", $location, lang('Item has been updated.')); } else { query_redirect("INSERT INTO " . idf_escape($_GET["edit"]) . " SET" . implode(",", $set), $location, lang('Item has been inserted.')); } } } -page_header((isset($_GET["default"]) ? lang('Default values') : ($_GET["where"] || (isset($_GET["select"]) && !$_POST["clone"]) ? lang('Edit') : lang('Insert'))), $error, array((isset($_GET["default"]) ? "table" : "select") => $_GET["edit"]), $_GET["edit"]); + +$table_name = adminer_table_name(table_status($_GET["edit"])); +page_header( + (isset($_GET["default"]) ? lang('Default values') : ($_GET["where"] || (isset($_GET["select"]) && !$_POST["clone"]) ? lang('Edit') : lang('Insert'))), + $error, + array((isset($_GET["default"]) ? "table" : "select") => array($_GET["edit"], $table_name)), + $table_name +); unset($row); if ($_POST["save"]) { @@ -53,7 +60,7 @@ if ($_POST["save"]) { } $row = array(); if ($select) { - $result = $dbh->query("SELECT " . implode(", ", $select) . " FROM " . idf_escape($_GET["edit"]) . " WHERE " . implode(" AND ", $where) . " LIMIT 1"); + $result = $dbh->query("SELECT " . implode(", ", $select) . " FROM " . idf_escape($_GET["edit"]) . " WHERE $where LIMIT 1"); $row = $result->fetch_assoc(); $result->free(); } @@ -66,7 +73,7 @@ if ($fields) { unset($create); echo "\n"; foreach ($fields as $name => $field) { - echo ""; + echo ""; $value = (isset($row) ? (strlen($row[$name]) && ($field["type"] == "enum" || $field["type"] == "set") ? intval($row[$name]) : $row[$name]) : ($_POST["clone"] && $field["auto_increment"] ? "" : ($where ? $field["default"] : false)) diff --git a/adminer/editing.js b/adminer/editing.js index 98df0498..a4dc4065 100644 --- a/adminer/editing.js +++ b/adminer/editing.js @@ -1,5 +1,23 @@ // Adminer specific functions +function body_load() { + var script = document.createElement('script'); + script.src = '../externals/jush/jush.js'; + script.onload = function () { + jush.style('../externals/jush/jush.css'); + jush.highlight_tag('pre'); + jush.highlight_tag('code'); + } + script.onreadystatechange = function () { + if (script.readyState == 'loaded' || script.readyState == 'complete') { + script.onload(); + } + } + document.body.appendChild(script); +} + + + var added = '.', row_count; function re_escape(s) { diff --git a/adminer/functions.js b/adminer/functions.js index 3c2fd363..9c2e62f0 100644 --- a/adminer/functions.js +++ b/adminer/functions.js @@ -13,22 +13,6 @@ function verify_version(version) { document.body.appendChild(script); } -function load_jush() { - var script = document.createElement('script'); - script.src = '../externals/jush/jush.js'; - script.onload = function () { - jush.style('../externals/jush/jush.css'); - jush.highlight_tag('pre'); - jush.highlight_tag('code'); - } - script.onreadystatechange = function () { - if (script.readyState == 'loaded' || script.readyState == 'complete') { - script.onload(); - } - } - document.body.appendChild(script); -} - function form_check(el, name) { var elems = el.form.elements; for (var i=0; i < elems.length; i++) { diff --git a/adminer/include/adminer.inc.php b/adminer/include/adminer.inc.php index 08100477..fe94acf4 100644 --- a/adminer/include/adminer.inc.php +++ b/adminer/include/adminer.inc.php @@ -1,35 +1,86 @@ ' . lang('Table structure') . '', $table_status); +} + +/** Process and print select query before execution +* @param string query to be executed +* @return string +*/ +function adminer_select_query($query) { + global $SELF; + // 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 + $return = call_adminer('select_query', "", $query); + if (!$return) { + echo "

" . htmlspecialchars($query) . " " . lang('Edit') . "

\n"; + return $query; } - - function server() { - return $_GET["server"]; - } - - function username() { - return $_SESSION["usernames"][$_GET["server"]]; - } - - function password() { - return $_SESSION["passwords"][$_GET["server"]]; - } - - function table_name($row) { - return htmlspecialchars($row["Name"]); - } - - function field_name($fields, $key) { - return htmlspecialchars($key); - } - - function navigation($missing) { - global $SELF; - if ($missing != "auth") { - $databases = get_databases(); - ?> + return $return; +} + +/** Query printed after execution in the message +* @param string executed query +* @return string +*/ +function adminer_message_query($query) { + global $SELF; + $id = "sql-" . count($_SESSION["messages"]); + return call_adminer('message_query', " " . lang('SQL command') . "', $query); +} + +/** Prints navigation after Adminer title +* @param string can be "auth" if there is no database connection or "db" if there is no database selected +* @return bool true if default navigation should be printed +*/ +function adminer_navigation($missing) { + global $SELF; + if (call_adminer('navigation', true, $missing) && $missing != "auth") { + $databases = get_databases(); + ?>

@@ -52,22 +103,19 @@ class AdminerBase {

" . lang('No tables.') . "

\n"; - } else { - echo "

\n"; - foreach ($table_status as $row) { - echo '' . lang('select') . ' '; - echo '' . $this->table_name($row) . "
\n"; - } - echo "

\n"; + if ($missing != "db" && strlen($_GET["db"])) { + $table_status = table_status(); + if (!$table_status) { + echo "

" . lang('No tables.') . "

\n"; + } else { + echo "

\n"; + foreach ($table_status as $row) { + echo '' . lang('select') . ' '; + echo '' . adminer_table_name($row) . "
\n"; } - echo '

' . lang('Create new table') . "

\n"; + echo "

\n"; } + echo '

' . lang('Create new table') . "

\n"; } } } - -$adminer = (class_exists("Adminer") ? new Adminer : new AdminerBase); diff --git a/adminer/include/bootstrap.inc.php b/adminer/include/bootstrap.inc.php index 7b539425..79f3699b 100644 --- a/adminer/include/bootstrap.inc.php +++ b/adminer/include/bootstrap.inc.php @@ -24,6 +24,9 @@ if (isset($_GET["file"])) { } elseif ($_GET["file"] == "functions.js") { header("Content-Type: text/javascript"); ?>compile_file('functions.js', 'JSMin::minify')compile_file('editing.js', 'JSMin::minify') @@ -9,17 +9,17 @@ function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") { -<?php echo $title . (strlen($title2) ? ": " . htmlspecialchars($title2) : "") . (strlen($_GET["server"]) && $_GET["server"] != "localhost" ? htmlspecialchars("- $_GET[server]") : "") . " - " . $adminer->name(); ?> - +<?php echo $title . (strlen($title2) ? ": " . htmlspecialchars($title2) : "") . (strlen($_GET["server"]) && $_GET["server"] != "localhost" ? htmlspecialchars("- $_GET[server]") : "") . " - " . adminer_name(); ?> + -"> +"> - +
' . htmlspecialchars($_GET["db"]) . ' » '; } foreach ($breadcrumb as $key => $val) { - if (strlen($val)) { - echo '' . htmlspecialchars($val) . ' » '; + $desc = (is_array($val) ? $val[1] : $val); + if (strlen($desc)) { + echo '' . htmlspecialchars($desc) . ' » '; } } } @@ -57,16 +58,16 @@ function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") { } function page_footer($missing = false) { - global $SELF, $VERSION, $dbh, $adminer; + global $SELF, $VERSION, $dbh; ?>
diff --git a/adminer/include/editing.inc.php b/adminer/include/editing.inc.php index 2c71c0c0..96d64fd6 100644 --- a/adminer/include/editing.inc.php +++ b/adminer/include/editing.inc.php @@ -58,7 +58,7 @@ function edit_fields($fields, $collations, $type = "TABLE", $allowed = 0, $forei + $field) { diff --git a/adminer/include/functions.inc.php b/adminer/include/functions.inc.php index d95ee7ed..64e050c3 100644 --- a/adminer/include/functions.inc.php +++ b/adminer/include/functions.inc.php @@ -73,7 +73,7 @@ function where($where) { $key = bracket_escape($key, "back"); $return[] = (preg_match('~^[A-Z0-9_]+\\(`(?:[^`]+|``)+`\\)$~', $key) ? $key : idf_escape($key)) . " IS NULL"; } - return $return; + return implode(" AND ", $return); } function where_check($val) { @@ -100,10 +100,9 @@ function redirect($location, $message = null) { function query_redirect($query, $location, $message, $redirect = true, $execute = true, $failed = false) { global $dbh, $error, $SELF; - $id = "sql-" . count($_SESSION["messages"]); $sql = ""; if ($query) { - $sql = " " . lang('SQL command') . "'; + $sql = adminer_message_query($query); $_SESSION["history"][$_GET["server"]][$_GET["db"]][] = $query; } if ($execute) { @@ -367,3 +366,26 @@ function dump_csv($row) { } echo implode(",", $row) . "\n"; } + +function is_email($email) { + $atom = '[-a-z0-9!#$%&\'*+/=?^_`{|}~]'; // characters of local-name + $domain = '[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])'; // one domain component + return eregi("^$atom+(\\.$atom+)*@($domain?\\.)+$domain\$", $email); +} + +function email_header($header) { + return chunk_split("=?UTF-8?B?" . base64_encode($header), 67, "\n "); // iconv_mime_encode requires PHP 5, imap_8bit requires IMAP extension +} + +function call_adminer($method, $default, $arg1 = null, $arg2 = null) { + static $adminer; + if (!isset($adminer)) { + $adminer = (class_exists('Adminer') ? new Adminer : false); // user defined class + } + // maintains original method name in minification + if (method_exists($adminer, $method)) { + // can use func_get_args() and call_user_func_array() + return $adminer->$method($arg1, $arg2); + } + return $default; //! $default is evaluated even if not neccessary +} diff --git a/adminer/include/lang.inc.php b/adminer/include/lang.inc.php index c0ee3a34..3f26478c 100644 --- a/adminer/include/lang.inc.php +++ b/adminer/include/lang.inc.php @@ -1,5 +1,5 @@ 'English', // Jakub Vrána - http://php.vrana.cz diff --git a/adminer/include/mysql.inc.php b/adminer/include/mysql.inc.php index b44feaa3..e55614a3 100644 --- a/adminer/include/mysql.inc.php +++ b/adminer/include/mysql.inc.php @@ -204,9 +204,9 @@ $types = array( $unsigned = array("unsigned", "zerofill", "unsigned zerofill"); function connect() { - global $adminer; $dbh = new Min_DB; - if ($dbh->connect($adminer->server(), $adminer->username(), $adminer->password())) { + $credentials = adminer_credentials(); + if ($dbh->connect($credentials[0], $credentials[1], $credentials[2])) { $dbh->query("SET SQL_QUOTE_SHOW_CREATE=1"); $dbh->query("SET NAMES utf8"); return $dbh; diff --git a/adminer/index.php b/adminer/index.php index 5c07c190..80efcc17 100644 --- a/adminer/index.php +++ b/adminer/index.php @@ -7,21 +7,6 @@ */ include "./include/bootstrap.inc.php"; -include "./include/version.inc.php"; -include "./include/functions.inc.php"; -include "./include/lang.inc.php"; -include "./lang/$LANG.inc.php"; -include "./include/adminer.inc.php"; -include "./include/design.inc.php"; -if (isset($_GET["coverage"])) { - include "./coverage.inc.php"; -} -include "./include/pdo.inc.php"; -include "./include/mysql.inc.php"; -include "./include/auth.inc.php"; -include "./include/connect.inc.php"; -include "./include/editing.inc.php"; -include "./include/export.inc.php"; $enum_length = '\'(?:\'\'|[^\'\\\\]+|\\\\.)*\'|"(?:""|[^"\\\\]+|\\\\.)*"'; $inout = array("IN", "OUT", "INOUT"); @@ -54,7 +39,7 @@ if (isset($_GET["download"])) { // edit form is used for default values and distinguished by checking isset($_GET["default"]) in edit.inc.php $_GET["edit"] = $_GET["default"]; } - if (isset($_GET["select"]) && $_POST && (!$_POST["delete"] && !$_POST["export"] && !$_POST["import"] && !$_POST["save"])) { + if (isset($_GET["select"]) && $_POST && (!$_POST["delete"] && !$_POST["export"] && !$_POST["import"] && !$_POST["save"] && !$_POST["email"])) { // POST form on select page is used to edit or clone data $_GET["edit"] = $_GET["select"]; } diff --git a/adminer/lang/cs.inc.php b/adminer/lang/cs.inc.php index 6fb82aed..5925ba8e 100644 --- a/adminer/lang/cs.inc.php +++ b/adminer/lang/cs.inc.php @@ -216,4 +216,9 @@ $translations = array( 'History' => 'Historie', 'Variables' => 'Proměnné', 'Source and target columns must have the same data type and there must be an index on the target columns.' => 'Zdrojové a cílové sloupce musí mít stejný datový typ a nad cílovými sloupci musí být definován index.', + 'E-mail' => 'E-mail', + 'From' => 'Odesílatel', + 'Subject' => 'Předmět', + 'Send' => 'Odeslat', + '%d e-mail(s) have been sent.' => array('Byl odeslán %d e-mail.', 'Byly odeslány %d e-maily.', 'Bylo odesláno %d e-mailů.'), ); diff --git a/adminer/lang/en.inc.php b/adminer/lang/en.inc.php index 414c91a9..d2df76db 100644 --- a/adminer/lang/en.inc.php +++ b/adminer/lang/en.inc.php @@ -7,4 +7,5 @@ $translations = array( '%d row(s)' => array('%d row', '%d rows'), '%d item(s) have been affected.' => array('%d item have been affected.', '%d items have been affected.'), '%d row(s) has been imported.' => array('%d row has been imported.', '%d rows has been imported.'), + '%d e-mail(s) have been sent.' => array('%d e-mail has been sent.', '%d e-mails have been sent.'), ); diff --git a/adminer/select.inc.php b/adminer/select.inc.php index 2d6b3f47..afb2ffd1 100644 --- a/adminer/select.inc.php +++ b/adminer/select.inc.php @@ -13,7 +13,7 @@ $columns = array(); // selectable columns unset($text_length); foreach ($fields as $key => $field) { if (isset($field["privileges"]["select"])) { - $columns[] = $key; + $columns[$key] = adminer_field_name($fields, $key); //! numeric $key is problematic in optionlist() if (preg_match('~text|blob~', $field["type"])) { $text_length = (isset($_GET["text_length"]) ? $_GET["text_length"] : "100"); } @@ -24,8 +24,8 @@ foreach ($fields as $key => $field) { $select = array(); // select expressions, empty for * $group = array(); // expressions without aggregation - will be used for GROUP BY if an aggregation function is used foreach ((array) $_GET["columns"] as $key => $val) { - if ($val["fun"] == "count" || (in_array($val["col"], $columns, true) && (!$val["fun"] || in_array($val["fun"], $functions) || in_array($val["fun"], $grouping)))) { - $select[$key] = (in_array($val["col"], $columns, true) ? (!$val["fun"] ? idf_escape($val["col"]) : ($val["fun"] == "distinct" ? "COUNT(DISTINCT " : strtoupper("$val[fun](")) . idf_escape($val["col"]) . ")") : "COUNT(*)"); + if ($val["fun"] == "count" || (isset($columns[$val["col"]]) && (!$val["fun"] || in_array($val["fun"], $functions) || in_array($val["fun"], $grouping)))) { + $select[$key] = (isset($columns[$val["col"]]) ? ($val["fun"] ? ($val["fun"] == "distinct" ? "COUNT(DISTINCT " : strtoupper("$val[fun](")) . idf_escape($val["col"]) . ")" : idf_escape($val["col"])) : "COUNT(*)"); if (!in_array($val["fun"], $grouping)) { $group[] = $select[$key]; } @@ -61,7 +61,7 @@ foreach ((array) $_GET["where"] as $val) { } $order = array(); // order expressions - will be joined by comma foreach ((array) $_GET["order"] as $key => $val) { - if (in_array($val, $columns, true) || in_array($val, $select, true)) { + if (isset($columns[$val]) || in_array($val, $select, true)) { $order[] = idf_escape($val) . (isset($_GET["desc"][$key]) ? " DESC" : ""); } } @@ -77,7 +77,7 @@ if ($_POST && !$error) { $union = array(); foreach ($_POST["check"] as $val) { // where may not be unique so OR can't be used - $union[] = "(SELECT $from " . ($where ? "AND " : "WHERE ") . implode(" AND ", where_check($val)) . $group_by . " LIMIT 1)"; + $union[] = "(SELECT $from " . ($where ? "AND " : "WHERE ") . where_check($val) . $group_by . " LIMIT 1)"; } dump_data($_GET["select"], "INSERT", implode(" UNION ALL ", $union)); } else { @@ -85,7 +85,18 @@ if ($_POST && !$error) { } exit; } - if (!$_POST["import"]) { // edit + if ($_POST["email"]) { + $sent = 0; + if ($_POST["all"] || $_POST["check"]) { + $field = idf_escape($_POST["email_field"]); + $result = $dbh->query("SELECT DISTINCT $field FROM " . idf_escape($_GET["select"]) . " WHERE $field IS NOT NULL AND $field != ''" . ($where ? " AND " . implode(" AND ", $where) : "") . ($_POST["all"] ? "" : " AND ((" . implode(") OR (", array_map('where_check', $_POST["check"])) . "))")); + while ($row = $result->fetch_row()) { + $sent += mail($row[0], email_header($_POST["email_subject"]), $_POST["email_message"], "MIME-Version: 1.0\nContent-Type: text/plain; charset=utf-8\nContent-Transfer-Encoding: 8bit" . ($_POST["email_from"] ? "\nFrom: " . email_header($_POST["email_from"]) : "")); + } + $result->free(); + } + redirect(remove_from_uri(), lang('%d e-mail(s) have been sent.', $sent)); + } elseif (!$_POST["import"]) { // edit $result = true; $affected = 0; $command = ($_POST["delete"] ? ($_POST["all"] && !$where ? "TRUNCATE " : "DELETE FROM ") : ($_POST["clone"] ? "INSERT INTO " : "UPDATE ")) . idf_escape($_GET["select"]); @@ -107,9 +118,8 @@ if ($_POST && !$error) { $affected = $dbh->affected_rows; } else { foreach ((array) $_POST["check"] as $val) { - parse_str($val, $check); // where may not be unique so OR can't be used - $result = queries($command . "\nWHERE " . implode(" AND ", where($check)) . " LIMIT 1"); + $result = queries($command . "\nWHERE " . where_check($val) . " LIMIT 1"); if (!$result) { break; } @@ -143,14 +153,15 @@ if ($_POST && !$error) { $error = lang('Unable to upload a file.'); } } -page_header(lang('Select') . ": " . $adminer->table_name($table_status), $error); + +page_header(lang('Select') . ": " . adminer_table_name($table_status), $error); echo "

"; if (isset($rights["insert"])) { //! pass search values forth and back echo '' . lang('New item') . ' '; } -echo '' . lang('Table structure') . ''; +echo adminer_select_links($table_status); echo "

\n"; if (!$columns) { @@ -202,7 +213,7 @@ if (!$columns) { echo '
' . lang('Sort') . "
1 ? "" : " class='hidden'") . ">\n"; $i = 0; foreach ((array) $_GET["order"] as $key => $val) { - if (in_array($val, $columns, true)) { + if (isset($columns[$val])) { echo "
"; echo "
\n"; $i++; @@ -228,7 +239,7 @@ if (!$columns) { echo "\n"; $query = "SELECT " . (count($group) < count($select) ? "SQL_CALC_FOUND_ROWS " : "") . $from . $group_by . (strlen($limit) ? " LIMIT " . intval($limit) . (intval($_GET["page"]) ? " OFFSET " . ($limit * $_GET["page"]) : "") : ""); - echo "

" . htmlspecialchars($query) . " " . lang('Edit') . "

\n"; + $query = adminer_select_query($query); $result = $dbh->query($query); if (!$result) { @@ -245,18 +256,23 @@ if (!$columns) { } } + $email_fields = array(); + echo "
" . $adminer->field_name($fields, $name) . "
" . adminer_field_name($fields, $name) . "
"; ?>"; ?>
\n"; for ($j=0; $row = $result->fetch_assoc(); $j++) { if (!$j) { echo ''; foreach ($row as $key => $val) { - echo ''; + echo ''; } echo "\n"; } $unique_idf = implode('&', unique_idf($row, $indexes)); //! don't use aggregation functions echo ''; foreach ($row as $key => $val) { + if (strlen($val) && (!isset($email_fields[$key]) || $email_fields[$key])) { + $email_fields[$key] = is_email($val); //! filled e-mails may be contained on other pages + } if (!isset($val)) { $val = "NULL"; } elseif (preg_match('~blob|binary~', $fields[$key]["type"]) && !is_utf8($val)) { @@ -319,6 +335,19 @@ if (!$columns) { } $result->free(); echo "
" . lang('CSV Import') . "
\n"; + + //! Editor only + $email_fields = array_filter($email_fields); + if ($email_fields) { + echo '
' . lang('E-mail') . "
\n"; + } + echo "\n"; } } diff --git a/adminer/user.inc.php b/adminer/user.inc.php index 5c59af8c..cafaba16 100644 --- a/adminer/user.inc.php +++ b/adminer/user.inc.php @@ -107,7 +107,7 @@ if ($_POST && !$error) { } } } -page_header((isset($_GET["host"]) ? lang('Username') . ": " . htmlspecialchars("$_GET[user]@$_GET[host]") : lang('Create user')), $error, array("privileges" => lang('Privileges'))); +page_header((isset($_GET["host"]) ? lang('Username') . ": " . htmlspecialchars("$_GET[user]@$_GET[host]") : lang('Create user')), $error, array("privileges" => array('', lang('Privileges')))); if ($_POST) { $row = $_POST; diff --git a/changes.txt b/changes.txt index 9a74275c..ba173e39 100644 --- a/changes.txt +++ b/changes.txt @@ -1,5 +1,7 @@ Adminer 1.12.0: Editor: User friendly data editor +Customization: Adminer class +E-mail sending Create single column foreign key in table structure Adminer 1.11.1 (released 2009-07-03): diff --git a/compile.php b/compile.php index 26da6b05..73eb3b51 100644 --- a/compile.php +++ b/compile.php @@ -17,43 +17,23 @@ function remove_lang($match) { } $lang_ids = array(); // global variable simplifies usage in a callback function + function lang_ids($match) { global $lang_ids; - return 'lang(' . $lang_ids[stripslashes($match[1])] . $match[2]; + $lang_id = &$lang_ids[stripslashes($match[1])]; + if (!isset($lang_id)) { + $lang_id = count($lang_ids) - 1; + } + return ($_COOKIE["adminer_lang"] ? $match[0] : "lang($lang_id$match[2]"); } function put_file($match) { - global $lang_ids, $project; + global $project; if (basename($match[2]) == '$LANG.inc.php') { - if ($_COOKIE["adminer_lang"]) { - return ""; - } - $return = ""; - foreach (glob(dirname(__FILE__) . "/$project/lang/*.inc.php") as $filename) { - // assign translation numbers - include $filename; - foreach ($translations as $key => $val) { - if (!isset($lang_ids[$key])) { - $lang_ids[$key] = count($lang_ids); - } - } - } - foreach (glob(dirname(__FILE__) . "/$project/lang/*.inc.php") as $filename) { - include $filename; // reassign $translations - $translation_ids = array_flip($lang_ids); - foreach ($translations as $key => $val) { - $translation_ids[$lang_ids[$key]] = $val; - } - $return .= 'case "' . basename($filename, '.inc.php') . '": $translations = array('; - foreach ($translation_ids as $val) { - $return .= (is_array($val) ? "array('" . implode("', '", array_map('add_apo_slashes', $val)) . "')" : "'" . add_apo_slashes($val) . "'") . ", "; - } - $return = substr($return, 0, -2) . "); break;\n"; - } - return "switch (\$LANG) {\n$return}\n"; + return $match[0]; // processed later } $return = file_get_contents(dirname(__FILE__) . "/$project/$match[2]"); - if ($match[2] != "./include/lang.inc.php" || !$_COOKIE["adminer_lang"]) { + if (basename($match[2]) != "lang.inc.php" || !$_COOKIE["adminer_lang"]) { $tokens = token_get_all($return); // to find out the last token return "?>\n$return" . (in_array($tokens[count($tokens) - 1][0], array(T_CLOSE_TAG, T_INLINE_HTML), true) ? " $val) { + if (isset($val)) { + $translation_ids[$lang_ids[$key]] = $val; + } + } + $return .= "\tcase \"" . basename($filename, '.inc.php') . '": $translations = array('; + foreach ($translation_ids as $val) { + $return .= (is_array($val) ? "array('" . implode("', '", array_map('add_apo_slashes', $val)) . "')" : "'" . add_apo_slashes($val) . "'") . ", "; + } + $return = substr($return, 0, -2) . "); break;\n"; + } + return "switch (\$LANG) {\n$return}\n"; +} + function short_identifier($number, $chars) { $return = ''; while ($number >= 0) { @@ -113,13 +116,17 @@ function php_shrink($input) { $space = ''; $output = ''; $in_echo = false; + $doc_comment = false; // include only first /** for (reset($tokens); list($i, $token) = each($tokens); ) { if (!is_array($token)) { $token = array(0, $token); } - if ($token[0] == T_COMMENT || $token[0] == T_WHITESPACE) { + if ($token[0] == T_COMMENT || $token[0] == T_WHITESPACE || ($token[0] == T_DOC_COMMENT && $doc_comment)) { $space = "\n"; } else { + if ($token[0] == T_DOC_COMMENT) { + $doc_comment = true; + } if ($token[0] == T_VAR) { $shortening = false; } elseif (!$shortening) { @@ -186,14 +193,15 @@ $filename = $project . ($_COOKIE["adminer_lang"] ? "-$_COOKIE[adminer_lang]" : " $file = file_get_contents(dirname(__FILE__) . "/$project/index.php"); $file = preg_replace('(' . str_replace(' ', '\\s*', preg_quote(' if (isset($_GET["coverage"])) { include "./coverage.inc.php"; }')) . ')', '', $file); $file = preg_replace_callback('~\\b(include|require) "([^"]*)";~', 'put_file', $file); +$file = preg_replace_callback('~\\b(include|require) "([^"]*)";~', 'put_file', $file); // bootstrap.inc.php $file = preg_replace("~if \\(isset\\(\\\$_SESSION\\[\"coverage.*\n}\n| && !isset\\(\\\$_SESSION\\[\"coverage\"\\]\\)~sU", '', $file); +$file = preg_replace_callback("~lang\\('((?:[^\\\\']+|\\\\.)*)'([,)])~s", 'lang_ids', $file); +$file = preg_replace_callback('~\\b(include|require) "([^"]*\\$LANG.inc.php)";~', 'put_file_lang', $file); if ($_COOKIE["adminer_lang"]) { // single language version $file = preg_replace_callback("~(<\\?php\\s*echo )?lang\\('((?:[^\\\\']+|\\\\.)*)'([,)])(;\\s*\\?>)?~s", 'remove_lang', $file); $file = str_replace("\n", "", $file); $file = str_replace('', $_COOKIE["adminer_lang"], $file); -} else { - $file = preg_replace_callback("~lang\\('((?:[^\\\\']+|\\\\.)*)'([,)])~s", 'lang_ids', $file); } $file = preg_replace_callback("~compile_file\\('([^']+)', '([^']+)'\\)~", 'compile_file', $file); // integrate static files $replace = 'htmlspecialchars(preg_replace("~\\\\\\\\?.*~", "", $_SERVER["REQUEST_URI"])) . "?file=\\1&version=' . $VERSION; diff --git a/editor/db.inc.php b/editor/db.inc.php index 8e61d318..b8529a09 100644 --- a/editor/db.inc.php +++ b/editor/db.inc.php @@ -1,2 +1,2 @@ $val) { + $on[] = "`t0`." . idf_escape($val) . " = `t$i`." . idf_escape($foreign_key["target"][$key]); + } + //~ $join .= "\nLEFT JOIN " . idf_escape($foreign_key["table"]) . " AS `t$i` ON " . implode(" AND ", $on); + //! use in select + $i++; } - - function server() { - return ""; + $query = preg_replace("~((?:[^'`]*|'(?:[^'\\\\]*|\\\\.)+')+)(`((?:[^`]+|``)*)`)~", '\\1`t0`.\\2', $query); // don't match ` inside '' + $query = preg_replace('~ FROM `t0`.(`((?:[^`]+|``)*)`) ?~', "\nFROM \\1 AS `t0`" . addcslashes($join, '\\$') . "\n", $query); + $return = call_adminer('select_query', "", $query); + if (!$return) { + echo "\n"; + return $query; } - - function username() { - return ""; - } - - function password() { - return ""; - } - - function table_name($row) { - return htmlspecialchars(strlen($row["Comment"]) ? $row["Comment"] : $row["Name"]); - } - - function field_name($fields, $key) { - return htmlspecialchars(strlen($fields[$key]["comment"]) ? $fields[$key]["comment"] : $key); - } - - function navigation($missing) { - global $SELF; - if ($missing != "auth") { - ?> + return $return; +} + +function adminer_message_query($query) { + return call_adminer('message_query', "", $query); +} + +function adminer_navigation($missing) { + global $SELF; + if (call_adminer('navigation', true, $missing) && $missing != "auth") { + ?>

" /> @@ -36,20 +61,19 @@ class AdminerBase {

" . lang('No tables.') . "

\n"; - } else { - echo "

\n"; - foreach ($table_status as $row) { - echo '' . $this->table_name($row) . "
\n"; + if ($missing != "db") { + $table_status = table_status(); + if (!$table_status) { + echo "

" . lang('No tables.') . "

\n"; + } else { + echo "

\n"; + foreach ($table_status as $row) { + if (isset($row["Engine"])) { // ignore views + echo '' . adminer_table_name($row) . "
\n"; } - echo "

\n"; } + echo "

\n"; } } } } - -$adminer = (class_exists("Adminer") ? new Adminer : new AdminerBase); diff --git a/editor/include/connect.inc.php b/editor/include/connect.inc.php index d542a14f..f1d3f89d 100644 --- a/editor/include/connect.inc.php +++ b/editor/include/connect.inc.php @@ -1,3 +1,3 @@ select_db($_GET["db"]); +$_GET["db"] = ""; // used here and there by Adminer +$dbh->select_db(adminer_database()); diff --git a/editor/include/editing.inc.php b/editor/include/editing.inc.php new file mode 100644 index 00000000..b3d9bbc7 --- /dev/null +++ b/editor/include/editing.inc.php @@ -0,0 +1 @@ + array('%d row', '%d rows'), '%d item(s) have been affected.' => array('%d item have been affected.', '%d items have been affected.'), '%d row(s) has been imported.' => array('%d row has been imported.', '%d rows has been imported.'), + '%d e-mail(s) have been sent.' => array('%d e-mail has been sent.', '%d e-mails have been sent.'), ); diff --git a/lang.php b/lang.php index b43c277d..f7a204e5 100644 --- a/lang.php +++ b/lang.php @@ -14,7 +14,7 @@ if (isset($_SERVER["argv"][1])) { } } -preg_match_all('~\\b(include|require) "([^"]*)";~', file_get_contents(dirname(__FILE__) . "/$project/index.php"), $matches); +preg_match_all('~\\b(include|require) "([^"]*)";~', file_get_contents(dirname(__FILE__) . "/$project/index.php") . file_get_contents(dirname(__FILE__) . "/adminer/include/bootstrap.inc.php"), $matches); $filenames = $matches[2]; $filenames[] = "index.php";
' . $adminer->field_name($fields, $key) . '' . adminer_field_name($fields, $key) . '
' . (count($select) != count($group) || information_schema($_GET["db"]) ? '' : ' ' . lang('edit') . '') . '