很久以前就像离开Wordpress了,不太习惯在线写东西,开始返璞归真了,比较喜欢 纯文本的内容创作方式,在TIPI中就使用了markdown, 在终端写也让我更有协作的欲望。

翻了一下以前的博客,原来一共加起来也不足20篇。以此作为起点今后多继续更新博客吧。

TIPI的issue里还有很多的待处理工作,计划是在7月份全部写完。这个始终是高优先级的。 最进给PHP修复了一些bug,也有一些feature被接受了。在这过程中对PHP的实现又有了一些更加深入 的理解。也有冲动想要写到TIPI里。总之,TIPI会一直更新。

就当时记事吧. 这不是怎样配置ssh密钥避免密码输入的实例, 当然经常ssh登陆的你肯定也配置过了.

我们公司的内网环境比较特殊, 为了安全性做了各种认证, 联入网络需要准入一下, 准入需要使用密码+随即密码的方式认证, 是挺安全的, 可以对于我们来说其实很痛苦,每次都要输入一下密码,因为包含了随即密码,我们无法使用脚本来方便的准入. 我们联入公司的开发机需要通过一台特殊的服务器来将我们的登陆转发, 也就是登陆到中转机,然后通过中转机在ssh.同样登陆中转机也是需要这个随机密码的. 吐槽完毕.

工作中经常需要在多台服务之间ssh登陆, screen 是一个不错的选择, 不过有时候还是需要打开另一个窗口再次登陆, 这时我又得再次输入那个随机密码, 如果你使用windows并且使用SecureCRT那你可以不用继续往下看了,SecureCRT可以简单的复制回话, 这个功能很贴心. 如果使用Linux&Mac OS那就继续往下看.

在/etc/ssh_config 文件中加入

Host *
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p

下次登陆同一站点的时候就会自动复用已有的回话. 可以只输入一次密码开N个窗口了. 这个和密钥要解决的不是同一个问题.

首先恭喜一下er童鞋的大婚吧.

接着er大婚的喜气,项目决定在今天发布我们的TIPI项目,项目从成立到现在,一直有条不紊的前进. 现在项目也进行的差不多,可以公开给大家了. 项目的第一个tag,其实是在20分钟前才提交完.终于能如期发布. 下面是我们的发布公告.  欢迎围观:)


我们的朋友,TIPI团队成员,博客哥,erhttp://www.zhangabc.com同学在今天这个春光灿烂,春暖花开,春心荡漾,春情澎湃的大好日子里,兴高采烈的走入了婚姻的殿堂。 在这样一个让人激动不已,激情四射的日子,TIPI团队决定发布深入理解PHP内核项目的第一阶段成果。

大概在半年前,我们在网上相聚,莫名的邂逅,有了我们这样的一个团队。我们有激情,有想法,有行动,也有了我们这个项目。 开始的艰难,没有时间的痛苦,坚持,从而有了今天的发布。一路走来,有辛苦,也有收获,至少记录了我们的青春,至少做了我们想做的!

深入理解PHP内核(TIPI)项目是一个开源的,分析PHP内核的系列文章项目。整个项目是基于PHP5.3版本的源码。 它包括PHP语言中我们常用的变量,函数,类,对象等的实现原理,也包括PHP的虚拟机,内存管理机制,线程安全,错误异常,文件流和PHP5.3新增加的垃圾收集机制,命名空间等。 除了PHP语言本身的特性外,还包括PHP扩展的相关信息。我们希望这个项目可以帮助更多的PHPer可以更加了解PHP语言本身,知其然知其所以然!

第一阶段,我们发布了前四章,从环境的搭建,源码的阅读方式到对于PHP源码的整体把握,再到对于变量和函数的详细解说。随着项目的进展,我们本身对于PHP内核的理解也加深了许多。 后续我们将以章为单位发布后续的章节。现在第5章正在撰写…

在线阅读入口>>>

TIPI团队序

