分类目录归档:PHP

php

[原] 去除csdn的blog上复制下来代码的行号

001 line 1
002 line 2
==>
line 1
line 2
不好意思,shell不太熟悉,只好用个php。。。欢迎补充其他语言的一行代码:

[原] php读取二进制流(C语言结构体struct数据文件)

尽管php是用C语言开发的,不过令我不解的是php没有提供对结构体struct的直接支持。
不过php提供了pack和unpack函数,用来进行二进制数据(binary data)和php内部数据的互转:

其中,$format跟perl里的pack格式类似,有如下一些(中文是我加的,有不准确的欢迎提出):
a NUL-padded string,即“\0”作为“空字符”的表示形式
A SPACE-padded string,空格作为“空字符”的表示形式
h Hex string, low nibble first,升序位顺序
H Hex string, high nibble first,降序位顺序
c signed char,有符号单字节
C unsigned char,无符号单字节
s signed short (always 16 bit, machine byte order)
S unsigned short (always 16 bit, machine byte order)
n unsigned short (always 16 bit, big endian byte order)
v unsigned short (always 16 bit, little endian byte order)
i signed integer (machine dependent size and byte order)
I unsigned integer (machine dependent size and byte order)
l signed long (always 32 bit, machine byte order)
L unsigned long (always 32 bit, machine byte order)
N unsigned long (always 32 bit, big endian byte order)
V unsigned long (always 32 bit, little endian byte order)
f float (machine dependent size and representation)
d double (machine dependent size and representation)
x NUL byte,实际使用的时候作为跳过多少字节用,很有用
X Back up one byte,后退1字节
@ NUL-fill to absolute position,实际使用的时候作为从开头跳到某字节用,很有用

实际使用发现:C里的“\0”(即字符串终止符)在php里并不是终止符,而是作为了字符串的一部分。因此,必须对“\0”进行特殊处理,才能进行struct和php内部数据的完美互转。比如 char name[10]; 如果实际数据是“62 69 61 6E 00 62 69 61 6E 00”,在C语言里第5个位置有终止符,name应该是“bian”;而用了unpack转换以后在php里的name却是“bian\0bian\0”。
一开始我用了strpos函数找到“\0”的位置,然后进行substr截取:

不过很Faint的事情发生了,不知道是strpos的bug还是substr的bug(其实测试一下就知道,懒得试),有些字符串没问题,有些字符串却只能得到空值(即$name == ”)。很是郁闷,后来找了个strtok函数,这下没有问题了:

难为大家看了那么多,下面写个完整的php读取二进制数据流(C语言结构体struct数据)文件的示例代码:
首先是C的struct定义示例,为了演示,我就写个简单点的,实际对照上面那个$format格式表应该没有问题:

比如有个“bianbian.org”文件,内容就是上面的N个BIANBIAN结构体构成的。读取的php代码:

pack应该跟unpack相反。

[原] php 5读取非UTF-8编码的文件或网页乱码的解决

php 5的流读取函数好像默认编码是UTF-8,以前在php 4里直接file_get_contents()读取gb2312编码的正常,到了5就乱码了。网上的解决办法说抓取后用iconv()转码。看后我就觉得不对劲:一个是不一定编译了iconv库,更大的问题是编码都跟流转换的时候有关(如果用了iconv实际上php转了两次码:流 -> UTF-8 -> GB2312):这不是白忙乎了吗?

仔细看了下php的文档(不知道大家都是怎么写代码的,其实文档上很清楚啊),上面关于fopen()及file_get_contents()都提到了“默认是UTF-8,但是用户可以用stream_default_encoding()或者用户自定义上下文属性改变编码”(If unicode semantics are enabled, the default encoding of the read data is UTF-8. You can specify a different encoding by creating a custom context or by changing the default using stream_default_encoding().)。于是用stream_default_encoding(‘gb2312’);测试:但是faint的是,这个函数不存在?!似乎php 6才支持。不过天无绝人之路,还有“用户自定义上下文属性”可以用。

经过更仔细的看文档,最后解决了这个问题:

[原] PHP bug or Slackware bug? –enable-fastcgi always failed.

On Slackware 12.0, compile php to fastcgi alwayes failed, only get CGI:

so use spawn-fcgi (lighttpd) always get exit.

OH MY GOD…. I tried from php 4.3.0 – php 5.2.0, only php 4.4.4 can get fastcgi:

why??????????????????????

[原]php的base64解码函数

调用 base64_decode() 就行了。
我承认我很BT地觉得是不是php的这个函数有问题,导致我原先提到的问题产生:php处理base64编码和Unicode客户端交互的问题
于是我照着某文档,重新实现了一下。结果发现是一样的(废话)。-___-!!
我承认我错了,当然前面那个问题不是php的原因。不过既然已经写了,我就贴一下吧。至少base64解码俺是会了。哈哈,对了,还有C语言实现的base64解码,下次也来贴一下。

[原]php处理base64编码和Unicode客户端交互的问题

最近才对编码问题真正深入研究。因为我碰到了这个问题:客户端传过来的是对UTF-16的base64编码,而php没有办法正确解码。
有关编码,可以先看看这篇文章:字符,字节和编码
关于UTF-8和UTF-16,可以参考:谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词
有关URL的base64处理,可以参考这篇:通过 URL 传递 base64 编码参数的问题
摘录如下:

一般情况下,URL 中的参数应使用 url 编码规则,即把参数字符串中除了 -_. 之外的所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号(+)。但是对于带有中文的参数来说,这种编码会使编码后的字符串变得很长。如果希望有短一点的方式对参数编码,可以采用 base64 编码方式对字符串进行编码,但是 base64 编码方式不能处理 JavaScript 中的中文,因为 JavaScript 中的中文都是以 UTF-16 方式保存的。而 base64 只能处理单字节字符,所以不能直接用 base64 对带有中文的 JavaScript 字符串进行编码。但是可以通过 utf.js 这个程序中提供的 utf16to8 来将 UTF-16 编码的中文先转化为 UTF-8 方式,然后再进行 base64 编码。这样编码后的字符串,在传递到服务器端后可以直接通过 base64_decode 解码成 UTF-8 的中文字符串。但是还有个问题需要注意。base64 编码中使用了加号(+),而 + 在 URL 传递时会被当成空格,因此必须要将 base64 编码后的字符串中的加号替换成 %2B 才能当作 URL 参数进行传递。否则在服务器端解码后就会出错。

不过,我对上述的“而 base64 只能处理单字节字符”有疑问,这是base64的标准规定,还是php的缺陷?
如果是php的缺陷,我想应该能写一个针对UTF-16的base64解码函数。这样就不需要客户端来进行UTF16转成UTF8了。

补充:
按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.)
上面第二篇摘录如下:

UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?

Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:

在UCS编码中有一个叫做”ZERO WIDTH NO-BREAK SPACE”的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符”ZERO WIDTH NO-BREAK SPACE”。

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符”ZERO WIDTH NO-BREAK SPACE”又被称作BOM。

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符”ZERO WIDTH NO-BREAK SPACE”的UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

Windows就是使用BOM来标记文本文件的编码方式的。

也就是说,base64编码必须针对单字节。从这个角度说,是不能对UTF-16的字串进行base64编码操作的。难怪php解码后得到的结果不一致。原来问题不是出在php上。

我又看了客户端base64编码部分的代码,确实是客户端的问题。客户端用了“(const BYTE*)sSrcBuf ”把UTF-16的双字节强制转为BYTE流之后进行base64编码,结果是错误的。难怪我解码以后英文字符之间都有莫名奇妙的“空格”(实际是“00”,但是记事本看网页源代码上的“00”显示成空格)。
实际上是这样的:比如“ABC”,UTF-8字节流是“41 42 43”。而UTF-16则是“41 00 42 00 43 00”,所以“(const BYTE*)sSrcBuf ”之后,“00”就被作为单独的一个字节进行了转码,所以解码以后就还原为UTF-8的字节流“41 00 42 00 43 00”,这时候跟初始的“41 42 43”已经不一致了(print的时候只能打出“A”)。难怪我的SQL会报出“ERROR: unterminated quoted string at or near “‘A” at character”的错,因为数据库读取SQL读到“00”就认为结束了。
这时候我冒出一个想法,要是服务器端解码以后再强制把字节流当做UTF-16转为UTF-8,结果不就一样了吗?
事实证明我的想法是正确的:

最后还有一个问题,UTF-16的BOM不一定是FF FE,也可能是FE FF。这怎么办?要是有ASCII字符还好办,两个两个的找,看“00”是在前还是在后。要是双字节都有内容呢?举上面文章的例子:“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?
这个问题单纯改服务器端php没有办法解决。最终的解决办法只有两个:
1)如上面文章所说,客户端UTF-16先转成UTF-8再base64编码,再提交;显示的时候转回UTF-16
2)客户端可以基于UTF-16的字节流base64编码,但是提交的时候要带上“BOM”,即指明是“FFFE”,还是“FEFF”

当然,如果能确定客户端的Unicode的BOM方式,上面的2)也可以不用。
直接在服务器端加上BOM标记进行转码即可。
好像Windows下都是FFFE的,所以可以直接用这个:

[原]超级简单访问PostgreSQL的小型php类

实在受不了ADOdb之类的庞大库了,还有网上下的几个库也超级难用,我自己写了一个。只当简单的用,事务之类的我还没有用到,所以没有写进去。感兴趣的可以补充。好像里面的函数有些要php 4.2以上的。
使用示例:

类的代码:
继续阅读

[原]php用UTF-8编码总结

前几天说的PostgreSQL ERROR原来是php文件没有UTF-8编码导致的问题。
以前说过如果JS文件不是UTF8会在IE有bug,所以JS代码也要用UTF-8。
还有数据库也都要用UTF-8。
php用UTF-8总结:
1) php文件本身必须是UTF-8编码。不像Java会生成class文件,避免这个问题。
2) php要输出头:header(“Content-Type: text/html; charset=UTF-8”);
3) meta标签无所谓,有header所有浏览器就会按header来解析
4) 所有外围都得用UTF8,包括数据库、*.js、*.css(CSS影响倒不大)
5) 最后,php本身不是Unicode的,所有substr之类的函数得改成mb_substr(需要装mbstring扩展);或者用iconv转码(基本上的linux都装了,没装的话download、tar、make、make install,很简单的)
特别郁闷的:
文件系统函数不支持UTF-8!

听说php6已经内置Unicode支持,以后试一下。

[原]php版md5,sha-1哪个更快

一般随机密码都是rand()出来的,我就偷懒直接拿md5,sha-1这些函数来算了:

经过测试,md5比sha1快(废话 – -):

function

with substr and rand

only function
md5

1.94637799263

1.79774594307
sha-1

2.12755990028

1.97592806816

[原]发现php几个很方便的函数

确实好久没接触php了,发现自己很落后了。呵呵,其实几年以前我还是php的超级粉丝。
嗯,突然想起大二时用php做过的一个网站:http://www.geohohai.com。这是我第一份Parttime Job,虽然因为客户的需求不是很明确导致我做的很累,不过从和客户谈、合同编写、项目整体规划、项目文档、美工、编码、部署、验收演示整个流程都是自己一个人搞定,我还是很感谢他们给了我这个长足进步的机会的,也是此后靠IT经济自理的正式开端(以前搞家教,真是的:认真备课教的学生反而没进步;随便瞎吹的反而大进步。真是汗颜)。
我又突然怀念起那一个人的浦口暑假,听着梁静茹,啜着咖啡,为了第一份薪水拼命敲键盘,背后是穿过窗帘的夕阳洒下的斑驳。。。。。为什么回忆总是美好的呢?
刚才点过去突然发现几年过去了,他们已经换成asp了。寒,他们又重复开发了一次,不过基本上的美工和系统架构还是我那个:我也是看链接是asp才发现的。架构也基本上是当时我能想出来最先进的了:所有菜单、所有内容都是后台生成的;菜单配置是程序生成JavaScript代码。嗯,又发神经看了一下JS代码,果然这个还在:
/* 本文件由系统产生,请勿更改 Written by http://dzren.com */
说到http://dzren.com,真是遗憾。原来是“东中人”的意思,做的是我高中母校的校友录,是我学网页编程的练习场所。承蒙大家支持和当时年轻气盛,也有兴旺发达的几年零几个月。可惜没有精力维护下去,现在域名都给别人捡走了。留了几百兆的压缩包在我硬盘上(主要是有上传的照片)。每次看到都伤心一番。。。。
。。。。离题了一大通。。。。
php还是在快速开发方面有很大的优势和进步。这次因为项目转别人的ASP+ACCESS到php+PostgreSQL平台,嗯,重温了一下。发现不用写Java的配置文件,还真是爽啊。
嗯,突然不想写了,贴个Example的代码吧(来自Tore Bjlseth),大家都看得明白:

[原]php使用PostgreSQL的编码问题

php 5.2 PostgreSQL 8.1
数据库是用UTF8编码建的:
./createdb -E UNICODE xxxx
但是用php插入中文数据的时候会报错:
ERROR: invalid byte sequence for encoding “UTF8” ….

看字面意思,好像是因为数据库是UTF8,而插入的数据不是UTF8导致的错误。到psql终端下:

# \encoding
UTF8
# show client_encoding;
UTF8

前面一个UTF8是数据库的编码,后一个表示客户端数据编码(就是插入数据的编码)。
怎么解决?

本问题已经解决,请参考这里:php用UTF-8编码总结

[原]解决qmail+iGenus webmail中文UTF-8乱码

最近帮忙解决了一个问题(下面的全凭回忆输入,可能拼写上有问题):很古老的qmail+iGenus webmail系统,邮件若是UTF-8编码则显示乱码(缺省编码为GB2312)。主要解决办法就是利用iconv进行转码:
先<?php phpinfo();?>看看有没有iconv模块,如果没有,需要重新编译php(如果iconv系统里没有装,得先安装iconv:去 http://www.gnu.org/software/libiconv/ 下载,
./configure,make,make install),编译php的时候加上 –with-iconv
如果php是静态模块方式和apache绑定的,还得把apache重新编译一下:
./configure –activate-module=src/modules/php4/libphp4.a,make clean,make,make install

然后打开iGenus include目录下的Fun_inc.php,找到Decode_mime()函数,在B和Q解码以后加上

还有一个地方是正文的编码,打开include目录下的Prev_inc.php,找到Decode_text()函数,为了防止出现错误,复制一下Decode_text(),比如Decode_text_my(),并增加一个参数:$Charset。在函数内解析完数据准备写到文件之前转码:

打开iGenus主目录下的prev.php,找到调用Decode_text()的两个地方,改成Decode_text_my(),并增加传递一个参数:$Charset

总结:我看的那个iGenus版本php写得很是糟糕,在那个上面改东西有一种想死的冲动……