分类目录归档:技术

抓取上海教育考试院的报名信息并短信通知

由于有过惨痛教训,老是错过重要的考试报名通知,所以这段代码抓取了上海教育考试院的报名页面,分析并发送短信通知相应的考试人员,然后将这个页面放到服务器上,每日定时检查,一有新的报名信息就能及时得知。中间涉及到部分php的知识点

    1. fscoketopen,上一篇已经写过相应的介绍,即可以用其来模拟web service调用,也可以使用其来抓取页面
    2. 正则表达式,preg_match,用来提取抓取后页面返回的数据
    3. 编码转换iconv,抓取的页面是GBK类型,如果不转换,则在控制台显示乱码。第二个是发送短信的接口,由于我使用的接口是GBK数据,所以我需要再从UTF-8转换到GBK
    4. php文件的相关操作函数:file_exists用来判断文件是否已经存在,fopen用来打开文件,fgets用来读取一行,fputs用来写入一行。
    5. 数组模拟push方法,使用arr[] = something;的形式
    6. vim 格式化代码 :gg=G
    7. vim 批量添加 //注释::10,50s#^#//#g ;批量删除 :10,50s#^//##g
    8. 定时的方法使用crontab -e,就可打开定时列表,设置成每天10点通知:
0 10 * * * /path/to/php /path/to/spta.php

spta.php

function get_spta() {
    $content = '';

    $fp = fsockopen('www.spta.gov.cn', 80);
    fwrite($fp, "GET /appendix/wsbm.html HTTP/1.0\r\n");
    fwrite($fp, "Host: www.spta.gov.cnrn");
    fwrite($fp, "Content-Type: text/html; charset=utf-8\r\n");
    fwrite($fp, "Content-Length: ".strlen($content)."\r\n");
    fwrite($fp, "\r\n");

    fwrite($fp, $content);

    $item = array();
    while (!feof($fp)) {
        $result = iconv('GBK', 'UTF-8', fgets($fp));
        if (strpos($result, '<td align="left">') > 0) {
            preg_match('/>([^<]*)</', $result, $matches);
            $title = $matches[1];
            $url = iconv('GBK', 'UTF-8', fgets($fp));
            preg_match('/href="([^"]*)"/', $url, $matches);
            $url = $matches[1];
            $item[] = array('title' = >$title, 'url' = >$url);
        }
    }
    fclose($fp);
    return $item;
}
function sent_sms($mobile, $msg) {
    $vars = "&mobs=$mobile&msg=".iconv('UTF-8', 'GBK', $msg);
    $fp = fsockopen('smsserver.com', 80);
    fwrite($fp, "GET /sms?$vars HTTP/1.0\r\n");
    fwrite($fp, "Host: smsserver.com\r\n");
    fwrite($fp, "\r\n");

    fwrite($fp, $content);
    fclose($fp);
}
$items = get_spta();
$title = '';
$path = '/path/to/spta';
if (file_exists($path)) {
    $file = fopen($path, 'r');
    $title = fgets($file);
}
foreach($items as $bean) {
    if ($title != $bean['title']) {
        sent_sms('your mobile', $bean['title'].'[考试院]');
        echo $bean['title']."n";
    } else {
        break;
    }
}
$file = fopen($path, 'w');
fputs($file, $items[0]['title']);

使用php fsockopen 调用 .NET的WebService接口

实现代码如下所示,我们知道了可以使用Telnet模拟http访问,也想试着使用socket来调用webservice接口,原因是默认的php Soap不起作用,可能需要繁琐的配置才能实现。但在使用fsockopen调用的时候也现出了一些问题:

    1. php中,单引号中是没有转义字符的,即\r\n是原始显示的
    2. http头部使用1.1的时候,可能会出现keep-alive模式,这种情况下需要使用Content-Length来判断body的长度,取出数据结束,而不应使用feof
    3. fgets()是一次读取一行;fread()是一次读取一个字符,后面可加数量
$content = '<?xml version="1.0" encoding="utf-8"?>'."\r\n";
$content. = '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'."\r\n";
$content. = '  <soap:Body>'."\r\n";
$content. = '    <QueryBalance  xmlns="http://tempuri.org/">'."\r\n";
$content. = '      <userId>sg128</userId>'."\r\n";
$content. = '    </QueryBalance >'."\r\n";
$content. = '  </soap:Body>'."\r\n";
$content. = '</soap:Envelope>'."\r\n";

$fp = fsockopen('example.com', 80);
fwrite($fp, "POST /Service/UserService.asmx HTTP/1.0\r\n");
fwrite($fp, "Host: example.com\r\n");
fwrite($fp, "Content-Type: text/xml; charset=utf-8\r\n");
fwrite($fp, "Content-Length: ".strlen($content)."\r\n");
fwrite($fp, "SOAPAction: \"http://tempuri.org/QueryBalance\"\r\n");
fwrite($fp, "\r\n");

