From a860f85e80c48b821c8cb53fc1d98d5ac2f6f07a Mon Sep 17 00:00:00 2001 From: Emiel Bruijntjes Date: Sat, 11 Apr 2015 21:12:49 +0200 Subject: function names are now turned into lowercase name when registering them with zend, this is necessary because all functions are lowercase, and function-table lookups were failing, and more importantly: the removal of functions was failing when a module was unloaded --- zend/hiddenpointer.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'zend') diff --git a/zend/hiddenpointer.h b/zend/hiddenpointer.h index d2636e3..147886e 100644 --- a/zend/hiddenpointer.h +++ b/zend/hiddenpointer.h @@ -38,8 +38,14 @@ public: // copy pointer into the buffer memcpy(buffer, &pointer, sizeof(Type *)); - // copy the name into the buffer - memcpy(buffer + sizeof(Type *), text, size + 1); + // copy the name into the buffer, making it lower case at the same time + // (php function names are case insensitive, and must even be lowercase + // because all the lookups are done in lowercase) + for (int i = 0; i < size + 1; i++) + { + // convert char the lower case + buffer[sizeof(Type *) + i] = tolower(text[i]); + } // store in member _buffer = buffer; -- cgit v1.2.3 From a8f3d4c47b342ef1ce9c951239a1618a0912484c Mon Sep 17 00:00:00 2001 From: Emiel Bruijntjes Date: Sun, 12 Apr 2015 12:11:13 +0200 Subject: Php::dl() function now gets an extra "persistent" parameter to load extensions persistently --- Examples/DlUnrestricted/dlunrestricted.cpp | 5 +- include/call.h | 6 +-- zend/eval.cpp | 9 +++- zend/module.cpp | 30 ++++++++++++ zend/module.h | 78 +++++++++++++++++++++++++++++- 5 files changed, 120 insertions(+), 8 deletions(-) create mode 100644 zend/module.cpp (limited to 'zend') diff --git a/Examples/DlUnrestricted/dlunrestricted.cpp b/Examples/DlUnrestricted/dlunrestricted.cpp index bdc7cae..a7ec7ed 100644 --- a/Examples/DlUnrestricted/dlunrestricted.cpp +++ b/Examples/DlUnrestricted/dlunrestricted.cpp @@ -29,8 +29,11 @@ Php::Value dl_unrestricted(Php::Parameters ¶ms) // get extension name std::string pathname = params[0]; + // should it be opened persistently? + bool persistent = params.size() > 1 ? params[1].boolValue() : false; + // load the extension - return Php::dl(pathname); + return Php::dl(pathname, persistent); } /** diff --git a/include/call.h b/include/call.h index 36574ce..094c7d2 100644 --- a/include/call.h +++ b/include/call.h @@ -27,9 +27,9 @@ extern PHPCPP_EXPORT bool define(const std::string &name, const Value &value extern PHPCPP_EXPORT bool defined(const char *constant); extern PHPCPP_EXPORT bool defined(const char *constant, size_t size); extern PHPCPP_EXPORT bool defined(const std::string &constant); -extern PHPCPP_EXPORT bool dl(const char *filename); -inline PHPCPP_EXPORT bool dl(const std::string &filename) { return dl(filename.c_str()); } -inline PHPCPP_EXPORT bool dl(const Value &filename) { return dl(filename.rawValue()); } +extern PHPCPP_EXPORT bool dl(const char *filename, bool persistent = false); +inline PHPCPP_EXPORT bool dl(const std::string &filename, bool persistent = false) { return dl(filename.c_str(), persistent); } +inline PHPCPP_EXPORT bool dl(const Value &filename, bool persistent = false) { return dl(filename.rawValue(), persistent); } extern PHPCPP_EXPORT Value eval(const char *phpCode); inline PHPCPP_EXPORT Value eval(const std::string &phpCode) { return eval(phpCode.c_str()); } extern PHPCPP_EXPORT Value include(const char *filename); diff --git a/zend/eval.cpp b/zend/eval.cpp index 7ab4957..6d043b1 100644 --- a/zend/eval.cpp +++ b/zend/eval.cpp @@ -93,12 +93,17 @@ Value require_once(const char *filename) /** * Implementation of the dl() function - activate a different PHP extension + * + * If you open an extension persistently, the static variables inside it are + * kept open for as long as apache runs. + * * @param filename + * @param persistent */ -bool dl(const char *filename) +bool dl(const char *filename, bool persistent) { // create the module - Module module(filename); + Module module(filename, persistent); // start the module return module.start(); diff --git a/zend/module.cpp b/zend/module.cpp new file mode 100644 index 0000000..46d03d8 --- /dev/null +++ b/zend/module.cpp @@ -0,0 +1,30 @@ +/** + * Module.cpp + * + * Module implementation file + * + * @author Emiel Bruijntjes + * @copyright 2015 Copernica BV + */ + +/** + * Dependencies + */ +#include "includes.h" + +/** + * Set up namespace + */ +namespace Php { + +/** + * The persistent handles + * @var Module::Persistent + */ +Module::Persistent Module::_persistent; + +/** + * End of namespace + */ +} + diff --git a/zend/module.h b/zend/module.h index 4fa6bce..40cd6f7 100644 --- a/zend/module.h +++ b/zend/module.h @@ -43,7 +43,7 @@ private: * @var zend_module_entry */ zend_module_entry *_entry = nullptr; - + #ifdef ZTS /** * When in thread safety mode, we also keep track of the TSRM_LS var @@ -52,12 +52,82 @@ private: void ***tsrm_ls; #endif + /** + * Internal helper class with persistent modules + */ + class Persistent + { + private: + /** + * The set of handles + * @var std::set + */ + std::set _handles; + + public: + /** + * Constructor + */ + Persistent() {} + + /** + * Destructor + */ + virtual ~Persistent() + { + // remove all handles + while (!_handles.empty()) + { + // get first handle + auto iter = _handles.begin(); + + // remove the handle + DL_UNLOAD(*iter); + + // remove from set + _handles.erase(iter); + } + } + + /** + * Check whether a handle is already persistently opened + * @param handle + * @return bool + */ + bool contains(void *handle) const + { + return _handles.find(handle) != _handles.end(); + } + + /** + * Add a library persistently + * @param module + */ + void add(const char *module) + { + // insert the handle + _handles.insert(DL_LOAD(module)); + } + }; + + /** + * All persistent modules + * @var Persistent + */ + static Persistent _persistent; + public: /** * Constructor + * + * A module can be loaded persistently. This means that the variables in + * the module will keep in scope for as long as Apache runs, even though + * the extension is not active in other page views + * * @param module Name of the module + * @param persistent Should it be loaded persistently */ - Module(const char *module) + Module(const char *module, bool persistent) { #ifdef ZTS // fetch multi-threading thing @@ -76,6 +146,10 @@ public: // handle should be valid if (!_handle) return; + // if we have to open it persistently, we open it for a second time so that + // the refcounter always stays 1 or higher + if (persistent && !_persistent.contains(_handle)) _persistent.add(module); + // we have to call the get_module() function Symbol get_module(_handle, "get_module"); -- cgit v1.2.3 From 5470a3d9556c04471660288a10098528ec9892e7 Mon Sep 17 00:00:00 2001 From: Emiel Bruijntjes Date: Sun, 12 Apr 2015 21:00:12 +0200 Subject: stop calling zend_next_free_module() -- some users complain that this function does not exist, this hopefully fixes issue #185 --- zend/executestate.h | 18 ++++++++++++++++-- zend/opcodes.h | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'zend') diff --git a/zend/executestate.h b/zend/executestate.h index 8e33b16..d71a252 100644 --- a/zend/executestate.h +++ b/zend/executestate.h @@ -26,11 +26,18 @@ class ExecuteState private: /** * All the original settings + * @var mixed */ zend_op_array *_active_op_array; zval **_return_value_ptr_ptr; zend_op **_opline_ptr; int _interactive; + + /** + * The new value for 'no-extensions' + * @var int + */ + int _no_extensions; #ifdef ZTS /** @@ -41,16 +48,23 @@ private: #endif public: + /** + * No trivial constructor + */ + ExecuteState() = delete; + /** * Constructor + * @param no_extensions */ - ExecuteState(TSRMLS_D) + ExecuteState(int no_extensions TSRMLS_DC) { // store all the original stuff _active_op_array = EG(active_op_array); _return_value_ptr_ptr = EG(return_value_ptr_ptr); _opline_ptr = EG(opline_ptr); _interactive = CG(interactive); + _no_extensions = no_extensions; #ifdef ZTS // copy tsrm_ls param @@ -65,7 +79,7 @@ public: { // restore all settings CG(interactive) = _interactive; - EG(no_extensions) = 0; + EG(no_extensions) = _no_extensions; EG(opline_ptr) = _opline_ptr; EG(active_op_array) = _active_op_array; EG(return_value_ptr_ptr) = _return_value_ptr_ptr; diff --git a/zend/opcodes.h b/zend/opcodes.h index 7e6d1ec..4e78083 100644 --- a/zend/opcodes.h +++ b/zend/opcodes.h @@ -74,7 +74,7 @@ public: // the zend engine is probably already busy processing opcodes, so we store // the current execute state before we're going to switch the runtime to // our own set of opcodes - ExecuteState oldstate(TSRMLS_C); + ExecuteState execState(0 TSRMLS_CC); // old execute state has been saved (and will automatically be restured when // the oldstate is destructed), so we can now safely overwrite all the settings -- cgit v1.2.3