Skip to content

New 'cache_key' streams operation #1711

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ PHP 7.2 UPGRADE NOTES
========================================
2. New Features
========================================
. Added cache_key() streams operation.

- Core:
. It is now possible to remove argument type annotations when overriding an
Expand Down
14 changes: 13 additions & 1 deletion ext/phar/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ php_stream_wrapper_ops phar_stream_wops = {
phar_wrapper_rename, /* rename */
phar_wrapper_mkdir, /* create directory */
phar_wrapper_rmdir, /* remove directory */
NULL
NULL, /* Metadata handling */
phar_wrapper_cache_key /* cache_key */
};

php_stream_wrapper php_stream_phar_wrapper = {
Expand Down Expand Up @@ -967,6 +968,17 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from
}
/* }}} */

/**
* Called by the opcode cache to get the key to use when caching this URL
*/
static zend_string *phar_wrapper_cache_key(php_stream_wrapper *wrapper, zend_string *url, int options, php_stream_context *context) /* {{{ */
{
/* Phar URLs are always cacheable */
zend_string_addref(url);
return url;
}
/* }}} */

/*
* Local variables:
* tab-width: 4
Expand Down
1 change: 1 addition & 0 deletions ext/phar/stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ static php_stream* phar_wrapper_open_url(php_stream_wrapper *wrapper, const char
static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from, const char *url_to, int options, php_stream_context *context);
static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context);
static int phar_wrapper_stat(php_stream_wrapper *wrapper, const char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context);
static zend_string *phar_wrapper_cache_key(php_stream_wrapper *wrapper, zend_string *url, int options, php_stream_context *context);

/* file/stream handlers */
static size_t phar_stream_write(php_stream *stream, const char *buf, size_t count);
Expand Down
4 changes: 3 additions & 1 deletion ext/phar/tests/phar_buildfromiterator10.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ unlink(dirname(__FILE__) . '/buildfromiterator10.phar');
__HALT_COMPILER();
?>
--EXPECTF--
array(35) {
array(36) {
["phar_ctx_001.phpt"]=>
string(%d) "%sphar_ctx_001.phpt"
["phar_get_supported_signatures_001.phpt"]=>
string(%d) "%sphar_get_supported_signatures_001.phpt"
["phar_get_supported_signatures_002.phpt"]=>
string(%d) "%sphar_get_supported_signatures_002.phpt"
["phar_is_cacheable_001.phpt"]=>
string(%d) "%sphar_is_cacheable_001.phpt"
["phar_oo_001.phpt"]=>
string(%d) "%sphar_oo_001.phpt"
["phar_oo_002.phpt"]=>
Expand Down
19 changes: 19 additions & 0 deletions ext/phar/tests/phar_is_cacheable_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
Phar URI is cacheable and key is URI
--SKIPIF--
<?php if (!extension_loaded("phar")) die("skip"); ?>
--FILE--
<?php
function check_cache_key($path)
{
$key=file_cache_key($path);
var_dump($key);
}
//-----------

check_cache_key('phar:///Foo/Bar/Moo.phar.php');
?>
==DONE==
--EXPECTF--
string(28) "phar:///Foo/Bar/Moo.phar.php"
==DONE==
8 changes: 8 additions & 0 deletions ext/standard/basic_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1220,6 +1220,13 @@ ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_sys_get_temp_dir, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_file_cache_key, 0, 0, 1)
ZEND_ARG_INFO(0, filename)
ZEND_ARG_INFO(0, options)
ZEND_ARG_INFO(0, context)
ZEND_END_ARG_INFO()

/* }}} */
/* {{{ filestat.c */
ZEND_BEGIN_ARG_INFO(arginfo_disk_total_space, 0)
Expand Down Expand Up @@ -3405,6 +3412,7 @@ const zend_function_entry basic_functions[] = { /* {{{ */
PHP_FE(output_reset_rewrite_vars, arginfo_output_reset_rewrite_vars)

PHP_FE(sys_get_temp_dir, arginfo_sys_get_temp_dir)
PHP_FE(file_cache_key, arginfo_file_cache_key)

#ifdef PHP_WIN32
PHP_FE(sapi_windows_cp_set, arginfo_sapi_windows_cp_set)
Expand Down
23 changes: 23 additions & 0 deletions ext/standard/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -2519,6 +2519,29 @@ PHP_FUNCTION(sys_get_temp_dir)
}
/* }}} */

/* {{{ proto bool file_cache_key(string filename [, int options [, resource context]])
Determine if a path can be cached and the key to use */
PHP_FUNCTION(file_cache_key)
{
zend_string *filename;
zend_long options = 0;
zval *zcontext = NULL;
zend_string *ret;

/* Parse arguments */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|lr!", &filename
, &options, &zcontext) == FAILURE) {
return;
}

