SAE的求助支出

今天在浏览“账户 -> 云豆记录 -> 支出”时,偶然发现“求助支出”每次需要30颗云豆。

云豆是要花钱买的!通过这种方式,SAE能够有效控制问题的数量和质量,管理员回答问题所创造的价值也有了一种量化的衡量方式。

SAE的求助支出,很好很强大!

用GreaseMonkey脚本美化Readability阅读页面

由于iReader有中文分页和打印Bug,Readability依然是目前Firefox扩展中最强大和兼容性最好的电子书阅读扩展。

Readability从2.1版开始,只提供在线转换功能,页面内容将被传送到Readability的网站,进行转换,然后用户通过一个临时URL阅读。这种方式相比本地阅读而言,可以提供更强大的社交分享功能,并且能够显著提高Readability网站的流量和排名,然而对于访问国外网站速度较慢的国内用户来说,这种改进就很让人郁闷了。这个问题目前没有更好的解决办法,只能是能用iReader的时候就用iReader,不能用的时候只能忍了。

Readability 2.1还有一个问题,就是和阅读无关的按钮太多,包括“READ LATER”、“Share”和一个图文广告。于是我写了一个GreaseMonkey脚本来过滤这些无用的页面元素,以获得一个无广告的阅读页面。

GreaseMonkey用户脚本redability_cleaner.user.js的源代码如下:

// ==UserScript==
// @name           Redability Cleaner
// @namespace      readability_cleaner
// @description    清除Readabiliy生成的阅读页面中的无关元素
// @include        http://www.readability.com/articles/*
// @require        http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.6.2.js
// ==/UserScript==
$(“#rdb-article-meta”).remove();
$(“#article-footer-actions-wrap”).remove();
$(“.article-pitch”).remove();

其中使用了jQuery来实现更简洁的代码。

注:iReader和Redability都支持Firefox 9。

SAE上的SOAP客户端——SaeSoap开发手记

前言
=========

Sina App Engine(SAE)到目前为止还不支持SOAP,但是询问的人不少,我也是一个。对于这些提问,新浪管理员都做了认真回复,给出了解决思路,并且希望有用户能够自己去实现。

SAE文档中心关于SOAP的问题:
http://sae.sina.com.cn/?keyword=SOAP&m=search

为了响应伟大的SAE的号召,为了满足项目的小小需要,SaeSoap诞生了!

基本信息
============

应用名称:
PHP SOAP for ASE

访问方式:
http://saesoap.sinaapp.com/

应用说明:
让SAE原生支持PHP SOAP!

开发环境
============

SAE应用管理 -> 应用管理 -> 代码管理:创建版本1

$ sudo aptitude install php-pear

$ cd /path/to/sae/
$ svn checkout https://svn.sinaapp.com/saesoap/
$ cd saesoap/1

拷贝 pear SOAP, HTTP_Request, Net_Socket, Net_URL,注意目录和文件的权限都必须是755。

$ ln -s /path/to/sae/saesoap/1 /var/www/saesoap

测试代码
============

问题和解决方法
—————–

$ gvim /path/to/sae/saesoap/1/index.php
<?php
require ‘SOAP/Client.php’;
$uri = ‘http://www.5haoxue.net/ws/hello-soap.php’;
$client = new SOAP_Client($uri);
$result = $client->call(‘fetch_news’, array());
echo $result;
?>
$ lynx http://localhost/saesoap/

出现了“No Transport for http”错误。这个错误提示是在Transport.php中定义的SOAP_Transport类的getTransport方法中输出的。出错的原因是没有复制SOAP/Transport/目录,在这个目录下有HTTP.php。补上以后测试成功!

在SAE上测试
—————-

$ svn status
$ svn add HTTP/ SOAP/ Net/
$ svn commit -m ‘Test pear SOAP client’
$ lynx http://saesoap.sinaapp.com/

发现SAE不支持PEAR:

SAE_Warning: require_once(PEAR.php) [function.require-once]: failed to open stream: No such file or directory in SOAP/Base.php on line 30
SAE_Fatal_error: require_once() [function.require]: Failed opening required ‘PEAR.php’ (include_path=’.:/usr/local/sae/php/lib/php/sae_std_lib/’) in SOAP/Base.php on line 30

管理员说是出于安全性考虑:
http://sae.sina.com.cn/?m=feedback&a=view&id=3262
建议手动安装PEAR,并给出了教程的链接:
http://hi.baidu.com/mleoking/blog/item/ebe307ca55146d43f21fe792.html

直接拷贝PER文件:
$ sudo updatedb
$ locate PEAR.php
$ cp /usr/share/php/PEAR.php /path/to/sae/saesoap/1
$ svn add PEAR.php
$ svn commit -m ‘Add PEAR.php’
$ lynx http://saesoap.sinaapp.com/

出现了一些警告信息,但是数据读出来了!警告信息如下:

SAE_Warning: include_once(PEAR5.php) [function.include-once]: failed to open stream: No such file or directory in PEAR.php on line 730
SAE_Warning: include_once() [function.include]: Failed opening ‘PEAR5.php’ for inclusion (include_path=’.:/usr/local/sae/php/lib/php/sae_std_lib/’) in PEAR.php on line 730

继续拷贝PEAR5.php文件:
$ locate PEAR5.php
$ cp /usr/share/php/PEAR5.php /path/to/sae/saesoap/1
$ svn add PEAR5.php
$ svn commit -m ‘Add PEAR5.php’

现在没有错误也没有警告了,只剩下一堆SAE_Deprecated和数据了:

SAE_Deprecated: Assigning the return value of new by reference is deprecated in SOAP/WSDL.php on line 214

SAE_Deprecated: Function split() is deprecated in SOAP/Transport/HTTP.php on line 272

现在可以把代码迁移到好学网手机版中去了!

小结
=========

SaeSoap目前实现了在SAE上使用SOAP Client,实现的方式是使用了PEAR SOAP,并不需要对代码进行修改。

SAE上的SOAP Server,目前项目还没有需求,因此暂时也没有时间去实现,希望能有朋友能够抽时间来完成!

SaeSoap Demo:
http://saesoap.sinaapp.com/

基于SpeedPHP和SaeSoap实现的手机版网站:
http://m.5haoxue.net/

桌面不死——PyQt 4.9和SIP 4.13.1发布

在Web应用和手机、平板应用大行其道的今天,桌面程序开发已经很难吸引大家的注意力。不过仍然有这么一些人还在努力为我们提供更好的桌面程序开发工具:

Riverbank Computing Ltd.于2011年12月22日发布了PyQt 4.9,这个版本提供了对Qt 4.8.0的支持,并包含了QtDBus模块。PyQt的上一个版本4.8.6的发布还是在10月25日,这个两次发布间隔将近2个月的时间。

同时发布的还有SIP 4.13.1,没有重大更新。PyQt 4.9依赖于SIP 4.13.1。

官方下载(Windows、Mac OS X、Linux):
http://www.riverbankcomputing.co.uk/software/pyqt/download
http://www.riverbankcomputing.co.uk/software/sip/download

背景资料:

PyQt是跨平台开发框架Qt的Python绑定,支持Windows、Mac OS X和Linux。SIP是创建C和C++库的Python绑定的工具。PyQt依赖于SIP。

PyQt兼有Qt跨平台和Python开发效率高的优点,代码修改后可直接运行,无须等待编译,节省大量开发调试时间。用cx_Freeze可以把PyQt程序打包成可执行文件,同时支持Windows和Linux,在Windows下可以用InnoSetup制作安装程序。PyQt的缺点和Qt一样,就是开发出来的程序体积较大,基本上10MB打底。华图微学公务员考试软件和华图微学公务员面试互动模拟软件都是用PyQt开发的,Windows版可以在华军软件园下载。

PHP JSON教程

PHP JSON简介
=================

参考资料
————

PHP Manual -> Function Reference -> Other Basic Extensions -> JSON
http://www.php.net/manual/en/book.json.php

JSON简介
————-

JSON是JavaScript Object Notation的缩写,是一种数据交换格式。

PHP JSON扩展简介
———————

PHP JSON扩展是PHP核心的一部分,相关函数可以直接使用。

PHP JSON函数的使用方法
=========================

json_decode(string $json)函数:解码JSON字符串,返回对象。

json_decode(string $json, TRUE)函数:解码JSON字符串,返回数组。

json_encode(mixed $value)函数:编码变量或对象,返回字符串。

注:仅支持UTF-8编码的数据。

:注: var_dump()竟然不支持中文!dump()支持中文!

PHP的json_decode函数的使用实例

基于SpeedPHP 3.1.89。

controller/admin.php文件源代码:

__getFunctions();
echo 'SOAP functions: ';
var_dump($soap_func_list); // array(1) { [0]=> string(14) "string Hello()" }
echo '
';
$soap_type_list = $client->__getTypes();
echo 'SOAP types: ';
var_dump($soap_type_list);
echo '
';
$result = $client->__soapCall('Hello', array());
echo 'Hello function call: ';
$result = json_decode($result, TRUE);
//var_dump($result); // 中文变成乱码,var_dump()不支持中文!
dump($result); // 中文正常显示
}
}

访问方式:
http://localhost/index.php?c=admin&a=soap_client_wsdl

访问结果:
结果截图参考“PHP的json_decode函数的使用实例截图_2011-12-123.png”。

非WSDL模式的PHP SoapServer类和SoapClient类使用实例

基于SpeedPHP 3.1.89。

controller/admin.php文件源代码:

$location, 'uri' => $uri));
$soap_func_list = $client->__getFunctions();
echo 'SOAP functions: ';
var_dump($soap_func_list); // 对于非WSDL模式的SOAP,返回值是NULL?
echo '
';
$soap_type_list = $client->__getTypes();
echo 'SOAP types: ';
var_dump($soap_type_list); // 对于非WSDL模式的SOAP,返回值是NULL?
echo '
';
$result = $client->__soapCall('hello', array()); // 函数名不区分大小写
echo 'Hello function call: ';
var_dump($result);
}
function soap_server() {
function hello() {
return 'Hello, kind SOAP user!';
}
$server = new SoapServer(NULL, array('uri' => 'http://www.5haoxue.net/'));
$server->addFunction('hello');
$server->handle();
}
}
?>

访问
http://localhost/5haoxue/index.php?c=admin&a=soap_server
结果为空。

访问
http://localhost/5haoxue/index.php?c=admin&a=soap_client
结果为:
SOAP functions: NULL
SOAP types: NULL
Hello function call: string(22) “Hello, kind SOAP user!”
结果截图参考“非WSDL模式的SoapServer和SoapClient使用实例截图_2011-12-23.png”。

PHP的SoapClient类使用实例

基于SpeedPHP 3.1.89。

controller/admin.php源代码:

__getFunctions();
echo 'SOAP functions: ';
var_dump($soap_func_list); // array(1) { [0]=> string(14) "string Hello()" }
echo '
';
$soap_type_list = $client->__getTypes();
echo 'SOAP types: ';
var_dump($soap_type_list);
echo '
';
$result = $client->__soapCall('Hello', array());
echo 'Hello function call: ';
var_dump($result); // string(1517804) "[{"Title":"2011\u5e74\u8d35\u5dde\u7701\u516d\u76d8\u6c34\u5e02\u5e02\u76f4\u4e8b\u4e1a\u5355\u62df\u8058\u7528\u4eba\u5458\u540d\u5355","Content":"...","Updatetime":"1324607604","TypeName":"\u8003\u8bd5\u52a8\u6001"},...]"
}
}
?>

访问方式:
http://localhost/index.php?c=admin&a=soap_extension

访问结果:
参考“SoapClient类使用实例截图_2011-12-23.png”。

利用SpeedPHP的URL Rewrite功能实现网站结构调整后的301重定向

最近要把一个网站从VPS迁移到SAE上,由于SAE还不支持web2py,因此整个网站用SpeedPHP重写。

在更新网站的过程中,对部分URL进行了重新规划,以实现更短、更容易理解的URL,例如/introduction改为/intro,/application改为/contact。熟悉SEO的朋友都知道,废弃的URL直接返回404并不是最佳选择,通过301跳转到新页面或者首页上才是首选。通过SpeedPHP的URL Rewrite功能,我们可以很容易地实现网站结构调整后的301重定向。

SpeedPHP的URL Rewrite功能的使用方法可以参考我之前写的《在SpeedPHP中启用URL Rewrite》。

主要代码如下:

