??? ??
PHP ???? ?? ??? ?? ? ??? ?? ???? ???? ? ??? ????. ??? ??: ?? ??, ?? ??, ???? ?? ??, ???? ????, ??? ??? ? ??? ??(??? ?? ? ??? ?? API).
?? ?? PHP ???
?? ??? ? ???? ???? ?? ?? ??? ????? ?? ???? ?? ??? ??? ??? ?? ??? ??? ????? ????. php_stream ??? ops ??.
typedef struct _php_stream { ... php_stream_ops *ops; ... } php_stream;
php_stream_ops ??? ?? ??? ???? ?? ??? ?????.
typedef struct _php_stream_ops { size_t (*write)(php_stream *stream, const char *buf, size_t count TSRMLS_DC); size_t (*read)(php_stream *stream, char *buf, size_t count TSRMLS_DC); int (*close)(php_stream *stream, int close_handle TSRMLS_DC); int (*flush)(php_stream *stream TSRMLS_DC); const char *label; int (*seek)(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC); int (*cast)(php_stream *stream, int castas, void **ret TSRMLS_DC); int (*stat)(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC); int (*set_option)(php_stream *stream, int option,int value, void *ptrparam TSRMLS_DC); } php_stream_ops;
php_stream_read() ?? ??? ??? ??? ?????? ??? ??? ??? ??? stream->ops?? ?? ??? ?? ???? ????? ???? ?????? ??? ?? ?? ??? ??? ??? ?? ?????. ?? ?? ?? ??? ??? ops ??? ?? ?? ??? ??? ?? ?????(?? ??? ?? ??? ?? ? ?????).
size_t php_stdio_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) { php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract; return read(data->fd, buf, count); }
compress.zlib ????? ???? ops ???? ?? ??? ?????.
size_t php_zlib_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) { struct php_gz_stream_data_t *data = (struct php_gz_stream_data_t *) stream->abstract; return gzread(data->gz_file, buf, count); }
??? ?? ?? ???? ? ?? ops ??? ???? ?? ???? ?? ??? ?? ?? ????? ????. ?? ? ??? ?? I/O ???? posix? read() ??? ???? ?? zlib ???? libz? gzread() ??? ?????.
????? stream->abstract ??? ????? ?? ? ? ????. ?? ??? ?? ?? ??? ?? ? ??? ? ?? ??? ??? ?? ??? ??????.
? ?? ?? php_stream_ops ??? ? ??? ?? ??? ????? ????? ????. ?? ??? ??? ???? ??? ???? ?? ?? ops ??? ?????? ?? ?? ??? ??? ? ?? ?? ??? ??(php_stream_open_wrapper())? ????.
? ??? ???? PHP? ??? ?? ???? ??? URL?cheme:// ??? ???? ?? ????? ???? ??? ????? ?????. ? ??? ???? ?? php_stream_wrapper ??? ?? ? ????. ? php_stream_wrapper ??? php_stream_wrapper_ops ??? ???? ?? ops ??? ?? ? ????.
typedef struct _php_stream_wrapper_ops { php_stream *(*stream_opener)(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); int (*stream_closer)(php_stream_wrapper *wrapper, php_stream *stream TSRMLS_DC); int (*stream_stat)(php_stream_wrapper *wrapper, php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC); int (*url_stat)(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC); php_stream *(*dir_opener)(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); const char *label; int (*unlink)(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC); int (*rename)(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC); int (*stream_mkdir)(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC); int (*stream_rmdir)(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC); } php_stream_wrapper_ops;
??? ??? ??? ??? ??->ops-> ??? ????? ???? ??? php_stream_ops ??? ???? ?? ?? ???? ????? ?? ?? ?? ??? ???? stream_opener().
dir_opener() ??? ??? ?? ??? ?????. ??? ?? php_stream_opendir() API ??? ?? ???? ????? ?? php_stream_ops ??? ??? ????? ??????. stat() ? close() ) ??? ????? ???? ?? ? ???? ?????.
?? ??? ???? ??? ??? API ??? ???? ??? ?? ??? ??? ??? ? ????. php_stream ??? ???? ?? ?? ?? ??? ? ?????.
php 4.3? flow ?? ??? ????? ? url_stat? ????? ?? ?? ??? ????? PHP 5.0??? ???? ?????. ?? ??? 3? ??? rename(), stream_mkdir( ) ? stream_rmdir()? PHP 5.0 ???? ??? ops ??? ?????.
?? ??
url_stat() ??? ???? ?? ??? const char *label ?? ??? ?? ??? ???? ??? ?????? ??? ? ????. ? ??? ??? ??? ????.
stream_opener()? ??? ????? ????????. ??? ?? fopen() ??? ???? ? ???
??? ?????. ? ???? ??? php_stream ????? fopen() ???? ??? ???????.
?? ?? file(), file_get_contents(),
file_put_contents(), readfile() ?? ?? ??, ??? ??? ?? ? , ? ???? ?????
loader ops
stream_closer() ? ??? ??? ????? ?? ??? ??? ? stream_opener()
? ?? ??? ?? ???? ? ?? ????? ????? ???.
stream_stat()??? ??? fstat() ??? ???? ? ??? ssb ??? ??? ???(???
??? struct statbuf sb ??? ??? ??),
dir_opener()? stream_opener()? ???? ????? ??? ??? ??? ? ?????.
???? ????? ???? ?? ??? ??? ?? ???? ??? ??? ????.
??? ???? ???? ?? ????? ?? ?? ??? ??? ???? ???? ???.
???? ??? dirent? ?????.
?? ?? ??? ?? ?? ??? ?? ????? ?? URI ???? ??? ??? ???? ????. php4.3?? php_stream_wrapper_ops ??? url_stat() ? unlink()? ????. ?? ??? php 5.0???. ??? ? #ifdef ?? ??? ???? ???.
url_stat()
stat() ?? ??? ??? ?? ??? ?? ?? ?????? ???? ? ?????. ??, ??,
???, ??, ?? ??. ?? ? ??? PHP 4.3? ??? ??? ???? ????? ? ??????. 在php_stream_wrapper_ops結(jié)構(gòu)體中的, 但直到php 5.0才被用戶空 間的stat()函數(shù)使用. unlink()和posix文件系統(tǒng)的同名函數(shù)語(yǔ)義相同, 它執(zhí)行文件刪除. 如果對(duì)于當(dāng) 前的包裝器刪除沒(méi)有意義, 比如內(nèi)建的http://包裝器, 這個(gè)函數(shù)應(yīng)該被 定義為NULL, 以便內(nèi)核去引發(fā)適當(dāng)?shù)腻e(cuò)誤消息. rename()當(dāng)用戶空間的rename()函數(shù)的參數(shù)$from和$to參數(shù)指向的是相同的 底層包裝器實(shí)現(xiàn), php則將這個(gè)重命名請(qǐng)求分發(fā)到包裝器的rename函 數(shù). mkdir() & rmdir()這兩個(gè)函數(shù)直接映射到對(duì)應(yīng)的用戶空間函數(shù). 實(shí)現(xiàn)一個(gè)包裝器 為了演示包裝器和流操作的內(nèi)部工作原理, 我們需要重新實(shí)現(xiàn)php手冊(cè)的stream_wrapper_register()一頁(yè)示例中的var://包裝器. 此刻, 首先從下面功能完整的變量流包裝實(shí)現(xiàn)開始. 構(gòu)建他, 并開始檢查每一塊的工作原理. 譯注: 為了方便大家閱讀, 對(duì)代碼的注釋進(jìn)行了適量補(bǔ)充調(diào)整, 此外, 由于phpapi的調(diào)整, 原著中的代碼不能直接在譯者使用的php-5.4.10中運(yùn)行, 進(jìn)行了適當(dāng)?shù)男薷? 因此下面代碼結(jié)構(gòu)可能和原著略有不同, 請(qǐng)參考閱讀.(下面opendir的例子也進(jìn)行了相應(yīng)的修改) config.m4 php_varstream.h varstream.c 在構(gòu)建加載擴(kuò)展后, php就可以處理以var://開始的URL的請(qǐng)求, 它的行為和手冊(cè)中用戶空間實(shí)現(xiàn)的行為一致. 內(nèi)部實(shí)現(xiàn) 首先你注意到的可能是這個(gè)擴(kuò)展完全沒(méi)有暴露用戶空間函數(shù). 它所做的只是在MINIT函數(shù)中調(diào)用了一個(gè)核心PHPAPI的鉤子, 將var協(xié)議和我們定義的包裝器關(guān)聯(lián)起來(lái): 很明顯, 最重要的元素就是ops, 它提供了訪問(wèn)特定流包裝器的創(chuàng)建以及檢查函數(shù). 你可以安全的忽略abstract屬性, 它僅在運(yùn)行時(shí)使用, 在初始化定義時(shí), 它只是作為一個(gè)占位符. 第三個(gè)元素is_url, 它告訴php在使用這個(gè)包裝器時(shí)是否考慮php.ini中的allow_url_fopen選項(xiàng). 如果這個(gè)值非0, 并且將allow_url_fopen設(shè)置為false, 則這個(gè)包裝器不能被腳本使用. 在本章前面你已經(jīng)知道, 調(diào)用用戶空間函數(shù)比如fopen將通過(guò)這個(gè)包裝器的ops元素得到php_varstream_wrapper_ops, 這樣去調(diào)用流的打開函數(shù)php_varstream_opener. 這個(gè)函數(shù)的第一塊代碼檢查是否請(qǐng)求持久化的流: 對(duì)于很多包裝器這樣的請(qǐng)求是合法的. 然而目前的情況這個(gè)行為沒(méi)有意義. 一方面用戶空間變量的定義就是臨時(shí)的, 另一方面, varstream的實(shí)例化代價(jià)很低, 這就使得持久化的優(yōu)勢(shì)很小. 像流包裝層報(bào)告錯(cuò)誤很簡(jiǎn)單, 只需要返回一個(gè)NULL值而不是流實(shí)例即可. 流包裝層透出到用戶空間的失敗消息并不會(huì)說(shuō)明具體的錯(cuò)誤, 只是說(shuō)明不能打開URL. 要想給開發(fā)者暴露更多的錯(cuò)誤信息, 可以在返回之前使用php_stream_wrapper_log_error()函數(shù). URL解析 實(shí)例化varstream的下一步需要一個(gè)人類可讀的URL, 將它分塊放入到一個(gè)易管理的結(jié)構(gòu)體中. 幸運(yùn)的是它使用了和用戶空間url_parse()函數(shù)相同的機(jī)制. 如果URL成功解析, 將會(huì)分配一個(gè)php_url結(jié)構(gòu)體并設(shè)置合適的值. 如果在URL中沒(méi)有某些值, 在返回的php_url中對(duì)應(yīng)的將被設(shè)置為NULL. 這個(gè)結(jié)構(gòu)體必須在離開php_varstream_opener函數(shù)之前被顯式釋放, 否則它的內(nèi)存將會(huì)泄露: 最后, varstream包裝器創(chuàng)建了一個(gè)數(shù)據(jù)結(jié)構(gòu), 保存了流指向的變量名, 讀取時(shí)的當(dāng)前位置. 這個(gè)結(jié)構(gòu)體將在流的讀取和寫入函數(shù)中用于獲取變量, 并且將在流結(jié)束使用時(shí)由php_varstream_close函數(shù)釋放. opendir() 讀寫變量?jī)?nèi)容的實(shí)現(xiàn)可以再次進(jìn)行擴(kuò)展. 這里可以加入一個(gè)新的特性, 允許使用目錄函數(shù)讀取數(shù)組中的key. 在你的php_varstream_wrapper_ops結(jié)構(gòu)體之前增加下面的代碼: 現(xiàn)在, 將你的php_varstream_wrapper_ops結(jié)構(gòu)體中的dir_opener的NULL替換成你的php_varstream_opendir函數(shù). 最后, 將下面新定義的類型放入到你的php_varstream.h文件的php_varstream_data定義下面: 在你基于fopen()實(shí)現(xiàn)的varstream包裝器中, 你直接使用持久變量名, 每次執(zhí)行讀寫操作時(shí)從符號(hào)表中獲取變量. 而這里, opendir()的實(shí)現(xiàn)中獲取變量時(shí)處理了變量不存在或者類型錯(cuò)誤的異常. 你還有一個(gè)數(shù)組變量的拷貝, 這就說(shuō)明原數(shù)組的改變并不會(huì)影響后續(xù)的readdir()調(diào)用的結(jié)果. 原來(lái)存儲(chǔ)變量名的方式也可以正常工作, 這里只是給出另外一種選擇作為演示示例. 由于目錄訪問(wèn)是基于成塊的目錄條目, 而不是字符, 因此這里需要一套獨(dú)立的流操作. 這個(gè)版本中, write沒(méi)有意義, 因此保持它為NULL. read的實(shí)現(xiàn)使用zend_hash_get_current_key_ex()函數(shù)將數(shù)組映射到目錄名. 而隨機(jī)訪問(wèn)也只是對(duì)SEEK_SET有效, 用來(lái)響應(yīng)rewinddir()跳轉(zhuǎn)到數(shù)組開始位置. 實(shí)際上, 目錄流并沒(méi)有使用SEEK_CUR, SEEK_END, 或者除了0之外的偏移量. 在實(shí)現(xiàn)目錄流操作時(shí), 最好還是涉及你的函數(shù)能以某種方式處理這些情況, 以使得在流包裝層變化時(shí)能夠適應(yīng)其目錄隨機(jī)訪問(wèn). 操縱 5個(gè)靜態(tài)包裝器操作中的4個(gè)用來(lái)處理不是基于I/O的流資源操作. 你已經(jīng)看到過(guò)它們并了解它們的原型; 現(xiàn)在我們看看varstream包裝器框架中它們的實(shí)現(xiàn): unlink 在你的wrapper_ops結(jié)構(gòu)體中增加下面的函數(shù), 它可以讓unlink()通過(guò)varstream包裝器, 擁有和unset()一樣的行為: 這個(gè)函數(shù)的編碼量和php_varstream_opener差不多. 唯一的不同在于這里你需要傳遞變量名給zend_hash_del()去刪除變量. 譯注: 譯者的php-5.4.10環(huán)境中, 使用unlink()刪除變量后, 在用戶空間再次讀取該變量名的值會(huì)導(dǎo)致core dump. 因此上面代碼中譯者進(jìn)行了修正, 刪除變量時(shí)使用了zend_delete_global_variable(), 請(qǐng)讀者參考閱讀zend_delete_global_variable()函數(shù)源代碼, 考慮為什么直接用zend_hash_del()刪除, 會(huì)導(dǎo)致core dump. 下面是譯者測(cè)試用的用戶空間代碼: 這個(gè)函數(shù)的代碼量應(yīng)該和php_varstream_opener差不多. 唯一的不同是這里是傳遞變量名給zend_hash_del()去刪除變量. rename, mkdir, rmdir 為了一致性, 下面給出rename, mkdir, rmdir函數(shù)的實(shí)現(xiàn): 檢查 并不是所有的流操作都涉及到資源的操縱. 有時(shí)候也需要查看活動(dòng)的流在某個(gè)時(shí)刻的狀態(tài), 或檢查潛在可打開的資源的狀態(tài). 這一節(jié)流和包裝器的ops函數(shù)都是在相同的數(shù)據(jù)結(jié)構(gòu)php_stream_statbuf上工作的, 它只有一個(gè)元素: posix標(biāo)準(zhǔn)的struct statbuf. 當(dāng)本節(jié)的某個(gè)函數(shù)被調(diào)用時(shí), 將嘗試填充盡可能多的statbuf元素的成員. stat 如果設(shè)置, 當(dāng)請(qǐng)求激活流實(shí)例的信息時(shí), 將會(huì)調(diào)用wrapper->ops->stream_stat(). 如果沒(méi)有設(shè)置, 則對(duì)應(yīng)的stream->ops->stat()將會(huì)被調(diào)用. 無(wú)論哪個(gè)函數(shù)被調(diào)用, 都應(yīng)該盡可能多的向返回的statbuf結(jié)構(gòu)體ssb->sb中填充盡可能多流實(shí)例的有用信息. 在普通文件I/O的用法中, 它對(duì)應(yīng)fstat()的標(biāo)準(zhǔn)I/O調(diào)用. url_stat 在流實(shí)例外部調(diào)用wrapper->ops->url_stat()取到流資源的元數(shù)據(jù). 通常來(lái)說(shuō), 符號(hào)鏈接和重定向都應(yīng)該被解析, 直到找到一個(gè)真正的資源, 對(duì)其通過(guò)stat()系統(tǒng)調(diào)用這樣的機(jī)制讀取統(tǒng)計(jì)信息. url_stat的flags參數(shù)允許是下面PHP_STREAM_URL_STAT_*系列的常量值(省略PHP_STREAM_URL_STAT_前綴): LINK不解析符號(hào)鏈接和重定向. 而是報(bào)告它碰到的第一個(gè)節(jié)點(diǎn)的信息, 無(wú)論是連 接還是真正的資源. QUIET? ??? ???? ????. ?? ?? ?? ??? ??? REPORT_ERRORS ??? ??????. . ?? ?? ???? I/O? ???? ???? ????? ?? ?? ????? ?? ???? ?? ??? ????? ???? ??? ?? ? I/O ?? ??? ?? ??? ??? ???? ??? ?? ???? ?? ???? ??????. ?? ???? ??? ????? ?? ???? ?? ??? ??? ?? ??? ????????. ??? ????? ???? ?? ?? ??? ???? ?????? ???? ??? ?? ????.
?? [??] [php ?? ?? ? ????] 15? - PHP ????? ?? ?????. PHP ??? ????(miracleart.cn)? ??????! PHP_ARG_ENABLE(varstream,whether to enable varstream support,
[ enable-varstream Enable varstream support])
if test "$PHP_VARSTREAM" = "yes"; then
AC_DEFINE(HAVE_VARSTREAM,1,[Whether you want varstream])
PHP_NEW_EXTENSION(varstream, varstream.c, $ext_shared)
fi
#ifndef PHP_VARSTREAM_H
#define PHP_VARSTREAM_H
extern zend_module_entry varstream_module_entry;
#define phpext_varstream_ptr &varstream_module_entry
#ifdef PHP_WIN32
# define PHP_VARSTREAM_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
# define PHP_VARSTREAM_API __attribute__ ((visibility("default")))
#else
# define PHP_VARSTREAM_API
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
PHP_MINIT_FUNCTION(varstream);
PHP_MSHUTDOWN_FUNCTION(varstream);
#define PHP_VARSTREAM_WRAPPER "var"
#define PHP_VARSTREAM_STREAMTYPE "varstream"
/* 變量流的抽象數(shù)據(jù)結(jié)構(gòu) */
typedef struct _php_varstream_data {
off_t position;
char *varname;
int varname_len;
} php_varstream_data;
#ifdef ZTS
#define VARSTREAM_G(v) TSRMG(varstream_globals_id, zend_varstream_globals *, v)
#else
#define VARSTREAM_G(v) (varstream_globals.v)
#endif
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "ext/standard/url.h"
#include "php_varstream.h"
static size_t php_varstream_write(php_stream *stream,
const char *buf, size_t count TSRMLS_DC)
{
php_varstream_data *data = stream->abstract;
zval **var;
size_t newlen;
/* 查找變量 */
if (zend_hash_find(&EG(symbol_table), data->varname,
data->varname_len + 1,(void**)&var) == FAILURE) {
/* 變量不存在, 直接創(chuàng)建一個(gè)字符串類型的變量, 并保存新傳遞進(jìn)來(lái)的內(nèi)容 */
zval *newval;
MAKE_STD_ZVAL(newval);
ZVAL_STRINGL(newval, buf, count, 1);
/* 將新的zval *放到變量中 */
zend_hash_add(&EG(symbol_table), data->varname,
data->varname_len + 1, (void*)&newval,
sizeof(zval*), NULL);
return count;
}
/* 如果需要, 讓變量可寫. 這里實(shí)際上處理的是寫時(shí)復(fù)制 */
SEPARATE_ZVAL_IF_NOT_REF(var);
/* 轉(zhuǎn)換為字符串類型 */
convert_to_string_ex(var);
/* 重置偏移量(譯注: 相比于正常的文件系統(tǒng), 這里的處理實(shí)際上不支持文件末尾的空洞創(chuàng)建, 讀者如果熟悉*nix文件系統(tǒng), 應(yīng)該了解譯者所說(shuō), 否則請(qǐng)略過(guò)) */
if (data->position > Z_STRLEN_PP(var)) {
data->position = Z_STRLEN_PP(var);
}
/* 計(jì)算新的字符串長(zhǎng)度 */
newlen = data->position + count;
if (newlen < Z_STRLEN_PP(var)) {
/* 總長(zhǎng)度不變 */
newlen = Z_STRLEN_PP(var);
} else if (newlen > Z_STRLEN_PP(var)) {
/* 重新調(diào)整緩沖區(qū)大小以保存新內(nèi)容 */
Z_STRVAL_PP(var) =erealloc(Z_STRVAL_PP(var),newlen+1);
/* 更新字符串長(zhǎng)度 */
Z_STRLEN_PP(var) = newlen;
/* 確保字符串NULL終止 */
Z_STRVAL_PP(var)[newlen] = 0;
}
/* 將數(shù)據(jù)寫入到變量中 */
memcpy(Z_STRVAL_PP(var) + data->position, buf, count);
data->position += count;
return count;
}
static size_t php_varstream_read(php_stream *stream,
char *buf, size_t count TSRMLS_DC)
{
php_varstream_data *data = stream->abstract;
zval **var, copyval;
int got_copied = 0;
size_t toread = count;
if (zend_hash_find(&EG(symbol_table), data->varname,
data->varname_len + 1, (void**)&var) == FAILURE) {
/* 變量不存在, 讀不到數(shù)據(jù), 返回0字節(jié)長(zhǎng)度 */
return 0;
}
copyval = **var;
if (Z_TYPE(copyval) != IS_STRING) {
/* 對(duì)于非字符串類型變量, 創(chuàng)建一個(gè)副本進(jìn)行讀, 這樣對(duì)于只讀的變量, 就不會(huì)改變其原始類型 */
zval_copy_ctor(?val);
INIT_PZVAL(?val);
got_copied = 1;
}
if (data->position > Z_STRLEN(copyval)) {
data->position = Z_STRLEN(copyval);
}
if ((Z_STRLEN(copyval) - data->position) < toread) {
/* 防止讀取到變量可用緩沖區(qū)外的內(nèi)容 */
toread = Z_STRLEN(copyval) - data->position;
}
/* 設(shè)置緩沖區(qū) */
memcpy(buf, Z_STRVAL(copyval) + data->position, toread);
data->position += toread;
/* 如果創(chuàng)建了副本, 則釋放副本 */
if (got_copied) {
zval_dtor(?val);
}
/* 返回設(shè)置到緩沖區(qū)的字節(jié)數(shù) */
return toread;
}
static int php_varstream_closer(php_stream *stream,
int close_handle TSRMLS_DC)
{
php_varstream_data *data = stream->abstract;
/* 釋放內(nèi)部結(jié)構(gòu)避免泄露 */
efree(data->varname);
efree(data);
return 0;
}
static int php_varstream_flush(php_stream *stream TSRMLS_DC)
{
php_varstream_data *data = stream->abstract;
zval **var;
/* 根據(jù)不同情況, 重置偏移量 */
if (zend_hash_find(&EG(symbol_table), data->varname,
data->varname_len + 1, (void**)&var)
== SUCCESS) {
if (Z_TYPE_PP(var) == IS_STRING) {
data->position = Z_STRLEN_PP(var);
} else {
zval copyval = **var;
zval_copy_ctor(?val);
convert_to_string(?val);
data->position = Z_STRLEN(copyval);
zval_dtor(?val);
}
} else {
data->position = 0;
}
return 0;
}
static int php_varstream_seek(php_stream *stream, off_t offset,
int whence, off_t *newoffset TSRMLS_DC)
{
php_varstream_data *data = stream->abstract;
switch (whence) {
case SEEK_SET:
data->position = offset;
break;
case SEEK_CUR:
data->position += offset;
break;
case SEEK_END:
{
zval **var;
size_t curlen = 0;
if (zend_hash_find(&EG(symbol_table),
data->varname, data->varname_len + 1,
(void**)&var) == SUCCESS) {
if (Z_TYPE_PP(var) == IS_STRING) {
curlen = Z_STRLEN_PP(var);
} else {
zval copyval = **var;
zval_copy_ctor(?val);
convert_to_string(?val);
curlen = Z_STRLEN(copyval);
zval_dtor(?val);
}
}
data->position = curlen + offset;
break;
}
}
/* 防止隨機(jī)訪問(wèn)指針移動(dòng)到緩沖區(qū)開始位置之前 */
if (data->position < 0) {
data->position = 0;
}
if (newoffset) {
*newoffset = data->position;
}
return 0;
}
static php_stream_ops php_varstream_ops = {
php_varstream_write,
php_varstream_read,
php_varstream_closer,
php_varstream_flush,
PHP_VARSTREAM_STREAMTYPE,
php_varstream_seek,
NULL, /* cast */
NULL, /* stat */
NULL, /* set_option */
};
/* Define the wrapper operations */
static php_stream *php_varstream_opener(
php_stream_wrapper *wrapper,
char *filename, char *mode, int options,
char **opened_path, php_stream_context *context
STREAMS_DC TSRMLS_DC)
{
php_varstream_data *data;
php_url *url;
if (options & STREAM_OPEN_PERSISTENT) {
/* 按照變量流的定義, 是不能持久化的
* 因?yàn)樽兞吭谡?qǐng)求結(jié)束后將被釋放
*/
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Unable to open %s persistently",
filename);
return NULL;
}
/* 標(biāo)準(zhǔn)URL解析: scheme://user:pass@host:port/path?query#fragment */
url = php_url_parse(filename);
if (!url) {
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Unexpected error parsing URL");
return NULL;
}
/* 檢查是否有變量流URL必須的元素host, 以及scheme是否是var */
if (!url->host || (url->host[0] == 0) ||
strcasecmp("var", url->scheme) != 0) {
/* Bad URL or wrong wrapper */
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Invalid URL, must be in the form: "
"var://variablename");
php_url_free(url);
return NULL;
}
/* 創(chuàng)建一個(gè)數(shù)據(jù)結(jié)構(gòu)保存協(xié)議信息(變量流協(xié)議重要是變量名, 變量名長(zhǎng)度, 當(dāng)前偏移量) */
data = emalloc(sizeof(php_varstream_data));
data->position = 0;
data->varname_len = strlen(url->host);
data->varname = estrndup(url->host, data->varname_len + 1);
/* 釋放前面解析出來(lái)的url占用的內(nèi)存 */
php_url_free(url);
/* 實(shí)例化一個(gè)流, 為其賦予恰當(dāng)?shù)牧鱫ps, 綁定抽象數(shù)據(jù) */
return php_stream_alloc(&php_varstream_ops, data, 0, mode);
}
static php_stream_wrapper_ops php_varstream_wrapper_ops = {
php_varstream_opener, /* 調(diào)用php_stream_open_wrapper(sprintf("%s://xxx", PHP_VARSTREAM_WRAPPER))時(shí)執(zhí)行 */
NULL, /* stream_close */
NULL, /* stream_stat */
NULL, /* url_stat */
NULL, /* dir_opener */
PHP_VARSTREAM_WRAPPER,
NULL, /* unlink */
#if PHP_MAJOR_VERSION >= 5
/* PHP >= 5.0 only */
NULL, /* rename */
NULL, /* mkdir */
NULL, /* rmdir */
#endif
};
static php_stream_wrapper php_varstream_wrapper = {
&php_varstream_wrapper_ops,
NULL, /* abstract */
0, /* is_url */
};
PHP_MINIT_FUNCTION(varstream)
{
/* 注冊(cè)流包裝器:
* 1. 檢查流包裝器名字是否正確(符合這個(gè)正則: /^[a-zA-Z0-9+.-]+$/)
* 2. 將傳入的php_varstream_wrapper增加到url_stream_wrappers_hash這個(gè)HashTable中, key為PHP_VARSTREAM_WRAPPER
*/
if (php_register_url_stream_wrapper(PHP_VARSTREAM_WRAPPER,
&php_varstream_wrapper TSRMLS_CC)==FAILURE) {
return FAILURE;
}
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(varstream)
{
/* 卸載流包裝器: 從url_stream_wrappers_hash中刪除 */
if (php_unregister_url_stream_wrapper(PHP_VARSTREAM_WRAPPER
TSRMLS_CC) == FAILURE) {
return FAILURE;
}
return SUCCESS;
}
zend_module_entry varstream_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"varstream",
NULL,
PHP_MINIT(varstream),
PHP_MSHUTDOWN(varstream),
NULL,
NULL,
NULL,
#if ZEND_MODULE_API_NO >= 20010901
"0.1",
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_VARSTREAM
ZEND_GET_MODULE(varstream)
#endif
static php_stream_wrapper php_varstream_wrapper = {
&php_varstream_wrapper_ops,
NULL, /* abstract */
0, /* is_url */
}
if (options & STREAM_OPEN_PERSISTENT) {
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Unable to open %s persistently",
filename);
return NULL;
typedef struct php_url {
/* scheme://user:pass@host:port/path?query#fragment */
char *scheme;
char *user;
char *pass;
char *host;
unsigned short port;
char *path;
char *query;
char *fragment;
} php_url;
static size_t php_varstream_readdir(php_stream *stream,
char *buf, size_t count TSRMLS_DC)
{
php_stream_dirent *ent = (php_stream_dirent*)buf;
php_varstream_dirdata *data = stream->abstract;
char *key;
int type, key_len;
long idx;
/* 查找數(shù)組中的key */
type = zend_hash_get_current_key_ex(Z_ARRVAL_P(data->arr),
&key, &key_len, &idx, 0, &(data->pos));
/* 字符串key */
if (type == HASH_KEY_IS_STRING) {
if (key_len >= sizeof(ent->d_name)) {
/* truncate long keys to maximum length */
key_len = sizeof(ent->d_name) - 1;
}
/* 設(shè)置到目錄結(jié)構(gòu)上 */
memcpy(ent->d_name, key, key_len);
ent->d_name[key_len] = 0;
/* 數(shù)值key */
} else if (type == HASH_KEY_IS_LONG) {
/* 設(shè)置到目錄結(jié)構(gòu)上 */
snprintf(ent->d_name, sizeof(ent->d_name), "%ld",idx);
} else {
/* 迭代結(jié)束 */
return 0;
}
/* 移動(dòng)數(shù)組指針(位置記錄到流的抽象結(jié)構(gòu)中) */
zend_hash_move_forward_ex(Z_ARRVAL_P(data->arr),
&data->pos);
return sizeof(php_stream_dirent);
}
static int php_varstream_closedir(php_stream *stream,
int close_handle TSRMLS_DC)
{
php_varstream_dirdata *data = stream->abstract;
zval_ptr_dtor(&(data->arr));
efree(data);
return 0;
}
static int php_varstream_dirseek(php_stream *stream,
off_t offset, int whence,
off_t *newoffset TSRMLS_DC)
{
php_varstream_dirdata *data = stream->abstract;
if (whence == SEEK_SET && offset == 0) {
/* 重置數(shù)組指針 */
zend_hash_internal_pointer_reset_ex(
Z_ARRVAL_P(data->arr), &(data->pos));
if (newoffset) {
*newoffset = 0;
}
return 0;
}
/* 不支持其他類型的隨機(jī)訪問(wèn) */
return -1;
}
static php_stream_ops php_varstream_dirops = {
NULL, /* write */
php_varstream_readdir,
php_varstream_closedir,
NULL, /* flush */
PHP_VARSTREAM_DIRSTREAMTYPE,
php_varstream_dirseek,
NULL, /* cast */
NULL, /* stat */
NULL, /* set_option */
};
static php_stream *php_varstream_opendir(
php_stream_wrapper *wrapper,
char *filename, char *mode, int options,
char **opened_path, php_stream_context *context
STREAMS_DC TSRMLS_DC)
{
php_varstream_dirdata *data;
php_url *url;
zval **var;
/* 不支持持久化流 */
if (options & STREAM_OPEN_PERSISTENT) {
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Unable to open %s persistently",
filename);
return NULL;
}
/* 解析URL */
url = php_url_parse(filename);
if (!url) {
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Unexpected error parsing URL");
return NULL;
}
/* 檢查請(qǐng)求URL的正確性 */
if (!url->host || (url->host[0] == 0) ||
strcasecmp("var", url->scheme) != 0) {
/* Bad URL or wrong wrapper */
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Invalid URL, must be in the form: "
"var://variablename");
php_url_free(url);
return NULL;
}
/* 查找變量 */
if (zend_hash_find(&EG(symbol_table), url->host,
strlen(url->host) + 1, (void**)&var) == FAILURE) {
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Variable $%s not found", url->host);
php_url_free(url);
return NULL;
}
/* 檢查變量類型 */
if (Z_TYPE_PP(var) != IS_ARRAY) {
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "$%s is not an array", url->host);
php_url_free(url);
return NULL;
}
/* 釋放前面分配的URL結(jié)構(gòu) */
php_url_free(url);
/* 分配抽象數(shù)據(jù)結(jié)構(gòu) */
data = emalloc(sizeof(php_varstream_dirdata));
if ( Z_ISREF_PP(var) && Z_REFCOUNT_PP(var) > 1) {
/* 全拷貝 */
MAKE_STD_ZVAL(data->arr);
*(data->arr) = **var;
zval_copy_ctor(data->arr);
INIT_PZVAL(data->arr);
} else {
/* 寫時(shí)拷貝 */
data->arr = *var;
Z_SET_REFCOUNT_P(data->arr, Z_REFCOUNT_P(data->arr) + 1);
}
/* 重置數(shù)組指針 */
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(data->arr),
&data->pos);
return php_stream_alloc(&php_varstream_dirops,data,0,mode);
}
#define PHP_VARSTREAM_DIRSTREAMTYPE "varstream directory"
typedef struct _php_varstream_dirdata {
zval *arr;
HashPosition pos;
} php_varstream_dirdata;
static int php_varstream_unlink(php_stream_wrapper *wrapper,
char *filename, int options,
php_stream_context *context
TSRMLS_DC)
{
php_url *url;
url = php_url_parse(filename);
if (!url) {
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Unexpected error parsing URL");
return -1;
}
if (!url->host || (url->host[0] == 0) ||
strcasecmp("var", url->scheme) != 0) {
/* URL不合法 */
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Invalid URL, must be in the form: "
"var://variablename");
php_url_free(url);
return -1;
}
/* 從符號(hào)表刪除變量 */
//zend_hash_del(&EG(symbol_table), url->host, strlen(url->host) + 1);
zend_delete_global_variable(url->host, strlen(url->host) + 1 TSRMLS_CC);
php_url_free(url);
return 0;
}
<?php
$fp = fopen('var://hello', 'r');
fwrite($fp, 'world');
var_dump($hello);
unlink('var://hello');
$a = $hello;
static int php_varstream_rename(php_stream_wrapper *wrapper,
char *url_from, char *url_to, int options,
php_stream_context *context TSRMLS_DC)
{
php_url *from, *to;
zval **var;
/* 來(lái)源URL解析 */
from = php_url_parse(url_from);
if (!from) {
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Unexpected error parsing source");
return -1;
}
/* 查找變量 */
if (zend_hash_find(&EG(symbol_table), from->host,
strlen(from->host) + 1,
(void**)&var) == FAILURE) {
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "$%s does not exist", from->host);
php_url_free(from);
return -1;
}
/* 目標(biāo)URL解析 */
to = php_url_parse(url_to);
if (!to) {
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Unexpected error parsing dest");
php_url_free(from);
return -1;
}
/* 變量的改名 */
Z_SET_REFCOUNT_PP(var, Z_REFCOUNT_PP(var) + 1);
zend_hash_update(&EG(symbol_table), to->host,
strlen(to->host) + 1, (void*)var,
sizeof(zval*), NULL);
zend_hash_del(&EG(symbol_table), from->host,
strlen(from->host) + 1);
php_url_free(from);
php_url_free(to);
return 0;
}
static int php_varstream_mkdir(php_stream_wrapper *wrapper,
char *url_from, int mode, int options,
php_stream_context *context TSRMLS_DC)
{
php_url *url;
/* URL解析 */
url = php_url_parse(url_from);
if (!url) {
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "Unexpected error parsing URL");
return -1;
}
/* 檢查變量是否存在 */
if (zend_hash_exists(&EG(symbol_table), url->host,
strlen(url->host) + 1)) {
php_stream_wrapper_log_error(wrapper, options
TSRMLS_CC, "$%s already exists", url->host);
php_url_free(url);
return -1;
}
/* EG(uninitialized_zval_ptr)通常是IS_NULL的zval *, 引用計(jì)數(shù)無(wú)限大 */
zend_hash_add(&EG(symbol_table), url->host,
strlen(url->host) + 1,
(void*)&EG(uninitialized_zval_ptr),
sizeof(zval*), NULL);
php_url_free(url);
return 0;
}
static int php_varstream_rmdir(php_stream_wrapper *wrapper,
char *url, int options,
php_stream_context *context TSRMLS_DC)
{
/* 行為等價(jià)于unlink() */
wrapper->wops->unlink(wrapper, url, options,
context TSRMLS_CC);
}

? 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
