国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Maison développement back-end tutoriel php [Traduction][Développement et intégration d'extensions php] Chapitre 14 - Accès aux flux en php

[Traduction][Développement et intégration d'extensions php] Chapitre 14 - Accès aux flux en php

Feb 10, 2017 am 10:18 AM
php


Flux d'accès

Tous les traitements d'E/S de fichiers dans l'espace utilisateur PHP se font via php Traité par le wrapper de flux PHP introduit dans la version 4.3. En interne, le code d'extension peut choisir d'utiliser le traitement de fichiers stdio ou posix pour communiquer avec le système de fichiers local ou le socket de domaine Berkeley, ou il peut appeler la même API que le flux d'espace utilisateur I/O.

Aper?u des flux

En général, les descripteurs de fichiers directs sont moins co?teux que d'appeler le processeur et la mémoire de la couche wrapper de flux ; cependant, cela vous impose tout le travail d'implémentation d'un protocole spécifique en tant que développeur d'extension. En vous connectant à la couche wrapper de flux, votre code d'extension peut utiliser de manière transparente les différents wrappers de flux intégrés, tels que HTTP, FTP et leurs. Homologues SSL, ainsi que les wrappers de compression gzip et bzip2 En incluant des modules PEAR ou PECL spécifiques, votre code peut également accéder à d'autres protocoles, tels que SSH2, WebDav et même Gopher?! Ce chapitre présentera l'API de base qui fonctionne en interne sur la base des flux. Plus loin dans le chapitre 16 "Flux intéressants", nous verrons des choses comme l'application de filtres, l'utilisation d'options et de paramètres contextuels, etc. Concepts avancés.

Ouvrir un flux

Bien qu'il s'agisse d'une API unifiée, cela dépend en fait des types de flux requis, il existe quatre chemins différents pour ouvrir un flux. Du point de vue de l'espace utilisateur, ces quatre catégories différentes sont les suivantes (la liste des fonctions ne représente que des exemples, pas une liste complète)?:

Peu importe le type de flux que vous ouvrez , ils sont tous stockés dans une structure commune php_stream.

<?php
    /* fopen包裝
     * 操作文件/URI方式指定遠(yuǎn)程文件類資源 */
    $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);
?>

wopen wrapper

Nous commen?ons d'abord par implémenter le fopen (). Vous devriez maintenant être familier avec la création de squelettes d'extension. Sinon, veuillez revenir au chapitre 5 ??Votre première extension?????Pour revoir, voici la fonction fopen() que nous avons implémentée?:

Le but de php_stream_open_wrapper() devrait être de contourner complètement la couche inférieure. path spécifie le nom du fichier ou l'URL à lire et à écrire, le comportement de lecture et d'écriture dépend de la valeur du mode .

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);
}

options est une collection de valeurs de balise dans le champ de bits, ici elle est définie sur un ensemble de valeurs fixes présentées ci-dessous?:

USE_PATHAppliquez le include_path dans le fichier php.ini au chemin relatif

Fonction intégrée fopen() Cette option sera. défini lors de la spécification du troisième paramètre comme TRUE

.

STREAM_USE_URLAprès avoir défini cette option , seules les URL distantes seront ouvertes pour

php://, file://, zlib://, bzip2 ://Ces wrappers d'URL le font. ne pas

les considérer comme des URL distantes.

ENFORCE_SAFE_MODE Bien que cette constante soit nommée de cette fa?on, il définit réellement cette option

est juste une vérification obligatoire pour activer le mode sans échec (la directive

safe_mode dans le fichier php.ini) . Si vous ne définissez pas cette option

, la vérification du mode sécurisé sera ignorée (quel que soit le paramètre INI

. Comment définir le mode sécurisé dans )

REPORT_ERRORSLorsqu'une erreur est rencontrée lors de l'ouverture de la ressource spécifiée, si vous définissez

Si cette option est utilisée, un rapport d'erreur sera généré.

STREAM_MUST_SEEKPour certains flux , comme les sockets, ce n'est pas une recherche possible (accès aléatoire

Ce type de descripteur de fichier ne peut être utilisé que dans des circonstances spécifiques

seek Si la portée appelante spécifie cette option et que le wrapper

détecte qu'il ne peut pas garantir cela. il peut chercher, il refusera d'ouvrir les

streams.

STREAM_WILL_CASTLe Le flux peut être converti en stdio si la portée appelante l'exige ou

descripteur de fichier posix, vous devez transmettre cette option à la fonction open_wrapper

, pour garantir l'échec avant que l'opération d'E/S ne se produise

STREAM_ONLY_GET_HEADERS identifie uniquement les métadonnées qui doivent être demandé à partir du flux. En fait, ceci est utilisé pour

le wrapper http, obtient la variable globale http_response_headers

<. ??> sans réellement récupérer le contenu du fichier distant.

STREAM_DISABLE_OPEN_BASEDIR

est similaire à la vérification safe_mode Si cette option n'est pas définie, elle vérifiera <. ??>

INI définit open_basedir Si vous spécifiez cette option, vous pouvez

contourner cette valeur par défaut. checkSTREAM_OPEN_PERSISTENT

Informe la couche wrapper de flux que tout l'espace alloué en interne est alloué de manière persistante et que les ressources associées sont enregistrées dans la liste de persistance.IGNORE_PATH

S'il n'est pas spécifié, le chemin d'inclusion par défaut est recherché. La plupart des URL

wrapper Tous les navigateurs l'ignorent. option.

IGNORE_URL提供這個(gè)選項(xiàng)時(shí), 流包裝層只打開本地文件. 所

有的is_url包裝器都將被忽略.

最后的NULL參數(shù)是char **類型, 它最初是用來設(shè)置匹配路徑, 如果path指向普通文件URL, 則去掉file://部分, 保留直接的文件路徑用于傳統(tǒng)的文件名操作. 這個(gè)參數(shù)僅僅是以前引擎內(nèi)部處理使用的.

此外, 還有php_stream_open_wrapper()的一個(gè)擴(kuò)展版本:

php_stream *php_stream_open_wrapper_ex(char *path,
            char *mode, int options, char **opened_path,
            php_stream_context *context);

最后一個(gè)參數(shù)context允許附加的控制, 并可以得到包裝器內(nèi)的通知. 你將在第16章看到這個(gè)參數(shù)的細(xì)節(jié).

傳輸層包裝

盡管傳輸流和fopen包裝流是相同的組件組成的, 但它的注冊(cè)策略和其他的流不同. 從某種程度上來說, 這是因?yàn)橛脩艨臻g對(duì)它們的訪問方式的不同造成的, 它們需要實(shí)現(xiàn)基于套接字的其他因子.

從擴(kuò)展開發(fā)者角度來看, 打開傳輸流的過程是相同的. 下面是對(duì)fsockopen()的實(shí)現(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&#39;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);
}

這個(gè)函數(shù)的基礎(chǔ)構(gòu)造和前面的fopen示例是一樣的. 不同在于host和端口號(hào)使用不同的參數(shù)指定, 接著為了給出一個(gè)傳輸流URL就必須將它們合并到一起. 在產(chǎn)生了一個(gè)有意義的"路徑:后, 將它傳遞給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);

每個(gè)參數(shù)的含義如下:

xport基于URI的傳輸描述符. 對(duì)于基于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的長(zhǎng)

度, 因此xport是二進(jìn)制安全的.

options這個(gè)值是由前面php_stream_open_wrapper()中介紹的選項(xiàng)通過按位

或組成的值.

flags由STREAM_XPORT_CLIENT或STREAM_XPORT_SERVER之一

與下面另外一張表中將列出的STREAM_XPORT_*常量通過按位或

組合得到的值.

persistent_idSi le flux de transport demandé doit être conservé entre les requêtes, la portée appelante peut fournir une

clé Nom décrivant la connexion. Spécifier cette valeur comme NULL crée une connexion non persistante?; la spécification d'une valeur de cha?ne unique tentera d'abord de rechercher dans le pool de persistance s'il existe un flux de transport existant ou s'il n'y a pas de

.

, créez un nouveau flux de persistance une fois trouvé

