Last updated September 23, 2009. Created by Epskampie on April 13, 2008.
Edited by tsunami7. Log in to edit this page.
Create a new file preferably in the same directory as your drupal dir. Name it 'cronall.php' or something. Copy the following script into it. Then adjust the settings in the file, and visit the script with your webbrowser, to see if it is setup correctly.
Then create a cronjob for the cronall.php script, and you're done.
<?php
/**
* This script scans the sites directory, and uses a regular expression to extract the sitenames.
* It then uses this sitename to execute the cronjob for these sites.
* You then only have to create a cronjob for this script.
* In this way, you can create and delete sites on the fly, but all their cronjobs will be executed.
*/
/***********
* SETTINGS
**********/
//the location of the 'sites' directory relative to this script.
$sitesDir = '../drupal/sites';
/**
* A regular expression that matches the name of the directories in
* the 'sites' dir that you want to execute cronjobs for, with a
* backreference around the actual site name. (so we can exclude the
* domain part)
*
* If you don't know regular expressions you might want to brush up
* on them: <a href="http://www.regular-expressions.info/tutorial.html
" title="http://www.regular-expressions.info/tutorial.html
" rel="nofollow">http://www.regular-expressions.info/tutorial.html
</a> *
* Alternatively, you can just copy the name of one of the directories
* in the site dir, put a backslash \ in front of all dots . and replace
* the actual name of the site with ([a-zA-Z0-9_-])
*/
$siteNameRegExp = 'www\.example\.com\.([a-zA-Z0-9_-])';
//the url of the cron script, you should insert %s where the sitename should be inserted later.
$cronUrl = 'http://www.example.com/%s/cron.php';
//any other sites that you want to execute cronjobs for. Just comment this if you haven't got any.
$addedSites = array('drupal');
/***********
* END SETTINGS
**********/
error_reporting(E_ALL);
$sites = array();
$handle = opendir($sitesDir);
while ($file = readdir($handle)) {
if(ereg($siteNameRegExp, $file)){
$sites[] = ereg_replace($siteNameRegExp, '\\1', $file);
}
}
//default site
if(isset($addedSites) && is_array($addedSites)){
$sites = array_merge($sites, $addedSites);
}
foreach($sites as $site){
$cmd = 'wget --spider '.sprintf($cronUrl, $site);
echo 'Executing command: '.$cmd.'<br>';
exec($cmd);
}
?>
Comments
Manual multisite cron
If you have many multisites, some not requiring cron.php or some even pointing to the same site (aliases), you may want to just define the list of sites to cron manually, below is a simplified version of the script that does this...
<?php
/**
* You only have to create a cronjob for this script.
* In this way, you can create and delete sites at will, but all their cronjobs will be executed.
*/
//cronUrl is the url of the cron script, you should insert %s where the sitename should be inserted later.
$cronUrl = 'http://%s/cron.php';
error_reporting(E_ALL);
$sites = array();
$sites[] = 'site1';
$sites[] = 'site2';
$sites[] = 'site3';
$sites[] = 'site4';
// add as many as needed, the value should be the root url you use to access each drupal site, ie. <a href="http://www.mysite1.com" title="www.mysite1.com" rel="nofollow">www.mysite1.com</a> or www.mysite.com/drupal
foreach($sites as $site){
$cmd = 'wget --spider '.sprintf($cronUrl, $site);
echo 'Executing command: '.$cmd.'<br>';
exec($cmd);
}
?>
------
Con paciencia y calma,
sube un burro a una palma
------
Con paciencia y calma,
sube un burro a una palma
Relief 2.0 - http://www.relief20.com
Navidad Latina - http://www.navidadlatina.com
Manual multisite cron via url argument
Not sure when you might need this, but this is another variation I tested while looking for a solution...
It is yet another simplified version of the script above, but this one allows you to pass the site as an argument in the url that calls the cron...
<?php
$drupal_sites_dir = 'c:/xampp/htdocs/drupal/sites/';
/* something like '/home/account/public_html/sites/', '/home/account/public_html/drupal/sites/' or 'c:/xampp/htdocs/drupal/sites/' */
$default_site_domain = 'defaultsite.com';
/* site to use in case invalid argument is passed or no argument is passed */
/*
verify the validity of GET var page.
this prevents passing an invalid argument (a site that does not exist)
if not set, set to default site
*/
if(isset($HTTP_GET_VARS['sitetocron']))
{
if (file_exists($drupal_sites_dir.$HTTP_GET_VARS['sitetocron'])) {
$sitetocron = $HTTP_GET_VARS['sitetocron'];
} else {
$sitetocron = $default_site_domain;
}
}
else
{
$sitetocron = $default_site_domain;
}
$cronUrl = 'http://'.$sitetocron.'/cron.php';
error_reporting(E_ALL);
$cmd = 'wget --spider '.$cronUrl;
echo 'Executing command: '.$cmd.'<br>';
exec($cmd);
?>
------
Con paciencia y calma,
sube un burro a una palma
------
Con paciencia y calma,
sube un burro a una palma
Relief 2.0 - http://www.relief20.com
Navidad Latina - http://www.navidadlatina.com
If you don't have Shell permission
My shared hosting account doesn't allow me to execute shell scripts or command line programs like wget, curl etc.
However I can use PHP Curl. So, here's my version of cronall.php:
<?php
/**
* You only have to create a cronjob for this script.
* In this way, you can create and delete sites at will, but all their cronjobs will be executed.
*/
error_reporting(E_ALL);
$sites = array();
$sites[] = 'http://www.exampe.com';
$sites[] = 'http://www.example2.com';
// add as many as needed, the value should be the root url you use to access each drupal site
$ch = curl_init();
foreach($sites as $site){
curl_setopt($ch, CURLOPT_URL, $site."/cron.php");
curl_exec($ch);
}
curl_close($ch);
?>
Peacog Web Development
Had the same issue
Had the same issue, script worked a treat.
Thanks for sharing :)
Cron with Python
I could not run neither wget, curl, lynx nor exec in php scripts, but I had python instead. Just in case you are interested (and because it is the only way I found I was able to run cron for multisite) I share a small python script.
import sys, urllibdef reporthook(*a): print a
for url in sys.argv[1:]:
i = url.rfind('/')
file = url[i+1:]
print url, "->", file
# urllib.urlretrieve(url, file, reporthook)
urllib.urlopen(url)
so my cron entry will be:
/path/to/python wget.py url1/cron.php url2/cron.php_____
http://davebv.com
Easy multisite crontab ...?
I am running 3 sites on one drupal code base.
The following crontab entry seems to work fine (no scripts necessary):
45 * * * * /usr/bin/wget -O - -q -t 1 http://www.site1.com/cron.php
46 * * * * /usr/bin/wget -O - -q -t 1 http://www.site2.com/cron.php
47 * * * * /usr/bin/wget -O - -q -t 1 http://www.site3.com/cron.php
ereg functions in PHP 5.3
My reading of the PHP documentation indicates that the use of ereg and ereg_replace are deprecated in PHP 5.3, and should no longer be used. They recommend using preg_match() and preg_replace() instead.
Also my understanding of the original script here is that it doesn't deal with sites built as sub-domains, eg. http://site1.example.com/. I've attempted to create a more robust/maintenance free Multi-Site cron script, which is Step 10 of my blog post for setting up a Multi-Site development environment for OS X. Those interested can find it at:
http://blogs.martiangraphix.com/2009/09/building-a-drupal-development-en...
Hope this helps.
Michael
Martian Graphix, Inc
PHP6 version with extra config options
Here's a version that doesn't use ereg, so should be PHP6 compatible. I did not test PHP 6 compatibility though, but the script is tested and works fine under PHP 5.2.
I wanted to keep in the automatic multisite url finder, and added a configuration option to be able to exclude domains from the cron run.
You can still manually add domains if you want to, and I also added an option which allows to set the cron commands to CURL if WGET is not an option.
By default it does not include your default sites cron, but it can easily be added, just look at the comments in the script.
<?php
/**
* This script scans the sites directory, and extracts the sitenames.
* It then uses this sitename to execute the cronjob for these sites.
* You then only have to create a cronjob for this script.
* In this way, you can create and delete sites on the fly, but all their cronjobs will be executed.
*/
/***********
* SETTINGS
**********/
//the location of the 'sites' directory.
$sitesDir = '/home/cpanelusername/public_html/sites';
//the url of the cron script, you should insert %s where the sitename should be inserted later.
$cronUrl = 'http://www.%s/cron.php';
//any other sites that you want to execute cronjobs for. Just comment this if you haven't got any.
$addedSites = array();
//$addedSites[] = 'example.com'; //for example your default domain
//Remove sites that you don't want to execute cronjobs for. The ., .., all, and default are just there to remove those directories from the cron list, it does not remove the default site.
$removedSites = array();
$removedSites[] = '.';
$removedSites[] = '..';
$removedSites[] = 'all';
$removedSites[] = 'default';
//$removedSites[] = 'nocronexample.com';
//set cron command style to curl or wget
$cronstyle = 'wget';
/***********
* END SETTINGS
**********/
error_reporting(E_ALL);
$sites = array();
$handle = opendir($sitesDir);
while ($file = readdir($handle)) {
$sites[] = $file;
}
//adding manually added sites
if(isset($addedSites) && is_array($addedSites)){
$sites = array_merge($sites, $addedSites);
}
//removing manually removed sites
if(isset($removedSites) && is_array($removedSites)){
$sites = array_diff($sites, $removedSites);
}
foreach($sites as $site){
if($cronstyle == 'curl') {
$cmd = 'curl --silent --compressed '.sprintf($cronUrl, $site);
} else {
$cmd = 'wget --spider '.sprintf($cronUrl, $site);
}
//echo 'Executing command: '.$cmd.'<br>';
exec($cmd);
}
?>
In my opinion the neatest option would be a Drupal 'cron manager' module for the default domain from which you could configure / hook cron runs for the other sites in the multi site installation.
Something to be aware of: I think this PHP script has its limitations regarding execution time. I don't know if for example the 2nd site's cron will run if the 1st in the list is exceeding maximum script execution time. I guess it just doesn't. :)
I uploaded this script in a folder that is not web accessible, so not everyone can just run the multisite cron script.
I added this command to execute the script silently: php -q /home/cpanelusername/cronmultisite.php
But that is just one of the many possible ways.
Multicron PHP5
I had some problems with the script above. so i rewrite it to php5 and uses some ideas postet before.
<?php
/**
* This script scans the sites directory, and uses a regular expression to extract the sitenames.
* It then uses this sitename to execute the cronjob for these sites.
* You then only have to create a cronjob for this script.
* In this way, you can create and delete sites on the fly, but all their cronjobs will be executed.
*/
/***********
* SETTINGS
**********/
//the location of the 'sites' directory relative to this script.
$sitesDir = '/sites'; // your drupal sites directory
/**
* A regular expression that matches the name of the directories in
* the 'sites' dir that you want to execute cronjobs for, with a
* backreference around the actual site name. (so we can exclude the
* domain part)
*
* If you don't know regular expressions you might want to brush up
* on them: <a href="http://www.regular-expressions.info/tutorial.html
" title="http://www.regular-expressions.info/tutorial.html
" rel="nofollow">http://www.regular-expressions.info/tutorial.html
</a> *
* Alternatively, you can just copy the name of one of the directories
* in the site dir, put a backslash \ in front of all dots . and replace
* the actual name of the site with ([a-zA-Z0-9_-])
*/
$siteNameRegExp = '([a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+)';
//the url of the cron script, you should insert %s where the sitename should be inserted later.
$cronUrl = 'http://www.%s/cron.php';
//any other sites that you want to execute cronjobs for. Just comment this if you haven't got any.
//$addedSites = array('drupal');
/***********
* END SETTINGS
**********/
error_reporting(E_ALL);
$sites = array();
$handle = opendir($sitesDir);
while ($file = readdir($handle)) {
if(preg_match($siteNameRegExp, $file)){
preg_match($siteNameRegExp, $file, $site);
$sites[] = $site[0];
}
}
//default site
if(isset($addedSites) && is_array($addedSites)){
$sites = array_merge($sites, $addedSites);
}
foreach($sites as $site){
$cmd = 'wget --spider --tries=3 '.sprintf($cronUrl, $site);
echo 'Executing command: '.$cmd.'<br>';
exec($cmd);
}
php?>
So...
Does anyone have a version of this that actually works?
Yes, the code in
Yes, the code in https://drupal.org/node/246091#comment-1161351 works all right.
But, to counter execution time problems, I'd add a shuffle($sites) line to make sure that the sites get called in a random order. This way, even if one site's cron takes longer and times out, other sites will get a chance sooner or later.
This works for php5 drupal 7 multisite
Here is a mod of some of the scripts that have been posted and it should work without any problems. Create a file called cronall.php and drop the contents below in. Here are some changes.
1) Scan's the 'sites' directory and brings in a list of the directories
2) Files and dot directories (.,..) are removed from the list
3) You can manually add directories in using $addedSites string array (see comments)
4) You can manually remove directories by using $removeSites string array
5) There is a test loop that will print out the list of directory names that is commented out but can be enabled to double check the list.
This was built from the previous posts above so all credit where credit is due...
Lagpro
<?php
/**
* This script scans the sites directory, and uses a regular expression to extract the sitenames.
* It then uses this sitename to execute the cronjob for these sites.
* You then only have to create a cronjob for this script.
* In this way, you can create and delete sites on the fly, but all their cronjobs will be executed.
*/
/***********
* SETTINGS
**********/
//the location of the 'sites' directory relative to this script.
$sitesDir = 'sites'; // your drupal sites directory
/**
* A regular expression that matches the name of the directories in
* the 'sites' dir that you want to execute cronjobs for, with a
* backreference around the actual site name. (so we can exclude the
* domain part)
*
* If you don't know regular expressions you might want to brush up
* on them: <a href="http://www.regular-expressions.info/tutorial.html
" title="http://www.regular-expressions.info/tutorial.html
" rel="nofollow">http://www.regular-expressions.info/tutorial.html
</a> *
* Alternatively, you can just copy the name of one of the directories
* in the site dir, put a backslash \ in front of all dots . and replace
* the actual name of the site with ([a-zA-Z0-9_-])
*/
$siteNameRegExp = '([a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+)';
//the url of the cron script, you should insert %s where the sitename should be inserted later.
$cronUrl = 'http://www.%s/cron.php';
// Add any additional sites
//any other sites that you want to execute cronjobs for. Just comment this if you haven't got any.
//$addedSites = array('drupal');
// example: $addedSites[0] = "test.com";
// Remove any additional sites
//any other sites that you want to remove from the execution cronjobs for.
//$removeSites = array('drupal');
// example: $removeSites[0] = "test.com";
/***********
* END SETTINGS
**********/
error_reporting(E_ALL);
$sites = array();
$handle = opendir($sitesDir);
while ($file = readdir($handle)) {
//
// Let's remove any files from the list so we only get site directories
//
if (is_dir($sitesDir . '/' . $file)) {
if(preg_match($siteNameRegExp, $file)){
preg_match($siteNameRegExp, $file, $site);
$sites[] = $site[0];
}
}
}
//add any additional sites
if(isset($addedSites) && is_array($addedSites)){
$sites = array_merge($sites, $addedSites);
}
// remove any sites from processing
if(isset($removeSites) && is_array($removeSites)){
foreach ($removeSites as $removeit) {
for ($countit = 0; $countit < COUNT($sites); $countit++) {
if ($sites[$countit] == $removeit) unset($sites[$countit]);
}
}
$sites = array_values($sites);
}
//
// for testing reasons
//
//foreach($sites as $site){
// echo $site . ' <br>';
//}
foreach($sites as $site){
debug($ste);
$cmd = 'wget --spider --tries=3 '.sprintf($cronUrl, $site);
echo 'Executing command: '.$cmd.'<br>';
exec($cmd);
}
php?>
Contains errors ?
I'm no PHP expert, so I cannot debug this.
But when I run this cronall.php, I receive errors for lines 89, 94.
line 89: "command debug unknown", can I remove this line?
line 89: variable $ste should be $site ?
line 94: php?> should be ?>
Another thing, this script appears to call the url of cron.php without the appropriate cron key. As such the cron command is not executed.
Or am I seeing things terribly wrong?
Yes, on all three
Yes, on all three counts.
Actually, there is some elegance in reading up the possible sites in that way. But if there is a stable setup with base URLs not changing very often or at all, this much easier approach has been serving me for quite some time without any problem:
<?php
error_reporting(E_ALL);
$sites = array();
$sites[] = 'http://www.example.com';
$sites[] = 'http://www.anotherexample.com';
// add more sites...
shuffle($sites);
$ch = curl_init();
foreach ($sites as $site) {
curl_setopt($ch, CURLOPT_URL, $site .'/cron.php');
curl_exec($ch);
}
curl_close($ch);
I simply put it into a cronall.php and call that regularly from the server.
Exec() have not been worked for me
May be it depends on my hoster, but exec() have not been worked for me and i used this code to run crons:
$result = file_get_contents(sprintf($cronUrl, $site));echo 'Result:'.$result.'<br>';