ret = php_stream_cache_key(filename, options, php_stream_context_from_zval(zcontext, 0));
if (ret) {
RETVAL_STR(ret);
}
/* Default: return null */
}
/* }}} */

/*
* Local variables:
* tab-width: 4
Expand Down
1 change: 1 addition & 0 deletions ext/standard/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ PHP_FUNCTION(fnmatch);
PHP_NAMED_FUNCTION(php_if_ftruncate);
PHP_NAMED_FUNCTION(php_if_fstat);
PHP_FUNCTION(sys_get_temp_dir);
PHP_FUNCTION(file_cache_key);

PHP_MINIT_FUNCTION(user_streams);

Expand Down
18 changes: 18 additions & 0 deletions ext/standard/tests/streams/http_url_is_not_cacheable_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
HTTP URL is not cacheable
--FILE--
<?php
function check_cache_key($path)
{
$key=file_cache_key($path);
var_dump($key);
}
//-----------


check_cache_key('http://acme.com/Foo.php');
check_cache_key('https://acme.com/Foo.php');
?>
--EXPECTF--
NULL
NULL
17 changes: 17 additions & 0 deletions ext/standard/tests/streams/plain_file_is_cacheable_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Plain file is cacheable
--FILE--
<?php
function check_cache_key($path)
{
$key=file_cache_key($path);
var_dump($key);
}
//-----------

check_cache_key('/Foo/Bar/Moo.php');
check_cache_key('file:///Foo/Bar/Moo.php');
?>
--EXPECTF--
string(16) "/Foo/Bar/Moo.php"
string(23) "file:///Foo/Bar/Moo.php"
22 changes: 22 additions & 0 deletions ext/standard/tests/streams/stream_cache_key_user_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Valid cache key returned from userspace wrapper
--FILE--
<?php
class MyWrapper
{
public function stream_cache_key($uri)
{
return $uri.':key';
}

}

//-----------

stream_wrapper_register('mystream','MyWrapper');

var_dump(file_cache_key('mystream://random/path'));

?>
--EXPECTF--
string(26) "mystream://random/path:key"
22 changes: 22 additions & 0 deletions ext/standard/tests/streams/stream_cache_key_user_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Null cache key returned from userspace wrapper
--FILE--
<?php
class MyWrapper
{
public function stream_cache_key($uri)
{
return null;
}

}

//-----------

stream_wrapper_register('mystream','MyWrapper');

var_dump(file_cache_key('mystream://random/path'));

?>
--EXPECTF--
NULL
18 changes: 18 additions & 0 deletions ext/standard/tests/streams/stream_cache_key_user_004.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Unimplemented cache_key() method in userspace wrapper
--FILE--
<?php
class MyWrapper
{

}

//-----------

stream_wrapper_register('mystream','MyWrapper');

var_dump(file_cache_key('mystream://random/path'));

?>
--EXPECTF--
NULL
24 changes: 24 additions & 0 deletions ext/standard/tests/streams/stream_cache_key_user_005.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
Invalid key returned by userspace cache_key() method
--FILE--
<?php
class MyWrapper
{

public function stream_cache_key($uri)
{
return 'invalid_key';
}

}

//-----------

stream_wrapper_register('mystream','MyWrapper');

var_dump(file_cache_key('mystream://random/path'));

?>
--EXPECTF--
Fatal error: file_cache_key(): cache_key: Key (invalid_key) should start with same prefix as URL (mystream://random/path) in %s on line %d

9 changes: 9 additions & 0 deletions main/php_streams.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ typedef struct _php_stream_wrapper_ops {
int (*stream_rmdir)(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context);
/* Metadata handling */
int (*stream_metadata)(php_stream_wrapper *wrapper, const char *url, int options, void *value, php_stream_context *context);

/* This operation was introduced in PHP 7.2 (PHP_API_VERSION >= 20160731) */
/* Asks whether an URL is cacheable and the key to use */
/* Note: Returned string must be zend_string_release()d by the caller */
zend_string *(*stream_cache_key)(php_stream_wrapper *wrapper, zend_string *url,
int options, php_stream_context *context);
} php_stream_wrapper_ops;

struct _php_stream_wrapper {
Expand Down Expand Up @@ -374,6 +380,9 @@ PHPAPI int _php_stream_scandir(const char *dirname, zend_string **namelist[], in
PHPAPI int _php_stream_set_option(php_stream *stream, int option, int value, void *ptrparam);
#define php_stream_set_option(stream, option, value, ptrvalue) _php_stream_set_option((stream), (option), (value), (ptrvalue))

PHPAPI zend_string *_php_stream_cache_key(zend_string *path, int options, php_stream_context *context);
#define php_stream_cache_key(path, options, context) _php_stream_cache_key((path), (options), (context))

#define php_stream_set_chunk_size(stream, size) _php_stream_set_option((stream), PHP_STREAM_OPTION_SET_CHUNK_SIZE, (size), NULL)

END_EXTERN_C()
Expand Down
9 changes: 8 additions & 1 deletion main/streams/plain_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,12 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url
return 1;
}

static zend_string *php_plain_files_cache_key(php_stream_wrapper *wrapper, zend_string *url, int option, php_stream_context *context)
{
/* Plain files are always cacheable*/
zend_string_addref(url);
return url;
}

static php_stream_wrapper_ops php_plain_files_wrapper_ops = {
php_plain_files_stream_opener,
Expand All @@ -1424,7 +1430,8 @@ static php_stream_wrapper_ops php_plain_files_wrapper_ops = {
php_plain_files_rename,
php_plain_files_mkdir,
php_plain_files_rmdir,
php_plain_files_metadata
php_plain_files_metadata,
php_plain_files_cache_key
};

PHPAPI php_stream_wrapper php_plain_files_wrapper = {
Expand Down
48 changes: 48 additions & 0 deletions main/streams/streams.c
Original file line number Diff line number Diff line change
Expand Up @@ -2320,6 +2320,54 @@ PHPAPI int _php_stream_scandir(const char *dirname, zend_string **namelist[], in
}
/* }}} */

/* {{{ php_stream_cache_key
*/
/* Note: If not NULL, the returned zend_string must be released by the caller */

PHPAPI zend_string *_php_stream_cache_key(zend_string *path, int options, php_stream_context *context)
{
php_stream_wrapper *wrapper = NULL;
zend_string *ret = NULL;

if (!path) {
return NULL;
}

wrapper = php_stream_locate_url_wrapper(ZSTR_VAL(path), NULL, options);

if (wrapper && wrapper->wops->stream_cache_key) {
ret = wrapper->wops->stream_cache_key(wrapper,
path, options, context);
if (ret) {
if (ZSTR_LEN(ret) == 0) {
/* Discard empty key as not cacheable */
zend_string_release(ret);
ret = NULL;
} else {
#ifdef PHP_DEBUG
if (path != ret) {
/* Check that returned key starts with the same '<protocol>://' */
/* prefix as input path */
const char *p1;
size_t n;

p1=php_memnstr(ZSTR_VAL(path), "://", sizeof("://") - 1
, ZSTR_VAL(path) + ZSTR_LEN(path));
if (p1) { /* Ignore non-protocol-prefixed strings */
n=p1-ZSTR_VAL(path)+3; /* Prefix length */
ZEND_ASSERT((n <= ZSTR_LEN(ret))
&& (!strncmp(ZSTR_VAL(ret), ZSTR_VAL(path), n)));
}
}
#endif
}
}
}

return ret;
}
/* }}} */

/*
* Local variables:
* tab-width: 4
Expand Down
Loading