1

I have a cronjob system with PHP. I have a file named cron.php and wanna to check if it is not loaded, load it. it is very important to me that this file run only one time and I need the way how define it is already running. I can't use any system functions like exec,system,... do you have any solutions?

NOTE: I run my script trough CURL and include_one and require_once don't work for this case.

IVIR3zaM
  • 567
  • 9
  • 23
  • 2
    Do you mean that you want to avoid the cron job cron.php running if an existing one is already executing? (because that is way different that the answers you're currently getting so you should clarify..) – Ben May 08 '12 at 07:28
  • sir see my answer and let me know if i am lagging somewhere – NullPoiиteя May 08 '12 at 07:55
  • 1
    You will have to store the last execution time of your script somewhere (database, text file). Then check the last execution time/date (userID, etc.) and execute the script only if some condition (timeout) is given. – djot May 08 '12 at 08:15
  • yes it is cool, but I research for better way, thanks – IVIR3zaM May 08 '12 at 08:27

9 Answers9

7

You could use flock() to lock the php file itself, like this:

<?php

class Lock{
    private $fp;
    function __construct(){
        $this->fp=fopen(__FILE__,'r');
        if (!flock($this->fp,LOCK_EX|LOCK_NB)) {
            die('already running !'.PHP_EOL);
        }       
    }
    function __destruct(){
        flock($this->fp,LOCK_UN);
        fclose($this->fp);  
    }
}

$lock=new Lock();


// simulate some processing
sleep(60);


echo "END";
?>
stewe
  • 41,820
  • 13
  • 79
  • 75
  • If Apache server get restarted did LOCK expired or not? – IVIR3zaM May 08 '12 at 08:09
  • 1
    @IVIR3zaM: if the script gets killed the lock also expires. (not sure if apache kills the script if it gets restarted, but i would think so) – stewe May 08 '12 at 08:20
  • 1
    right, forgot about flock. there were some discussions, how reliable flock is under different server configurations, but it seems it is pretty reliable now? - I too think apache kills running scripts when it's restarted normaly – cypherabe May 08 '12 at 08:38
  • @stewe: yes I test it and it work properly for Apache, and it is too cool,Thanks – IVIR3zaM May 08 '12 at 08:55
2

Can you just use require_once or include_once?

require_once will throw a PHP fatal error (will stop execution) if the file cannot be evaluated. include_once will throw a PHP warning (execution may continue).

// Require tasks.php to run once
require_once 'path/to/tasks.php';

// Attempt to run tasks.php and only once
include_once 'path/to/tasks.php';
DJ Tarazona
  • 1,769
  • 14
  • 18
2

Your problem is essentially equivalent to "Check if a php script is still running"

Please refer this

Check if a php script is still running

Community
  • 1
  • 1
piyush
  • 976
  • 4
  • 13
  • 28
  • it is nice but not work correctly, in my script many works execute and may it take too long and pass from seconds, in this case my script thought it is not running and run again – IVIR3zaM May 08 '12 at 08:14
2

if I understand you correctly, you want to prevent your cron.php script from getting started a second time by cron, it is not called from another PHP script? (in that case, require_once would be the right answer)

as I understand it, you need to store a marker that indicates that your script is running and remove that marker at the end of your script.

depending on your environment, you could either create a small file, i.e. .lock or store a status = locked entry in your database.

edit: here is a small code example using the file method:

<?php
// cron.php
$path = '/path/to/your/data/directory/';
if (file_exists($path . '.lock') {
   die('cron.php is already running');
}
// if script reaches this point, it is not locked -> create a lock
file_put_contents($path . '.lock', 'lockfile created at ' . now());

//... your code....

//unlocking
unlink($path . '.lock');
?>
cypherabe
  • 2,562
  • 1
  • 20
  • 35
  • yes you understood it. it called trough CURL. but your idea have a problem, maybe Apache get restarted and my script didn't to end to unlink .lock file and then my system shutting down forever – IVIR3zaM May 08 '12 at 08:03
2

If you are using cURL then I believe your are using cURL to request a page such as http://domain.com/cron.php. The machine requesting the script via cURL/wget/browser/etc has no way of knowing if the script is already being executed on the server. However, you can configure your cron.php script to run only once:

<?php
// attempt to obtain a lock
$fp = fopen(basename(__FILE__) . ".lock", "w");
if (flock($fp, LOCK_EX | LOCK_NB) === false) {
    echo basename(__FILE__) . ": already running\n";
    exit(-1);
}

// code goes here
echo date("Y-m-d H:i:s") . ": cron job started\n";
sleep(30);
echo date("Y-m-d H:i:s") . ": cron job ended\n";

// release the lock
flock($fp, LOCK_UN);
fclose($fp);

The sample code uses PHP flock function. The LOCK_EX flag tells PHP that it needs to obtain an exclusive lock; i.e. no other process is allowed to access the file. The LOCK_NB tells PHP that it should not block (wait for the lock to be released) and return false immediately. Together, the two switches assure that a second process cannot lock the file while the first one has it locked.

Salman A
  • 262,204
  • 82
  • 430
  • 521
  • thanks, I have only one question. when Apache server restart this lock removed or not? – IVIR3zaM May 08 '12 at 08:29
  • I test it and read more about it, yes when apache get restarted all locks released. Thanks – IVIR3zaM May 08 '12 at 08:51
  • 1
    @IVIR3zaM: I have Apache on windows; which seems to wait for PHP processes to finish; but I am not sure what happens if Apache (or the PHP process) is _killed_. I did test the script on PHP CLI which correctly released lock when I killed the script or terminated it using CTRL+C. The PHP documentation also says that the locking is _advisory, not mandatory_ which could mean that the locking mechanism is kill-safe. – Salman A May 08 '12 at 10:11
1

you can use require_once or include_once

The general syntax of both the include and require statements are as follows:

include "file_to_load.php";
include_once "file_to_load.php";

When the include_once/require_once statements are used, the file cannot be loaded or executed multiple times. If an attempt is made to load a file twice using one of these two methods, it will be ignored. Because it is unacceptable to define the same function multiple times within a script, these functions allow the developer to include a script as needed without having to check whether it has been previously loaded.

NOTE The capability to return values from external files is limited only to the include_once statements. The require_once statements cannot be used in this fashion.

NullPoiиteя
  • 56,591
  • 22
  • 125
  • 143
  • it is incorrect. I run my script trough CURL. include_one is for each client and I wanna that my script run one time for all clients – IVIR3zaM May 08 '12 at 08:05
1
include_once('class.php');

php.net states

The include_once statement includes and evaluates the specified file during the execution of the script. This is a behavior similar to the include statement, with the only difference being that if the code from a file has already been included, it will not be included again. As the name suggests, it will be included just once.

Darren Burgess
  • 4,200
  • 6
  • 27
  • 43
0

You can use either require_once or include_once.

if you are confuse what to use then difference between this two is that

require_once will stop executing preceding code, trwos fatal error, if file mentioned is not found so if you want preceding code to continue even file is not found then don't use it.

where as the include_once will continue executing preceding code.

Rajan Rawal
  • 6,171
  • 6
  • 40
  • 62
0

You can use Database for this case, make an entry of the page in database and second column for checking whether is it loaded or not (eg. '0' if not loaded yet and '1' it is loaded). Initially keep value of that row as '0' when the page is loaded update that column as '1'.

Bhavesh G
  • 3,000
  • 4
  • 39
  • 66