PHP Wrapper在SAE上的應(yīng)用方法
本文講述了PHP Wrapper在SAE上的應(yīng)用方法。分享給大家供大家參考,具體如下:
一、PHP Wrapper是什么
自PHP 4.3開(kāi)始,PHP開(kāi)始允許用戶(hù)通過(guò)stream_wrapper_register()自定義URL風(fēng)格的協(xié)議。用戶(hù)使用fopen(), copy()等文件系統(tǒng)函數(shù)對(duì)封裝協(xié)議進(jìn)行操作時(shí),PHP會(huì)調(diào)用注冊(cè)協(xié)議時(shí)所提供的類(lèi)中相應(yīng)的函數(shù)。
PHP手冊(cè)中給了一個(gè)例子,它將VariableStream類(lèi)注冊(cè)為var://協(xié)議,通過(guò)這個(gè)協(xié)議,用戶(hù)可以使用文件系統(tǒng)函數(shù)直接讀寫(xiě)全局變量。例如,用戶(hù)可以通過(guò) “var://foo” 讀寫(xiě) $GLOBALS['foo'] 。
二、SAE為什么需要PHP Wrapper
出于性能和安全方面的考慮,SAE平臺(tái)上禁用了本地文件讀寫(xiě)和對(duì)外的數(shù)據(jù)抓取。相應(yīng)的,我們提供了對(duì)應(yīng)的服務(wù)來(lái)做同樣的事情。
由于新服務(wù)的接口和PHP本身的接口不太一樣,專(zhuān)門(mén)為我們平臺(tái)開(kāi)發(fā)的程序當(dāng)然不會(huì)存在問(wèn)題,但是大量已有的程序和開(kāi)源項(xiàng)目,就面臨著繁雜的遷移工作。而使用PHP Wrapper對(duì)我們的服務(wù)的接口進(jìn)行封裝之后,用戶(hù)就可以更方便地將程序遷移到SAE平臺(tái)。
三、如何寫(xiě)PHP Wrapper
要通過(guò)PHP Wrapper封裝一個(gè)協(xié)議,首先,我們需要寫(xiě)一個(gè) streamWrapper 類(lèi),類(lèi)名可自定義,類(lèi)的格式為:
streamWrapper { public resource $context ; __construct ( void ) public bool dir_closedir ( void ) public bool dir_opendir ( string $path , int $options ) public string dir_readdir ( void ) public bool dir_rewinddir ( void ) public bool mkdir ( string $path , int $mode , int $options ) public bool rename ( string $path_from , string $path_to ) public bool rmdir ( string $path , int $options ) public resource stream_cast ( int $cast_as ) public void stream_close ( void ) public bool stream_eof ( void ) public bool stream_flush ( void ) public bool stream_lock ( mode $operation ) public bool stream_open ( string $path , string $mode , int $options , string &$opened_path ) public string stream_read ( int $count ) public bool stream_seek ( int $offset , int $whence = SEEK_SET ) public bool stream_set_option ( int $option , int $arg1 , int $arg2 ) public array stream_stat ( void ) public int stream_tell ( void ) public int stream_write ( string $data ) public bool unlink ( string $path ) public array url_stat ( string $path , int $flags ) }
類(lèi)中各方法說(shuō)明:
streamWrapper::__construct — 構(gòu)造函數(shù),僅在stream_open前被調(diào)用
streamWrapper::dir_closedir — 關(guān)閉目錄句柄,響應(yīng)closedir()函數(shù)
streamWrapper::dir_opendir — 打開(kāi)目錄句柄,響應(yīng)opendir()函數(shù)
streamWrapper::dir_readdir — 從目錄句柄讀取條目,響應(yīng)readdir()函數(shù)
streamWrapper::dir_rewinddir — 倒回目錄句柄,響應(yīng)rewinddir()函數(shù)
streamWrapper::mkdir — 創(chuàng)建目錄,響應(yīng)mkdir()函數(shù)
streamWrapper::rename — 目錄或文件重命名,響應(yīng)rename()函數(shù)
streamWrapper::rmdir — 刪除目錄,響應(yīng)rmdir()函數(shù)
streamWrapper::stream_cast — 檢索基礎(chǔ)資源,響應(yīng)stream_select()函數(shù)
streamWrapper::stream_close — 關(guān)閉資源,響應(yīng)fclose()函數(shù)
streamWrapper::stream_eof — 檢查文件指針是否已經(jīng)在文件末尾,響應(yīng)feof()函數(shù)
streamWrapper::stream_flush — 清除輸出緩存,響應(yīng)fflush()函數(shù)
streamWrapper::stream_lock — 咨詢(xún)文件鎖定,響應(yīng)flock()函數(shù)
streamWrapper::stream_open — 打開(kāi)文件或URL為流,響應(yīng)fopen()函數(shù)
streamWrapper::stream_read — 從流中讀取內(nèi)容,響應(yīng)fread(), fgets()函數(shù)
streamWrapper::stream_seek — 在流中定位指針,響應(yīng)fseek()函數(shù)
streamWrapper::stream_set_option — 改變流設(shè)置
streamWrapper::stream_stat — 檢索文件資源的信息,響應(yīng)fstat()函數(shù)
streamWrapper::stream_tell — 檢索流中指針的位置,響應(yīng)ftell()函數(shù)
streamWrapper::stream_write — 向流中寫(xiě)入內(nèi)容,響應(yīng)fwrite(), fputs()函數(shù)
streamWrapper::unlink — 刪除文件,響應(yīng)unlink()函數(shù)
streamWrapper::url_stat — 檢索文件的信息,響應(yīng)所有stat()相關(guān)的函數(shù),例如file_exists(), is_dir(), is_file(), filesize(), fileinode()等等
詳細(xì)說(shuō)明請(qǐng)參考PHP手冊(cè):http://cn2.php.net/manual/en/class.streamwrapper.php
寫(xiě)好streamWrapper類(lèi)之后,使用 stream_wrapper_register () 將這個(gè)類(lèi)注冊(cè)到Wrapper中,就可以開(kāi)始使用了。函數(shù)使用方法為:
bool stream_wrapper_register ( string $protocol , string $classname [, int $flags = 0 ] )
例如:
stream_wrapper_register("saemc", "SaeMemcacheWrapper");
由于SAE平臺(tái)不支持對(duì)本地文件的寫(xiě)操作,因此Smarty之類(lèi)的一些需要在本地寫(xiě)文件的開(kāi)源項(xiàng)目就沒(méi)辦法直接在SAE平臺(tái)上使用,而有了saemc Wrapper,用戶(hù)就可以將Smarty編譯的模板保存在MC中,很方便的將Smarty遷移到SAE平臺(tái)上來(lái)。
在附件中我們?yōu)榇蠹姨峁┝薙AE上Memcache Wrapper的實(shí)現(xiàn)代碼,大家可以下載此附件進(jìn)行測(cè)試。
在測(cè)試之前,需要先在本地啟動(dòng)一個(gè)端口為22222的Memcached服務(wù):
memcached -m 10 -p 22222 -u nobody -l 127.0.0.1
然后使用下面代碼就可以測(cè)試了:
//包含附件代碼,注冊(cè)saemc Wrapper include_once('wrapper.php'); //測(cè)試 saemc Wrapper $fp = fopen( "saemc://test.txt", "w+" ) or die("fopen faild!"); fwrite( $fp, "line1\n" ) or die("fwrite line1 faild!"); fwrite( $fp, "line2\n" ) or die("fwrite line2 faild!"); fwrite( $fp, "line3\n" ) or die("fwrite line3 faild!"); var_dump(ftell($fp)); fseek( $fp, 0 ); while ( !feof( $fp ) ) { $c = fgets( $fp ) or die("fgets faild!"); var_dump($c); } fclose( $fp ); var_dump(file_get_contents("saemc://test.txt")); var_dump(file_put_contents("saemc://path/test.txt", "hello world!\n")); var_dump(file_put_contents("saemc://path/test.txt", "hello world!\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 "====test include====\n"; include_once("saemc://path/test.txt");
測(cè)試頁(yè)面的輸出結(jié)果:
int(18) string(6) "line1 " string(6) "line2 " string(6) "line3 " string(18) "line1 line2 line3 " int(13) int(13) string(26) "hello world! hello world! " bool(true) string(26) "hello world! hello world! " bool(true) bool(false) bool(true) string(26) "hello world! hello world! " ====test include==== hello world! hello world!
我們提供的 Memcache Wrapper并沒(méi)有實(shí)現(xiàn)目錄操作的一些方法和Memcache的Timeout,大家可以參考PHP手冊(cè),嘗試實(shí)現(xiàn)目錄操作,或者通過(guò)context使這個(gè)Wrapper支持Memcache的Timeout。
另外,大家可以到下面這個(gè)地址查看SAE Stdlib中sae_include的源碼,在其中還有我們?yōu)镾torage服務(wù)封裝的saestor Wrapper和為Fetchurl服務(wù)重新封裝的http Wrapper的實(shí)現(xiàn):
http://stdlib.sinaapp.com/?f=sae_include.function.php
四、寫(xiě)Wrapper時(shí)的一些注意事項(xiàng)
1. 構(gòu)造函數(shù)
streamWrapper 類(lèi)很特別,它的構(gòu)造函數(shù)并不是每次都調(diào)用的。只有在你的操作觸發(fā)了stream_open相關(guān)的操作時(shí)才會(huì)調(diào)用,比如你用file_get_contents()了。而當(dāng)你的操作觸發(fā)和stream無(wú)關(guān)的函數(shù)時(shí),比如file_exists會(huì)觸發(fā)url_stat方法,這個(gè)時(shí)候構(gòu)造函數(shù)是不會(huì)被調(diào)用的。
2. 讀實(shí)現(xiàn)
Wrapper里邊有Position和Seek等概念,但是很多服務(wù)其實(shí)是一次性就讀取全部數(shù)據(jù)的,這個(gè)可以在stream_open的時(shí)候一次性讀回,放到一個(gè)屬性中,以后seek和tell的時(shí)候直接操作屬性里邊存放的數(shù)據(jù)就可以了。
3. 追加寫(xiě)實(shí)現(xiàn)
有很多服務(wù)是一次性寫(xiě)入所有數(shù)據(jù),不支持追加寫(xiě)的功能(比如Memcache),這就需要我們自己在Wrapper中來(lái)實(shí)現(xiàn)追加寫(xiě)??梢詫⒄麄€(gè)value一次性讀取出來(lái),將需要追加寫(xiě)的數(shù)據(jù)追加在讀取出來(lái)的內(nèi)容后面之后,再一次性寫(xiě)回。
但是這種追加寫(xiě)的實(shí)現(xiàn)方式性能會(huì)比較差,尤其是內(nèi)容體積較大之后,一次性讀取所有內(nèi)容會(huì)非常消耗資源,因此在某些服務(wù)中我們不得不舍棄對(duì)追加寫(xiě)的支持。
4. url_stat的實(shí)現(xiàn)
在streamWrapper類(lèi)的實(shí)現(xiàn)中,url_stat的實(shí)現(xiàn)是個(gè)難點(diǎn)。必須正確的實(shí)現(xiàn)url_stat才能使is_writable和is_readable等查詢(xún)文件元信息的函數(shù)正常工作。
而我們需要為我們的虛設(shè)備偽造這些值。以mc為例,我們給大家一些參考數(shù)據(jù):
url_stat應(yīng)該返回一個(gè)數(shù)組,分13個(gè)項(xiàng),內(nèi)容如下:
dev 設(shè)備號(hào) - 寫(xiě)0即可;
ino inode號(hào) - 寫(xiě)0即可;
mode 文件mode - 這個(gè)是文件的權(quán)限控制符號(hào),稍后詳細(xì)說(shuō)明;
nlink link - 寫(xiě)0即可;
uid uid - Linux上用posix_get_uid可以取到,windows上為0;
gid gid - Linux上用posix_get_gid可以取到,windows上為0;
rdev 設(shè)備類(lèi)型 - 當(dāng)為inode設(shè)備時(shí)有值;
size - 文件大??;
atime - 最后讀時(shí)間 格式為unix時(shí)間戳;
mtime - 最后寫(xiě)時(shí)間;
ctime - 創(chuàng)建時(shí)間;
blksize - blocksize of filesystem IO 寫(xiě)零即可;
blocks - number of 512-byte blocks allocated 寫(xiě)零即可;
其中mode的值必須寫(xiě)對(duì):
如果是文件,其值為:
0100000 + 文件權(quán)限,如 0100000 + 0777。
如果是目錄,其值為:
040000 + 目錄權(quán)限,如 0400000 + 0777。
5. 關(guān)于stat的緩存
PHP會(huì)在同一個(gè)頁(yè)面的執(zhí)行過(guò)程中對(duì)文件的元信息進(jìn)行緩存。
根據(jù)PHP文檔對(duì) clearstatcache() 這個(gè)方法的說(shuō)明得知:在使用 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() 方法查詢(xún)文件信息時(shí),PHP會(huì)將文件的stat的緩存以提高性能。 clearstatcache()方法可以用來(lái)清除這個(gè)緩存,當(dāng)unlink()會(huì)自動(dòng)清除stat緩存。
而實(shí)際上,PHP只有在對(duì)本地文件進(jìn)行unlink, rename和rmdir操作時(shí)會(huì)清除stat緩存,而在通過(guò)其他的wrapper進(jìn)行unlink, rename和rmdir操作時(shí),并不會(huì)清除stat緩存。因此在寫(xiě)wrapper時(shí)我們要自己在unlink等方法中通過(guò)clearstatcache()來(lái)清除stat緩存。
點(diǎn)擊此處下載附件。
更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專(zhuān)題:《php curl用法總結(jié)》、《php socket用法總結(jié)》、《PHP網(wǎng)絡(luò)編程技巧總結(jié)》、《PHP基本語(yǔ)法入門(mén)教程》、《php操作office文檔技巧總結(jié)(包括word,excel,access,ppt)》、《php日期與時(shí)間用法總結(jié)》、《php面向?qū)ο蟪绦蛟O(shè)計(jì)入門(mén)教程》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫(kù)操作入門(mén)教程》及《php常見(jiàn)數(shù)據(jù)庫(kù)操作技巧匯總》
希望本文所述對(duì)大家PHP程序設(shè)計(jì)有所幫助。
- PHP中的流(streams)淺析
- PHP Streams(流)詳細(xì)介紹及使用
- PHP中的Streams詳細(xì)介紹
- php常用Stream函數(shù)集介紹
- php stream_get_meta_data返回值
- PHP stream_context_create()函數(shù)的使用示例
- PHP Stream_*系列函數(shù)
- PHP使用stream_context_create()模擬POST/GET請(qǐng)求的方法
- 深入理解PHP中的Streams工具
- PHP stream_context_create()作用和用法分析
- PHP流Streams、包裝器wrapper概念與用法實(shí)例詳解
相關(guān)文章
php使用json_decode后數(shù)字對(duì)象轉(zhuǎn)換成了科學(xué)計(jì)數(shù)法的解決方法
這篇文章主要介紹了php使用json_decode后數(shù)字對(duì)象轉(zhuǎn)換成了科學(xué)計(jì)數(shù)法的解決方法,涉及php操作json格式數(shù)據(jù)與數(shù)值轉(zhuǎn)換相關(guān)技巧,需要的朋友可以參考下2017-02-02php下通過(guò)curl抓取yahoo boss 搜索結(jié)果的實(shí)現(xiàn)代碼
php下通過(guò)curl抓取yahoo boss 搜索結(jié)果的實(shí)現(xiàn)代碼,需要的朋友可以參考下。2011-06-06phpmail類(lèi)發(fā)送郵件函數(shù)代碼
前天要給網(wǎng)站做一個(gè)小功能,就是在用戶(hù)留言的時(shí)候發(fā)郵件通知管理員。我們都知道在PHP里有一個(gè)mail函數(shù),但是要求服務(wù)器要有郵件服務(wù)器的功能,比如簡(jiǎn)單的SMTP或者POP3。但是,如果我們的服務(wù)器沒(méi)有這種功能,那么怎么辦呢2012-02-02PHP基于非遞歸算法實(shí)現(xiàn)先序、中序及后序遍歷二叉樹(shù)操作示例
這篇文章主要介紹了PHP基于非遞歸算法實(shí)現(xiàn)先序、中序及后序遍歷二叉樹(shù)操作,結(jié)合實(shí)例形式分析了php采用非遞歸算法對(duì)二叉樹(shù)進(jìn)行先序、中序及后序遍歷操作的原理與具體實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-01-01火車(chē)采集器 免費(fèi)版使出收費(fèi)版本功能實(shí)現(xiàn)原理
火車(chē)頭免費(fèi)版本不支持采集結(jié)果的外掛處理,比如采用php來(lái)輔助處理結(jié)果,而火車(chē)頭本身對(duì)于正則表達(dá)式的不完整支持,2009-09-09