summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2015-01-20 13:45:17 +0100
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2015-01-20 13:45:17 +0100
commit5235f87126cc2bca3907daada9f59e0c7c7bc834 (patch)
tree6b049edd2eca0b74a8acb9ff7ee0c84c93bf1a5c
parent821e65d876cc0ce2b32471791b02d9f7cc784c99 (diff)
PHP-CPP now checks whether an already compiled extension is still compatible with the PHP-CPP library. This prevents weird crashes when users update their PHP-CPP library, without recompiling their extensions
-rw-r--r--include/extension.h11
-rw-r--r--include/version.h17
-rw-r--r--phpcpp.h1
-rw-r--r--zend/extension.cpp5
-rw-r--r--zend/extensionimpl.cpp59
-rw-r--r--zend/extensionimpl.h29
-rw-r--r--zend/includes.h1
7 files changed, 116 insertions, 7 deletions
diff --git a/include/extension.h b/include/extension.h
index 562fceb..15ad5e1 100644
--- a/include/extension.h
+++ b/include/extension.h
@@ -38,10 +38,19 @@ class Extension : public Namespace
public:
/**
* Constructor that defines a number of functions right away
+ *
+ * The first two parameters should be filled by the extension programmer with the
+ * name of the extension, and the version number of the extension (like "1.0").
+ * The third parameter, apiversion, does not have to be supplied and is best kept
+ * to the default value. This third parameter checks whether the PHP-CPP version
+ * that is currently installed on the server is the same as the PHP-CPP version
+ * that was used to compile the extension with.
+ *
* @param name Extension name
* @param version Extension version string
+ * @param apiversion PHP API version (this should always be PHPCPP_API_VERSION, so you better not supply it)
*/
- Extension(const char *name, const char *version = "1.0");
+ Extension(const char *name, const char *version = "1.0", int apiversion = PHPCPP_API_VERSION);
/**
* No copy'ing and no moving
diff --git a/include/version.h b/include/version.h
new file mode 100644
index 0000000..85d2b66
--- /dev/null
+++ b/include/version.h
@@ -0,0 +1,17 @@
+/**
+ * Version.h
+ *
+ * Macro with API version. The API version number prevents that
+ * extensions are loaded that are incompatible with the libphpcpp.so
+ * library
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2015 Copernica BV
+ */
+
+/**
+ * Macro with version number (this is incremented with every release)
+ */
+#define PHPCPP_API_VERSION 20150120
+
+
diff --git a/phpcpp.h b/phpcpp.h
index 231e112..b5216ff 100644
--- a/phpcpp.h
+++ b/phpcpp.h
@@ -27,6 +27,7 @@
/**
* Include all headers files that are related to this library
*/
+#include <phpcpp/version.h>
#include <phpcpp/inivalue.h>
#include <phpcpp/ini.h>
#include <phpcpp/exception.h>
diff --git a/zend/extension.cpp b/zend/extension.cpp
index 1545f89..4ad54a3 100644
--- a/zend/extension.cpp
+++ b/zend/extension.cpp
@@ -15,9 +15,10 @@ namespace Php {
* Constructor that defines a number of functions right away
* @param name Extension name
* @param version Extension version string
+ * @param apiversion API version number
*/
-Extension::Extension(const char *name, const char *version) :
- Namespace(""), _impl(new ExtensionImpl(this, name, version)) {}
+Extension::Extension(const char *name, const char *version, int apiversion) :
+ Namespace(""), _impl(new ExtensionImpl(this, name, version, apiversion)) {}
/**
* Destructor
diff --git a/zend/extensionimpl.cpp b/zend/extensionimpl.cpp
index 262ecdb..fd97a76 100644
--- a/zend/extensionimpl.cpp
+++ b/zend/extensionimpl.cpp
@@ -220,12 +220,34 @@ int ExtensionImpl::processIdle(int type, int module_number TSRMLS_DC)
}
/**
+ * Function that is called when the PHP engine initializes with a different PHP-CPP
+ * version for the libphpcpp.so file than the version the extension was compiled for
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int 0 on success
+ */
+int ExtensionImpl::processMismatch(int type, int module_number TSRMLS_DC)
+{
+ // get the extension
+ auto *extension = find(module_number TSRMLS_CC);
+
+ // report a warning
+ warning << "Version mismatch between PHP-CPP and extension " << extension->name() << " " << extension->version() << " (recompile needed?)" << std::endl;
+
+ // done
+ return BOOL2SUCCESS(true);
+}
+
+/**
* Constructor
* @param data Pointer to the extension object created by the extension programmer
* @param name Name of the extension
* @param version Version number
+ * @param apiversion API version number
*/
-ExtensionImpl::ExtensionImpl(Extension *data, const char *name, const char *version) : ExtensionBase(data)
+ExtensionImpl::ExtensionImpl(Extension *data, const char *name, const char *version, int apiversion) :
+ ExtensionBase(data)
{
// keep extension pointer based on the name
name2extension[name] = this;
@@ -262,6 +284,17 @@ ExtensionImpl::ExtensionImpl(Extension *data, const char *name, const char *vers
_entry.globals_ptr = NULL;
#endif
+ // everything is ok if the api versions match
+ if (apiversion == PHPCPP_API_VERSION) return;
+
+ // mismatch between api versions, the extension is invalid, we use a
+ // different startup function to report to the user
+ _entry.module_startup_func = &ExtensionImpl::processMismatch;
+
+ // the other callback functions are no longer necessary
+ _entry.module_shutdown_func = nullptr;
+ _entry.request_startup_func = nullptr;
+ _entry.request_shutdown_func = nullptr;
}
/**
@@ -277,6 +310,26 @@ ExtensionImpl::~ExtensionImpl()
}
/**
+ * The extension name
+ * @return const char *
+ */
+const char *ExtensionImpl::name() const
+{
+ // name is stored in the struct
+ return _entry.name;
+}
+
+/**
+ * The extension version
+ * @return const char *
+ */
+const char *ExtensionImpl::version() const
+{
+ // version is stored in the struct
+ return _entry.version;
+}
+
+/**
* Retrieve the module entry
* @return zend_module_entry
*/
@@ -285,6 +338,10 @@ zend_module_entry *ExtensionImpl::module()
// check if functions were already defined
if (_entry.functions) return &_entry;
+ // if the 'processMismatch' function is installed, the API version is wrong,
+ // and nothing should be initialized
+ if (_entry.module_startup_func == &ExtensionImpl::processMismatch) return &_entry;
+
// the number of functions
int count = _data->functions();
diff --git a/zend/extensionimpl.h b/zend/extensionimpl.h
index 0e9a289..0a366ba 100644
--- a/zend/extensionimpl.h
+++ b/zend/extensionimpl.h
@@ -37,15 +37,16 @@ protected:
* @var zend_ini_entry
*/
zend_ini_entry *_ini = nullptr;
-
+
public:
/**
* Constructor
* @param data Extension object created by the extension programmer
* @param name Name of the extension
* @param version Version number
+ * @param apiversion API version number
*/
- ExtensionImpl(Extension *data, const char *name, const char *version);
+ ExtensionImpl(Extension *data, const char *name, const char *version, int apiversion);
/**
* No copy'ing and no moving
@@ -58,6 +59,18 @@ public:
*/
virtual ~ExtensionImpl();
+ /**
+ * The extension name
+ * @return const char *
+ */
+ const char *name() const;
+
+ /**
+ * The extension version
+ * @return const char *
+ */
+ const char *version() const;
+
/**
* Is the object locked (true) or is it still possible to add more functions,
* classes and other elements to it?
@@ -94,7 +107,7 @@ private:
* @param tsrm_ls
*/
void initialize(TSRMLS_D);
-
+
/**
* Function that is called when the extension initializes
* @param type Module type
@@ -130,6 +143,16 @@ private:
* @return int 0 on success
*/
static int processIdle(int type, int module_number TSRMLS_DC);
+
+ /**
+ * Function that is called when the PHP engine initializes with a different PHP-CPP
+ * version for the libphpcpp.so file than the version the extension was compiled for
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int 0 on success
+ */
+ static int processMismatch(int type, int module_number TSRMLS_DC);
};
/**
diff --git a/zend/includes.h b/zend/includes.h
index 83b1086..fb14b87 100644
--- a/zend/includes.h
+++ b/zend/includes.h
@@ -46,6 +46,7 @@
/**
* Include other files from this library
*/
+#include "../include/version.h"
#include "../include/inivalue.h"
#include "../include/ini.h"
#include "../include/exception.h"