Creating PHP cronjobs without cron and php-cli

Yesterday my internet connection was down due a problem with the line. It’s often when I don’t have a connection to the internet I come up with good idea’s.

A while ago I read in a blogpost that someone had a problem with wp-cron.php. It brought the server of the blogger to his knees. It was a bug in wp-cron.php that caused WordPress to keep starting these jobs bringing the webserver down. I don’t know if this bug is fixed now but I thought it would be one of those things you would check while progging the code.

Then again, WordPress is OOP code. I rest my case.

Anyway, while I have started my own Open-Source project ( still have to announce that here ) I needed to think of a way to let the webserver do a lot of work without slowing the experience of the user.

In other words, I needed to circumvent the fact that the user needs to wait until this work is finished. That is, when you would implement the code in a way that this work is being executed when a random user opens your software.

It would work this way:

  1. User opens one of your scripts.
  2. User waits for content to arrive.
  3. Server-side is being checked if there is any work to do
    ( for example: e-mailing, processing data into new mysql tables etc. )
  4. If there is server-side work ( in this case we assume there is ) the server is going to process this data.
  5. User needs to wait until this work is finished.

With this method you would have the problem that the user could just leave the page he’s browsing on because things take to damn long.
This isn’t a good option.

I already knew you can use Cron in combination with a php cli script for this.
This all happens server-side. Cron fires every x minutes/hours/days the php cli script that checks for work that needs to be done and then executes this work.
Advantages:

  • Users don’t need to wait until the script finished and won’t notice anything ( because the script that executes the work isn’t implemented in the code that users access ).
  • You’re sure the work is being executed every x minutes/hours/day.

Disadvantage:

  • This is for n00bs difficult to set up. Without ssh access it’s already complicated to add jobs to cron. Also, in the case of an Open-Source project you would have handle a LOT of questions regarding this. This simply isn’t practical.

There’s a third solution. I have implemented this before. You can use shell_exec in php to execute the script via the user interface. Another problem you’re facing here is that you have to build status script ( possible with ajax or an iframe ) that checks the status of the work that is being done and if the job is already started. You would also face problems with scripts that do not have the right rights to execute the script.

I evaluated the above possibilites and concluded that these weren’t options. I knew WordPress did something with opening their own scripts to make the server-side cronjobs execute.

I tried to make a script to open itself with file_get_contents(). This works, but the user still needs to wait until the file_get_contents() request is finished. This is exactly the same problem as with the first case, so this doesn’t work.

My internet connection still wasn’t back so I decided to fool around with php myself. Maybe I could found a solution to this problem.

Then I got it. Socket connections. Simple socket connections.
I knew this could work in theory:

  • Open the connection to yourself, to a php script that does the work.
  • Don’t wait until the data is coming back, just close the damn socket.

But what about the server-side parsing time? That would be problematic.

Here’s a POC for this method:
Make sure that this script is in the document root otherwise this won’t work. Sorry for the bad indentation. WordPress seems to completely ignore all my efforts in putting spaces, tabs or any form of space before my code lines.

index.php:

<?php
//Open socket connection to cron.php
$socketcon = fsockopen($_SERVER['HTTP_HOST'],80,$errorno,$errorstr,10);
if($socketcon) {
$socketdata = "GET /cron.php HTTP 1.1\r\nHost: ".$_SERVER['HTTP_HOST']."\r\nConnection: Close\r\n\r\n";
fwrite($socketcon,$socketdata);
//Normally you would get all the data back with fgets and wait until $socketcon reaches feof.
//In this case, we just do this:
fclose($socketcon);
} else {
//something went wrong. Put your error handler here.
}
?>

cron.php:

<?php
//This script does all the work.
sleep(200);
//To prove that this works we will create an empty file here, after the sleep is done.
//Make sure that the webserver can write in the directory you're testing this file in.
$handle = fopen('test.txt','w');
fclose($handle);
?>

As you can see cron.php sleeps for 200 seconds and then creates a file. But wait, isn’t the parse time a problem? Well, apparently not.
This probably has something to do with way browser-server interaction and php works, but the above method actually works. The parse time isn’t a problem anymore.
It would even more practical to make this script open a socket connection to itself. This way the request would look this:

$socketdata = "GET /".$_SERVER['PHP_SELF']."?secret=hash HTTP 1.1\r\nHost: ".$_SERVER['HTTP_HOST']."\r\nConnection: Close\r\n\r\n";

This way the location of the script in the directories is dynamic and it doesn’t matter where it is.

A few things to keep in mind:

  • Make sure that when you’re opening your own script, you don’t create infinite loops just like the WP guys did.
  • The user needs to open this script. He won’t notice anything, but we need to make sure that the cronjobs are only executed when the script wants this to happen. In other words, a user can’t ddos the server by opening this script very often. The use of a secret hash to give as a url parameter to the script would solve this. Note that this hash has to change everytime.

Well, there we have it.
Server-side cronjobs with php without the problem of the php parse-time limit. Users don’t need to do anything than install your script and it works.
It’s easy and practical. Oh yeah, before I forget to mention that: This works in safe-mode. A lot of people actual are bugged by safe mode because their webmasters are paranoid people and decide to turn this on while safe mode clearly is deprecated.

My following post will probably be about ignorant people in all kinds of business and places.
This is an addition/response to Jorrizza’s blogpost about OOP programmers. There will probably also a post in the
future about the Open-Source project I’m working on. I will announce this when the first beta of that software is ready.

This entry was posted in Tech. Bookmark the permalink.

8 Responses to Creating PHP cronjobs without cron and php-cli

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.