Discuz!官方免费开源建站系统

 找回密码
 立即注册
搜索

DiscuzX如此慢原因之1

[复制链接]
mark35 发表于 2012-8-19 21:34:31 | 显示全部楼层 |阅读模式
本帖最后由 mark35 于 2012-12-3 20:22 编辑

为啥DiscuzX大家都觉得慢呢?
除开因开启新增功能导致的性能损失,某些代码也会造成性能下降

如果你DiscuzX2的 config_global.php文件中是这样的:
  1. $_config['security']['querysafe']['status'] = 1;
复制代码
那么在执行每条SQL前都会对此字符串调用下面函数进行过滤:

  1.     function _do_query_safe($sql) {
  2.         static $_CONFIG = null;
  3.         if($_CONFIG === null) {
  4.             $_CONFIG = getglobal('config/security/querysafe');
  5.         }

  6.         $sql = str_replace(array('\\\\', '\\\'', '\"', '\'\''), '', $sql);
  7.         $mark = $clean = '';
  8.         if(strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) {
  9.             $clean = preg_replace("/'(.+?)'/s", '', $sql);
  10.         } else {
  11.             $len = strlen($sql);
  12.             $mark = $clean = '';
  13. //  逐字扫描的大坨代码开始~
  14.             for ($i = 0; $i <$len; $i++) {
  15.                 $str = $sql[$i];
  16.                 switch ($str) {
  17.                     case '\'':
  18.                         if(!$mark) {
  19.                             $mark = '\'';
  20.                             $clean .= $str;
  21.                         } elseif ($mark == '\'') {
  22.                             $mark = '';
  23.                         }
  24.                         break;
  25.                     case '/':
  26.                         if(empty($mark) && $sql[$i+1] == '*') {
  27.                             $mark = '/*';
  28.                             $clean .= $mark;
  29.                             $i++;
  30.                         } elseif($mark == '/*' && $sql[$i -1] == '*') {
  31.                             $mark = '';
  32.                             $clean .= '*';
  33.                         }
  34.                         break;
  35.                     case '#':
  36.                         if(empty($mark)) {
  37.                             $mark = $str;
  38.                             $clean .= $str;
  39.                         }
  40.                         break;
  41.                     case "\n":
  42.                         if($mark == '#' || $mark == '--') {
  43.                             $mark = '';
  44.                         }
  45.                         break;
  46.                     case '-':
  47.                         if(empty($mark)&& substr($sql, $i, 3) == '-- ') {
  48.                             $mark = '-- ';
  49.                             $clean .= $mark;
  50.                         }
  51.                         break;

  52.                     default:

  53.                         break;
  54.                 }
  55.                 $clean .= $mark ? '' : $str;
  56.             }
  57.         }

  58.         $clean = preg_replace("/[^a-z0-9_\-\(\)#\*\/"]+/is", "", strtolower($clean));

  59.         if($_CONFIG['afullnote']) {
  60.             $clean = str_replace('/**/','',$clean);
  61.         }

  62.         if(is_array($_CONFIG['dfunction'])) {
  63.             foreach($_CONFIG['dfunction'] as $fun) {
  64.                 if(strpos($clean, $fun.'(') !== false) return '-1';
  65.             }
  66.         }

  67.         if(is_array($_CONFIG['daction'])) {
  68.             foreach($_CONFIG['daction'] as $action) {
  69.                 if(strpos($clean,$action) !== false) return '-3';
  70.             }
  71.         }

  72.         if($_CONFIG['dlikehex'] && strpos($clean, 'like0x')) {
  73.             return '-2';
  74.         }

  75.         if(is_array($_CONFIG['dnote'])) {
  76.             foreach($_CONFIG['dnote'] as $note) {
  77.                 if(strpos($clean,$note) !== false) return '-4';
  78.             }
  79.         }

  80.         return 1;

  81.     }
复制代码
看到其中的 最大坨的那个 for 循环块没?这段代码意味着将会对整个SQL字符串逐字符(8bit)进行搜索处理。SQL越长当然执行时间越久。再加上前后的多条preg_replace, PHP毕竟不是在字符串处理及正则处理有特长的PERL,这种处理多少会降低php进程执行效率。

也许使用 mysql_real_escape_string() 更为合适。
因为addslashes() 函数在处理多字节字符串时可能会有疏漏。

在这点上postgresq安全性更高:自v9.1 开始对于通过 \ 转义的字符默认不再解析,即 \ 字符不再是转义字符用,而是一个合法字符。对于单引号的转义按照SQL标准从 \' 改为 '' (两个单引号)。

这是 pgsql v8.2的帮助文档:
standard_conforming_strings (boolean)
控制普通字符串文本('...')中是否按照 SQL 标准把反斜扛当普通文本。缺省为 off ,表示反斜扛当作逃逸对待。将来的版本会把这个设置的缺省值改成 on ,这样字符串文本的语法就变为符合标准了。应用可以检查这个参数来判断字符串文本如何被处理。建议明确使用逃逸字符串语法(E'...')来逃逸字符。

pgsql v9.1的:
standard_conforming_strings (boolean)

    This controls whether ordinary string literals ('...') treat backslashes literally, as specified in the SQL standard. Beginning in PostgreSQL 9.1, the default is on (prior releases defaulted to off). Applications can check this parameter to determine how string literals will be processed. The presence of this parameter can also be taken as an indication that the escape string syntax (E'...') is supported. Escape string syntax (Section 4.1.2.2) should be used if an application desires backslashes to be treated as escape characters.

http://www.postgresql.org/docs/9 ... fig-compatible.html







评分

1

查看全部评分

回复

使用道具 举报

明镜 发表于 2012-8-19 21:42:59 | 显示全部楼层
看见pgsql就知道是楼主

评分

1

查看全部评分

回复

使用道具 举报

78137302 发表于 2012-8-19 21:55:10 | 显示全部楼层
2.5呢??
回复

使用道具 举报

 楼主| mark35 发表于 2012-8-19 21:56:18 | 显示全部楼层
本帖最后由 mark35 于 2012-8-19 22:00 编辑
明镜 发表于 2012-8-19 21:42
看见pgsql就知道是楼主

标题中可没有pgsql啊。 最后那段是顺手写上的,只让大家了解下其他数据库(我不会ORACLE,mssql,所以就只有写pgsql的啦)而不要被mysql所局限甚至禁锢。

我现在的SQL处理是放弃addslashes() ,在PDO上面做prepare()/execute() 或者使用 pgsql的$dbh->quote(),一了百了。
回复

使用道具 举报

 楼主| mark35 发表于 2012-8-19 22:01:27 | 显示全部楼层
78137302 发表于 2012-8-19 21:55
2.5呢??

没看。应该差不多。
回复

使用道具 举报

hjyy 发表于 2012-8-20 12:35:58 | 显示全部楼层
mark35 发表于 2012-8-19 22:01
没看。应该差不多。

DX25不是说重写代码了吗?
回复

使用道具 举报

 楼主| mark35 发表于 2012-8-20 12:45:58 | 显示全部楼层
本帖最后由 mark35 于 2012-8-20 12:47 编辑
hjyy 发表于 2012-8-20 12:35
DX25不是说重写代码了吗?

重写也不会推翻重来嘛,否则就不是2.5了。
看了X2.5,此函数定义与X2相同。
回复

使用道具 举报

xulin188 发表于 2012-8-20 14:21:31 | 显示全部楼层
看不懂~~~~~~~~~~~~~~
回复

使用道具 举报

Monkey威武 发表于 2012-8-20 14:31:49 | 显示全部楼层
mark35 发表于 2012-8-20 12:45
重写也不会推翻重来嘛,否则就不是2.5了。
看了X2.5,此函数定义与X2相同。

这个是为了安全性才做的,如果没有的话,安全性会下降的
回复

使用道具 举报

Monkey威武 发表于 2012-8-20 14:32:56 | 显示全部楼层
mark35 发表于 2012-8-20 12:45
重写也不会推翻重来嘛,否则就不是2.5了。
看了X2.5,此函数定义与X2相同。

还有,目前不少的虚拟主机,好像都没有配置pgsql数据库
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|Discuz! 官方站 ( 皖ICP备16010102号 )star

GMT+8, 2025-9-11 12:08 , Processed in 0.136466 second(s), 16 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表