??? ??
PHP ??? ??? ?? ?? I/O ??? PHP? ?? ??????. 4.3? ??? PHP ??? ??. ????? ?? ??? stdio ?? posix ?? ??? ???? ?? ?? ??? ?? Berkeley ??? ??? ????? ??? ?? ??? I/O? ??? API? ??? ? ????.
??? ??
????? ?? ?? ???? ??? ?? ?? CPU ? ???? ???? ??? ??? ?????. ??? ?? ?? ????? ???? ?? ??? ?? ????? ??? ???. ??? ?? ??? ???? ?? ??? HTTP, FTP ? ?? ?? ??? ?? ??? ??? ???? ??? ? ????. SSL ???? ??, ?? PEAR ?? PECL ??? ?????? ??? SSH2, WebDav, ??? Gopher? ?? ?? ?????? ???? ? ????! ? ???? ???? ???? ????? ???? ?? API? ???? ??? 16? "???? ???"?? ?? ??, ??? ?? ? ?? ?? ?? ?? ?? ??? ???????.
??? ??
?? API??? ???? ??? ??? ??? ?? ???? ???? ?? ?? ? ?? ??? ????. ??? ?? ???? ? ? ? ? ?? ??? ??? ????(?? ??? ?? ??? ?? ?? ???).
<?php /* fopen包裝 * 操作文件/URI方式指定遠程文件類資源 */ $fp = fopen($url, $mode); $data = file_get_contents($url); file_put_contents($url, $data); $lines = file($url); /* 傳輸 * 基于套接字的順序I/O */ $fp = fsockopen($host, $port); $fp = stream_socket_client($uri); $fp = stream_socket_server($uri, $options); /* 目錄流 */ $dir = opendir($url); $files = scandir($url); $obj = dir($url); /* "特殊"的流 */ $fp = tmpfile(); $fp = popen($cmd); proc_open($cmd, $pipes); ?>
?? ??? ???? ?? ???? ?? ?? ?? php_stream? ?????.
fopen ??
?? fopen() ???? ?????. ?? ?? ?? ??? ????? ????. ??? ??? 5? "? ?? ??"?? ???? ??? ???. ?? ??? ??? fopen() ??? ??? ????.
PHP_FUNCTION(sample5_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()? ?? ??? ??? ????? ????? ???. ??? ?? ? ?? ???? URL? ????, ?? ? ?? ??? ?? ?? ?? ????. >options? ?? ??? ??? ? ????, ???? ??? ??? ?? ? ??? ?????.
USE_PATH
php.ini ??? include_path? ?? ??
? ???? ?? ?? fopen()? ? ??? ???? ??? ?????. ????? TRUE? ??
.
STREAM_USE_URL? After ??? ?????.
php://, file://, zlib://, bzip2://? ?? ??? URL ??? ???? ????.
? ??? ??? ??? ??? ???? ? ??? ?????.
? ?? ??? ????? ?? ?? ?? ?????(php.ini ???
safe_mode ???). . ?
??? ???? ??? safe_mode ??? ?????(INI ??
). ?? safe_mode? ???? ??)
REPORT_ERRORS??? ???? ?? ?? ??? ??? ?? ? ????
? ??? ???? ?? ???? ?????.
STREAM_MUST_SEEK?? ???? ?? , ??? ?? ??? ??????(???
???). ??? ??? ?? ??? ?? ????? ??? ? ????
seek. ?? ??? ? ??? ???? ??
? ?? ??? ? ??? ??? ?? ??? ? ???
??? ??? ?????.
STREAM_WILL_CAST ?? ???? ???? ?? ???? stdio? ???? ? ????.
posix ?? ???? ?? ? ??? open_wrapper ??? ???? ???
I/O ??? ???? ?? ??? ???? ??
STREAM_ONLY_GET_HEADERS? ??? ?????? ?????. ??? ???
http ??? ???? http_response_headers ?? ??? ?????
??? ?? ?? Content? ???? ??
STREAM_DISABLE_OPEN_BASEDIR? safe_mode ??? ?????. ? ??? ???? ?? ?? ?????. ??>
INI? open_basedir? ?????. ? ??? ????
? ???? ??? ? ????. check
STREAM_OPEN_PERSISTENT ????? ??? ?? ??? ????? ???? ?? ???? ??? ??? ?????? ??? ?? ??? ????.
IGNORE_PATH???? ??? ?? ?? ??? ?????. ???? URL
?? ?? ????? ?? ?????. ?????.
IGNORE_URL提供這個選項時, 流包裝層只打開本地文件. 所
有的is_url包裝器都將被忽略.
最后的NULL參數(shù)是char **類型, 它最初是用來設置匹配路徑, 如果path指向普通文件URL, 則去掉file://部分, 保留直接的文件路徑用于傳統(tǒng)的文件名操作. 這個參數(shù)僅僅是以前引擎內(nèi)部處理使用的.
此外, 還有php_stream_open_wrapper()的一個擴展版本:
php_stream *php_stream_open_wrapper_ex(char *path, char *mode, int options, char **opened_path, php_stream_context *context);
最后一個參數(shù)context允許附加的控制, 并可以得到包裝器內(nèi)的通知. 你將在第16章看到這個參數(shù)的細節(jié).
傳輸層包裝
盡管傳輸流和fopen包裝流是相同的組件組成的, 但它的注冊策略和其他的流不同. 從某種程度上來說, 這是因為用戶空間對它們的訪問方式的不同造成的, 它們需要實現(xiàn)基于套接字的其他因子.
從擴展開發(fā)者角度來看, 打開傳輸流的過程是相同的. 下面是對fsockopen()的實現(xiàn):
PHP_FUNCTION(sample5_fsockopen) { php_stream *stream; char *host, *transport, *errstr = NULL; int host_len, transport_len, implicit_tcp = 1, errcode = 0; long port = 0; int options = ENFORCE_SAFE_MODE; int flags = STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &host, &host_len, &port) == FAILURE) { return; } if (port) { int implicit_tcp = 1; if (strstr(host, "://")) { /* A protocol was specified, * no need to fall back on tcp:// */ implicit_tcp = 0; } transport_len = spprintf(&transport, 0, "%s%s:%d", implicit_tcp ? "tcp://" : "", host, port); } else { /* When port isn't specified * we can safely assume that a protocol was * (e.g. unix:// or udg://) */ transport = host; transport_len = host_len; } stream = php_stream_xport_create(transport, transport_len, options, flags, NULL, NULL, NULL, &errstr, &errcode); if (transport != host) { efree(transport); } if (errstr) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "[%d] %s", errcode, errstr); efree(errstr); } if (!stream) { RETURN_FALSE; } php_stream_to_zval(stream, return_value); }
這個函數(shù)的基礎構(gòu)造和前面的fopen示例是一樣的. 不同在于host和端口號使用不同的參數(shù)指定, 接著為了給出一個傳輸流URL就必須將它們合并到一起. 在產(chǎn)生了一個有意義的"路徑:后, 將它傳遞給php_stream_xport_create()函數(shù), 方式和fopen()使用的php_stream_open_wrapper()API一樣. php_stream_xport_create()的原型如下:
php_stream *php_stream_xport_create(char *xport, int xport_len, int options, int flags, const char *persistent_id, struct timeval *timeout, php_stream_context *context, char **errstr, int *errcode);
每個參數(shù)的含義如下:
xport基于URI的傳輸描述符. 對于基于inet的套接字流, 它可以是
tcp://127.0.0.1:80, udp://10.0.0.1:53, ssl://169.254.13.24:445等. 此
外, UNIX域傳輸協(xié)議unix:///path/to/socket,
udg:///path/to/dgramsocket等都是合法的. xport_len指定了xport的長
度, 因此xport是二進制安全的.
options這個值是由前面php_stream_open_wrapper()中介紹的選項通過按位
或組成的值.
flags由STREAM_XPORT_CLIENT或STREAM_XPORT_SERVER之一
與下面另外一張表中將列出的STREAM_XPORT_*常量通過按位或
組合得到的值.
persist_id??? ?? ???? ?? ?? ????? ?? ?? ?? ???
?? ??? ? ????. ??? ???? ?????. ? ?? NULL? ???? ???? ??? ?????. ??? ??? ?? ???? ?? ??? ??? ??? ?????. ?? ?? ???? ???
? ?? ?????? ? ??? ???? ?????.
?? ?? ? ?? NULL? ????
? php.ini ?? ?? ?? ??? ???? ???? ???. ? ????? ?? ? ?? ???? ??? ????.
errstr??? ???? ??, ??, ??? ?? ?? ???? ?? ??? ???? ??? ??? char * ?? ?
? ??? ?? ??? ???? ???? ?????.
? ??? NULL? ???? ???. ??? ? ??? ???? ?? ????
? ???? ??? ???? ??? ??? ????.
errcodeerrstr? ??? ?? ???? ???? ?? ?? ??.
php_stream_xport_create? ??? ?? ??? ???? STREAM_XPORT_* ?? ??( )? ??? ?? ?????:
STREAM_XPORT_CLIENT?? ?? ?? ??? ?? ?? ????? ??? ?????.
??? ????? STREAM_XPORT_CONNECT ??
STREAM_XPORT_CONNECT_ASYNC
? ?? ?????. .
STREAM_XPORT_SERVER? ?????. ?? ???? ????? ?? ??? ?? ??? ?????.
? STREAM_XPORT_BIND ?
STREAM_XPORT_LISTEN
STREAM_XPORT_CONNECT ?? ?????. ??>? ?? ??? ?? ??? ?? ??? ??? ???? ???? ? ?????.
, ??? ??? ???
php_stream_xport_connect().? ???? ???? ???.
STREAM_XPORT_CONNECT_ASYNC嘗試連接到遠程資源, 但不阻塞.
STREAM_XPORT_BIND將傳輸流綁定到本地資源. 用在服務端傳輸流時,
這將使得accept連接的傳輸流準備端口, 路徑或
特定的端點標識符等信息.
STREAM_XPORT_LISTEN在已綁定的傳輸流端點上監(jiān)聽到來的連接. 這通
常用于基于流的傳輸協(xié)議, 比如: tcp://, ssl://,
unix://.
目錄訪問
fopen包裝器支持目錄訪問, 比如file://和ftp://, 還有第三種流打開函數(shù)也可以用于目錄訪問, 下面是對opendir()的實現(xiàn):
PHP_FUNCTION(sample5_opendir) { php_stream *stream; char *path; int path_len, options = ENFORCE_SAFE_MODE | REPORT_ERRORS; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &path_len) == FAILURE) { return; } stream = php_stream_opendir(path, options, NULL); if (!stream) { RETURN_FALSE; } php_stream_to_zval(stream, return_value); }
同樣的, 也可以為某個特定目錄打開一個流, 比如本地文件系統(tǒng)的目錄名或支持目錄訪問的URL格式資源. 這里我們又看到了options參數(shù), 它和原來的含義一樣, 第三個參數(shù)NULL原型是php_stream_context類型.
在目錄流打開后, 和文件以及傳輸流一樣, 返回給用戶空間.
特殊流
還有一些特殊類型的流不能歸類到fopen/transport/directory中. 它們中每一個都有自己獨有的API:
php_stream *php_stream_fopen_tmpfile(void); php_stream *php_stream_fopen_temporary_file(const char *dir, const char *pfx, char **opened_path);
創(chuàng)建一個可seek的緩沖區(qū)流用于讀寫. 在關閉時, 這個流使用的所有臨時資源, 包括所有的緩沖區(qū)(無論是在內(nèi)存還是磁盤), 都將被釋放. 使用這一組API中的后一個函數(shù), 允許臨時文件被以特定的格式命名放到指定路徑. 這些內(nèi)部API調(diào)用被用戶空間的tmpfile()函數(shù)隱藏.
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);
這3個API方法接受已經(jīng)打開的FILE *資源或文件描述符ID, 使用流API的某種操作包裝. fd格式的接口不會搜索匹配你前面看到過的fopen函數(shù)打開的資源, 但是它會注冊持久化的資源, 后續(xù)的fopen可以使用到這個持久化資源.
訪問流
在你打開一個流之后, 就可以在它上面執(zhí)行I/O操作了. 使用那種協(xié)議包裝API創(chuàng)建了流并不重要, 它們都使用相同的訪問API.
讀
流的讀寫可以使用下面的API函數(shù)組合完成, 它們多數(shù)都是遵循POSIX I/O中對應的API規(guī)范的:
int php_stream_getc(php_stream *stream);
從數(shù)據(jù)流中接收一個字符. 如果流上再沒有數(shù)據(jù), 則返回EOF.
size_t php_stream_read(php_stream *stream, char *buf, size_t count);
從指定流中讀取指定字節(jié)的數(shù)據(jù). buf必須預分配至少count字節(jié)的內(nèi)存空間. 這個函數(shù)將返回從數(shù)據(jù)流實際讀到緩沖區(qū)中的數(shù)據(jù)字節(jié)數(shù).
php_stream_read()不同于其他的流讀取函數(shù). 如果使用的流不是普通文件流, 哪怕數(shù)據(jù)流中有超過請求字節(jié)數(shù)的數(shù)據(jù), 并且當前也可以返回, 它也只會調(diào)用過一次底層流實現(xiàn)的read函數(shù). 這是為了兼容基于包(比如UDP)的協(xié)議的這種做法.
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);
這兩個函數(shù)從stream中讀取最多maxlen個字符, 直到碰到換行符或流結(jié)束. buf可以是一個指向預分配的至少maxlen字節(jié)的內(nèi)存空間的指針, 也可以是NULL, 當它是NULL時, 則會自動的創(chuàng)建一個動態(tài)大小的緩沖區(qū), 用從流中實際讀出的數(shù)據(jù)填充, 成功后函數(shù)返回指向緩沖區(qū)的指針, 失敗則返回NULL. 如果returned_len傳遞了非NULL值, 則在返回時它將被設置為實際從流中讀取的字節(jié)數(shù).
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_get_line()類似, 這個函數(shù)將讀取最多maxlen, 或到達EOF/行結(jié)束第一次出現(xiàn)的位置. 但是它也有和php_stream_get_line()的不同指出, 這個函數(shù)允許指定任意的停止讀取標記.
讀取目錄項
從php流中讀取目錄項和上面從普通文件中讀取普通數(shù)據(jù)相同. 這些數(shù)據(jù)放到了固定大小的dirents塊中. 內(nèi)部的php_stream_dirent結(jié)構(gòu)體如下, 它與POSIX定義的dirent結(jié)構(gòu)體一致:
typedef struct _php_stream_dirent { char d_name[MAXPATHLEN]; } php_stream_dirent;
實際上你可以直接使用php_stream_read()函數(shù)讀取數(shù)據(jù)到這個結(jié)構(gòu)體中:
{ struct dirent entry; if (php_stream_read(stream, (char*)&entry, sizeof(entry)) == sizeof(entry)) { /* 成功從目錄流中讀取到一項 */ php_printf("File: %s\n", entry.d_name); } }
由于從目錄流中讀取是很常見的操作, php流包裝層暴露了一個API, 它將記錄大小的檢查和類型轉(zhuǎn)換處理封裝到了一次調(diào)用中:
php_stream_dirent *php_stream_readdir(php_stream *dirstream, php_stream_dirent *entry);
如果成功讀取到目錄項, 則傳入的entry指針將被返回, 否則返回NULL標識錯誤. 使用這個為目錄流特殊構(gòu)建的函數(shù)而不是直接從目錄流讀取非常重要, 這樣做未來流API改變時就不至于和你的代碼沖突.
寫
和讀類似, 向流中寫數(shù)據(jù)只需要傳遞一個緩沖區(qū)和緩沖區(qū)長度給流.
size_t php_stream_write(php_stream *stream, char *buf, size_t count); size_t php_stream_write_string(php_stream *stream, char *stf);
write_string的版本實際上是一個提供便利的宏, 它允許寫一個NULL終止的字符串,而不用顯式的提供長度. 返回的是實際寫到流中的字節(jié)數(shù). 要特別小心的是嘗試寫大數(shù)據(jù)的時候可能導致流阻塞, 比如套接字流, 而如果流被標記為非阻塞, 則實際寫入的數(shù)據(jù)量可能會小于傳遞給函數(shù)的期望大小.
int php_stream_putc(php_stream *stream, int c); int php_stream_puts(php_string *stream, char *buf);
還有一種選擇是, 使用php_stream_putc()和php_stream_puts()寫入一個字符或一個字符串到流中. 要注意, php_stream_puts()不同于php_stream_write_string(), 雖然它們的原型看起來是一樣的, 但是php_stream_puts()會在寫出buf中的數(shù)據(jù)后自動的追加一個換行符.
size_t php_stream_printf(php_stream *stream TSRMLS_DC, const char *format, ...);
功能和格式上都類似于fprintf(), 這個API調(diào)用允許在寫的同時構(gòu)造字符串而不用去創(chuàng)建臨時緩沖區(qū)構(gòu)造數(shù)據(jù). 這里我們能夠看到的一個明顯的不同是它需要TSRMLS_CC宏來保證線程安全.
隨機訪問, 查看文件偏移量以及緩存的flush
基于文件的流, 以及另外幾種流是可以隨機訪問的. 也就是說, 在流的一個位置讀取了一些數(shù)據(jù)之后, 文件指針可以向前或向后移動, 以非線性順序讀取其他部分.
如果你的流應用代碼預測到底層的流支持隨機訪問, 在打開的時候就應該傳遞STREAM_MUST_SEEK選項. 對于那些原本就可隨機訪問的流來說, 這通常不會有什么影響, 因為流本身就是可隨機訪問的. 而對于那些原本不可隨機訪問的流, 比如網(wǎng)絡I/O或線性訪問文件比如FIFO管道, 這個暗示可以讓調(diào)用程序有機會在流的數(shù)據(jù)被消耗掉之前, 優(yōu)雅的失敗.
在可隨機訪問的流資源上工作時, 下面的函數(shù)可用來將文件指針移動到任意位置:
int php_stream_seek(php_stream *stream, off_t offset, int whence); int php_stream_rewind(php_stream *stream);
offset是相對于whence表示的流位置的偏移字節(jié)數(shù), whence的可選值及含義如下:
SEEK_SEToffset相對于文件開始位置. php_stream_rewind()API調(diào)用實際上是一個宏,
展開后是php_stream_seek(stream, 0, SEEK_SET), 表示移動到文件開始
位置偏移0字節(jié)處. 當使用SEEK_SET時, 如果offset傳遞負值被認為是錯誤
的, 將會導致未定義行為. 指定的位置超過流的末尾也是未定義的, 不過結(jié)果
通常是一個錯誤或文件被擴大以滿足指定的偏移量.
SEEK_CURoffset相對于文件的當前偏移量. 調(diào)用php_stream_seek(steram, offset,
SEEK_CUR)一般來說等價于php_stream_seek(stream, php_stream_tell()
+ offset, SEEK_SET);
SEEK_ENDoffset是相對于當前的EOF位置的. 負值的offset表示在EOF之前的位置, 正
值和SEEK_SET中描述的是相同的語義, 可能在某些流實現(xiàn)上可以工作.
int php_stream_rewinddir(php_stream *dirstream);
在目錄流上隨機訪問時, 只有php_stream_rewinddir()函數(shù)可用. 使用php_stream_seek()函數(shù)將導致未定義行為. 所有的隨機訪問一族函數(shù)返回0標識成功或者-1標識失敗.
off_t php_stream_tell(php_stream *stream);
如你之前所見, php_stream_tell()將返回當前的文件偏移量.
int php_stream_flush(php_stream *stream);
調(diào)用flush()函數(shù)將強制將流過濾器此類內(nèi)部緩沖區(qū)中的數(shù)據(jù)輸出到最終的資源中. 在流被關閉時, flush()函數(shù)將自動調(diào)用, 并且大多數(shù)無過濾流資源雖然不進行任何內(nèi)部緩沖, 但也需要flush. 顯式的調(diào)用這個函數(shù)很少見, 并且通常也是不需要的.
int php_stream_stat(php_stream *stream, php_stream_statbuf *ssb);
調(diào)用php_stream_stat()可以獲取到流實例的其他信息, 它的行為類似于fstat()函數(shù). 實際上, php_stream_statbuf結(jié)構(gòu)體現(xiàn)在僅包含一個元素: struct statbuf sb; 因此, php_stream_stat()調(diào)用可以如下面例子一樣, 直接用傳統(tǒng)的fstat()操作替代, 它只是將posix的stat操作翻譯成流兼容的:
int php_sample4_fd_is_fifo(int fd) { struct statbuf sb; fstat(fd, &sb); return S_ISFIFO(sb.st_mode); } int php_sample4_stream_is_fifo(php_stream *stream) { php_stream_statbuf ssb; php_stream_stat(stream, &ssb); return S_ISFIFO(ssb.sb.st_mode); }
關閉
所有流的關閉都是通過php_stream_free()函數(shù)處理的, 它的原型如下:
int php_stream_free(php_stream *stream, int options);
這個函數(shù)中的options參數(shù)允許的值是PHP_STREAM_FREE_xxx一族常量的按位或的結(jié)果, 這一族常量定義如下(下面省略PHP_STREAM_FREE_前綴):
CALL_DTOR流實現(xiàn)的析構(gòu)器應該被調(diào)用. 這里提供了一個時機對特定的流
進行顯式釋放.
RELEASE_STREAM釋放為php_stream結(jié)構(gòu)體分配的內(nèi)存
PRESERVE_HANDLE指示流的析構(gòu)器不要關閉它的底層描述符句柄
RSRC_DTOR流包裝層內(nèi)部管理資源列表的垃圾回收
PERSISTENT作用在持久化流上時, 它的行為將是永久的而不局限于當前請
求.
CLOSECALL_DTOR和RELEASE_STREAM的聯(lián)合. 這是關閉
非持久化流的一般選項.
CLOSE_CASTEDCLOSE和PRESERVE_HANDLE的聯(lián)合.
CLOSE_PERSISTENTCLOSE和PERSISTENT的聯(lián)合. 這是永久關閉持久化流的一
般選項.
實際上, 你并不需要直接調(diào)用php_stream_free()函數(shù). 而是在關閉流時使用下面兩個宏的某個替代:
#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)
通過zval交換流
因為流通常映射到zval上, 反之亦然, 因此提供了一組宏用來簡化操作, 并統(tǒng)一編碼(格式):
#define php_stream_to_zval(stream, pzval) \ ZVAL_RESOURCE((pzval), (stream)->rsrc_id);
要注意, 這里并沒有調(diào)用ZEND_REGISTER_RESOURCE(). 這是因為當流打開的時候, 已經(jīng)自動的注冊為資源了, 這樣就可以利用到引擎內(nèi)建的垃圾回收和shutdown系統(tǒng)的優(yōu)點. 使用這個宏而不是嘗試手動的將流注冊為新的資源ID是非常重要的; 這樣做的最終結(jié)果是導致流被關閉兩次以及引擎崩潰.
#define php_stream_from_zval(stream, ppzval) \ ZEND_FETCH_RESOURCE2((stream), php_stream*, (ppzval), \ -1, "stream", php_file_le_stream(), php_file_le_pstream()) #define php_stream_from_zval_no_verify(stream, ppzval) \ (stream) = (php_stream*)zend_fetch_resource((ppzval) \ TSRMLS_CC, -1, "stream", NULL, 2, \ php_file_le_stream(), php_file_le_pstream())
從傳入的zval *中取回php_stream *有一個類似的宏. 可以看出, 這個宏只是對資源獲取函數(shù)(第9章"資源數(shù)據(jù)類型")的一個簡單封裝. 請回顧ZEND_FETCH_RESOURCE2()宏, 第一個宏php_stream_from_zval()就是對它的包裝, 如果資源類型不匹配, 它將拋出一個警告并嘗試從函數(shù)實現(xiàn)中返回. 如果你只是想從傳入的zval *中獲取一個php_stream *, 而不希望有自動的錯誤處理, 就需要使用php_stream_from_zval_no_verify()并且需要手動的檢查結(jié)果值.
靜態(tài)資源操作
一個基于流的原子操作并不需要實際的實例. 下面這些API僅僅使用URL執(zhí)行這樣的操作:
int php_stream_stat_path(char *path, php_stream_statbuf *ssb);
和前面的php_stream_stat()類似, 這個函數(shù)提供了一個對POSIX的stat()函數(shù)協(xié)議依賴的包裝. 要注意, 并不是所有的協(xié)議都支持URL記法, 并且即便支持也可能不能報告出statbuf結(jié)構(gòu)體中的所有成員值. 一定要檢查php_stream_stat_path()失敗時的返回值, 0標識成功, 要知道, 不支持的元素返回時其值將是默認的0.
int php_stream_stat_path_ex(char *path, int flags, php_stream_statbuf *ssb, php_stream_context *context);
這個php_stream_url_stat()的擴展版本允許傳遞另外兩個參數(shù). 第一個是flags, 它的值可以是下面的PHP_STERAM_URL_STAT_*(下面省略PHP_STREAM_URL_STAT_前綴)一族常量的按位或的結(jié)果. 還有一個是context參數(shù), 它在其他的一些流函數(shù)中也有出現(xiàn), 我們將在第16章去詳細學習.
LINK原始的php_stream_stat_path()對于符號鏈接或目錄將會進行解析直到碰到
協(xié)議定義的結(jié)束資源. 傳遞PHP_STREAM_URL_STAT_LINK標記將導致
php_stream_stat_path()返回請求資源的信息而不會進行符號鏈接的解析.
(譯注: 我們可以這樣理解, 沒有這個標記, 底層使用stat(), 如果有這個標記,
底層使用lstat(), 關于stat()和lstat()的區(qū)別, 請查看*nix手冊)
QUIET默認情況下, 如果在執(zhí)行URL的stat操作過程中碰到錯誤, 包括文件未找到錯
誤, 都將通過php的錯誤處理機制觸發(fā). 傳遞QUIET標記可以使得
php_stream_stat_path()返回而不報告錯誤.
int php_stream_mkdir(char *path, int mode, int options, php_stream_context *context); int php_stream_rmdir(char *path, int options, php_stream_context *context);
創(chuàng)建和刪除目錄也會如你期望的工作. 這里的options參數(shù)和前面的php_stream_open_wrapper()函數(shù)的同名參數(shù)含義一致. 對于php_stream_mkdir(), 還有一個參數(shù)mode用于指定一個八進制的值表明讀寫執(zhí)行權限.
小結(jié)
本章中你接觸了一些基于流的I/O的內(nèi)部表象. 下一章將演示做呢樣實現(xiàn)自己的協(xié)議包裝, 甚至是定義自己的流類型.
以上就是[翻譯][php擴展開發(fā)和嵌入式]第14章-php中流的訪問的內(nèi)容,更多相關內(nèi)容請關注PHP中文網(wǎng)(miracleart.cn)!

? AI ??

Undress AI Tool
??? ???? ??

Undresser.AI Undress
???? ?? ??? ??? ?? AI ?? ?

AI Clothes Remover
???? ?? ???? ??? AI ?????.

Clothoff.io
AI ? ???

Video Face Swap
??? ??? AI ?? ?? ??? ???? ?? ???? ??? ?? ????!

?? ??

??? ??

???++7.3.1
???? ?? ?? ?? ???

SublimeText3 ??? ??
??? ??, ???? ?? ????.

???? 13.0.1 ???
??? PHP ?? ?? ??

???? CS6
??? ? ?? ??

SublimeText3 Mac ??
? ??? ?? ?? ?????(SublimeText3)

??? ??











tostaycurrentwithphpdevelopments ? bestpractices, followkeynewssources lifephp.netandphpweekly, adgytwithcommunitiesonforumsandconferences, readlingupdated andgrad indewfeatures, andreadorcontributetoopensourceproceprosts.first

phpbecamepupularforwebdevelopmentduetoiteofleneflening, whithhtml, wididepreadhostingsupport, andalargeecosystemincludingframeworkslikelaravelandcmsplatformsformslikewordpress.itexcelsinhandlingformsubmissions, managingussess, interptisussivers, ?? ???

TOSETTHERIGHTTIMEZONEINPHP, usedate_default_timezone_set () functionattStartOfyourscriptwitHavalidInlifiersuchas'America/new_york'.1.edate_default_timezone_set () beforeanydate/timeFunctions.2

