分类 代码分析 下的文章

fsockopen返回null的怪异问题排查

今天测试过程中发现fsockopen请求有问题,代码里进行了断点记录,具体代码如下:

if(function_exists('fsockopen')) {
	$fp = @fsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout);
        file_put_contents('d.log', var_export($fp)); // 断点记录
}

执行后,找到d.log文件,内容如下:

null

查了PHP手册里fsockopen函数的说明,如果失败应该是返回false。
呃,居然返回了null,十分怪异。网上搜索了下相关问题,没找到具体原因,但是有发现类似的问题。

没办法,本地重新写了个脚本test.php,具体代码(忽略部分代码):

$host = 'api.discuz.qq.com';

$port = 80;

$errno = 0;
$errstr = '';
$timeout = 30;

$fp = fsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout);
var_dump($fp);

执行这个脚本,输出结果为:

resource(21) of type (stream)

囧,居然成功了。
好吧,两个的区别是一个是用文件记录的,另一个是直接输出的。

将test.php文件的代码改为如下:

$host = 'api.discuz.qq.com';

$port = 80;

$errno = 0;
$errstr = '';
$timeout = 30;

$fp = fsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout);
var_dump($fp);
file_put_contents('d.log', var_export($fp, TRUE));

执行后,页面直接输出还是

resource(21) of type (stream)

但是文件里记录的内容却是:

null

好吧,问题就处在var_dump和var_export这两个函数上。
在PHP手册上关于var_export函数的说明里找到下面一句话:

Variables of type resource couldn't be exported by this function.

资源类型的变量不能使用这个函数输出。

var_export() differs from print_r() for variables that are resources, with print_r() being more useful if you are using the function for debugging purposes.

如果是调试目的的话,print_r更为有用。

回到test.php文件,修改为下面的代码:

$host = 'api.discuz.qq.com';

$port = 80;

$errno = 0;
$errstr = '';
$timeout = 30;

$fp = fsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout);
var_dump($fp);
echo "\n";
var_dump(var_export($fp, TRUE));
echo "\n";
print_r($fp);

执行后,页面的输出为:

resource(14) of type (stream) 
string(4) "NULL" 
Resource id #14

0116更新:
今天又碰到返回为null的情况了。。
接口里不好判断,单独写了个脚本模拟了下,发现fsockopen返回如下信息:

unable to connect to 192.168.0.180:80 (No route to host)

问了下系统的同事,说是这台服务器和要请求的服务器不在一个机房,没法用内网IP。
改成用host请求就可以了。

p标签内的img元素高度超出问题解决

代码如下:


******//文字

img由于float:left,父标签p没有进行float,导致img的高度超出了p的高度。

试了很多方法都没发搞定,想到是否可以让p标签自适应高度实现。
搜索的自适应方法都很复杂,好不容易找到一处改动很少的方法:
给父标签p添加以下的css属性:

overflow:auto;  
zoom:1;

原文地址:http://weixing.me/webdesign/float-div-zishiyingwenti/
感谢作者,添加后我的问题已经解决了。

前台查询的结果字段不更新的问题排查

今天开发更新状态的一个功能,开发完后测试发现数据库里的字段值已经变了,但是前台仍显示的是以前的状态。
一开始以为是没更新成功,在数据库里仔细查了下确定是更改了状态,但是前台就是没有变化。
然后怀疑是前台查询的sql有问题,可能是没加相应的状态判断,于是文件里断点记录了下sql和查询结果,执行后发现sql没有问题,但是查询出来的结果里相应记录的状态没变。

呃,焦虑,这是什么情况啊...

接着怀疑是否是连错了数据库,不过这个直接被排除了,不可能的情况...

然后突然想到以前同事讲过的数据库缓存,于是搜索了下发现还真有这个功能。

MySQL cache功能分析:

1 MySQL的cache功能的key的生成原理是:把select语句按照一定的hash规则生成唯一的key,select的结果生成value,即key=>value。所以对于cache而言,select语句是区分大小写的,也区分空格的。两个select语句必须完完全全一致,才能够获取到同一个cache。

2 生成cache之后,只要该select中涉及到的table有任何的数据变动(insert,update,delete操作等),相关的所有cache都会被删除。因此只有数据很少变动的table,引入MySQL 的cache才较有意义。

使用场景:

MySQL的cache功能只适用于下列场合:数据变动较少,select较多的table。

