5

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.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Ben Sonley
  • 79
  • 1
  • 5

5 Answers5

3

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.

scones
  • 3,317
  • 23
  • 34
  • not worried about showing time at this stage, no heard of this before so will take a look - but after having a brief browse through the readme and package it looks quite difficult to implement for someone with my skill levels. I could be wrong though! – Ben Sonley Feb 15 '13 at 01:04
2

If you're running on FastCGI / FPM you could consider doing the following:

  1. You put a regular <img> tag with the src attribute pointing to your script.

  2. If your script needs to regenerate, you make the browser redirect to a processing image.

  3. 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.

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
  • i like this approach, but i give it a quick test run but it seems to stop the page load half way down and the process isnt starting, not sure i've implemented it correctly or not understanding maybe. Currently the function is located on helper.php and is called from a view.php page using what u have suggested in stage 1. but where the image is displayed the page load stops. – Ben Sonley Feb 15 '13 at 01:01
  • @BenSonley By the time you call `fastcgi_finish_request()` the whole page MUST be done rendering. – Ja͢ck Feb 15 '13 at 10:30
  • ahh ok - that wont work then as this is part of a CMS template - ive also noticed i don't have fastcgi - it's the plesk version which is apparently different. So that complicates matters maybe. – Ben Sonley Feb 15 '13 at 18:22
  • @BenSonley that's unfortunate. I guess it's either task scheduler or background process then :) – Ja͢ck Feb 15 '13 at 18:28
2

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.

Hikari
  • 3,797
  • 12
  • 47
  • 77
0

you can use "try" and "finally"

try {
    return "hello world";
} finally {
    //do something
}
Daniel
  • 9,491
  • 12
  • 50
  • 66
  • 2
    While this code snippet may be the solution, including an explanation really helps to improve the quality of your post. It will be helpful for future users as well. – Sangam Belose Jun 28 '19 at 12:34
  • This doesn't work because you don't get the return until after the finally block has executed: https://www.php.net/manual/en/language.exceptions.php – Lars SG Jun 16 '23 at 19:14
0

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.

Pingolin
  • 3,161
  • 6
  • 25
  • 40
kimoduor
  • 504
  • 6
  • 16