阅读鸟哥的风雪之隅PHP博客的笔记(1)

大兔子大兔子 提交于 2019-12-07 19:31:58

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)

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!