出于性能和安全方面的考虑,公司的平台上禁用了本地文件读写和对外的数据抓取.相应的,我们提供了对应的服务来做同样的事情.新服务的接口和原来不太一样.
专门为我们平台开发的程序当然不会存在问题,但是有大量的已有的程序和开源项目,就面临着繁杂的迁移工作.
Wrapper
其实从PHP4.3开始,PHP就支持Wrapper了,这意味着用户可以自定义和重载协议.
只需要使用 stream_wrapper_register
函数就可以注册一个协议,对这个协议的相关操作,PHP都会回调相关的函数.
手册上给了一个例子. 它注册了一个叫var的协议,然后对这个协议操作都会回调VariableStream class
里边定义的方法.
varname = $url["host"]; $this->position = 0; return true; } function stream_read($count) { $ret = substr($GLOBALS[$this->varname], $this->position, $count); $this->position += strlen($ret); return $ret; } function stream_write($data) { $left = substr($GLOBALS[$this->varname], 0, $this->position); $right = substr($GLOBALS[$this->varname], $this->position + strlen($data)); $GLOBALS[$this->varname] = $left . $data . $right; $this->position += strlen($data); return strlen($data); } function stream_tell() { return $this->position; } function stream_eof() { return $this->position >= strlen($GLOBALS[$this->varname]); } function stream_seek($offset, $whence) { switch ($whence) { case SEEK_SET: if ($offset < strlen($GLOBALS[$this->varname]) && $offset >= 0) { $this->position = $offset; return true; } else { return false; } break; case SEEK_CUR: if ($offset >= 0) { $this->position += $offset; return true; } else { return false; } break; case SEEK_END: if (strlen($GLOBALS[$this->varname]) + $offset >= 0) { $this->position = strlen($GLOBALS[$this->varname]) + $offset; return true; } else { return false; } break; default: return false; } } } stream_wrapper_register("var", "VariableStream") or die("Failed to register protocol"); $myvar = ""; $fp = fopen("var://myvar", "r+"); fwrite($fp, "line1\n"); fwrite($fp, "line2\n"); fwrite($fp, "line3\n"); rewind($fp); while (!feof($fp)) { echo fgets($fp); } fclose($fp); var_dump($myvar); "external nofollow" href="http://cn2.php.net/manual/en/class.streamwrapper.php">http://cn2.php.net/manual/en/class.streamwrapper.php需要注意的一些问题
构造函数
首先是,
wrapper class
很特别,它的构造函数并不是每次都调用的.只有在你的操作触发了stream_open相关的操作时才会调用,比如你用file_get_contents
了.而当你的操作触发和stream无关的函数时,比如file_exists会触发url_stat方法,这个时候构造函数是不会被调用的.读实现
wrapper里边有position和seek等概念,但是很多服务其实是一次性就读取全部数据的,这个可以在
stream_open
的时候一次性读回,放到一个属性中,以后seek和tell的时候直接操作属性里边存放的数据就可以了.url_stat的实现
在wrapper class的实现中,url_stat的实现是个难点.必须正确的实现url_stat才能使
is_writable
和is_readable等查询文件元信息的函数正常工作.而我们需要为我们的虚设备伪造这些值.以mc为例,我给大家一些参考数据.
url_stat应该返回一个数组,分13个项,内容如下:
dev 设备号- 写0即可
ino inode号 - 写0即可
mode 文件mode - 这个是文件的权限控制符号,稍后详细说明
nlink link - 写0即可.
uid uid - Linux上用posix_get_uid可以取到,windows上为0
gid gid - Linux上用posix_get_gid可以取到,windows上为0
rdev 设备类型 - 当为inode设备时有值
size 文件大小
atime 最后读时间 格式为unix时间戳
mtime 最后写时间
ctime 创建时间
blksize blocksize of filesystem IO 写零即可
blocks number of 512-byte blocks allocated 写零即可
其中mode的值必须写对
如果是文件,其值为
0100000 + 文件权限 ; 如 0100000 + 0777;
如果是目录,其值为
040000 + 目录权限 ; 如 0400000 + 0777;
可以重载标准协议
根据实际测试来看,用
stream_wrapper_unregister
可以卸载掉http等内置协议.这就方便我们完全无缝的替换用户的一些操作,比如file_get_contents(‘http://sae.sina.com.cn')
到我们自己实现的服务上.知识点补充:
php wrapper实现
【背景】
做一个thrift client的wrapper,用以实现对于服务器的重试逻辑。
【关键点】
1. wrapper要求跟用client一样方便。
2. 当某个服务器挂掉之后可以随机选另一台重试。
3. 用到的php几个关键特性: __call()(magic function,当访问的对象函数不存在时会调用这个), ReflectionClass 反射类及其其成员函数newInstanceArgs , call_user_func_array回调函数。
直接看代码吧(某位牛人写的,not me):
#!/usr/bin/env php <"all server down!"); } public function inner_call($host, $method, $args) { $tmp = explode(":", $host); $socket = new TSocket($tmp[0], (int)$tmp[1]); $transport = new TBufferedTransport($socket, 1024, 1024); $protocol = new TBinaryProtocol($transport); $client = $this->clazz->newInstanceArgs(array($protocol)); $transport->open(); $result = call_user_func_array(array($client, $method), $args); $transport->close(); return $result; } } $hosts = array('localhost:9090', 'localhost:9091'); $wrapper = new RetryWrapper("\xxx\xx\MessageServiceClient", $hosts, 3); $data = array('businessId' => 300100001, 'phones' => array('2','2','3'), 'message' => 'asdfqer') ; $message = new \xxx\xx\Message($data); print $wrapper->sendMessage($message); print "\n"; "color: #ff0000">总结
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 【雨果唱片】中国管弦乐《鹿回头》WAV
- APM亚流新世代《一起冒险》[FLAC/分轨][106.77MB]
- 崔健《飞狗》律冻文化[WAV+CUE][1.1G]
- 罗志祥《舞状元 (Explicit)》[320K/MP3][66.77MB]
- 尤雅.1997-幽雅精粹2CD【南方】【WAV+CUE】
- 张惠妹.2007-STAR(引进版)【EMI百代】【WAV+CUE】
- 群星.2008-LOVE情歌集VOL.8【正东】【WAV+CUE】
- 罗志祥《舞状元 (Explicit)》[FLAC/分轨][360.76MB]
- Tank《我不伟大,至少我能改变我。》[320K/MP3][160.41MB]
- Tank《我不伟大,至少我能改变我。》[FLAC/分轨][236.89MB]
- CD圣经推荐-夏韶声《谙2》SACD-ISO
- 钟镇涛-《百分百钟镇涛》首批限量版SACD-ISO
- 群星《继续微笑致敬许冠杰》[低速原抓WAV+CUE]
- 潘秀琼.2003-国语难忘金曲珍藏集【皇星全音】【WAV+CUE】
- 林东松.1997-2039玫瑰事件【宝丽金】【WAV+CUE】