Auto-execute a function after everything else has executed - php

Basically, I have a script that is included at the top of a page that does a bunch of things, the most important being an ob_start(). Then in the body of the page I have a variety of tags that will be replaced, such as {hello_word}. Then at the very end, I include another script that ends the output buffer, and makes the tag replacements with other code, then prints.
Is there any possible way to do this without having to include my second file at the end? Is there some simple way I can automatically execute a function or include a file at the very end?

You can register a function to be executed at the very end of script using register_shutdown_function

Any objects that you have remaining will be destroyed at the end of the script, and their destructors will be called (manual). You can put code that you want executed at the end in the destructor.
For example:
Class Waitforme {
function __destruct() {
echo "I'm here!";
}
}
$hello = new Waitforme();
This will do nothing until $hello is destroyed, at which time we'll see "I'm here!"

You can use the auto_append setting in php.ini, but you'll sacrifice portability. If you don't plan on distributing your application, this is a good option.

Related

php codeigniter how to run multiple function simultaneously

I have 2 functions, let's call them login and doSomething and currently, I implemented them this way,
$member=$this->login();
$this->doSomething($member);
//show welcome page
When a user logs in, I want to do some stuff but it takes around 20 seconds or more to complete. Is there any ways where after login() is run, it will show the welcome page immediately while the method doSomething() is being executed separately. The method doSomething() doesn't return any values thus does not affect the welcome page.
Please try the following.
ob_start();
$member = $this->login();
ob_end_flush();
ob_flush();
flush();
$this->doSomething($member);
If you do not want to print anything after login, you can use:
ob_start();
$this->doSomething($member);
ob_end_clean();
Also using Ajax from the front site's login page(after loading), you can start processing
$this->doSomething($member);
in another ajax call in the back end silently.
There are other ways for achieving threading, pseudo threading like behaviour.
But these are the easiest one for your scenerio :)
You can check WorkerThreads also.
Their implementation example documentation are available in the net.
If you really, really want to run it in parallel, then you need to run it in a sperate process. That means you are running it in different scope, so while the code you invoke might contain $this->doSomething($member), that "this" won't be this "this".
Assuming that is possible, then your question is a duplicate of this one (but beware - the accepted answer is not good). Note that you will run in blocking problems if both parts of the script depend on a session.

PHP - file_put_contents writes content multiple times

