PHP浮点数比较不准的解决方法

首先看一段代码:

 $a = 0.1;
$b = 0.7;
var_dump(($a + $b) == 0.8);

打印出来的值居然为 boolean false

这是为啥?PHP手册对于浮点数有以下警告信息:

Warning
浮点数精度
显然简单的十进制分数如同 0.1 或 0.7 不能在不丢失一点点精度的情况下转换为内部二进制的格式。这就会造成混乱的结果:例如,floor((0.1+0.7)*10) 通常会返回 7 而不是预期中的 8,因为该结果内部的表示其实是类似 7.9999999999…。

这和一个事实有关,那就是不可能精确的用有限位数表达某些十进制分数。例如,十进制的 1/3 变成了 0.3333333. . .。

所以永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等。如果确实需要更高的精度,应该使用任意精度数学函数或者 gmp 函数

那么上面的算式我们应该改写为

 $a = 0.1;
$b = 0.7;
var_dump(bcadd($a,$b,2) == 0.8);

这样就能解决浮点数的计算问题了

上班前两天-编译环境

上班第一天,鸟哥让我编译环境,说实话这个还真不会,以前虽然折腾过VPS或虚拟机,但从来不曾下足勇气去编译。。。一直都是yum或apt-get的选手。。。因为组中大家共用一个开发机,所以每个人分了个帐号,没有root权限。。。

A. 先编译apache吧

./configure –prefix=/home/guweigang/local/httpd …
配置选项在这里(中文):http://apache.jz123.cn/programs/configure.html#configurationoptions
(英文):http://httpd.apache.org/docs/2.2/zh-cn/programs/configure.html

在配置rewrite的时候,发现apache没有mod_rewrite,可能是当初编译apache的时候没有带上 –enable-rewrite选项。

重新编译mod_rewrite.so:
在apache的源码安装目录中寻找mod_rewrite.c文件
find / -name mod_rewrite.c
/home/springshine/LAMP/httpd-2.2.3/modules/mappers/mod_rewrite.c

编译:
cd /home/springshine/LAMP/httpd-2.2.3/modules/mappers/
/usr/local/apache2/bin/apxs -c mod_rewrite.c
/usr/local/apache2/bin/apxs -i -a -n mod_rewrite mod_rewrite.la
如果没出错,在/usr/local/apache2/modules/ 中就会有mod_rewrite.so了

B. MySQL

C. PHP
1.获取源码
2.解压
tar -jxvf php-5.x.x.tar.bz2
cd php-5.x.x
3.配置编译选项
./configure –with-apxs2=/usr/local/apache2/bin/apxs –with-mysql=/path/to/mysql –with-xml –with-dom –with-openssl –enable-ftp
其中–with-apxs2=/usr/local/apache2/bin/apxs 选项和作用是:在安装里会修改APACHE配置文件,加入PHP模块,同时交将模块复制到apache的模块目录下。
4.编译并安装
make && make insatll
5.测试
1).查看/usr/local/apache2/conf/httpd.conf中是否存在并且启用下面的行
LoadModule php5_moudle moudles/libphp5.so
2).在配置文件添加下面的行,使以php为扩展名的文件会使用PHP程序来解析
AddType application/x-httpd-php .php
注:在.php前必须有空格
3).在/usr/local/apache2/htdocs下,创建一个测试文件index.php,内容如下
phpinfo();
?>
4).检测并启动服务
/usr/local/apache2/bin/httpd -S
/usr/local/apache2/bin/httpd -k start
5).测试
在浏览器中输入http://10.1.1.199/index.php
如果成功返回php的相关信息,说明安装成功.

原来编译php的时候,没有把pdo_ mysql 相关的参数带上,安装完后才发现。再重新编译有点费时间,所以决定单独来安装。

$cd $HOME/php-5.x.x/ext/pdo_mysql
$ ~/local/php/bin/phpize
Configuring for:
PHP Api Version: 20041225
Zend Module Api No: 20060613
Zend Extension Api No: 220060519
$ ./configure –with-php-config=PATH –with-pdo-mysq=DIR
$ make && make install

D. SVN
最新的SVN源代码包依赖sqlite和neon。。。
分别到其官网下载源代码,解压并并分别重命名文件夹为:sqlite-amalgamation和neon
然后编译安装,即可。

E. 最后在配置emacs的时候,怎么样都无法显示中文,我靠,设置语言环境也不行,最后在网上找到一个简单的方法,在~/bashrc中加入以下环境变量:
LC_CTYPE=zh_CN.UTF-8

OK,全部搞定,你也可以在直接输入$ LC_CTYPE=zh_CN.UTF-8 emacs启动emacs。

个人用户的环境配置文件是~/.bashrc,全局的环境配置文件是在./etc/profile

一切都归咎于Zend Engine 1(PHP 4.x)兼容模式

前段时间,杨老师给服务器装了Zend Optimizer,至此,我的几个网站就没有正常运行过。。。几经测试:纯HTML没问题,非数据库以外的PHP代码没问题,WordPress可以正常运行。于是大胆去掉Solar站的数据库连接,结果就可以正常运行了。。。真是奇怪了,查了查去才知道是此兼容模式和PDO的冲突问题,而此模式又是为了兼容PHP 4.X的。所以大胆在php.ini中把此兼容模式改成Off状态。。。
; Enable compatibility mode with Zend Engine 1 (PHP 4.x)
zend.ze1_compatibility_mode = Off

原来一切都是这个兼容模式在搞怪。。。

配置Apache+fcgid_module

请先看VC9,VC6,Thread Safe,Non Thread Safe的意思?。 PHP有两种执行方式:ISAPI 和 FastCGI。

ISAPI 执行方式是以 DLL 动态库的形式使用,可以在被用户请求后执行,在处理完一个用户请求后不会马上消失,所以需要进行线程安全检查,这样来提高程序的执行效率,所以如果是以 ISAPI 来执行 PHP,建议选择 Thread Safe 版本;

而 FastCGI 执行方式是以单一线程来执行操作,所以不需要进行线程的安全检查,除去线程安全检查的防护反而可以提高执行效率,所以,如果是以 FastCGI 来执行 PHP,建议选择 Non Thread Safe 版本。

FastCGI 又有fastcgi和fcgid两个模块,推荐使用fcgid,在apache项目的页面上有单独的链接页面。配置信息如下:

LoadModule fcgid_module modules/mod_fcgid.so

<IfModule fcgid_module>
   FcgidInitialEnv PHPRC "c:/php/"
   FcgidInitialEnv PATH "C:/php;C:/WINDOWS/system32;C:/WINDOWS;C:/WINDOWS/System32/Wbem;"
   FcgidInitialEnv SystemRoot "C:/Windows"
   FcgidInitialEnv SystemDrive "C:"
   FcgidInitialEnv TEMP "C:/WINDOWS/TEMP"
   FcgidInitialEnv TMP "C:/WINDOWS/TEMP"
   FcgidInitialEnv windir "C:/WINDOWS"

   FcgidIOTimeout 40
   FcgidConnectTimeout 10
   FcgidMaxProcesses 1000
   FcgidOutputBufferSize 64
   FcgidProcessLifeTime 120
   FcgidMaxRequestsPerProcess 10000
   FcgidMinProcessesPerClass 0
   FcgidFixPathinfo 1

# Global Config Example
  <Files ~ "\.php$">

    Options Indexes FollowSymLinks ExecCGI
    AddHandler fcgid-script .php
    FcgidWrapper "c:/php/php-cgi.exe" .php
  </Files>
</IfModule>

现在官方都不推荐使用VC6版本了,也不会提供VC6的源码,所以大家都迁移到PHP VC9。这里推荐几个网站,分别提供了Apache VC9, Apache X64, PHP X64。

原来PHP原生支持Memcached存储session

