In the last chapter, you used zend_alter_ini_setting() to modify some PHP INI options. Because sapi/embed thrusts your script directly into runtime mode, most of the more important INI options are unmodifiable after control has been returned to your application. To change these values, it's necessary to be able to execute code after the main engine startup so that space for these variables is available, yet before the request startup.
One approach might be to copy and paste the contents of php_embed_init() into your application, make the necessary changes in your local copy, and then use that method instead. Of course, this approach presents some problems.
First and foremost, you've effectively forked a portion of code someone else was already busily putting the work in on maintaining. Now, instead of just maintaining your application, you've got to keep up with a random bit of forked code someone else wrote as well. Fortunately, there are a few much simpler methods.
Overriding the Default php.ini File
Because embed is a sapi just like any other PHP sapi implementation, it's hooked into the engine by way of a sapi_module_struct. The embed SAPI declares and populates an instance of this structure that your application has access to even before calling php_embed_init().
In this structure is a simple char* field named php_ini_path_override. To request that embedand by extension PHP and Zenduse your alternate file, just populate this field with a NULL-terminated string prior to calling php_embed_init() as in the following modified startup_php() function in embed4.c.
static void startup_php(void) { /* Create "dummy" argc/argv to hide the arguments * meant for our actual application */ int argc = 1; char *argv[2] = { "embed4", NULL }; php_embed_module.php_ini_path_override = "/etc/php_embed4.ini"; php_embed_init(argc, argv PTSRMLS_CC); }
This allows each application using the embed library to remain customizable, without imposing their configurations on each other. Conversely, if you'd rather prevent your application from using php.ini at all, simply set the php_ini_ignore field in php_embed_module and all settings will default to their built-in values unless specifically modified by your application.
Overriding Embed Startup
The sapi_module_struct also contains several callback functions, four of which are of interest for periodically taking back control during PHP startup and shutdown.
/* From main/SAPI.h */ typedef struct _sapi_module_struct { ... int (*startup)(struct _sapi_module_struct *sapi_module); int (*shutdown)(struct _sapi_module_struct *sapi_module); int (*activate)(TSRMLS_D); int (*deactivate)(TSRMLS_D); ... } sapi_module_struct;
Do these method names ring a bell? They shouldthey correspond to an extension's MINIT, MSHUTDOWN, RINIT, and RSHUTDOWN methods and trigger during the same cycles as they do for extensions. To take advantage of these hooks, modify startup_php() in embed4 to the following version along with the additional code provided:
static int (*original_embed_startup)(struct _sapi_module_struct *sapi_module); static int embed4_startup_callback(struct _sapi_module_struct *sapi_module) { /* Call original startup callback first, * otherwise the environment won't be ready */ if (original_embed_startup(sapi_module) == FAILURE) { /* Application failure handling may occur here */ return FAILURE; } /* Calling the original embed_startup actually places us * in the ACTIVATE stage rather than the STARTUP stage, but * we can still alter most INI_SYSTEM and INI_PERDIR entries anyhow */ zend_alter_ini_entry("max_execution_time", sizeof("max_execution_time"), "15", sizeof("15") - 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE); zend_alter_ini_entry("safe_mode", sizeof("safe_mode"), "1", sizeof("1") - 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE); return SUCCESS; } static void startup_php(void) { /* Create "dummy" argc/argv to hide the arguments * meant for our actual application */ int argc = 1; char *argv[2] = { "embed4", NULL }; /* Override the standard startup method with our own * but save the original so that it can still be invoked. */ original_embed_startup = php_embed_module.startup; php_embed_module.startup = embed4_startup_callback; php_embed_init(argc, argv PTSRMLS_CC); }
Using options like safe_mode, open_basedir, and others will help limit what individuals scripting behavior into your application can do and should help ensure a safer, more reliable application.
The PHP Life Cycle
Variables from the Inside Out
Memory Management
Setting Up a Build Environment
Your First Extension
Returning Values
Accepting Parameters
Working with Arrays and HashTables
The Resource Data Type
PHP4 Objects
PHP5 Objects
Startup, Shutdown, and a Few Points in Between
INI Settings
Accessing Streams
Implementing Streams
Diverting the Stream
Configuration and Linking
Extension Generators
Setting Up a Host Environment
Advanced Embedding
Appendix A. A Zend API Reference
Appendix B. PHPAPI
Appendix C. Extending and Embedding Cookbook
Appendix D. Additional Resources