Question

Is it possible to setup a CRON JOB Programmatically? Using PHP with the php_curl extension? I have the following code:

function wp_cron_control_call_cron( $blog_address ) {
    $cron_url = $blog_address . '/wp-cron.php?doing_wp_cron';
    $ch = curl_init( $cron_url );
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 0 );
    curl_setopt( $ch, CURLOPT_TIMEOUT, '3' );
    $result = curl_exec( $ch );
    curl_close( $ch );
    return $result;
}

Is there anyway to execute this on a set interval programmatically? I'm not trying to setup a CRONTAB or anything like that in cPanel manually. I would like this to be able to be done with actual code, if possible. Is this possible? Is there a setting in curl_setopt to do this with? Or some other way? Using PHP 5.4.16 if that matters.

Was it helpful?

Solution

Why not using cPanel API v2 ?

cPanel Inc created a Client XML API, guess what.. it's using cURL to call API.

Firstly get the xmlapi.php file, now search in the xmlapi.php these lines :

private $port               =   '2087';
private $protocol       =   'https';

In order to make it work with a cPanel account without root access, change the $port to 2083 (HTTPS) or 2082 (HTTP), obviously, if you're using HTTP-Port, change the $protocol to http.

cPanel API has a Cron module documentation as you asked, you can delete, add and even edit a CronJob.

Example of use

List all CronJob :

require_once 'xmlapi.php';

/*
 *  Instanciate the class, setting up username/password/IP
 *  @ip - cPanel server IP, if this script is on the cPanel server replace $ip by $ip = getenv('REMOTE_HOST');
 *  @account - string - your cPanel username
 *  @pass - string - your cPanel password
 */

$ip = '127.0.0.1';
$account = 'username';
$pass = "password";
$xmlapi = new xmlapi($ip, $account, $pass);

/*
 * Just to be sure that XML-API will use the correct port and protocol
 * @set_port(port); change port to 2082 if it isn't redirected to HTTPS and/or using HTTP protocol, else.. use 2083
 * @set_protocol(protocol); change protocol to http if your sever accept HTTP else put the protocol to https
 * @set_output(format); change to XML if you want the result output w/ XML, JSON if you want the result output w/ JSON
 */
$xmlapi->set_port('2083');
$xmlapi->set_protocol('https');
$xmlapi->set_output("json");
$xmlapi->set_debug(1);

/*
 * @api2_query(account, module, function, params)
 */
print $xmlapi->api2_query($account, "Cron", "listcron");

Per example, with a single line in CronJob it'll return :

{"cpanelresult":{"data":[{"day":"1","minute":"1","hour":"1","count":1,"command_htmlsafe":"/usr/bin/php5","command":"/usr/bin/php5","weekday":"1","month":"1","linekey":"7209fe24c876a729b42a929692c62ce3"},{"count":2}],"apiversion":2,"module":"Cron","event":{"result":1},"func":"listcron"}}

Create a CronJob

require_once 'xmlapi.php';

/*
 *  Instanciate the class, setting up username/password/IP
 *  @ip - cPanel server IP, if this script is on the cPanel server replace $ip by $ip = getenv('REMOTE_HOST');
 *  @account - string - your cPanel username
 *  @pass - string - your cPanel password
 */

$ip = '127.0.0.1';
$account = 'username';
$pass = "password";
$xmlapi = new xmlapi($ip, $account, $pass);

/*
 * Just to be sure that XML-API will use the correct port and protocol
 * @set_port(port); change port to 2082 if it isn't redirected to HTTPS and/or using HTTP protocol, else.. use 2083
 * @set_protocol(protocol); change protocol to http if your sever accept HTTP else put the protocol to https
 * @set_output(format); change to XML if you want the result output w/ XML, JSON if you want the result output w/ JSON
 */
$xmlapi->set_port('2083');
$xmlapi->set_protocol('https');
$xmlapi->set_output("json");
$xmlapi->set_debug(1);

