【问题标题】:How to set up a Cron Job Programmatically?如何以编程方式设置 Cron 作业?
【发布时间】:2014-06-26 00:39:08
【问题描述】:

是否可以以编程方式设置 CRON 作业?使用带有php_curl 扩展名的PHP?我有以下代码:

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;
}

有没有以编程方式在设定的时间间隔内执行此操作?我不想在 cPanel 中手动设置 CRONTAB 或类似的东西。如果可能的话,我希望能够使用实际代码来完成。这可能吗? curl_setopt 中有设置吗?还是其他方式?如果重要,请使用 PHP 5.4.16。

【问题讨论】:

  • 假设您的“代码”在 PHP 中。如果不是 crontab,什么会定期调用 PHP 脚本?
  • 这很好,但是如何在 PHP 中做到这一点?
  • 什么好?我刚刚问了你一个问题
  • 设置crontab 很好,如果它可以严格地在代码中完成!也许可以在 php.ini 中完成?还是 .htaccess 文件?
  • php_curl 与 CRON 无关。它所做的一切都是发出网络请求。如果您想以间隔运行此脚本,则需要设置crontab。您可能可以从 PHP 代码中编辑 crontab,但您为什么要这样做?

标签: php wordpress curl cron


【解决方案1】:

为什么不使用 cPanel API v2?

cPanel Inc 创建了一个Client XML API,你猜怎么着......它使用 cURL 来调用 API。

首先获取 xmlapi.php 文件,现在在 xmlapi.php 中搜索这些行:

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

为了使其在没有 root 访问权限的 cPanel 帐户下工作,请将 $port 更改为 2083 (HTTPS) 或 2082 (HTTP),显然,如果您使用的是 HTTP-Port,请将 $protocol 更改为http.

cPanel API 有一个 Cron module documentation 如你所问,你可以删除、添加甚至编辑 CronJob。

使用示例

列出所有 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");

例如,在 CronJob 中只有一行会返回:

{"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"}}

创建一个 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
));

显然,它会返回:

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

删除一个 CronJob

在解释如何删除 CronJob 之前,您必须知道要删除的 CronJob 的行。如果您在响应部分选中“列出所有 CronJob”,您可能会在 JSON 响应中看到计数,正是这个:

[{"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}]

确切的行是"hour":1之后的"count":1不是最新的"count":2,正如你所理解的,该行是..... FIRST(干得好,sherlock)。

现在我们可以使用带有 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"
));

然后输出:

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

编辑 CronJob

AGAIN 您需要linekey OR 行号(称为commandnumber)才能编辑一行,代码完全相同,除了那里是一个 linekey 和 line params ,检查 linekey 的 Cron::listcron 响应,这里的每个示例:

[{"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}]

linekey 参数为 7209fe24c876a729b42a929692c62ce3,commandnumber 为 1(请参见此处的计数:"hour":"1","count":1

有代码:

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 : 如果你使用 linekey,你可以将命令行留空,反之亦然。

我让它变得简单..但是使用 POST 请求等有很多可能性..

libssh2 方式

我找到了一种使用 libssh2 的方法,checkout here

shell_exec方式

唯一的缺点是共享主机甚至是正确的网站管理员都不会启用shell功能,但是..如果启用了,您应该检查here@ajreal给出的解决方案,但这也取决于什么用户 crontab..

希望这对您有所帮助!

【讨论】:

  • 谢谢,就是这样。 cPanel API 很好,只是希望 API 的第 2 版能够支持大多数平台,无论如何,我想 libssh2 将作为后备。太棒了,谢谢!
【解决方案2】:

How to enable CURL extension

wordpress WP-Cron-Control

Managing Cron Jobs with PHP

每 30 分钟执行一次 cron 作业

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

注意:同理,每 10 分钟使用 */10,每 15 分钟使用 */15,每 30 分钟使用 */30,等等。

WordPress Cron 间隔

<?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
}

?>

完整源代码(保存到任何 PHP 文件并添加到插件文件夹并激活)

功能

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);
    }
?>

【讨论】:

  • 这不起作用。 Wordpress 预定事件依赖于用户在激活 cron 之前访问该站点。这是不可靠的。正是我问这个问题的原因。
  • 我已经在激活插件时设置了预定的事件,但是,由于 Wordpress Cron 不准确并且依赖于某人访问该站点来激活它,我禁用了 CRON,通过 define('DISABLE_WP_CRON', true)wp-config.php 并且需要通过实际的 cron 作业运行 cron 脚本 (/wp-cron.php?doing_wp_cron)!
  • @SolomonClosson:苛刻。然后你要求一个不存在的解决方案。如果没有实际的 cronjob,唯一的选择是触发用户交互。那是他的 Apache、PHP 和 WiodPress 作品。
  • 好吧,我正在寻求一种以编程方式创建 cronjob 的解决方案。不要求提供有关如何创建 Wordpress 预定事件的解决方案。无意冒犯。
  • 很好的编辑,现在非常有用,尤其是:Managing Cron Jobs with PHP 链接。