博客哥三者,今聚首于网络一偶,共谋TIPI大计,与诸君共享技术之事: 向来穷PHP内核之事者或多,却鲜有分享之举。哥三者,常流连于中外博客也,若得一佳作,即欣喜若狂,本乐分享,及有学习总结之心,欲为PHP内核之事穷全身之力。

  • reeze,博客哥者,好苹果,好开源, 陶醉于Web开发及架构, 为Ruby之美所折服, 甚爱iOS及其开发, 好一切善美之事物.

  • er,博客哥者,稀饭Linux, Web, 2.0, Ajax, C, PHP, Javascript, CSS等。乃一以代码为乐之码农也。

  • phppan,博客哥者,好书,好PHP,亲于PHP,C,Ajax,程序架构等

是以三人之力行分享之事,转GIT,习markdown,论项目之计于深夜,何怕事之不成?务使PHP内核之事向众人知。 为此特示。

项目大事记

  • 2010/12/28 14:47 pan向reeze提议写一个PHP内核系列文章,一拍即合.

  • 2010/12/28 15:10 er同学加入.组织正式形成.

  • 2010/12/30 11:11 pan发出<<深入理解PHP内核>>第一份完整目录草稿.

  • 2010/12/31 21:14 举行第一次三方会谈,结合pan和reeze的目录草稿确定了正式目录. 标志着TIPI团队项目的正式确立.. (鼓掌).

  • 2011/01/01 05:08 reeze向github版本库提交了完整的项目, TIPI项目开始进入实施阶段

  • 2011/01/06 15:22 经过哥三激烈的讨论后做出艰难的决定,我们的项目域名正式确定为php-internal.com.(撒花无数).

  • 2011/02/14 23:32 在这个几人欢喜几人愁,充满花香的日子里, 哥三在深夜确定了TIPI项目的第一次整体发布流程,并且定稿了前三章的大纲以及确定了发布前的调整工作。

  • 2011/02/25 02:53 虽然我们还没有正式开始推广TIPI, 但已经有人开始关注TIPI了. 恭喜icodeuhttp://blog.icodeu.com同学成为我们第一位留下脚印的同学(看留言时间,也是个夜猫子啊.)

  • 2011/03/10 11:22 经过TIPI团队的慎重考虑, TIPI团队新增一员大将:honestqiao同学, 欢迎他的加入!

  • 2011/03/20 20:00 今天是TIPI团队成员er同学的大婚之日,团队决定在这个喜庆的日子将我们第一阶段的成果对外发布。让我们恭喜这对新人和我们的TIPI团队。

特别鸣谢

我们需要感谢我们家里的领导,没有有她们的支持,也就没有我们今天的发布,感谢她们的包容,感谢她们的照顾,感谢她们的理解和支持。谢谢!

我喜欢在博客中显示我在豆瓣上的一些信息,比如想看哪些书哪些电影神马的。刚开始用的是 Robin的 http://www.robb.com.cn/plugins/ 的 WP-DoubanShow插件,他用的是豆瓣API。这个插件需要手动修改主题模板文件。刚开始用的挺好,修改就修改吧。不过后来换过几次主题后发现每次修改模板文件还挺“脏”的。遂问robin能否修改成widget的方式,他说官方推出了一个豆瓣秀功能http://www.douban.com/service/badgemaker, 所以不继续维护了。看过官方的说明。发现要在Wordpress中用也只能手动修改模板,不过官方提供了一个生成js的设置项,可以根据需要生成相应的脚本,选项也还算简单。 在网上搜了一番,没有给wordpress用的插件,所以自己写了一个,设置项和官方的一样。下面简单的说明一下:

  1. 第一步:下载插件文件: DoubanShow.zip, 或者在管理界面中添加插件, 搜索douban即可看到”豆瓣秀For Wordpress” 选择安装, 如果这样的话,下面的上传步骤就不需要了

  2. 第二步:上传安装。 后台管理的  插件 -> 添加插件 -> 上传中上传下载的文件。

上传完后记得“启用插件”

第三步:在后台管理的 外观 -> 小工具 中选择”豆瓣秀“ 拖到右侧你想放置的位置。 然后点击拖过去的豆瓣秀箭头。出现如下设置:

标题默认为空,就是不显示标题。也可以设置成你想要的标题。然后要设置好你的豆瓣ID,记住不是豆瓣的登录用户名。 设置好以后。去你的页面看看效果吧,也可以看我博客页面右下角。

昨天在网上看到几道有意思的PHP题, 下面这道题让我想起了对应的Javascript版本. `

这段代码运行结果是什么呢? 别急着执行这段代码,先想想你的结果.然后再对比一下吧.

我们看先看看global的定义 http://www.php.net/manual/en/language.variables.scope.php 这里也没有太为规范的解释.只是说可以通过global关键字来访问全局变量. 这里还涉及到一个类型转换的问题.

大家都知道PHP脚本是编译为opcode逐语句执行的. 那么现在要一句语句解释就很容易了. `

这里可能比较困惑的的是现在变量$a到底是局部变量还是全局变量了.因为global在定义局部变量之后.所以$a变为了全局变量,而在最后输出结果的时候$a并没有值.所以最后在相乘的时候是 NULL * 100; 也就是0了;可能会有人有疑问, 后面只是把$a变为了全局变量, 他的值应该不变的啊. 让我通过下面的例子来看把: `

int(0) [“a”]=> &NULL; } 变量a是NULL的一个引用,因为全局作用域内没有a这个变量. 所以即使在函数前面定义了一个a变量,但是它的值已经指向了全局作用域了. 实际上 global关键字首先从全局符号表中查找变量名叫做a的变量,并把这个变量值设置为当前作用域的符号表中的a变量(更新了当前变量的值). 如果全局作用域内没有这个变量则会在全局作用域内增加这个变量, 实现代码见: $PHP_SRC/Zend/zend_vm_execute.h static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST(int type, ZEND_OPCODE_HANDLER_ARGS) {

    // ...
    if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval;) == FAILURE) {
        switch (type) {
            case BP_VAR_R:
            case BP_VAR_UNSET:
                zend_error(E_NOTICE,"Undefined variable: %s", Z_STRVAL_P(varname));
                /* break missing intentionally */
            case BP_VAR_IS:
                retval = &EG;(uninitialized_zval_ptr);
                break;
            case BP_VAR_RW:
                zend_error(E_NOTICE,"Undefined variable: %s", Z_STRVAL_P(varname));
                /* break missing intentionally */
            case BP_VAR_W: {
                    zval *new_zval = &EG;(uninitialized_zval);

                    Z_ADDREF_P(new_zval);
                    zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new;_zval, sizeof(zval *), (void **) &retval;);
                }
                break;
            EMPTY_SWITCH_DEFAULT_CASE()
        }
    }

 //...

} 看了这个解释大家可能觉得理所当然.一句一句执行的嘛. 看完了PHP中全局作用域的例子,咱们再看看类似的Javascript中的局部变量的版本吧 var a = 1; function multiply(b) {

 a = 100;
 var a;

 return a * b;

} alert(a); alert(multiply(100)); ` 那这段代码的输出将会是多少呢? 如果还是同样的思路,结果可能是你的期望完全不一样的结果. 这里的var定义变量和php中global不是一样的东西, php中的global是会在运行时执行的.而Javascript中的var在运行之前就已经”处理”好了.在运行之前的”语法分析”(没有看过Javascript引擎的实现.姑且这么分把)过程中,multiply函数中出现了var a;则把变量a加到函数体内的”局部变量表”中了.在运行过程中并不会执行var a;这一句. 这也是Javascript”怪异”的地方.定义变量的位置并没有关系.所以在函数内定义局部变量最好放在函数体的前面.

所以第一个alert输出的1, 函数的执行并没有改版全局范围内的a变量; 第二就没有什么问题了, 是10000;

上一篇文章里提到是用PHP扩展实现获取变量的变量名的方法. 今天发现有一个PHP实现的版本 . 实现方法来自:http://mach13.com/how-to-get-a-variable-name-as-a-string-in-php

刚开始以为这个方法好使, 仔细想想其实也是有问题的. 这个解决方法是用的PHP里的get_defined_vars()方法,该方法返回当前作用域内的所有变量信息.也是和$GLOBALS一样,以变量名 => 值的方式返回. 他的代码很简单:

` $v)

    $aDefinedVars_0[$k] = $v;

$iVarSave = $iVar;
$iVar     =!$iVar;   // 将当前变量的值取反

$aDiffKeys = array_keys (array_diff_assoc ($aDefinedVars_0, $aDefinedVars));  // 对比取反前后的变量
$iVar      = $iVarSave; // 恢复当前变量的值

return $aDiffKeys[0];
}

?>

`

它通过引用的方式改变当前变量的值, 然后通过对比前后两个数组的差异来获取值被改变了的变量.然后返回其名字.经过测试这的确是一个方法.相对我实现的方法. 它提供的方法移植性较好, 不需要赖以扩展. 而这个php版本的实现, 必须传递一个get_defined_vars()的参数, 我实现的那个扩展,则不需要. 对于类似 var_name($a=10,get_defined_vars()); 的调用,该方法无法正常获得变量名.

这个今天又仔细想了想,下面提供的方法是有问题的.. 他解决问题的方法是通过修改变量的值, 并对比前后所有的变量来找出值发生变化的变量. 而实际上.修改了其中一个变量另一个变量的值也会发生变化: 这就是引用, 如下 `

PS: 如果你真的需要这种方法. 请重新思考一下你的需要真的需要这样的方法么?

[?25l[J[J[J[J[J[J[?12l[?25h[?1049h[?1h=[1;37r[?12;25h[?12l[?25h[27m[m[H[2J[?25l[37;1H”2010-10-30-php-internal-how-to-get-variables-name-an-extension-implement.markdown” 301L, 12377C[1;1H— date: ‘2010-10-30 00:39:01’ layout: post slug: php-internal-how-to-get-variables-name-an-extension-implement status: publish title: ‘[PHP-Internal]鎬庝箞鏍疯幏鍙朠HP鍙橀噺鐨勫彉閲忓悕涔嬫墿灞曞疄鐜

工作中开发基本都是ssh到远程服务器上vim开发,有时候因为网络原因或者不小心把终端给关了或者网络出现问题以后就痛苦了,因为vim默认会用swp文件保存修改,我又不想关掉这个功能,一不小心真丢数据就划不来了,非法关闭vim之后再次打开就会提示是否恢复文件,自从发现screen这个绝佳的绘画管理工具,就深深的爱上了它,IBM的这篇文章有详细的介绍 “linux 技巧:使用screen 管理你的远程会话”。在使用过程中发现一些问题,默认快捷键是Ctrl + A, 用惯了命令行的人肯定会用Ctrl +A , Ctrl + E来定位当前输入的命令吧. 在~/.screenrc中修改一下就可以了,下面是我的.screenrc vbell_msg "" # 比如在tab自动提示的时候,默认总是会出现一个Wuff,觉得很烦,关掉 escape ``  # instead of Control-a  使用 反引号当快捷键,因为用的相对较少 termcapinfo xterm* ti@:te@  # 这个就是解决mac下看不到滚动条的问题了 解决方法来源见:http://stackoverflow.com/questions/1039442/mac-os-x-terminal-apps-buffer-and-screen-command

如果你比较好奇,可以先从这里下载所有代码,也可以点击这里查看chrome下上传的demo,点这里查看firefox下的demo

前不久Gmail推出了支持拖拽的附件上传功能,试用了下还真不错,其实很久以前就在想能有直接拖拽附件的功能,多亏有了HTML5,Web应用越来越像客户端的应用了。

在好奇心驱使下,想了解一下Gmail到底是怎么做到的,了解了一下最新的HTML5 File API草案,这个接口主要提供的就是提供对文件对象的访问,别想歪了,这个接口是无法随意的访问系统里的文件的。他能做的就是访问标签里所选择的文件,这些文件可以通过用户手动选择,或者是HTML5的拖放接口选中的文件。有兴趣的童鞋可以看看这个规范,还算比较简单。

下面简单看看接口定义几个对象。

FileList、File对象。

在HTML5中的标签中增加了mutilple属性,允许进行多文件选择。大家应该都知道一般上传标签中是不允许选择多个文件的。 新增的这个属性就是允许进行多个文件的选择(这个在桌面应用中也很常见)。

下面是在Firebug中的输出 `

var f = document.getElementById(“file”) f.files FileList0=File length=1 // 选中的文件数量 f.files[0] FilefileName=es.dll fileSize=271360 `

FileList对象就是用户选择的所有文件的对象表示,如果是通过input标签选择的,就可以通过上面代码所示的方法进行访问,File对象就可以刚才选择的某个文件的信息,如上面的代码所示,主要可以得到所选中的文件名以及文件大小信息。

你可能在想只能得到这些信息到底有什么用呢?都没有办法读取文件内容,这就得提到规范中的FileReader接口了,这个接口就是用来读取File对象文件的。

File API规范中提到File API主要是和其他的接口协同合作。比如XMLHttpRequest (这个新接口支持通过xhr的send()方法发送File对象), DataTransfer(也就是HTML5中的拖拽接口 ), 以及Web Worksers(这个主要是异步脚本执行,相当于给JS提供了“多线程”脚本执行能力,并且支持通过postMessage()进行“线程间通信”),感兴趣的,可以看看这篇日志,以及这篇

目前能实现这样的效果的方式主要有如下几种:

  • Gmail中提到的这两个浏览器都支持拖放接口,托放以后可以直接通过托放事件的DataTransfer属性访问到本次托放是关联的文件对象列表FileList,然后通过XMLHttpRequest的send方法将File对象发送到服务器

  • 在Chrome下支持直接将文件拖放到文件选择控件上,就相当于直接选择了文件。这时可以通过DOM对象的files属性访问到被托放进来的文件列表对象,然后也可以通过Ajax将文件对象发送到服务器,通过将文件选择控件透明度降低也可以实现Gmail类似的效果。 在Chrome因为可以直接通过托拽的方式让文件选择控件“赋值”,此时也可以通过一个iframe加表单的方式将数据发送到服务器。

  • 在Firefox3.6下可以通过FileReader直接读取到文件的内容,然后直接将文件内容发送到服务器端(可以参考这个例子,这是个不完整的例子,直接浏览是看不到效果的,查看源代码你就会懂的。)

下面就来看看Gmail到底是怎么做到的吧。

本来想通过Firebug的概况功能来捕捉到在托拽期间的脚本执行情况,比如:

但是脚本执行里压根没有找到ajax相关的函数调用,可能是因为firebug还不支持监控页面里嵌入的iframe中的脚本执行跟踪,这也说明本次上传肯定是在某个iframe中完成的。,那就直接监听网络吧,托拽上传一个附件时查看网络情况,发现附件是通过下面的ajax post过去的:

大家注意看,是通过ajax post方式将附件POST到服务器的,

可以看出Gmail在firefox下不是通过表单直接提交实现的。在chrome下的开发人员工具有点简单,无法看到网络情况,我也懒的再去抓包看了,估计是使用透明+ajax方式实现的。

在Gmail支持托拽的声明中提到目前只支持Chrome 2+以及FireFox3.6+。虽然这两个浏览器都支持HTML5,但是对于所有规范的支持程度都是不一样的,并且规范也还不是正式规范。在Firefox3.6的release note中提到:

Support for new DOM and HTML5 specifications including the Drag & Drop API and the File API, which allow for more interactive web pages.

开始支持了HTML5的拖拽接口以及File API。


下面根据浏览器以及HTML5的规范整理出两个浏览器下实现类似Gmail 上传附件的代码。

点击这里下载所有代码,有兴趣的童鞋查看源代码就知道怎么回事了,有一定的注释:)

也可以点击这里查看chrome下上传的demo,点这里查看firefox下的demo,之所以分开是为了简单起见,当然你真的想要给你的网站提供托拽上传功能,你就得自己去同时兼容这两个浏览器啦,相信这也不是件困难的事情:)