转自:http://blog.csdn.net/ctowoo/archive/2009/09/28/4607858.aspx
一般地, Session 是以文本文件形式存储在服务器端的。如果使用 Seesion,或者该 PHP 文件要调用 Session 变量,那么就必须在调用 Session 之前启动它,使用 session_start() 函数。其它都不需要你设置了,PHP 自动完成 Session 文件的创建。其默认 Session 的存放路径是服务器的系统临时文件夹。

但是如果碰到大数据量的Sesstion的时候, 使用基于文件的Session存取瓶颈可能都是在磁盘IO操作上,现在利用Memcached来保存Session数据,直接通过内存的方式,效率自然能够提高不少。 在读写速度上会比 files 时快很多,而且在多个服务器需要共用 session 时会比较方便,将这些服务器都配置成使用同一组 memcached 服务器就可以,减少了额外的工作量。

其缺点是 session 数据都保存在 memory 中,一旦宕机,数据将会丢失。但对 session 数据来说并不是严重的问题。

如何用 memcached 来存储 session呢?以下是基本的配置步骤:

1. 安装 memcached (略过,不清楚的筒子可以查看我的另一篇文章:http://blog.csdn.net/ctowoo/archive/2009/09/26/459 6701.aspx )

在 phpinfo 输出中的 “Registered save handlers” 会有 “files user sqlite”。

2. 修改配置文件,
a. 在 php.ini 中全局设置(* 需要重启服务器)

session.save_handler = memcache
session.save_path = "tcp://127.0.0.1:11211"

b. 或者某个目录下的 .htaccess :

php_value session.save_handler "memcache"
php_value session.save_path "tcp://127.0.0.1:11211"

c. 也可以在某个一个应用中:

ini_set("session.save_handler", "memcache");
ini_set("session.save_path", "tcp://127.0.0.1:11211");

注:使用多个 memcached server 时用逗号”,”隔开,并且和 Memcache::addServer() 文档中说明的一样,可以带额外的参数”persistent”、”weight”、”timeout”、”retry_interval” 等等,类似这样的:”tcp://host:port?persistent=1&weight=2,tcp://host2 :port2″ 。

3. 启动 memcached

memcached -d -m 10 -u root -l 127.0.0.1 -p 11211 -c 256 -P /tmp/memcached.pid

4.测试 创建一个 session

<?php
//set_session.php
session_start();

if (!isset($_SESSION['admin'])) {
$_SESSION['TEST'] = 'wan';
}
print $_SESSION['admin'];
print "\n";
print session_id();
?>

5. 用 sessionid 去 memcached 里查询一下

<?php
//get_session.php
$mem = new Memcache;
$mem->connect("127.0.0.1", 11211);
var_dump($mem->get('0935216dbc0d721d629f89efb89affa 6'));
?>

。。。

[root@localhost html]# /usr/local/webserver/php/bin/php -f get_session.php

输出结果:

string(16)
"admin|s:3:"wan";"

证明 session 正常工作。

用error_log函数写缓存

恩,没错,@伪造 在看ezSQL源代码的时候,总是看到作者用error_log函数写缓存,如:

error_log( serialize($result_cache), 3, $cache_file);

来看看error_log的原型:

bool error_log ( string $message [,
        int $message_type = 0 [, string $destination [, string $extra_headers ]]] )
error_log() log types
0 message is sent to PHP’s system logger, using the Operating System’s system logging mechanism or a file, depending on what the error_log configuration directive is set to. This is the default option.
1 message is sent by email to the address in the destination parameter. This is the only message type where the fourth parameter, extra_headers is used.
2 No longer an option.
3 message is appended to the file destination. A newline is not automatically added to the end of the message string.
4 message is sent directly to the SAPI logging handler.

当$message_type 值为3时,代表写文件,而且是以append的方式写文件。同类型的函数有file_put_contents,不过它是以覆盖方式写文件。而使用这两个函数,都能节约代码,因为file_put_conents和error_log不需要提前获得文件句柄,当然也不需要关闭它们。