mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Implement user-space streams.
There's probably room for improvement, docs will following some time this week.
This commit is contained in:
parent
9e14ed0255
commit
06712a508a
10 changed files with 507 additions and 11 deletions
|
@ -624,6 +624,7 @@ function_entry basic_functions[] = {
|
|||
PHP_FE(socket_set_blocking, NULL)
|
||||
|
||||
PHP_FE(fgetwrapperdata, NULL)
|
||||
PHP_FE(file_register_wrapper, NULL)
|
||||
|
||||
#if HAVE_SYS_TIME_H
|
||||
PHP_FE(socket_set_timeout, NULL)
|
||||
|
|
|
@ -71,6 +71,7 @@ PHP_NAMED_FUNCTION(php_if_ftruncate);
|
|||
PHP_NAMED_FUNCTION(php_if_fstat);
|
||||
|
||||
PHP_FUNCTION(fgetwrapperdata);
|
||||
PHP_FUNCTION(file_register_wrapper);
|
||||
|
||||
PHPAPI int php_set_sock_blocking(int socketd, int block);
|
||||
PHPAPI int php_file_le_stream(void);
|
||||
|
|
|
@ -79,13 +79,14 @@ static int php_get_ftp_result(php_stream *stream TSRMLS_DC)
|
|||
|
||||
php_stream_wrapper php_stream_ftp_wrapper = {
|
||||
php_stream_url_wrap_ftp,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/* {{{ php_fopen_url_wrap_ftp
|
||||
*/
|
||||
php_stream * php_stream_url_wrap_ftp(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
|
||||
php_stream * php_stream_url_wrap_ftp(char *path, char *mode, int options, char **opened_path, void *wrappercontext STREAMS_DC TSRMLS_DC)
|
||||
{
|
||||
php_stream *stream=NULL;
|
||||
php_url *resource=NULL;
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
#define HTTP_HEADER_BLOCK_SIZE 1024
|
||||
|
||||
|
||||
php_stream *php_stream_url_wrap_http(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
|
||||
php_stream *php_stream_url_wrap_http(char *path, char *mode, int options, char **opened_path, void *wrappercontext STREAMS_DC TSRMLS_DC)
|
||||
{
|
||||
php_stream *stream = NULL;
|
||||
php_url *resource = NULL;
|
||||
|
@ -268,7 +268,7 @@ php_stream *php_stream_url_wrap_http(char *path, char *mode, int options, char *
|
|||
else {
|
||||
strlcpy(new_path, location, sizeof(new_path));
|
||||
}
|
||||
stream = php_stream_url_wrap_http(new_path, mode, options, opened_path STREAMS_CC TSRMLS_CC);
|
||||
stream = php_stream_url_wrap_http(new_path, mode, options, opened_path, NULL STREAMS_CC TSRMLS_CC);
|
||||
if (stream->wrapperdata) {
|
||||
entryp = &entry;
|
||||
MAKE_STD_ZVAL(entry);
|
||||
|
@ -311,6 +311,7 @@ out:
|
|||
|
||||
php_stream_wrapper php_stream_http_wrapper = {
|
||||
php_stream_url_wrap_http,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "php_standard.h"
|
||||
#include "php_fopen_wrappers.h"
|
||||
|
||||
php_stream * php_stream_url_wrap_php(char * path, char * mode, int options, char ** opened_path STREAMS_DC TSRMLS_DC)
|
||||
php_stream * php_stream_url_wrap_php(char * path, char * mode, int options, char ** opened_path, void *wrappercontext STREAMS_DC TSRMLS_DC)
|
||||
{
|
||||
FILE * fp = NULL;
|
||||
php_stream * stream = NULL;
|
||||
|
@ -54,6 +54,7 @@ php_stream * php_stream_url_wrap_php(char * path, char * mode, int options, char
|
|||
|
||||
php_stream_wrapper php_stream_php_wrapper = {
|
||||
php_stream_url_wrap_php,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#ifndef PHP_FOPEN_WRAPPERS_H
|
||||
#define PHP_FOPEN_WRAPPERS_H
|
||||
|
||||
php_stream *php_stream_url_wrap_http(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC);
|
||||
php_stream *php_stream_url_wrap_ftp(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC);
|
||||
php_stream *php_stream_url_wrap_http(char *path, char *mode, int options, char **opened_path, void *wrappercontext STREAMS_DC TSRMLS_DC);
|
||||
php_stream *php_stream_url_wrap_ftp(char *path, char *mode, int options, char **opened_path, void *wrappercontext STREAMS_DC TSRMLS_DC);
|
||||
php_stream_wrapper php_stream_http_wrapper;
|
||||
php_stream_wrapper php_stream_ftp_wrapper;
|
||||
php_stream_wrapper php_stream_php_wrapper;
|
||||
|
|
|
@ -237,9 +237,7 @@ PHP_MINFO_FUNCTION(zlib)
|
|||
{
|
||||
php_info_print_table_start();
|
||||
php_info_print_table_row(2, "ZLib Support", "enabled");
|
||||
#if HAVE_FOPENCOOKIE
|
||||
php_info_print_table_row(2, "'zlib:' fopen wrapper", "enabled");
|
||||
#endif
|
||||
php_info_print_table_row(2, "Compiled Version", ZLIB_VERSION );
|
||||
php_info_print_table_row(2, "Linked Version", (char *)zlibVersion() );
|
||||
php_info_print_table_end();
|
||||
|
|
|
@ -101,12 +101,13 @@ typedef struct _php_stream_ops {
|
|||
} php_stream_ops;
|
||||
|
||||
/* options uses the IGNORE_URL family of defines from fopen_wrappers.h */
|
||||
typedef php_stream *(*php_stream_factory_func_t)(char *filename, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC);
|
||||
typedef php_stream *(*php_stream_factory_func_t)(char *filename, char *mode, int options, char **opened_path, void * wrappercontext STREAMS_DC TSRMLS_DC);
|
||||
typedef void (*php_stream_wrapper_dtor_func_t)(php_stream *stream TSRMLS_DC);
|
||||
|
||||
typedef struct _php_stream_wrapper {
|
||||
php_stream_factory_func_t create;
|
||||
php_stream_wrapper_dtor_func_t destroy;
|
||||
void * wrappercontext;
|
||||
} php_stream_wrapper;
|
||||
|
||||
struct _php_stream {
|
||||
|
@ -253,6 +254,7 @@ PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show
|
|||
# define IGNORE_URL_WIN 0
|
||||
#endif
|
||||
|
||||
int php_init_user_streams(TSRMLS_D);
|
||||
int php_init_stream_wrappers(TSRMLS_D);
|
||||
int php_shutdown_stream_wrappers(TSRMLS_D);
|
||||
PHPAPI int php_register_url_stream_wrapper(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC);
|
||||
|
@ -268,6 +270,11 @@ PHPAPI php_stream *_php_stream_open_wrapper(char *path, char *mode, int options,
|
|||
PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstream STREAMS_DC TSRMLS_DC);
|
||||
#define php_stream_make_seekable(origstream, newstream) _php_stream_make_seekable(origstream, newstream STREAMS_CC TSRMLS_CC)
|
||||
|
||||
|
||||
/* for user-space streams */
|
||||
extern php_stream_ops php_stream_userspace_ops;
|
||||
#define PHP_STREAM_IS_USERSPACE &php_stream_userspace_ops
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
@ -891,7 +891,9 @@ exit_success:
|
|||
int php_init_stream_wrappers(TSRMLS_D)
|
||||
{
|
||||
if (PG(allow_url_fopen)) {
|
||||
return zend_hash_init(&url_stream_wrappers_hash, 0, NULL, NULL, 1);
|
||||
if (zend_hash_init(&url_stream_wrappers_hash, 0, NULL, NULL, 1) == SUCCESS)
|
||||
return php_init_user_streams(TSRMLS_C);
|
||||
return FAILURE;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
@ -940,7 +942,7 @@ static php_stream *php_stream_open_url(char *path, char *mode, int options, char
|
|||
protocol = NULL;
|
||||
}
|
||||
if (wrapper) {
|
||||
php_stream *stream = wrapper->create(path, mode, options, opened_path STREAMS_REL_CC TSRMLS_CC);
|
||||
php_stream *stream = wrapper->create(path, mode, options, opened_path, wrapper->wrappercontext STREAMS_REL_CC TSRMLS_CC);
|
||||
if (stream)
|
||||
stream->wrapper = wrapper;
|
||||
return stream;
|
||||
|
|
484
main/user_streams.c
Normal file
484
main/user_streams.c
Normal file
|
@ -0,0 +1,484 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2002 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.02 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available at through the world-wide-web at |
|
||||
| http://www.php.net/license/2_02.txt. |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: |
|
||||
| Wez Furlong (wez@thebrainroom.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "php.h"
|
||||
#include "php_globals.h"
|
||||
|
||||
static int le_protocols;
|
||||
|
||||
struct php_user_stream_wrapper {
|
||||
char * protoname;
|
||||
char * classname;
|
||||
zend_class_entry *ce;
|
||||
php_stream_wrapper wrapper;
|
||||
};
|
||||
|
||||
static php_stream *user_wrapper_factory(char *filename, char *mode, int options, char **opened_path, void * wrappercontext STREAMS_DC TSRMLS_DC);
|
||||
|
||||
static void stream_wrapper_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
|
||||
{
|
||||
struct php_user_stream_wrapper * uwrap = (struct php_user_stream_wrapper*)rsrc->ptr;
|
||||
|
||||
php_unregister_url_stream_wrapper(uwrap->protoname TSRMLS_CC);
|
||||
efree(uwrap->protoname);
|
||||
efree(uwrap->classname);
|
||||
efree(uwrap);
|
||||
}
|
||||
|
||||
int php_init_user_streams(TSRMLS_D)
|
||||
{
|
||||
le_protocols = zend_register_list_destructors_ex(stream_wrapper_dtor, NULL, "stream factory", 0);
|
||||
return le_protocols == FAILURE ? FAILURE : SUCCESS;
|
||||
}
|
||||
|
||||
struct _php_userstream_data {
|
||||
struct php_user_stream_wrapper * wrapper;
|
||||
zval * object;
|
||||
};
|
||||
typedef struct _php_userstream_data php_userstream_data_t;
|
||||
|
||||
/* names of methods */
|
||||
#define USERSTREAM_OPEN "stream_open"
|
||||
#define USERSTREAM_CLOSE "stream_close"
|
||||
#define USERSTREAM_READ "stream_read"
|
||||
#define USERSTREAM_WRITE "stream_write"
|
||||
#define USERSTREAM_FLUSH "stream_flush"
|
||||
#define USERSTREAM_SEEK "stream_seek"
|
||||
#define USERSTREAM_GETS "stream_gets"
|
||||
#define USERSTREAM_TELL "stream_tell"
|
||||
#define USERSTREAM_EOF "stream_eof"
|
||||
|
||||
/* class should have methods like these:
|
||||
|
||||
function stream_open($path, $mode, $options, &$opened_path)
|
||||
{
|
||||
return true/false;
|
||||
}
|
||||
function stream_read($count)
|
||||
{
|
||||
return false on error;
|
||||
else return string;
|
||||
}
|
||||
function stream_write($data)
|
||||
{
|
||||
return false on error;
|
||||
else return count written;
|
||||
}
|
||||
function stream_close()
|
||||
{
|
||||
}
|
||||
function stream_flush()
|
||||
{
|
||||
}
|
||||
function stream_seek($offset, $whence)
|
||||
{
|
||||
}
|
||||
function stream_gets($size)
|
||||
{
|
||||
return false on error;
|
||||
else return string;
|
||||
}
|
||||
|
||||
* */
|
||||
|
||||
static php_stream *user_wrapper_factory(char *filename, char *mode, int options, char **opened_path, void *wrappercontext STREAMS_DC TSRMLS_DC)
|
||||
{
|
||||
struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrappercontext;
|
||||
php_userstream_data_t *us;
|
||||
zval *zfilename, *zmode, *zopened, *zoptions, *zretval = NULL, *zfuncname;
|
||||
zval **args[4];
|
||||
int call_result;
|
||||
php_stream *stream = NULL;
|
||||
|
||||
us = emalloc(sizeof(*us));
|
||||
us->wrapper = uwrap;
|
||||
|
||||
/* create an instance of our class */
|
||||
ALLOC_ZVAL(us->object);
|
||||
object_init_ex(us->object, uwrap->ce);
|
||||
ZVAL_REFCOUNT(us->object) = 1;
|
||||
PZVAL_IS_REF(us->object) = 1;
|
||||
|
||||
/* call it's stream_open method - set up params first */
|
||||
MAKE_STD_ZVAL(zfilename);
|
||||
ZVAL_STRING(zfilename, filename, 1);
|
||||
args[0] = &zfilename;
|
||||
|
||||
MAKE_STD_ZVAL(zmode);
|
||||
ZVAL_STRING(zmode, mode, 1);
|
||||
args[1] = &zmode;
|
||||
|
||||
MAKE_STD_ZVAL(zoptions);
|
||||
ZVAL_LONG(zoptions, options);
|
||||
args[2] = &zoptions;
|
||||
|
||||
MAKE_STD_ZVAL(zopened);
|
||||
ZVAL_REFCOUNT(zopened) = 1;
|
||||
PZVAL_IS_REF(zopened) = 1;
|
||||
ZVAL_NULL(zopened);
|
||||
args[3] = &zopened;
|
||||
|
||||
MAKE_STD_ZVAL(zfuncname);
|
||||
ZVAL_STRING(zfuncname, USERSTREAM_OPEN, 1);
|
||||
|
||||
call_result = call_user_function_ex(NULL,
|
||||
&us->object,
|
||||
zfuncname,
|
||||
&zretval,
|
||||
4, args,
|
||||
0, NULL TSRMLS_CC);
|
||||
|
||||
if (call_result == SUCCESS && zretval != NULL) {
|
||||
/* the stream is now open! */
|
||||
stream = php_stream_alloc_rel(&php_stream_userspace_ops, us, 0, mode);
|
||||
|
||||
/* if the opened path is set, copy it out */
|
||||
if (Z_TYPE_P(zopened) == IS_STRING && opened_path) {
|
||||
*opened_path = estrndup(Z_STRVAL_P(zopened), Z_STRLEN_P(zopened));
|
||||
}
|
||||
} else {
|
||||
/* destroy the object */
|
||||
zval_ptr_dtor(&us->object);
|
||||
efree(us);
|
||||
}
|
||||
|
||||
/* destroy everything else */
|
||||
if (zretval)
|
||||
zval_ptr_dtor(&zretval);
|
||||
|
||||
zval_ptr_dtor(&zfuncname);
|
||||
zval_ptr_dtor(&zopened);
|
||||
zval_ptr_dtor(&zoptions);
|
||||
zval_ptr_dtor(&zmode);
|
||||
zval_ptr_dtor(&zfilename);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/* {{{ proto bool file_register_wrapper(string protocol, string classname)
|
||||
Registers a custom URL protocol handler class */
|
||||
PHP_FUNCTION(file_register_wrapper)
|
||||
{
|
||||
char *protocol, *classname;
|
||||
int protocol_len, classname_len;
|
||||
struct php_user_stream_wrapper * uwrap;
|
||||
int rsrc_id;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &protocol, &protocol_len, &classname, &classname_len) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (!PG(allow_url_fopen)) {
|
||||
zend_error(E_WARNING, "%s(): fopen wrappers have been disabled", get_active_function_name(TSRMLS_C));
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
uwrap = (struct php_user_stream_wrapper *)ecalloc(1, sizeof(*uwrap));
|
||||
uwrap->protoname = estrndup(protocol, protocol_len);
|
||||
uwrap->classname = estrndup(classname, classname_len);
|
||||
uwrap->wrapper.create = user_wrapper_factory;
|
||||
uwrap->wrapper.wrappercontext = uwrap;
|
||||
|
||||
zend_str_tolower(uwrap->classname, classname_len);
|
||||
rsrc_id = ZEND_REGISTER_RESOURCE(NULL, uwrap, le_protocols);
|
||||
|
||||
if (zend_hash_find(EG(class_table), uwrap->classname, classname_len + 1, (void**)&uwrap->ce) == SUCCESS) {
|
||||
#ifdef ZEND_ENGINE_2
|
||||
uwrap->ce = *(zend_class_entry**)uwrap->ce;
|
||||
#endif
|
||||
if (php_register_url_stream_wrapper(protocol, &uwrap->wrapper TSRMLS_CC) == SUCCESS) {
|
||||
RETURN_TRUE;
|
||||
}
|
||||
} else {
|
||||
zend_error(E_WARNING, "%s(): class '%s' is undefined", get_active_function_name(TSRMLS_C),
|
||||
classname);
|
||||
}
|
||||
|
||||
zend_list_delete(rsrc_id);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
static size_t php_userstreamop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
|
||||
{
|
||||
zval func_name;
|
||||
zval *retval = NULL;
|
||||
int call_result;
|
||||
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
|
||||
zval **args[1];
|
||||
zval zbuff, *zbufptr;
|
||||
size_t didwrite = 0;
|
||||
|
||||
assert(us != NULL);
|
||||
|
||||
ZVAL_STRINGL(&func_name, USERSTREAM_WRITE, sizeof(USERSTREAM_WRITE)-1, 0);
|
||||
|
||||
ZVAL_STRINGL(&zbuff, (char*)buf, count, 0);
|
||||
zbufptr = &zbuff;
|
||||
args[0] = &zbufptr;
|
||||
|
||||
call_result = call_user_function_ex(NULL,
|
||||
&us->object,
|
||||
&func_name,
|
||||
&retval,
|
||||
1, args,
|
||||
0, NULL TSRMLS_CC);
|
||||
|
||||
if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_LONG)
|
||||
didwrite = Z_LVAL_P(retval);
|
||||
else
|
||||
didwrite = 0;
|
||||
|
||||
if (retval)
|
||||
zval_ptr_dtor(&retval);
|
||||
|
||||
return didwrite;
|
||||
}
|
||||
|
||||
static size_t php_userstreamop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
|
||||
{
|
||||
zval func_name;
|
||||
zval *retval = NULL;
|
||||
zval **args[1];
|
||||
int call_result;
|
||||
size_t didread = 0;
|
||||
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
|
||||
|
||||
assert(us != NULL);
|
||||
|
||||
if (buf == NULL && count == 0) {
|
||||
ZVAL_STRINGL(&func_name, USERSTREAM_EOF, sizeof(USERSTREAM_EOF)-1, 0);
|
||||
|
||||
call_result = call_user_function_ex(NULL,
|
||||
&us->object,
|
||||
&func_name,
|
||||
&retval,
|
||||
0, NULL, 0, NULL TSRMLS_CC);
|
||||
|
||||
if (call_result == SUCCESS && retval != NULL && zval_is_true(retval))
|
||||
didread = 0;
|
||||
else
|
||||
didread = EOF;
|
||||
|
||||
} else {
|
||||
zval *zcount;
|
||||
|
||||
ZVAL_STRINGL(&func_name, USERSTREAM_READ, sizeof(USERSTREAM_READ)-1, 0);
|
||||
|
||||
MAKE_STD_ZVAL(zcount);
|
||||
ZVAL_LONG(zcount, count);
|
||||
args[0] = &zcount;
|
||||
|
||||
call_result = call_user_function_ex(NULL,
|
||||
&us->object,
|
||||
&func_name,
|
||||
&retval,
|
||||
1, args,
|
||||
0, NULL TSRMLS_CC);
|
||||
|
||||
if (retval && Z_TYPE_P(retval) == IS_STRING) {
|
||||
didread = Z_STRLEN_P(retval);
|
||||
if (didread > count) {
|
||||
zend_error(E_WARNING, "%s::" USERSTREAM_READ " - read more data than requested; some data will be lost",
|
||||
us->wrapper->classname);
|
||||
didread = count;
|
||||
}
|
||||
if (didread > 0)
|
||||
memcpy(buf, Z_STRVAL_P(retval), didread);
|
||||
}
|
||||
|
||||
zval_ptr_dtor(&zcount);
|
||||
}
|
||||
|
||||
if (retval)
|
||||
zval_ptr_dtor(&retval);
|
||||
|
||||
return didread;
|
||||
}
|
||||
|
||||
static int php_userstreamop_close(php_stream *stream, int close_handle TSRMLS_DC)
|
||||
{
|
||||
zval func_name;
|
||||
zval *retval = NULL;
|
||||
int call_result;
|
||||
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
|
||||
|
||||
assert(us != NULL);
|
||||
|
||||
ZVAL_STRINGL(&func_name, USERSTREAM_CLOSE, sizeof(USERSTREAM_CLOSE)-1, 0);
|
||||
|
||||
call_result = call_user_function_ex(NULL,
|
||||
&us->object,
|
||||
&func_name,
|
||||
&retval,
|
||||
0, NULL, 0, NULL TSRMLS_CC);
|
||||
|
||||
if (retval)
|
||||
zval_ptr_dtor(&retval);
|
||||
|
||||
zval_ptr_dtor(&us->object);
|
||||
|
||||
efree(us);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int php_userstreamop_flush(php_stream *stream TSRMLS_DC)
|
||||
{
|
||||
zval func_name;
|
||||
zval *retval = NULL;
|
||||
int call_result;
|
||||
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
|
||||
|
||||
assert(us != NULL);
|
||||
|
||||
ZVAL_STRINGL(&func_name, USERSTREAM_FLUSH, sizeof(USERSTREAM_FLUSH)-1, 0);
|
||||
|
||||
call_result = call_user_function_ex(NULL,
|
||||
&us->object,
|
||||
&func_name,
|
||||
&retval,
|
||||
0, NULL, 0, NULL TSRMLS_CC);
|
||||
|
||||
if (call_result == SUCCESS && retval != NULL && zval_is_true(retval))
|
||||
call_result = 0;
|
||||
else
|
||||
call_result = -1;
|
||||
|
||||
if (retval)
|
||||
zval_ptr_dtor(&retval);
|
||||
|
||||
return call_result;
|
||||
}
|
||||
|
||||
static int php_userstreamop_seek(php_stream *stream, off_t offset, int whence TSRMLS_DC)
|
||||
{
|
||||
zval func_name;
|
||||
zval *retval = NULL;
|
||||
int call_result;
|
||||
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
|
||||
|
||||
assert(us != NULL);
|
||||
|
||||
if (offset == 0 && whence == SEEK_CUR) {
|
||||
ZVAL_STRINGL(&func_name, USERSTREAM_TELL, sizeof(USERSTREAM_TELL)-1, 0);
|
||||
|
||||
call_result = call_user_function_ex(NULL,
|
||||
&us->object,
|
||||
&func_name,
|
||||
&retval,
|
||||
0, NULL, 0, NULL TSRMLS_CC);
|
||||
|
||||
|
||||
} else {
|
||||
zval **args[2];
|
||||
zval *zoffs, *zwhence;
|
||||
|
||||
ZVAL_STRINGL(&func_name, USERSTREAM_SEEK, sizeof(USERSTREAM_SEEK)-1, 0);
|
||||
|
||||
MAKE_STD_ZVAL(zoffs);
|
||||
ZVAL_LONG(zoffs, offset);
|
||||
args[0] = &zoffs;
|
||||
|
||||
MAKE_STD_ZVAL(zwhence);
|
||||
ZVAL_LONG(zwhence, whence);
|
||||
args[1] = &zwhence;
|
||||
|
||||
call_result = call_user_function_ex(NULL,
|
||||
&us->object,
|
||||
&func_name,
|
||||
&retval,
|
||||
2, args,
|
||||
0, NULL TSRMLS_CC);
|
||||
|
||||
zval_ptr_dtor(&zoffs);
|
||||
zval_ptr_dtor(&zwhence);
|
||||
|
||||
}
|
||||
|
||||
if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_LONG)
|
||||
call_result = Z_LVAL_P(retval);
|
||||
else
|
||||
call_result = -1;
|
||||
|
||||
if (retval)
|
||||
zval_ptr_dtor(&retval);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *php_userstreamop_gets(php_stream *stream, char *buf, size_t size TSRMLS_DC)
|
||||
{
|
||||
zval func_name;
|
||||
zval *retval = NULL;
|
||||
zval *zcount;
|
||||
zval **args[2];
|
||||
int call_result;
|
||||
size_t didread = 0;
|
||||
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
|
||||
|
||||
assert(us != NULL);
|
||||
|
||||
/* TODO: when the gets method is not available, fall back on emulated version using read */
|
||||
|
||||
ZVAL_STRINGL(&func_name, USERSTREAM_GETS, sizeof(USERSTREAM_GETS)-1, 0);
|
||||
|
||||
MAKE_STD_ZVAL(zcount);
|
||||
ZVAL_LONG(zcount, size);
|
||||
args[0] = &zcount;
|
||||
|
||||
call_result = call_user_function_ex(NULL,
|
||||
&us->object,
|
||||
&func_name,
|
||||
&retval,
|
||||
1, args,
|
||||
0, NULL TSRMLS_CC);
|
||||
|
||||
if (retval && Z_TYPE_P(retval) == IS_STRING) {
|
||||
didread = Z_STRLEN_P(retval);
|
||||
if (didread > size) {
|
||||
zend_error(E_WARNING, "%s::" USERSTREAM_GETS " - read more data than requested; some data will be lost",
|
||||
us->wrapper->classname);
|
||||
didread = size;
|
||||
}
|
||||
if (didread > 0)
|
||||
memcpy(buf, Z_STRVAL_P(retval), didread);
|
||||
|
||||
zval_ptr_dtor(&retval);
|
||||
}
|
||||
|
||||
if (retval)
|
||||
zval_ptr_dtor(&zcount);
|
||||
|
||||
if (didread)
|
||||
return buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
php_stream_ops php_stream_userspace_ops = {
|
||||
php_userstreamop_write, php_userstreamop_read,
|
||||
php_userstreamop_close, php_userstreamop_flush,
|
||||
php_userstreamop_seek, php_userstreamop_gets,
|
||||
NULL, /* cast */
|
||||
"user-space"
|
||||
};
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue