Is there anyway I can check when file_get_contents has finished loading the file, so I can load another file, will it automatically finish loading the one file before going onto the next one?
Loading a file with file_get_contents() will block operation of your script until PHP is finished reading it in completely. It must, because you couldn't assign the $content = otherwise.
PHP is single threaded - all functions happen one after the other. There is a php_threading PECL extension if you did want to try loading files asynchronously, but I haven't tried it myself so I can't say if it would work or not.
simple example that will loop through and get google.co.uk#q=* 5 times and output if it got it or not, pretty useless but kinda answers your question that a check can be done to see if file_get_contents was successful before doing the next one, obviously google could be changed to something else. but wouldn't be very practical. plus output buffering dont output within functions.
<?php
function _flush (){
echo(str_repeat("\n\n",256));
if (ob_get_length()){
#ob_flush();
#flush();
#ob_end_flush();
}
#ob_start();
}
function get_file($loc){
return file_get_contents($loc);
}
for($i=0;$i<=5;$i++){
$content[$i] = #get_file("http://www.google.co.uk/#q=".$i);
if($content[$i]===FALSE){
echo'Error getting google ('.$i.')<br>';
return;
}else{
echo'Got google ('.$i.')<br>';
}
ob_flush();
_flush();
}
?>
Related
I have a problem where I call a PHP function on page load - the function checks to see if a file exists it returns the filename, if it doesn't exist it runs a script which is fairly resourceful and takes time - converting a waveform image from an audio file. The problem is the audio files are large so creating the file can take some time, so if the audio file doesn't have this image file associated with it the page load takes as long as the process does.
What I'm after is for this function to return a placeholder image if one doesn't exist, but carry on with the process after the page is loaded - or in the background. So in theory when the page is reloaded at a later date the correct image will be there.
I can get the return of the placeholder image currently but then the process stops and the image doesn't get generated. Here's what I have so far:
function example($file_path, $file_name) {if ($file_path) {
if (file_exists("/path/to/folder/{$file_name}.png")) {
return "/path/to/folder/{$file_name}.png";
}
if (!file_exists("/path/to/folder/{$audio_file_name}.png")) {
return "/path/to/folder/processing.png";
Some stuff in here
return $new image
} return FALSE
As you can see this just stops when the file doesn't exist but I want the stuff in here to continue in background. Is it possible or do I need a different approach? Like a cron job or something? Any help appreciated.
You might try a queuing system like resque https://github.com/chrisboulton/php-resque
You then can generate a job, that processes the information and quite fast return with the "processing" image.
With this approach you won't know when it is finished though.
In my experience this is still easier than arguing with the operations guys to compile php with multi threading support.
I'd do it with AJAX. If the image is found, just put it there.
Otherwise, put the placeholder, and add a JS flag with data to load the waveform image.
In the PHP code that generates HTML Document, no conversion happens. And you have another request handler to handle requests coming from JS, that makes the conversion with suppied data.
The data created originally on HTML Document generation code will be passed to JS, which will use it to send a request for the conversion. While JS waits for response, you handle to loading time, and when response comes you put it on the placeholder.
If you're running on FastCGI / FPM you could consider doing the following:
You put a regular <img> tag with the src attribute pointing to your script.
If your script needs to regenerate, you make the browser redirect to a processing image.
If the image is ready, you redirect to the created image (you could do an AJAX poll on the page as well)
How to do step 2?
Normally, the browser has to wait for your script to end before performing a render or redirect; but FastCGI (PHP-FPM) has a special function for this: fastcgi_finish_request. It's largely undocumented, but its use is simple:
if ($need_to_process) {
header('Location: /path/to/processing.png');
fastcgi_finish_request();
// do processing here
} else {
header('Location: /path/to/final_image.png');
}
Alternative
You can apply it to your existing process as well if you have a template that you can immediately render just before doing fastcgi_finish_request().
Yet another alternative
Use a task scheduler like Gearman.
you can use "try" and "finally"
try {
return "hello world";
} finally {
//do something
}
I am not able to comment because my reputation is below 50, but I wanted to note something on mohammadhasan's answer. It seems to work but avoid 'return' statement in both try and finally block
try {
return "hello world";
} finally {
//do not put return here
}
Example:
function runner() {
try {
return "I am the trial runner";
} finally {
return "I am the default runner";
}
}
echo runner();
Will only show I am the default runner.
I developed a facebook application in PHP. The problem is that it takes 2 minutes to display the result. This might confuse the user, who sees a blank canvas and leaves.
I just want to echo a statement that it is still processing.
I tried flush(); and ob_flush(); and ob_start(); but it is of no use.
Is there any other simpler alternative to address my specific problem?
I tried this, but it did not work as well.
ob_implicit_flush(true);
ob_end_flush();
for ($i=0; $i<5; $i++) {
echo $i.'<br>';
sleep(1);
}
EDIT:
The above code works perfectly fine with IE and other Browsers.
Only Chrome has this issue.
Convert it to an AJAX request, where you load a quick page which can have anything you want, and then loads in data from the slower page in the background.
flush() won't do what you want because it will return only part of the output and the client will tend to wait for the complete page.
Call flush(); as often as required.
Unfortunately, this might or might not make the browser feel happy to display your stuff. Even on IE, the result isn't predictable.
I am using flash to call a PHP page that needs to do a bit of processing. Is it possible to let PHP continue processing but show a response anyway so flash doesn't stall waiting?
My answer from here:
You can send Connection:Close headers,
which finishes the page for your user,
but enables you to execute things
"after page loads".
There is a simple way to ignore user
abort (see php manual too):
ignore_user_abort(true);
Use output control aka output buffering to do this. http://www.php.net/manual/en/function.ob-flush.php
You could try using flush()
As an example, try these two different pieces of code:
// without flush()
foreach ( range(1, 5) as $num ) {
echo "Beep $num<br>";
sleep(1);
}
// with flush()
foreach ( range(1, 5) as $num ) {
echo "Beep $num<br>";
flush();
sleep(1);
}
You can close the connection within a registered function within register_shutdown_function if you do not need to wait for the processing to be over to output content (i.e., if you do not need to output anything related to the outcome of the processing you wish to do).
See : http://www.php.net/manual/en/features.connection-handling.php#93441
The reason to put it in a register_shutdown_function is that even if the client aborts the connection, the processing will keep on going to the very end.
How does the server knows that i've closed the browser in a code like this?
<?php
$i = 0;
while (1) {
echo "a";
flush();
$fp = fopen("$i.txt", "w");
fclose($fp);
sleep(1);
$i++;
}
?>
If i close the browser, the script stops and no more files are created.
This is because when you try to output something, such as echo "a"; flush();", PHP sees that the request has been aborted, and therefore stops the request.
Just a quick note. This only happens when you output something. I'm guessing this is because PHP was primarily used for templating, and designed mainly for outputting content. Well, if the content is not going to go anywhere, why continue processing the script?
If you don't want it to stop. Do one of the following:
Option A: Don't output anything.
flush() and echo are both considered outputs, along with many other functions. PHP only checks to see if a user has aborted when it goes to send content, so not outputting anything will make sure it doesn't check. Although that is probably not as reliable as...
Option B: use ignore_user_abort(true)
This will make sure that the script continues to output even if the user leaves the page. You can then check with connection_aborted() to find out if the connection has been aborted.
You can read all of this on PHP's Connection Handling Documentation.
If I'm generating a stream of data to send out to a browser, and the user closes the browser, can I tell within PHP that I don't need to bother generating or sending the rest of the stream? I'd like to insert something into this loop:
while (!feof($pipes[1])) {
echo fgets($pipes[1]);
}
My fallback plan is to have the browser use a JavaScript onunload to hit another PHP page to kill the process that's generating the data, but it would be cleaner if PHP could tell when I'm echoing to nowhere.
By default PHP will abort the script if the user navigates away. There are however times where you don't want this to happen so php has a config you set called ignore_user_abort.
http://php.net/manual/en/misc.configuration.php
There's also a function called register_shutdown_function() that is supposedly executed when execution halts. I've never actually used it, so I won't vouch for how well it works, but I thought I'd mention it for completeness.
I believe that script will automatically abort when loaded normally (No ajax). But if you want to implement some sort of long polling via php using xmlhttprequest I think you will have to do it with some sort of javascript because then php can't detect it. Also like to know the precise case.
These answers pointed me towards what I was looking for. The underlying process needed special attention to kill it. I needed to jump out of the loop. Thanks again, Stack Overflow.
while (!feof($pipes[1]) && !connection_aborted())
{
echo fgets($pipes[1]);
}
if (connection_aborted())
{
exec('kill -4 '.$mypid);
}