mirror of
https://github.com/php/php-src.git
synced 2025-08-16 14:08:47 +02:00
Fix for php_stream_gets when the implementation does not support it
natively (Thanks Marcus). Implement php_stream_make_seekable() and add STREAM_MUST_SEEK as an option to php_stream_open_wrapper(). See README.STREAMS for usage.
This commit is contained in:
parent
effa6e8daa
commit
12a0092376
4 changed files with 120 additions and 18 deletions
|
@ -51,7 +51,16 @@ Where:
|
||||||
IGNORE_URL - do not use plugin wrappers
|
IGNORE_URL - do not use plugin wrappers
|
||||||
REPORT_ERRORS - show errors in a standard format if something
|
REPORT_ERRORS - show errors in a standard format if something
|
||||||
goes wrong.
|
goes wrong.
|
||||||
opened_path is used to return the path of the actual file opened.
|
STREAM_MUST_SEEK - If you really need to be able to seek the stream
|
||||||
|
and don't need to be able to write to the original
|
||||||
|
file/URL, use this option to arrange for the stream
|
||||||
|
to be copied (if needed) into a stream that can
|
||||||
|
be seek()ed.
|
||||||
|
|
||||||
|
opened_path is used to return the path of the actual file opened,
|
||||||
|
but if you used STREAM_MUST_SEEK, may not be valid. You are
|
||||||
|
responsible for efree()ing opened_path. opened_path may be (and usually
|
||||||
|
is) NULL.
|
||||||
|
|
||||||
If you need to open a specific stream, or convert standard resources into
|
If you need to open a specific stream, or convert standard resources into
|
||||||
streams there are a range of functions to do this defined in php_streams.h.
|
streams there are a range of functions to do this defined in php_streams.h.
|
||||||
|
@ -109,6 +118,39 @@ The buffer is allocated using pemalloc(); you need to call pefree() to
|
||||||
release the memory when you are done.
|
release the memory when you are done.
|
||||||
As with copy_to_stream, this function will try use mmap where it can.
|
As with copy_to_stream, this function will try use mmap where it can.
|
||||||
|
|
||||||
|
If you have an existing stream and need to be able to seek() it, you
|
||||||
|
can use this function to copy the contents into a new stream that can
|
||||||
|
be seek()ed:
|
||||||
|
|
||||||
|
PHPAPI int php_stream_make_seekable(php_stream *origstream, php_stream **newstream);
|
||||||
|
|
||||||
|
It returns one of the following values:
|
||||||
|
#define PHP_STREAM_UNCHANGED 0 /* orig stream was seekable anyway */
|
||||||
|
#define PHP_STREAM_RELEASED 1 /* newstream should be used; origstream is no longer valid */
|
||||||
|
#define PHP_STREAM_FAILED 2 /* an error occurred while attempting conversion */
|
||||||
|
#define PHP_STREAM_CRITICAL 3 /* an error occurred; origstream is in an unknown state; you should close origstream */
|
||||||
|
|
||||||
|
make_seekable will always set newstream to be the stream that is valid
|
||||||
|
if the function succeeds.
|
||||||
|
When you have finished, remember to close the stream.
|
||||||
|
|
||||||
|
NOTE: If you only need to seek forwards, there is no need to call this
|
||||||
|
function, as the php_stream_seek can emulate forward seeking when the
|
||||||
|
whence parameter is SEEK_CUR.
|
||||||
|
|
||||||
|
NOTE: Writing to the stream may not affect the original source, so it
|
||||||
|
only makes sense to use this for read-only use.
|
||||||
|
|
||||||
|
NOTE: If the origstream is network based, this function will block
|
||||||
|
until the whole contents have been downloaded.
|
||||||
|
|
||||||
|
NOTE: Never call this function with an origstream that is referenced
|
||||||
|
as a resource! It will close the origstream on success, and this
|
||||||
|
can lead to a crash when the resource is later used/released.
|
||||||
|
|
||||||
|
NOTE: If you are opening a stream and need it to be seekable, use the
|
||||||
|
STREAM_MUST_SEEK option to php_stream_open_wrapper();
|
||||||
|
|
||||||
Casting Streams
|
Casting Streams
|
||||||
===============
|
===============
|
||||||
What if your extension needs to access the FILE* of a user level file pointer?
|
What if your extension needs to access the FILE* of a user level file pointer?
|
||||||
|
|
|
@ -22,19 +22,6 @@
|
||||||
|
|
||||||
#include "php_globals.h"
|
#include "php_globals.h"
|
||||||
|
|
||||||
#define IGNORE_PATH 0
|
|
||||||
#define USE_PATH 1
|
|
||||||
#define IGNORE_URL 2
|
|
||||||
/* There's no USE_URL. */
|
|
||||||
#define ENFORCE_SAFE_MODE 4
|
|
||||||
#define REPORT_ERRORS 8
|
|
||||||
|
|
||||||
#ifdef PHP_WIN32
|
|
||||||
# define IGNORE_URL_WIN IGNORE_URL
|
|
||||||
#else
|
|
||||||
# define IGNORE_URL_WIN 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC);
|
PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC);
|
||||||
PHPAPI char *expand_filepath(const char *filepath, char *real_path TSRMLS_DC);
|
PHPAPI char *expand_filepath(const char *filepath, char *real_path TSRMLS_DC);
|
||||||
|
|
||||||
|
|
|
@ -146,13 +146,36 @@ PHPAPI int php_stream_cast(php_stream *stream, int castas, void **ret, int show_
|
||||||
#define php_stream_is_persistent(stream) (stream)->is_persistent
|
#define php_stream_is_persistent(stream) (stream)->is_persistent
|
||||||
|
|
||||||
/* Wrappers support */
|
/* Wrappers support */
|
||||||
|
|
||||||
|
#define IGNORE_PATH 0
|
||||||
|
#define USE_PATH 1
|
||||||
|
#define IGNORE_URL 2
|
||||||
|
/* There's no USE_URL. */
|
||||||
|
#define ENFORCE_SAFE_MODE 4
|
||||||
|
#define REPORT_ERRORS 8
|
||||||
|
/* If you don't need to write to the stream, but really need to
|
||||||
|
* be able to seek, use this flag in your options. */
|
||||||
|
#define STREAM_MUST_SEEK 16
|
||||||
|
|
||||||
|
#ifdef PHP_WIN32
|
||||||
|
# define IGNORE_URL_WIN IGNORE_URL
|
||||||
|
#else
|
||||||
|
# define IGNORE_URL_WIN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
int php_init_stream_wrappers(TSRMLS_D);
|
int php_init_stream_wrappers(TSRMLS_D);
|
||||||
int php_shutdown_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);
|
PHPAPI int php_register_url_stream_wrapper(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC);
|
||||||
PHPAPI int php_unregister_url_stream_wrapper(char *protocol TSRMLS_DC);
|
PHPAPI int php_unregister_url_stream_wrapper(char *protocol TSRMLS_DC);
|
||||||
|
|
||||||
PHPAPI php_stream *php_stream_open_wrapper(char *path, char *mode, int options, char **opened_path TSRMLS_DC);
|
PHPAPI php_stream *php_stream_open_wrapper(char *path, char *mode, int options, char **opened_path TSRMLS_DC);
|
||||||
|
|
||||||
|
#define PHP_STREAM_UNCHANGED 0 /* orig stream was seekable anyway */
|
||||||
|
#define PHP_STREAM_RELEASED 1 /* newstream should be used; origstream is no longer valid */
|
||||||
|
#define PHP_STREAM_FAILED 2 /* an error occurred while attempting conversion */
|
||||||
|
#define PHP_STREAM_CRITICAL 3 /* an error occurred; origstream is in an unknown state; you should close origstream */
|
||||||
|
/* DO NOT call this on streams that are referenced by resources! */
|
||||||
|
PHPAPI int php_stream_make_seekable(php_stream *origstream, php_stream **newstream);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -166,7 +166,7 @@ PHPAPI char *php_stream_gets(php_stream *stream, char *buf, size_t maxlen)
|
||||||
return stream->ops->gets(stream, buf, maxlen);
|
return stream->ops->gets(stream, buf, maxlen);
|
||||||
} else {
|
} else {
|
||||||
/* unbuffered fgets - poor performance ! */
|
/* unbuffered fgets - poor performance ! */
|
||||||
size_t n = 0;
|
size_t n = 1;
|
||||||
char *c = buf;
|
char *c = buf;
|
||||||
|
|
||||||
/* TODO: look at error returns? */
|
/* TODO: look at error returns? */
|
||||||
|
@ -944,7 +944,7 @@ PHPAPI php_stream *php_stream_open_wrapper(char *path, char *mode, int options,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((options & USE_PATH) && PG(include_path) != NULL) {
|
if ((options & USE_PATH) && PG(include_path) != NULL) {
|
||||||
stream = php_stream_fopen_with_path(path, mode, PG(include_path), opened_path TSRMLS_CC);
|
stream = php_stream_fopen_with_path(path, mode, PG(include_path), opened_path TSRMLS_CC);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -954,7 +954,29 @@ PHPAPI php_stream *php_stream_open_wrapper(char *path, char *mode, int options,
|
||||||
|
|
||||||
stream = php_stream_fopen(path, mode, opened_path TSRMLS_CC);
|
stream = php_stream_fopen(path, mode, opened_path TSRMLS_CC);
|
||||||
out:
|
out:
|
||||||
if (stream == NULL && (options & REPORT_ERRORS)) {
|
if (stream != NULL && (options & STREAM_MUST_SEEK)) {
|
||||||
|
php_stream *newstream;
|
||||||
|
|
||||||
|
switch(php_stream_make_seekable(stream, &newstream)) {
|
||||||
|
case PHP_STREAM_UNCHANGED:
|
||||||
|
return stream;
|
||||||
|
case PHP_STREAM_RELEASED:
|
||||||
|
return newstream;
|
||||||
|
default:
|
||||||
|
php_stream_close(stream);
|
||||||
|
stream = NULL;
|
||||||
|
if (options & REPORT_ERRORS) {
|
||||||
|
char *tmp = estrdup(path);
|
||||||
|
php_strip_url_passwd(tmp);
|
||||||
|
zend_error(E_WARNING, "%s(\"%s\") - could not make seekable - %s",
|
||||||
|
get_active_function_name(TSRMLS_C), tmp, strerror(errno));
|
||||||
|
efree(tmp);
|
||||||
|
|
||||||
|
options ^= REPORT_ERRORS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stream == NULL && (options & REPORT_ERRORS)) {
|
||||||
char *tmp = estrdup(path);
|
char *tmp = estrdup(path);
|
||||||
php_strip_url_passwd(tmp);
|
php_strip_url_passwd(tmp);
|
||||||
zend_error(E_WARNING, "%s(\"%s\") - %s", get_active_function_name(TSRMLS_C), tmp, strerror(errno));
|
zend_error(E_WARNING, "%s(\"%s\") - %s", get_active_function_name(TSRMLS_C), tmp, strerror(errno));
|
||||||
|
@ -963,6 +985,34 @@ out:
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PHPAPI int php_stream_make_seekable(php_stream *origstream, php_stream **newstream)
|
||||||
|
{
|
||||||
|
assert(newstream != NULL);
|
||||||
|
|
||||||
|
*newstream = NULL;
|
||||||
|
|
||||||
|
if (origstream->ops->seek != NULL) {
|
||||||
|
*newstream = origstream;
|
||||||
|
return PHP_STREAM_UNCHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use a tmpfile and copy the old streams contents into it */
|
||||||
|
|
||||||
|
*newstream = php_stream_fopen_tmpfile();
|
||||||
|
|
||||||
|
if (*newstream == NULL)
|
||||||
|
return PHP_STREAM_FAILED;
|
||||||
|
|
||||||
|
if (php_stream_copy_to_stream(origstream, *newstream, PHP_STREAM_COPY_ALL) == 0) {
|
||||||
|
php_stream_close(*newstream);
|
||||||
|
*newstream = NULL;
|
||||||
|
return PHP_STREAM_CRITICAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
php_stream_close(origstream);
|
||||||
|
|
||||||
|
return PHP_STREAM_RELEASED;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue