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:
Wez Furlong 2002-03-17 14:21:01 +00:00
parent effa6e8daa
commit 12a0092376
4 changed files with 120 additions and 18 deletions

View file

@ -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?

View file

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

View file

@ -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
/*

View file

@ -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: