PHP Wrapper在SAE上的应用方法
本文讲述了PHPWrapper在SAE上的应用方法。分享给大家供大家参考,具体如下:
一、PHPWrapper是什么
自PHP4.3开始,PHP开始允许用户通过stream_wrapper_register()自定义URL风格的协议。用户使用fopen(),copy()等文件系统函数对封装协议进行操作时,PHP会调用注册协议时所提供的类中相应的函数。
PHP手册中给了一个例子,它将VariableStream类注册为var://协议,通过这个协议,用户可以使用文件系统函数直接读写全局变量。例如,用户可以通过“var://foo”读写$GLOBALS['foo']。
二、SAE为什么需要PHPWrapper
出于性能和安全方面的考虑,SAE平台上禁用了本地文件读写和对外的数据抓取。相应的,我们提供了对应的服务来做同样的事情。
由于新服务的接口和PHP本身的接口不太一样,专门为我们平台开发的程序当然不会存在问题,但是大量已有的程序和开源项目,就面临着繁杂的迁移工作。而使用PHPWrapper对我们的服务的接口进行封装之后,用户就可以更方便地将程序迁移到SAE平台。
三、如何写PHPWrapper
要通过PHPWrapper封装一个协议,首先,我们需要写一个streamWrapper类,类名可自定义,类的格式为:
streamWrapper{ publicresource$context; __construct(void) publicbooldir_closedir(void) publicbooldir_opendir(string$path,int$options) publicstringdir_readdir(void) publicbooldir_rewinddir(void) publicboolmkdir(string$path,int$mode,int$options) publicboolrename(string$path_from,string$path_to) publicboolrmdir(string$path,int$options) publicresourcestream_cast(int$cast_as) publicvoidstream_close(void) publicboolstream_eof(void) publicboolstream_flush(void) publicboolstream_lock(mode$operation) publicboolstream_open(string$path,string$mode,int$options,string&$opened_path) publicstringstream_read(int$count) publicboolstream_seek(int$offset,int$whence=SEEK_SET) publicboolstream_set_option(int$option,int$arg1,int$arg2) publicarraystream_stat(void) publicintstream_tell(void) publicintstream_write(string$data) publicboolunlink(string$path) publicarrayurl_stat(string$path,int$flags) }
类中各方法说明:
streamWrapper::__construct—构造函数,仅在stream_open前被调用
streamWrapper::dir_closedir—关闭目录句柄,响应closedir()函数
streamWrapper::dir_opendir—打开目录句柄,响应opendir()函数
streamWrapper::dir_readdir—从目录句柄读取条目,响应readdir()函数
streamWrapper::dir_rewinddir—倒回目录句柄,响应rewinddir()函数
streamWrapper::mkdir—创建目录,响应mkdir()函数
streamWrapper::rename—目录或文件重命名,响应rename()函数
streamWrapper::rmdir—删除目录,响应rmdir()函数
streamWrapper::stream_cast—检索基础资源,响应stream_select()函数
streamWrapper::stream_close—关闭资源,响应fclose()函数
streamWrapper::stream_eof—检查文件指针是否已经在文件末尾,响应feof()函数
streamWrapper::stream_flush—清除输出缓存,响应fflush()函数
streamWrapper::stream_lock—咨询文件锁定,响应flock()函数
streamWrapper::stream_open—打开文件或URL为流,响应fopen()函数
streamWrapper::stream_read—从流中读取内容,响应fread(),fgets()函数
streamWrapper::stream_seek—在流中定位指针,响应fseek()函数
streamWrapper::stream_set_option—改变流设置
streamWrapper::stream_stat—检索文件资源的信息,响应fstat()函数
streamWrapper::stream_tell—检索流中指针的位置,响应ftell()函数
streamWrapper::stream_write—向流中写入内容,响应fwrite(),fputs()函数
streamWrapper::unlink—删除文件,响应unlink()函数
streamWrapper::url_stat—检索文件的信息,响应所有stat()相关的函数,例如file_exists(),is_dir(),is_file(),filesize(),fileinode()等等
详细说明请参考PHP手册:http://cn2.php.net/manual/en/class.streamwrapper.php
写好streamWrapper类之后,使用stream_wrapper_register()将这个类注册到Wrapper中,就可以开始使用了。函数使用方法为:
boolstream_wrapper_register(string$protocol,string$classname[,int$flags=0])
例如:
stream_wrapper_register("saemc","SaeMemcacheWrapper");
由于SAE平台不支持对本地文件的写操作,因此Smarty之类的一些需要在本地写文件的开源项目就没办法直接在SAE平台上使用,而有了saemcWrapper,用户就可以将Smarty编译的模板保存在MC中,很方便的将Smarty迁移到SAE平台上来。
在附件中我们为大家提供了SAE上MemcacheWrapper的实现代码,大家可以下载此附件进行测试。
在测试之前,需要先在本地启动一个端口为22222的Memcached服务:
memcached-m10-p22222-unobody-l127.0.0.1
然后使用下面代码就可以测试了:
//包含附件代码,注册saemcWrapper include_once('wrapper.php'); //测试saemcWrapper $fp=fopen("saemc://test.txt","w+")ordie("fopenfaild!"); fwrite($fp,"line1\n")ordie("fwriteline1faild!"); fwrite($fp,"line2\n")ordie("fwriteline2faild!"); fwrite($fp,"line3\n")ordie("fwriteline3faild!"); var_dump(ftell($fp)); fseek($fp,0); while(!feof($fp)){ $c=fgets($fp)ordie("fgetsfaild!"); var_dump($c); } fclose($fp); var_dump(file_get_contents("saemc://test.txt")); var_dump(file_put_contents("saemc://path/test.txt","helloworld!\n")); var_dump(file_put_contents("saemc://path/test.txt","helloworld!\n",FILE_APPEND)); var_dump(file_get_contents("saemc://path/test.txt")); var_dump(copy("saemc://path/test.txt","saemc://path/test_new.txt")); var_dump(file_get_contents("saemc://path/test_new.txt")); var_dump(unlink("saemc://path/test.txt")); var_dump(file_get_contents("saemc://path/test.txt")); var_dump(rename("saemc://path/test_new.txt","saemc://path/test.txt")); var_dump(file_get_contents("saemc://path/test.txt")); echo"====testinclude====\n"; include_once("saemc://path/test.txt");
测试页面的输出结果:
int(18) string(6)"line1 " string(6)"line2 " string(6)"line3 " string(18)"line1 line2 line3 " int(13) int(13) string(26)"helloworld! helloworld! " bool(true) string(26)"helloworld! helloworld! " bool(true) bool(false) bool(true) string(26)"helloworld! helloworld! " ====testinclude==== helloworld! helloworld!
我们提供的MemcacheWrapper并没有实现目录操作的一些方法和Memcache的Timeout,大家可以参考PHP手册,尝试实现目录操作,或者通过context使这个Wrapper支持Memcache的Timeout。
另外,大家可以到下面这个地址查看SAEStdlib中sae_include的源码,在其中还有我们为Storage服务封装的saestorWrapper和为Fetchurl服务重新封装的httpWrapper的实现:
http://stdlib.sinaapp.com/?f=sae_include.function.php
四、写Wrapper时的一些注意事项
1.构造函数
streamWrapper类很特别,它的构造函数并不是每次都调用的。只有在你的操作触发了stream_open相关的操作时才会调用,比如你用file_get_contents()了。而当你的操作触发和stream无关的函数时,比如file_exists会触发url_stat方法,这个时候构造函数是不会被调用的。
2.读实现
Wrapper里边有Position和Seek等概念,但是很多服务其实是一次性就读取全部数据的,这个可以在stream_open的时候一次性读回,放到一个属性中,以后seek和tell的时候直接操作属性里边存放的数据就可以了。
3.追加写实现
有很多服务是一次性写入所有数据,不支持追加写的功能(比如Memcache),这就需要我们自己在Wrapper中来实现追加写。可以将整个value一次性读取出来,将需要追加写的数据追加在读取出来的内容后面之后,再一次性写回。
但是这种追加写的实现方式性能会比较差,尤其是内容体积较大之后,一次性读取所有内容会非常消耗资源,因此在某些服务中我们不得不舍弃对追加写的支持。
4.url_stat的实现
在streamWrapper类的实现中,url_stat的实现是个难点。必须正确的实现url_stat才能使is_writable和is_readable等查询文件元信息的函数正常工作。
而我们需要为我们的虚设备伪造这些值。以mc为例,我们给大家一些参考数据:
url_stat应该返回一个数组,分13个项,内容如下:
dev设备号-写0即可;
inoinode号-写0即可;
mode文件mode-这个是文件的权限控制符号,稍后详细说明;
nlinklink-写0即可;
uiduid-Linux上用posix_get_uid可以取到,windows上为0;
gidgid-Linux上用posix_get_gid可以取到,windows上为0;
rdev设备类型-当为inode设备时有值;
size-文件大小;
atime-最后读时间格式为unix时间戳;
mtime-最后写时间;
ctime-创建时间;
blksize-blocksizeoffilesystemIO写零即可;
blocks-numberof512-byteblocksallocated写零即可;
其中mode的值必须写对:
如果是文件,其值为:
0100000+文件权限,如0100000+0777。
如果是目录,其值为:
040000+目录权限,如0400000+0777。
5.关于stat的缓存
PHP会在同一个页面的执行过程中对文件的元信息进行缓存。
根据PHP文档对clearstatcache()这个方法的说明得知:在使用stat(),lstat(),file_exists(),is_writable(),is_readable(),is_executable(),is_file(),is_dir(),is_link(),filectime(),fileatime(),filemtime(),fileinode(),filegroup(),fileowner(),filesize(),filetype(),或fileperms()方法查询文件信息时,PHP会将文件的stat的缓存以提高性能。clearstatcache()方法可以用来清除这个缓存,当unlink()会自动清除stat缓存。
而实际上,PHP只有在对本地文件进行unlink,rename和rmdir操作时会清除stat缓存,而在通过其他的wrapper进行unlink,rename和rmdir操作时,并不会清除stat缓存。因此在写wrapper时我们要自己在unlink等方法中通过clearstatcache()来清除stat缓存。
点击此处下载附件。
更多关于PHP相关内容感兴趣的读者可查看本站专题:《phpcurl用法总结》、《phpsocket用法总结》、《PHP网络编程技巧总结》、《PHP基本语法入门教程》、《php操作office文档技巧总结(包括word,excel,access,ppt)》、《php日期与时间用法总结》、《php面向对象程序设计入门教程》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》
希望本文所述对大家PHP程序设计有所帮助。