存档

文章标签 ‘PHP’

Facebook神作: HipHop for PHP

2010年2月4日

PHP很容易开发,它的弱类型的变量和近乎万能的array,可以节约很多开发的时间,当然这也导致它的运行效率不高。有一些扩展例如APC 和 eAccelerator 致力于缓存PHP编译成的opcode来提高速度,不过facebook花了一年半的时间做了更彻底的事情,他们不想容忍连$a=1; $b=1; $c = $a + $b这样简单的事情都要去判断zval的类型,于是他们写出了HipHop for PHP——直接把PHP往C++上转换。

主创人员的blog文章:HipHop for PHP: Move Fast
一个关于HipHop for PHP的talk的视频:http://www.ustream.tv/recorded/4409735

PHP的语法大致被分为两类,一种是传统的,几乎可以和C++直接对应的语法,一种是所谓的”magic”语法。magic语法包括诸如:

$$$$$foo = 1;(动态变量)
$$$$foo();  (动态函数)
extract(array(‘a’ => 1, ‘b’ => 2));

从上面的视频可以看到,动态变量,动态函数乃至extract()都被支持了,不过他们没说是怎么实现的,好奇中。而且对于下面这种code,会是如何编译的呢,a到底要声明为一个int还是查表呢,或者莫非只要scope中有extract()的存在一切变量都要查表?

$a = 1;
$arr['a'] = “2″;
extract($arr);
$b = $a + 1;

另外还有明确说了不支持的,包括eval()的功能,还有is_function_exists()这样的运行时的判断,到是不太用得着。另外在视频中的Q&A环节,看意思是PHP的已有extension都要rewrite一下,感觉这个的代价是不是太大了?

还不知道啥时能用上这个技术,facebook说他们已经有90%的服务已经在用了,用了6个月部署。不清楚它的开源度如何,其它人能不能随便用。HTTP Server方面,facebook方面用了一个自已写的http server以及non-multithreading的apache 1.3,multithreading的暂时还不可用的样子,所以说短期内至少未名是不能用上这个技术的。

ps. 这个技术如果真的发达了,是不是广大C++民工身价会小跌呢。。。

编程

活动目录中时间日期格式的总结

2009年5月3日

活动目录中关于日期和时间的存储还是比较复杂的,如果是用ldap直接操作的话,需要了解得比较清楚的。这里查了一些文档,做一个笔记。

AD中关于时间的属性有两种类型:

1.NT时间戳型:

以lastLogon、pwdLastSet、accountExpires等属性为代表,这类属性的类型(syntax)其实就是一个大整数。NT时间戳与Unix时间戳的思想是一样的,只是前者的定义更bt一些:从1601年1月1日0时起经过的1E-7秒(即100纳秒)的个数(时间是GMT的)。

官方文档可以参考:How to convert date/time attributes in Active Directory to standard time format

如果用PHP之类的语言操作AD,可以先求出标准的Unix时间戳,然后乘上1E7,再加上1970年1月1日00:00:00的NT时间戳(常量:116445312000000000)即得到了NT时间戳。这需要用到计算大数值的BC库,如果没有的话也可以改用字符串,不乘那个1E7,而是直接转成字符串接上7个”0″

2. Generalized Time/Universal time 类型

这种以whenCreated、whenChanged属性为代表,这种属性的类型是真正的时间类型。

这种格式的说明在MSDN上的这个页面:http://msdn.microsoft.com/en-us/library/cc223266(PROT.10).aspx

格式的核心是由ISO8601定义的,W3上的 Date and Time Formats一文介绍得比较易读。不过实际使用的格式不包括横线、冒号等分隔符,具体格式是由ITUX680规定的(在64~65页)。

概括起来,这种格式就是年月日时分秒连续地写在一起,加上一个小数点后的秒值(一般为0),再加上时区,小数点和时区都不可省略。
对于UTC时间,它就形如:20090502173227.0Z 
对于本地时间,它就形如:20090503013227.0+0800 (这两个时间是同一个)

一般来说,向AD中写入时,可以用本地的表示也可以用UTC的表示,但是读出来的时候,都是UTC表示(也就是以Z结尾的) 

 

如果你是PHP用户,可以参照下面的代码实现DateTime对象与Generalized Time格式的相互转化:

 

    function DateTimeToGeneralizedTime($datetime) {
        return $datetime->format(‘YmdHis.0O’);
    }

    function GeneralizedTimeToDateTime($str) {
        $ret = strptime($str, ‘%Y%m%d%H%M%S.0%z’);
        if (!$ret) $ret = strptime($str, ‘%Y%m%d%H%M%S.0%Z’);

        $gmtTimestamp = gmmktime($ret['tm_hour'], $ret['tm_min'], $ret['tm_sec'], $ret['tm_mon'] + 1, $ret['tm_mday'], $ret['tm_year'] + 1900);

        $ret = getdate($gmtTimestamp);

        $datetime = new DateTime();
        $datetime->setDate($ret['year'], $ret['mon'], $ret['mday']);
        $datetime->setTime($ret['hours'], $ret['minutes'], $ret['seconds']);

        return $datetime;
    }

 

 

编程, 技术 , ,

长期陷入PHP这类动态语言的思维定式中

2009年3月19日

长期陷入PHP这类动态语言的思维定式中,一个实际的页面就对应着一个物理的文件,有时还要特意借助什么rewrite之类的功能来实现文件结构不暴露给用户。

其实像python这类的语言做web server时先天的就不是这样做的,人家就是用一个url dispatcher来分配什么url交给哪个函数去处理,你访问 /foo/bar,其实根本没有bar那个文件在那里,这很方便嘛。甚至这些python的代码都不需要放在httpd的document目录里了。事实上,The Django Book里赫然就鄙视了原来PHP的这种方法来着:

Where Should This Directory Live?

If your background is in PHP, you’re probably used to putting code under the Web server’s document root (in a place such as /var/www). With Django, you don’t do that. It’s not a good idea to put any of this Python code within your Web server’s document root, because in doing so you risk the possibility that people will be able to view your raw source code over the Web. That’s not good.

Put your code in some directory outside of the document root.

中译版

这个目录应该放哪儿?

 

有过 PHP 编程背景的话,你可能习惯于将代码都放在 Web 服务器的文档根目录 (例如 /var/www 这样的地方)。而在 Django 中,你不能这样做。把任何 Python 代码放到 Web 服务器的文档根目录中都不是个好主意,因为这样一来,你就要冒着别人透过页面直接看到代码的风险。这对于安全可不是件好事。

 

把代码放置在文档根目录 之外 的某些目录中。

编程 ,

搬家日记(X-Space到WordPress)

2009年2月8日

搬家工作基本完成,颇发扬了自已动手,丰衣足食的精神,记录一下吧。

我的blog原先架在Discuz!的附属的Supesite的X-Space上,目的是转到现在的wordpress上来。本来以为会有现成的blog搬家工具,结果各处一搜,竟然都不支持X-Space自已host的这种blog,唯一看到一个叫blogbak的,也只能把X-Space上的blog导到它自己的51某某站上。
那没有现成的工具,那就用RSS吧,结果发现X-Space不能把日志导出成RSS2.0的文件,作罢。那,从WP这边导入X-Space的rss的feed总是万能的了吧,结果再一次被X-Space的RSS输出打击掉,它只输出一定长度的文章,结果长的文章的后半部分就被截掉了,而且不能通过设置改变这个行为。。。。

没办法,自己写程序搬家好了。。。不过也好,这样comment和commentor的联系方式什么的都能留下,否则我就放弃他们了
(注:上面的功能新版的X-Space好像已经有了,不过我的版本很老。。。)

我写的这些代码适用于满足以下条件的人:
1.是自己host的X-Space和wordpress,自己的主机或者虚拟主机都行,专门的博客提供商(BSP)就不行了
2.X-Space和wordpress在同一个数据库中(一般虚拟主机都这样),如果不是,就得自己改改代码了
3.X-Space的文字编码是gb2312,wordpress的是UTF-8(话又说回来,要是编码相同,连程序都不用了,完全靠SQL也能完成搬家)

搬家步骤:

  1. 正常地安装wordpress
  2. 首先,要小改一下X-Space在数据库里的supe_spacecomments表,在它之中加一列integer列,叫wpID,用于保存原blog里日志的ID和新WP的blog中日志的ID的对应
  3. 打开本文附件convertscript.zip里的两个PHP文件,把里面的数据名、用户名密码等改成实际的值,上传到自己的虚拟主机上
  4. 执行convertArticle.php,把原有的日志转换到WP中(新文章的作者会是默认的id=1,也就是admin用户)
  5. 执行convertComment.php,把原有的comment也转到WP中
  6. 跑一下这句sql: UPDATE `wp_posts` SET `post_name` = md5( `post_content` ) WHERE `post_name` = “”, 用来给每篇日志生成一个post_name,用在该文的静态地址中

至此,搬家基本就算是完成了,不过有点美中不足,就是WP的wp_posts表中有一列叫comment_count,算是个冗余的计数信息吧。默认它是0的,我写了下面的sql以填写它的值:

UPDATE `wp_posts` AS w
INNER JOIN
(
    SELECT p.`ID` AS `wpID` , count( * ) AS `comment_count`
    FROM `wp_posts` AS p
    INNER JOIN `wp_comments` AS c ON p.`ID` = c.`comment_post_ID`
    GROUP BY p.`ID`
) AS ct
ON w.`ID`=ct.`wpID`
SET w.`comment_count`=ct.`comment_count`

但是我的512j的服务器上mysql是4.0.22版本,还不支持子查询。。。。
不过,这个字段有没有用我也不确定,因为各种地方显示的comment计数都是正常的。。。

最后,小感慨一下。以后挑blog建的时候,要先研究好这东西的接口怎么样,否则就容易上X-Space这样的贼船了。。。

技术, 杂记 , , ,

用PHP通过LDAP操作活动目录(AD)的笔记

2007年11月12日

最近一周一直在研究AD这方面的问题,主要难题就是用跑在Linux上的PHP通过LDAP来读写Windows上的活动目录中用户的信息。一般来说需要这么做的情况不常见,因为既然是用AD了就可以用很多现在的LDAP模块,但是我现在要做的是把已有的一个非标准的用户/密码的库转换到AD里去,所以必须亲自来完成一些底层的工作。这方面的文章网上不多见,所以这里综述一下。

首先,是安装配置AD本身的这部分工作:
主要包括:装Win2k3(或2008哈),建立域控制器,建DNS服务,把要加入域的几个机器加进域来,然后建设OU(放用户的OU及放计算机的OU),建立安全组(我用它来限制哪些用户可以登录哪些计算机),设立组策略并应用到各OU等。
这部分内容的文章很多,微软给的文档就足够详细了,比如这个Step by Step的教程:http://www.microsoft.com/china/technet/prodtechnol/windowsserver2003/technologies/directory/activedirectory/stepbystep/default.mspx
(ps.这中间在密码策略上浪费了大量时间,后来才弄清一个域中只能在根下设置密码策略,就算把带有密码策略的组策略应用在OU上,也是无效的。2008里已经可以针对安全组甚至用户设置独立的密码策略了,期待~~)

然后是一些为了就乎linux的准备工作:
先去http://www.microsoft.com/windowsserversystem/sfu/downloads/default.mspx下载一套Windows Services for UNIX,这个装上以后AD里用户的属性页里会出现一个UNIX属于页,有uid,gid什么的,这是为了让linux能结合AD验证用户登录的(比如pam),我目前没用上,不过装它没坏处。
还有是要建立一个proxyuser,这个user是ldap客户端连AD时登录用的,想让PHP实现对AD的什么操作,就给这个proxyuser赋予什么权限。
这里推荐一套很好的文档,是微软的Windows Security and Directory Services for UNIX Guide(还是要pf一下m$,文档就是全,这里对linux中安全体系的介绍比专方介绍的文档都详细。。。)

下面就是资料不好找的工作啦,一步一步来:

1.关于AD与ldap的符合性。AD被做成基本符合ldap的模式,每个用户和计算机或是组什么的都有一个DN,形如CN=loudly,OU=bbs,DC=bdwm,DC=net这样子,而用户的每个属性就是这条记录里的一个attribute,所以可以用ldap_search(),ldap_add()这些标准的函数来操作AD。一个特殊但是关键的地方就是用户的密码,很不易地找到这两个文档介绍这个事情:
How To Change a Windows 2000 User’s Password Through LDAP
User Management with Active Directory―LDAP Password Modification
文章中的核心内容就是:用户的密码是一个叫unicodePwd的属性表示的,这个属于只能写不能读,写的时候的格式是用一对双引号括起密码原文,再编码为unicode传给它,还有,要想改用户密码,必须是通过SSL方式连接LDAP(636端口,而不是普通的389端口)。因为如上要求,就要有以下步骤的工作了。