/*
 *  @command string - The command, script, or program you wish for your cronjob to execute.
 *  @day int - The day on which you would like this crontab entry to run. Wildcards and any acceptable input to a crontab time expression line are allowed here.
 *  @hour int - The hour at which you would like this crontab entry to run. Wildcards and any acceptable input to a crontab time expression line are allowed here.
 *  @minute int - The minute at which you would like this crontab entry to run. Wildcards and any acceptable input to a crontab time expression line are allowed here.
 *  @month int - The month you would like this crontab entry to run. Wildcards and any acceptable input to a crontab time expression line are allowed here.
 *  @weekday int - The weekday on which you would like this crontab entry to run. Wildcards and any acceptable input to a crontab time expression line is allowed here. Acceptable values range from 0 to 6, where 0 represents Sunday and 6 represents Saturday.
 */

$command = "/usr/bin/php cron.php";
$day = "1";
$hour = "1";
$minute = "1";
$month = "1";
$weekday = "1";

/*
 * @api2_query(account, module, function, params)
 */
print $xmlapi->api2_query($account, "Cron", "add_line", array(
    "command"=>$command,
    "day"=>$day,
    "hour"=>$hour,
    "minute"=>$minute,
    "month"=>$month,
    "weekday"=>$weekday
));

Obviously, it returns you this :

{"cpanelresult":{"module":"Cron","event":{"result":1},"apiversion":2,"data":[{"statusmsg":"crontab installed","status":1,"linekey":"9b0c93fe238a185e4aa78752a49a0718"}],"func":"add_line"}}

Removing a CronJob

Before explaining how to remove a CronJob, you have to know the line of the CronJob that you want to remove.. If you check "List all CronJob" on the response part, you may saw a count in the JSON response, exactly this :

[{"day":"1","minute":"1","hour":"1","count":1,"command_htmlsafe":"/usr/bin/php5","command":"/usr/bin/php5","weekday":"1","month":"1","linekey":"7209fe24c876a729b42a929692c62ce3"},{"count":2}]

The exact line is the "count":1 after the "hour":1 and NOT the latest "count":2, as you understand, the line is the..... FIRST (well done sherlock).

Now we can use the same script with a Curl::remove_line :

require_once 'xmlapi.php';

/*
 *  Instanciate the class, setting up username/password/IP
 *  @ip - cPanel server IP, if this script is on the cPanel server replace $ip by $ip = getenv('REMOTE_HOST');
 *  @account - string - your cPanel username
 *  @pass - string - your cPanel password
 */

$ip = '127.0.0.1';
$account = 'username';
$pass = "password";
$xmlapi = new xmlapi($ip, $account, $pass);

/*
 * Just to be sure that XML-API will use the correct port and protocol
 * @set_port(port); change port to 2082 if it isn't redirected to HTTPS and/or using HTTP protocol, else.. use 2083
 * @set_protocol(protocol); change protocol to http if your sever accept HTTP else put the protocol to https
 * @set_output(format); change to XML if you want the result output w/ XML, JSON if you want the result output w/ JSON
 */
$xmlapi->set_port('2083');
$xmlapi->set_protocol('https');
$xmlapi->set_output("json");
$xmlapi->set_debug(1);

/*
 * @api2_query(account, module, function, params)
 */
print $xmlapi->api2_query($account, "Cron", "remove_line", array(
    "line" => "1"
));

And output :

{"cpanelresult":{"module":"Cron","data":[{"status":1,"statusmsg":"crontab installed"}],"func":"remove_line","apiversion":2,"event":{"result":1}}}

Editing a CronJob

AGAIN You need the linekey OR the line number (called commandnumber) in order to edit a line, the code is exactly the same except that there is a linekey and line params , check the Cron::listcron response for linekey, per example here :

[{"day":"1","minute":"1","hour":"1","count":1,"command_htmlsafe":"/usr/bin/php5","command":"/usr/bin/php5","weekday":"1","month":"1","linekey":"7209fe24c876a729b42a929692c62ce3"},{"count":2}]

The linekey param is 7209fe24c876a729b42a929692c62ce3 and the commandnumber is 1 (see count here : "hour":"1","count":1)

There is the code :

require_once 'xmlapi.php';

/*
 *  Instanciate the class, setting up username/password/IP
 *  @ip - cPanel server IP, if this script is on the cPanel server replace $ip by $ip = getenv('REMOTE_HOST');
 *  @account - string - your cPanel username
 *  @pass - string - your cPanel password
 */

$ip = '127.0.0.1';
$account = 'username';
$pass = "password";
$xmlapi = new xmlapi($ip, $account, $pass);

/*
 * Just to be sure that XML-API will use the correct port and protocol
 * @set_port(port); change port to 2082 if it isn't redirected to HTTPS and/or using HTTP protocol, else.. use 2083
 * @set_protocol(protocol); change protocol to http if your sever accept HTTP else put the protocol to https
 * @set_output(format); change to XML if you want the result output w/ XML, JSON if you want the result output w/ JSON
 */
$xmlapi->set_port('2083');
$xmlapi->set_protocol('https');
$xmlapi->set_output("json");
$xmlapi->set_debug(1);

/*
 *  @command string - The command, script, or program you wish for your cronjob to execute.
 *  @commandnumber int - The line of the cron entry to be edited, as reported by listcron. If this is not specified, linekey (see below) must be specified.
 *  @linekey int - The linekey for the entry to be edited, as reported by listcron. If this is not specified, commandnumber (see above) must be specified.
 *  @day int - The day on which you would like this crontab entry to run. Wildcards and any acceptable input to a crontab time expression line are allowed here.
 *  @hour int - The hour at which you would like this crontab entry to run. Wildcards and any acceptable input to a crontab time expression line are allowed here.
 *  @minute int - The minute at which you would like this crontab entry to run. Wildcards and any acceptable input to a crontab time expression line are allowed here.
 *  @month int - The month you would like this crontab entry to run. Wildcards and any acceptable input to a crontab time expression line are allowed here.
 *  @weekday int - The weekday on which you would like this crontab entry to run. Wildcards and any acceptable input to a crontab time expression line is allowed here. Acceptable values range from 0 to 6, where 0 represents Sunday and 6 represents Saturday.
 */

$command = "/usr/bin/php cron.php";
$commandnumber = "1";
$linekey = "7209fe24c876a729b42a929692c62ce3";
$day = "1";
$hour = "2";
$minute = "1";
$month = "1";
$weekday = "1";

/*
 * @api2_query(account, module, function, params)
 */

print $xmlapi->api2_query($account, "Cron", "edit_line", array(
    "command"=>$command,
    "commandnumber"=>$commandnumber,
    "linekey"=>$linekey,
    "day"=>$day,
    "hour"=>$hour,
    "minute"=>$minute,
    "month"=>$month,
    "weekday"=>$weekday
));

PS : If you use linekey you can leave commandline empty and vice-versa.

I make it simple.. but there is a ton of possibilities using POST request etc..

libssh2 way

I found a way to do it with libssh2, checkout here

shell_exec way

Only disadvantage is that shared hosting or even a correct webmaster is not going to enable shell function but.. if there're enabled, you should check here a solution was given by @ajreal, but it also depends on what user crontab..

Hope this helped you!

OTHER TIPS

How to enable CURL extension

wordpress WP-Cron-Control

Managing Cron Jobs with PHP

Execute a cron job every 30 Minutes

*/30 * * * * /home/ramesh/backup.sh

Note: In the same way, use */10 for every 10 minutes, */15 for every 15 minutes, */30 for every 30 minutes, etc.

WordPress Cron Intervals

<?php

// Add a new interval of a week
// See http://codex.wordpress.org/Plugin_API/Filter_Reference/cron_schedules

