{ yeah : 必须哒 } No place to place should record our youth?

3Aug/104

[转]搭建Eclipse PDT开发CakePHP的环境

Posted by ofeng

Eclipse 是常见的开源IDE工具,通过增加插件,可用于PHP开发。下文参考CakePHP的bakery中一文:Setting up Eclipse to work with Cake,搭建一个Windows 7下面用于调试CakePHP的环境。特标注一些需留意的地方。
一、下载Eclipse PDT
Eclipse可用于开发PHP的插件有不少,其中部署最方便的是PDT(PHP Development Tools Project)。
官方网站:http://www.eclipse.org/pdt/
当前最新版本是2.2,基于Eclipse Platform 3.6.0.v2010060。
下载地址是:点击
操作系统中需先安装Java虚拟机,PDT本身不需安装,直接解压即可使用,例如:D:\Tools\eclipse
其他运行环境为:

引用

Windows 7
XAMPP 1.7.1(包括Apache 2.2、PHP 5.2.9、Mysql 5.0等)

二、Workspace环境
打开PDT后,首先会问你Workspace的路径:
1  

该路径应指向今后应用程序项目(project)存放的本地物理磁盘目录的位置。现我们使用的是XAMPP环境,为尽量减少需修改的配置,我们把Workspace定义到htdocs目录下。
以XAMPP默认路径为例,http.conf存放在D:\Tools\xampp\apache\conf,其中定义有:

引用

DocumentRoot "D:/Tools/xampp/htdocs"

所以,这也将会是我们的Workspace位置。当然,稍后,我们也可以在IDE中对其进行修改:打开File > Switch Workspace > Other。
定义Workspace后,我们就可以创建project项目了。打开File > PHP Project,会弹出一个向导:
2
根据提示来完成。
为了解决中文字符的问题,需把默认的字符集GBK,改为UTF-8。右键点击对应的项目,然后选择Properties,修改为图中提示:
3
保存即可。
三、配置PHP Debugger
IDE 的其中一个最大优势,就是提供Debugger工具,而可用于PDT的Debugger,有两个,分别是:ZendDebugger 和 XDebug。两者都可以免费使用,我这里都介绍一下,当然择其一即可。
1、ZendDebugger
这是由Zend提供的Debug工具,原包括在Zend Studio中,可作为PDT的插件来使用。
下载地址是:这里
我们已经有PDT环境,下载Zend Executable Debugger Eclipse Plug-in即可。
下载后,打开压缩包,把其中的目录解压到eclipse对应的目录下:

引用

D:\Tools\eclipse\features
D:\Tools\eclipse\plugins\org.zend.php.debug.debugger.win32.x86_5.2.15.v20081217

然后,修改PHP的php.ini,例如:D:\Tools\xampp\php\php.ini ,把:

引用

[Zend]
zend_extension_ts = "D:\Tools\xampp\php\zendOptimizer\lib\ZendExtensionManager.dll"

改为:

引用

[Zend]
;zend_extension_ts = "D:\Tools\xampp\php\zendOptimizer\lib\ZendExtensionManager.dll"
zend_extension_ts = "D:\Tools\eclipse\plugins\org.zend.php.debug.debugger.win32.x86_5.2.15.v20081217\resources\php5\ZendDebugger.dll"

然后重启Apache,ZendDebugger即可使用。
2、XDebug
其官网为:http://xdebug.org/,XAMPP已经自带了该库,但并没有激活。
当然,你也可以从官网上下载,例如php_xdebug-2.1.0-5.2-vc6.dll,然后把其放到php的ext目录下,如:D:\Tools\xampp\php\ext,最后才修改php.ini 。
因为Zend Optimizer与XDebug不兼容,所以,在启动XDebug前,必须把Zend Optimizer注释掉:

引用

[Zend]
;zend_extension_ts = "D:\Tools\xampp\php\zendOptimizer\lib\ZendExtensionManager.dll"
;zend_extension_ts = "D:\Tools\eclipse\plugins\org.zend.php.debug.debugger.win32.x86_5.2.15.v20081217\resources\php5\ZendDebugger.dll"

然后才能打开XDebug的注释项,最后结果为:

引用

[XDebug]
zend_extension_ts="D:\Tools\xampp\php\ext\php_xdebug.dll"
xdebug.remote_enable=true
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9000
xdebug.remote_handler=dbgp
xdebug.profiler_enable=1
xdebug.profiler_output_dir="D:\Tools\xampp\tmp"

同样的,重启Apache后生效。
3、使用Debugger
假设我们已经在PDT中创建一个叫test的project。在其中建立一个php文件,内容为:

<?php
$i = 1;
$i++;
echo $i;
?>

并且在第三行设置一个断点,如图:
4
接着,在文件浏览窗口中,右键点击对应的php文件,选择Debug As > PHP Web Page,如图:
5
即会提示切换到Debug界面:
6
确认后,可看到类似下面的PHP Debug界面:
7
可见,断点设置已生效,可用于程序调试。
四、添加对.ctp视图文件的支持
CakePHP 1.2使用的View视图文件后缀是.ctp,我们需要在PDT中增加对其的识别:从Window > Perferences > General > Content types 中,在text > PHP content type 里面添加一项,结果如下:
8
※ 注意,把Default encoding中也设置为utf8
五、添加bake脚本的支持
bake是CakePHP的其中一个不错的功能,若能在PDT中直接运行,将是一个不错的选择。实际上,PDT也考虑到编写PHP脚本的情况,所以,通过一些简单的配置,完全可以在PDT的console中运行bake脚本。
从菜单中选择Run > External Tools > Open External Tools Dialogue...,输入以下信息:

引用

Name: bake
Location: D:\Tools\xampp\php\php.exe
Working Directory: ${workspace_loc:/blog/cake/console}
Arguments:
cake.php bake -working ${workspace_loc:/blog/} -app ${workspace_loc:/blog/app/}

这里的值输入方式有很多,其中${workspace_loc: 表示当前Workspace目录。Location是脚本运行的路径,Working Directory是运行的当前目录(cake.php所在目录),Arguments 是运行时需要的参数。
※ cake.php中两参数的意思是:

引用

-working 应用的根目录,底下有cake、app、vendors 等目录
-app 应用根目录下的app目录位置

※ 注意:我并没有按照:bakery中的方法用cake.bat来配置,当然,你可以参考。
配置完成后,点击Run,可在console中看到脚本运行的状态:
9
六、用于CakePHP的Eclipse插件
在使用CakePHP框架时,因为MVC的关系,经常需要在多个文件之间来回切换。Eclipse中的一个插件可以让这些工作轻便些。
下载地址是:http://opencakefile.sourceforge.net/
把下载后的文件org.xicabin.cakephp.opencakefile_1.0.0.jar,放到eclipse的插件目录D:\Tools\eclipse\plugins下,重启PDT即可生效。
因为该插件开发得比较早,故view视图是的默认后缀是*.thtml,我们可在Window > Preferences > Open Cake File中设定。
当打开CakePHP中某个control文件时,可通过快捷键Ctrl+Shift+; ,快速切换到model 或view 等视图。(或在工具栏中,选择对应的图标)
其他使用方式如下:(部分快捷方式我没有用出来)

引用

1. Open a CakePHP model file
2. Click 'Ctrl + Shift + ;' to switch to its controller file
3. Click 'Ctrl + O' to select an action
4. Click 'Ctrl + Shift + ;' to swtich to its view file
5. Click 'Ctrl + Shift + ;' to swtich to its model file
6. Click 'Ctrl + Shift + C' to swtich to its controller file
7. Click 'Ctrl + Shift + V' to swtich to its view file
8. Click 'Ctrl + Shift + M' to swtich to its model file
9. Select text like 'products/index' and Click 'Ctrl + Shift + V' to swtich to products's index view

七、添加Subversion支持
PDT默认使用CVS来进行版本控制,当然,也可以通过插件的方式支持Subversion。
从菜单中选择Help > Install New Software,在Work with中输入:
http://subclipse.tigris.org/update_1.6.x
把Subclipse展开后,选择全部组件:
10
点击Next,接受License后,即会自动从网上下载对应的Subclipse组件(会提示Subclipse没有签名,确认即可),安装完成后,选择重启Eclipse。
Subclipse的使用一般有两种:
1、通过视图的方式
从Window > Open perspective > Other ..>中选择SVN repository exploring(SVN资源库研究)。
打开后,在左上方的窗口中,点击右键,选择“新建”>“资源库位置”,填入svn的地址即可:
11
该方式主要用于从SVN中checkout资源出来,而下面的方式用于把项目添加或更新到SVN中。
2、添加项目到SVN中
右键点击某个项目,选择Team > Share project,选择SVN作为库的类型:
12
然后输入SVN库的地址即可。结果如下:
13
八、连接到Mysql
除了可以通过插件让PDT连接到subversion中,还可以连接到数据库上,我这里会使用QuantumDB。与Subclipse的安装方法类似,在Work with中输入:
http://quantum.sourceforge.net/update-site
根据情况,选择需安装的组件:
14
安装完毕后,重启eclipse生效。
QuantumDB可用于管理多种支持Java连接的数据库,前提是,需要安装Java的连接库。
所以,需要从这里下载连接库后,把库mysql-connector-java-5.1.13-bin.jar放到eclipse的插件目录D:\Tools\eclipse\plugins下。
从Window > Open perspective > Other ..>中选择Quantum DB,然后在左边的窗口中,右键点击,选择New Bookmark > Add Driver > Add External Jar,找到Mysql 库的位置。
Class name中输入com.mysql.jdbc.Driver(或用Browse浏览)
Type中选择MySQL
如图:
15
确认后,回到原来的Bookmark菜单,从Driver中选择刚创建的“MySQL-AB JDBC Driver”,然后输入连接到mysql 的信息:
16
保存后,可看到类似的表信息:
17
右上方的窗口可用于输入SQL查询语句,右下方的窗口是结果:
18
九、附录
1、Zend Optimizer与XDebug 的冲突
如果在配置XDebug前没有Zend Optimizer关闭,Apache是不能成功启动的,在其后台error.log日志中,会提示:

引用

PHP Fatal error:  [Zend Optimizer] Zend Optimizer 3.3.3 is incompatible with Xdebug 2.1.0 in Unknown on line 0

2、Zend Debugger 与 XDebug 的配置问题
虽然,通常情况下,我们会从Zend Debugger 或 XDebug中择其一。但若在使用中途对Debug工具进行调整,可能会带来一些意想不到的问题。
这时,可试试修改一下默认配置,从Window > Preferences > PHP > Debug,把默认Debug工具改一下,如图:
19
另外,PDT会自动保存已设置断点的文件配置,若前后使用的Debug工具不一致,需改过来。
可点击菜单工具栏中的小虫标记,并选择Debug Configurations:
20
即可修改该配置使用的Debug工具:
21

转载完毕

3Aug/102

[转]注意PHP对字符串的递增运算

Posted by ofeng

早上reader中看到的,有意思,而且以前还真没试过

有同学问了一个问题:

   1: <?php

   2: for($i = 'A'; $i <= 'Z'; $i++) {    

   3:     echo $i;

   4: }

   5: ?>

输出是啥?

输出是:

ABCDEFGHIJKLMNOPQRSTUVWXYZAAABACADAEAFAGAHAIAJAKALAMANAOAPAQARAS…….

为啥?

其实很简单, PHP的手册中也有说明, 只不过恐怕很多人不会一章一节的把手册仔细阅读一遍:

PHP follows Perl’s convention when dealing with arithmetic operations on character variables and not C’s. For example, in Perl ‘Z’+1 turns into ‘AA’, while in C ‘Z’+1 turns into ‘[‘ ( ord(‘Z’) == 90, ord(‘[‘) == 91 ). Note that character variables can be incremented but not decremented and even so only plain ASCII characters (a-z and A-Z) are supported.

在处理字符变量的算数运算时,PHP 沿袭了 Perl 的习惯,而非 C 的。例如,在 Perl 中 ‘Z’+1 将得到 ‘AA’,而在 C 中,’Z'+1 将得到 ‘[‘(ord(‘Z’) == 90,ord(‘[‘) == 91)。注意字符变量只能递增,不能递减,并且只支持纯字母(a-z 和 A-Z)。

也就是说, 如果:

  1. $name = "laruence";
  2. ++$name; //将会是"laruencf"

而:

  1. $name = "laruence";
  2. --$name; //没有影响, 还是"laruence"

所以, 这个问题的原因就是当$i = Z的时候, ++$i成了AA, 而字符串比较的话,

AA,BB,XX一直到YZ都是小于等于Z的… so..

2Aug/101

php字符转换全角转半角

Posted by ofeng

今天遇到字符转换的问题,发现用iconv(“gb2312”,”utf-8”,$string)这个函数的时候,如果string中含有全角字符,函数就会返回空。

首先查了下手册

string iconv ( string $in_charset , string $out_charset , string $str )

in_charset
The input charset.

out_charset
The output charset.

If you append the string //TRANSLIT to out_charset transliteration is activated. This means that when a character can't be represented in the target charset, it can be approximated through one or several similarly looking characters. If you append the string //IGNORE, characters that cannot be represented in the target charset are silently discarded. Otherwise, str is cut from the first illegal character.

加上 //TRANSLIT ,当一个字符无法被要转化的编码描述,找一个或者几个类似的字符替代,如果用 //IGNORE ,特殊字符会被直接丢弃,不加则会从非法字符后截断。果然会被咔嚓掉……

再看看string中的字符集,为啥会变成illegal character呢?

怀疑是string中的全角标点符号引起的,网上google了个php转换函数,试了一把,果然可以了

php全角转半角函数

/**
* 将一个字串中含有全角的数字字符、字母、空格或'%+-()'字符转换为相应半角字符
*
* @access public
* @param string $str 待转换字串
*
* @return string $str 处理后字串
*/
function make_semiangle($str)
{
$arr = array('0' => '0', '1' => '1', '2' => '2', '3' => '3', '4' => '4',
'5' => '5', '6' => '6', '7' => '7', '8' => '8', '9' => '9',
'A' => 'A', 'B' => 'B', 'C' => 'C', 'D' => 'D', 'E' => 'E',
'F' => 'F', 'G' => 'G', 'H' => 'H', 'I' => 'I', 'J' => 'J',
'K' => 'K', 'L' => 'L', 'M' => 'M', 'N' => 'N', 'O' => 'O',
'P' => 'P', 'Q' => 'Q', 'R' => 'R', 'S' => 'S', 'T' => 'T',
'U' => 'U', 'V' => 'V', 'W' => 'W', 'X' => 'X', 'Y' => 'Y',
'Z' => 'Z', 'a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd',
'e' => 'e', 'f' => 'f', 'g' => 'g', 'h' => 'h', 'i' => 'i',
'j' => 'j', 'k' => 'k', 'l' => 'l', 'm' => 'm', 'n' => 'n',
'o' => 'o', 'p' => 'p', 'q' => 'q', 'r' => 'r', 's' => 's',
't' => 't', 'u' => 'u', 'v' => 'v', 'w' => 'w', 'x' => 'x',
'y' => 'y', 'z' => 'z',
'(' => '(', ')' => ')', '〔' => '[', '〕' => ']', '【' => '[',
'】' => ']', '〖' => '[', '〗' => ']', '“' => '[', '”' => ']',
'‘' => '[', '’' => ']', '{' => '{', '}' => '}', '《' => '<',
'》' => '>',
'%' => '%', '+' => '+', '—' => '-', '-' => '-', '~' => '-',
':' => ':', '。' => '.', '、' => ',', ',' => '.', '、' => '.',
';' => ',', '?' => '?', '!' => '!', '…' => '-', '‖' => '|',
'”' => '"', '’' => '`', '‘' => '`', '|' => '|', '〃' => '"',
' ' => ' ');

return strtr($str, $arr);
}

全角与半角之区别(来自中文维基百科)

全角,又称全形、全宽,是电脑字符的一种格式,字面意思是比普通字符(或半角字符)宽的字符。

传统上,英语或拉丁字母语言使用一字节的空间来存储,而汉字、日语等常使用两字节存储,在使用固定宽度文字的地方,为了使字体看起来整齐,英文字母、数字及其他符号,也由原来只占用一个字空间,改为一概占用两个字的空间来显示,并且使用两个字节来存储。

回头想想,为啥全角就会出现问题呢?难道是字符集不一致……再度google

http://hi.baidu.com/clx2575167/blog/item/2f10071f3abdc3fee1fe0bfb.html

按照上面的介绍,utf-8的字符集应该是大于gb2312的,所以引起上述原因的肯定不是全角标点字符

狗日的,终于搜索到了,居然是iconv的bug,在转换到gb2312的过程中,如果碰到破折号'—'就会出现!

2Aug/101

[原创]解决服务器本地时间与UTC相差太大的方法(php class)

Posted by alacner

无废话版:
[cc lang='php']

/**
* Time class to resolve local time and UTC time inconsistency problem.
* If you use this class to your own program, you may need to re-implement T::_diff() function
*/

class T {

function its($time_servers = array()) {
// Internet Time Service (ITS)
$time_servers || $time_servers = array(
'time.nist.gov',//NCAR, Boulder, Colorado
'time-a.nist.gov',//NIST, Gaithersburg, Maryland
'time-b.nist.gov',//NIST, Gaithersburg, Maryland
'time-nw.nist.gov',//Microsoft, Redmond, Washington
'time-a.timefreq.bldrdoc.gov',//NIST, Boulder, Colorado
'time-b.timefreq.bldrdoc.gov',//NIST, Boulder, Colorado
'time-c.timefreq.bldrdoc.gov',//NIST, Boulder, Colorado
'utcnist.colorado.edu',//University of Colorado, Boulder
'nist1.symmetricom.com',//Symmetricom, San Jose, California
'nist1.aol-ca.truetime.com',//TrueTime, AOL facility, Sunnyvale, California
'nist1.datum.com',
);

foreach ($time_servers as $time_server) {
if ($time = T::_its($time_server)) return $time;
}

return false;
}

/**
* Time difference between ITS and locale time
*
* @return number|boolean
*/
function diff() {
static $diff = null;
if (!is_null($diff)) return $diff;

// Get time diff from cache
$diff = T::_diff();
if (!is_null($diff)) return $diff;

// Get now timestamp from ITS
if ($time = T::its()) {
$diff = (int)$time[0]-(int)$time[1];
T::_diff($diff);// cache time diff
return $diff;
}
return false;
}

/**
* Return current Unix timestamp fixed system time
*/
function now($timestamp = 0) {
$timestamp || $timestamp = T::locale();
return $timestamp + T::diff();
}

/**
* Return the system Unix timestamp
* @return number
*/
function locale() {
return time();
}

/**
* Format a local+diff time/date
*
* @param string $format Format string
* @param int $timestamp Default is T::now()
* @return string
*/
function format($format = 'Y-m-d H:i:s', $timestamp = 0) {
$timestamp && $timestamp += T::diff();
$timestamp || $timestamp = T::now();
return date($format, $timestamp);
}

/**
* Internet Time Service (ITS) - Daytime Protocol
* http://tf.nist.gov/service/its.htm
*
* @param $time_server its host, example: time.nist.gov
* @param $timeout Timeout
* @param $block Set blocking/non-blocking mode on a stream
* @return bool|array array(its timestamp, system tempstamp)
*/
function _its($time_server, $timeout = 5) {
$fp = @fsockopen($time_server, 13, $errno, $errstr, $timeout);
if (!$fp) return false;

stream_set_blocking($fp, TRUE);
stream_set_timeout($fp, $timeout);
@fwrite($fp, "\n");
$status = stream_get_meta_data($fp);
$status = stream_get_meta_data($fp);
if (!$status['timed_out']) {
while (!feof($fp)) {
if (($header = @fgets($fp)) && ($header == "\r\n" || $header == "\n")) {
break;
}
}

while (!feof($fp)) {
$return .= $data = fread($fp, 1);
if ($data === '*') {
$now = (int)ceil(array_sum(explode(' ', microtime())));
break;
}

}
//$now = time();
}

if (!$return) return false;
// $return Format: JJJJJ YR-MO-DA HH:MM:SS TT L H msADV UTC(NIST) OTM
// example: 55409 10-08-01 15:33:36 50 0 0 856.3 UTC(NIST) *
$date = substr($return, 6, 17);
$time = strtotime($date);
if ($time > 0 && date('y-m-d H:i:s', $time) === $date) return array($time, $now);

return false;
}

function _diff($diff = null) {
$cache_time_diff_file = sys_get_temp_dir() . 'time_diff.cache.php';
if (is_null($diff)) { //get diff
$diff = @include $cache_time_diff_file;
if (is_numeric($diff)) return (int)$diff;
return null;
}
// cache diff
file_put_contents($cache_time_diff_file, '');
}
}//end class
[/cc]

1Aug/100

xdebug 参数配置详解

Posted by alacner

安装:

  预编译模块

  安装预编译模块是很容易的。只需要将它们放到一个目录中,并将下面的内容添加到php.ini中:(不要忘记更改路径和文件名为你自己的值,并确信你使用的是完整路)

  zend_extension_ts = "c:/php/modules/php_xdebug.dll"

  基本特征:

  相关参数设置

  xdebug.default_enable

  类型:布尔型 默认值:On

  如果这项设置为On,堆栈跟踪将被默认的显示在错误事件中。你可以通过在代码中使用xdebug_disable()来禁止堆叠跟踪的显示。因为这是xdebug基本功能之一,将这项参数设置为On是比较明智的。

  xdebug.max_nesting_level

  类型:整型 默认值:100

  The value of this setting is the maximum level of nested functions that are allowed before the script will be aborted.

  限制无限递归的访问深度。这项参数设置的值是脚本失败前所允许的嵌套程序的最大访问深度。

  堆栈跟踪:

  相关参数设置

  xdebug.dump_globals

  类型:布尔型 默认值:1

  限制是否显示被xdebug.dump.*设置定义的超全局变量的值

  例如,xdebug.dump.SERVER = REQUEST_METHOD,REQUEST_URI,HTTP_USER_AGENT 将打印 PHP 超全局变量 $_SERVER['REQUEST_METHOD']、$_SERVER['REQUEST_URI'] 和 $_SERVER['HTTP_USER_AGENT']。

  xdebug.dump_once

  类型:布尔型 默认值:1

  限制是否超全局变量的值应该转储在所有出错环境(设置为Off时)或仅仅在开始的地方(设置为On时)

  xdebug.dump_undefined

  类型:布尔型 默认值:0

  如果你想从超全局变量中转储未定义的值,你应该把这个参数设置成On,否则就设置成Off

  xdebug.show_exception_trace

  类型:整型 默认值:0

  当这个参数被设置为1时,即使捕捉到异常,xdebug仍将强制执行异常跟踪当一个异常出现时。

  xdebug.show_local_vars

  类型:整型 默认值:0

  当这个参数被设置为不等于0时,xdebug在错环境中所产生的堆栈转储还将显示所有局部变量,包括尚未初始化的变量在最上面。要注意的是这将产生大量的信息,也因此默认情况下是关闭的。

  分析PHP脚本

  相关参数设置

  xdebug.profiler_append

  类型:整型 默认值:0

  当这个参数被设置为1时,文件将不会被追加当一个新的需求到一个相同的文件时(依靠xdebug.profiler_output_name的设置)。相反的设置的话,文件将被附加成一个新文件。

  xdebug.profiler_enable

  类型:整型 默认值:0

  开放xdebug文件的权限,就是在文件输出目录中创建文件。那些文件可以通过KCacheGrind来阅读来展现你的数据。这个设置不能通过在你的脚本中调用ini_set()来设置。

  xdebug.profiler_output_dir

  类型:字符串 默认值:/tmp

  这个文件是profiler文件输出写入的,确信PHP用户对这个目录有写入的权限。这个设置不能通过在你的脚本中调用ini_set()来设置。

  xdebug.profiler_output_name

  类型:字符串 默认值:cachegrind.out%p

  这个设置决定了转储跟踪写入的文件的名称。

  远程Debug

  相关参数设置

  xdebug.remote_autostart

  类型:布尔型 默认值:0

  一般来说,你需要使用明确的HTTP GET/POST变量来开启远程debug。而当这个参数设置为On,xdebug将经常试图去开启一个远程debug session并试图去连接客户端,即使GET/POST/COOKIE变量不是当前的。

  xdebug.remote_enable

  类型:布尔型 默认值:0

  这个开关控制xdebug是否应该试着去连接一个按照xdebug.remote_host和xdebug.remote_port来设置监听主机和端口的debug客户端。

  xdebug.remote_host

  类型:字符串 默认值:localhost

  选择debug客户端正在运行的主机,你不仅可以使用主机名还可以使用IP地址

  xdebug.remote_port

  类型:整型 默认值:9000

  这个端口是xdebug试着去连接远程主机的。9000是一般客户端和被绑定的debug客户端默认的端口。许多客户端都使用这个端口数字,最好不要去修改这个设置。

  注意:所有以上参数修改后,要重启Apache才能生效!

1Aug/100

利用Xdebug分析PHP程序,找出性能瓶颈

Posted by alacner

经济学中有一条著名的80-20定律,引用到编程中,就是:80%的性能瓶颈是由20%的代码引起的。借助PHP的XDebug扩展,可以有效地找出这20%的代码。

  一、安装配置

  1、下载PHP的XDebug扩展,网址:http://xdebug.org/

  2、在Linux下编译安装XDebug

  引用
[cc lang='bash']
  tar -xzf xdebug-2.0.0RC3.gz

  cd xdebug-2.0.0RC3

  /usr/local/php/bin/phpize

  ./configure --enable-xdebug

  cp modules/xdebug.so /usr/local/php/extensions/
[/cc]
  注:/usr/local/php/extensions/不同的PHP版本路径不同,也不一定要放在该路径,可以在zend_extension_ts中自行指定xdebug.so所在位置。

  引用
[cc lang='bash']
  vi /usr/local/php/lib/php.ini
[/cc]
  修改php.ini,去除PHP加速模块,增加以下配置信息支持XDebug扩展
[cc lang='bash']
  [Xdebug]

  zend_extension_ts="/usr/local/php/extensions/xdebug.so"

  xdebug.profiler_enable=on

  xdebug.trace_output_dir="/tmp/xdebug"

  xdebug.profiler_output_dir="/tmp/xdebug"

  xdebug.profiler_output_name="script"
[/cc]
  引用
[cc lang='bash']
  mkdir -p /tmp/xdebug

  chmod 755 /tmp/xdebug

  chown www:www /tmp/xdebug

  /usr/local/apache/bin/apachectl -k restart
[/cc]
  3、客户端(Windows):WinCacheGrind

  下载地址:http://sourceforge.net/projects/wincachegrind/

  二、分析过程

  1、访问你的网站,将首页上各种链接点击几遍,XDebug在/tmp/xdebug目录生成以下文件:

  usr_local_apache_htdocs_app_checknum_chknum_php_cachegrind.out

  usr_local_apache_htdocs_app_login_showHeaderLogin_php_cachegrind.out

  usr_local_apache_htdocs_app_play_play_php_cachegrind.out

  usr_local_apache_htdocs_app_user_member_php_cachegrind.out

  usr_local_apache_htdocs_tag_tags_php_cachegrind.out

  usr_local_apache_htdocs_top_top_php_cachegrind.out

  2、将以上文件拷贝到Windows上,用客户端软件WinCacheGrind打开每个文件,发现以下PHP程序执行所耗费的时间最长:

  /usr/local/apache/htdocs/tag/tags.php      耗时840ms

  三、分析结果:

  1、/usr/local/apache/htdocs/tag/tags.php


  (1)耗时最长的filter_tags函数出现在/usr/local/apache/htdocs/tag/tags.php的第158行:

  $tags .= filter_tags($videos[$i]['tags'])." ";

  (2)filter_tags函数引自/usr/local/apache/htdocs/include/misc.php,getForbiddenTags函数被filter_tags函数调用了21次,filter_tags函数耗费的时间中绝大多数因getForbiddenTags函数所致。getForbiddenTags函数的内容如下:

[cc lang='php']
function getForbiddenTags()
{
 
 $tagsPath=TEMPLATE_FILE_PATH."tags/forbidden_tags.txt";
  if(file_exists($tagsPath))
  {
    $fp = fopen($tagsPath, "r");
   $arrconf = array ();
   if ($fp)
    {
    while (!feof($fp))
      {
     $line = fgets($fp, 1024);
     $line = trim($line);
     $rows = explode("#", $line);
     $coumns = explode("=", trim($rows[0]));
        if(""!=trim($coumns[0]))
        {
       $arrconf[trim($coumns[0])] = trim($coumns[1]);
        }
    }
   }
    return $arrconf;
  }
}
[/cc]

  (4)对getForbiddenTags函数进行分析,其中的PHP函数trim被调用了16827次。

  (5)可能造成瓶颈的原因:

  要过滤的156个关键字逐行存放在/usr/local/apache/template/tags/forbidden_tags.txt文件中,文本数据库的效率不高。

  逐行读取函数fgets、以及去除字符串两边的空白或者指定的字符的函数trim在高负载下的效率低,可以测试fopen、fread、fscanf之类的文件读取函数,对比一下。

转载自:http://blog.s135.com

31Jul/101

HTTP Authentication When PHP Runs As CGI/PHPSuExec

Posted by alacner

呵呵,原来以前给一个linux服务器的页面做最简单的验证,习惯用WWW-Authenticate的方式,一般也没问题,今天用的时候发现godaddy的是fcgi模式的,无法获取到$_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']两个变量,所以google了下,发现了一篇解决方案,不错,分享下:

PHP is a feature-rich programming language that includes simple HTTP authentication. Unfortunately, if PHP is running under CGI then PHP scripts cannot use HTTP authentication. The workaround for this problem is to use mod_rewrite to pass HTTP authentication info to scripts as a GET parameter.

The following are step-by-step instructions on how to get HTTP authentication working when PHP is running as a CGI/PHPSuExec.

Step 1:
Create a plain text file using a text editor such as Windows Notepad.

Step 2:
Add the following text...
[cc lang='bash']

RewriteEngine on
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]

[/cc]

Step 3:
Save the file as a plain text file. Name the file ".htaccess"

Step 4:
Upload the .htaccess file in ASCII mode to your web space using an FTP application.

Step 5:
Add the following in your PHP script right before your user/pass check routine.

[cc lang='php']
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
[/cc]

Example:
[cc lang='php']
// split user/pass parts
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));

// open user/pass prompt
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="Your Realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'Text to send if Cancel button is used';
exit;
} else {
echo "

Greetings:

".$_SERVER['PHP_AUTH_USER'];
echo "

Password you entered:

".$_SERVER['PHP_AUTH_PW'];
}
?>
[/cc]

转自:http://www.sslcatacombnetworking.com/articles/http-authentication-php-cgi.html

31Jul/100

undefined reference to `libiconv_open‘ 导致无法编译PHP

Posted by alacner

[cc lang='bash']

./configure --with-mysql=/backup/mysql --with-freetype-dir --with-jpeg-dir --with-png-dir --with-zlib --with-curl --with-gd --enable-gd-native-ttf --with-apxs2=/usr/local/apache/bin/apxs --enable-sockets --with-iconv

[/cc]
make时提示:

[cc lang='bash']
.....................................................
ext/iconv/.libs/iconv.o(.text+0x1738): In function `zif_iconv_mime_encode':
/home/work/php-5.2.0/ext/iconv/iconv.c:1017: undefined reference to `libiconv_open'
ext/iconv/.libs/iconv.o(.text+0x1756):/home/work/php-5.2.0/ext/iconv/iconv.c:1031: undefined reference to `libiconv_open'
ext/iconv/.libs/iconv.o(.text+0x1993):/home/work/php-5.2.0/ext/iconv/iconv.c:1290: undefined reference to `libiconv_close'
ext/iconv/.libs/iconv.o(.text+0x19ad):/home/work/php-5.2.0/ext/iconv/iconv.c:1293: undefined reference to `libiconv_close'
ext/iconv/.libs/iconv.o(.text+0x1b01):/home/work/php-5.2.0/ext/iconv/iconv.c:1102: undefined reference to `libiconv'
ext/iconv/.libs/iconv.o(.text+0x1b33):/home/work/php-5.2.0/ext/iconv/iconv.c:1134: undefined reference to `libiconv'
ext/iconv/.libs/iconv.o(.text+0x1b5e):/home/work/php-5.2.0/ext/iconv/iconv.c:1150: undefined reference to `libiconv'
ext/iconv/.libs/iconv.o(.text+0x1e10):/home/work/php-5.2.0/ext/iconv/iconv.c:1202: undefined reference to `libiconv'
ext/iconv/.libs/iconv.o(.text+0x1e3c):/home/work/php-5.2.0/ext/iconv/iconv.c:1233: undefined reference to `libiconv'
ext/iconv/.libs/iconv.o(.text+0x207f):/home/work/php-5.2.0/ext/iconv/iconv.c:1277: more undefined references to `libiconv' follow
ext/iconv/.libs/iconv.o(.text+0x2c08): In function `php_iconv_stream_filter_dtor':
/home/work/php-5.2.0/ext/iconv/iconv.c:2393: undefined reference to `libiconv_close'
ext/iconv/.libs/iconv.o(.text+0x2cf2): In function `php_iconv_stream_filter_append_bucket':
/home/work/php-5.2.0/ext/iconv/iconv.c:2543: undefined reference to `libiconv'
ext/iconv/.libs/iconv.o(.text+0x2d34):/home/work/php-5.2.0/ext/iconv/iconv.c:2543: undefined reference to `libiconv'
ext/iconv/.libs/iconv.o(.text+0x2de7):/home/work/php-5.2.0/ext/iconv/iconv.c:2465: undefined reference to `libiconv'
ext/iconv/.libs/iconv.o(.text+0x30e2): In function `php_iconv_stream_filter_factory_create':
/home/work/php-5.2.0/ext/iconv/iconv.c:2419: undefined reference to `libiconv_open'
collect2: ld returned 1 exit status
make: *** [sapi/cli/php] Error 1

[/cc]

解决方法:

[cc lang='bash']
#wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.13.1.tar.gz
#tar -zxvf libiconv-1.13.1.tar.gz
#cd libiconv-1.13.1
# ./configure --prefix=/usr/local/libiconv
# make
# make install

[/cc]

再检查php

[cc lang='bash']
#./configure --with-mysql=/backup/mysql --with-freetype-dir --with-jpeg-dir --with-png-dir --with-zlib --with-curl --with-gd --enable-gd-native-ttf --with-apxs2=/usr/local/apache/bin/apxs --enable-sockets --with-iconv=/usr/local/libiconv
#make
#make install

[/cc]

另一种解决方法为去除iconv模块也能正常编译php,如下:
編輯 Makefile 大約 77 行左右的地方:
[cc lang='bash']

EXTRA_LIBS = ..... -lcrypt
[/cc]

在最後加上 -liconv,例如:
[cc lang='bash']

EXTRA_LIBS = ..... -lcrypt -liconv
[/cc]

再运行make就可以了。

最后一种方法:由tonyty163提供:

[cc lang='bash']

#make ZEND_EXTRA_LIBS='-liconv'
#make install

[/cc]

Tagged as: , No Comments
23Jul/102

[原创]解除高耦合提高效能

Posted by alacner