2.生成根证书
用SSL的话嘛,就需要证书。可以在域控制器上开启认证服务来创建企业的CA(注意这个服务开启后域的设置就不能改了,包括域名,这个机器的名等,所以要在进行这步之前设置好)。这里要做的就是创建CA,然后验证一下是不是ok的。其实这部分内容我也不懂,主要就是照着下面两篇参考着做的,具体步骤怎么回事(尤其是验证的时候)我也不知道是在做什么。
a.Install an enterprise root certification authority
b.就是上面提到的Windows Security and Directory Services for UNIX Guide第二卷的第Chapter4的Build a Certification Authority那一节
如果不自己建CA,而是从别处获得CA,那就看下面这篇:
c.How to enable LDAP over SSL with a third-party certification authority
下面这篇也可以参考,不过该文的主题是别的
d.如何在 Windows 2000 域控制器中配置数字证书来确保 LDAP 和 SMTP 复制的安全
上面的工作做好后,如果正常,那么域控制器就会开始listen 636端口,也就可以通过SSL连AD了(一般ldap客户端的规矩是:连的时候直接写DC地址就是用非加密方法连,连的时候如果写ldaps://地址,就是用SSL方法连接DC)

3.LDAP客户端的配置
客户端,就是要去连AD的机器,也就是本文中跑着PHP的那个机器,要做的工作主要是把DC上的CA导出成.cer,然后拷到客户端上来,然后转化为.pem(可是我的.cer和.pem文件是一样的)放到某个位置,然后再修改一下/etc/openldap/ldap.conf,这样连DC的时候系统就可以去查相应的证书。主要参考的文档是这篇:
Communicating between OpenLDAP and Active Directory over SSL
下面两篇也可以参考:
Configuring Microsoft Active Directory for SSL access
LDAP over SSL – Modifying Active Directory with PHP
上面的文章里最后都要用linux下的ldapsearch命令来测试连接是否可以进行,不过语法不同,我最后成功地连上DC用的语句是:
ldapsearch -x -H “ldaps://theDC.yourdomain.net” -s base -D “cn=proxyuser,cn=users,dc=yourdomain,dc=net” -W -b “dc=yourdomain,dc=net”(回车后提示输proxyuser的密码)
还有,要强调的是,连DC一定要用它的域名,不要用IP或是NetBIOS名,因为CA里写的是域名,要匹配
另,上面说的是linux的ldap客户端,win下也有啊,比如说win2k和2k3的support-tools里的ldp.exe,可是我还没搞清楚它应该怎么才能以SSL连AD。。。

4.用PHP来操作活动目录
这步算是最轻松的了,就是学一学PHP的相关函数的语法就好了。不过大概是没几个人用到ldap这方面的功能吧,PHP manual中ldap这部分的说明很简略,特别是用TLS的文档里写着这部分没有文档。。。所以最好的办法还是看一些源代码,这里推荐的是我在SourceForge上找到一个的PHP连AD的类:http://adldap.sourceforge.net/
这个类写的并不是特别好,比如添用户时非要求填几个没用的属性,还有至少在一层的OU里的样子,所以推荐它主要是为了看它的原码(30k左右,不是很多)学习用ldap来添加、查询、修改、加组等操作应该怎么写,如果你的应用比较复杂,建议还是自己来写,不直接用它的类。
下面几个地址也列出来考虑吧,它们都是我google到的别人问的问题,本身没有确切解答,不过还是有功劳的,比如我认识到了没有验证一个用户的密码对不对的函数,要做的就是用那个用户名和密码去bind一下,bind上
就是对,否则就是错。
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_21296510.html?qid=21296510
http://topic.csdn.net/t/20060524/10/4774581.html
http://www.ideawu.net/ideablog/category6/article238.html
http://topic.csdn.net/t/20030520/15/1809327.html#

上面列出的文章链接真的不是那么好挑选出来,真怕他们哪天没了,回头我下载完打包传上来吧

编程, 技术 , , ,

php中调用mysql存储过程的两个问题

2007年5月1日

一、存储过程返回一个结果集的问题

正常情况下,如果在php中调用一个mysql存储过程,而该过程返回一个结果集的话,那么会收到“#1312 – PROCEDURE XXX can’t return a result set in the given context”的错误提示。
解决方法是,在用mysql_connect()连接数据库时,使用最后一个参数client_flags,设该参数值为0×20000,即如下:

define(‘CLIENT_MULTI_RESULTS’, 0×20000);
$db = mysql_connect(“dbhost”, “dbuser”, “dbpasswd”,1,CLIENT_MULTI_RESULTS);

二、提示“Lost connection to MySQL server during query”的问题

如果在一个页面中调用了不止一次存储过程,就可能收到上面的提示。一个省事的方法就是每次调用储存过程都重connect一下数据库。
在网上查了一下这个问题,有的人说可以在phpinfo()中看一下mysql client API的版本,至少在5.0.15以上才行,不过我的已然是5.0.18了。还有说要改php.ini,设置这个参数:set-variable=thread_stack=256k

编程 ,

列一下自己的MAP安装程序吧

2006年7月21日

UploadFiles/2006-7/721619265.rar装的次数太多了,不过每次的设置越来越少,列个表吧

1装apache
文件httpd-2.2.0.tar.gz
命令./configure –enable-so (它默认的prefix=/usr/local/apache2)
自启方法:把系统自带的init.d/httpd改成新的目录就得了
附件一就是这个httpd文件(直接上传非说文档类型不对,只得打包)

2装mysql
参考页面:http://dev.mysql.com/doc/refman/5.0/en/quick-install.html
基本就按上面的做就得了
文件:mysql-5.0.18.tar.gz
命令:./configure –prefix=/usr/local/mysql –with-extra-character=gb2312,gbk,big5
(注:后来在一个redhat8.0上装mysql,发现用上面的命令根本没有gb2312编码,所以改用./configure –prefix=/usr/local/mysql –with-charset=gb2312 –with-extra-charset=all)
安完后到/usr/local/mysql去
执行bin/mysql_install_db –user=mysql
自启方法:在mysql的源码目录中有个support-files/mysql.server,把它拷为/etc/rc.d/init.d/mysqld,然后加上执行权限就行了

方便起见,用这个命令grant一下来自非localhost的root的权限:
grant all on *.* to root@’%’ identified by ‘xxxx’;

后来升级了内核,mysql会crash,原因不太清楚,编译时多加了几项:
./configure –prefix=/usr/local/mysql –with-extra-charsets=gb2312,gbk,big5 –with-mysqld-ldflags=-all-static –enable-assembler –with-debug
还要编辑一下生成的Makefile,我的CXXFLAG字段是这样的:CXXFLAGS = -g -O -DDBUG_ON -DSAFE_MUTEX -fno-implicit-templates -fno-exceptions -fno-rtti -felide-constructors
参考的是以下两个地址:
http://dev.mysql.com/doc/refman/5.0/en/installing-source.html
http://dev.mysql.com/doc/refman/5.0/en/configure-options.html

3装PHP5
参考页面:http://www.php.net/manual/en/install.unix.apache2.php
文件:php-5.1.2.tar.gz
./configure –with-apxs2=/usr/local/apache2/bin/apxs –with-mysql=/usr/local/mysql –with-mysqli=/usr/local/mysql/bin/mysql_config –enable-ftp

4.关于gd的相关内容

今天我又装了个gd,要装的东西挺多的,在这列一下用到的文件:

freetype-2.3.4.tar.gz  gd-2.0.34.tar.gz  jpegsrc.v6b.tar.gz  libpng-1.2.16.tar.gz  zlib-1.2.3.tar.gz
除了gd本身以外,其余几个都是解开,./configure;make;make install就完事了
最后编gd,gd其实也是这个步骤,它是自动检测另外几个包的安装情况,configure的时候会列出来其它几项的有无,看一下对不对就是了,如果不对的话configure的时候再指定路径。
然后就是再编译一下php,我用到的命令为:
./configure –with-apxs2=/usr/local/apache2/bin/apxs –with-mysql=/usr/local/mysql –with-mysqli=/usr/local/mysql/bin/mysql_config –with-gd –with-jpeg-dir –with-png-dir –with-zlib-dir –with-freetype-dir –enable-ftp

运维, 技术 , , ,