How to flush output in ZF - php

I have a controller that, among other things, sends emails. I need to echo a message to the user before the email sending starts (otherwise it looks like the screen is stuck).
So, how do I echo a message which is set in the start of a controller, before I reach the end of the controller, or, should I think in another direction all together?

Try maybe:
<?php
//...
public function someAction()
{
echo "Something";
ob_flush();flush();
}
This forum post discusses your issue. They suggest:
<?php
$frontController = Zend_Controller_Front::getInstance();
$frontController->setParam('disableOutputBuffering', true);
And then performing the ob_flush();flush(); technique.

For the mail part of the question.
Depending on the timing - how soon after the request the message needs to be sent - another possiblity would be to create a message queue (maybe a db table), write a record to that table, and then run a cron process that consumes the queue, sending any unsent messages, marking them as sent, etc.

You could try using a shutdown function to send the email. If you also flush the output buffer this will make sure the user gets to see the rendered page first. In your code call:
register_shutdown_function('send_email', $params);
And then have a function that looks like:
function send_email($params) {
ob_flush();flush();
// Send your email here
}

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!

Get full output from a PHP script

I am running a script every night and the output of the script will only be send to a mail address. But the problem is that I need to receive a copy of the output in my own mailbox. I registered an shutdown handler in the script and I tried to send a mail with functions like ob_get_contents which actually shows data. But only the last thing I printed to the terminal.
cronMail('Cron', ob_get_contents());
The function called is just a simple function which adds the default receiver and sender and call the PHP Mail function.
The output in the mail is:
array()
While the terminal has te following output:
Starting cron...
Exiting...
array()
Can anyone tell me how to receive the whole output? I started the output buffer by using the ob_start method. And after each line I make sure there is an ob_flush method called so the output will also be send to the browser if the script is called directly.
ob_flush stands in your way, see the linked description on the manual page, it is pretty clear about that: It flushes the buffer so outputs it.
You do not want that. Remove the calls to it and you should be fine.
ob_start();
... your script without "ob_flush()" ...
$buffer = ob_get_clean(); # finally get the output buffer as string
echo $buffer; # pass output along for cron
cronMail('Cron', $buffer); # send your mail
This variant ensures that you get your own email but also the output is passed along to cron. This can be useful if you do some error reporting in the cronMail function, so that at least there is some way to further debug that.
Another alternative is to register an output handling function that stores the output on the go. But that is less trivial so I keep it out.

zend framework disable output for capture

I need to run post connection close processing (sending emails, refreshing caches etc) which take a long time. So in order to do this I have an action helper which will eventually down the line will check if anything needs to be done and process it.
Here's a simplified version of the output bit:
$this->getFrontController()->returnResponse(false);
$response = $this->getResponse();
$body = $response->getBody();
$response->setHeader('Connection', 'close');
ob_start();
echo $body;
$size = ob_get_length();
$response->setHeader('Content-length', $size);
ob_end_flush();
flush();
$this->run();
(Note, when live I intend on using fastcgi_finish_request but this also needs to work locally. $this->run() runs the post processing functions, no output here).
I keep getting the ol' hated Headers Sent error with this, but the exception returns no file or line number where it happened (I am guessing this is because of the nature of action helpers in Zend).
Some digging has got the error down to the setHeader() call. But I thought with returnResponse(false) they wouldn't auto send?
Is my logic to output this correct?
Edit:
Another issue is that getReponse doesn't return anything because the layout render hasn't been called, but calling Zend_Layout::getMvcInstance()->render(); gives me the layout with no content rendered to $layout->content ?
I guess ob_end_flush() sends $body, etc. but $this->run() tries to send the headers afterwards. Try to use something like $content = ob_get_contents(); and ob_end_clean() to save the buffer content to a variable and to clear the buffer without sending. Then, you can echo $content after sending your headers.

Using Jquery to update a page when a database is modified

I want to update a page when my database is modified. I want to use jquery for doing this. Question not clear? Then have a look at this, Suppose this is my page:
<?php
$query=mysql_query("select * from tbl1 where user='admin'");
if(mysql_num_rows?($query)!=0)
{
echo 'Table 1 has values';
} else {
echo 'Table1 is empty';
}
?>
This action should be performed whenever any new entry is added to the database. Now suppose I add an entry to the database manually then the page should automatically show the result as "Table1 has values". I know it can be used by using refresh page periodically but I don't want to use it. Instead I want to try something other, like ajax polling? Can someone give me a demo?
You can use long polling, but do a lot of research first. Your server may kill the request that appears to be open for a long amount of time.
In PHP, your code will look something like...
set_time_limit(0);
while (TRUE) {
// Query database here
if ($results) {
echo json_encode($results);
exit;
}
sleep(1);
}
You can use Ajax jQuery Framework with Ajax:
http://www.w3schools.com/Ajax/default.asp
http://api.jquery.com/jQuery.ajax/
It will call the server side script Asynchronously and update your page accordingly. You can use jQuery to specify the format of the update also.
You are looking for Ajax-Push/Comet solutions. These aren't trivial.
You also mentioned ajax pooling.
Well, on the server side you need to loop until you have a timeout (that you defined yourself or the server did, make sure you return the HTTP status code for Timeout Occured) or the request can be satisfied.
And on the client side whenever you complete the operation successfully just handle it and than make the same ajax call again, if you timed out just make the same ajax request again until it's satisfied.

Categories