Load PHP Script Outside of Zend Framework Before Bootstrapping - php

I need to run a php script once before my zend framework application is bootstrapped and run. This works now by calling this initial script in my /public/index.php, however the script is run for all subsequent zend framework page requests as well. I need this script to only be run once on the initial request and not again when additional pages are loaded via ajax.
My initial attempts were to set some php constants in the /public/index.php file like so:
if (!defined('SOME_VAR')) require_once 'path/to/script/to/run/once.php';
define('SOME_VAR', '1);
However, when another page is loaded via ajax, even though I've defined 'SOME_VAR', it doesn't persist and stay as defined and the script is executed again.
I'm using Zend Framework 1.11, Apache (Xampp).
Executing this script AFTER Zend has been bootstrapped and run (inside Zend Framework) is not an option.

Constants don't work because they only exist for the duration of the request.
It sounds like you want to figure out if the current request is a regular request or an XmlHttpRequest (AJAX) request.
You could try something like this at the top of your index.php:
<?php
define('IS_AJAX_REQUEST', isset($_SERVER['HTTP_X_REQUESTED_WITH'])
&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
if (! IS_AJAX_REQUEST){
// run your code.
}
If you're using sessions, you could also just set a flag in the session once you special code has been run, and test for that.

According to the Zend Framework Documentation:
However, should custom initialization be necessary, you have two choices. First, you can write methods prefixed with _init to specify discrete code to bootstrap. These methods will be called by bootstrap(), and can also be called as if they were public methods: bootstrap(). They should accept an optional array of options.
If your resource method returns a value, it will be stored in a container in the bootstrap. This can be useful when different resources need to interact (such as one resource injecting itself into another). The method getResource() can then be used to retrieve those values.
The other option is to use resource plugins. Resource plugins are objects that perform specific initializations, and may be specified:
When instantiating the Zend_Application object
During initialization of the bootstrap object
By explicitly enabling them via method calls to the bootstrap object
Resource plugins implement Zend_Application_Resource_ResourceAbstract, which defines simply that they allow injection of the caller and options, and that they have an init() method.

Related

Natively profile multiple scripts in PHP7

Since the release of PHP 7 it is now not possible to profile an entire selection of scripts using declare(ticks=1) in your base file and then using register_tick_function() to monitor each tick as it no longer follows include paths. According to the PHP bug filed at https://bugs.php.net/bug.php?id=71448 this will never be available again in PHP 7.
Due to an implementation bug, the declare(ticks=1) directive leaked into different compilation units prior to PHP 7.0. This is not how declare() directives, which are per-file or per-scope, are supposed to work.
Are there any alternatives to this approach using native PHP (not C or pear extensions etc.) that are available to me in PHP 7 that will allow me to profile each function or file called in a page load, getting details of the actual file path at least.
My original question that led to finding the bug can be found at How to avoid redeclaring ticks on every file in PHP 7, this question is now about alternative methods.
One common way to do this without declare(ticks=1) is to use a profiler. A profiler will take notice of any method/function called, file loaded etc. and even take timing information so you not only can say which function was called when and by what code and which files were opened but also which part of the program took how long.
A well known profiler in PHP comes with the famous Xdebug extension. It also ships with a debugger:
https://xdebug.org/
One benefit is that you don't need to change the code to do the profiling, it is just the PHP configuration you need to adopt so you can switch it on and off as you need it (e.g. debug / profiling session).
PHP Userland (tick function)
As a work-around not having declare(ticks=1); at the beginning of each file (after #71448), it is possible to add this on-the-fly via a stream-wrapper on the file protocol (for files in the local file-system which is common) that injects it.
This is technically feasible by creating a stream-wrapper that is registered on the file protocol to proxy standard file i/o operations. In this PoC (Gist on Github) the bare-minimum implementation is shown to demonstrate that it works for includes. When test.php is executed and despite that other.php has not declare(ticks=1); in it on disk, the registered tick function is called on the include as the print of the backtraces show:
...
tick_handler() called
#0 tick_handler(1) called at [/home/hakre/stream-wrapper-default-files/test.php:18]
#1 tick_handler() called at [/home/hakre/stream-wrapper-default-files/other.php:2]
#2 include(/home/hakre/stream-wrapper-default-files/other.php) called at [/home/hakre/stream-wrapper-default-files/test.php:24]
...
The output is generated from the registered tick function (here: test.php):
<?php
/**
* Inject declare ticks on include
*/
declare(ticks=1);
require __DIR__ . '/streamwrapper.php';
FileStreamWrapper::init();
// using a function as the callback
register_tick_function('tick_handler', true);
// Function which is called on each tick-event
function tick_handler()
{
echo "tick_handler() called\n";
debug_print_backtrace();
}
register_tick_function('tick_handler');
include "other.php";
include "another.php"; # file does not exists
The stream wrapper in the gist example has only implemented as little as needed to work for the two include statements, as PHP scripts normally do more file i/o it needs to be extended as needed. When it goes about seeking etc., the dynamic insertion needs to be taken into account etc. but there is state per file operation (handle) as there is one instance per each one so this should be well encapsulated. The global state is used for registering/unregistering the stream wrapper for each operation to proxy into the real file-system functions as otherwise it creates endless recursion (wrapper uses the wrapper uses the wrapper ...). The PoC so far shows how it works on principle.
This can be (mis-)used for other things as well, but this PoC is for your specific declare ticks and include use-case.

Laravel: Customize the request flow

Within my app ("BIRD3"), I have a NodeJS server that uses the hprose RPC system to talk to a PHP server to query it run a request and return the result (the PHP server is multi-process and spawns a sub-process per request - for now). This proposes a few difficulties; headers, cookies, sessions.
In my Yii1 based app, I used an in-development branch of the runkit extension. But, as you can tell, this is super hacky, not clean, and dependency-wise, not a smart idea. But it worked, for the most part. Here is a snippet from that very bit of code I did:
<?php
// Header.
runkit_function_redefine("headers_sent", '', 'return false;');
runkit_function_redefine(
"header", '$to,$replace=false,$status=200',
'return HttpResponse::header($to);'
);
// We have a custom handler.
runkit_function_redefine(
"setcookie",
'$name,$value,$expire=0,$path="/",$domain=null,$secure=false,$httponly=false',
'return HttpResponse::setcookie($name,$value,$expire,$domain,$secure,$httponly);'
);
// Because...
runkit_function_redefine(
"session_regenerate_id",
'$deleteOld=false',
'return bird3_session_regenerate_id($deleteOld);'
);
Now, why did I need this? Simple: Yii does not have a direct way to override Session/Header/Cookie management without doing a good load of wiring of the internals. Overriding internal dependencies with extended, derived classes is not very easy and bulks up the config file a lot.
So my question is:
Does Laravel give me the possibility to extend a few classes, override methods that do Session and Header and Cookie management and enhance it to use my custom functions instead?

Proceedural Code in Silex or maybe other Microframeworks

I'm taking an application I wrote, a form, and rewriting it in Silex. It was, for various reasons, written like:
page1.php
page1_process.php
page2.php
page2_process.php
page3.php
page3_process.php
Where pageX.php is an HTML form with little PHP code, that passes data to the process script. The process script stores data to a Form object, and serializes the object in the Session.
Currently, I have the pageX.php pages as TWIG template files and they work, but I don't know how to incorporate the logic of the procedural process scripts.
I'm sure I don't copy the actual logic to the controllers.
If I follow your requirements, you just need the same route twice: one for get (displaying the form) and one for post to handle it. In the post controller you just need to include your pageX_process.php and you should be ready to go.
Translated in Silex code it should be something like:
<?php
/**
* if you're using silex-skeleton
* from: https://packagist.org/packages/fabpot/silex-skeleton)
* this file should be src/controllers
*/
// standard setup, like error handling and other route declarations
$app->get('/page1', function() use ($app) {
// you're currently using this (somehow)
$params = []; //set up your template parameters here
return $app['twig']->render('page1.twig', $params);
});
$app->post('/page1_proccess', function() use($app) {
ob_start();
require PATH_TO_LEGACY_FILES_DIR . '/page1_process.php';
return ob_get_clean();
});
From now on, and if you want / find it adequate, you can start to refactor your pageX_process.php pages in a more OOP / Silex way, but you have a starting point with this application architecture.
NOTICE:
you should move your php files away from the web directory (for example legacy/ in the root of your project)
you must point your form handling script (the action parameter) to the new route (you can make it to work using the old route also but requires some little more effort)

PHP / SOAP / WSDL questions

I'm writing a SOAP API in PHP and I've run into a small problem. The API uses a functions file which contains a function called "GetChallenges()". I'd like my API to have a method with the same name, but since I'm including the functions file, it causes an error saying that I can't redefine that function. I'd really rather not rename the function in the functions file since i'd have to go all through my existing code and change the references. Is there a way to have the name of the function in PHP be something like"GetChallengesApi()" and yet have SOAP be able to run it as just GetChallenges()?

PHP OOP and AJAX: How to handle serverside in Class?

I'm working on converting my standard PHP project to OOP but I ran into a wall about how to handle AJAX calls with PHP Classes. I'm not happy with the way I'm doing this now. I have a TillAjax.php file which I call from my TillUI.php file from a AJAX call.
In the TillAjax.php file I do this to get the information passed from the ajax call.
$till = new Till();
if(isset($_POST['data']))
$till->doStuff($_POST['data']);
I think this ruins the OOP.
I have worked with ASP.NET MVC and here its possible to call a specific action in a controller without i have to check for the post value. So I want to know if there is a smarter PHP way to solve the above problem?
The method I use for this is to have an Ajax class.
Your php file calls Ajax::Process($_GET['handle']), where 'handle' contains the name of a static class method, so perhaps 'Till::Process'. The Ajax class checks the function against a list of permitted functions (i.e. functions that you are allowing to be called via ajax), and then uses call_user_func_array to call the function (my code uses the contents of $_POST as arguments to pass to the function). The return of that function is automatically encoded as json and outputted to the client.
This means that your target php file looks like this:
<?php
//File: ajax.php
include ("Ajax.php");
Ajax::Process($_GET['handle']);
?>
Which I think is pretty simple.
Then you can have javascript that looks like this (jquery) :
$.get('ajax.php?handle=Till::Process', {}, function(result) {
//called on page response
});
So then result now contains whatever data is returned from the php method Till::Process.
Have you considered using a PHP MVC framework such as CodeIgniter, CakePHP, Kohana, etc? They will let you route requests to specific controller methods. It will be a much cleaner solution if migrating to one of these frameworks is an option for you.

Categories