最近有个项目,接口api负载预计会比较繁重,所以将采用队列的模式来解除这个耦合,因为提交的数据不需要很强的时效性,完全可以用异步的模式来处理。前端与api交互的当然是php,这个是毫无疑问的,不过几年的linux的了解和切身体验,在早期的时候也做过一些比较,用写数据为例,写相同数量的数据,如果把C的读写算作1的话,那么用php来处理将会是20左右,而用python,lua这种虚拟机机制更小的语言来处理,那么将是6左右,再加上php执行是加载入过多的模块,呃,至少我不知道如何去除这些模块,所以选择一种轻载的语言来处理进程交互数据,将是提高整体效率的很好途经,代价也比较小,同样的系统环境,可以处理更大的数据量。

以下为可分摊可扩展的实现示意图:

使用者(用户)量会很大,访问的api也会很多很频繁,比如微博,所有的api都会汇总在一个平台处理第三方的api,那么如何减少在应用api处提交时对使用者体验最好,互相作用力最小呢?(互相作用力,这里我的意思是:一个节点出现故障,会成为连锁反应,蝴蝶效应,当时在某上市公司的时候就遇到某个时间段突然上升的压力导致了某一台机器缓慢,最终引发整个机房的相关应用全部处于崩溃状态,全部处于active状态,因为都在等那台故障的机器的返回)答案就是引入高效的提交机制,快连快断,加入有序化管理,队列话,队列服务器也可以采用多台,由上层的proxy服务器来随机提交到某个队列中,然后立即返回给用户成功,随后,队列服务器上的进程(当然有条件的可以另外单独服务器)采用多进程盯某个队列,甚至可以优化成优先盯某个队列,某个队列处理完毕后可以辅助处理其他队列服务器中的数据。这里就不展开联想了,思路很多,然后通过进程服务与第三方的多种应用api交互,最终形成了可以任意扩展的异步消息传递系统。