add_filter( 'cron_schedules', 'myprefix_add_weekly_cron_schedule' );
function myprefix_add_weekly_cron_schedule( $schedules ) {
    $schedules['weekly'] = array(
        'interval' => 604800, // 1 week in seconds
        'display'  => __( 'Once Weekly' ),
    );

    return $schedules;
}

// Schedule an action if it's not already scheduled


if ( ! wp_next_scheduled( 'myprefix_my_cron_action' ) ) {
    wp_schedule_event( time(), 'weekly', 'myprefix_my_cron_action' );
}

// Hook into that action that'll fire weekly


add_action( 'myprefix_my_cron_action', 'myprefix_function_to_run' );
function myprefix_function_to_run() {
    // Add some code here
}

?>

Full Source (Save it to any PHP File and Add To Plugin Folder and Activate)

Function

wp_schedule_event($time, $interval, $hook, $args);
$time:it Contain TimeStamp Format or when the execute the Event is set Here.time must be in UNIX Time stamp Format.

$interval: it Define When Schedule recoours. Schedule Must Be (hourly,twicedaily,daily)

$hook: name of hoo


<?php
/* 
    Plugin Name:Cron-Job Example
    Version: 1.0
    Author: ravipatel
    Description: Simple Cron-Job Example
    */ 
    register_activation_hook( __FILE__, 'cron_schedule_activate' ); // When Plugin Activate Set Cron-Job
    function cron_schedule_activate()
    {
        wp_schedule_event( time(), 'hourly', 'cron_simple_example_hook' );   //Set Function and Set Schedule as Per Your Requirement
    }
    add_action( 'cron_simple_example_hook', 'cron_simple_example' );    //Add Action

    function cron_simple_example()
    {
        //Add Here Curl Function to submit Data to Site You Want
        $ch = curl_init();
        curl_setopt($ch,CURLOPT_POST,1);
        curl_setopt($ch,CURLOPT_URL,"Your URL");
        curl_setopt($ch,CURLOPT_HEADER,0);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
        curl_setopt($ch,CURLOPT_TIMEOUT,40);
        curl_setopt($ch,CURLOPT_POSTFIELDS,"POST Parameter Detail");
        curl_exec($ch);
        curl_close($ch);
    }
?>

You can add following php code :

$mycronjob = "0 * * * * /home/website.com/my.php";

$output = shell_exec('echo "$mycronjob" | crontab -');

You can modify $mycronjob value as you like.

To setup a 'cron job' on your system, you modify the crontab file by adding a new line in the specific format.

From Wikipedia

# * * * * *  command to execute
# ┬ ┬ ┬ ┬ ┬
# │ │ │ │ │
# │ │ │ │ │
# │ │ │ │ └───── day of week (0 - 7) (0 to 6 are Sunday to Saturday, or use names; 7 is Sunday, the same as 0)
# │ │ │ └────────── month (1 - 12)
# │ │ └─────────────── day of month (1 - 31)
# │ └──────────────────── hour (0 - 23)
# └───────────────────────── min (0 - 59)

So to execute your job every 30 minutes

*/30 * * * * php myscript.php?param1=test

To make this string into a cron job it needs to be added to the crontab file, there are quite a few different ways people have done this via scripting. Once you find one you like, you can then use PHP to execute the script.

To do this via PHP you can leverage the shell_exec() function

$output = shell_exec('SCRIPT GOES HERE');

Try something like this:

<?php
// ...
$scriptPath = '/path/of/the/phpscript/';
$dayOfWeek = date('w', time());
$hour = date('H', time());
$minute = date('i', time());
$srtCron = "$minute $hour * * $dayOfWeek php $scriptPath";
shell_exec("(crontab -l ; echo $srtCron)| crontab -");
// ...

Remember that $srtCron is:

* * * * *
| | | | |
| | | | ----- Day of week (0 - 7) (Sunday=0 or 7)
| | | ------- Month (1 - 12)
| | --------- Day of month (1 - 31)
| ----------- Hour (0 - 23)
------------- Minute (0 - 59)

Some reference:

Add Jobs To cron Under Linux or UNIX

Appending to crontab with a shell script

Editing crontab programmatically from PHP is hard and painful. My advice for you is simple.

  1. Add 1 entry in crontab that run every minute. This cron will execute a PHP script. It will be the main entry point (see point 3)
  2. Create a simple MySQL table where you can add/delete/edit entries from PHP. This table must be a copy of the fields of the cron system (column example : Day, Month, Week, Hour, Minute and "script to execute")
  3. Create a cron.php script (for point 1) that connects to your MySQL DB and check in the list (point 2) if there is something to execute right now for the current minute. If so then you can shell_exec().

Now you want to edit a cron ? Just edit your Mysql table (by hand or from a php script). It should solve all you problems.

This is just an example you can visit How can I programmatically create a new cron job? to know commands much better way, and to understand the corn you can go to Running a simple shell script as a cronjob

PHP to create Cronjob

<?php
  $output = shell_exec('crontab -l'); // <- thats an L right there
  file_put_contents('/tmp/crontab.txt', $output . '* * * * * NEW_CRON' . PHP_EOL);
  echo exec('crontab /tmp/crontab.txt');
?>

PHP to delete Cronjob

<?php
  echo exec('crontab -r');
?>

This will delete the whole crontab file.

You may try this:

ignore_user_abort(1);
ini_set('max_execution_time',0);
$startingtime=date();
for($i=0;$i<1;){
if(date() > $startingtime+[time for cron job]){

CODE TO EXECUTE

}
else{
sleep($startingtime+[time for cron job]-date());
}
}

Doesn’t WordPress already have built in pseudo-cron capabilities? The function wp_schedule_event() seems to handle what you are describing right within the WordPress API:

Schedules a hook which will be executed by the WordPress actions core on a specific interval, specified by you. The action will trigger when someone visits your WordPress site, if the scheduled time has passed. See the Plugin API for a list of hooks.

Here is an example of how to setup an hourly event that includes wp_next_scheduled():

add_action( 'wp', 'prefix_setup_schedule' );
/**
 * On an early action hook, check if the hook is scheduled - if not, schedule it.
 */
function prefix_setup_schedule() {
    if ( ! wp_next_scheduled( 'prefix_hourly_event' ) ) {
        wp_schedule_event( time(), 'hourly', 'prefix_hourly_event');
    }
}


add_action( 'prefix_hourly_event', 'prefix_do_this_hourly' );
/**
 * On the scheduled action hook, run a function.
 */
function prefix_do_this_hourly() {
    // do something every hour
}

So using your example code, this should work:

add_action( 'wp', 'prefix_setup_schedule' );
/**
 * On an early action hook, check if the hook is scheduled - if not, schedule it.
 */
function prefix_setup_schedule() {
    if ( ! wp_next_scheduled( 'prefix_hourly_event' ) ) {
        wp_schedule_event( time(), 'hourly', 'prefix_hourly_event');
    }
}


add_action( 'prefix_hourly_event', 'wp_cron_control_call_cron' );
/**
 * On the scheduled action hook, run a function.
 */
function wp_cron_control_call_cron( $blog_address ) {
    $cron_url = $blog_address . '/wp-cron.php?doing_wp_cron';
    $ch = curl_init( $cron_url );
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 0 );
    curl_setopt( $ch, CURLOPT_TIMEOUT, '3' );
    $result = curl_exec( $ch );
    curl_close( $ch );
    return $result;
}

Also, you could do something similar in plain PHP by simply storing the timestamp somewhere. Either in a DB field, or perhaps as in a file stored in a cache directory or tmp directory. Then just check that file each time a page loads—for example—and if the time the page loads has a delta outside of the timespan you have checked, run the task.

Or instead of a PHP page load you could actually have a real cron job run every minute—for example—that would load a PHP page that then does the delta comparison logic based on your needs.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top