Files
archived-pecl-caching-apc/apc_zend.c
2018-10-03 21:38:20 +02:00

283 lines
9.9 KiB
C

/*
+----------------------------------------------------------------------+
| APC |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2011 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
+----------------------------------------------------------------------+
This software was contributed to PHP by Community Connect Inc. in 2002
and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
Future revisions and derivatives of this source code must acknowledge
Community Connect Inc. as the original contributor of this module by
leaving this note intact in the source code.
All other licensing and usage conditions are those of the PHP Group.
*/
/* $Id$ */
#include "apc_zend.h"
#include "apc_globals.h"
/* true global */
int apc_reserved_offset;
void* apc_php_malloc(size_t n TSRMLS_DC)
{
return emalloc(n);
}
void apc_php_free(void* p TSRMLS_DC)
{
efree(p);
}
#ifdef APC_OPCODE_OVERRIDE
static opcode_handler_t *apc_original_opcode_handlers;
static opcode_handler_t apc_opcode_handlers[APC_OPCODE_HANDLER_COUNT];
#ifdef ZEND_ENGINE_2_5
#define APC_EX_CV(i) (*EX_CV_NUM(execute_data, i))
#define APC_EX_T(offset) (*EX_TMP_VAR(execute_data, offset))
#else
#define APC_EX_CV(i) execute_data->CVs[i]
#define APC_EX_T(offset) (*(temp_variable *)((char*)execute_data->Ts + offset))
#endif
#ifdef ZEND_ENGINE_2_4
static zval *apc_get_zval_ptr(zend_uchar op_type, znode_op *node, zval **freeval, zend_execute_data *execute_data TSRMLS_DC)
{
*freeval = NULL;
switch (op_type) {
case IS_CONST:
return node->zv;
case IS_VAR:
return APC_EX_T(node->var).var.ptr;
case IS_TMP_VAR:
return (*freeval = &APC_EX_T(node->var).tmp_var);
case IS_CV:
{
zval ***ret = &APC_EX_CV(node->var);
if (!*ret) {
zend_compiled_variable *cv = &EG(active_op_array)->vars[node->var];
if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void**)ret)==FAILURE) {
apc_notice("Undefined variable: %s" TSRMLS_CC, cv->name);
return &EG(uninitialized_zval);
}
}
return **ret;
}
case IS_UNUSED:
default:
return NULL;
}
}
#else
static zval *apc_get_zval_ptr(znode *node, zval **freeval, zend_execute_data *execute_data TSRMLS_DC)
{
*freeval = NULL;
switch (node->op_type) {
case IS_CONST:
return &(node->u.constant);
case IS_VAR:
return APC_EX_T(node->u.var).var.ptr;
case IS_TMP_VAR:
return (*freeval = &APC_EX_T(node->u.var).tmp_var);
#ifdef ZEND_ENGINE_2_1
case IS_CV:
{
zval ***ret = &APC_EX_CV(node->u.var);
if (!*ret) {
zend_compiled_variable *cv = &EG(active_op_array)->vars[node->u.var];
if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void**)ret)==FAILURE) {
apc_notice("Undefined variable: %s" TSRMLS_CC, cv->name);
return &EG(uninitialized_zval);
}
}
return **ret;
}
#endif
case IS_UNUSED:
default:
return NULL;
}
}
#endif
static int ZEND_FASTCALL apc_op_ZEND_INCLUDE_OR_EVAL(ZEND_OPCODE_HANDLER_ARGS)
{
APC_ZEND_OPLINE
zval *freeop1 = NULL;
zval *inc_filename = NULL, tmp_inc_filename;
php_stream_wrapper *wrapper;
char *path_for_open, realpath_storage[MAXPATHLEN], *real_path;
int ret = 0;
zend_file_handle file_handle;
apc_cache_entry_t* cache_entry;
#ifdef ZEND_ENGINE_2_4
if (opline->extended_value != ZEND_INCLUDE_ONCE &&
opline->extended_value != ZEND_REQUIRE_ONCE) {
return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
inc_filename = apc_get_zval_ptr(opline->op1_type, &opline->op1, &freeop1, execute_data TSRMLS_CC);
#else
if (Z_LVAL(opline->op2.u.constant) != ZEND_INCLUDE_ONCE &&
Z_LVAL(opline->op2.u.constant) != ZEND_REQUIRE_ONCE) {
return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
inc_filename = apc_get_zval_ptr(&opline->op1, &freeop1, execute_data TSRMLS_CC);
#endif
if (Z_TYPE_P(inc_filename) != IS_STRING) {
tmp_inc_filename = *inc_filename;
zval_copy_ctor(&tmp_inc_filename);
convert_to_string(&tmp_inc_filename);
inc_filename = &tmp_inc_filename;
}
/* Check to see if this is a regular file and bail if it isn't */
wrapper = php_stream_locate_url_wrapper(Z_STRVAL_P(inc_filename), &path_for_open, 0 TSRMLS_CC);
if (wrapper != &php_plain_files_wrapper) {
if (inc_filename == &tmp_inc_filename) {
zval_dtor(&tmp_inc_filename);
}
return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
/*
Before we do anything else, we can check to see if we have a cached version of this
file, in which case we can skip the realpath - this also means that we will be checking
the correct realpath for this cache entry since it is possible that the inode existed in
a different directory at the time it was cached. Some deploy systems will do tricky things
where they rename directories and move a symlink around.
*/
file_handle.filename = inc_filename->value.str.val;
file_handle.free_filename = 0;
file_handle.type = ZEND_HANDLE_FILENAME;
file_handle.opened_path = NULL;
file_handle.handle.fp = NULL;
cache_entry = apc_get_cache_entry(&file_handle TSRMLS_CC);
if (cache_entry) {
real_path = cache_entry->data.file.filename;
} else {
if (!IS_ABSOLUTE_PATH(path_for_open, strlen(path_for_open)) || !VCWD_REALPATH(path_for_open, realpath_storage)) {
/* Fallback to original handler */
if (inc_filename == &tmp_inc_filename) {
zval_dtor(&tmp_inc_filename);
}
return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
real_path = realpath_storage;
}
if (zend_hash_exists(&EG(included_files), real_path, strlen(real_path) + 1)) {
#ifdef ZEND_ENGINE_2_4
if (!(opline->result_type & EXT_TYPE_UNUSED)) {
ALLOC_INIT_ZVAL(APC_EX_T(opline->result.var).var.ptr);
ZVAL_TRUE(APC_EX_T(opline->result.var).var.ptr);
}
#else
if (!(opline->result.u.EA.type & EXT_TYPE_UNUSED)) {
ALLOC_INIT_ZVAL(APC_EX_T(opline->result.u.var).var.ptr);
ZVAL_TRUE(APC_EX_T(opline->result.u.var).var.ptr);
}
#endif
if (inc_filename == &tmp_inc_filename) {
zval_dtor(&tmp_inc_filename);
}
if (freeop1) {
zval_dtor(freeop1);
}
execute_data->opline++;
return 0;
}
#ifdef ZEND_ENGINE_2_4
opline->extended_value = (opline->extended_value == ZEND_INCLUDE_ONCE) ? ZEND_INCLUDE : ZEND_REQUIRE;
ret = apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
opline->extended_value = (opline->extended_value == ZEND_INCLUDE) ? ZEND_INCLUDE_ONCE : ZEND_REQUIRE_ONCE;
#else
Z_LVAL(opline->op2.u.constant) = (Z_LVAL(opline->op2.u.constant) == ZEND_INCLUDE_ONCE) ? ZEND_INCLUDE : ZEND_REQUIRE;
ret = apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
Z_LVAL(opline->op2.u.constant) = (Z_LVAL(opline->op2.u.constant) == ZEND_INCLUDE) ? ZEND_INCLUDE_ONCE : ZEND_REQUIRE_ONCE;
#endif
return ret;
}
void apc_zend_init(TSRMLS_D)
{
zend_extension dummy_ext;
apc_reserved_offset = zend_get_resource_handle(&dummy_ext);
assert(apc_reserved_offset == dummy_ext.resource_number);
assert(apc_reserved_offset != -1);
assert(sizeof(apc_opflags_t) <= sizeof(void*));
if (!APCG(include_once)) {
/* If we're not overriding the INCLUDE_OR_EVAL handler, then just skip this malarkey */
return;
}
memcpy(apc_opcode_handlers, zend_opcode_handlers, sizeof(apc_opcode_handlers));
/* 5.0 exposes zend_opcode_handlers differently than 5.1 and later */
#ifdef ZEND_ENGINE_2_1
apc_original_opcode_handlers = zend_opcode_handlers;
zend_opcode_handlers = apc_opcode_handlers;
#else
apc_original_opcode_handlers = apc_opcode_handlers;
#endif
APC_REPLACE_OPCODE(ZEND_INCLUDE_OR_EVAL);
}
void apc_zend_shutdown(TSRMLS_D)
{
if (!APCG(include_once)) {
/* Nothing changed, nothing to restore */
return;
}
#ifdef ZEND_ENGINE_2_1
zend_opcode_handlers = apc_original_opcode_handlers;
#else
memcpy(zend_opcode_handlers, apc_original_opcode_handlers, sizeof(apc_opcode_handlers));
#endif
}
#else /* Opcode Overrides unavailable */
void apc_zend_init(TSRMLS_D) { }
void apc_zend_shutdown(TSRMLS_D) { }
#endif /* APC_OPCODE_OVERRIDE */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4 sts=4
*/