mirror of
https://github.com/php/php-src.git
synced 2024-11-25 02:44:58 +08:00
Added ability to create local or remote (URL) user streams
Local user streams must not be able to open(), URLs if allow_url_include is off Implemented new function stream_is_local() [ - stream_wrapper_register() extended with additional optional argument "flags" of type long. This time only one flag is implemented - STREAM_IS_URL, that means that userstream wrapper is remote (URL). By default stream is local. - stream_is_local() is a new function that accepts stream and tell if this stream is local or remote (URL) ]
This commit is contained in:
parent
fe9a826605
commit
539f67ed8f
@ -207,9 +207,10 @@ ZEND_END_ARG_INFO()
|
||||
/* }}} */
|
||||
/* {{{ main/streams/userspace.c */
|
||||
static
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_stream_wrapper_register, 0)
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_stream_wrapper_register, 0, 0, 2)
|
||||
ZEND_ARG_INFO(0, protocol)
|
||||
ZEND_ARG_INFO(0, classname)
|
||||
ZEND_ARG_INFO(0, flags)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
static
|
||||
@ -221,6 +222,11 @@ static
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_stream_wrapper_restore, 0)
|
||||
ZEND_ARG_INFO(0, protocol)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
static
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_stream_is_local, 0)
|
||||
ZEND_ARG_INFO(0, stream)
|
||||
ZEND_END_ARG_INFO()
|
||||
/* }}} */
|
||||
/* {{{ array.c */
|
||||
static
|
||||
@ -3555,6 +3561,7 @@ zend_function_entry basic_functions[] = {
|
||||
PHP_FE(stream_wrapper_restore, arginfo_stream_wrapper_restore)
|
||||
PHP_FE(stream_get_wrappers, arginfo_stream_get_wrappers)
|
||||
PHP_FE(stream_get_transports, arginfo_stream_get_transports)
|
||||
PHP_FE(stream_is_local, arginfo_stream_is_local)
|
||||
PHP_FE(get_headers, arginfo_get_headers)
|
||||
|
||||
#if HAVE_SYS_TIME_H || defined(PHP_WIN32)
|
||||
|
@ -1341,6 +1341,37 @@ PHP_FUNCTION(stream_socket_enable_crypto)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto bool stream_is_local(resource stream|string url) U
|
||||
*/
|
||||
PHP_FUNCTION(stream_is_local)
|
||||
{
|
||||
zval *zstream;
|
||||
php_stream *stream = NULL;
|
||||
php_stream_wrapper *wrapper = NULL;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zstream) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if(Z_TYPE_P(zstream) == IS_RESOURCE) {
|
||||
php_stream_from_zval(stream, &zstream);
|
||||
if(stream == NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
wrapper = stream->wrapper;
|
||||
} else {
|
||||
convert_to_string_ex(&zstream);
|
||||
wrapper = php_stream_locate_url_wrapper(Z_STRVAL_P(zstream), NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC);
|
||||
}
|
||||
|
||||
if(!wrapper) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
RETURN_BOOL(wrapper->is_url==0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#ifdef HAVE_SHUTDOWN
|
||||
/* {{{ proto int stream_socket_shutdown(resource stream, int how)
|
||||
causes all or part of a full-duplex connection on the socket associated
|
||||
|
@ -55,6 +55,7 @@ PHP_FUNCTION(stream_filter_remove);
|
||||
PHP_FUNCTION(stream_socket_enable_crypto);
|
||||
PHP_FUNCTION(stream_socket_shutdown);
|
||||
PHP_FUNCTION(stream_socket_pair);
|
||||
PHP_FUNCTION(stream_is_local);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
82
ext/standard/tests/file/include_userstream_001.phpt
Executable file
82
ext/standard/tests/file/include_userstream_001.phpt
Executable file
@ -0,0 +1,82 @@
|
||||
--TEST--
|
||||
User streams and include()
|
||||
--INI--
|
||||
allow_url_fopen=1
|
||||
allow_url_include=0
|
||||
--FILE--
|
||||
<?php
|
||||
class test {
|
||||
private $data = '<?php echo "Hello World\n";?>';
|
||||
private $pos;
|
||||
|
||||
function stream_open($path, $mode, $options, &$opened_path)
|
||||
{
|
||||
if (strchr($mode, 'a'))
|
||||
$this->pos = strlen($this->data);
|
||||
else
|
||||
$this->po = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function stream_read($count)
|
||||
{
|
||||
$ret = substr($this->data, $this->pos, $count);
|
||||
$this->pos += strlen($ret);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function stream_tell()
|
||||
{
|
||||
return $this->pos;
|
||||
}
|
||||
|
||||
function stream_eof()
|
||||
{
|
||||
return $this->pos >= strlen($this->data);
|
||||
}
|
||||
|
||||
function stream_seek($offset, $whence)
|
||||
{
|
||||
switch($whence) {
|
||||
case SEEK_SET:
|
||||
if ($offset < $this->data && $offset >= 0) {
|
||||
$this->pos = $offset;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
if ($offset >= 0) {
|
||||
$this->pos += $offset;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SEEK_END:
|
||||
if (strlen($this->data) + $offset >= 0) {
|
||||
$this->pos = strlen($this->data) + $offset;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
stream_register_wrapper("test1", "test", STREAM_IS_URL);
|
||||
stream_register_wrapper("test2", "test");
|
||||
echo @file_get_contents("test1://hello"),"\n";
|
||||
@include "test1://hello";
|
||||
echo @file_get_contents("test2://hello"),"\n";
|
||||
@include "test2://hello";
|
||||
--EXPECT--
|
||||
<?php echo "Hello World\n";?>
|
||||
<?php echo "Hello World\n";?>
|
||||
Hello World
|
106
ext/standard/tests/file/include_userstream_002.phpt
Executable file
106
ext/standard/tests/file/include_userstream_002.phpt
Executable file
@ -0,0 +1,106 @@
|
||||
--TEST--
|
||||
local user streams must not be able to open() url's
|
||||
--INI--
|
||||
allow_url_fopen=1
|
||||
allow_url_include=0
|
||||
--FILE--
|
||||
<?php
|
||||
class test {
|
||||
private $data = '<?php echo "Hello World\n";?>';
|
||||
private $pos;
|
||||
private $stream = null;
|
||||
|
||||
function stream_open($path, $mode, $options, &$opened_path)
|
||||
{
|
||||
if (strpos($path, "test2://") === 0) {
|
||||
$this->stream = fopen("test1://".substr($path, 8), $mode);
|
||||
return !empty($this->stream);
|
||||
}
|
||||
if (strchr($mode, 'a'))
|
||||
$this->pos = strlen($this->data);
|
||||
else
|
||||
$this->po = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function stream_read($count)
|
||||
{
|
||||
if (!empty($this->stream)) {
|
||||
return fread($this->stream, $count);
|
||||
}
|
||||
$ret = substr($this->data, $this->pos, $count);
|
||||
$this->pos += strlen($ret);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function stream_tell()
|
||||
{
|
||||
if (!empty($this->stream)) {
|
||||
return ftell($this->stream);
|
||||
}
|
||||
return $this->pos;
|
||||
}
|
||||
|
||||
function stream_eof()
|
||||
{
|
||||
if (!empty($this->stream)) {
|
||||
return feof($this->stream);
|
||||
}
|
||||
return $this->pos >= strlen($this->data);
|
||||
}
|
||||
|
||||
function stream_seek($offset, $whence)
|
||||
{
|
||||
if (!empty($this->stream)) {
|
||||
return fseek($this->stream, $offset, $whence);
|
||||
}
|
||||
switch($whence) {
|
||||
case SEEK_SET:
|
||||
if ($offset < $this->data && $offset >= 0) {
|
||||
$this->pos = $offset;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
if ($offset >= 0) {
|
||||
$this->pos += $offset;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SEEK_END:
|
||||
if (strlen($this->data) + $offset >= 0) {
|
||||
$this->pos = strlen($this->data) + $offset;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
stream_register_wrapper("test1", "test", STREAM_IS_URL);
|
||||
stream_register_wrapper("test2", "test");
|
||||
echo @file_get_contents("test1://hello"),"\n";
|
||||
@include "test1://hello";
|
||||
echo @file_get_contents("test2://hello"),"\n";
|
||||
include "test2://hello";
|
||||
--EXPECTF--
|
||||
<?php echo "Hello World\n";?>
|
||||
<?php echo "Hello World\n";?>
|
||||
|
||||
Warning: fopen(): URL file-access is disabled in the server configuration in %sinclude_userstream_002.php on line 10
|
||||
|
||||
Warning: fopen(test1://hello): failed to open stream: no suitable wrapper could be found in %sinclude_userstream_002.php on line 10
|
||||
|
||||
Warning: include(test2://hello): failed to open stream: "test::stream_open" call failed in %sinclude_userstream_002.php on line 89
|
||||
|
||||
Warning: include(): Failed opening 'test2://hello' for inclusion (include_path='%s') in %sinclude_userstream_002.php on line 89
|
@ -1121,6 +1121,7 @@ int php_request_startup(TSRMLS_D)
|
||||
PG(modules_activated) = 0;
|
||||
PG(header_is_being_sent) = 0;
|
||||
PG(connection_status) = PHP_CONNECTION_NORMAL;
|
||||
PG(in_user_include) = 0;
|
||||
|
||||
zend_activate(TSRMLS_C);
|
||||
sapi_activate(TSRMLS_C);
|
||||
|
@ -156,6 +156,7 @@ struct _php_core_globals {
|
||||
zend_bool com_initialized;
|
||||
#endif
|
||||
long max_input_nesting_level;
|
||||
zend_bool in_user_include;
|
||||
};
|
||||
|
||||
|
||||
|
@ -499,6 +499,9 @@ END_EXTERN_C()
|
||||
/* get (or create) a persistent version of the stream */
|
||||
#define STREAM_OPEN_PERSISTENT 2048
|
||||
|
||||
/* don't check allow_url_fopen and allow_url_include */
|
||||
#define STREAM_DISABLE_URL_PROTECTION 0x00002000
|
||||
|
||||
/* Antique - no longer has meaning */
|
||||
#define IGNORE_URL_WIN 0
|
||||
|
||||
@ -550,6 +553,9 @@ PHPAPI HashTable *php_get_stream_filters_hash_global();
|
||||
END_EXTERN_C()
|
||||
#endif
|
||||
|
||||
/* Definitions for user streams */
|
||||
#define PHP_STREAM_IS_URL 1
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
|
@ -1606,7 +1606,11 @@ PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, char
|
||||
return &php_plain_files_wrapper;
|
||||
}
|
||||
|
||||
if ((wrapperpp && (*wrapperpp)->is_url) && (!PG(allow_url_fopen) || ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include))) ) {
|
||||
if (wrapperpp && (*wrapperpp)->is_url &&
|
||||
(options & STREAM_DISABLE_URL_PROTECTION) == 0 &&
|
||||
(!PG(allow_url_fopen) ||
|
||||
((options & STREAM_OPEN_FOR_INCLUDE) ||
|
||||
PG(in_user_include)) && !PG(allow_url_include))) {
|
||||
if (options & REPORT_ERRORS) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ PHP_MINIT_FUNCTION(user_streams)
|
||||
REGISTER_LONG_CONSTANT("STREAM_URL_STAT_QUIET", PHP_STREAM_URL_STAT_QUIET, CONST_CS|CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("STREAM_MKDIR_RECURSIVE", PHP_STREAM_MKDIR_RECURSIVE, CONST_CS|CONST_PERSISTENT);
|
||||
|
||||
REGISTER_LONG_CONSTANT("STREAM_IS_URL", PHP_STREAM_IS_URL, CONST_CS|CONST_PERSISTENT);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@ -215,6 +216,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
|
||||
int call_result;
|
||||
php_stream *stream = NULL;
|
||||
zval *zcontext = NULL;
|
||||
zend_bool old_in_user_include;
|
||||
|
||||
/* Try to catch bad usage without preventing flexibility */
|
||||
if (FG(user_stream_current_filename) != NULL && strcmp(filename, FG(user_stream_current_filename)) == 0) {
|
||||
@ -223,6 +225,17 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
|
||||
}
|
||||
FG(user_stream_current_filename) = filename;
|
||||
|
||||
/* if the user stream was registered as local and we are in include context,
|
||||
we add allow_url_include restrictions to allow_url_fopen ones */
|
||||
/* we need only is_url == 0 here since if is_url == 1 and remote wrappers
|
||||
were restricted we wouldn't get here */
|
||||
old_in_user_include = PG(in_user_include);
|
||||
if(uwrap->wrapper.is_url == 0 &&
|
||||
(options & STREAM_OPEN_FOR_INCLUDE) &&
|
||||
!PG(allow_url_include)) {
|
||||
PG(in_user_include) = 1;
|
||||
}
|
||||
|
||||
us = emalloc(sizeof(*us));
|
||||
us->wrapper = uwrap;
|
||||
|
||||
@ -258,6 +271,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
|
||||
FREE_ZVAL(us->object);
|
||||
efree(us);
|
||||
FG(user_stream_current_filename) = NULL;
|
||||
PG(in_user_include) = old_in_user_include;
|
||||
return NULL;
|
||||
} else {
|
||||
if (retval_ptr) {
|
||||
@ -339,6 +353,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
|
||||
|
||||
FG(user_stream_current_filename) = NULL;
|
||||
|
||||
PG(in_user_include) = old_in_user_include;
|
||||
return stream;
|
||||
}
|
||||
|
||||
@ -436,8 +451,9 @@ PHP_FUNCTION(stream_wrapper_register)
|
||||
int protocol_len, classname_len;
|
||||
struct php_user_stream_wrapper * uwrap;
|
||||
int rsrc_id;
|
||||
long flags = 0;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &protocol, &protocol_len, &classname, &classname_len) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &protocol, &protocol_len, &classname, &classname_len, &flags) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
@ -446,6 +462,7 @@ PHP_FUNCTION(stream_wrapper_register)
|
||||
uwrap->classname = estrndup(classname, classname_len);
|
||||
uwrap->wrapper.wops = &user_stream_wops;
|
||||
uwrap->wrapper.abstract = uwrap;
|
||||
uwrap->wrapper.is_url = ((flags & PHP_STREAM_IS_URL) != 0);
|
||||
|
||||
rsrc_id = ZEND_REGISTER_RESOURCE(NULL, uwrap, le_protocols);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user