Skip navigation.

极湖

无不用其“极”

March 2008

( Monthly archive )

通过浏览器自动安装 DRM 许可证的代码 (Windows Media Player)

, , ,

Windows 媒体播放器下的 DRM 的版权保护机制,用 JavaScript 控制 HTML 内嵌对象来实现。
为了对不同的文件安装不同的许可证,需要动态生成相应的代码,以下是我的一个土办法(Perl):
# 这儿是许可证
$licenseID = "......"; 

# 页面载入时的JavaScript代码
my $add_js = qq|
<script Language="JavaScript">
    function StoreLicense() {
        GetLicenseObj.StoreLicense('<LICENSERESPONSE>$licenseID</LICENSERESPONSE>');
    }

    try{
        window.addEventListener('load', StoreLicense, true);
    } catch(ex) {
        window.attachEvent('onload', StoreLicense);
    }
</script>
|;

# DRM对象的HTML代码
my $add_html = qq|
<object id="GetLicenseObj" classid="clsid:A9FC132B-096D-460B-B7D5-1DB0FAE0C062" name="GetLicenseObj" viewastext>
    <embed mayscript type="application/x-drm-x2" hidden="true">
    </embed>
</object>
|;

# 打开 HTML 文件,插入以上代码并送出
open(TMP, $html_path) or die "Can not open temp file: $html_path";
print "Content-type: text/html\n\n";
while(<TMP>) {
    
    if( /[\s\t]*<\/head/i ) {
        print $add_js;
    } elsif( /[\s\t]*<\/body/i ) {
        print $add_html;
    }
    print $_;
}

close(TMP);

以上方法,仅供参考,切勿照抄。

第一个 Flex3 程序

公司领导说接下来的活要用 Flex3,叫我我有空学习一下。

Adobe Flex Builder 3 装好之后,做了第一个程序 HelloWorld,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Text x="10" y="10" text="Hello World"/>
<mx:Label x="10" y="10" text="HelloWorld!" fontSize="40"/>
<mx:Script>
<![CDATA[
  private function buttonClick():void{
    button1.label = "Hello World";
    trace("按钮button1被点击!");
  }
]]>
</mx:Script>
<mx:Button x="10" y="56" label="Button" id="button1" click="buttonClick();"/>
</mx:Application>

原来用 XML 和 JavaScript ,就能做 Flash,哈,不错不错!

Drupal 6.1 体验

,

闲着没事装了个 Drupal 6.1 ,暂作学习研究之用。

以前也安装过 Drupal ,都是放一段时间就删了,一来没什么内容可作,二来也没有体会到 Drupal 的强大和方便。在普通用户眼中,Drupal 跟一个普通的 Blog 发布系统差不了太多,很多人宁可用 WordPress,因为后者更方便,而且有很多的插件和主题可选择。

为了体会 Drupal 之不同于 Blog 的 CMS 的功能,我决定用新装的系统发布一本书,我选的书是《古文观止》。

经过一番鼓捣后,“极湖”版的《古文观止》上线了。

在 Drupal 里面组织一本书的容易还真容易,因为系统默认有个 Book 模块(以前的 Drupal 中文版翻译成“手册”),用这个模块做Web版的电子书,层次很清楚,如果发表的时候章节顺序搞错了,调整起来也很容易,拖放即可。

目前只用了一个模块,已经感觉到 Drupal 是一个相当不错的内容管理系统,以后会考虑用它来做网站。

一些日文处理的正则表达式(Perl)

, ,

# 半角スペース
$spc = '\x20';

# 全角スペース
$eSpc = '(?:\xA1\xA1)'; # EUC-JP
$sSpc = '(?:\x81\x40)'; # SJIS


# 全角数字 [0-9]
$eLng = '(?:\xA3[\xB0-\xB9])'; # EUC-JP
$sLng = '(?:\x82[\x4F-\x58])'; # SJIS


# 全角小英字 [a-z]
$estr = '(?:\xA3[\xE1-\xFA])'; # EUC-JP
$sstr = '(?:\x82[\x81-\x9A])'; # SJIS


# 全角大英字 [A-Z]
$eStr = '(?:\xA3[\xC1-\xDA])'; # EUC-JP
$sStr = '(?:\x82[\x60-\x79])'; # SJIS


# 全角ひらがな [ぁ-ん]
$eHira = '(?:\xA4[\xA1-\xF3])'; # EUC-JP
$sHira = '(?:\x82[\x9F-\xF1])'; # SJIS


# 全角カタカナ [ァ-ヶ]
$eKana = '(?:\xA5[\xA1-\xF6])'; # EUC-JP
$sKana = '(?:\x83[\x40-\x96])'; # SJIS


# 半角カタカナ [ヲ-゜]
$ekana = '(?:\x8E[\xA6-\xDF])'; # EUC-JP
$skana = '[\xA6-\xDF]'; # SJIS


# EUC-JP文字
$euc1 = '[\x00-\x7F]'; # 1byte EUC-JP文字
$euc2 = '(?:[\x8E\xA1-\xFE][\xA1-\xFE])'; # 2byte EUC-JP文字
$euc3 = '(?:\x8F[\xA1-\xFE][\xA1-\xFE])'; # 3byte EUC-JP文字
$euc = "(?:$euc1|$euc2|$euc3)"; # EUC-JP文字

获取 PostgreSQL 数据库之 sequence 名称列表的 SQL

, , ,

较低版本(1.0 ?) CakePHP 的文件
cake/libs/model/dbo/dbo_postgres.php
中,有一句 SQL:

SELECT sequence_name FROM information_schema.sequences

在 PostgreSQL 8 中,以上 SQL 运行出错。

根据原意修改如下:

SELECT c.relname as sequence_name FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n WHERE c.relnamespace = n.oid AND c.relkind='S' and n.nspname = 'public'

其中的 'public' 是 schema 名,需要根据实际情况修改。

顺便把 dbo_postgres.php 中包含以上 SQL 的函数修改如下:
    function sequenceExists($seq) {
        $cache = parent::__cacheDescription('sequences');
        if($cache != null) {
            return in_array($seq, $cache);
        }
        $sequences = array();
        // ★修改这句
        //$res = $this->rawQuery("SELECT sequence_name FROM information_schema.sequences");
        $schema = $this->config['schema'];
        $res = $this->rawQuery("SELECT c.relname as sequence_name FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n WHERE c.relnamespace = n.oid AND c.relkind='S' AND n.nspname = '{$schema}'");
        while($row = $this->fetchRow($res)) {
            $sequences[] = $row[0]['sequence_name'];
        }
        
        parent::__cacheDescription('sequences', $sequences);
        return in_array($seq, $sequences);
    }

需要说明的是,在新版本的 CakePHP 中,已见不到以上函数。

CakePHP 动态设置 tablePrefix 的一个例子

, ,

遇到一个问题

用 CakePHP 开发的网站,有几个子网站,每个子网站有一个 webroot,共用数据库,其中有部分数据表格不能共用,因此需要根据实际情况设置表格的前缀。

这个在 CakePHP 下其实很简单,只是没有先例,所以摸索了半天,最后得出的方法如下:

首先,在各个 webroot 下的 index.php 追加一个常量(在载入 bootstrap.php 之前)

例:
app/webroot-a/index.php
define('SITE_ID', 1);

app/webroot-b/index.php
define('SITE_ID', 2);

app/webroot-c/index.php
define('SITE_ID', 3);


然后,在需要不同前缀的表格的 Model 中加入 settableprefix() 函数

例:
app/models/users.php
<?php
class Users extends AppModel {
    var $name = 'Users';
    var $useTable = 'users';
    var $primaryKey = 'user_id';

    function settableprefix() {
        if(SITE_ID == 1) {
            $this->tablePrefix = 'a_';
        } elseif(SITE_ID == 2)  {
            $this->tablePrefix = 'b_';
        } elseif(SITE_ID == 3)  {
            $this->tablePrefix = 'c_';
        }
    }
}
?>

这样就可以了。

其实,index.php 中的常量也可以不用追加,直接利用现成的常量就行,比如 WEBROOT_DIR。追加常量是为了程序照顾运行的效率。

cakePHP 动态选择数据库连接的方法

, ,

很简单,只要把 /app/config/database.php 文件的内容替换成以下形式:
<?php
class DATABASE_CONFIG {
    #localhost
    var $local = array('driver' => 'mysql',
        'connect' => 'mysql_connect',
        'host' => 'localhost',
        'login' => 'root',
        'password' => ",
        'database' => 'local',
        'prefix' => '');

    #dev server
    var $dev = array('driver' => 'mysql',
        'connect' => 'mysql_connect',
        'host' => 'mysql.dev.com',
        'login' => 'dev',
        'password' => 'password',
        'database' => 'dev',
        'prefix' => '');

    #live server
    var $live = array('driver' => 'mysql',
        'connect' => 'mysql_connect',
        'host' => 'mysql.live.com',
        'login' => 'live',
        'password' => 'password',
        'database' => 'live',
        'prefix' => ");

    #switch between configs
    var $default = array();
    var $test = array();
    function __construct() {

        #wildcard the subdomains
        $host_r = explode('.', $_SERVER['SERVER_NAME']);
        if(count($host_r)>2) while(count($host_r)>2)array_shift($host_r);
        $mainhost = implode('.', $host_r);

        #switch between servers
        switch(strtolower($mainhost)) {
            case 'localhost':
                $this->default = $this->local;
                break;
            case 'dev.com':
                $this->default = $this->dev;
                break;
            case 'live.com':
                $this->default = $this->live;
                break;
            default:
                $this->default = $this->local;
        }
    }

    #php 4 compatibility
    function DATABASE_CONFIG() {
        $this->__construct();
    }
}
?>

★注:以上方法来自 这儿

从 UE 到 EmEditor

, ,

首先,这儿的“UE”指的是 UltraEdit

以前我一直用UE编辑代码,至少有5年吧,最近两年却不怎么用UE了,原因就是用了 EmEditor,顺手之后就不忍放弃了。

UE的列模式确实很好用,十六进制的编辑功能确实很“Ultra”。

先说说EmEditor的优点:

多语言多内码支持;(这一点UE没法比)
非常强悍的正则查找替换功能;(正则表达式很标准,查找结果全部着色,一目了然)
非常强悍的宏功能;(默认是JavaScript,几乎无所不能)
很好的插件体系;(因此可以无限扩展,这和Vim和Emacs的路线一致)
非常方便的文件比较功能;(这个UE做得也不错)
多文件操作,包括查找替换等;(这个功能UE也不错,可以说各有千秋)
界面的定制功能不弱,基本能够满足个性化的需求;
... ...

接下来说说EmEditor不足的地方:

作为插件的目录文件树(TreeView)反应迟钝,增删文件和目录不能立即反映,按F5可更新整个树,这个更新过程其实做了很多无用功;
列模式或者方块模式的编辑不如UE;
多文件查找的结果,以新文件中的链接的方式实现,不是很方便,每点开一个文件,都要切换一次文档;(这一点UE做得很好,放在下面的列表里面)
... ...

对EmEditor的一点期待:

实现TextMate那样的代码块"智能编辑"

iptables 下实现 FTP 的 PASV 模式连接

, , , ...

问题:
Linux 下有 iptables 设置,FTP(21 端口)已许可 ,然而无法用 PASV 模式连接。

解决办法:

先用 lsmod 命令确认已加载的内核模块,如果没有 ip_nat_ftpip_conntrack_ftp,运行

# modprobe ip_nat_ftp

即可实现 FTP 连接。

另外,

/etc/sysconfig/iptables 文件中,

-A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT

不要忘了加入以上这一行。

还有,

/etc/sysconfig/iptables-config 文件中,追加(或把注释去掉):

IPTABLES_MODULES="ip_nat_ftp"

这样就不需要每次手动运行 modprobe 命令了。

iptables 的设置修改之后,还需重新启动一下 iptables 服务:

# /etc/init.d/iptables restart

以上文章翻译整理自 iptables、FTP で PASV 接続

一个远程更新代码的 Shell 脚本

, ,

自己胡乱写的脚本,以后可能还用到,因此贴于此处。

update.sh
#!/bin/bash

# 生成数据路径(若不存在)
CONTENTS_ROOT=/opt/data
DATA_DIR=(image/01 image/02 movie/01 movie/02)
for ((i=0; i<${#DATA_DIR[@]}; i++)); do
    NEW_PATH=$CONTENTS_ROOT/${DATA_DIR[i]}
    if [ ! -d $NEW_PATH ]; then 
        mkdir -p $NEW_PATH
        chmod a+rw $NEW_PATH
        echo "Make $NEW_PATH ok ..."
    fi
done

# 从远程服务器取得新的程序代码, 命令须加 -r 参数
if [ "$1" = "-r" ]; then
        rm -f new_src.tar.gz
        scp myuser@remote.server:~/project1/new_src.tar.gz .
        tar -zxvf new_src.tar.gz
        rm -f new_src.tar.gz
        echo "Copy files from remote.server ok ..."
fi

# 若是测试服务器,修改代码,设置 DEBUG 标志为 1
if [ `hostname` = test_server ]; then
    sed -i "s/define('DEBUG', 0)/define('DEBUG', 1)/g;" ./config/setting.php
    echo "Set DEBUG = 1 ok ..."
fi

# 把新代码拷贝到目标路径
DEST_PATH=/opt/project1/src
if [ `pwd` != $DEST_PATH ]; then
    cp -prf * $DEST_PATH/
    echo "Copy source ok ..."
fi

# UPDATE 结束
echo "Update finish!"

说明:以上程序仅为模板,其中的路径是杜撰,还省略了一些步骤。
March 2008
S M T W T F S
February 2008April 2008
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31