Most efficient way of writing a (To File) logger in PHP? - php

Hopefully someone here can help me out - basically I have a logging class that I'm updating (Made it ages ago), and I want to make sure it logs messages under 98-99% of circumstances. However right now it doesn't handle exit()s, it basically just writes to a file (Opening, writing, and closing) every time a message/error is sent to the logger.
What would be the best way to handle exit()s, and be efficient in terms of disk writes? Right now I'm looking at __destruct in the logger class (With fopen, fwrite, and fclose being called in it), however I'm not quite sure if this is safe, or efficient.
Edit: What about set_error_handler()? I remember reading years ago that this was very slow and not very good for custom errors/messages (Like SQL issues)

If you wish to log something when your script ends, you should take a look at PHP's register_shutdown_function():
function shutdown()
{
// .. log code here.
}
register_shutdown_function('shutdown');
You should avoid using the __destruct() method as there is no guarantee that it will be called when you expect it to be called.
You could also take a look at PHP's built in error_log() method to write the contents to the actual PHP error log file (this is possibly more reliable than writing your own logger).
References:
http://php.net/manual/en/function.register-shutdown-function.php
http://php.net/manual/en/function.error-log.php

I always use some global function, e.g.
function BeforeExit () {
//do stuff like logging
exit;
}

Related

Preventing crash in user-written includes()

Consider the following code:
try {
include_once "malformedFile.php";
} catch(Exception $e) {
return null;
}
I have no way to ensure that the file malformedFile.php is valid PHP code, won't crash or won't call die(). How can I continue onto the catch even if malformedFile.php dies or crashes? My interest is to make the application as robust as possible while still allowing users to implement their own plugins via includes.
Thanks.
Unfortunately, you cannot. If the included code causes a fatal error (e.g. bad syntax) you 're dead in the water.
What you could try is loading the file manually and then calling eval:
$code = file_get_contents("malformedFile.php");
eval($code);
Of course this is something you should think thrice before doing because as we all know eval is evil etc.
The most robust option would be to spawn another process that does the include for you (so if it dies unexpectedly no big deal), but communicating between the parent and child processes will be much harder than just having one process.
Include will include source, no way around it.
Maybe you can call this file as an external process and just use the results. This could be done like a CLI script or with a separate CURL call.

How atomic are lockfiles in PHP?

I have a PHP page that should be accessible only by one user at a time. It's a kind of "poor man's cron": A "Javascript" file, that is requested in the background. At the moment I'm thinking of creating a lock file like this:
if(file_exists($lockfile) && filemtime($lockfile) + EXPIRES_AFTER > time() ) {
die("// Page is locked.");
}
touch($lockfile);
// do stuff
unlink($lockfile);
echo "// Cron stuff was run";
But I'm not sure if there could be a very short window of opportunity between the file_exists and the touch call where another page request could check for the file existence and see that it isn't there. We're probably talking microseconds here so I would like top know at which amount of requests I really need to start worrying.
If you want to do this really precisely, then use a different approach, because there IS some time between the check and the lock.
Two possible implementations:
Use flock:
https://secure.php.net/manual/en/function.flock.php
Use something like STM:
E.g. open the lockfile for append, write something into it, close the handle. Then read the file back, and if it only has what you wrote into it then you have acquired the lock.
Other than that, your original code would probably not cause any problems.
There is no atomicity in the code you wrote, so yes, there is a race condition.
Your code has a race condition. Instead, dio_open the file with O_EXCL. This will fail if the file already exists. Unlink it when you're done.
The only thing to watch out for is if the system or the script crashes while the file exists, the script will never run again. If you are worried about this, check the age of the file (if you fail to create it) and if it's older than the longest the script could ever take, unlink it.
Using flock is another option.

register_shutdown_function Or ignore_user_abort?

Hey i've seen people recommend each of them, One calimed register_shutdown_function to be better but without explination.
I'm talking about which is better to send a response back and still preform other tasks.
I Wondered what really is the better method and why.
EDIT:
In the register_shutdown_function documentation, someone published the following method:
<?php
function endOutput($endMessage){
ignore_user_abort(true);
set_time_limit(0);
header("Connection: close");
header("Content-Length: ".strlen($endMessage));
echo $endMessage;
echo str_repeat("\r\n", 10); // just to be sure
flush();
}
// Must be called before any output
endOutput("thank you for visiting, have a nice day');
sleep(100);
mail("you#yourmail.com", "ping", "im here");
?>
Could it be better then any of the functions i stated?
ignore_user_abort() tells PHP/Apache to not terminate execution when the user disconnects. register_shutdown_function simply allows you to do some cleanup while PHP is in the process of shutting down.
register_shut_down is only useful if you need to do some cleanup that PHP's normal shutdown routines wouldn't take care, e.g. removing a manually created lock file, flipping a bit in a DB record somewhere, etc...
In older versions of PHP (<4.1.0 under Apache), register_shutdown_function() would ensure that the connection was closed before your shutdown functions ran. This is no longer the case. The endOutput() function in your edit should indeed do what you want, provided you don't have any output buffers open. Though, it does set the script to be able to run forever if necessary, which could be annoying if it goes into an infinite loop (especially during debugging). You might want to change set_time_limit() to use a value that actually reflects how many seconds the script should take.
It's probably best to avoid register_shutdown_function() if you don't need it, since it has some other odd behavior (such as not being able to add a second layer of shutdown functions to run if the first shutdown function calls exit()).

How to determine that a PHP script is in termination phase?

Is there any function / global variable in PHP that returns the current state of the script (something like runnning, terminating)?
Or is the only way to set this state by making use of register_shutdown_function()?
That function looks inflexible to me as an already registered shutdown functions can be overriden with it. And the shutdown function gets executed when a user aborts the connection, which is not what I'm looking for explicitly and I don't want to introduce too many constraints.
Are there any alternatives to register_shutdown_function() available? Or if not, how to deal with the shortcomings of that function?
UPDATE
Just to clarify: I'm not looking for connection state (e.g. connection_aborted()) but for the run state of the PHP script (running, terminating). Functions to find out more about the connection state I already know of, but how about the current state of the script? Has the script already been terminated and are objects (going to be) destroyed because of that?
UPDATE2
To clarify even more, I'm still not looking for connection state but for something comparable regarding the run-state. It should work in CLI as well which does not have any connection state as there is no TCP connection related to executing the code - to better illustrate what I'm looking for.
After reading a larger part of the PHP sourcecode I came to the conclusion that even if such state(s) exist on the level of experience, they do not really exist within the interpreter in form of a flag or variable.
The code about throwing Exceptions for example decides on various variables if that is possible or not.
The answer to the question is no therefore.
The best workaround I could find so far is to have a global variable for this which is set in a registered shutdown function. But a flag from PHP seems to be not really available.
<?php
register_shutdown_function(function() {$GLOBALS['shutdown_flag']=1;});
class Test {
public function __destruct() {
isset($GLOBALS['shutdown_flag'])
&& var_dump($GLOBALS['shutdown_flag'])
;
}
}
$test = new Test;
#EOF; Script ends here.
You are looking for:
Connection_aborted();
http://it.php.net/manual/en/function.connection-aborted.php
or
Connection_status();
http://it.php.net/manual/en/function.connection-status.php
Addendum
There can't be any Terminated status, because if it's terminated you can't check its status lol
I have never made (practical) use of it myself yet, but you might be able to make use of:
http://www.php.net/manual/en/function.register-tick-function.php
Using this means you can write a file or update a db or something while script is running... i.e. write a record session/some id and a timestamp id to a file or something and check for time between execution perhaps, you could say if it's not been updated in X seconds it's still running.
But as stated PHP is stateless so it's not a notion that PHP will be aware of.
Failing this, you could set a DB field in some way when a script starts/just before it 'ends', but would place a lot of overhead really.
Is there any function / global
variable in PHP that returns the
current state of the script (something
like runnning, terminating)?
No, PHP is stateless.

PHP: Prevent a function from returning value?

How could I make sure that the startProcess(); function is being called, but without halting the execution for myFunction(). I'll guess that there's a way to call a function and prevent it from returning it's value to thereby accomplishing this?
Pseudo-code:
function myFunction() {
startProcess();
return $something;
}
function startProcess() {
sleep(5);
// Do stuff that user doesn't should have to wait for.
}
You can't do it. There are some a few functions in PHP that allow async I/O, but nothing like the concurrency you require.
The reason for existing no language support is that PHP is designed to execute short-lived scripts, while the concurrency is managed by the HTTP daemon.
See also:
cur_mult_init
pcntl_fork (unix only)
http://wezfurlong.org/blog/2005/may/guru-multiplexing
To make a small addition to Artefecto's answer, there are some people who've attempted to recreate a sort of threads situation. You can find some information on it using google, but I doubt it'll be helpful as it's just too experimental and probably pretty unreliable.
Found one link that might be helpful for you.
http://w-shadow.com/blog/2008/05/24/improved-thread-simulation-class-for-php/
As far as I can tell from your question and tags, you want to do some background processing, meaning, essentially, multiple threads.
Unfortunately, PHP doesn't do this. There are some IO functions that are asynchronous, but in general you cannot do concurrent processing in PHP.
What is it you want startProcess() to do? There are many ways to keep the user from having to wait.
Emails are a good example: the thread that runs mail() spins until the message is accepted or rejected; you don't want a user to have to wait for that. So you queue up the task, and then process your queue on cron.
function myFunction() {
addToQueue();
return $something;
}
function addToQueue() {
// add stuff to the queue of tasks
}
function runQueue() {
// process the queue of tasks; called by cron.
}
Have you looked at Gearman for farming out this kind of background task?
I'm going to take a shot in the dark here, but does this function look like it could be a solution for your overall goal ?
http://php.net/manual/en/function.register-shutdown-function.php

Categories