【解决方案3】:

您可以添加以下 php 代码:

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

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

您可以根据需要修改 $mycronjob 值。

【讨论】:

  • lol @$mycornjob 谢谢,会试一试并报告。 echo 在这里做什么?你能在这里解释一下crontab -吗?
  • 你的玉米工作要花多少钱?
  • 好吧,真的是每 30 分钟一次,但实际上需要能够添加和删除 cron 作业......因为希望能够在插件中将其更改为 30 分钟,每小时一次,或每天。
  • 我喜欢这个答案,但我们可以稍微扩展一下以删除 cron 作业吗?或者这就是它应该做的?
【解决方案4】:

要在系统上设置“cron 作业”,您可以通过添加特定格式的新行来修改 crontab 文件。

来自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)

所以每 30 分钟执行一次你的工作

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

要将这个字符串变成一个 cron 作业,需要将它添加到 crontab 文件中,有 quite a few 不同的方式 people have done this 通过脚本编写。一旦你找到了你喜欢的,你就可以使用 PHP 来执行脚本了。

要通过 PHP 执行此操作,您可以利用 shell_exec() 函数

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

【讨论】:

    【解决方案5】:

    试试这样的:

    <?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 -");
    // ...
    

    记住 $srtCron 是:

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

    一些参考:

    Add Jobs To cron Under Linux or UNIX

    Appending to crontab with a shell script

    【讨论】:

      【解决方案6】:

      从 PHP 以编程方式编辑 crontab 既困难又痛苦。我给你的建议很简单。

      1. 在每分钟运行的 crontab 中添加 1 个条目。这个 cron 将执行一个 PHP 脚本。它将是主要入口点(见第 3 点)
      2. 创建一个简单的 MySQL 表,您可以在其中添加/删除/编辑 PHP 中的条目。此表必须是 cron 系统字段的副本(列示例:日、月、周、小时、分钟和“要执行的脚本”)
      3. 创建一个连接到您的 MySQL 数据库的 cron.php 脚本(针对第 1 点),并检查列表(第 2 点)是否有当前分钟需要执行的内容。如果是这样,那么您可以使用 shell_exec()。

      现在你想编辑一个 cron 吗?只需编辑您的 Mysql 表(手动或从 php 脚本)。它应该可以解决你所有的问题。

      【讨论】:

        【解决方案7】:

        这只是一个例子 您可以访问How can I programmatically create a new cron job? 以更好地了解命令, 要了解玉米,你可以去 Running a simple shell script as a cronjob

        【讨论】:

          【解决方案8】:

          PHP 创建 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 删除 Cronjob

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

          这将删除整个 crontab 文件。

          【讨论】:

          • 谢谢。但是它怎么知道要删除哪个crontab?例如,如果还有其他crontabs,出于其他目的,就不想干涉那些。 crontab -r 怎么知道要删除哪一个?
          • 我发现了这个:stackoverflow.com/questions/15830758/… - 它是关于删除一个不断变化的 crontabs。
          【解决方案9】:

          你可以试试这个:

          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());
          }
          }
          

          【讨论】:

            【解决方案10】:

            WordPress 不是已经内置了伪 cron 功能吗? wp_schedule_event() 函数似乎可以处理您在 WordPress API 中描述的内容:

            安排一个将由 WordPress 动作核心执行的钩子 在您指定的特定时间间隔内。动作会在什么时候触发 如果预定时间已过,有人访问您的 WordPress 网站。 有关挂钩列表,请参阅插件 API。

            以下是如何设置包含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
            }
            

            所以使用您的示例代码,这应该可以工作:

            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;
            }
            

            此外,您可以通过简单地将时间戳存储在某处来在普通 PHP 中执行类似的操作。在数据库字段中,或者在缓存目录或 tmp 目录中存储的文件中。然后只需在每次页面加载时检查该文件,例如,如果页面加载时间的增量超出您检查的时间跨度,则运行该任务。

            或者,您实际上可以每分钟运行一个真正的 cron 作业来代替 PHP 页面加载——例如,它会加载一个 PHP 页面,然后根据您的需要执行增量比较逻辑。

            【讨论】:

            • 再一次,由于 ravi patel 的回答不起作用的同样原因,它不起作用。
            • @SolomonClosson 他们说“再次……”的方式让这里的每个用户都对这里的所有其他帖子和答案都有清晰的叙述,这有点傲慢和贬低。我希望有人可以回答您的问题并提供可靠且理智的解决方案;我有兴趣看到那个。但是你的整体举止几乎扼杀了我必须为这个线程自行研究解决这个问题的任何愿望。祝你好运!
            猜你喜欢
            • 1970-01-01
            • 2010-10-11
            • 2019-09-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多