實現
/* reimplement fopen using stream */zend_function(donie_stream_fopen){ php_stream *stream; char *path, *mode; int path_len, mode_len; int options = enforce_safe_mode|report_errors; if (zend_parse_parameters(zend_num_args() tsrmls_cc, ss, &path, &path_len, &mode, &mode_len) == failure) { return; } stream = php_stream_open_wrapper(path, mode, options, null); if (!stream) { return_false; } php_stream_to_zval(stream, return_value);}
php_stream_open_wrapper()是對文件類型資源創建流的方法,此外還有基於socket的流、目錄流和特殊流三種。php_stream_to_zval()用於把流實例轉換成zval結構。
創建文件類型的流
#define php_stream_open_wrapper(path, mode, options, opened) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), null streams_cc tsrmls_cc)#define php_stream_open_wrapper_ex(path, mode, options, opened, context) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), (context) streams_cc tsrmls_cc)
參數path是文件名或url,mode是模式字符串,options是選項組合。php_stream_open_wrapper_ex()允許指定一個流的上下文。
options包含以下選項:
use_path:應用ini中的include_path到相對路徑。內建的fopen()的第三個參數置true時使用此選項。 stream_use_url:只有遠程url才允許打開,%%file://, php://, compress.zlib://%%這樣的本地url會報錯。 enforce_safe_mode:只有設置了此選項且ini中的safe_mode開啟時,才會使safe_mode生效,不設置此選項,則不論ini中是否開啟都不會生效。 report_errors:若開啟流出錯,生成錯誤信息。 stream_must_seek:不是所有流都允許seek,若置此選項,且流不允許seek,則包裝器不會開啟流。 stream_will_cast:置此參數將要求流可被轉換成posix或stdio類型的文件描述符,若流不可轉換,可在io開始前失敗。 stream_only_get_headers:http包裝器使用此參數,只獲取資源的元數據,不獲取內容。 stream_disable_open_basedir:當ini中的open_basedir開啟時,置此參數跳過open_basedir檢查。 stream_open_persistent:要求流和相關資源都創建為持久數據。 ignore_path:不從include_path中搜索。 ignore_url:只有本地文件才可以被打開。 創建傳輸類型的流
php_stream *_php_stream_xport_create(const char *name, size_t namelen, int options, int flags, const char *persistent_id, struct timeval *timeout, php_stream_context *context, char **error_string, int *error_code)
參數:
name:url。 options:參數,與php_stream_open_wrapper()的相同。 flags:stream_xport_client或stream_xport_server與其它stream_xport_*常量的組合。 persistent_id:鍵值,置此參數將使流在多次請求間持久存在。 timeout:置null將使用ini中設置的值。 errstr:用於向外傳遞錯誤信息,初始應置為null,若有錯誤信息傳出,調用方有責任釋放錯誤信息佔用的內存。 errcode:錯誤碼。 flags:
stream_xport_client:工作為客戶端,向遠程發起連接。 stream_xport_server:工作為服務器,接受連接。 stream_xport_connect:傳輸建立的同時發起對遠程的連接,否則,需手動調用php_stream_xport_connect()。 stream_xport_connect_async:發起異步遠程連接。 stream_xport_bind:将传输流绑定到本地资源. 用在服务端传输流时,这将使得accept连接的传输流准备端口, 路径或特定的端点标识符等信息。 stream_xport_listen:%%listen for inbound connections on the bound transport endpoint. this is typically used with stream-based transports such as tcp://, ssl://, and unix://%%. 創建目錄類型的流 php_stream php_stream_opendir(const char *path, int options, php_stream_context *context)
創建特殊類型的流
php_stream *php_stream_fopen_tmpfile(void);php_stream *php_stream_fopen_temporary_file(const char *dir, const char *pfx, char **opened_path);php_stream *php_stream_fopen_from_fd(int fd, const char *mode, const char *persistent_id);php_stream *php_stream_fopen_from_file(file *file, const char *mode);php_stream *php_stream_fopen_from_pipe(file *file, const char *mode);
讀流
// 讀一個字符int php_stream_getc(php_stream *stream);// 讀取指定數量的字符size_t php_stream_read(php_stream *stream, char *buf, size_t count);// 讀取直到行末、或流末、或最多maxlen個字符char *php_stream_get_line(php_stream *stream, char *buf, size_t maxlen, size_t *returned_len);char *php_stream_gets(php_stream *stream, char *buf, size_t maxlen);// 與php_stream_get_line相同,可指定截止標記char *php_stream_get_record(php_stream *stream, size_t maxlen, size_t *returned_len, char *delim, size_t delim_len tsrmls_dc);// 讀取一個目錄項php_stream_dirent *php_stream_readdir(php_stream *dirstream, php_stream_dirent *entry);
寫流
// 寫非阻塞流可能寫入的數據比傳入的短;_string要求傳入的字符串以null結尾size_t php_stream_write(php_stream *stream, char *buf, size_t count);size_t php_stream_write_string(php_stream *stream, char *stf);int php_stream_putc(php_stream *stream, int c);// 與_string不同的是會自動追加一個換行符到字符串末尾int php_stream_puts(php_string *stream, char *buf);size_t php_stream_printf(php_stream *stream tsrmls_dc, const char *format, ...);
int php_stream_flush(php_stream *stream);
在關閉流的時候,flush會被自動調用,並且大部分無過濾的流因無內部緩沖而不需flush,所以單獨flush一般是不需要的。
尋址 int php_stream_seek(php_stream *stream, off_t offset, int whence); int php_stream_rewind(php_stream *stream); int php_stream_rewinddir(php_stream *dirstream); off_t php_stream_tell(php_stream *stream);
offset是相對於whence的位移量,whence包含:
seek_set:文件開頭。置offet為負值被認為是個錯誤並導致不可預料的行為。offset超出文件範圍會導致一個錯誤,或文件被增大。 seek_cur:當前位置。 seek_end:文件末尾。offset一般為負,正值的行為因流的實現而異。 獲取額外信息 int php_stream_stat(php_stream *stream, php_stream_statbuf *ssb);
關閉流 #define php_stream_close(stream) php_stream_free((stream), php_stream_free_close) #define php_stream_pclose(stream) php_stream_free((stream), php_stream_free_close_persistent)
包含以下選項:
php_stream_free_call_dtor:銷毀流時調用php_stream->ops->close php_stream_free_release_stream:銷毀流時調用php_stream_wrapper->ops->stream_close php_stream_free_preserve_handle:php_stream->ops->close不銷毀句柄 php_stream_free_rsrc_dtor:用於流內部資源列表垃圾回收 php_stream_free_persistent:用於持久流,所有操作的結果在多次請求間持久有效 php_stream_free_close:call_dtor和release_stream的組合,用於非持久流的常規選項 php_stream_free_close_casted:close和preserve_handle的組合 php_stream_free_close_persistent:close和persistent的組合,用於持久流的常規選項