délai d'expiration Combien de temps faut-il tenter une connexion avant d'échouer avec un. timeout. Passer cette valeur comme NULL oblige

à utiliser la valeur par défaut spécifiée dans php.ini Timeout. Ce paramètre n'a aucune signification pour les flux de transport c?té serveur.

errstrEn cas de création, de connexion, de liaison ou d'écoute sur le socket sélectionné Une erreur se produit, la valeur de référence char * passée ici

sera défini sur une cha?ne décrivant la raison de l'erreur. errstr initialement

devrait initialement pointer vers NULL?; elle est définie sur une valeur lorsqu'elle est renvoyée, la portée appelante a

Responsable de libérer la mémoire liée à cette cha?ne.

errcodeLe code d'erreur numérique correspondant au message d'erreur renvoyé par errstr.

La famille de constantes STREAM_XPORT_* utilisée dans le paramètre flags de php_stream_xport_create() sont définis comme suit?:

STREAM_XPORT_CLIENT

L'extrémité locale établira une connexion avec la ressource distante via la couche de transport . La balise

est généralement utilisée en conjonction avec STREAM_XPORT_CONNECT ou

STREAM_XPORT_CONNECT_ASYNC

Utilisez .STREAM_XPORT_SERVER

Le c?té local acceptera la connexion via la couche de transport. Cette balise est généralement

est utilisé avec STREAM_XPORT_BIND et

STREAM_XPORT_LISTEN.

STREAM_XPORT_CONNECT

est utilisé pour illustrer que l'établissement d'une connexion à une ressource distante fait partie de la création du flux de transport. Il est légal d'omettre cette balise

, mais cela nécessite d'appeler manuellement

php_stream_xport_connect().

STREAM_XPORT_CONNECT_ASYNC嘗試連接到遠(yuǎn)程資源, 但不阻塞.

STREAM_XPORT_BIND將傳輸流綁定到本地資源. 用在服務(wù)端傳輸流時(shí),

這將使得accept連接的傳輸流準(zhǔn)備端口, 路徑或

特定的端點(diǎn)標(biāo)識(shí)符等信息.

STREAM_XPORT_LISTEN在已綁定的傳輸流端點(diǎn)上監(jiān)聽到來的連接. 這通

常用于基于流的傳輸協(xié)議, 比如: tcp://, ssl://,

unix://.

目錄訪問

fopen包裝器支持目錄訪問, 比如file://和ftp://, 還有第三種流打開函數(shù)也可以用于目錄訪問, 下面是對(duì)opendir()的實(shí)現(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);
}

同樣的, 也可以為某個(gè)特定目錄打開一個(gè)流, 比如本地文件系統(tǒng)的目錄名或支持目錄訪問的URL格式資源. 這里我們又看到了options參數(shù), 它和原來的含義一樣, 第三個(gè)參數(shù)NULL原型是php_stream_context類型.

在目錄流打開后, 和文件以及傳輸流一樣, 返回給用戶空間.

特殊流

還有一些特殊類型的流不能歸類到fopen/transport/directory中. 它們中每一個(gè)都有自己獨(dú)有的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)建一個(gè)可seek的緩沖區(qū)流用于讀寫. 在關(guān)閉時(shí), 這個(gè)流使用的所有臨時(shí)資源, 包括所有的緩沖區(qū)(無論是在內(nèi)存還是磁盤), 都將被釋放. 使用這一組API中的后一個(gè)函數(shù), 允許臨時(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個(gè)API方法接受已經(jīng)打開的FILE *資源或文件描述符ID, 使用流API的某種操作包裝. fd格式的接口不會(huì)搜索匹配你前面看到過的fopen函數(shù)打開的資源, 但是它會(huì)注冊(cè)持久化的資源, 后續(xù)的fopen可以使用到這個(gè)持久化資源.

訪問流

在你打開一個(gè)流之后, 就可以在它上面執(zhí)行I/O操作了. 使用那種協(xié)議包裝API創(chuàng)建了流并不重要, 它們都使用相同的訪問API.

流的讀寫可以使用下面的API函數(shù)組合完成, 它們多數(shù)都是遵循POSIX I/O中對(duì)應(yīng)的API規(guī)范的:

int php_stream_getc(php_stream *stream);

從數(shù)據(jù)流中接收一個(gè)字符. 如果流上再?zèng)]有數(shù)據(jù), 則返回EOF.

size_t php_stream_read(php_stream *stream, char *buf, size_t count);

從指定流中讀取指定字節(jié)的數(shù)據(jù). buf必須預(yù)分配至少count字節(jié)的內(nèi)存空間. 這個(gè)函數(shù)將返回從數(shù)據(jù)流實(shí)際讀到緩沖區(qū)中的數(shù)據(jù)字節(jié)數(shù).

php_stream_read()不同于其他的流讀取函數(shù). 如果使用的流不是普通文件流, 哪怕數(shù)據(jù)流中有超過請(qǐng)求字節(jié)數(shù)的數(shù)據(jù), 并且當(dāng)前也可以返回, 它也只會(huì)調(diào)用過一次底層流實(shí)現(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);

這兩個(gè)函數(shù)從stream中讀取最多maxlen個(gè)字符, 直到碰到換行符或流結(jié)束. buf可以是一個(gè)指向預(yù)分配的至少maxlen字節(jié)的內(nèi)存空間的指針, 也可以是NULL, 當(dāng)它是NULL時(shí), 則會(huì)自動(dòng)的創(chuàng)建一個(gè)動(dòng)態(tài)大小的緩沖區(qū), 用從流中實(shí)際讀出的數(shù)據(jù)填充, 成功后函數(shù)返回指向緩沖區(qū)的指針, 失敗則返回NULL. 如果returned_len傳遞了非NULL值, 則在返回時(shí)它將被設(shè)置為實(shí)際從流中讀取的字節(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()類似, 這個(gè)函數(shù)將讀取最多maxlen, 或到達(dá)EOF/行結(jié)束第一次出現(xiàn)的位置. 但是它也有和php_stream_get_line()的不同指出, 這個(gè)函數(shù)允許指定任意的停止讀取標(biāo)記.

讀取目錄項(xiàng)

從php流中讀取目錄項(xiàng)和上面從普通文件中讀取普通數(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;

實(shí)際上你可以直接使用php_stream_read()函數(shù)讀取數(shù)據(jù)到這個(gè)結(jié)構(gòu)體中:

{
   struct dirent entry;
   if (php_stream_read(stream, (char*)&entry, sizeof(entry))
                               == sizeof(entry)) {
       /* 成功從目錄流中讀取到一項(xiàng) */
       php_printf("File: %s\n", entry.d_name);
   }
}

由于從目錄流中讀取是很常見的操作, php流包裝層暴露了一個(gè)API, 它將記錄大小的檢查和類型轉(zhuǎn)換處理封裝到了一次調(diào)用中:

php_stream_dirent *php_stream_readdir(php_stream *dirstream,
                            php_stream_dirent *entry);

如果成功讀取到目錄項(xiàng), 則傳入的entry指針將被返回, 否則返回NULL標(biāo)識(shí)錯(cuò)誤. 使用這個(gè)為目錄流特殊構(gòu)建的函數(shù)而不是直接從目錄流讀取非常重要, 這樣做未來流API改變時(shí)就不至于和你的代碼沖突.

和讀類似, 向流中寫數(shù)據(jù)只需要傳遞一個(gè)緩沖區(qū)和緩沖區(qū)長(zhǎng)度給流.

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的版本實(shí)際上是一個(gè)提供便利的宏, 它允許寫一個(gè)NULL終止的字符串,而不用顯式的提供長(zhǎng)度. 返回的是實(shí)際寫到流中的字節(jié)數(shù). 要特別小心的是嘗試寫大數(shù)據(jù)的時(shí)候可能導(dǎo)致流阻塞, 比如套接字流, 而如果流被標(biāo)記為非阻塞, 則實(shí)際寫入的數(shù)據(jù)量可能會(huì)小于傳遞給函數(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()寫入一個(gè)字符或一個(gè)字符串到流中. 要注意, php_stream_puts()不同于php_stream_write_string(), 雖然它們的原型看起來是一樣的, 但是php_stream_puts()會(huì)在寫出buf中的數(shù)據(jù)后自動(dòng)的追加一個(gè)換行符.

size_t php_stream_printf(php_stream *stream TSRMLS_DC,
                                        const char *format, ...);

功能和格式上都類似于fprintf(), 這個(gè)API調(diào)用允許在寫的同時(shí)構(gòu)造字符串而不用去創(chuàng)建臨時(shí)緩沖區(qū)構(gòu)造數(shù)據(jù). 這里我們能夠看到的一個(gè)明顯的不同是它需要TSRMLS_CC宏來保證線程安全.

隨機(jī)訪問, 查看文件偏移量以及緩存的flush

基于文件的流, 以及另外幾種流是可以隨機(jī)訪問的. 也就是說, 在流的一個(gè)位置讀取了一些數(shù)據(jù)之后, 文件指針可以向前或向后移動(dòng), 以非線性順序讀取其他部分.

如果你的流應(yīng)用代碼預(yù)測(cè)到底層的流支持隨機(jī)訪問, 在打開的時(shí)候就應(yīng)該傳遞STREAM_MUST_SEEK選項(xiàng). 對(duì)于那些原本就可隨機(jī)訪問的流來說, 這通常不會(huì)有什么影響, 因?yàn)榱鞅旧砭褪强呻S機(jī)訪問的. 而對(duì)于那些原本不可隨機(jī)訪問的流, 比如網(wǎng)絡(luò)I/O或線性訪問文件比如FIFO管道, 這個(gè)暗示可以讓調(diào)用程序有機(jī)會(huì)在流的數(shù)據(jù)被消耗掉之前, 優(yōu)雅的失敗.

在可隨機(jī)訪問的流資源上工作時(shí), 下面的函數(shù)可用來將文件指針移動(dòng)到任意位置:

int php_stream_seek(php_stream *stream, off_t offset, int whence);
int php_stream_rewind(php_stream *stream);

offset是相對(duì)于whence表示的流位置的偏移字節(jié)數(shù), whence的可選值及含義如下:

SEEK_SEToffset相對(duì)于文件開始位置. php_stream_rewind()API調(diào)用實(shí)際上是一個(gè)宏,

展開后是php_stream_seek(stream, 0, SEEK_SET), 表示移動(dòng)到文件開始

位置偏移0字節(jié)處. 當(dāng)使用SEEK_SET時(shí), 如果offset傳遞負(fù)值被認(rèn)為是錯(cuò)誤

的, 將會(huì)導(dǎo)致未定義行為. 指定的位置超過流的末尾也是未定義的, 不過結(jié)果

通常是一個(gè)錯(cuò)誤或文件被擴(kuò)大以滿足指定的偏移量.

SEEK_CURoffset相對(duì)于文件的當(dāng)前偏移量. 調(diào)用php_stream_seek(steram, offset,

SEEK_CUR)一般來說等價(jià)于php_stream_seek(stream, php_stream_tell()

+ offset, SEEK_SET);

SEEK_ENDoffset是相對(duì)于當(dāng)前的EOF位置的. 負(fù)值的offset表示在EOF之前的位置, 正

值和SEEK_SET中描述的是相同的語(yǔ)義, 可能在某些流實(shí)現(xiàn)上可以工作.

int php_stream_rewinddir(php_stream *dirstream);

在目錄流上隨機(jī)訪問時(shí), 只有php_stream_rewinddir()函數(shù)可用. 使用php_stream_seek()函數(shù)將導(dǎo)致未定義行為. 所有的隨機(jī)訪問一族函數(shù)返回0標(biāo)識(shí)成功或者-1標(biāo)識(shí)失敗.

off_t php_stream_tell(php_stream *stream);

如你之前所見, php_stream_tell()將返回當(dāng)前的文件偏移量.

int php_stream_flush(php_stream *stream);

調(diào)用flush()函數(shù)將強(qiáng)制將流過濾器此類內(nèi)部緩沖區(qū)中的數(shù)據(jù)輸出到最終的資源中. 在流被關(guān)閉時(shí), flush()函數(shù)將自動(dòng)調(diào)用, 并且大多數(shù)無過濾流資源雖然不進(jìn)行任何內(nèi)部緩沖, 但也需要flush. 顯式的調(diào)用這個(gè)函數(shù)很少見, 并且通常也是不需要的.

int php_stream_stat(php_stream *stream, php_stream_statbuf *ssb);

調(diào)用php_stream_stat()可以獲取到流實(shí)例的其他信息, 它的行為類似于fstat()函數(shù). 實(shí)際上, php_stream_statbuf結(jié)構(gòu)體現(xiàn)在僅包含一個(gè)元素: 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);
}