I have an extremely oversimplified logger function:
<?php
class Logger {
public function __construct($logFile) {
$this->logFile = $logFile;
}
public function log($message) {
$message = date('c') . $message;
file_put_contents($this->logFile, $message, FILE_APPEND | LOCK_EX);
echo "it ran ";
}
}
Calling it like this
$logger = new Logger('log.txt');
$logger->log("message");
echo "called the method";
causes the message to be written to the file exactly 3 times, instead of 1.
The code is outside of any loop, which is confirmed by echo statements, which get printed only once.
Also, if I simply run file_put_contents() function on place where I'd call the log method, it works fine and writes the content just once. So it might have something to do with my class, but no clue what.
EDIT: #Tommy: here is the log file content:
2014-09-26T07:24:51-04:00message2014-09-26T07:24:54-04:00message2014-09-26T07:24:54-04:00message
EDIT 2: I tried using die() function after calling the method, and then it did write the message just once. So I kept moving the die() through the code, and it starts writing the message 3 times after this exact line:
if (isset($_POST['create_account'])) {
die;
Since there's a die below it, it shouldn't even matter what's in further code, right?
Wonder if it might be some sort of php bug, this is very stange. If I put the die() above this line, it will work fine and write the message just once.
There's a fairly good chance that your code does a redirect or reload somewhere. This causes a new request to start, which wipes away the original echo but does not remove the one written to file. As a result it looks like it was echo'd once and written thrice. But really, it was echo'd thrice as well, just the other copies have been removed.
If you want to see what's going on, print part of the stack-trace into the log-file along with the message. You can see exactly on which line the message is created and during which function call.
The main issue as per my experience is the index.php is being called twice. So, to fix:
change the file name
fix the index.php such that favicon.ico is missing!

Is it possible to ignore exit of child script from parent script in PHP?

A child script terminates the parent script because it has exit;
Since it is a third party extension, I need to avoid any core hack. Would it be possible somehow to ignore the exit of the child script from parent script. I am calling its controller and a method from an external script.
parent.php
<?php
require "child.php";
?>
child.php
<?php
does something;
exit;
?>
Update
Any alternative solution would be fine as long as we dont modify the child script.
Is it possible to ignore exit from included script in PHP?
No.
exit terminates execution of the script regardless from where it is called.
As noted in sjagr's answer, there are alternatives to using exit.
If you do in fact end up editing the core files, then it is possible to use return inside of the "child script." From the PHP docs:
If called from the global scope, then execution of the current script
file is ended. If the current script file was included or required,
then control is passed back to the calling file. Furthermore, if the
current script file was included, then the value given to return will
be returned as the value of the include call. If return is called from
within the main script file, then script execution ends. If the
current script file was named by the auto_prepend_file or
auto_append_file configuration options in php.ini, then that script
file's execution is ended.
However, there is no way to prevent the parent script from preventing a child script from killing the process if it has an exit statement. Unfortunately you cannot override this functionality.
You might be able to run child.php in a thread. Use join to wait until that thread finishes before continuing with the main thread. This way, calling exit in child.php will terminate the child thread and the main thread will continue.
class myThread extends Thread {
public function run(){
include "child.php";
//Call methods from child.php here
}
}
$thread = new myThread();
$thread->start();
$thread->join();
Thank you so much everyone for answering the question. Finally I came up with the following alternative idea. I am not sure if it is similar to any design pattern. The following example does not get terminated from loop although the child.php has exit.
parent.php
<?php
require "temp.php";
for($i=1;$i<10;$i++){
file_get_contents("http://url/temp.php?var=$i");
}
?>
temp.php
<?php
$var = $_GET['var'];
// execute
require "child.php";
$testController = new TestController();
$testController->method($var);
?>
Yes.
In your child.php you can use a return to return the control back to the parent.php.
Otherwise if child.php isn't included, it will continue with its normal operation, which is exit.
<?php
does something;
return;
exit;
?>
If you want to check whether a file was included or run directly, you could this answer.
So in that case, make a check in the child file, if it isn't included, goto the exit command, otherwise continue with the rest of the code.

How to exit a PHP script without calling the destructor?

Working with an MVC framework and the controller renders the page in the destructor. I am downloading a file through php, so at the end of the action the script should end.
How to end the script without calling the destructor?
Is there a better solution?
exit and die call the destructor.
See this answer.
Try creating a destructor in the class that downloads the file that checks if a file was indeed sent to the browser, and if so, call exit() in that destructor.
As David said: you'll need to call exit() inside a destructor to stop it.
If however you just want to halt the visual output caused by these destructors but not any other side-effects (file closing, database connection closing) they might do, then it's best to just kill the further output but leave the destructors alone. Which in my opinion would be the route to take since destructors tend to be there for one important reason: cleaning up.
you can do that by manipulating buffered output:
<?php
class Tester{
public function devNull($string){
return "";
}
public function runAndBreak(){
print "run" . PHP_EOL;
// if any output buffer is working, flush it and close it
if(ob_get_level()) ob_end_flush();
// redirect new buffer to our devNull
ob_start(array($this,'devNull'));
exit();
print "still running";
}
function __destruct(){
print "destructor" . PHP_EOL;
}
}
$t = new Tester();
$t->runAndBreak();
this will only print run and not what's in the destructor. It's done by giving your own callback routine to ob_start that handles and then returns the output. In our case here we simply discard it by returning an empty string.
This will certainly stop your script but be careful, if you run such a server where one process serves several PHP requests those will stop as well:
$pid = getmypid();
exec("kill $pid");
exec("TSKILL $pid");

PHP header in a loop

Is it possible to "call" a PHP script in a loop like this ?
...
while (...)
{
...
header("Location:myscript.php");
...
}
...
Nope. header("Location: ...") is supposed to redirect the browser to a different page, so only one of the calls you make will take effect.
What do you want to do?
You can always include the script from another to execute it's logic:
include('myscript.php');
In principle, this shouldn't require refactoring any myscript.php code. Be forewarned - myscript.php and the containing script will share the same global namespace, which may introduce bugs. (For instance, if the container outputs HTML and myscript calls session_start() a warning will be generated).
What you propose should work fine, however not in the way you expect. The header() function simply sends information to the browser in a single batch before the script content (You modify the http headers). So when the script finishes execution the browser will go to the specified page, hence only the last call to header('Location... will have any effect and that effect will only happen when the php script has finished executing.
A good way to do what I think you want to do would be to encapsulate the functionality of 'myscript.php' into a function.
include 'myscript.php';
while (...)
{
...
myscriptFunction();
...
}
...
You can call header() in a loop, but with the location header, the browser will only follow one.
location:<url> tells the browser to go to the url specified. it is known as a 301 redirect. Why you would call it in a loop, I don't know.
No. Rather pass it as a request parameter, assuming you're trying to redirect to self. E.g.
<?php
$i = isset($_GET['i']) ? intval($_GET['i']) : 10; // Or whatever loop count you'd like to have.
if ($i-- > 0) {
header("Location:myscript.php?i=" . $i);
}
?>
I however highly question the sense/value of this :)
Update, you just want to include a PHP script/template in a loop? Then use include() instead.
while ( ... )
include('myscript.php');
}
If it contains global code, then it will get evaluated and executed that many times.

Categories