关于反向地址解析

PTR (Pointer Recore),指针记录,是电子邮件系统中的一种数据类型,被互联网标准文件RFC1035所定义。与其相对应的是A记录、地址记录。二者组成邮件交换记录。
  A记录解析名字到地址,而PTR记录解析地址到名字。地址是指一个客户端的IP地址,名字是指一个客户的完全合格域名。
   PTR记录被用于电子邮件发送过程中的反向地址解析。当正向域名解析完成后,还应当向您的线路接入商(ISP)申请做反向地址解析,以减少被国外机构退信的可能性。
   因为反向地址解析是需要“钱”的,所以除了用于发邮件的IP做反向地址解析,提供web服务的IP一般是不做反向地址解析的,所以很难根据IP地址反向解析到域名

实例:
提供邮件服务的IP的反向地址解析:

提供web服务的IP的反向地址解析:

PHP中使用文件锁

 
  1. <?php
  2. $lock_file = "/tmp/logging.lock";
  3. if($should_do_sth) {
  4.     $fp = @fopen($lock_file"w+");
  5.     if ($fp && flock($fp, LOCK_EX)) {
  6.         do_sth();
  7.         flock($fp, LOCK_UN);
  8.         fclose($fp);
  9.         @unlink($lock_file);  // 1.  这里删除自己创建的文件,避免因属主权限问题导致其他进程无法打开该所文件 2. 这里也可能多进程间重复删除,所以使用 @
  10.     }
  11. }

form 表单的text/plain 编码方式

form表单的enctype属性可以设置表单提交时表单内容的编码方式,可用的编码方式有:

  enctype
When the value of the method attribute is post, this attribute is the MIME type of content that is used to submit the form to the server. Possible values are:

  • application/x-www-form-urlencoded: The default value if the attribute is not specified.
  • multipart/form-data: Use this value if you are using an <input>  element with the type attribute set to "file".
  • text/plain (HTML5)

其中, text/plain 很少使用,其编码方式如下:

关于PHP中popen使用的一点注意

引子:
PHP的popen可以并发调起多个进程吗?

我们做如下测试:
测试1

分析1
我们发现,这里只输出了"a", 没有输出"b",说明sleep 100;执行了, sleep 200; 没有立即执行

测试2

分析2
这里a、b都输出了,说明两条命令都被调起执行了;同时,我们也发现,主进程并没有立即退出,而是在等待所有子进程执行完毕,如果使用 "&" 将启动的命令推倒后台,主进程也就不等待了。

测试3

分析3
这里a没有输出,说明如果不将popen赋值给一个变量,则进程阻塞,如果使用 "&" 将启动的命令推倒后台,则亦不阻塞。

关于ttserver的异常退出

使用Tokyotrant有相当一段时间了,确实有几次莫名的退出,今天再次出现,查了一下系统日志,报错如下:
$grep ttserver /var/log/messages
Jun 18 22:00:42 localhost kernel: [2463228.773583] ttserver[32282] general protection rip:2b6557922dcb rsp:4a0b2c08 error:0

 

又出现一次;

Jul 18 07:00:21 localhost kernel: [11461817.641400] ttserver[612]: segfault at 000000001ffc2000 rip 0000003f5407c08f rsp 000000004732ec08 error 4

关于PHP中配置文件的定义

定义方法1
—– conf.php ——

  1. <?php
  2. $conf = "hello world";
  3. ?>

引用配置文件:
—– test.php ——

  1. <?php
  2. test();
  3. function test() {
  4.     include("conf.php");
  5.     echo $conf;
  6. }
  7. ?>

———————
分析
如果代码就这么简单,我们发现程序工作的很好,但是:
1. 如果$conf文件很大,每次都include势必浪费很多时间
2. 如果把include修改为include_once,则情况就会变得怪异了; 如果外部不小心include的了一次conf.php ,则test中不再执行conf.php,则test() 不能正常工作; 如果保证外面没有include("conf.php"); 则test() 第一次可以工作正常,第二次就无法正常工作,因为第二次执行test()函数并没有执行conf.php,也就没有$conf变量
3. conf.php 中 $conf 变量的作用域是不固定的,依赖于conf.php 的执行环境,所以简单地把 $conf看做是global的,更是容易犯错误的