队列服务系统也很多,简单的有张宴基于libevent和tokyocabinet写的httpsqs,当然还有很多复杂的队列,看具体应用而定了。

18Jul/103

zend studio 7.2 常用快捷键

Posted by alacner

最近一直在用zend studio 7.2在开发,整理了下本人认为最为常用的几个快捷键,希望可以给后来者提供一点点帮助,我怀念vi的那个时期,可惜现在的类文件,函数太多了,光靠我的烂记性来写出函数和类方法就比较吃力了,o(︶︿︶)o 唉,只能借助强大的IDE来提高工作效率,多一些微操,让生活更美好~

OK,直接无废话进入正题:
F3 快速跳转到当前所指的函数,常量,方法,类的定义处,相当常用。当然还可以用Ctrl+鼠标左键
win+D 显示桌面(可切回来)
shift+end 此行第一个到最后一个
shift+home 此行最后一个到第一个

Ctrl+home 文件头
Ctrl+end 文件尾
Ctrl+1 快速修复(传说中最经典的快捷键)
Ctrl+M 编辑窗口最大化
Ctrl+N=新建
Ctrl+D: 删除当前行
Ctrl+Q 定位到最后编辑的地方(我的语录:这个定位的不是当前文本的,也是一个全局的,要留意)
Ctrl+L 定位在某行 (对于程序超过100的人就有福音了)
Ctrl+M 最大化当前的Edit或View (再按则反之)
Ctrl+/ 注释当前行,再按则取消注释
Ctrl+O 快速显示 OutLine
Ctrl+T 快速显示当前类的继承结构
Ctrl+W 关闭当前Editer
Ctrl+K 参照选中的Word快速定位到下一个
Ctrl+E 快速显示当前Editer的下拉列表(如果当前页面没有显示的用黑体)
Ctrl+F 查找(小提醒:你要是比较懒,可以在wrap search上打上勾,这样就可以循环查找了,要不然只能forward、backward)
Ctrl+H 全局查找,功能很丰富的,用的比较多

Ctrl+Shift+E 显示管理当前打开的所有的View的管理器(可以选择关闭,激活等操作)
Ctrl+Shift+X 把当前选中的文本全部变为大写
Ctrl+Shift+Y 把当前选中的文本全部变为小写
Ctrl+Shift+F 格式化当前代码
Ctrl+Shift+P 定位到对于的匹配符(譬如{}) (从前面定位后面时,光标要在匹配符里面,后面到前面,则反之)
Ctrl+Shift+R 查找资源 (此快捷键利用率甚高,如果你没用到,可能你得考虑下,为什么其他程序员都用到频率很高,你没用到的原因)
Ctrl+Shift+T 查找某个具体的类
Ctrl+Shift+G 查找某个函数、方法、常量等在哪些地方被调用了,刚好和F3相反。

Alt+↓ 当前行和下面一行交互位置(特别实用,可以省去先剪切,再粘贴了)
Alt+↑ 当前行和上面一行交互位置(同上)
Alt+← 前一个编辑的页面
Alt+→ 下一个编辑的页面(当然是针对上面那条来说了)

Shift+Enter 在当前行的下一行插入空行(这时鼠标可以在当前行的任一位置,不一定是最后)
Shift+Ctrl+Enter 在当前行插入空行(原理同上条)

Shift+Alt+A  列编辑
Shift+Alt+R 重命名 (**慎重,改变所有workspace**,我当时以为改变一个文件,哈哈)

Ctrl+Alt+u svn的update
Ctrl+Alt+c svn的commit

最后带上,你忘记了快捷键怎么办?有一个汇总:Shift+Ctrl+l ,当然了,你也可以去Preferences -> General -> Keys里面慢慢翻……