Monday, June 29, 2009

Convert Zend Framework project to UTF-8

Here is an article about converting Zend Framework project to UTF-8:

http://www.iezzi.ch/archives/371

another post of PHP performance

http://php100.wordpress.com/2009/06/26/php-performance-google/

PHP performance tips from Google

Posted by Stas on June 26, 2009

I saw a link on twitter referring to PHP optimization advice from Google. There are a bunch of advices there, some of them are quite sound, if not new – like use latest versions if possible, profile your code, cache whatever can be cached, etc. Some are of doubtful value – like the output buffering one, which could be useful in some situations but do nothing or be worse in others, and if you’re a beginner generally it’s better for you to leave it alone until you’ve solved the real performance problems.

However some of the advices make no sense at best and are potentially harmful at worst. Let’s get to it:

First one: Don’t copy variables for no reason. I don’t know what the author intended to describe there, but PHP engine is refcounting copy-on-write, and there’s absolutely no copying going on when assigning variables as they described it:
$description = strip_tags($_POST['description']);
echo $description;

I don’t know where it comes from but it’s just not so, unless maybe in some prehistoric version of PHP. Which means unless you’re going back to 1997 in a time machine this advice is no good for you.

Next one: Avoid doing SQL queries within a loop. This actually might make sense in some situations, however the code examples they give there is missing one important detail that makes it potentially harmful for beginners (see if you can spot it):
$userData = [];
foreach ($userList as $user) {
$userData[] = '("' . $user['first_name'] . '", "' . $user['last_name'] . '")';
}
$query = 'INSERT INTO users (first_name,last_name) VALUES' . implode(',', $userData);
mysql_query($query);

Please repeat after me – DO NOT INSERT USER DATA INTO SQL WITHOUT SANITIZING IT!
Of course, I can not know that $user was not sanitized. Maybe the intent was that it was. But if you give such example and target beginners, you should say so explicitly, every time! People tend to copy/paste examples, and then you get SQL injection in a government site.

Another thing: most of real-life PHP applications usually do not insert data in bulk, except for some very special scenarios (bulk data imports, etc.) – so actually in most cases one would be better off using PDO and prepared statements. Or some higher-level frameworks which will do it for you. But if you roll your own SQL – sanitize the data! This is much more important than any performance tricks.

Next one: Use single-quotes for long strings. PHP code is parsed and compiled, and any possible difference in speed between parsing “” and ” is really negligible unless you operate with hundreds of megabyte-size strings embedded in your code. If you do so, your quotes probably aren’t where you should start optimizing. And of course, using caching (see below) eliminates this difference altogether.

Next one: Use switch/case instead of if/else. This makes no sense since switch does essentially the same things as if’s do. See for yourself, here is the “if” code:
0 2 A(0) = FETCH_R(C("_POST")) [global]
1 2 A(1) = FETCH_DIM_R(A(0), C("action")) [Standard]
2 2 T(2) = IS_EQUAL(A(1), C("add"))
3 2 JMPZ(T(2), 7)
4 3 INIT_FCALL_BY_NAME(function_table, C("addUser"))
5 3 Au(3) = DO_FCALL_BY_NAME() [0 arguments]
6 4 JMP(16)
7 4 A(4) = FETCH_R(C("_POST")) [global]
8 4 A(5) = FETCH_DIM_R(A(4), C("action")) [Standard]
9 4 T(6) = IS_EQUAL(A(5), C("delete"))
10 4 JMPZ(T(6), 14)
11 5 INIT_FCALL_BY_NAME(function_table, C("deleteUser"))
12 5 Au(7) = DO_FCALL_BY_NAME() [0 arguments]
13 6 JMP(16)
14 7 INIT_FCALL_BY_NAME(function_table, C("defaultAction"))
15 7 Au(8) = DO_FCALL_BY_NAME() [0 arguments]
16 9 RETURN(C(1))
17 9 HANDLE_EXCEPTION()

Here is the “switch” code:
0 2 A(0) = FETCH_R(C("_POST")) [global]
1 2 A(1) = FETCH_DIM_R(A(0), C("action")) [Standard]
2 3 T(2) = CASE(A(1), C("add"))
3 3 JMPZ(T(2), 8 )
4 4 INIT_FCALL_BY_NAME(function_table, C("addUser"))
5 4 Au(3) = DO_FCALL_BY_NAME() [0 arguments]
6 5 BRK(0, C(1))
7 6 JMP(10)
8 6 T(2) = CASE(A(1), C("delete"))
9 6 JMPZ(T(2), 14)
10 7 INIT_FCALL_BY_NAME(function_table, C("deleteUser"))
11 7 Au(4) = DO_FCALL_BY_NAME() [0 arguments]
12 8 BRK(0, C(1))
13 9 JMP(15)
14 9 JMP(19)
15 10 INIT_FCALL_BY_NAME(function_table, C("defaultAction"))
16 10 Au(5) = DO_FCALL_BY_NAME() [0 arguments]
17 11 BRK(0, C(1))
18 12 JMP(20)
19 12 JMP(15)
20 12 SWITCH_FREE(A(1))
21 13 RETURN(C(1))
22 13 HANDLE_EXCEPTION()
No. CONT BRK Parent
0 20 20 -1

You can see there’s a little difference – the latter has CASE/BRK opcodes, which act more or less like IS_EQUAL and JMP, but their plumbing is a bit different, but in general, code is the same (you could even argue “switch” code is a bit less optimal, but that is really the area you shouldn’t be concerned with before you can read and understand the code in zend_vm_def.h – which is not exactly a beginner stuff.

Another thing that the author absolutely failed to mention and which should be one of the very first things anybody who cares about performance should do – is to use a bytecode cache. There are plenty of free ones (shameless plug: Zend Server CE includes one of them – all the performance improvements for $0 and you don’t have to change a bit of code to run it.

Now, I understand Google is not a PHP shop like Yahoo or Facebook or many others. But this article is signed “Eric Higgins, Google Webmaster” and one would expect something much more sound from such source. And in fact there are a lot of blogs and conference talks on the topic and lots of community folks around that I am sure would be ready to help with such article – I wonder why wasn’t it done? Why apparently the best advice we can find from Google is either trivial or useless or wrong?

I think they can do much better, and they should if they take “making the web faster” seriously.

Monday, June 15, 2009

facebook username

I got my facebook username: hengrui.li, so now u can reach me at http://www.facebook.com/hengrui.li

Friday, June 12, 2009

vim中大小写转化

vim中大小写转化的命令是
gu或者gU
形象一点的解释就是小u意味着转为小写;大U意味着转为大写.

剩下的就是对这两个命令的限定(限定操作的行,字母,单词)等等

1、整篇文章大写转化为小写
打开文件后,无须进入命令行模式。键入:ggguG

解释一下:ggguG分作三段gg gu G
gg=光标到文件第一个字符
gu=把选定范围全部小写
G=到文件结束
2、整篇文章小写转化为大写
打开文件后,无须进入命令行模式。键入:gggUG

解释一下:gggUG分作三段gg gU G
gg=光标到文件第一个字符
gU=把选定范围全部大写
G=到文件结束
3、只转化某个单词
guw 、gue
gUw、gUe
这样,光标后面的单词便会进行大小写转换
想转换5个单词的命令如下:
gu5w、gu5e
gU5w、gU5e
4、转换几行的大小写
将光标定位到想转换的行上,键入:1gU 从光标所在行 往下一行都进行小写到大写的转换
10gU,则进行11行小写到大写的转换
以此类推,就出现其他的大小写转换命令
gU0 :从光标所在位置到行首,都变为大写
gU$ :从光标所在位置到行尾,都变为大写
gUG :从光标所在位置到文章最后一个字符,都变为大写
gU1G :从光标所在位置到文章第一个字符,都变为大写

Wednesday, June 10, 2009

naming submit button "submit" break things

The form element has a method named submit, but also has the form elements in the form as members.

If you have a button in the form named submit, you could access it using document.form1.submit. However, as that is the same name as the submit method, there is no longer any way of accessing that method. If you use the method to submit the form, that will no longer work.

For example, if you have a button that submits the form using Javascript, that doesn't work:

< input type="button" name="submit" onclick="this.form.submit();" value="try" />

When the button tries to use the submit method, it will instead get a reference to itself (and an error message when trying to call it, as the button is not a function).

Monday, June 8, 2009

install svn on windows

Setting up a Subversion Server under Windows

I talked a little bit about what Subversion is in my previous post. Now, let's get it set it up in Windows.

Luckily for us, Joe White has done most of the work already; he has a tremendously helpful post that documents how to set up Subversion. I'll see if I can streamline his excellent post a bit further, and illustrate it with screenshots.

A) Download Subversion

You'll need the latest version of..

* the Windows binaries
* the "run Subversion as a windows service" wrapper
* the TortoiseSVN shell integration utility

B) Install Subversion

1. Unzip the Windows binaries to a folder of your choice. I chose c:\program files\subversion\ as my path.
2. Now, add the subversion binaries to the path environment variable for the machine. I used %programfiles%\subversion\bin\

3. You'll also need another environment variable, SVN_EDITOR, set to the text editor of your choice. I used c:\windows\notepad.exe

C) Create a Repository

1. Open a command prompt and type

svnadmin create "c:\Documents and Settings\Subversion Repository"

2. Navigate to the folder we just created. Within that folder, uncomment the following lines in the /conf/svnserve.conf file:

[general]
anon-access = read
auth-access = write
password-db = passwd

Next, uncomment these lines in the /conf/passwd file:

[users]
harry = harryssecret
sally = sallyssecret

D) Verify that everything is working

1. Start the subversion server by issuing this command in the command window:

svnserve --daemon --root "C:\Documents and Settings\Subversion Repository"

2.

Create a project by opening a second command window and entering this command:

svn mkdir svn://localhost/myproject

It's a standard Subversion convention to have three folders at the root of a project:

/trunk
/branches
/tags

3.

At this point, Notepad should launch:

Enter any comment you want at the top of the file, then save and exit.

4.

You'll now be prompted for credentials. In my case I was prompted for the administrator credentials as well:

Authentication realm: 0f1a8b11-d50b-344d-9dc7-0d9ba12e22df
Password for 'Administrator': *********
Authentication realm: 0f1a8b11-d50b-344d-9dc7-0d9ba12e22df
Username: sally
Password for 'sally': ************

Committed revision 1.

Congratulations! You just checked a change into Subversion!

E) Start the server as a service

1. Stop the existing command window that's running svnserve by pressing CTRL+C.
2. Copy the file SVNService.exe from the zip file of the same name to the subversion\bin folder.
3. Install the service by issuing the following commands:

svnservice -install --daemon --root "C:\Documents and Settings\Subversion Repository"
sc config svnservice start= auto
net start svnservice

4. Test the new service by listing all the files in the repository:

svn ls svn://localhost/

You should see the single project we created earlier, myproject/

F) Set up the shell extension

1. Run the TortoiseSVN installer. It will tell you to restart, but you don't need to.
2. Create a project folder somewhere on your hard drive. Right click in that folder and select "SVN Checkout..."



type svn://localhost/myproject/ for the repository URL and click OK.


3. Create a new file in that directory. Right click the file and select "TortoiseSVN, Add"


4. The file hasn't actually been checked in yet. Subversion batches any changes and commits them as one atomic operation. To send all your changes to the server, right click and select "SVN Commit":



And we're done! You now have a networked Subversion server and client set up on your machine. Note that the default port for svnserve is 3690.


CHINESE VERSION:

SubVersion服务器Windows安装指南
SubVersion及TortoiseSVN下载请到其官方网站:http://subversion.tigris.org
注:如果要使用TortoiseSVN中文界面,还要下载其语言安装包. 若只在本地计算机上使用,不使用SubVersion服务,则只需安装TortoiseSVN相关组件即可.

一.下载文件列表:

1.SubVersion 点击这里下载,版本是1.3.0,SubVersion服务程序.

2.TortoiseSVN 点击这里下载,版本是1.3.2,SubVersion客户端程序.

3.TortoiseSVN 中文语言包 点击这里下载,版本与上面的匹配.

4.SVNService 点击这里下载,可以将SubVersion服务包装成Windows NT服务.

二.安装步骤

1.安装SubVersion

2.安装TortoiseSVN及语言包

3.配置SubVersion服务

SubVersion本身是由命令行启动的,在SubVersion安装目录中找到,它不能像Windows NT服务一样随Windows启动,需要借SVNService来包装成Windows NT服务.具体设置如下:

将下载的SVNService解包后,将其中的拷贝到SubVersion的安装目录中的\bin目录, 保证SVNService.exe和svnserve.exe在同一目录.

安装服务:
运行命令:SVNService -install -d -r
在实际操作中,代表SubVersion服务的电子仓库目录.

改变服务设置:
运行命令:SVNService -setup -d -r
在实际操作中,代表与SubVersion服务启动时不同的电子仓库目录.

删除服务:
运行命令:SVNService -remove

4.用TortoiseSVN创建电子仓库

TortoiseSVN客户端不是独立的程序,而是与Windows Explorer进行了外壳集成,其操作通过环境菜单来完成.



如上图所示:
1.创建名为SVNroot的空目录
2在目录上,或在在目录内空白处点右键,从TortoiseSVN菜单中选择Create repository here...(在此处创建电子仓库),在选择电子仓库类型后,将会自动生成一些文件和目录.这样就完成了电子仓库的创建,你可以用同样的方法创建多个电子仓库.

注:电子仓库类型有两种可供选择,选择任意一种即可:
1.Native filesystem(FSFS) 本地文件系统
2.Berkely database(BDB) Berkely数据库
不同的选择只会影响电子仓库的数据存取格式,默认选择为:Native filesystem

在本例中,可以用:SVNService -install -d -r e:\svnroot来安装SubVersion服务

要问本机安装的服务请在右键菜单中选择Reop-browser(电子仓库浏览),弹出如下对话框:

Congratulations, Roger Federer

从你身上, 我看到了执着,坚韧和顽强. 更明白了什么叫天道酬勤. 祝贺你成为历史上最伟大的网球选手, 更欣喜你坚持不懈的付出终于得到了回报.

Monday, June 1, 2009

MYSQL主从数据库同步备份

首先两台机器:
a: 192.168.0.1
b: 192.168.0.2


打开a机器的my.cnf/my.ini设置

首先要保证要同步的数据库内容完全一致

在[mysqld]下添加以下内容
server-id=1

log-bin=/var/db/mysql/master.log

binlog-do-db=要同步的数据库名称 //不写就同步全部。
#binlog-ignore-db = mysql //忽略的数据库

增加一个backup的用户

GRANT FILE,REPLICATION SLAVE,REPLICATION CLIENT,SUPER ON *.* TO backup@'192.168.0.2' IDENTIFIED by 'backuppassword';
这个权限表示,这个backup账号只能由从备份机192.168.0.2访问只能用来进行备份操作


因为要实现双向备份,所以a上还要加以下内容。 如果是单向,则不需要加。
master-host=192.168.0.2
master-user=backup
master-password=backuppassword
master-port=3306
master-connect-retry=60
replicate-do-db=要同步的数据库
#replicate-ignore-db=不同步的数据库

打开b机器的my.cnf/my.ini文件
添加或修改以下内容
server-id=2

master-host=192.168.0.1
master-user=backup
master-password=backuppassword
master-port=3306
master-connect-retry=60
replicate-do-db=要同步的数据库
#replicate-ignore-db=不同步的数据库

如果要双向同步则再加上以下内容

log-bin=/var/db/mysql/master.log
binlog-do-db=要同步的数据库名称
#binlog-ignore-db = mysql //忽略的数据库

再增加一个帐号给a
GRANT FILE,REPLICATION SLAVE,REPLICATION CLIENT,SUPER ON *.* TO backup2@'192.168.0.1' IDENTIFIED by 'backuppassword';


至此基于mysql的同步功能就做好了。
重起两边的服务器。 用show master status查看主服务器状态。 用 show slave status 查看从服务器状态。

slave stop; 停止从服务器
slave start; 启动从服务器
master stop; 停止主服务器
master start; 启动主服务器

用show processlist可以查看同步状态。
如果有什么错误打开mysql的 hostname.err 查看原因,再调用下面的修改命令:

CHANGE MASTER TO
MASTER_HOST='master_host_name',
MASTER_USER='master_user_name',
MASTER_PASSWORD='master_pass',
MASTER_LOG_FILE='recorded_log_file_name',
MASTER_LOG_POS=recorded_log_position;

然后再重起slave;

install multiple mysql instances on windows

1.正常安装Windows版的Mysql,例如安装在d:\mysql文件夹里;

2.按照常规配置好Mysql;

3.复制备份安装好的文件夹,比如备份到另外一个文件夹,或者命名为“复件mysql";

4.运行卸载程序删除安装的MYSQL和文件夹;

5.把备份的mysql文件夹,重新恢复原来的名字,或还原到原来的位置上;

6.再次运行安装程序,安装在另外一个目录,例如:“d:\mysql2"。配置端口为3307;

现在,后面安装的第二个Mysql——mysql2肯定是可以正常运行的,下面让起初安装的第一个Mysql

服务正常运行:

在cmd命令行模式下,进入第一个Mysql的\bin文件夹。

执行mysql-nt install mysql2命令。作用是为Mysql安装一个服务,服务名是mysql2,你也可以自己改名字,比如mysql5,那么命令就是:

mysql-nt install mysql5

完毕后,在运行里运行REGEDIT,打开WINDOWS注册表编辑器,在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\项目找到你刚才手动安装的服务,

我这里是mysql2。打开,修改下面的ImagePath数值。

你一般将会看到"D:\mysql\bin\mysqld-nt" mysql2类似的数值。

在mysql-nt"和mysql2之间加入my.ini的路径信息,格式为:

--defaults-file="d:\mysql\my.ini"

其中粗体部分替换你的正确的路径,

修改完毕后数据数值一般是类似这个样子:

"D:\mysql\bin\mysqld-nt"
--defaults-file="d:\mysql\my.ini" mysql2

确定,退出注册表编辑器。

然后就可以正常启动mysql2服务了,在CMD窗口下输入命令:

net start mysql2

一般应能正常启动了。

我的经历, 按以上配置好后, 我无法同时启动两个MYSQL服务, 经研究, 原因是

MYSQL5.1把DATA文件夹分离出来, 放在datadir="C:/ProgramData/MySQL/MySQL Server 5.1/Data/", 要修改其中一个MY.INI配置, 把DATA文件夹放在另一个不同的地方, 就可以了.