fwrite($fp, $content);

header('Content-type: text/plain');

// $length = 0;
// $line = '';
// while($line !== "\r\n") {
//     $line = fgets($fp);
//     if(substr($line, 0, 15) === 'Content-Length:') {
//         $length = intval(substr($line, 16));
//     }
// }
// echo fread($fp, $length);
while (!feof($fp)) {
    echo fgets($fp);
}
fclose($fp);

由XMLRPC想到的

一直使用Windows Live Writer来写博客,但对于其使用的xmlrpc协议一点都还不知道。本来是想找一个基于xmlrpc协议的软件来Windows Live Writer的功能,因为微软自己产的软件除了Office体验还行以为,其余用户体验基本处于最低端

于是查询相关的软件,但好像不多,也许应该叫没有,但xmlrpc有点意思,不同的语言都有基于其协议的实现,如果自己有时间的话,开发一款自己用起来还算顺手的工具应该不是一件难事,但基于我目前困于温饱问题还没有解决的现状,这个基本也属于自己想象的一款软件吧(其实我自己想象的软件已经很多了,自己动手做的真是少之又少)。由于博客的没落,我也相信这样的软件也不会受到更多人的欢迎,大家使用一下Windows的产品就可以了。

接着又看到了jsonrpc的信息,他们都属于SOAP的一部分,而SOAP的实现方式是http请求与响应,只不过中间传递的数据根据协议的不同而不同罢了。于是我又在问自己,http请求究竟是怎样实现的?其数据组织格式是什么?我们怎么通过更低一级的socket编程来模拟http请求?于是查找了相关信息,大概了解了socket怎么样组织请求,怎么样来伪装自己,比起语言本身封装的http请求,这些内容让我更进一步了解了http协议的原理

普通form和文件form有什么不同?其组织形式是怎样的?普通的from可以以文本的形式获取到,而文件form则是以流(java)来读入的,根据php经验,http头和内容的区分只是根据两个“\r\n”来完成的。http协议可以设定文件的读取起始位置,这样可以来做断点续传

socket是基于tcp协议的,所以比http更低一层,其实现https的方式是使用SSL进行加密。客户端实现实时通信是通过相互监听来实现的,即,一款软件会在你的机器打开一个tcp端口来监听服务器的回应。但这种情况在NAT下面会遇到问题,因为NAT服务器不允许主动访问内网机器,只能被动的方法。这其实就把双方监听的优势给磨灭了;但好在客户端的软件也是我们写的,这样我们就可以主动发起请求,穿透NAT;

雅虎信箱

没有什么比看到雅虎信箱要关闭的消息让我更揪心的事情了。我开始上网于2003年,开始注册的第一个邮箱是雅虎,开始上的最多的网站也是雅虎。当时记得学校里面的教学楼有几台可以免费使用的机器,在大厅里面,需要一直站在那里操作,从此那里成了我最常去的地方。

然而更幸运的是,有一段时间,那边的机器竟然是可以上互联网的,在那几个月的时间也是我初步接触互联网的时间(平时计算机课里面的网络都是断掉的)。于是我周末的大部分时间就耗在了那边,探索着互联网的奥秘。而注册的第一个邮箱就是当时著名的雅虎邮箱,具体是什么方式引导我到雅虎网站上去也到现在我也说不清楚了,于是,雅虎打开了我互联网的大门。而当时为了练习邮箱注册操作,我一口气注册了几十个邮箱,其中就包括我目前正在使用的这一个,一晃已经十年的时间了

雅虎的信息地址又臭又长(尤其yahoo.com.cn的后缀),后面又尝试了很多免费邮箱的服务,msn,hotmail,eyou,网易,新浪,搜狐,QQ,Gmail等,这些后其之秀长度都比雅虎好了不少,而其新功能也有很多雅虎邮箱所不具备的。而我的雅虎信箱在注册好以后,隔一个月不登录里面的邮件就会被清空,而当时学校放假的时间一度近一个月,于是yahoo不小心被清除了几次,而现在我能找到的最新的一封邮件是2006年的。

既然雅虎信箱这么多缺点,为什么还继续使用它呢?可能是对其有感情了吧,再加上那里注册其他网站的账号都是使用的雅虎信箱,于是就这么沿用了下来,就连我的支付宝账号也是雅虎信箱注册的。而当时也使用了yahoo.com的服务,但最终还是没有坚持下来。

直到毕业后的几年时间里面,我注册网站从来想都不想就把自己的雅虎信箱提供出去,但其里面的邮件我基本上不太关注的,因为提供的次数与场合太多了,里面的邮件大多是垃圾邮件。但其重要的一个用途就是当我忘记一个站点的密码时,通过注册邮箱找回密码,于是我还特意为yahoo设置了一个跟其他站点不同的密码,而这一做法在CSDN密码泄露事件爆发后来看显得多么的明智,我也因此没有造成更大的损失。

也许我想雅虎邮箱会一直作为我注册网站的邮箱进行下去,就跟其2007年推出的叫“终身邮”一样,只要有注册我就会被它推出去,但昨天的消息太令我震惊了,我一时都统计不过来我到底有多少站点是使用雅虎的邮箱做的注册邮箱,当时我最想说的一句话是,雅虎你TMD也太不靠谱了!

骂归骂,迁移的工作还是要进行的,虽然里面没有太多的重要邮件(其中重置密码的邮件也算是很重要的,况且很多网站就直接把相应的密码明文发到了邮箱里),但还是想给自己一个更长的缓冲其,于是就按照他们的要求把邮箱从雅虎迁移到阿里云邮箱,但这个过程中我遇到了问题,迁移的页面显示js加载失败,经我检测确实是访问不到,试过多种浏览器,多台机器,多个网络,这个问题依然存在,折腾了两天也没有什么结果,只好给阿里云的客服打电话,但他们好像是不知所云……

3

我已经将重要的站点的邮箱全部切换成自己域名的邮箱,这样的好处是只要我还在续费,我的邮箱就不会停止,即使一个邮箱服务停止了,我还可以迁移到另外一个上,不会取决于第三个人。但这浪费了我不少时间,而且到现在迁移到阿里云上的事情还没有搞定,又发邮件给雅虎的客服,到现在还没有消息

使用CI的几大误区

在使用CodeIgniter做开发的时候还是遇到不少误区的,其中最大的一个就是怎么样使用函数的问题,当然可以在一个Controller方法中内部再定义一个函数来使用,但函数通用性就成了问题,为此我曾经单独写一个通用函数的php放到common里面然后要使用的地方都需要引用一下这个文件,这样一来也算是解决了问题,不过总觉得有点山寨

后来才注意到其方法也有修饰符,既然有public,想必也有private ,试用了一下,使用private修饰的方法在外部是不能访问的,那么内部一定可以通过某种方式来访问。因为已经经过了一段时间对CI的了解,一般CI访问自身方法变量的方式是$this ->,于是这也就是访问私有函数的方法。

第二个误区是我不喜欢使用Model,开始的几个项目都空在那,里面没写任何的东西,直到一个中等的项目到来,我发现不写Model要多出很多的工作量,而这些工作很多都是重复的,于是后面就恢复了Model模块,这也是走了一次弯路,因为我在使用java框架SSH的时候总觉得Action和Service是合并的,没有太大的必要,只有经历多了才发现,这种成熟的架构总是有其一定的道理的

NanoHTTPD.java

在使用jquery.validationEngine的时候,看到其github上有相关java测试的代码,包括了一个NanoHTTPD.java来模拟http响应,虽然里面的原来还不是太清楚,但无疑,如果弄明白他可以让我们更进一步了解http和socket程序的关系,能够看清http的原理

github地址:https://github.com/posabsolute/jQuery-Validation-Engine

(待续)

稳定否?

想着自己的空间不怎么稳定,因为服务器毕竟在国外,又出现过几次问题,就想把博客的文章迁移到相对稳定的blogger上,而且其支持独立域名绑定。但在国内不能正常使用这个服务,于是找了相关的东西出来,有两个 办法可以解决这个问题,一个是有独立的vps,也就是我现在的情况,设置对ghs的apache反向映射。我设置过以后,还是有问题,那就是通过邮件发送的博客的文章图片没办法正常显示,如果翻墙的话可以显示,看到图片的地址是在appspot.com上托管,由于appspot也不能访问,造成目前这种情况。所以暂时还是只能使用我自己的博客顶着,如果找到更好的方式和更好的地方,还是尽快把博客备份的事情搞定,不然万一那天VPS出了点问题我写的这些东西都找不到了

另外目前wordpress还有几个问题,1、由于是vps,硬盘的写入速度实在不怎么样,所以在一些数据库操作上很耗费时间,导致博客的速度非常慢。2、发布文章的时候不能直接贴图,而gmail已经解决了这个问题,如果wordpress使用email发文章的功能能够正常实现这也不成一个问题,但wordpress发文章仅限于文字,且每次都要手动访问wp-mail.php来更新,非常的麻烦。

而blogger就没有以上的缺点了,其速度很快,可以跟gmail完美拉登完成发布任务。就我一篇介绍svn的邮件直接转到blogger上显示效果等没有任何问题。但blogger最大的问题是国内不能访问!

git svn更换svn地址的方法

主要有以下几步:

  1. 打开“工程/.git/config”文件,找到其中“[svn-remote “svn”]”将相应地址更换
  2. 将cmd打开,进入到本工程,然后使用git svn fetch命令
  3. 刚开始会直接要求输入密码,如果所给提示用户名是正确的,刚将正确的密码输入即可
  4. 如果所给的用户名不正确,则直接按回车,就会提示输入正确的用户名和正确的密码
  5. 在完成以上操作后,如果在使用git svn dcommit的时候还是出现问题,则需要svn库里面增加新的提交,然后使用git svn fetch取回本地,这样就可以正确识别了

JavaScript正则表达式定义常用方法

正则的定义:

var reg = /pattern/igm;
var reg = new RegExp(‘pattern’, ‘igm’);

1. 其中i的意思是忽略大小写,如:

不加i

reg = /test/;
str = ‘tEStab’;
reg.exec(str);//返回null

加上i

reg = /test/i;
str = “tEStab”;
reg.exec(str);//返回["tESt"]

2. g的意思是全局查找,

不加g

reg = /tes[ta]/;
str = ‘testatesab’;
reg.exec(str); //返回["test"]
reg.exec(str); //返回["test"]

加上g

reg = /tes[ta]/g;
str = ‘testatesab’;
reg.exec(str); //返回["test"]
reg.exec(str); //返回["tesa"]
reg.exec(str); //返回null

3. m的意思是指让^和$匹配行首和行尾

不加m

reg = /^b[ac]/g;
str=’ba.sinnbcsohu’;
reg.exec(str); //返回["ba"]
reg.exec(str); //返回null

加上m

reg = /^b[ac]/g;
str=’ba.sinnbcsohu’;
reg.exec(str); //返回["ba"]
reg.exec(str); //返回["bc"]
reg.exec(str); //返回null

正则的常用方法:

1. exec方法

result = reg.exec(str)
//返回的result是一个类数组的对象,如果在chrome的console里看到是数组,其实使用for in可以得到另外两个只读属性index, input
for(a in result) console.log(a + “:” + result[a]);

结果如下:

0:tESt
index:0
input:tEStab
result.input存放匹配的原始字符串,result.index是当前匹配的索引,其作用是当我们使用了g修饰符时,它是多次执行reg.exec(str)的依据;数据里依次存放匹配到的字符串,和正则中小括号匹配的分组数据,如:
reg = /tes(t)/;
str = ‘testab’;
reg.exec(str);//返回["test", "t"]
exec方法也同样影响RegExp(稍后介绍)

2. test方法

reg.test(str)
//测试是否匹配成功,若成功返回true,否则返回false。跟exec一样,其也返回结果,存放在RegExp.$*几个变量中,其中RegExp.$input, RegExp.$_表示输入字符串,而RegExp.$1 – RegExp.$9表示匹配的变量

3. RegExp对象

如果直接使用console.log(RegExp),function RegExp() { [native code] },这也是正则的构成方法,使用for in来看一下其中的变量:

reg = /tes(t)/;
str = ‘atestb’;
reg.exec(str);//结果为 ["test']
for(name in RegExp) console.log(name + “:” + RegExp[name]);

结果如下:

input:atestb
multiline:false
lastMatch:test
lastParen:t
leftContext:a
rightContext:b
$1:t
$2:
$3:
$4:
$5:
$6:
$7:
$8:
$9:

其中RegExp.input = RegExp.$input = RegExp.$_,RegExp.multiline表示m标签符是否被设置

总结

当然,能用正则的方法还有String对象的match, replace, split, search等方法,有时间再做一次介绍。这里只是介绍其使用方法,对于如果写正则表达式没有深入讲,内容还有很多
推荐阅读:JavaScript正则表达式

CentOS 6.2修改DNS

修改DNS如果只是修改/etc/resolv.conf,再进行service network restart,会发现原来修改过的内容又回去了。所以只配置这里是不能够修改DNS的。

找到你目前正在使用的网上,一般是eth0

  1. vim /etc/sysconfig/network-scripts/ifcfg-eth0
  2. 修改里面的DNS1和DNS2为自己的DNS指向
  3. service network restart

这样做,resolve.conf就会自动修改了;如果还没有修改,则查一下是不是自己刚才找的网卡不对,另外再检查一下其他网卡的设置,找出可能的网上再修改一下;

另外我觉得,使用ifconfig修改ip地址也不是一个持久的做法,重启机器后也就不见了,所以最保险的办法还是修改ifcfg脚本,然后重启服务