结论: 这样写配置文件很容易犯错误,所以不要这样定义配置文件

定义方法2
——- conf.php —–

  1. <?php
  2. $GLOBALS["conf"] = "hello phpor";
  3. ?>

引用配置文件:
——- test.php ——-

  1. <?php
  2. test();
  3. function test() {
  4.     include_once("conf.php");
  5.     echo $GLOBALS["conf"];
  6. }
  7. ?>

分析
1. 配置文件包含进来之后,将一直占用内存空间,所以配置文件不宜太大,不过一般都不太太大
2. 为了提高效率,这里最好使用include_once, 而不是include
3. 这种写法不管怎么调用都不会有问题
4. 需要注意一点的是: 如果配置文件确实很大,解析该配置文件需要10毫秒, 而且不是每次请求都会用到大部分配置,或许整个请求之间只用到了其中1/10的配置,但是还是不得不耗费10ms来解析整个配置文件; 如果确实这这种情况,不妨考虑第三种配置方法

定义方法3
——- conf.php ——

 
  1. <?php
  2. class conf {
  3.     private static $cache = array();
  4.     public static function get($alias) {
  5.         if (isset(self::$cache[$alias])) return self::$cache[$alias];
  6.         $method = "get_$alias";
  7.         if (!method_exists(self, $method)) return array();
  8.         return self::$method();
  9.     }
  10.     private static function get_conf1() {
  11.         return self::$cache["conf1"] = "hello phpor";
  12.     }
  13.     private static function get_conf2() {
  14.         return self::$cache["conf2"] = "maybe this is a big array";
  15.     }
  16. }
  17. ?>

引用配置文件:
——- test.php ——-

  1. <?php
  2. include_once("conf.php");  // 对于应用了PHP加速器的程序来讲,因为conf.php中没有包含就执行的语句,所以使用include或者include_once也没什么区别
  3. test();
  4. function test() {
  5.    var_dump(conf::get("conf1"));
  6. }
  7. ?>

分析
1. 这种办法似乎规避了前两种写法的所有缺点
2. 我们还可以在配置文件中添加一些逻辑,避免代码的重复

关于PHP中的变量作用于问题

引子:
有文件1.php:

  1. <?php
  2. $conf = array("hello world");
  3. ?>

文件2.php

  1. <?php
  2. include_once("1.php");
  3. function do_sth() {
  4.      global $conf;
  5.      print_r($conf);
  6. }
  7. ?>

文件3.php

 
  1. <?php
  2. include_once("2.php");
  3. do_sth(); // 这里能不能打印出数组内容取决于3.php的上下文环境
  4. ?>

直接执行 3.php 可以打印出数组内容。

下面使用文件4.php来include文件3.php
文件4.php

  1. <?php
  2. wrap(); // 这里不能打印出$conf数组的内容
  3. function wrap() {
  4.     include_once("3.php");
  5. }
  6. ?>

分析
1) 因为1.php 中的$conf数组没有使用global声明,所以1.php中 $conf数组的作用于取决于 1.php的上下文环境;
2) 3.php 直接执行的话,工作的很好,但是一旦被一个函数给包裹住,则$conf 数组不再是一个全局变量,这样do_str() 也就不能按照预期执行了
3) 如果在1.php中也使用global声明一下 $conf , 然后再赋值,就比较靠谱了

结论
1. 不要指望在任何函数外部声明的变量就是全局的
2. 虽然使用global 声明后同样可以确保是一个全局变量,但是这里还是建议使用 $GLOBALS 数组来访问全局变量

关于PHP加速器APC的使用

PHP加速器APC除了缓存字节码,还有一个很重要的应用就是 apc_store, 通常会将配置信息使用apc 缓存起来,更多时候是我们发现配置信息的数组太大了,才考虑将整个数组使用apc缓存起来。

下面我们明确一点基本的知识: apc缓存PHP的数组是序列化之后存储的,

下面我们做一个测试:
测试代码:

 
  1. <?php
  2. test_exec_code();
  3. test_unserialize();
  4. test_apc_fetch_arr();
  5. test_apc_fetch_str();
  6. test_apc_fetch_str_then_unserialize();
  7. function test_exec_code() {
  8.         $s = microtime(1);
  9.         while($i++<1000) {
  10.                 $arr = getData();
  11.         }
  12.         echo "exec time:", microtime(1) – $s , "s\n";
  13. }
  14. function test_unserialize() {
  15.         $arr = getData();
  16.         $str = serialize($arr);
  17.         $s = microtime(1);
  18.         $i = 0;
  19.         while($i++<1000) {
  20.                 $arr = unserialize($str);
  21.         }
  22.         echo "unserialize time:", microtime(1) – $s , "s\n";
  23. }
  24. function test_apc_fetch_arr() {
  25.         $arr = getData();
  26.         apc_store("arr"$arr);
  27.         $s = microtime(1);
  28.         $i = 0;
  29.         while($i++<1000) {
  30.                 $arr = apc_fetch("arr");
  31.         }
  32.         echo "apc_fetch_arr time:", microtime(1) – $s , "s\n";
  33. }
  34. function test_apc_fetch_str() {
  35.         $arr = getData();
  36.         $str = serialize($arr);
  37.         apc_store("str"$str);
  38.         $s = microtime(1);
  39.         $i = 0;
  40.         while($i++<1000) {
  41.                 $str = apc_fetch("str");
  42.         }
  43.         echo "apc_fetch_str time:", microtime(1) – $s , "s\n";
  44. }
  45. function test_apc_fetch_str_then_unserialize() {
  46.         $arr = getData();
  47.         $str = serialize($arr);
  48.         apc_store("str"$str);
  49.         $s = microtime(1);
  50.         $i = 0;
  51.         while($i++<1000) {
  52.                 $str = apc_fetch("str");
  53.                 $arr = unserialize($str);
  54.         }
  55.         echo "apc_fetch_str_then_unserialize time:", microtime(1) – $s , "s\n";
  56. }
  57. function getData() {
  58.         $arr = array(
  59.             ‘220.181.7.41’,
  60.             ‘113.5.32.130’,
  61.             //…  共 9000 个IP
  62.         );
  63.         return $arr;
  64. }

测试结果:
$ php test.php
exec time:5.3702118396759s
unserialize time:7.4545278549194s
apc_fetch_arr time:50.132069826126s
apc_fetch_str time:0.18340110778809s
apc_fetch_str_then_unserialize time:7.9918370246887s

分析:
1. 不做缓存,每次都执行字节码的效率是最高的,大约每次执行需要 5ms 的时间
2. PHP 反序列话的速度也赶不上执行字节码的速度(至少在这种情况下是这样的)
3. 使用apc缓存数组的效率是相当低的, 每次约 50ms,不如不缓存
4. 使用apc缓存字符串的速度还是不错的,这里的数据量约为260KB,fetch一次的时间约0.18ms
5. 如果说apc的序列化和反序列化使用的是php标准的序列化和反序列化函数,则: apc_fetch_arr 的时间应该基本和 apc_fetch_str_then_unserialize time 的时间一样,但是,这里差别太大了,有些不太理解; 如此看来,如果真要使用apc,则最好先显式地序列化然后在存储,fetch后在显式地反序列化一下

Firefox 禁用cache

httpwatch是个很好的东西,但是对于常用的禁用cache的功能却没有,而Firebug 有禁用cache的功能,后来才发现,Firebug是如此禁用cache的:

Firebug只是一个Firefox的插件,是简单利用了Firefox的一个特性来实现的“禁用浏览器缓存”; 而httpwatch不仅用于Firefoxo,还用于IE,就不方便来如此实现了。

如果你使用的Firefox,但是没有安装Firebug,则不妨通过 about:config 的方式来实现“禁用浏览器缓存”