how to make a php automation background script for Windows and Unix?

1.1k views Asked by At

I have a script that creates thumbnails of larger images and it works fine, the problem is that it is placed at the beginning of the page where both images are viewed and to my understanding would run every time someone visits the page. This doesn't seem very performant.

I would rather the script have its own page and somehow detected when more large images had been added to the directory it scans and go to work then.

How would i go about setting this up or improving it in someway?

found this, not sure how it works. what is $cmd:

  /*I combined several efforts in this topic into one function: 
This will execute $cmd in the background (no cmd window) 
without PHP waiting for it to finish, on both Windows and Unix.*/
    function execInBackground($cmd) { 
        if (substr(php_uname(), 0, 7) == "Windows"){ 
            pclose(popen("start /B ". $cmd, "r"));  
        } 
        else { 
            exec($cmd . " > /dev/null &");   
        } 
    } 
3

There are 3 answers

5
Akarun On

Time base creation : Perhaps (if you have a shell access), you can create a "Cron job" :

In ''/etc/crond.d/'' Create a file like this :

0 6-18 * * *    root    /path/to/your/script.php >> /dev/null 2>&1

It will be execute every hour from 6.00 to 18.00.

See : http://en.wikipedia.org/wiki/Cron for more details.

Automatic Creation : If you have an "upload procedure", put simply the "Thumbnail generator" after uploading.

Hook Creation : Indeed, it depend of the procedure you use to add new images in your directory.

Perhaps, you can also make a hook to execute the script after updating the dir.

But I think the first solution based on time (cron) is the most easy to implement.

0
Jevgenij Evll On

As stated in another answer, cron would be your best bet, but it is available on Linux only (perhaps Windows has another alternative). However, if you need a platform independent solution or you don't have access to your server's configuration you could stick to your original solution (generate thumbnail on every page load), but modify it for efficiency using the CronExpression class: https://github.com/mtdowling/cron-expression

Using this class you would simply define a cron execution expression, like this one:

0 6-18 * * *

and then check if thumbnail regeneration task should be executed:

$cron_expression = Cron\CronExpression::factory($cron_schedule);
$next_run_date = $cron_expression->getNextRunDate();
if ($next_run_date <= new DateTime()) {
    //execute task
}
0
LSerni On

You can do this in several ways.

The best way, IMHO, is to break the script into a "directory scanning" part, which decides what images are in need of thumbnailing by comparing timestamp of source and existence and timestamp of destination.

The second part thumbnails only one image at a time.

Then, you can run the second part of the script and only thumbnail the image when the thumbnail is requested:

<?php
    ...
    $run = true;
    if (file_exists($thumbnail))
        if (filemtime($thumbnail) > filemtime($source))
            $run = false;
    if ($run)
    {
        // run, say, ImageMagick and convert $source to $thumbnail

        if (!$success)
            $thumbnail = './images/sorry-error-in-thumbnailing.jpg';
    }
    Header("Content-Type: image/jpeg");
    Header("Content-Length: " . filesize($thumbnail));
    readfile($thumbnail);
?>

Of course, if you are liable to have to generate lots of thumbnails at a time, this is dangerous because you might run lots of copies of the thumbnailer, hogging your server CPU.

Let me clarify: you put the above script in place of IMG SRC="thumbnail1234.jpg"
request. Then the user viewing the page with the thumbnails will start several
requests for thumbnail.php?source=image123, ...?source=image235 and so on. They
will run in parallel, and most of them (if the thumb is there) can read the thumbnail
or issue a 302 Redirect to it, both very fast and with little server load.
ONLY IF the thumbnail isn't there, THAT image will appear after a delay because it
is generated and served directly. The user will see most, maybe all, images loading
instantly, and some of them lag behind a little (ideally).

In that case you can run a system load check before popening, or you can keep a running account of the processes being run.

You might limit one thumber to run at a time by checking if "tempthumbnail.jpg" exists and is no older than $SECONDS seconds, thumbing $source to tempthumbnail.jpg and then renaming tempthumbnail to $thumbnail; and/or using flock() if the system allows it reliably. Or you might store the number of processes running in a database:

query("UPDATE sysvars SET runner = runner + 1;");
shell_exec("...");
query("UPDATE sysvars SET runner = runner - 1;");

Otherwise you can run the script every now and then, through cron or also at the beginning of your script, when you see that the previous run was more than $TIME seconds ago. Or you can check a flag (or the filemtime() of the source directory) when you upload an image to be thumbed.

In the latter case, if you're in control of uploads, run the thumber immediately after the upload completes. The user's upload will serialize your thumbing processes, and it is highly unlikely that whatever operation is done to "show" the new images will be activated so soon after an upload; therefore, it is conversely HIGHLY probable that when the user says, "OK, activate image 12345", the thumbnail of 12345 has already been done and is ready to "instantly" show.

Much depends on how the thumbing script runs. if it always regenerates all thumbnails, the inefficiency is there. If it checks, then a "dry run" is simply a read of a whole directory and a bunch of stat() calls, which are quite fast. Unless you run on thousands of images, you've little to worry.