Enjoy unlimited access to all forum features for FREE! Optional upgrade available for extra perks.

Shutdown function php

Status
Not open for further replies.
Joined
Jul 11, 2008
Posts
4,616
Reaction score
209
I've run into a slight problem, and wondered if anyone here had any suggestions or idea's.

I use register_shutdown_function() to catch unexpected errors and perform house cleaning (deleting temp files, unlocking databases, etc) but I'm having problems catching a 500 error.

When the script times out, I want to perform house cleaning, but as yet nothing seems to work, an option would be to create a 500.php file so when it served it could check the referer then perform defined housecleaning but this would mean maintaining a 500 catch/clean system.

Does anyone know if you can actually catch a 500 error ?

My code is as simple as

PHP:
register_shutdown_function( "house_cleaning" );

function house_cleaning() {
 // perform required tasks
 // possibly restart process if incomplete
}

I assume from within the shutdown function, I can access the resources from the main script ?
 
Last edited:
register_shutdown_function does catch fatal errors, and since 500 is considered a fatal error, the following code should suffice?

PHP:
register_shutdown_function('my_shutdown_function');

// .. do your stuff ..

function my_shutdown_function()
{
    $err = error_get_last();
    // Error of type 1 is a fatal error
    if($err['type'] == 1) { 
	    // .. do your stuff ..
    }
}

Or am I misunderstanding you?
 
500 is a pre-processing error to say the php parser could not process the php file and convert it into object code. So essentially the code doesn't run.
 
Well 500 is also raised when an unhandled exception is thrown too, which does raise another point that the unhandled exception should be handled. :D
 
The problem is a "request timeout", which occurs due some queries / operations being too big.

On my local machine / dedi the timeout isn't an issue and the script works fine but on shared hosting, its problematic.
 
If you are using 5.1+ and can run a preliminary test without damage, try this in the main index.php for most errors: (without the code tags of course):

Code:
<?php

define('E_FATAL',  E_ERROR | E_USER_ERROR | E_PARSE | E_CORE_ERROR | 
        E_COMPILE_ERROR | E_RECOVERABLE_ERROR);

define('ENV', 'dev');

//Custom error handling vars
define('DISPLAY_ERRORS', TRUE);
define('ERROR_REPORTING', E_ALL | E_STRICT);
define('LOG_ERRORS', TRUE);

register_shutdown_function('shut');

set_error_handler('handler');

//Function to catch no user error handler function errors...
function shut(){

    $error = error_get_last();

    if($error && ($error['type'] & E_FATAL)){
        handler($error['type'], $error['message'], $error['file'], $error['line']);
    }

}

function handler( $errno, $errstr, $errfile, $errline ) {

    switch ($errno){

        case E_ERROR: // 1 //
            $typestr = 'E_ERROR'; break;
        case E_WARNING: // 2 //
            $typestr = 'E_WARNING'; break;
        case E_PARSE: // 4 //
            $typestr = 'E_PARSE'; break;
        case E_NOTICE: // 8 //
            $typestr = 'E_NOTICE'; break;
        case E_CORE_ERROR: // 16 //
            $typestr = 'E_CORE_ERROR'; break;
        case E_CORE_WARNING: // 32 //
            $typestr = 'E_CORE_WARNING'; break;
        case E_COMPILE_ERROR: // 64 //
            $typestr = 'E_COMPILE_ERROR'; break;
        case E_CORE_WARNING: // 128 //
            $typestr = 'E_COMPILE_WARNING'; break;
        case E_USER_ERROR: // 256 //
            $typestr = 'E_USER_ERROR'; break;
        case E_USER_WARNING: // 512 //
            $typestr = 'E_USER_WARNING'; break;
        case E_USER_NOTICE: // 1024 //
            $typestr = 'E_USER_NOTICE'; break;
        case E_STRICT: // 2048 //
            $typestr = 'E_STRICT'; break;
        case E_RECOVERABLE_ERROR: // 4096 //
            $typestr = 'E_RECOVERABLE_ERROR'; break;
        case E_DEPRECATED: // 8192 //
            $typestr = 'E_DEPRECATED'; break;
        case E_USER_DEPRECATED: // 16384 //
            $typestr = 'E_USER_DEPRECATED'; break;

    }

    $message = '<b>'.$typestr.': </b>'.$errstr.' in <b>'.$errfile.'</b> on line <b>'.$errline.'</b><br/>';

    if(($errno & E_FATAL) && ENV === 'production'){

        header('Location: 500.html');
        header('Status: 500 Internal Server Error');

    }

    if(!($errno & ERROR_REPORTING))
        return;

    if(DISPLAY_ERRORS)
        printf('%s', $message);

    //Logging error on php file error log...
    if(LOG_ERRORS)
        error_log(strip_tags($message), 0);

}

ob_start();

@include 'content.php';

ob_end_flush();
?>

Apologies if I have the wrong end of the stick reg your problem.
 
I'll give it a try later on, thanks :)

This particular problem is operating on a 12gb database, some searches can take upto 8 minutes inc processing. Most queries complete within the time allowed those that don't lock the database.

All I really need to do is detect when the request timesout / 500 happens, then at least unlock the database, or ideally run the query (which is cached) so its ready to be run later then unlock but I'd settle for simply unlocking the database.
 
The 8 minutes includes post processing/acting on the data as well, but the main query is using the lions share.

Its wildcard queries which cause most of the problems, and I'm not sure of any way to easily speed these up aside from more resources.
 
Hmm, perhaps you need to be reviewing the design, this is a long time. Perhaps web/PHP is not the best way of doing things if you need to wildcard search over such a huge data-set.

I'm guessing the "customer" is not sitting in front of the browser waiting 8 minutes, so could you build the system to queue these searches and build a SQL stored procedure to run these queries and store the results for later collection?

Alternatively, run a 16Gb RAM box and push the data into an in-memory table to gain the necessary speed increase.
 
Most queries come in, in under a minute or two but wildcards are a nightmare.

80% of wildcard searches are done on a unique field, so I cant reduce that, so far just been trying to nail down the where clause to reduce set as much as possible.

Before I start mega hassle, the shutdown func is easier route for now, all else fails ill disable wildcards until I have a solution.
 
even a minute or 2 is huge, I'd be tempted to build a lean table to search and then to pull the main data by key.

I presume if using PHP the database is likely to be MySQL, so if you must have such a long running query, look at putting the search table into a memory table.

Database optimisation really seems to be the key to what you need to do rather than attempt to tidy up after failed reads / writes.
 
I was thinking about a table which contained just the unique column which is problematic, purely for the wildcard search on that dataset. However modifying all the relevant parts in other files to insert data into both tables (to keep them synced) isn't possible.

I just ran a query based on 1 column, nearly 500,000 results returned out of 150m and took about 8 seconds to run, a wildcard search returning just over 80,000 rows took 63 seconds, then less than 2 seconds from the cached query.

If I have no luck with the clean up idea, I'll have to try and tackle it from another angle.

Was hoping was something I was missing, like the missing ; and 's.
 
I didn't even think of triggers.

I am wondering if the fact the shutdown won't trigger means there could be a bigger issue somewhere in the code or even with the php install. Kinda locked on trying to solve this problem (of why shutdown won't fire) to see the forest :)
 
Status
Not open for further replies.

The Rule #1

Do not insult any other member. Be polite and do business. Thank you!

Featured Services

Sedo - it.com Premiums

IT.com

Premium Members

AucDom
UKBackorder
Be a Squirrel
Acorn Domains Merch
MariaBuy Marketplace

New Threads

Domain Forum Friends

Other domain-related communities we can recommend.

Our Mods' Businesses

Perfect
Service
Laskos
*the exceptional businesses of our esteemed moderators
Top Bottom