關(guān)閉

所有流的關(guān)閉都是通過php_stream_free()函數(shù)處理的, 它的原型如下:

int php_stream_free(php_stream *stream, int options);

這個(gè)函數(shù)中的options參數(shù)允許的值是PHP_STREAM_FREE_xxx一族常量的按位或的結(jié)果, 這一族常量定義如下(下面省略PHP_STREAM_FREE_前綴):

CALL_DTOR流實(shí)現(xiàn)的析構(gòu)器應(yīng)該被調(diào)用. 這里提供了一個(gè)時(shí)機(jī)對(duì)特定的流

進(jìn)行顯式釋放.

RELEASE_STREAM釋放為php_stream結(jié)構(gòu)體分配的內(nèi)存

PRESERVE_HANDLE指示流的析構(gòu)器不要關(guān)閉它的底層描述符句柄

RSRC_DTOR流包裝層內(nèi)部管理資源列表的垃圾回收

PERSISTENT作用在持久化流上時(shí), 它的行為將是永久的而不局限于當(dāng)前請(qǐng)

求.

CLOSECALL_DTOR和RELEASE_STREAM的聯(lián)合. 這是關(guān)閉

非持久化流的一般選項(xiàng).

CLOSE_CASTEDCLOSE和PRESERVE_HANDLE的聯(lián)合.

CLOSE_PERSISTENTCLOSE和PERSISTENT的聯(lián)合. 這是永久關(guān)閉持久化流的一

般選項(xiàng).

實(shí)際上, 你并不需要直接調(diào)用php_stream_free()函數(shù). 而是在關(guān)閉流時(shí)使用下面兩個(gè)宏的某個(gè)替代:

#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交換流

因?yàn)榱魍ǔS成涞絲val上, 反之亦然, 因此提供了一組宏用來簡(jiǎn)化操作, 并統(tǒng)一編碼(格式):

#define php_stream_to_zval(stream, pzval) \
    ZVAL_RESOURCE((pzval), (stream)->rsrc_id);

要注意, 這里并沒有調(diào)用ZEND_REGISTER_RESOURCE(). 這是因?yàn)楫?dāng)流打開的時(shí)候, 已經(jīng)自動(dòng)的注冊(cè)為資源了, 這樣就可以利用到引擎內(nèi)建的垃圾回收和shutdown系統(tǒng)的優(yōu)點(diǎn). 使用這個(gè)宏而不是嘗試手動(dòng)的將流注冊(cè)為新的資源ID是非常重要的; 這樣做的最終結(jié)果是導(dǎo)致流被關(guān)閉兩次以及引擎崩潰.

#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 *有一個(gè)類似的宏. 可以看出, 這個(gè)宏只是對(duì)資源獲取函數(shù)(第9章"資源數(shù)據(jù)類型")的一個(gè)簡(jiǎn)單封裝. 請(qǐng)回顧ZEND_FETCH_RESOURCE2()宏, 第一個(gè)宏php_stream_from_zval()就是對(duì)它的包裝, 如果資源類型不匹配, 它將拋出一個(gè)警告并嘗試從函數(shù)實(shí)現(xiàn)中返回. 如果你只是想從傳入的zval *中獲取一個(gè)php_stream *, 而不希望有自動(dòng)的錯(cuò)誤處理, 就需要使用php_stream_from_zval_no_verify()并且需要手動(dòng)的檢查結(jié)果值.

靜態(tài)資源操作

一個(gè)基于流的原子操作并不需要實(shí)際的實(shí)例. 下面這些API僅僅使用URL執(zhí)行這樣的操作:

int php_stream_stat_path(char *path, php_stream_statbuf *ssb);

和前面的php_stream_stat()類似, 這個(gè)函數(shù)提供了一個(gè)對(duì)POSIX的stat()函數(shù)協(xié)議依賴的包裝. 要注意, 并不是所有的協(xié)議都支持URL記法, 并且即便支持也可能不能報(bào)告出statbuf結(jié)構(gòu)體中的所有成員值. 一定要檢查php_stream_stat_path()失敗時(shí)的返回值, 0標(biāo)識(shí)成功, 要知道, 不支持的元素返回時(shí)其值將是默認(rèn)的0.

int php_stream_stat_path_ex(char *path, int flags,
        php_stream_statbuf *ssb, php_stream_context *context);

這個(gè)php_stream_url_stat()的擴(kuò)展版本允許傳遞另外兩個(gè)參數(shù). 第一個(gè)是flags, 它的值可以是下面的PHP_STERAM_URL_STAT_*(下面省略PHP_STREAM_URL_STAT_前綴)一族常量的按位或的結(jié)果. 還有一個(gè)是context參數(shù), 它在其他的一些流函數(shù)中也有出現(xiàn), 我們將在第16章去詳細(xì)學(xué)習(xí).

LINK原始的php_stream_stat_path()對(duì)于符號(hào)鏈接或目錄將會(huì)進(jìn)行解析直到碰到

協(xié)議定義的結(jié)束資源. 傳遞PHP_STREAM_URL_STAT_LINK標(biāo)記將導(dǎo)致

php_stream_stat_path()返回請(qǐng)求資源的信息而不會(huì)進(jìn)行符號(hào)鏈接的解析.

(譯注: 我們可以這樣理解, 沒有這個(gè)標(biāo)記, 底層使用stat(), 如果有這個(gè)標(biāo)記,

底層使用lstat(), 關(guān)于stat()和lstat()的區(qū)別, 請(qǐng)查看*nix手冊(cè))

QUIET默認(rèn)情況下, 如果在執(zhí)行URL的stat操作過程中碰到錯(cuò)誤, 包括文件未找到錯(cuò)

誤, 都將通過php的錯(cuò)誤處理機(jī)制觸發(fā). 傳遞QUIET標(biāo)記可以使得

php_stream_stat_path()返回而不報(bào)告錯(cuò)誤.

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)建和刪除目錄也會(huì)如你期望的工作. 這里的options參數(shù)和前面的php_stream_open_wrapper()函數(shù)的同名參數(shù)含義一致. 對(duì)于php_stream_mkdir(), 還有一個(gè)參數(shù)mode用于指定一個(gè)八進(jìn)制的值表明讀寫執(zhí)行權(quán)限.

小結(jié)

本章中你接觸了一些基于流的I/O的內(nèi)部表象. 下一章將演示做呢樣實(shí)現(xiàn)自己的協(xié)議包裝, 甚至是定義自己的流類型.

以上就是[翻譯][php擴(kuò)展開發(fā)和嵌入式]第14章-php中流的訪問的內(nèi)容,更多相關(guān)內(nèi)容請(qǐng)關(guān)注PHP中文網(wǎng)(miracleart.cn)!


Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefa?on, veuillez contacter admin@php.cn

Outils d'IA chauds

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

échangez les visages dans n'importe quelle vidéo sans effort grace à notre outil d'échange de visage AI entièrement gratuit?!

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment rester à jour avec les derniers développements PHP et meilleures pratiques? Comment rester à jour avec les derniers développements PHP et meilleures pratiques? Jun 23, 2025 am 12:56 AM

TostayCurrentwithPhpDevelopments andBestPractices, suiventyewnewsources likephp.netandphpweekly, engagewithcommunitiesonforumums et conférences, keeptoolingupdated etgradualadoptnewfeatures, etreadorontruttetoopensourceprojects.

Qu'est-ce que PHP et pourquoi est-il utilisé pour le développement Web? Qu'est-ce que PHP et pourquoi est-il utilisé pour le développement Web? Jun 23, 2025 am 12:55 AM

PhpBecamepopularforwebDevelopmentDuetoitSeaseOflearning, Samoussentegration withhtml, widespreadhostingsupport, andalargecosystemysteclustingframeworkslikeLaravelandcmsplateformeslikewordpress.itexcelSinlingFormSubMissions, ManagetingSeSeSessions, interactif, interactif

Comment définir le fuseau horaire PHP? Comment définir le fuseau horaire PHP? Jun 25, 2025 am 01:00 AM

Tosetherighttimezoneinphp, usedate_default_timezone_set () Fonctionnellestartofyourscriptwithavalididentifiersuchas'america / new_york'.1.usedate_default_timezone_set () beforeanydate / timefunctions.20

Comment valider la saisie des utilisateurs dans PHP pour m'assurer qu'il répond à certains critères? Comment valider la saisie des utilisateurs dans PHP pour m'assurer qu'il répond à certains critères? Jun 22, 2025 am 01:00 AM

TovalidateUserInputinPhp, usebuilt-invalidationfunctions likeFilter_var () etFilter_Input (), appliquerareArexpressionsforcustomFormatsSuchasUserNameSorphonEnombers

Qu'est-ce que la sérialisation des données dans PHP (Serialize (), Unserialize ())? Qu'est-ce que la sérialisation des données dans PHP (Serialize (), Unserialize ())? Jun 22, 2025 am 01:03 AM

ThePhpFunctionSerialize () andUnserialize () sont utilisés pour le stobercomplexdatasterDestoRoSintOsTorasandAbackAgain.1.Serialize () C onvertsDatalikECarraysorObjectSraystringContainingTypeandStructureInformation.2

Comment intégrer le code PHP dans un fichier HTML? Comment intégrer le code PHP dans un fichier HTML? Jun 22, 2025 am 01:00 AM

Vous pouvez intégrer le code PHP dans des fichiers HTML, mais assurez-vous que le fichier a une extension de .php afin que le serveur puisse l'analyser correctement. Utilisez des balises standard pour envelopper le code PHP, insérez le contenu dynamique n'importe où dans HTML. De plus, vous pouvez changer plusieurs fois PHP et HTML dans le même fichier pour réaliser des fonctions dynamiques telles que le rendu conditionnel. Assurez-vous de prêter attention à la configuration du serveur et à l'exactitude de la syntaxe pour éviter les problèmes causés par de courtes étiquettes, des erreurs de devis ou des étiquettes de fin omises.

Quelles sont les meilleures pratiques pour écrire du code PHP propre et maintenable? Quelles sont les meilleures pratiques pour écrire du code PHP propre et maintenable? Jun 24, 2025 am 12:53 AM

La clé pour écrire le code PHP propre et facile à maintenir réside dans une dénomination claire, des normes suivantes, une structure raisonnable, une bonne utilisation des commentaires et une testabilité. 1. Utilisez des variables claires, des fonctions et des noms de classe, tels que $ userdata et calculatotalprice (); 2. Suivez le style de code unifié standard PSR-12; 3. Divisez la structure du code en fonction des responsabilités et organisez-la à l'aide de catalogues MVC ou de style Laravel; 4. évitez le code de style nouilles et divisez la logique en petites fonctions avec une seule responsabilité; 5. Ajouter des commentaires aux points clés et écrire des documents d'interface pour clarifier les paramètres, les valeurs de retour et les exceptions; 6. Améliorer la testabilité, adopter l'injection de dépendance, réduire l'état mondial et les méthodes statiques. Ces pratiques améliorent la qualité du code, l'efficacité de la collaboration et la facilité de post-maintenance.

Comment exécuter des requêtes SQL à l'aide de PHP? Comment exécuter des requêtes SQL à l'aide de PHP? Jun 24, 2025 am 12:54 AM

Oui, YouCanrunsqlQueriesUsingPhp, et theprocessInvolvesChoosingAdatabaseextenten, ConnectTotheDatabase, ExecutingQueessaFely, andcosingConnectionSwhendOne.Todothis, FirstChooseBetweenmysqliorpDo, avec unplaying

See all articles