$ gvim index.php &
$spConfig = array(
‘ext’ => array(
‘spUrlRewrite’ => array(
‘map’ => array(
‘introduction’ => ‘main@redirect’,
‘application’ => ‘main@’redirect’,

$ gvim controller/main.php &
function redirect() {
header(‘HTTP/1.1 301 Moved Permanently’);
header(‘Location: /’);
}

这样就实现了废弃的URL到网站首页的301跳转,而不需要借助.htaccess。SpeedPHP还是很强大的。

在SpeedPHP中启用URL Rewrite

启用Apache的.htaccess
==========================

参考资料:Ubuntu下启动Apache对.htaccess文件的支持

$ sudo a2enmod
rewrite
$ gvim /etc/apache2/sites-enabled/000-default &
AllowOverride All
$ sudo service apache2 restart

SpeedPHP的.htaccess文件
============================

参考资料:Apache的UrlRewrite伪静态htaccess设置

$ cd /var/www/ # root of SpeedPHP project
$ gvim .htaccess &

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?$1 [L]

在SpeedPHP中启用URL Rewrite
===============================

参考资料:SpeedPHP框架的urlrewrite伪静态实现

$ gvim index.php &
$spConfig = array(
‘launch’ => array(
‘router_prefilter’ => array(
array(‘spUrlRewrite’, ‘setReWrite’),
),
‘function_url’ => array(
array(‘spUrlRewrite’, ‘getReWrite’),
),
),
);

测试URL Rewrite的效果
=========================

$ gvim index.php &
$spConfig = array(
‘auto_display’ => TRUE,

$ gvim controller/main.php &
function test_smarty() {
$this->name = ‘chinakr’;
$this->display(‘index.html’);
}

$ gvim tpl/index.html &

Hi, {$name}!
Go to Home Page or stay here.

$ lynx localhost/index.php?c=main&a=test_smarty
$ lynx localhost/main-test_smarty.html

也即默认的URL Rewrite,得到的URL的形式是“controller-action.html”。

优化我们的URL
=================

参考资料:SpeedPHP框架的urlrewrite伪静态实现

看起来像HTML页面的形式
————————

$ gvim index.php &
$spConfig = array(
‘ext’ => array(
‘spUrlRewrite’ => array(
‘suffix’ => ”,
‘sep’ => ‘/’,
),
),

$ lynx localhost/index.php?c=main&a=test_smarty
$ lynx localhost/main/test_smarty.html

也就是说,现在的URL的形式是“controller/action.html”,目录层次和逻辑关系更加清晰。

更加简洁的形式
—————–

$ gvim index.php &
$spConfig = array(
‘ext’ => array(
‘spUrlRewrite’ => array(
‘suffix’ => NULL,
‘sep’ => ‘/’,
),
),

$ lynx localhost/index.php?c=main&a=test_smarty
$ lynx localhost/main/test_smarty

也就是说,现在的URL的形式是“controller/action”,更简洁了。

URL中的参数
===============

参考资料:SpeedPHP框架的urlrewrite伪静态实现

$ gvim tpl/index.html &

Sample for URL with arguments.

$ lynx localhost/index.php?c=main&a=test_smarty&id=0&from=baidu
$ lynx localhost/main/test_smarty/id/0/from/baidu.html

也就是说,现在的URL的形式是“controller/action/参数1/值1/参数2/值2”,不太美观。

优化我们的URL参数
====================

参考资料:SpeedPHP框架的urlrewrite伪静态实现

$ gvim index.php &
$spConfig = array(
‘ext’ => array(
‘spUrlRewrite’ => array(
‘suffix’ => NULL,
‘sep’ => ‘/’,
‘map’ => array(
‘smarty’ => ‘main@test_smarty’,
),
‘args’ => array(
‘smarty’ => array(‘id’, ‘from’),
),
),
),

$ lynx localhost/index.php?c=main&a=test_smarty&id=0&from=baidu
$ lynx localhost/smarty/0/baidu

也可以这样:

$ gvim index.php &
$spConfig = array(
‘ext’ => array(
‘spUrlRewrite’ => array(
‘suffix’ => NULL,
‘sep’ => ‘/’,
‘map’ => array(
‘smarty’ => ‘main@test_smarty’,
),
‘args’ => array(
‘smarty’ => array(‘from’, ‘baidu’),
),
),
),

$ lynx localhost/index.php?c=main&a=test_smarty&id=0&from=baidu
$ lynx localhost/smarty/baidu/0

在这里,建议把重要的参数放在前面,不重要的放在后面,这样逻辑相对更清晰一些。

能否做得更好?
=================

事实上,如果SpeedPHP的URL能够支持这样的形式可能逻辑关系会更清晰一些:
/controller/action-参数1-值1-参数2-值2.html
或者
/controller/action-值1-值2.html

这样的话,上面的URL就可以写成:
http://localhost/main/test_smarty-id-0-from-baidu.html
或者
http://localhost/main/test_smarty-0-baidu.html

这样是不是会更清楚更好看一些呢?见仁见智,权当抛砖引玉了!