升级MT dv 3.0主机到php5

MT主机dv 3.0上的php默认是4,现在已经是php5时代了,不知道MT什么时候默认给配php5,现阶段官方的方式仍然是由用户自行升级,详细步骤见kb中的Upgrade to PHP5 on (dv) 3.0 Dedicated Virtual Servers

推荐使用suexec方式,这样每个用户执行cgi使用的都是自己的身份,即安全也便于管理。suexec要求的前提条件有三个,就是用户的主机设置开启如下三个选项:

  • PHP支持打开,安全模式safe_mode关闭。
  • CGI支持打开。
  • FastCGI支持打开。

具体步骤说起来也是很简单的,首先把/opt/php51下的php5执行文件拷贝到用户目录下,并设置相应权限:

cp /opt/php51/cgi-bin/php5 /var/www/vhosts/<domain>/bin/
cd /var/www/vhosts/<domain>/
chown -R <domain-user>:psacln bin/

其中<domain>是用户的域名,<domain-user>是用户的ssh/ftp用户名,然后编辑/var/www/vhosts/<domain>/conf/vhost.conf文件,添加如下内容:

AddHandler fcgid-script .php .php5
SuexecUserGroup <domain-user> psacln
<Directory /var/www/vhosts/<domain>/httpdocs>
     FCGIWrapper /var/www/vhosts/<domain>/bin/php5 .php
     FCGIWrapper /var/www/vhosts/<domain>/bin/php5 .php5
     Options ExecCGI
     allow from all
</Directory>

如果是https站点,除了httpdocs换成httpsdocs之外,配置文件名称为vhost_ssl.conf。最后启用设置:

/usr/local/psa/admin/sbin/websrvmng -a -v

就可以了,我们主机上现在的php5版本是5.1.4,还是不够新:)。

为了方便操作,自己写了个小脚本:

#! /bin/bash
# Automatic enable php5 support for mediatemple user(via suexec).

# Pre-prepare in plesk:
#   php support is checked, safe_mod 'on' is UNCHECKED
#   cgi support is checked.
#   fastcgi support is checked.

# Check username, must run with root
WHOAMI=`whoami`
if [ ! $WHOAMI == 'root' ]; then
    echo "This script must run with root."
    exit 1
fi

# Check parameters
if [ $# -lt 2 ];then
    echo "Usage: `basename $0` ssh_user domain"
    exit 1
fi
USER=$1
DOMAIN=$2

# If given a wrong domain, exit
if [ ! -d /var/www/vhosts/$DOMAIN ]; then
    echo "Domain doesn't exists."
    exit 1
fi

# Copy php5 files
cp /opt/php51/cgi-bin/php5 /var/www/vhosts/$DOMAIN/bin/
cd /var/www/vhosts/$DOMAIN/
chown -R $USER:psacln bin/
cd conf

BEGIN="###_87b4e7fc -- Add by enable_php script, DON'T modify this section --"
END="# -- Enable_php modify section end -- 87b4e7fc_###"

# If vhost.conf doesn't exists, create it with default content
if [ -z vhost.conf ]; then
    echo "\\
$BEGIN\\
$END\\
" >> vhost.conf
else
    MARK=`grep "###_87b4e7fc" vhost.conf|wc -l`
    if [ $MARK -eq 0 ]; then
        # If vhost.conf exists & not mark, add replace mark
        echo "\\
$BEGIN\\
$END\\
" >> vhost.conf
    fi
fi
# Vhost_ssl.conf
if [ -z vhost_ssl.conf ]; then
    echo "\\
$BEGIN\\
$END\\
" >> vhost_ssl.conf
else
    MARK=`grep "###_87b4e7fc" vhost_ssl.conf|wc -l`
    if [ $MARK -eq 0 ]; then
        # If vhost.conf exists & not mark, add replace mark
        echo "\\
$BEGIN\\
$END\\
" >> vhost_ssl.conf
    fi
fi


STR="$BEGIN\\n\\
AddHandler fcgid-script .php .php5\\n\\
SuexecUserGroup $USER psacln\\n\\
<Directory \\/var\\/www\\/vhosts\\/$DOMAIN\\/httpdocs>\\n\\
    FCGIWrapper \\/var\\/www\\/vhosts\\/$DOMAIN\\/bin\\/php5 .php\\n\\
    FCGIWrapper \\/var\\/www\\/vhosts\\/$DOMAIN\\/bin\\/php5 .php5\\n\\
    Options \\+ExecCGI\\n\\
    allow from all\\n\\
<\\/Directory>\\n\\
<Directory \\/var\\/www\\/vhosts\\/$DOMAIN\\/httpsdocs>\\n\\
    FCGIWrapper \\/var\\/www\\/vhosts\\/$DOMAIN\\/bin\\/php5 .php\\n\\
    FCGIWrapper \\/var\\/www\\/vhosts\\/$DOMAIN\\/bin\\/php5 .php5\\n\\
    Options \\+ExecCGI\\n\\
    allow from all\\n\\
<\\/Directory>\\n\\
$END"

# Backup original configure
cp vhost.conf vhost.conf.`date +"%Y%m%d-%H%M%S"`
cp vhost_ssl.conf vhost_ssl.conf.`date +"%Y%m%d-%H%M%S"`

# Write configure information
sed -i -e ":begin; /###_87b4e7fc/,/87b4e7fc_###/ { /87b4e7fc_###/! { $! { N; b begin }; }; s/###_87b4e7fc.*87b4e7fc_###/$STR/g };" vhost.conf
sed -i -e ":begin; /###_87b4e7fc/,/87b4e7fc_###/ { /87b4e7fc_###/! { $! { N; b begin }; }; s/###_87b4e7fc.*87b4e7fc_###/$STR/g };" vhost_ssl.conf

# Active new configure
/usr/local/psa/admin/sbin/websrvmng -a -v

使用方法,用root用户执行:

enable_php5 <domain-user> <domain>

不支持subdomain的设置,其中sed替换多行内容的用法,可以参考我写的另外一篇文章用sed替换跨行内容

conf/vhost.conf这个文件存在之后,并不会自动被apache调用,执行/usr/local/psa/admin/sbin/websrvmng -a -v可以自动在conf/httpd.include文件中include vhost.conf了。而conf/httpd.include这个文件是由plesk维护的,用户不要直接修改它,会被plesk覆盖掉。

另外由于使用的是suexec方式执行,所以上传目录、cache等以前需要设置apache用户有可写权限的文件,现在要把owner设置为<domain-user>:psacln才行,和用户的其他文件权限一样就可以了,是不是管理起来更方便一些?

看了一下phpinfo,自动加载了位于/opt/php51/lib/php5/extensions/下的如下模块:

curl.so  gd.so        mysql.so    pdo.so        sockets.so  zlib.so
dom.so   iconv.so     mysqli.so   pdo_mysql.so  sqlite.so
ftp.so   mbstring.so  openssl.so  posix.so      xsl.so

基本上常用的都有了,但不知道/opt/php51这个目录下的内容MT什么时候给更新,还是说需要用户自己更新?

参考

用sed替换跨行内容

sed是*nix下方便的行编辑工具,经常用来替换文件的内容,sed一般都是处理单行的,但通过它的一些内建功能,也能实现跨行替换(即要替换的内容有多行内容)。

解决方法主要来自网上搜到的一篇文章,但文中的大侠并没有解释得特别清楚,我对照着其他两个更晦涩的例子(),结合man搞懂了之后,记录于此。

假设我们的目标文件test内容是这样的:

file content
  aabbcc<<<comment part 1
  comment part 2>>>
  ddeeff

现在需要把[[[…]]]这一段替换为“COMMENT”(为了说明的必要,没有用容易和正则相混淆的字符比如//*{}[]等来举例子),那么sed语法应当是:

:begin
/<<</,/>>>/ {
    />>>/! {
        $! {
            N;
             b begin
        }
    }
    s/<<<.*>>>/COMMENT/;
}

上述语句存储在test.sed中,那么执行的方式和结果就是:

$ sed -f test.sed test
        file content
          aabbccCOMMENT
          ddeeff

把正则直接写到命令里面也可以,用“;”来分隔命令即可:

$ sed -e ":begin; /<<</,/>>>/ { />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
        file content
          aabbccCOMMENT
          ddeeff

注意右花括号之后也要加上分号“;”,如果再加上-i参数就可以直接把改动写到原文件中去了。

怎么样?看懂了么?我来详细说明吧,看那个多行命令的test.sed文件的内容:

  • 首先花括号{}代表命令块的开始,类似c的语法,后面就不再说了。

  • :begin,这是一个标号,man中叫做label,也就是跳转标记,供b和t命令用,本例中使用了b命令。

  • /<<</,/>>>/,这是一个地址范围(Addresses),后面{}中的命令只对地址范围之间的内容使用。其中逗号前面的部分是开始地址,逗号后面是结束地址,都是正则表达式。由于sed是“流”式“行”处理,所以结束地址是可以省略的,即如果地址的结束范围不存在,那么将一直处理到文件结尾。本例中使用这个地址范围主要是缩小处理的数据量,因为虽然后面用N命令把对一行的处理扩展为了多行,但如果从文件开头一直N扩展到<<<出现为止,buffer中要处理的字符串可能会很长,影响效率。所以去掉这个处理范围也是能够得到正确结果的,比如:

    $ sed -e ":begin; { />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
    or
    $ sed -e "{:begin;  />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
    
  • />>>/!>>>是要替换内容的结束标记,带上!就是说当一行处理完毕之后,如果没有发现结束标记。。。

  • $!$在正则中表示字符串结尾,在sed中代表文件的最后一行,本句和上一句结合起来的意思就是:如果在本行没有发现结束标记,并且当前扫描过的行并不是文件的最后一行。

  • N;,把下一行的内容追加(append)到缓冲区(pattern)之后,在我们的例子中,在处理aabbcc<<<comment part 1这一行的内容时,就会执行到这里,然后把下一行的内容comment part 2>>>一起放入缓冲区,相当于“合并”成了一行(sed的缓冲区中默认都只会包含一行的内容)。

  • b begin,由于仍然没有找到结束标记<<<(注意上一条说的缓冲区还没有被处理),所以在这里跳回到标号begin,重新开始命令。如果开始和结束标记之间间隔了多行,那么就会有多次跳转发生。

  • s/<<<.*>>>/COMMENT/;,终于,/>>>/!不再匹配成功,也就是我们已经找到了结束标记,那么用s命令来进行替换。如果开始和结束标记在一行的话,就会越过上面那些复杂的处理,直接执行到这里了。

介绍完毕,收工。

Update @ 2007-12-14

在和bxy讨论的过程中,又发现sed的另外一种用途,从html或xml中按照tag对应关系,筛选打印出指定的tag内容,使用了正则中的p命令,好像默认就没有“不能处理多行内容”以及“贪婪性”的问题,很好用,很强大:

    $ sed -n -e '/<title>/p' -e '/<text /,/<\/text>/p' from.xml

注意//不在同一行的时候才好用,不然会匹配到下一个实例出现的位置作为结束边界。

CSS裸奔节之强制脱衣

今天是CSS裸奔节,所谓CSS裸奔,就是把网站的所有css去掉,这样所有的显示格式什么的就都没有了,只剩下html实体显示出来,起源好像是比较无聊的想法,就是剥去css的外衣,让大家看看你的(x)html代码是否工整。

不过今天偶不打算裸奔,而是告诉大家一个可以看到任何网站裸奔形象的方法,参考我以前写的用js丰富你的书签功能,创建一个书签,也可以放到书签工具栏上,内容如下:

javascript:void((function(){var style=document.getElementsByTagName('style');for (i=0; i<style.length; i++)style.item(i).disabled=true;var link = document.getElementsByTagName('link');for (i=0; i<link.length; i++)if ('text/css' == link.item(i).type)link.item(i).disabled=true;var obj = document.getElementsByTagName('*');for (i=0; i<obj.length; i++){obj1 = obj.item(i);if (obj1.attributes.getNamedItem('style')){obj1.attributes.getNamedItem('style').value = '';}}})());

注意一定要是一行才行,作为书签地址就可以了,然后打开任何一个网站,点这个书签,是不是把css全部都脱掉了?懒人也可以直接把这个链接拖到工具栏上使用:

CSS裸奔

公布源代码如下,没有太复杂的地方,有了DOM说明,知道各个对象的方法和属性之后,把stylelink全部禁用,然后把inline的style=""的value全部设置为空串就可以了:

javascript:void((function(){
/* 用style方式引用的css */
var style=document.getElementsByTagName('style');
var s='Style:' + style.length;
for (i=0; i<style.length; i++)
{
    /*s += style.item(i) + '|';*/
    style.item(i).disabled=true;
}
/* 用link方式引用的css */
var link = document.getElementsByTagName('link');
s += 'Link:' + link.length;
for (i=0; i<link.length; i++)
    if ('text/css' == link.item(i).type)
        {
            /*s += link.item(i).href + "|\\n";*/
            link.item(i).disabled=true;
        }
/* 任意对象的style="" */
var obj = document.getElementsByTagName('body').item(0).childNodes;
var obj = document.getElementsByTagName('*');
s += 'Obj:' + obj.length;
for (i=0; i<obj.length; i++)
{   
    obj1 = obj.item(i);
    if (obj1.attributes.getNamedItem('style'))
    {
        s += obj1.nodeName + obj1.attributes.getNamedItem('style').value + "\\n";
        obj1.attributes.getNamedItem('style').value = "";
    }
}
/*alert(s);*/
})());

这个文件删除掉注释以后,可以用下面这个命令转换为一行:

cat css1.js |tr -d \\\\n |sed -r -e 's/$/\\n/' -e 's/\\t//g'

这样就得到了上面那段源代码。

javascript程序调试比较麻烦,以前我的方法是在vim中编辑,然后用命令转化为一行,再手工粘贴到书签的地址中,执行,然后有错误再回到编辑。不过今天发现一个好方法,其实也就是脑子转个弯儿的事,创建一个html文件,在里面把javascript代码调试好,然后再转换为可以用在书签中的形式。

另外Firefox2的Error Console虽然能够监测js错误,但是如果不小心点了上面的“Messages”,就会发现错误不显示了,需要再点“All”查看所有信息,今天为这是纳闷了半天,因为切换显示错误分类的时候没有任何征兆。

参考: