如题所述
第1个回答 2016-08-02
编译
当的大小 adminer.php然后我开始增长已经意识到是明智的分割文件管理的发展。尽管如此,我仍然想要的文件我已经创建了一个编译脚本,连接起来的文件。
因为一切都是一个文件,管理员不能使用通常的URL alter.php?table=X和操作必须通过在查询字符串中。而不是常见的 ?action=alter&table=X,我有更紧凑的替代使用 ?alter=X。然后一系列中央脚本 if (isset($_GET["..."]))而不是一个大 switch ($_GET["action"])。有一个包括内部的特定功能 if这些包括编译构建过程中的一个文件:
<?php
function include_file($match) {
$file = file_get_contents($match[1]);
$token = end(token_get_all($file));
$php = (is_array($token) && in_array($token[0], array(T_CLOSE_TAG, T_INLINE_HTML)));
return "?>\n$file" . ($php ? "<?php" : "");
}
$file = preg_replace_callback('~include "([^"]+)";~', 'include_file', $file);
?>
这个代码不是普遍可用,因为它只发现 include ""变体。它将需要处理的文件token_get_all功能和找到所有包括变体。的 _once变异将会更加困难。也可以有一个全球水平返回.
管理也使用一些外部文件——样式表,快捷方式图标和图像。有几种可能的访问这些文件的方法:
他们可以集成在主HTML代码——样式表 <style>标签,利用图像 data:协议。这种方法的问题是,Internet Explorer 8 <不支持这个协议。第二个问题是,浏览器需要反复与每��页面传输这些数据。
可以从外部服务器下载的文件。会有问题,如果服务器不可用或如果计算机的运行管理是没有互联网连接。然而这种方法是使用SQL查询语法高亮显示,这是一个可选的特性——管理使用JavaScript语法高亮显示JUSH对于这个任务。
文件可以被集成的源代码和一个特殊的参数将为他们服务。你有没有注意到PHP输出的标志吗phpinfo吗?PHP从本地服务器下载它特殊的查询字符串 ?=PHP…。管理使用类似的方法,节省了Base64编码的文件的源代码(编码不是必需的,但它简化了脚本编辑共同的文本编辑器)。这种方法允许HTTP缓存管理利用的外部文件。
注意:PHP 5.3附带了一个支持PHP档案通过phar扩展。这个扩展,可以装几个文件归档和从PHP访问内部的文件归档。使用webPhar包装方法允许大多数PHP应用程序创建phar归档和有指令phpMyAdmin的版本PHP手册。管理不使用这个扩展和使用PHP > = 4.3和PHP > = 5.0。
缩小
编译脚本也贬低代码——它删除评论和修剪空白。大卫的缩小代码是基于工作Grudl谁使用它为他的才华横溢的库Texy,dibi和Nette。这个函数是比内部功能更有效php_strip_whitespace.
<?php
function php_shrink($input) {
$set = array_flip(preg_split('//', '!"#$&\'()*+,-./:;<=>?@[\]^`{|}'));
$space = '';
$output = '';
foreach (token_get_all($input) as $token) {
if (!is_array($token)) {
$token = array(0, $token);
}
if ($token[0] == T_COMMENT || $token[0] == T_WHITESPACE) {
$space = "\n";
} else {
if (isset($set[substr($output, -1)]) || isset($set[$token[1][0]])) {
$space = '';
}
$output .= $space . $token[1];
$space = '';
}
}
return $output;
}
?>
当前版本也缩短用户变量和函数的名字。它发现的变量和函数的源代码token_get_all功能和通过短标识符替换它们。缩短过程跳过内部PHP变量和函数。也有可能缩短他们但它会更复杂,它将有一个的性能损失。一些PHP变量有其超全局特性是必要的别名功能内的全球化。
内部函数可以包含在包络函数较短的名字。然而这种方法是有问题的,因为PHP函数可以有可选参数没有默认值(这个函数的例子写入文件这检测传递的参数的数量而不是它们的值)。通用函数func_get_args不使用引用相反。
替代的方法是定义一个变量为一个内部函数(例如 $fw = 'fwrite'通过这个变量)和调用的函数: $fw($fp, $string)。管理但不使用没有方法,因为它将使应用程序慢下来。
的缩小从CSS和去掉空格也PHP版本的个贬低的JavaScript代码。
文件会小得多的如果它被压缩。PHP支持几个压缩算法,但只有通过一个扩展。我在想用PHP编写的一个简单的减压函数将解压缩文件的其他部分,但需要eval解压缩代码和每个人都知道eval是恶(原因之一是不兼容PHP加速器)。因此,代码不是压缩但只有缩小。
翻译
我在英语发展管理。还有一个捷克版本(这是我的母语)从一开始就和管理目前有11种语言。所有消息是由一个简单的函数,它检查当前的语言并返回相应的翻译。
一个简单的函数检测的语言 Accept-Language标题:
<?php
function acceptable_language($translations) {
$accept_language = array();
preg_match_all('~([-a-z]+)(;q=([0-9.]+))?~', strtolower($_SERVER["HTTP_ACCEPT_LANGUAGE"]), $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$accept_language[$match[1]] = (isset($match[3]) ? $match[3] : 1);
}
arsort($accept_language);
foreach ($accept_language as $lang => $q) {
if (isset($translations[$lang])) {
return $lang;
}
$lang = preg_replace('~-.*~', '', $lang);
if (!isset($accept_language[$lang]) && isset($translations[$lang])) {
return $lang;
}
}
return false;
}
?>
这个函数的调用者保存语言一个cookie在第一次检测。用户可以随时改变语言在同一页面。保存页面语言饼干是一个非常糟糕的实践在一个公共网站,因为搜索引擎才能指数只有一个版本的页面。然而在管理可接受的,因为搜索引擎不索引页面和页面的主要内容(例如表结构)在所有的语言都是一样的。语言存储在cookie的奖励是一个简单的URL而仍有可能执行语言通过语言标识符在查询字符串中。
翻译存储在一个简单的数组,其中的关键是一个消息标识符(这是一个英语版本的消息,并使用它如果翻译不存在),该值是一个字符串翻译。值是包含一些更有趣的信息(如“一行”或“两行”)。大多数语言有不同的单数和复数形式,但有些语言(例如捷克语或俄语)使用更多的复数形式取决于数量(如捷克“皮沃- 1”,“2 piva”或“5 piv”啤酒)。消息和数据都存储在一个数组,而不是字符串和管理包含一个简单的逻辑语言选择正确的形式取决于数量。
默认情况下,管理员有所有语言。编译转换翻译数组值只和改变了标识符数字保存一些字节每个翻译大约需要4 KB。编译脚本也能够创建一个单一的语言版本,它完全消除了语言翻译功能和检测。这个文件只需要111 KB的英文版本管理1.10.1。
数据库扩展抽象
PHP允许通过三个扩展:连接到一个MySQL数据库MySQL,mysqli pdo_mysql。管理支持他们和包含这些扩展的一个简单的抽象层。这个抽象层模拟的子集mysqli和mysqli_result类为所有三个扩展。
PDO的支持是有些微妙,因为PDO使用异常来报告连接错误。管理员不能用通常的 try块来捕捉这些异常,因为它运行在PHP 4。一切都在一个文件所以PDO支持不能有条件地只包括在PHP 5。解决方案是使用set_exception_handler函数来处理连接错误。PHP 4还不支持类常量在语法层面上的源代码使用数值常量代替。
安全
最重要的部分的安全管理是惊人的防御跨���点请求伪造。CSRF攻击者可以执行操作在一个登录的用户的名字。管理员登录信息存储在一个标准的PHP会话所以可以发送cookie会话标识符和抵御CSRF是必要的。管理员发送一个令牌与每个形式和在执行操作前检查这个令牌的形式。令牌保护甚至经常被遗忘的注销动作在其他web应用程序。
非常重要的也是防止跨站点脚本。输出的HTML代码存储在数据库中可以透露敏感信息攻击者htmlspecialchars函数每输出函数逃。
管理也防止SQL注入,但它不是安全的名义——如果攻击者已经登录到管理员然后她可以执行任何SQL命令的SQL代码页。因此,防止SQL注入只是一个适当的操作与用户输入的副作用——用户可以通过任何数据到数据库中。如果管理检测magic_quotes_gpc然后它中和这个指令,并使用适当的转义函数只有当传递到MySQL的数据。
<?php
if (get_magic_quotes_gpc()) {
$process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
while (list($key, $val) = each($process)) {
foreach ($val as $k => $v) {
unset($process[$key][$k]);
if (is_array($v)) {
$process[$key][stripslashes($k)] = $v;
$process[] = &$process[$key][stripslashes($k)];
} else {
$process[$key][stripslashes($k)] = stripslashes($v);
}
}
}
unset($process);
}
?>
调用的session_regenerate_id登录后防止会话固定。
管理包含的每一个页面 robots: noindex元信息隐藏页面的搜索引擎。
登录表单
管理数据库证书保存到一个会话,检查每一页。如果数据库不能授权用户登录表单是直接显示在页面上。这种方法是更好的然后将用户重定向到一个登录页面有��个原因:
它节省了一个请求,直接登录表单发送到目标页面。
用户可以收藏任何页面,登录后直接显示。重定向到一个登录表单的方法也可以实现这一目标,但要复杂得多(登录表单需要返回的URL,检查它的有效性和重定向后登录,因为 Referer头不可靠)。
如果会话到期之前发送任何申请表然后发布数据预填充登录表单隐藏字段。
<?php
function hidden_fields($process) {
while (list($key, $val) = each($process)) {
if (is_array($val)) {
foreach ($val as $k => $v) {
$process[$key . "[$k]"] = $v;
}
} else {
echo '<input type="hidden" name="' . htmlspecialchars($key) . '" value="' . htmlspecialchars($val) . '" />';
}
}
}
hidden_fields($_POST);
?>
发送文件也保存到隐藏字段和有一个小层服务的文件带有_file美元的变量或隐藏字段。
可以不填表单通过登录 ?username=参数。用户可以使用这个特性在一个安全的环境验证由其他意思(如没有远程访问localhost或HTTP身份验证)。然而,它是不可能通过密码在GET参数这将是非常不安全的。管理员使用的价值 mysql.default_password在这种情况下配置指令。演示应用程序使用这种方法自动登录用户。
表单处理
管理POST方法发送所有动作形式。如果操作成功,那么它将浏览器重定向到一个页面显示结果的确认消息。这消息存储到一个会话变量后开始执行行动,每个HTML页面处理这个会话变量。有理论的可能性,其他管理页面打开同时在不同的浏览器选项卡可以捕获消息并显示它而不是原始页面。然而,设置消息和显示之间的时期很短所以这个概率很低。除此之外,这个巧合的结果小,用户会被告知结果,只是在不同的选项卡。
另一种可选择的方法是发送消息ID或消息本身在URL中但杂乱浏览器历史。此外,页面刷新将保持消息在页面上,这是不可取的。
如果表单操作产生的错误页面直接显示错误消息与肾上腺素的形式发送数据。不重定向浏览器的代码在这种情况下,它允许一个用户刷新页面发送数据只是暂时的错误(例如,如果它可以固定在其他浏览器选项卡)。
数据库模式
简单的数据库模式管理包含一个简单的界面的可视化数据库模式。它显示所有表的列。颜色区分列类型和箭头象征着表引用。表在屏幕上用鼠标可以移动,通过JavaScript和CSS。数据库模式页面使用一个cookie表放置保存。
出口
管理支持SQL和CSV进出口。最有趣的变体出口是使用ALTER命令。通常会有不同的生产和开发服务器上的数据库。如果你有了一些变化的数据库结构应该在发布到生产服务器然后删除旧表和创建新的不是一个选择,因为有实时数据表所示。管理员能够生成一组改变同步数据库的命令。它利用一个存储过程,探讨了生产数据库并改变它符合开发版本。创建新表像往常一样,旧表下降,缺少字段和索引。
性能
管理总是查询所有数据直接从数据库只有一个例外。获取数据库列表可能需要很长时间如果有许多服务器上的数据库,即使用户访问只有两个。因为每个页面显示数据库列表缓存是一个会话变量中。这个变量如果刷新用户创建或删除一个数据库从用户界面或SQL命令。
关闭一个会话session_write_close是一个性能优化影响不大。默认的PHP会话处理程序锁文件会话数据,从而防止web服务器为多个请求相同的用户在同一时间。这是非常重要的网站上使用框架,这是一个常见的情况。管理不使用框架,但用户仍然可以同时打开多个浏览器选项卡与管理。管理员写所有的会话数据,尽快关闭会话允许的最大并发性。
大多数用户感受到管理的平滑,甚至一个用户创建测试套件,衡量phpMyAdmin的性能比较:
性能相同操作的平均速度快了28%(2×23测试)。
登录后开始快56%(2×4测试)。
最后,了解源代码是快100%。
示范
演示是一个最好的方式来展示一些产品的特点。 我已经创建了一些样例数据库,使它从网站访问通过管理但用户已经开始腐蚀它很快。我在想定期恢复数据库,但它不会工作,因为与此同时数据库仍然会损坏。另一方面,在重置用户使用数据库将正在发生的事情感到惊讶。限制将削弱的操作演示,所以这不是一个选择。其他可能是模拟数据库访问为每个用户会话,但这将是一个非常复杂的任务,它不会出现管理的所有功能。
最后,我已经结束,为每个用户创建一个单独的数据库进入演示。脚本初始化这个数据库的示例数据后登录注销后的演示和破坏它。一个cron作业滴的用户数据库没有注销。演示用户目前���强大的特权管理的特点所以有必要限制数据库的列表不允许其他用户访问数据库。每个MySQL用户也可以修改自己的密码和演示应用程序的用户很快就发现了它。因此,演示也禁用这个特性。
我不想创建一个单独的版本的管理只是为了演示我所有定制auto_prepend_file。前缀脚本限制数据库列表,不允许改变密码,初始化演示数据库和滴。
测试和代码覆盖率
几乎所有的应用程序测试。我已经创建了测试Selenium IDE,这是一个非常方便的Firefox插件创建复杂的web应用程序测试。硒的主要优势是,它可以测试整个应用程序——从PHP服务器端HTML在客户端,它甚至可以测试JavaScript交互。管理工作没有JavaScript但更舒适的启用了JavaScript的一些特性,例如添加一个表中的字段不需要将页面发送到服务器。
Selenium IDE可以创建测试很容易。可以把记录按钮,像通常在浏览器中工作。记录测试之后可以修改如果你检查的一些特性的应用程序,那么为什么不来记录一个测试吗?
我很好奇有多少代码测试和我感兴趣的是管理的哪些部分需要更彻底的测试。它可以找到的代码覆盖率。我已经使用了Xdebug扩展,能够测量代码覆盖率。它非常适合运行单元测试,因为整个的代码覆盖率计算运行的测试。但web应用程序测试不同组合来自多个请求和代码覆盖率的计算分别为每个请求。解决方案很简单——我已经注册关闭功能保存代码覆盖一个会话和连接它与以前的结果。
管理的代码覆盖率是75%左右,这是令人满意的。相比较而言,代码覆盖率的PHP源代码是70%左右。我非常高兴当我测试存在的重构应用程序的某些部分。我很确定重构没有破坏任何东西当所有的测试已经通过了。
版本检查
有一个与项目消息和电子邮件订阅RSS提要的新版本。然而一些用户只需安装当前版本并忘记它。出于这个原因,管理包含一个版本检查。
版本检查必须尽可能不引人注目的,因为有时运行管理的环境没有互联网连接或服务器可能是遥不可及的。所以检查当前版本的PHP代码不是一个选择,因为它是阻塞。此外,管理员可以禁用PHP的远程连接allow_url_fopen配置指令。因此,从JavaScript版本检查程序运行。一个简单的 <script src>阻碍(用户可以使用页面但仍在加载状态)是相同的图片。所以一个脚本加载 onload非阻塞事件。服务器部分非常简单:
<?php
header("Content-Type: text/javascript");
if (version_compare($_GET["version"], $VERSION) < 0) {
echo "document.getElementById('version').innerHTML = '$VERSION';\n";
}
echo "document.cookie = 'adminer_version=$VERSION';\n";
?>
如果当前版本是老那么脚本修改文档来显示新的版本号。客户端检查发送cookie与服务器通信只是偶尔。
设计
设计从Vlasta纽鲍尔我不是一个艺术家所以样式表来自自由平面设计师Ondřej Valka。设计是整个管理简单整洁,所以我喜欢它。然而其他用户更喜欢花哨的设计,所以他们创造了自己。设计可以很容易地集成到单个文件的编译但用户喜欢测试几个设计管理检查外部文件 adminer.css的存在。如果它确实存在,那么该脚本使用它而不是集成的CSS。
结论
这篇文章是关于管理架构,而不是对其特性。然而,它应该明确,管理支持所有MySQL特性从一个简单的表编辑,通过多个列外键、触发器、存储过程、出口、用户和流程管理MySQL 5.1事件和表分区。当然是一个普遍的非标准任务的SQL命令。
phpMyAdmin的管理不仅仅是一个紧凑的版本,它试图成为一个完全竞争选择MySQL管理和小足迹仅仅是一个愉快的奖金。
当的大小 adminer.php然后我开始增长已经意识到是明智的分割文件管理的发展。尽管如此,我仍然想要的文件我已经创建了一个编译脚本,连接起来的文件。
因为一切都是一个文件,管理员不能使用通常的URL alter.php?table=X和操作必须通过在查询字符串中。而不是常见的 ?action=alter&table=X,我有更紧凑的替代使用 ?alter=X。然后一系列中央脚本 if (isset($_GET["..."]))而不是一个大 switch ($_GET["action"])。有一个包括内部的特定功能 if这些包括编译构建过程中的一个文件:
<?php
function include_file($match) {
$file = file_get_contents($match[1]);
$token = end(token_get_all($file));
$php = (is_array($token) && in_array($token[0], array(T_CLOSE_TAG, T_INLINE_HTML)));
return "?>\n$file" . ($php ? "<?php" : "");
}
$file = preg_replace_callback('~include "([^"]+)";~', 'include_file', $file);
?>
这个代码不是普遍可用,因为它只发现 include ""变体。它将需要处理的文件token_get_all功能和找到所有包括变体。的 _once变异将会更加困难。也可以有一个全球水平返回.
管理也使用一些外部文件——样式表,快捷方式图标和图像。有几种可能的访问这些文件的方法:
他们可以集成在主HTML代码——样式表 <style>标签,利用图像 data:协议。这种方法的问题是,Internet Explorer 8 <不支持这个协议。第二个问题是,浏览器需要反复与每��页面传输这些数据。
可以从外部服务器下载的文件。会有问题,如果服务器不可用或如果计算机的运行管理是没有互联网连接。然而这种方法是使用SQL查询语法高亮显示,这是一个可选的特性——管理使用JavaScript语法高亮显示JUSH对于这个任务。
文件可以被集成的源代码和一个特殊的参数将为他们服务。你有没有注意到PHP输出的标志吗phpinfo吗?PHP从本地服务器下载它特殊的查询字符串 ?=PHP…。管理使用类似的方法,节省了Base64编码的文件的源代码(编码不是必需的,但它简化了脚本编辑共同的文本编辑器)。这种方法允许HTTP缓存管理利用的外部文件。
注意:PHP 5.3附带了一个支持PHP档案通过phar扩展。这个扩展,可以装几个文件归档和从PHP访问内部的文件归档。使用webPhar包装方法允许大多数PHP应用程序创建phar归档和有指令phpMyAdmin的版本PHP手册。管理不使用这个扩展和使用PHP > = 4.3和PHP > = 5.0。
缩小
编译脚本也贬低代码——它删除评论和修剪空白。大卫的缩小代码是基于工作Grudl谁使用它为他的才华横溢的库Texy,dibi和Nette。这个函数是比内部功能更有效php_strip_whitespace.
<?php
function php_shrink($input) {
$set = array_flip(preg_split('//', '!"#$&\'()*+,-./:;<=>?@[\]^`{|}'));
$space = '';
$output = '';
foreach (token_get_all($input) as $token) {
if (!is_array($token)) {
$token = array(0, $token);
}
if ($token[0] == T_COMMENT || $token[0] == T_WHITESPACE) {
$space = "\n";
} else {
if (isset($set[substr($output, -1)]) || isset($set[$token[1][0]])) {
$space = '';
}
$output .= $space . $token[1];
$space = '';
}
}
return $output;
}
?>
当前版本也缩短用户变量和函数的名字。它发现的变量和函数的源代码token_get_all功能和通过短标识符替换它们。缩短过程跳过内部PHP变量和函数。也有可能缩短他们但它会更复杂,它将有一个的性能损失。一些PHP变量有其超全局特性是必要的别名功能内的全球化。
内部函数可以包含在包络函数较短的名字。然而这种方法是有问题的,因为PHP函数可以有可选参数没有默认值(这个函数的例子写入文件这检测传递的参数的数量而不是它们的值)。通用函数func_get_args不使用引用相反。
替代的方法是定义一个变量为一个内部函数(例如 $fw = 'fwrite'通过这个变量)和调用的函数: $fw($fp, $string)。管理但不使用没有方法,因为它将使应用程序慢下来。
的缩小从CSS和去掉空格也PHP版本的个贬低的JavaScript代码。
文件会小得多的如果它被压缩。PHP支持几个压缩算法,但只有通过一个扩展。我在想用PHP编写的一个简单的减压函数将解压缩文件的其他部分,但需要eval解压缩代码和每个人都知道eval是恶(原因之一是不兼容PHP加速器)。因此,代码不是压缩但只有缩小。
翻译
我在英语发展管理。还有一个捷克版本(这是我的母语)从一开始就和管理目前有11种语言。所有消息是由一个简单的函数,它检查当前的语言并返回相应的翻译。
一个简单的函数检测的语言 Accept-Language标题:
<?php
function acceptable_language($translations) {
$accept_language = array();
preg_match_all('~([-a-z]+)(;q=([0-9.]+))?~', strtolower($_SERVER["HTTP_ACCEPT_LANGUAGE"]), $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$accept_language[$match[1]] = (isset($match[3]) ? $match[3] : 1);
}
arsort($accept_language);
foreach ($accept_language as $lang => $q) {
if (isset($translations[$lang])) {
return $lang;
}
$lang = preg_replace('~-.*~', '', $lang);
if (!isset($accept_language[$lang]) && isset($translations[$lang])) {
return $lang;
}
}
return false;
}
?>
这个函数的调用者保存语言一个cookie在第一次检测。用户可以随时改变语言在同一页面。保存页面语言饼干是一个非常糟糕的实践在一个公共网站,因为搜索引擎才能指数只有一个版本的页面。然而在管理可接受的,因为搜索引擎不索引页面和页面的主要内容(例如表结构)在所有的语言都是一样的。语言存储在cookie的奖励是一个简单的URL而仍有可能执行语言通过语言标识符在查询字符串中。
翻译存储在一个简单的数组,其中的关键是一个消息标识符(这是一个英语版本的消息,并使用它如果翻译不存在),该值是一个字符串翻译。值是包含一些更有趣的信息(如“一行”或“两行”)。大多数语言有不同的单数和复数形式,但有些语言(例如捷克语或俄语)使用更多的复数形式取决于数量(如捷克“皮沃- 1”,“2 piva”或“5 piv”啤酒)。消息和数据都存储在一个数组,而不是字符串和管理包含一个简单的逻辑语言选择正确的形式取决于数量。
默认情况下,管理员有所有语言。编译转换翻译数组值只和改变了标识符数字保存一些字节每个翻译大约需要4 KB。编译脚本也能够创建一个单一的语言版本,它完全消除了语言翻译功能和检测。这个文件只需要111 KB的英文版本管理1.10.1。
数据库扩展抽象
PHP允许通过三个扩展:连接到一个MySQL数据库MySQL,mysqli pdo_mysql。管理支持他们和包含这些扩展的一个简单的抽象层。这个抽象层模拟的子集mysqli和mysqli_result类为所有三个扩展。
PDO的支持是有些微妙,因为PDO使用异常来报告连接错误。管理员不能用通常的 try块来捕捉这些异常,因为它运行在PHP 4。一切都在一个文件所以PDO支持不能有条件地只包括在PHP 5。解决方案是使用set_exception_handler函数来处理连接错误。PHP 4还不支持类常量在语法层面上的源代码使用数值常量代替。
安全
最重要的部分的安全管理是惊人的防御跨���点请求伪造。CSRF攻击者可以执行操作在一个登录的用户的名字。管理员登录信息存储在一个标准的PHP会话所以可以发送cookie会话标识符和抵御CSRF是必要的。管理员发送一个令牌与每个形式和在执行操作前检查这个令牌的形式。令牌保护甚至经常被遗忘的注销动作在其他web应用程序。
非常重要的也是防止跨站点脚本。输出的HTML代码存储在数据库中可以透露敏感信息攻击者htmlspecialchars函数每输出函数逃。
管理也防止SQL注入,但它不是安全的名义——如果攻击者已经登录到管理员然后她可以执行任何SQL命令的SQL代码页。因此,防止SQL注入只是一个适当的操作与用户输入的副作用——用户可以通过任何数据到数据库中。如果管理检测magic_quotes_gpc然后它中和这个指令,并使用适当的转义函数只有当传递到MySQL的数据。
<?php
if (get_magic_quotes_gpc()) {
$process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
while (list($key, $val) = each($process)) {
foreach ($val as $k => $v) {
unset($process[$key][$k]);
if (is_array($v)) {
$process[$key][stripslashes($k)] = $v;
$process[] = &$process[$key][stripslashes($k)];
} else {
$process[$key][stripslashes($k)] = stripslashes($v);
}
}
}
unset($process);
}
?>
调用的session_regenerate_id登录后防止会话固定。
管理包含的每一个页面 robots: noindex元信息隐藏页面的搜索引擎。
登录表单
管理数据库证书保存到一个会话,检查每一页。如果数据库不能授权用户登录表单是直接显示在页面上。这种方法是更好的然后将用户重定向到一个登录页面有��个原因:
它节省了一个请求,直接登录表单发送到目标页面。
用户可以收藏任何页面,登录后直接显示。重定向到一个登录表单的方法也可以实现这一目标,但要复杂得多(登录表单需要返回的URL,检查它的有效性和重定向后登录,因为 Referer头不可靠)。
如果会话到期之前发送任何申请表然后发布数据预填充登录表单隐藏字段。
<?php
function hidden_fields($process) {
while (list($key, $val) = each($process)) {
if (is_array($val)) {
foreach ($val as $k => $v) {
$process[$key . "[$k]"] = $v;
}
} else {
echo '<input type="hidden" name="' . htmlspecialchars($key) . '" value="' . htmlspecialchars($val) . '" />';
}
}
}
hidden_fields($_POST);
?>
发送文件也保存到隐藏字段和有一个小层服务的文件带有_file美元的变量或隐藏字段。
可以不填表单通过登录 ?username=参数。用户可以使用这个特性在一个安全的环境验证由其他意思(如没有远程访问localhost或HTTP身份验证)。然而,它是不可能通过密码在GET参数这将是非常不安全的。管理员使用的价值 mysql.default_password在这种情况下配置指令。演示应用程序使用这种方法自动登录用户。
表单处理
管理POST方法发送所有动作形式。如果操作成功,那么它将浏览器重定向到一个页面显示结果的确认消息。这消息存储到一个会话变量后开始执行行动,每个HTML页面处理这个会话变量。有理论的可能性,其他管理页面打开同时在不同的浏览器选项卡可以捕获消息并显示它而不是原始页面。然而,设置消息和显示之间的时期很短所以这个概率很低。除此之外,这个巧合的结果小,用户会被告知结果,只是在不同的选项卡。
另一种可选择的方法是发送消息ID或消息本身在URL中但杂乱浏览器历史。此外,页面刷新将保持消息在页面上,这是不可取的。
如果表单操作产生的错误页面直接显示错误消息与肾上腺素的形式发送数据。不重定向浏览器的代码在这种情况下,它允许一个用户刷新页面发送数据只是暂时的错误(例如,如果它可以固定在其他浏览器选项卡)。
数据库模式
简单的数据库模式管理包含一个简单的界面的可视化数据库模式。它显示所有表的列。颜色区分列类型和箭头象征着表引用。表在屏幕上用鼠标可以移动,通过JavaScript和CSS。数据库模式页面使用一个cookie表放置保存。
出口
管理支持SQL和CSV进出口。最有趣的变体出口是使用ALTER命令。通常会有不同的生产和开发服务器上的数据库。如果你有了一些变化的数据库结构应该在发布到生产服务器然后删除旧表和创建新的不是一个选择,因为有实时数据表所示。管理员能够生成一组改变同步数据库的命令。它利用一个存储过程,探讨了生产数据库并改变它符合开发版本。创建新表像往常一样,旧表下降,缺少字段和索引。
性能
管理总是查询所有数据直接从数据库只有一个例外。获取数据库列表可能需要很长时间如果有许多服务器上的数据库,即使用户访问只有两个。因为每个页面显示数据库列表缓存是一个会话变量中。这个变量如果刷新用户创建或删除一个数据库从用户界面或SQL命令。
关闭一个会话session_write_close是一个性能优化影响不大。默认的PHP会话处理程序锁文件会话数据,从而防止web服务器为多个请求相同的用户在同一时间。这是非常重要的网站上使用框架,这是一个常见的情况。管理不使用框架,但用户仍然可以同时打开多个浏览器选项卡与管理。管理员写所有的会话数据,尽快关闭会话允许的最大并发性。
大多数用户感受到管理的平滑,甚至一个用户创建测试套件,衡量phpMyAdmin的性能比较:
性能相同操作的平均速度快了28%(2×23测试)。
登录后开始快56%(2×4测试)。
最后,了解源代码是快100%。
示范
演示是一个最好的方式来展示一些产品的特点。 我已经创建了一些样例数据库,使它从网站访问通过管理但用户已经开始腐蚀它很快。我在想定期恢复数据库,但它不会工作,因为与此同时数据库仍然会损坏。另一方面,在重置用户使用数据库将正在发生的事情感到惊讶。限制将削弱的操作演示,所以这不是一个选择。其他可能是模拟数据库访问为每个用户会话,但这将是一个非常复杂的任务,它不会出现管理的所有功能。
最后,我已经结束,为每个用户创建一个单独的数据库进入演示。脚本初始化这个数据库的示例数据后登录注销后的演示和破坏它。一个cron作业滴的用户数据库没有注销。演示用户目前���强大的特权管理的特点所以有必要限制数据库的列表不允许其他用户访问数据库。每个MySQL用户也可以修改自己的密码和演示应用程序的用户很快就发现了它。因此,演示也禁用这个特性。
我不想创建一个单独的版本的管理只是为了演示我所有定制auto_prepend_file。前缀脚本限制数据库列表,不允许改变密码,初始化演示数据库和滴。
测试和代码覆盖率
几乎所有的应用程序测试。我已经创建了测试Selenium IDE,这是一个非常方便的Firefox插件创建复杂的web应用程序测试。硒的主要优势是,它可以测试整个应用程序——从PHP服务器端HTML在客户端,它甚至可以测试JavaScript交互。管理工作没有JavaScript但更舒适的启用了JavaScript的一些特性,例如添加一个表中的字段不需要将页面发送到服务器。
Selenium IDE可以创建测试很容易。可以把记录按钮,像通常在浏览器中工作。记录测试之后可以修改如果你检查的一些特性的应用程序,那么为什么不来记录一个测试吗?
我很好奇有多少代码测试和我感兴趣的是管理的哪些部分需要更彻底的测试。它可以找到的代码覆盖率。我已经使用了Xdebug扩展,能够测量代码覆盖率。它非常适合运行单元测试,因为整个的代码覆盖率计算运行的测试。但web应用程序测试不同组合来自多个请求和代码覆盖率的计算分别为每个请求。解决方案很简单——我已经注册关闭功能保存代码覆盖一个会话和连接它与以前的结果。
管理的代码覆盖率是75%左右,这是令人满意的。相比较而言,代码覆盖率的PHP源代码是70%左右。我非常高兴当我测试存在的重构应用程序的某些部分。我很确定重构没有破坏任何东西当所有的测试已经通过了。
版本检查
有一个与项目消息和电子邮件订阅RSS提要的新版本。然而一些用户只需安装当前版本并忘记它。出于这个原因,管理包含一个版本检查。
版本检查必须尽可能不引人注目的,因为有时运行管理的环境没有互联网连接或服务器可能是遥不可及的。所以检查当前版本的PHP代码不是一个选择,因为它是阻塞。此外,管理员可以禁用PHP的远程连接allow_url_fopen配置指令。因此,从JavaScript版本检查程序运行。一个简单的 <script src>阻碍(用户可以使用页面但仍在加载状态)是相同的图片。所以一个脚本加载 onload非阻塞事件。服务器部分非常简单:
<?php
header("Content-Type: text/javascript");
if (version_compare($_GET["version"], $VERSION) < 0) {
echo "document.getElementById('version').innerHTML = '$VERSION';\n";
}
echo "document.cookie = 'adminer_version=$VERSION';\n";
?>
如果当前版本是老那么脚本修改文档来显示新的版本号。客户端检查发送cookie与服务器通信只是偶尔。
设计
设计从Vlasta纽鲍尔我不是一个艺术家所以样式表来自自由平面设计师Ondřej Valka。设计是整个管理简单整洁,所以我喜欢它。然而其他用户更喜欢花哨的设计,所以他们创造了自己。设计可以很容易地集成到单个文件的编译但用户喜欢测试几个设计管理检查外部文件 adminer.css的存在。如果它确实存在,那么该脚本使用它而不是集成的CSS。
结论
这篇文章是关于管理架构,而不是对其特性。然而,它应该明确,管理支持所有MySQL特性从一个简单的表编辑,通过多个列外键、触发器、存储过程、出口、用户和流程管理MySQL 5.1事件和表分区。当然是一个普遍的非标准任务的SQL命令。
phpMyAdmin的管理不仅仅是一个紧凑的版本,它试图成为一个完全竞争选择MySQL管理和小足迹仅仅是一个愉快的奖金。