mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +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
|
||||
REPORT_ERRORS - show errors in a standard format if something
|
||||
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
|
||||
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.
|
||||
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
|
||||
===============
|
||||
What if your extension needs to access the FILE* of a user level file pointer?
|
||||
|
|
|
@ -22,19 +22,6 @@
|
|||
|
||||
#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 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
|
||||
|
||||
/* 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_shutdown_stream_wrappers(TSRMLS_D);
|
||||
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 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
|
||||
|
||||
/*
|
||||
|
|
|
@ -166,7 +166,7 @@ PHPAPI char *php_stream_gets(php_stream *stream, char *buf, size_t maxlen)
|
|||
return stream->ops->gets(stream, buf, maxlen);
|
||||
} else {
|
||||
/* unbuffered fgets - poor performance ! */
|
||||
size_t n = 0;
|
||||
size_t n = 1;
|
||||
char *c = buf;
|
||||
|
||||
/* TODO: look at error returns? */
|
||||
|
@ -944,7 +944,7 @@ PHPAPI php_stream *php_stream_open_wrapper(char *path, char *mode, int options,
|
|||
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);
|
||||
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);
|
||||
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);
|
||||
php_strip_url_passwd(tmp);
|
||||
zend_error(E_WARNING, "%s(\"%s\") - %s", get_active_function_name(TSRMLS_C), tmp, strerror(errno));
|
||||
|
@ -963,6 +985,34 @@ out:
|
|||
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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue