RE : [PHP-DEV] Simulating require_once within an extension

From: Date: Mon, 26 Feb 2007 10:26:54 +0000
Subject: RE : [PHP-DEV] Simulating require_once within an extension
References: 1  Groups: php.internals 
Request: Send a blank email to internals+get-28152@lists.php.net to get a copy of this message
Sorry, I can't help with your C extension but I can give you a solution I implemented in PHP for the same needs. I did using two mechanisms : - A stream wrapper to allow require_once to reference a virtual path. Not required if you require 'real' files. In PHK, I need it because I implement a virtual file system. - A 'tunneling' function like yours, used through an eval(). I agree it is not very elegant but, unfortunately, there is no 'uplevel' feature in PHP (could be an interesting addition, along with a who_called_me()). This function generally returns a 'require_once <stream-wrapped path>' string, but as we eval()uate the result, it can return any code, even a 'throw Exception', to be thrown from the calling scope. If you want to see more about this example, download the PHK_Creator building kit from http://www.tekwire.net/joomla/download/phk, and search for the 'web_tunnel' function in file PHK.php. Regards François > -----Original Message----- > From: Mo McRoberts [mailto:mo@nevali.net] > Sent: Saturday, February 24, 2007 4:18 AM > To: internals@lists.php.net > Subject: [PHP-DEV] Simulating require_once within an extension > > > Hi list, > > Apologies if I'm sending this to the wrong list; I couldn't > see another which was more appropriate on the PHP Mailing Lists page. > > I'm developing a PHP extension for which part of the > functionality can be described in a nutshell as: > > * at request start-up time, build a map of identifiers to > path-names, read > from a configuration file; > > * whilst a user script is being processed, a function provided by the > extension can be called to add, remove or modify items in > the mapping; > > * a user script can call a function, passing it an identifier > in the map, > and the extension should simulate require_once being called with the > corresponding pathname (with some transformation applied). > > For example, if the configuration file specified that 'foo' > mapped to /www/common/foo, calling the above function with a > parameter of 'foo' might simulate > require_once('/www/common/foo/script.php') (where the > transformation applied in this case is appending 'script.php' > to the given pathname). A prototype implementation written in > PHP itself works well enough, but obviously there are scoping > issues with such an implementation (i.e., any scripts > included are included within the scope of the function, not the > caller) which I want to avoid through the use of an extension. > > Obviously, much of this is pretty trivial and > straightforward. My problem is the actual simulation of > require_once itself. As it's a language intrinsic, there's no > simply-exposed API for performing the same action. Digging > through the PHP sources, I've come across > zend_execute_scripts(), which seems to fit the bill, although > there's no documentation and very few examples of it being > used outside of the PHP engine itself. > > From skimming as many bits of the PHP sources that actually use > zend_execute_scripts() that I could find, the code I've come > up with isn't hugely dissimilar to this: > > static int > do_required(const char *filename TSRMLS_DC) > { > int r; > zend_file_handle zh; > > if(SUCCESS != (r = zend_stream_open(filename, &zh TSRMLS_CC))) > { > return r; > } > if(NULL == zh.opened_path) > { > zh.opened_path = estrdup(filename); > } > if(zend_hash_add_empty_element(&EG(included_files), > zh.opened_path, strlen(zh.opened_path) + 1) == SUCCESS) > { > r = zend_execute_scripts(ZEND_REQUIRE_ONCE > TSRMLS_CC, NULL, 1, &zh); > } > zend_stream_close(TSRMLS_CC); > return r; > } > > Simple enough, right? Wrong. > > I'm hoping at this point that somebody who knows the Zend > internals pretty well will immediately spot which things I'm > not initialising, saving/restoring, or happen to be > double-freeing at this point, because I'm at a loss. My > symptoms are this: > > * If calls to this function are nested, and an inner call results in > zend_stream_open() failing, I get faults in > zend_get_executed_lineno(), > suggesting corruption somewhere. > > * If I save, reset and restore return_value_ptr_ptr, active_op_array, > opline_ptr before doing anything, things seem better, but > the Warning > message reported when the file can't be opened gives the > error location > as [no active file] on line 0, which is less than ideal. > > * If I only save/reset/restore around the call to > zend_get_executed_lineno() > itself, things seem to work until I get as far as > installing the extension > for my Apache 2.2 module build of PHP: at which point, as > soon as there's > some nesting things start to go bad (errors reported or > not). Removing the > final zend_stream_close() call stops Apache from dying, but > I strongly > suspect that I'm just masking the problem rather than fixing it. > > So, my questions are: what am I doing wrong, and is there a > better way to accomplish the same thing? I considered > evaluating a script instead of trying to simulate > require_once itself, but that seemed incredibly kludgy. > > Any help appreciated. > > Thanks, > > Mo. > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >

« previous php.internals (#28152) next »