1. 在PHP中使用协程实现多任务调度
http://www.laruence.com/2015/05/28/3038.html
2. Curl的毫秒超时的一个”Bug”
CentOS服务器上, 当你设置了小于1000ms的超时以后, curl不会发起任何请求, 而直接返回超时错误(Timeout reached 28).
原来, 这里面有一个坑, CURL默认的, 在Linux系统上, 如果使用了系统标准的DNS解析, 则会使用SIGALARM来提供控制域名解析超时的功能, 但是SIGALARM不支持小于1s的超时, 于是在libcurl 7.28.1的代码中(注意中文注释行):
int Curl_resolv_timeout(struct connectdata *conn,
const char *hostname,
int port,
struct Curl_dns_entry **entry,
long timeoutms)
{
.......
.......
#ifdef USE_ALARM_TIMEOUT
if(data->set.no_signal)
/* Ignore the timeout when signals are disabled */
timeout = 0;
else
timeout = timeoutms;
if(!timeout)
/* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
return Curl_resolv(conn, hostname, port, entry);
if(timeout < 1000) //如果小于1000, 直接超时返回
/* The alarm() function only provides integer second resolution, so if
we want to wait less than one second we must bail out already now. */
return CURLRESOLV_TIMEDOUT;
....
....
<?php
curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
?>
这样就可以支持了。
在比较新的PHP版本中,CURLOPT_NOSIGNAL是默认启用的,所以可以不用设置了。
可以纯粹了解一下就行吧。
3. PHP浮点数的一个常见问题的解答
关于PHP的浮点数, 我之前写过一篇文章: 关于PHP浮点数你应该知道的(All ‘bogus’ about the float in PHP)
不过, 我当时遗漏了一点, 也就是对于如下的这个常见问题的回答:
<?php
$f = 0.58;
var_dump(intval($f * 100)); //为啥输出57
?>
为啥输出是57啊? PHP的bug么?
我相信有很多的同学有过这样的疑问, 因为光问我类似问题的人就很多, 更不用说bugs.php.net上经常有人问…
要搞明白这个原因, 首先我们要知道浮点数的表示,
计算机专业科班出身的我,表示理解这个并不难。
4. PDOStatement::bindParam的一个陷阱
<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', "test");
$query = <<<QUERY
INSERT INTO `user` (`username`, `password`) VALUES (:username, :password);
QUERY;
$statement = $dbh->prepare($query);
$bind_params = array(':username' => "laruence", ':password' => "weibo");
foreach( $bind_params as $key => $value ){
$statement->bindParam($key, $value);
}
$statement->execute();
最后执行的确实下面的sql。
INSERT INTO `user` (`username`, `password`) VALUES ("weibo", "weibo");
究其原因, 也就是bindParam和bindValue的不同之处, bindParam要求第二个参数是一个引用变量(reference).
解决方法:
A. 不要使用foreach, 而是手动赋值
$statement->bindParam(":username", $bind_params[":username"]); //$value是引用变量了
$statement->bindParam(":password", $bind_params[":password"]);
B. 使用bindValue代替bindParam, 或者直接在execute中传递整个参数数组.
5. Mcrypt响应慢的一个原因
<?php
$dmcryptText = "This string was AES-256 / CBC / ZeroBytePadding encrypted.";
$key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");
# 显示 AES-128, 192, 256 对应的密钥长度:
# #16,24,32 字节。
$key_size = strlen($key);
echo "Key size: " . $key_size . ", key: $key\n";
//$size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
//$iv = mcrypt_create_iv($size); //注意这里
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);
echo "Iv size: " . $iv_size . ", iv: $iv\n";
# 创建和 AES 兼容的密文(Rijndael 分组大小 = 128)
# 仅适用于编码后的输入不是以 00h 结尾的
# (因为默认是使用 0 来补齐数据)
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $dmcryptText, MCRYPT_MODE_CBC, $iv);
echo base64_encode($ciphertext) . "\n";
这里的问题就在于/dev/random, 它的random pool依赖于系统的中断来产生. 当系统的中断数不足, 不够产生足够的随机数, 那么尝试读取的进程就会等待, 也就是会hang住, 来看一个简单的例子:
解决的办法就是, 改用/dev/urandom, /dev/urandom也是一个产生随机数的设备, 但是它不依赖于系统中断.
Weibo上SAE的同学 @胥昕ops提供了一个不需要修改PHP代码的解决方案:
胥昕ops: SAE 二三月份遇到的这个问题,一条命令秒杀此问题,
$ rngd -r /dev/urandom -o /dev/random -t 1
用urandom的结果填充entropy池子,这样既保证了entropy池的数量,也保证了随机性
然而, 为什么PHP使用/dev/random作为默认, 这是因为理论上来说, /dev/urandom在一定的情况下, 可能会被可预测(参看: /dev/random), 所以一般上认为, /dev/urandom不如/dev/random安全.
后记, 大家看手册, 一定也要看手册下面的评论, 呵呵, 有很多东西在评论中, 是有提到的, 如下面这条评论, 来自mcrypt_create_iv:
6. 再一次, 不要使用(include/require)_once
关于使用include还是include_once(以下,都包含require_once), 这个讨论很长了, 结论也一直有, 就是尽量使用include, 而不是include_once, 以前最多的理由的是, include_once需要查询一遍已加载的文件列表, 确认是否存在, 然后再加载.
解释的比较复杂,懒得解释了,反正尽量少用。
排除这些技术因素, 我也一直认为, 我们应该使用include, 而不是include_once, 因为我们完全能做到自己规划, 一个文件只被加载一次. 还可以借助自动加载, 来做到这一点.
你使用include_once, 只能证明, 你对自己的代码没信心.
7. 关于PHP的编译和执行分离
这篇讲得不是很详细,我也没有能够重现出来,估计是我的打开方式不对,评论里面很多也是说不知道怎么apc_bin_load的,Google了半天还是没有能够解决,所以我就说服自己别去想了,估计也用不上。如果真的要用的话,那么试试Facebook的HHVM或者PHP7,估计效果也比这个强。
8. 请手动释放你的资源(Please release resources manually)
来源:oschina
链接:https://my.oschina.net/u/160089/blog/690012