执行下面的命令

show variables like '%query_cache%';

结果如下图:

可以看出来确实是开启了cache功能,但是这个缓存要求查询的sql必须要写SQL_CACHE,看了下php文件里并没有用到这个SQL_CACHE,应该不是这个缓存的,同样也排除了。

没办法,从最底层看吧。检查Mysql类文件,发现里面增加了memcache的处理,看了下代码,应该是memcache缓存了sql结果,至此困扰了快一下午的问题找到了原因。

调用远程接口失败报错分析及验证方法

问题描述:
在开通云平台或者开启/关闭某个云平台服务的时候,云平台报下面的错误:
调用远程接口失败。请检查您的服务器是否处于内网以及您服务器的防火墙设置。

出现此类问题的可能原因:
1.没有开放80端口,云平台只允许访问80端口。
非80端口的站点请改为80端口开通。

2.您的网站处于内网。
云平台只能在外网使用,请在外网搭建站点再进行开通。

3.接口文件无法访问或输出不正确。
接口文件为:您的论坛地址/api/manyou/my.php,您可以试着在浏览器里访问接口文件看是否可以正常访问。
类似的输出如下:

4.服务器上有防火墙,拦截了云平台与站点间接口文件的通信。
云平台是通过curl的方式去请求站点的接口文件,有些空间商可能对此做了限制,可咨询空间商。

5.域名还未完全生效。
如果您是使用一个刚申请的域名开通云平台,这种情况下可能是域名还未完全生效,建议您等24小时再进行开通操作。

6.云平台回调论坛方法的操作时间超时。
在开通/关闭的操作中,云平台会回调论坛的方法进行更新缓存等操作,此步操作可能超时,导致云平台没有收到正确的返回值。
此类可参考之前一个的问题分析:http://www.liudon.org/?p=102

如果出现此类报错,站长可以按下面的方法自行进行一下验证,检查问题是出在云平台访问站点接口文件还是云平台回调论坛方法上。

验证方法:
x2版本:
找到api\manyou\my.php文件,搜索代码

$my->run();

这句代码下面添加代码

file_put_contents('./d.txt', '云平台访问接口文件成功!');

修改后,进入站点后台->云平台下进行开通云平台或者开启/关闭某些云平台服务的操作,这个时候仍会报调用远程接口失败的错误。
这个时候进入网站目录/api/manyou目录下,检查是否有d.txt文件,里面的内容应该是“云平台访问接口文件成功!”。

如果存在d.txt,则说明云平台可以正常访问站点的接口文件,问题出在云平台回调论坛方法这里。这种情况大部分都会在更新缓存这里,可以参考这个方法修改试下:http://www.liudon.org/?p=102

如果没有生成d.txt,则说明云平台无法访问站点的接口文件,问题处在云平台访问站点接口文件这里。云平台无法访问站点的接口文件的原因,可能是服务器上有防火墙或者新域名还未完全生效。

建议您按上面的验证方法自行进行一下验证,如果自己解决不了,希望您在官方发帖求助的时候可以贴上您验证的结果,方便我们定位问题。

PHP执行sql与Mysql下执行sql效率

今天将一个表数据拷贝到另一个表中,特地分析了下这两种执行方式的效率。

第一种:PHP脚本执行。

PHP脚本代码如下:

$limit = 1000;
$start = !empty($_GET['start']) ? $_GET['start'] : 0;

$query = DB::query("SELECT COUNT(*) FROM temp", 'SILENT');
$count = $query ? DB::result($query, 0) : 0;

if($start <= $count) {
	$query = DB::query("SELECT * FROM temp LIMIT $start, $limit");
	while($row = DB::fetch($query)) {
		$row = daddslashes($row);
		DB::query("INSERT INTO tests (id, name) values ('$row[conuin]', '$row[openid]')");
	}
	$start += $limit;
	showmessage('next',"1.php?start=$start");			
}

从temp表查询数据,然后插入到tests表中,其中temp表有80W条数据,PHP脚本执行情况:
晚上8点22分开始执行,到晚上10点11分执行完毕,耗时38+11=49分钟。

第二种:Mysql命令行下使用SQL执行。
执行SQL如下:

INSERT INTO tests (id, name) (SELECT conuin as id, openid as name FROM temp);

执行情况:耗时不到2分钟。

可见,Mysql下使用SQL命令导入数据的方式更加快捷。