TovalidateUserInputInphp, useBuilt-invalidationFunctions likefilter_var () ? filter_input (), applyRegulArexPessionSforCustomFormatsSuchasUsUserPhonEnumbers, CheckDatatypesFornumericValuesLikeAgeArPrice, setLtrimtsAnspacetReopeTopeTopeTopePeTopePeTopePeTopeTopeTopeTlyout

thephpfunctionserialize () andunserialize () areusedtoconvertcomplexDattoresintostorasandabackagain.1.serialize () c onvertsDatalikeCarraysorObjectSrayStringStringStrainingTainingTypeanDtuctureIncomation.2.

PHP ??? HTML ??? ???? ? ??? ??? ???? .php? ?? ??? ??? ???? ??? ???? ?? ?? ? ? ??? ??????. ?? ??? ???? PHP ??? ???? HTML? ?? ???? ?? ???? ??????. ?? ??? ???? PHP ? HTML? ?? ? ???? ??? ???? ?? ?? ??? ??? ? ????. ?? ???, ?? ?? ?? ?? ?? ? ?? ???? ?? ??? ??? ?? ?? ?? ? ?? ??????? ???????.

???? ???? ?? PHP ??? ???? ??? ??, ???? ??? ?? ??? ?? ??? ????. ??? ??? ???? ? ?????. 1. $ userData ? calculateToTalPrice ()? ?? ??? ??, ?? ? ??? ??? ??????. 2. PSR-12 ?? ?? ?? ???? ?????. 3. ??? ?? ?? ??? ???? MVC ?? Laravel ??? ????? ???? ??????. 4. ?? ??? ??? ??? ?? ???? ??? ?? ???? ????. 5. ? ???? ??? ???? ????? ??? ???? ?? ??, ?? ? ? ??? ??????. 6. ??? ??? ??, ??? ?? ??, ??? ?? ? ?? ??? ????. ??? ??? ?? ??, ?? ??? ? ?? ?? ? ???? ??????.

?, youcanrunsqlqueriesusingphp, andtheprocessinvolveschoingadatabaseexextension, executequeriessafely, andclosingconnectionswhendone.todothis, firstchoosebetween -mysqliorpdo, withpdobeingmoreflectibleblyblyblyblyblyblyblyblyblyblyblyblyblyblyblybledingmuttitatabas
